master
cody 3 months ago
parent 63c17bddc0
commit 4a8a5f68c2

@ -4,6 +4,7 @@ namespace App\Console\Commands;
use App\Models\EmailRecord;
use App\Models\EmailRecordUser;
use App\Models\Upload;
use App\Models\User;
use App\Repositories\MeetRepository;
use Illuminate\Console\Command;
@ -51,6 +52,16 @@ class SendEmail extends Command
foreach ($emailRecords as $records) {
// 获取模版配置
$emailTemplate = $records->emailTemplate;
// 获取附件
$attachments = [];
if (!empty($records->attachments)) {
$attachmentIds = explode(',', $records->attachments);
$attachmentIds = array_filter(array_map('trim', $attachmentIds));
if (!empty($attachmentIds)) {
$attachments = Upload::whereIn('id', $attachmentIds)->get();
}
}
// 获取未发送人员
$emailRecordUsers = $records->emailRecordUsers->where('status', 0);
foreach ($emailRecordUsers as $recordUser) {
@ -59,8 +70,8 @@ class SendEmail extends Command
// 替换后的内容
$template = EmailRecordUser::template($emailTemplate->content, $recordUser->var_data);
try {
// 发送邮件
EmailRecordUser::email($title, $template, $recordUser->email);
// 发送邮件(带附件)
EmailRecordUser::email($title, $template, $recordUser->email, $attachments);
$recordUser->status = 1;
} catch (\Exception $e) {
$recordUser->status = 2;

@ -15,6 +15,7 @@ use App\Models\EmailRecord;
use App\Models\EmailRecordUser;
use App\Models\EmailTemplate;
use App\Models\SupplyDemand;
use App\Models\Upload;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
@ -177,6 +178,8 @@ class EmailRecordController extends BaseController
* @OA\Parameter(name="subject", in="query", @OA\Schema(type="string", maxLength=255), required=false, description="主题"),
* @OA\Parameter(name="email_template_id", in="query", @OA\Schema(type="string", format="mediumtext"), required=false, description="邮件模版id"),
* @OA\Parameter(name="email_record_users", in="query", @OA\Schema(type="string", format="mediumtext"), required=false, description="二维数组包括建明emailvar_data自定义数据"),
* @OA\Parameter(name="attachments", in="query", @OA\Schema(type="array", @OA\Items(type="file")), required=false, description="附件文件数组,支持多个附件"),
* @OA\Parameter(name="attachment_ids", in="query", @OA\Schema(type="string"), required=false, description="附件ID多个用英文逗号分隔如果已上传附件"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="认证token"),
* @OA\Response(
* response="200",
@ -199,6 +202,63 @@ class EmailRecordController extends BaseController
$all['admin_id'] = $this->getUserId();
$all['department_id'] = $this->getUser()->department_id;
}
// 处理附件上传
$attachmentIds = [];
// 如果提供了已上传的附件ID
if (isset($all['attachment_ids']) && !empty($all['attachment_ids'])) {
$attachmentIds = array_merge($attachmentIds, explode(',', $all['attachment_ids']));
$attachmentIds = array_filter(array_map('trim', $attachmentIds));
}
// 如果有新上传的附件文件
if (\request()->hasFile('attachments')) {
$files = \request()->file('attachments');
// 如果是单个文件,转换为数组
if (!is_array($files)) {
$files = [$files];
}
foreach ($files as $file) {
if ($file && $file->isValid()) {
// 获取文件大小,单位B
$fileSize = floor($file->getSize());
if ($fileSize >= 50 * 1024 * 1024) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '文件必须小于50M']);
}
// 过滤文件后缀
$ext = $file->getClientOriginalExtension();
if (in_array($ext, ['zip', 'rar', 'ppt', 'pptx', 'xls', 'xlsx', 'doc', 'docx', 'png', 'gif', 'jpg', 'jpeg', 'pdf', 'mp4'])) {
// 保存目录
$dir = 'files';
// 文件名
$fileName = time() . uniqid() . '.' . $ext;
$file->storeAs($dir, $fileName, ['disk' => 'public']);
// 写入上传文件记录表
$uploadData = [
'original_name' => $file->getClientOriginalName(),
'folder' => 'storage/' . $dir,
'name' => $fileName,
'extension' => $ext,
'size' => $fileSize,
'creator_id' => $this->getUserId(),
'created_at' => date('Y-m-d H:i:s')
];
$uploadId = Upload::insertGetId($uploadData);
$attachmentIds[] = $uploadId;
} else {
return $this->fail([ResponseCode::ERROR_BUSINESS, '文件格式错误仅支持zip、rar、ppt、pptx、xls、xlsx、doc、docx、png、gif、jpg、jpeg、pdf、mp4']);
}
}
}
}
// 保存附件ID用逗号分隔
if (!empty($attachmentIds)) {
$all['attachments'] = implode(',', $attachmentIds);
}
$original = $model->getOriginal();
$model->fill($all);
$model->save();
@ -226,6 +286,8 @@ class EmailRecordController extends BaseController
* @OA\Parameter(name="subject", in="query", @OA\Schema(type="string", format="date"), required=false, description="标题"),
* @OA\Parameter(name="email", in="query", @OA\Schema(type="string", format="date"), required=false, description="邮箱地址"),
* @OA\Parameter(name="var_data", in="query", @OA\Schema(type="string", format="mediumtext"), required=false, description="数组var_data自定义数据"),
* @OA\Parameter(name="attachments", in="query", @OA\Schema(type="array", @OA\Items(type="file")), required=false, description="附件文件数组,支持多个附件"),
* @OA\Parameter(name="attachment_ids", in="query", @OA\Schema(type="string"), required=false, description="附件ID多个用英文逗号分隔如果已上传附件"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="认证token"),
* @OA\Response(
* response="200",
@ -251,9 +313,63 @@ class EmailRecordController extends BaseController
$title = EmailRecordUser::template($all['subject'], $all['var_data']);
// 替换后的内容
$template = EmailRecordUser::template($emailTemplate->content, $all['var_data']);
// 处理附件
$attachments = [];
// 如果提供了已上传的附件ID
if (isset($all['attachment_ids']) && !empty($all['attachment_ids'])) {
$attachmentIds = explode(',', $all['attachment_ids']);
$attachmentIds = array_filter(array_map('trim', $attachmentIds));
$attachments = Upload::whereIn('id', $attachmentIds)->get();
}
// 如果有新上传的附件文件
if (\request()->hasFile('attachments')) {
$files = \request()->file('attachments');
// 如果是单个文件,转换为数组
if (!is_array($files)) {
$files = [$files];
}
foreach ($files as $file) {
if ($file && $file->isValid()) {
// 获取文件大小,单位B
$fileSize = floor($file->getSize());
if ($fileSize >= 50 * 1024 * 1024) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '文件必须小于50M']);
}
// 过滤文件后缀
$ext = $file->getClientOriginalExtension();
if (in_array($ext, ['zip', 'rar', 'ppt', 'pptx', 'xls', 'xlsx', 'doc', 'docx', 'png', 'gif', 'jpg', 'jpeg', 'pdf', 'mp4'])) {
// 保存目录
$dir = 'files';
// 文件名
$fileName = time() . uniqid() . '.' . $ext;
$file->storeAs($dir, $fileName, ['disk' => 'public']);
// 写入上传文件记录表
$uploadData = [
'original_name' => $file->getClientOriginalName(),
'folder' => 'storage/' . $dir,
'name' => $fileName,
'extension' => $ext,
'size' => $fileSize,
'creator_id' => $this->getUserId(),
'created_at' => date('Y-m-d H:i:s')
];
$uploadId = Upload::insertGetId($uploadData);
$upload = Upload::find($uploadId);
$attachments[] = $upload;
} else {
return $this->fail([ResponseCode::ERROR_BUSINESS, '文件格式错误仅支持zip、rar、ppt、pptx、xls、xlsx、doc、docx、png、gif、jpg、jpeg、pdf、mp4']);
}
}
}
}
try {
// 发送邮件
EmailRecordUser::email($title, $template, $all['email']);
// 发送邮件(带附件)
EmailRecordUser::email($title, $template, $all['email'], $attachments);
return $this->success("发送成功");
} catch (\Exception $e) {
return $this->fail([ResponseCode::ERROR_BUSINESS, $e->getMessage()]);

@ -0,0 +1,279 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Exports\BaseExport;
use App\Exports\CommonExport;
use App\Helpers\ResponseCode;
use App\Models\CustomForm;
use App\Models\CustomFormField;
use App\Models\StockCompany;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Facades\Excel;
class StockCompanyController extends BaseController
{
/**
* 构造函数
*/
public function __construct()
{
parent::__construct(new StockCompany());
}
/**
* @OA\Get(
* path="/api/admin/stock-company/index",
* tags={"上市公司管理"},
* summary="列表",
* description="",
* @OA\Parameter(name="is_export", in="query", @OA\Schema(type="string"), required=false, description="是否导出0否1是"),
* @OA\Parameter(name="export_fields", in="query", @OA\Schema(type="string"), required=false, description="需要导出的字段数组"),
* @OA\Parameter(name="filter", in="query", @OA\Schema(type="string"), required=false, description="查询条件。数组"),
* @OA\Parameter(name="show_relation", in="query", @OA\Schema(type="string"), required=false, description="需要输出的关联关系数组"),
* @OA\Parameter(name="page_size", in="query", @OA\Schema(type="string"), required=false, description="每页显示的条数"),
* @OA\Parameter(name="page", in="query", @OA\Schema(type="string"), required=false, description="页码"),
* @OA\Parameter(name="sort_name", in="query", @OA\Schema(type="string"), required=false, description="排序字段名字"),
* @OA\Parameter(name="sort_type", in="query", @OA\Schema(type="string"), required=false, description="排序类型"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function index()
{
$all = request()->all();
$list = $this->model->with(underlineToHump($all['show_relation'] ?? []))
->where(function ($query) use ($all) {
if (isset($all['filter']) && !empty($all['filter'])) {
foreach ($all['filter'] as $condition) {
$key = $condition['key'] ?? null;
$op = $condition['op'] ?? null;
$value = $condition['value'] ?? null;
if (!isset($key) || !isset($op) || !isset($value)) {
continue;
}
// 等于
if ($op == 'eq') {
$query->where($key, $value);
}
// 不等于
if ($op == 'neq') {
$query->where($key, '!=', $value);
}
// 大于
if ($op == 'gt') {
$query->where($key, '>', $value);
}
// 大于等于
if ($op == 'egt') {
$query->where($key, '>=', $value);
}
// 小于
if ($op == 'lt') {
$query->where($key, '<', $value);
}
// 小于等于
if ($op == 'elt') {
$query->where($key, '<=', $value);
}
// 模糊搜索
if ($op == 'like') {
$query->where($key, 'like', '%' . $value . '%');
}
// 否定模糊搜索
if ($op == 'notlike') {
$query->where($key, 'not like', '%' . $value . '%');
}
// null搜索
if ($op == 'null') {
$query->whereNull($key);
}
// notnull搜索
if ($op == 'notnull') {
$query->whereNotNull($key);
}
// 范围搜索
if ($op == 'range') {
list($from, $to) = explode(',', $value);
if (empty($from) || empty($to)) {
continue;
}
$query->whereBetween($key, [$from, $to]);
}
}
}
})->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc');
if (isset($all['is_export']) && !empty($all['is_export'])) {
$list = $list->get()->toArray();
$export_fields = $all['export_fields'] ?? [];
// 导出文件名字
$tableName = $this->model->getTable();
$filename = (new CustomForm())->getTableComment($tableName);
return Excel::download(new BaseExport($export_fields, $list, $tableName), $filename . date('YmdHis') . '.xlsx');
} else {
// 输出
$list = $list->paginate($all['page_size'] ?? 20);
}
return $this->success($list);
}
/**
* @OA\Get(
* path="/api/admin/stock-company/show",
* tags={"上市公司管理"},
* summary="详情",
* description="",
* @OA\Parameter(name="id", in="query", @OA\Schema(type="string"), required=true, description="id"),
* @OA\Parameter(name="show_relation", in="query", @OA\Schema(type="string"), required=false, description="需要输出的关联关系数组,填写输出指定数据"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function show()
{
return parent::show();
}
/**
* @OA\Post(
* path="/api/admin/stock-company/save",
* tags={"上市公司管理"},
* summary="保存",
* description="",
* @OA\Parameter(name="id", in="query", @OA\Schema(type="int"), required=false, description="Id(存在更新,不存在新增)"),
* @OA\Parameter(name="company_name", in="query", @OA\Schema(type="string", nullable=true), description="公司名称"),
* @OA\Parameter(name="stock_date", in="query", @OA\Schema(type="string", format="date", nullable=true), description="上市时间"),
* @OA\Parameter(name="enrollment_date", in="query", @OA\Schema(type="string", format="date", nullable=true), description="入学时间"),
* @OA\Parameter(name="is_after_enrollment", in="query", @OA\Schema(type="string", nullable=true), description="是否入学后上市-0否1是"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="认证token"),
* @OA\Response(
* response="200",
* description="操作成功"
* )
* )
*/
public function save()
{
$all = \request()->all();
DB::beginTransaction();
try {
if (isset($all['id'])) {
$model = $this->model->find($all['id']);
if (empty($model)) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '数据不存在']);
}
} else {
$model = $this->model;
$all['admin_id'] = $this->getUserId();
$all['department_id'] = $this->getUser()->department_id;
}
// 如果提供了上市时间和入学时间,自动计算是否入学后上市
if (isset($all['stock_date']) && isset($all['enrollment_date'])) {
$stockDate = strtotime($all['stock_date']);
$enrollmentDate = strtotime($all['enrollment_date']);
$all['is_after_enrollment'] = ($stockDate > $enrollmentDate) ? 1 : 0;
}
$original = $model->getOriginal();
$model->fill($all);
$model->save();
DB::commit();
// 记录日志
$this->saveLogs($original, $model);
return $this->success($model);
} catch (\Exception $exception) {
DB::rollBack();
return $this->fail([$exception->getCode(), $exception->getMessage()]);
}
}
/**
* @OA\Get(
* path="/api/admin/stock-company/destroy",
* tags={"上市公司管理"},
* summary="删除",
* description="",
* @OA\Parameter(name="id", in="query", @OA\Schema(type="string"), required=true, description="id"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function destroy()
{
return parent::destroy();
}
/**
* @OA\Get(
* path="/api/admin/stock-company/this-year-new",
* tags={"上市公司管理"},
* summary="今年新增上市公司",
* description="",
* @OA\Parameter(name="year", in="query", @OA\Schema(type="string"), required=false, description="年份,默认为当前年份"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function thisYearNew()
{
$all = request()->all();
$year = $all['year'] ?? date('Y');
$startDate = $year . '-01-01';
$endDate = $year . '-12-31';
$list = $this->model->whereBetween('stock_date', [$startDate, $endDate])
->orderBy('stock_date', 'desc')
->get();
return $this->success([
'year' => $year,
'total' => $list->count(),
'list' => $list
]);
}
/**
* @OA\Get(
* path="/api/admin/stock-company/after-enrollment",
* tags={"上市公司管理"},
* summary="入学后新上市公司数据显示",
* description="",
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function afterEnrollment()
{
$list = $this->model->where('is_after_enrollment', 1)
->orderBy('stock_date', 'desc')
->get();
return $this->success([
'total' => $list->count(),
'list' => $list
]);
}
}

@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Cache;
class EmailRecord extends SoftDeletesModel
{
protected $appends = ['attachment_files'];
public function emailTemplate()
{
@ -19,5 +20,24 @@ class EmailRecord extends SoftDeletesModel
return $this->hasMany(EmailRecordUser::class, 'email_record_id', 'id');
}
/**
* 获取附件文件对象数组
*/
public function getAttachmentFilesAttribute()
{
if (empty($this->attachments)) {
return [];
}
$attachmentIds = explode(',', $this->attachments);
$attachmentIds = array_filter(array_map('trim', $attachmentIds));
if (empty($attachmentIds)) {
return [];
}
return Upload::whereIn('id', $attachmentIds)->get();
}
}

@ -34,12 +34,36 @@ class EmailRecordUser extends SoftDeletesModel
/**
* 发送邮件
* @param string $title 邮件标题
* @param string $template 邮件内容
* @param string $email 收件人邮箱
* @param array $attachments 附件数组,可以是 Upload 对象数组或文件路径数组
*/
public static function email($title, $template, $email)
public static function email($title, $template, $email, $attachments = [])
{
Mail::send('email', compact('template'), function ($message) use ($email, $title) {
Mail::send('email', compact('template'), function ($message) use ($email, $title, $attachments) {
$message->from(env('MAIL_USERNAME'), '苏州科技商学院');
$message->to($email)->subject($title);
// 添加附件
if (!empty($attachments)) {
foreach ($attachments as $attachment) {
if ($attachment instanceof Upload) {
// 如果是 Upload 对象,获取文件路径
// folder 格式为 'storage/files',实际文件存储在 storage/app/public/files
$folderPath = str_replace('storage/', '', $attachment->folder);
$filePath = storage_path('app/public/' . $folderPath . '/' . $attachment->name);
if (file_exists($filePath)) {
$message->attach($filePath, [
'as' => $attachment->original_name,
]);
}
} elseif (is_string($attachment) && file_exists($attachment)) {
// 如果是文件路径字符串
$message->attach($attachment);
}
}
}
});
return true;
}

@ -0,0 +1,30 @@
<?php
namespace App\Models;
class StockCompany extends SoftDeletesModel
{
protected $fillable = [
'admin_id',
'department_id',
'company_name',
'stock_date',
'enrollment_date',
'is_after_enrollment',
];
protected $appends = ['is_after_enrollment_text'];
/**
* 获取是否入学后上市的文本
*/
public function getIsAfterEnrollmentTextAttribute()
{
$array = [
0 => '否',
1 => '是',
];
return $array[$this->is_after_enrollment] ?? '否';
}
}

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('stock_companys', function (Blueprint $table) {
$table->id();
$table->integer('admin_id')->nullable()->comment('管理员ID');
$table->integer('department_id')->nullable()->comment('部门ID');
// 公司名称
$table->string('company_name')->nullable()->comment('公司名称');
// 上市时间
$table->date('stock_date')->nullable()->comment('上市时间');
// 入学时间
$table->date('enrollment_date')->nullable()->comment('入学时间');
// 是否入学后上市
$table->tinyInteger('is_after_enrollment')->default(0)->comment('是否入学后上市0否1是');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('stock_companys');
}
};

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('email_records', function (Blueprint $table) {
// 附件ID多个附件用英文逗号分隔
$table->text('attachments')->nullable()->comment('附件ID多个附件用英文逗号分隔');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('email_records', function (Blueprint $table) {
$table->dropColumn('attachments');
});
}
};

@ -242,6 +242,14 @@ Route::group(["namespace" => "Admin", "prefix" => "admin"], function () {
Route::post('company/save', [\App\Http\Controllers\Admin\CompanyController::class, "save"]);
Route::get('company/destroy', [\App\Http\Controllers\Admin\CompanyController::class, "destroy"]);
// 上市公司管理
Route::get('stock-company/index', [\App\Http\Controllers\Admin\StockCompanyController::class, "index"]);
Route::get('stock-company/show', [\App\Http\Controllers\Admin\StockCompanyController::class, "show"]);
Route::post('stock-company/save', [\App\Http\Controllers\Admin\StockCompanyController::class, "save"]);
Route::get('stock-company/destroy', [\App\Http\Controllers\Admin\StockCompanyController::class, "destroy"]);
Route::get('stock-company/this-year-new', [\App\Http\Controllers\Admin\StockCompanyController::class, "thisYearNew"]);
Route::get('stock-company/after-enrollment', [\App\Http\Controllers\Admin\StockCompanyController::class, "afterEnrollment"]);
// 签到管理
Route::get('course-content-check/index', [\App\Http\Controllers\Admin\CourseContentCheckController::class, "index"]);
Route::get('course-content-check/show', [\App\Http\Controllers\Admin\CourseContentCheckController::class, "show"]);

Loading…
Cancel
Save