From abb18b3a01eb4efdaa23fa3e2a071c38243acf14 Mon Sep 17 00:00:00 2001 From: cody <648753004@qq.com> Date: Sat, 17 Jan 2026 10:24:46 +0800 Subject: [PATCH] update --- .../Admin/EmployeeParticipationController.php | 107 +++++++++ .../Admin/TraineeStudentController.php | 217 ++++++++++++++++++ app/Models/Company.php | 24 +- app/Models/TraineeStudent.php | 8 + ...7_094313_create_trainee_students_table.php | 38 +++ ...ields_to_employee_participations_table.php | 33 +++ routes/api.php | 8 + 7 files changed, 432 insertions(+), 3 deletions(-) create mode 100644 app/Http/Controllers/Admin/TraineeStudentController.php create mode 100644 app/Models/TraineeStudent.php create mode 100644 database/migrations/2026_01_17_094313_create_trainee_students_table.php create mode 100644 database/migrations/2026_01_17_095245_add_fields_to_employee_participations_table.php diff --git a/app/Http/Controllers/Admin/EmployeeParticipationController.php b/app/Http/Controllers/Admin/EmployeeParticipationController.php index c57fda6..5630223 100644 --- a/app/Http/Controllers/Admin/EmployeeParticipationController.php +++ b/app/Http/Controllers/Admin/EmployeeParticipationController.php @@ -5,10 +5,12 @@ namespace App\Http\Controllers\Admin; use App\Exports\BaseExport; use App\Helpers\ResponseCode; use App\Models\CustomForm; +use App\Models\CustomFormField; use App\Models\EmployeeParticipation; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; use Maatwebsite\Excel\Facades\Excel; +use Rap2hpoutre\FastExcel\FastExcel; class EmployeeParticipationController extends BaseController { @@ -156,6 +158,9 @@ class EmployeeParticipationController extends BaseController * @OA\Parameter(name="total", in="query", @OA\Schema(type="integer", format="int64"), required=false, description="数量"), * @OA\Parameter(name="course_type_id", in="query", @OA\Schema(type="integer", format="int64"), required=false, description="课程类型ID"), * @OA\Parameter(name="course_name", in="query", @OA\Schema(type="string", nullable=true), description="课程名称"), + * @OA\Parameter(name="company_name", in="query", @OA\Schema(type="string", nullable=true), description="公司名字"), + * @OA\Parameter(name="name", in="query", @OA\Schema(type="string", nullable=true), description="姓名"), + * @OA\Parameter(name="department", in="query", @OA\Schema(type="string", nullable=true), description="部门"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="认证token"), * @OA\Response( * response="200", @@ -205,5 +210,107 @@ class EmployeeParticipationController extends BaseController return parent::destroy(); } + /** + * @OA\Post( + * path="/api/admin/employee-participations/excel-show", + * tags={"员工参与"}, + * summary="导入预览", + * description="", + * @OA\Parameter(name="file", in="query", @OA\Schema(type="string"), required=true, description="文件"), + * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), + * @OA\Response( + * response="200", + * description="暂无" + * ) + * ) + */ + public function excelShow() + { + $file = \request()->file('file'); + //判断文件是否有效 + if (!(\request()->hasFile('file') && $file->isValid())) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '文件不存在或无效']); + } + //获取文件大小 + $img_size = floor($file->getSize() / 1024); + if ($img_size >= 50 * 1024) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '文件必须小于50M']); + } + //过滤文件后缀 + $ext = $file->getClientOriginalExtension(); + if (!in_array($ext, ['xls', 'xlsx', 'csv'])) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '仅支持xls/xlsx/csv格式']); + } + $tempFile = $file->getRealPath(); + $dataArray = (new FastExcel)->import($tempFile)->toArray(); + + // 固定的字段映射(Excel表头中文 => 数据库字段名) + $fieldMapping = [ + '类型' => 'type', + '开始日期' => 'start_date', + '结束日期' => 'end_date', + '数量' => 'total', + '课程类型ID' => 'course_type_id', + '课程名称' => 'course_name', + '公司名字' => 'company_name', + '姓名' => 'name', + '部门' => 'department', + ]; + + $list = []; + foreach ($dataArray as $key => $value) { + $list[$key] = []; + // 根据固定字段映射转换数据 + foreach ($fieldMapping as $excelHeader => $dbField) { + if (isset($value[$excelHeader])) { + $list[$key][$dbField] = $value[$excelHeader]; + } + } + } + return $this->success($list); + } + + /** + * @OA\Post( + * path="/api/admin/employee-participations/import", + * tags={"员工参与"}, + * summary="导入", + * description="", + * @OA\Parameter(name="data", in="query", @OA\Schema(type="string"), required=true, description="导入分析获取到的二维数组"), + * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), + * @OA\Response( + * response="200", + * description="暂无" + * ) + * ) + */ + public function import() + { + $all = \request()->all(); + $messages = [ + 'data.required' => '数据必填', + ]; + $validator = Validator::make($all, [ + 'data' => 'required', + ], $messages); + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + $records = $all['data']; + DB::beginTransaction(); + try { + $successCount = 0; + foreach ($records as $record) { + $this->model->create($record); + $successCount++; + } + DB::commit(); + return $this->success(['total' => count($records), 'success_count' => $successCount]); + } catch (\Exception $exception) { + DB::rollBack(); + return $this->fail([$exception->getCode(), $exception->getMessage()]); + } + } + } diff --git a/app/Http/Controllers/Admin/TraineeStudentController.php b/app/Http/Controllers/Admin/TraineeStudentController.php new file mode 100644 index 0000000..1c53eb3 --- /dev/null +++ b/app/Http/Controllers/Admin/TraineeStudentController.php @@ -0,0 +1,217 @@ +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/trainee-students/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() + { + $all = \request()->all(); + $messages = [ + 'id.required' => 'Id必填', + ]; + $validator = Validator::make($all, [ + 'id' => 'required' + ], $messages); + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + $detail = $this->model->with(underlineToHump($all['show_relation'] ?? []))->find($all['id']); + return $this->success($detail); + } + + /** + * @OA\Post( + * path="/api/admin/trainee-students/save", + * tags={"跟班学员管理"}, + * summary="保存", + * description="", + * @OA\Parameter(name="id", in="query", @OA\Schema(type="int"), required=true, description="Id(存在更新,不存在新增)"), + * @OA\Parameter(name="name", in="query", @OA\Schema(type="string", nullable=true), description="名字"), + * @OA\Parameter(name="start_date", in="query", @OA\Schema(type="string", format="date", nullable=true), description="开始日期"), + * @OA\Parameter(name="end_date", in="query", @OA\Schema(type="string", format="date", nullable=true), description="结束日期"), + * @OA\Parameter(name="total", in="query", @OA\Schema(type="integer", nullable=true), description="加减数据(正数表示加,负数表示减)"), + * @OA\Parameter(name="remark", in="query", @OA\Schema(type="string", format="textarea", nullable=true), description="备注"), + * @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; + } + $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/trainee-students/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(); + } +} diff --git a/app/Models/Company.php b/app/Models/Company.php index 71adeef..0fbe836 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -344,9 +344,27 @@ class Company extends SoftDeletesModel $stockCodePattern = '/\.(SWR|SW|WR|SS|RS|SB|PK|TO|AX|WS|PR|DB|UN|RT|WT|SH|SZ|BJ|TW|HK|SG|US|DE|FR|JP|KR|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|U|V|W|X|Y|Z)(?![A-Za-z0-9])/i'; $hasStockCode = preg_match($stockCodePattern, $company->company_tag); - // 检查是否包含"新三板" - $hasXinsanban = strpos($company->company_tag, '新三板') !== false; - // 如果匹配到股票代码或包含"新三板",则标记为上市 + + // 不属于新三板上市公司的关键字(需要排除) + $excludeXinsanbanKeywords = [ + '新三板摘牌', + '新三板挂牌审核', + '新三板终止', + '新三板退市', + '新三板撤销', + '新三板注销', + '新三板中止', + ]; + + // 检查是否包含排除关键字 + $hasExcludeKeyword = array_reduce($excludeXinsanbanKeywords, function ($carry, $keyword) use ($company) { + return $carry || strpos($company->company_tag, $keyword) !== false; + }, false); + + // 检查是否包含"新三板",且不包含排除关键字 + $hasXinsanban = !$hasExcludeKeyword && strpos($company->company_tag, '新三板') !== false; + + // 如果匹配到股票代码或包含"新三板"(且非排除关键字),则标记为上市 $newMarketStatus = ($hasStockCode || $hasXinsanban) ? 1 : 0; // 只有状态变化才更新 diff --git a/app/Models/TraineeStudent.php b/app/Models/TraineeStudent.php new file mode 100644 index 0000000..6ef9fe2 --- /dev/null +++ b/app/Models/TraineeStudent.php @@ -0,0 +1,8 @@ +id(); + $table->integer('admin_id')->nullable(); + $table->integer('department_id')->nullable(); + $table->string('name')->nullable()->comment('名字'); + $table->date('start_date')->nullable()->comment('开始日期'); + $table->date('end_date')->nullable()->comment('结束日期'); + $table->integer('total')->default(0)->comment('加减数据(正数表示加,负数表示减)'); + $table->text('remark')->nullable()->comment('备注'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('trainee_students'); + } +}; diff --git a/database/migrations/2026_01_17_095245_add_fields_to_employee_participations_table.php b/database/migrations/2026_01_17_095245_add_fields_to_employee_participations_table.php new file mode 100644 index 0000000..ee8fd39 --- /dev/null +++ b/database/migrations/2026_01_17_095245_add_fields_to_employee_participations_table.php @@ -0,0 +1,33 @@ +string('company_name')->nullable()->comment('公司名字')->after('course_name'); + $table->string('name')->nullable()->comment('姓名')->after('company_name'); + $table->string('department')->nullable()->comment('部门')->after('name'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('employee_participations', function (Blueprint $table) { + $table->dropColumn(['company_name', 'name', 'department']); + }); + } +}; diff --git a/routes/api.php b/routes/api.php index 7196cf7..7be9ba6 100755 --- a/routes/api.php +++ b/routes/api.php @@ -283,6 +283,14 @@ Route::group(["namespace" => "Admin", "prefix" => "admin"], function () { Route::get('employee-participations/show', [\App\Http\Controllers\Admin\EmployeeParticipationController::class, "show"]); Route::post('employee-participations/save', [\App\Http\Controllers\Admin\EmployeeParticipationController::class, "save"]); Route::get('employee-participations/destroy', [\App\Http\Controllers\Admin\EmployeeParticipationController::class, "destroy"]); + Route::post('employee-participations/excel-show', [\App\Http\Controllers\Admin\EmployeeParticipationController::class, "excelShow"]); + Route::post('employee-participations/import', [\App\Http\Controllers\Admin\EmployeeParticipationController::class, "import"]); + + // 跟班学员 + Route::get('trainee-students/index', [\App\Http\Controllers\Admin\TraineeStudentController::class, "index"]); + Route::get('trainee-students/show', [\App\Http\Controllers\Admin\TraineeStudentController::class, "show"]); + Route::post('trainee-students/save', [\App\Http\Controllers\Admin\TraineeStudentController::class, "save"]); + Route::get('trainee-students/destroy', [\App\Http\Controllers\Admin\TraineeStudentController::class, "destroy"]); // 统计数据配置管理 Route::get('statistics-configs/index', [\App\Http\Controllers\Admin\StatisticsConfigController::class, "index"]);