all(); $list = $this->model->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 . '%'); } // 范围搜索 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/employee-participations/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->find($all['id']); return $this->success($detail); } /** * @OA\Post( * path="/api/admin/employee-participations/save", * tags={"员工参与"}, * summary="保存", * description="", * @OA\Parameter(name="id", in="query", @OA\Schema(type="int"), required=false, description="Id(存在更新,不存在新增)"), * @OA\Parameter(name="type", in="query", @OA\Schema(type="integer"), required=true, description="类型:1员工参与数,2干部培训数"), * @OA\Parameter(name="start_date", in="query", @OA\Schema(type="string", format="date"), required=false, description="开始日期"), * @OA\Parameter(name="end_date", in="query", @OA\Schema(type="string", format="date"), required=false, description="结束日期"), * @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_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", * 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; } $model->fill($all); $model->save(); DB::commit(); return $this->success($model); } catch (\Exception $exception) { DB::rollBack(); return $this->fail([$exception->getCode(), $exception->getMessage()]); } } /** * @OA\Get( * path="/api/admin/employee-participations/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\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(); // 类型映射:兼容页面文案、库字段备注、数字 $typeMapping = [ '元禾员工参与' => 1, '元和员工参与' => 1, '员工参与数' => 1, '员工参与' => 1, '1' => 1, '干部培训' => 2, '干部培训数' => 2, '2' => 2, ]; $typeNameMapping = [ 1 => '元禾员工参与', 2 => '干部培训', ]; $list = []; foreach ($dataArray as $value) { if ($value instanceof \Illuminate\Support\Collection) { $value = $value->toArray(); } if (!is_array($value)) { continue; } $row = $this->normalizeExcelRow($value); $courseName = $this->getExcelCell($row, ['课程名称']); $typeText = $this->getExcelCell($row, ['类型']); $companyName = $this->getExcelCell($row, ['公司名称', '公司名字']); $name = $this->getExcelCell($row, ['姓名']); $department = $this->getExcelCell($row, ['部门']); $total = $this->getExcelCell($row, ['数量']); // 跳过模板说明行、空行 if ($this->isExcelInstructionRow($typeText, $courseName, $companyName, $name, $department)) { continue; } $type = $this->parseParticipationType($typeText, $typeMapping); $course = null; if ($courseName) { $course = Course::where('name', $courseName)->first(); } $item = [ 'type' => $type, 'type_name' => $type ? ($typeNameMapping[$type] ?? '') : '', 'course_name' => $courseName, 'company_name' => $companyName, 'name' => $name, 'department' => $department, 'total' => $total !== null && $total !== '' ? $total : 1, ]; if ($course) { $item['start_date'] = $course->start_date; $item['end_date'] = $course->end_date; $item['course_type_id'] = $course->type; $item['course_id'] = $course->id; } else { $item['start_date'] = null; $item['end_date'] = null; $item['course_type_id'] = null; $item['course_id'] = null; } $list[] = $item; } return $this->success($list); } /** * 去掉表头空格,避免 FastExcel 读到「类型 」导致取不到值 */ private function normalizeExcelRow(array $row): array { $normalized = []; foreach ($row as $key => $cell) { $header = trim((string)$key); if ($header === '') { continue; } if (is_string($cell)) { $cell = trim($cell); } $normalized[$header] = $cell; } return $normalized; } /** * 按候选表头取值,兼容「类型:1员工参与数,2干部培训数」这类备注表头 */ private function getExcelCell(array $row, array $candidates) { foreach ($candidates as $name) { if (array_key_exists($name, $row) && $row[$name] !== null && $row[$name] !== '') { return $row[$name]; } } foreach ($row as $header => $cell) { foreach ($candidates as $name) { if (mb_strpos((string)$header, $name) !== false && $cell !== null && $cell !== '') { return $cell; } } } return null; } private function isExcelInstructionRow($typeText, $courseName, $companyName, $name, $department): bool { $hasData = !empty($courseName) || !empty($companyName) || !empty($name) || !empty($department); $typeString = is_scalar($typeText) ? trim((string)$typeText) : ''; $isTip = $typeString !== '' && (mb_strpos($typeString, '请填入') !== false || mb_strpos($typeString, '请确保') !== false); // 纯说明行才跳过;同一行如果已经填了业务数据则保留,类型按空处理 if ($isTip && !$hasData) { return true; } return $typeString === '' && !$hasData; } private function parseParticipationType($typeText, array $typeMapping): ?int { if ($typeText === null || $typeText === '' || !is_scalar($typeText)) { return null; } if (is_numeric($typeText) && (int)$typeText > 0) { $numeric = (int)$typeText; return in_array($numeric, [1, 2], true) ? $numeric : null; } $typeString = trim((string)$typeText); if (mb_strpos($typeString, '请填入') !== false || mb_strpos($typeString, '请确保') !== false) { return null; } return $typeMapping[$typeString] ?? null; } /** * @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()]); } } }