xiaweibo 3 bulan lalu
induk
melakukan
e3ed6607b1

+ 152 - 0
src/api/evaluationSystem/index.ts

@@ -472,3 +472,155 @@ export function querySecurityExamineIssueAdvanced(params: QuerySecurityExamineIs
     data: params,
   });
 }
+
+/**
+ * 部门端先进个人查询请求参数(queryParam)
+ */
+export interface QuerySecurityExamineDeptAdvancedUserQueryParam {
+  psemId?: number; // 考核表ID
+  userName?: string; // 员工工号/名称
+  planStartTime?: string; // 计划开始时间
+  planEndTime?: string; // 计划结束时间
+}
+
+/**
+ * 部门端先进个人查询请求参数
+ */
+export interface QuerySecurityExamineDeptAdvancedUserParams {
+  pageNumber: number; // 页号
+  pageSize: number; // 每页数量
+  queryParam: QuerySecurityExamineDeptAdvancedUserQueryParam; // 查询参数
+}
+
+/**
+ * 部门端先进个人返回对象
+ */
+export interface EvaluationDeptAdvancedUserItem {
+  id?: number; // 记录ID
+  deptName: string; // 所属部门
+  deptId?: number; // 部门ID
+  deptUserId?: number; // 部门用户ID
+  deptUserName: string; // 部门负责人
+  deptUserLink: string; // 部门负责人联系方式
+  advUserStaffNo: string; // 员工工号
+  advUserName: string; // 先进个人姓名
+  advUserLink: string; // 先进个人联系方式(员工联系方式)
+  remark: string; // 先进个人描述
+  attachments: string; // 附件
+  planEndTime: string; // 上报日期(计划结束时间)
+}
+
+/**
+ * 查询部门端先进个人列表
+ */
+export function querySecurityExamineDeptAdvancedUser(params: QuerySecurityExamineDeptAdvancedUserParams) {
+  return http.request<QueryPageResponse<EvaluationDeptAdvancedUserItem>>({
+    url: '/securityExamine/dept/querySecurityExamineDeptAdvancedUser',
+    method: 'post',
+    data: params,
+  });
+}
+
+/**
+ * 管理员端先进个人查询请求参数(queryParam)
+ */
+export interface QuerySecurityExamineIssueAdvancedUserQueryParam {
+  psemId?: number; // 考核表ID
+  deptName?: string; // 部门名称
+  userName?: string; // 员工工号/名称
+  planStartTime?: string; // 计划开始时间
+  planEndTime?: string; // 计划结束时间
+}
+
+/**
+ * 管理员端先进个人查询请求参数
+ */
+export interface QuerySecurityExamineIssueAdvancedUserParams {
+  pageNumber: number; // 页号
+  pageSize: number; // 每页数量
+  queryParam: QuerySecurityExamineIssueAdvancedUserQueryParam; // 查询参数
+}
+
+/**
+ * 查询管理员端先进个人列表
+ */
+export function querySecurityExamineIssueAdvancedUser(params: QuerySecurityExamineIssueAdvancedUserParams) {
+  return http.request<QueryPageResponse<EvaluationDeptAdvancedUserItem>>({
+    url: '/securityExamine/admin/querySecurityExamineIssueAdvancedUser',
+    method: 'post',
+    data: params,
+  });
+}
+
+/**
+ * 保存部门端先进个人请求参数
+ */
+export interface SaveSecurityExamineDeptAdvUserRequest {
+  psemId: number; // 考核表ID
+  users: Array<{
+    deptId: number; // 部门ID
+    advUserStaffNo: string; // 员工工号
+    advUserName: string; // 先进个人姓名
+    advUserLink: string; // 先进个人联系方式
+    remark: string; // 先进个人描述
+  }>;
+}
+
+/**
+ * 保存部门端先进个人
+ */
+export function saveSecurityExamineDeptAdvUser(data: SaveSecurityExamineDeptAdvUserRequest) {
+  return http.request({
+    url: '/securityExamine/dept/saveSecurityExamineDeptAdvUser',
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 查询部门端先进个人详情
+ */
+export function querySecurityExamineDeptAdvUserDetail(id: number) {
+  return http.request<EvaluationDeptAdvancedUserItem>({
+    url: `/securityExamine/dept/querySecurityExamineDeptAdvUser?id=${id}`,
+    method: 'get',
+  });
+}
+
+/**
+ * 更新部门端先进个人请求参数
+ */
+export interface UpdateSecurityExamineDeptAdvUserRequest {
+  id: number; // 记录ID
+  psemId: number; // 考核表ID
+  deptName: string; // 部门名称
+  deptId: number; // 部门ID
+  deptUserId: number; // 部门用户ID
+  deptUserName: string; // 部门负责人姓名
+  deptUserLink: string; // 部门负责人联系方式
+  advUserStaffNo: string; // 员工工号
+  advUserName: string; // 先进个人姓名
+  advUserLink: string; // 先进个人联系方式
+  remark: string; // 先进个人描述
+}
+
+/**
+ * 更新部门端先进个人
+ */
+export function updateSecurityExamineDeptAdvUser(data: UpdateSecurityExamineDeptAdvUserRequest) {
+  return http.request({
+    url: '/securityExamine/dept/updateSecurityExamineDeptAdvUser',
+    method: 'put',
+    data,
+  });
+}
+
+/**
+ * 删除部门端先进个人
+ */
+export function deleteSecurityExamineDeptAdvUser(id: number) {
+  return http.request({
+    url: `/securityExamine/dept/deleteSecurityExamineDeptAdvUser?id=${id}`,
+    method: 'delete',
+  });
+}

+ 517 - 174
src/views/production-safety/safetyAssessment/evaluationDepartment/components/EvaluationDepartmentAdvancedPerson.vue

@@ -12,43 +12,15 @@
     </header>
     <main class="safety-platform-container__main">
       <div class="search-table-container">
-        <!-- tabs 放在搜索条件上面 -->
-        <div class="header-tabs-wrapper">
-          <el-tabs v-model="activeTab" @tab-change="handleTabChange">
-            <el-tab-pane label="先进个人信息" name="ALL" />
-          </el-tabs>
-        </div>
-
         <header>
           <div class="act-search">
             <section class="select-box">
-              <!-- 状态筛选仅在"全部"tab 下显示(包含文字和下拉框) -->
-              <div class="select-box--item" v-if="activeTab === 'ALL'">
-                <span>状态:</span>
-                <el-select
-                  v-model="tableQuery.queryParam.status"
-                  placeholder="请选择状态"
-                  clearable
-                >
-                  <el-option
-                    v-for="item in EVALUATION_SYSTEM_STATUS_OPTIONS"
-                    :key="item.value"
-                    :label="item.label"
-                    :value="item.value"
-                  />
-                </el-select>
-              </div>
               <div class="select-box--item">
-                <span>考核对象:</span>
-                <el-cascader
-                  ref="targetDeptCascaderRef"
-                  v-model="targetDeptId"
-                  :options="deptTree"
-                  :props="cascaderDeptProp"
-                  :show-all-levels="false"
-                  placeholder="请选择考核对象部门"
-                  filterable
-                  @change="handleTargetDeptChange"
+                <span>员工工号/名称:</span>
+                <el-input
+                  v-model="tableQuery.queryParam.userName"
+                  placeholder="搜索员工工号或名称"
+                  class="act-search-input"
                 />
               </div>
               <div class="select-box--item">
@@ -67,6 +39,17 @@
             <section class="search-btn">
               <el-button type="primary" @click="handleSearch">查询</el-button>
               <el-button @click="handleReset">重置</el-button>
+              <el-dropdown trigger="click" @command="selectDeptType">
+                <el-button type="primary" style="margin:0 10px;">
+                  添加
+                </el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item command="normal">普通部门</el-dropdown-item>
+                    <el-dropdown-item command="advanced">先进集体部门</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
               <el-button plain class="search-table-container--button" @click="handleExport">
                 导出
               </el-button>
@@ -82,68 +65,184 @@
             @update:pageSize="handleSizeChange"
             @update:pageNumber="handleCurrentChange"
           >
-            <template #status="scope">
-              <span>
-                {{ EVALUATION_SYSTEM_STATUS_LABEL[String(scope.row.status)] || '-' }}
-              </span>
-            </template>
-            <template #evaluationDocument="scope">
-              <div
-                class="file-container--div"
-                v-for="item in parseAttachments(scope.row.evaluationDocument)"
-                :key="item.fileUrl"
-              >
-                <img
-                  class="file-container--div__icon"
-                  @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
-                  :src="FILE_TYPE_ICON[item.fileType]"
-                />
-                <span
-                  class="file-container--div__name"
-                  @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
-                  >{{ item.fileName }}</span
-                >
-                <img
-                  class="file-container--div__download"
-                  :src="DownloadIcon"
-                  @click="downloadFile(item.fileUrl, item.fileName)"
-                />
+            <template #action="scope">
+              <div class="action-container--div" style="justify-content: left">
+                <ActionButton text="编辑" @click="handleEdit(scope.row)" />
+                <ActionButton text="删除" @click="handleDelete(scope.row)" />
               </div>
             </template>
           </BasicTable>
         </div>
       </div>
     </main>
-    <PreviewOnline ref="previewOnlineRef" />
+
+    <!-- 添加/编辑先进个人对话框 -->
+    <el-dialog
+      v-model="addDialogVisible"
+      :title="`${isEditMode ? '编辑' : '新增'}先进个人 (${deptType === 'normal' ? '普通部门' : '先进集体部门'})`"
+      width="800px"
+      :close-on-click-modal="false"
+      @close="handleDialogClose"
+    >
+      <div class="add-dialog-content">
+        <div class="description">
+          <span class="description-label">说明:</span>
+          <span class="description-text">
+            评为先进集体部门,先进个人可以申报两位员工。非先进集体部门,只能申报一位员工为先进个人。
+          </span>
+        </div>
+
+        <!-- 普通部门表单 -->
+        <el-form
+          v-if="deptType === 'normal'"
+          ref="normalFormRef"
+          :model="normalForm"
+          :rules="normalFormRules"
+          label-width="140px"
+        >
+          <el-form-item label="员工工号:" prop="employeeCode">
+            <el-input
+              v-model="normalForm.employeeCode"
+              placeholder="请输入员工工号"
+              maxlength="50"
+            />
+          </el-form-item>
+          <el-form-item label="员工姓名:" prop="employeeName">
+            <el-input
+              v-model="normalForm.employeeName"
+              placeholder="请输入员工姓名"
+              maxlength="50"
+            />
+          </el-form-item>
+          <el-form-item label="员工联系方式:" prop="employeeContact">
+            <el-input
+              v-model="normalForm.employeeContact"
+              placeholder="请输入11位手机号码"
+              maxlength="11"
+              @input="handlePhoneInput"
+            />
+          </el-form-item>
+          <el-form-item label="个人先进描述:" prop="remark">
+            <el-input
+              v-model="normalForm.remark"
+              type="textarea"
+              :rows="4"
+              placeholder="请填写个人先进获取内容描述。"
+              maxlength="300"
+              show-word-limit
+            />
+          </el-form-item>
+        </el-form>
+
+        <!-- 先进集体部门表格表单 -->
+        <div v-if="deptType === 'advanced'">
+          <el-table :data="advancedFormList" border style="width: 100%">
+            <el-table-column label="编号" width="80" align="center">
+              <template #default="{ $index }">
+                {{ $index + 1 }}
+              </template>
+            </el-table-column>
+            <el-table-column label="员工工号" prop="employeeCode">
+              <template #default="{ row, $index }">
+                <el-input
+                  v-model="row.employeeCode"
+                  placeholder="请输入..."
+                  maxlength="50"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="员工姓名" prop="employeeName">
+              <template #default="{ row }">
+                <el-input
+                  v-model="row.employeeName"
+                  placeholder="请输入..."
+                  maxlength="50"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="员工联系方式" prop="employeeContact">
+              <template #default="{ row }">
+                <el-input
+                  v-model="row.employeeContact"
+                  placeholder="请输入11位手机号码"
+                  maxlength="11"
+                  @input="(val) => handlePhoneInputForTable(row, val)"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="个人先进描述" prop="remark">
+              <template #default="{ row }">
+                <el-input
+                  v-model="row.remark"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入..."
+                  maxlength="300"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" width="150" align="center">
+              <template #default="{ $index }">
+                <el-button
+                  type="primary"
+                  link
+                  :disabled="advancedFormList.length >= 2"
+                  @click="handleAddAdvancedRow"
+                >
+                  新增
+                </el-button>
+                <el-button
+                  type="danger"
+                  link
+                  @click="handleRemoveAdvancedRow($index)"
+                >
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="handleDialogClose">取消</el-button>
+          <el-button type="primary" @click="handleSave">保存</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
   </div>
 </template>
 
 <script lang="ts" setup>
-  import { computed, onMounted, reactive, ref, watch } from 'vue';
+  import { computed, onMounted, reactive, ref } from 'vue';
   import { useRoute } from 'vue-router';
+  import { ElMessage, ElMessageBox } from 'element-plus';
+  import type { FormInstance, FormRules } from 'element-plus';
   import BasicTable from '@/components/BasicTable.vue';
   import useTableConfig from '@/hooks/useTableConfigHook';
+  import ActionButton from '@/components/ActionButton.vue';
   import { TABLE_OPTIONS } from '../../evaluationSystem/configs/tables';
   import { EVALUATION_ADVANCED_PERSON_TABLE_COLUMNS } from '../../evaluationSystem/configs/targetTables';
-  import { EVALUATION_SYSTEM_STATUS_OPTIONS, EVALUATION_SYSTEM_STATUS_LABEL } from '../../evaluationSystem/configs/status';
   import type { QueryPageRequest } from '@/types/basic-query';
-  import { getAllDepartments } from '@/api/auth/dept';
-  import type { DeptTree } from '@/types/dept/type';
   import {
-    querySecurityExamineIssue,
+    querySecurityExamineDeptAdvancedUser,
     querySecurityExamineIssueDeptDetail,
+    saveSecurityExamineDeptAdvUser,
+    deleteSecurityExamineDeptAdvUser,
+    querySecurityExamineDeptAdvUserDetail,
+    updateSecurityExamineDeptAdvUser,
+  } from '@/api/evaluationSystem';
+  import type {
+    QuerySecurityExamineDeptAdvancedUserParams,
+    EvaluationDeptAdvancedUserItem,
+    EvaluationTargetItem,
+    UpdateSecurityExamineDeptAdvUserRequest,
   } from '@/api/evaluationSystem';
-  import type { QuerySecurityExamineIssueParams, EvaluationTargetItem } from '@/api/evaluationSystem';
-  import DownloadIcon from '@/views/disaster/disaster-control/src/svg/download.svg';
-  import { downloadFile } from '@/views/disaster/utils';
-  import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
-  import { FILE_TYPE_ICON } from '@/components/UploadFiles/constants';
 
   const route = useRoute();
 
-  // tabs(ALL:全部,其它为对应状态码字符串)
-  const activeTab = ref<'ALL' | '0' | '2' | '3' | '4' | '5' | '1'>('ALL');
-
   // 表格
   const basicTableRef = ref<InstanceType<typeof BasicTable>>();
 
@@ -151,24 +250,11 @@
 
   const tableData = ref<any[]>([]);
 
-  // 部门树(复用下发考核表的部门下拉逻辑)
-  const targetDeptCascaderRef = ref();
-  const deptTree = ref<DeptTree[]>([]);
-  const targetDeptId = ref<number | null>(null);
-  const cascaderDeptProp = {
-    checkStrictly: true,
-    expandTrigger: 'hover' as const,
-    value: 'id',
-    label: 'deptName',
-    emitPath: false,
-  };
-
   const tableQuery = reactive<QueryPageRequest<any>>({
     pageNumber: pagination.pageNumber,
     pageSize: pagination.pageSize,
     queryParam: {
-      status: '',
-      target: '',
+      userName: '',
       dateRange: null as any,
       startTime: '',
       endTime: '',
@@ -183,6 +269,57 @@
 
   // 考核表详情
   const evaluationDetail = ref<Partial<EvaluationTargetItem>>({});
+  const deptId = ref<number | undefined>(undefined); // 部门ID
+  const psemId = ref<number | undefined>(undefined); // 考核表ID(从接口获取)
+  const deptUserId = ref<number | undefined>(undefined); // 部门用户ID(从接口获取)
+
+  // 添加对话框相关
+  const addDialogVisible = ref(false); // 添加对话框
+  const deptType = ref<'normal' | 'advanced'>('normal'); // 当前部门类型
+  const isEditMode = ref(false); // 是否为编辑模式
+  const currentEditRow = ref<any>(null); // 当前编辑的行数据
+  const editDetailData = ref<EvaluationDeptAdvancedUserItem | null>(null); // 编辑时的详情数据
+
+  // 普通部门表单
+  const normalFormRef = ref<FormInstance>();
+  const normalForm = reactive({
+    employeeCode: '',
+    employeeName: '',
+    employeeContact: '',
+    remark: '',
+  });
+
+  const normalFormRules: FormRules = {
+    employeeCode: [
+      { required: true, message: '请输入员工工号', trigger: 'blur' },
+    ],
+    employeeName: [
+      { required: true, message: '请输入员工姓名', trigger: 'blur' },
+    ],
+    employeeContact: [
+      { required: true, message: '请输入员工联系方式', trigger: 'blur' },
+      { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的11位手机号码', trigger: 'blur' },
+    ],
+    remark: [
+      { required: true, message: '请输入个人先进描述', trigger: 'blur' },
+      { max: 300, message: '最多输入300个字符', trigger: 'blur' },
+    ],
+  };
+
+  // 先进集体部门表单列表
+  const advancedFormList = ref<Array<{
+    employeeCode: string;
+    employeeName: string;
+    employeeContact: string;
+    remark: string;
+  }>>([
+    {
+      employeeCode: '',
+      employeeName: '',
+      employeeContact: '',
+      remark: '',
+    },
+  ]);
 
   const handleSizeChange = (value: number) => {
     pagination.pageSize = value;
@@ -199,41 +336,31 @@
   async function getTableData() {
     tableConfig.loading = true;
     try {
-      const params: QuerySecurityExamineIssueParams = {
+      const params: QuerySecurityExamineDeptAdvancedUserParams = {
         pageNumber: tableQuery.pageNumber,
         pageSize: tableQuery.pageSize,
         queryParam: {
           psemId: evaluationId.value, // 考核表ID(从路由参数获取)
+          userName: tableQuery.queryParam.userName || undefined,
           planStartTime: tableQuery.queryParam.startTime || undefined,
           planEndTime: tableQuery.queryParam.endTime || undefined,
-          deptName: tableQuery.queryParam.target || undefined,
-          status:
-            tableQuery.queryParam.status !== '' && tableQuery.queryParam.status !== null
-              ? Number(tableQuery.queryParam.status)
-              : undefined,
         },
       };
 
-      const res = await querySecurityExamineIssue(params);
+      const res = await querySecurityExamineDeptAdvancedUser(params);
       if (res) {
         // 映射返回数据字段到表格字段(先进个人信息)
-        tableData.value = res.records.map((item) => ({
-          id: item.id,
-          employeeCode: item.deptUserId || '-', // 员工工号(使用部门用户ID)
-          employeeName: item.deptUserName || '-', // 员工姓名(使用部门用户名)
+        tableData.value = res.records.map((item: EvaluationDeptAdvancedUserItem) => ({
+          id: item.id, // 记录ID(用于删除等操作)
+          employeeCode: item.advUserStaffNo || '-', // 员工工号
+          employeeName: item.advUserName || '-', // 员工姓名
+          employeeContact: item.advUserLink || '-', // 员工联系方式
           deptName: item.deptName || '-', // 所属部门
-          contactPhone: item.deptUserLink || '-', // 联系方式
-          departmentLeader: item.deptUserName || '-', // 部门负责人(暂时使用部门用户名)
-          remark: '-', // 备注(接口暂无此字段)
-          evaluationDocument: item.attachments, // 考核文档
-          plannedCompletionTime: item.planEndTime || '-', // 计划完成时间
-          status: item.status, // 状态
-          statusName: item.statusName, // 状态名称
-          // 保留原始数据,供其他操作使用
-          psemId: item.psemId,
-          deptId: item.deptId,
-          scores: item.scores,
-          scoreRank: item.scoreRank,
+          departmentLeader: item.deptUserName || '-', // 部门负责人
+          remark: item.remark || '-', // 先进个人描述
+          reportDate: item.planEndTime || '-', // 上报日期
+          // 保留原始数据,供编辑等操作使用
+          originalData: item, // 保存列表接口返回的完整原始数据
         }));
         pagination.total = res.totalRow;
       }
@@ -246,20 +373,6 @@
     }
   }
 
-  const getDeptTreeData = async () => {
-    try {
-      const res = await getAllDepartments();
-      deptTree.value = res?.[0]?.children ?? [];
-    } catch (e) {
-      console.error('获取部门树失败:', e);
-    }
-  };
-
-  const handleTargetDeptChange = () => {
-    const nodes = targetDeptCascaderRef.value?.getCheckedNodes?.();
-    tableQuery.queryParam.target = nodes?.[0]?.label ?? '';
-  };
-
   function handleSearch() {
     if (tableQuery.queryParam.dateRange && tableQuery.queryParam.dateRange.length === 2) {
       tableQuery.queryParam.startTime = tableQuery.queryParam.dateRange[0];
@@ -274,70 +387,277 @@
   }
 
   const handleReset = () => {
-    tableQuery.queryParam.status = '';
-    tableQuery.queryParam.target = '';
+    tableQuery.queryParam.userName = '';
     tableQuery.queryParam.dateRange = null;
-    targetDeptId.value = null;
     handleSearch();
   };
 
-  const handleTabChange = (name: string | number) => {
-    if (name === 'ALL') {
-      tableQuery.queryParam.status = '';
+  // 选择部门类型(从下拉菜单触发)
+  const selectDeptType = (type: 'normal' | 'advanced') => {
+    deptType.value = type;
+    addDialogVisible.value = true;
+    
+    // 如果是先进集体部门,初始化表格数据(默认1行)
+    if (type === 'advanced') {
+      advancedFormList.value = [
+        {
+          employeeCode: '',
+          employeeName: '',
+          employeeContact: '',
+          remark: '',
+        },
+      ];
+    }
+  };
+
+  // 处理电话号码输入(只允许数字)
+  const handlePhoneInput = (value: string) => {
+    // 只保留数字
+    normalForm.employeeContact = value.replace(/\D/g, '');
+  };
+
+  // 处理表格中电话号码输入(只允许数字)
+  const handlePhoneInputForTable = (row: any, value: string) => {
+    // 只保留数字
+    row.employeeContact = value.replace(/\D/g, '');
+  };
+
+  // 添加先进集体部门行
+  const handleAddAdvancedRow = () => {
+    if (advancedFormList.value.length < 2) {
+      advancedFormList.value.push({
+        employeeCode: '',
+        employeeName: '',
+        employeeContact: '',
+        remark: '',
+      });
+    }
+  };
+
+  // 删除先进集体部门行
+  const handleRemoveAdvancedRow = (index: number) => {
+    if (advancedFormList.value.length > 1) {
+      advancedFormList.value.splice(index, 1);
     } else {
-      tableQuery.queryParam.status = Number(name);
+      ElMessage.warning('至少需要保留一条记录');
     }
-    handleSearch();
   };
 
-  const handleExport = () => {
-    // TODO: 导出当前筛选结果
-    console.log('export advanced person list', tableQuery);
+  // 关闭对话框
+  const handleDialogClose = () => {
+    addDialogVisible.value = false;
+    isEditMode.value = false;
+    currentEditRow.value = null;
+    editDetailData.value = null;
+    // 重置表单
+    if (normalFormRef.value) {
+      normalFormRef.value.resetFields();
+    }
+    normalForm.employeeCode = '';
+    normalForm.employeeName = '';
+    normalForm.employeeContact = '';
+    normalForm.remark = '';
+    advancedFormList.value = [
+      {
+        employeeCode: '',
+        employeeName: '',
+        employeeContact: '',
+        remark: '',
+      },
+    ];
+    deptType.value = 'normal';
   };
 
-  // 预览
-  const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
-  const previewOnline = (url: string | undefined, type: keyof typeof FILE_TYPE_ICON) => {
-    if (url) {
-      previewOnlineRef.value?.open(url, type);
+  // 验证普通部门表单
+  const validateNormalForm = (): Promise<boolean> => {
+    return new Promise((resolve) => {
+      if (!normalFormRef.value) {
+        resolve(false);
+        return;
+      }
+      normalFormRef.value.validate((valid) => {
+        resolve(valid);
+      });
+    });
+  };
+
+  // 验证先进集体部门表单
+  const validateAdvancedForm = (): boolean => {
+    const phonePattern = /^1[3-9]\d{9}$/;
+    for (let i = 0; i < advancedFormList.value.length; i++) {
+      const item = advancedFormList.value[i];
+      if (!item.employeeCode || !item.employeeName || !item.employeeContact || !item.remark) {
+        ElMessage.warning(`请填写第${i + 1}行的所有必填项`);
+        return false;
+      }
+      if (!phonePattern.test(item.employeeContact)) {
+        ElMessage.warning(`第${i + 1}行的员工联系方式请输入正确的11位手机号码`);
+        return false;
+      }
+      if (item.remark.length > 300) {
+        ElMessage.warning(`第${i + 1}行的个人先进描述最多输入300个字符`);
+        return false;
+      }
     }
+    return true;
   };
 
-  // 解析逗号分隔的URL字符串为文件列表
-  const parseAttachments = (attachmentsStr: string | undefined): Array<{
-    fileUrl: string;
-    fileName: string;
-    fileType: string;
-  }> => {
-    if (!attachmentsStr || !attachmentsStr.trim()) {
-      return [];
+  // 保存
+  const handleSave = async () => {
+    if (!psemId.value || !deptId.value) {
+      ElMessage.error('缺少必要参数');
+      return;
     }
 
-    // 按逗号分割URL
-    const urls = attachmentsStr.split(',').map(url => url.trim()).filter(url => url);
-
-    return urls.map((url) => {
-      // 从URL中提取文件名
-      const urlParts = url.split('/');
-      const fileName = urlParts[urlParts.length - 1] || '未知文件';
-
-      // 根据文件扩展名判断文件类型
-      const extension = fileName.split('.').pop()?.toLowerCase() || '';
-      let fileType = 'pdf';
-      if (extension === 'doc' || extension === 'docx') {
-        fileType = 'word';
-      } else if (extension === 'xls' || extension === 'xlsx') {
-        fileType = 'excel';
-      } else if (extension === 'ppt' || extension === 'pptx') {
-        fileType = 'ppt';
+    let users: Array<{
+      deptId: number;
+      advUserStaffNo: string;
+      advUserName: string;
+      advUserLink: string;
+      remark: string;
+    }> = [];
+
+    if (deptType.value === 'normal') {
+      // 验证普通部门表单
+      const isValid = await validateNormalForm();
+      if (!isValid) {
+        return;
+      }
+      users = [
+        {
+          deptId: deptId.value,
+          advUserStaffNo: normalForm.employeeCode,
+          advUserName: normalForm.employeeName,
+          advUserLink: normalForm.employeeContact,
+          remark: normalForm.remark,
+        },
+      ];
+    } else {
+      // 验证先进集体部门表单
+      if (!validateAdvancedForm()) {
+        return;
       }
+      // 过滤掉空行
+      users = advancedFormList.value
+        .filter(
+          (item) =>
+            item.employeeCode || item.employeeName || item.employeeContact || item.remark,
+        )
+        .map((item) => ({
+          deptId: deptId.value!,
+          advUserStaffNo: item.employeeCode,
+          advUserName: item.employeeName,
+          advUserLink: item.employeeContact,
+          remark: item.remark,
+        }));
+    }
 
-      return {
-        fileUrl: url,
-        fileName,
-        fileType,
-      };
-    });
+    if (users.length === 0) {
+      ElMessage.warning('请至少填写一条记录');
+      return;
+    }
+
+    try {
+      if (isEditMode.value && currentEditRow.value?.id && editDetailData.value) {
+        // 编辑模式:调用更新接口
+        // 验证表单
+        const isValid = await validateNormalForm();
+        if (!isValid) {
+          return;
+        }
+        if (!psemId.value) {
+          ElMessage.error('缺少必要参数');
+          return;
+        }
+        // 使用详情接口返回的数据作为基础,但使用表单中修改后的字段
+        const updateParams: UpdateSecurityExamineDeptAdvUserRequest = {
+          id: currentEditRow.value.id,
+          psemId: psemId.value,
+          deptName: editDetailData.value.deptName,
+          deptId: editDetailData.value.deptId || deptId.value || 0,
+          deptUserId: editDetailData.value.deptUserId || deptUserId.value || 0,
+          deptUserName: editDetailData.value.deptUserName,
+          deptUserLink: editDetailData.value.deptUserLink,
+          // 使用表单中修改后的字段
+          advUserStaffNo: normalForm.employeeCode,
+          advUserName: normalForm.employeeName,
+          advUserLink: normalForm.employeeContact,
+          remark: normalForm.remark,
+        };
+        await updateSecurityExamineDeptAdvUser(updateParams);
+        ElMessage.success('更新成功');
+      } else {
+        // 新增模式:调用保存接口
+        await saveSecurityExamineDeptAdvUser({
+          psemId: psemId.value,
+          users,
+        });
+        ElMessage.success('保存成功');
+      }
+      handleDialogClose();
+      getTableData();
+    } catch (e) {
+      console.error('保存失败:', e);
+      ElMessage.error(isEditMode.value ? '更新失败' : '保存失败');
+    }
+  };
+
+  const handleEdit = async (row: any) => {
+    if (!row.id) {
+      ElMessage.error('缺少记录ID,无法编辑');
+      return;
+    }
+
+    try {
+      // 调用详情接口获取数据
+      const detail = await querySecurityExamineDeptAdvUserDetail(row.id);
+      
+      // 保存当前编辑的行数据和详情数据
+      currentEditRow.value = row;
+      editDetailData.value = detail;
+      isEditMode.value = true;
+      deptType.value = 'normal'; // 编辑时固定为普通部门
+      addDialogVisible.value = true;
+      
+      // 回填表单数据(普通部门)- 使用详情数据
+      normalForm.employeeCode = detail.advUserStaffNo || '';
+      normalForm.employeeName = detail.advUserName || '';
+      normalForm.employeeContact = detail.advUserLink || '';
+      normalForm.remark = detail.remark || '';
+    } catch (e) {
+      console.error('获取详情失败:', e);
+      ElMessage.error('获取详情失败');
+    }
+  };
+
+  const handleDelete = async (row: any) => {
+    try {
+      await ElMessageBox.confirm('确定要删除这条记录吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      });
+      
+      if (!row.id) {
+        ElMessage.error('缺少记录ID,无法删除');
+        return;
+      }
+      
+      await deleteSecurityExamineDeptAdvUser(row.id);
+      ElMessage.success('删除成功');
+      getTableData();
+    } catch (e: any) {
+      // 用户取消删除或删除失败
+      if (e !== 'cancel') {
+        console.error('删除失败:', e);
+        ElMessage.error('删除失败');
+      }
+    }
+  };
+
+  const handleExport = () => {
+    // TODO: 导出当前筛选结果
+    console.log('export advanced person list', tableQuery);
   };
 
   // 格式化日期时间
@@ -371,6 +691,10 @@
           createdUserName: res.deptUserName || '-', // 部门端可能没有创建人字段,使用部门用户名
           createdAt: res.createdAt,
         };
+        // 保存部门ID、考核表ID和部门用户ID,用于提交时使用
+        deptId.value = res.deptId;
+        psemId.value = res.psemId;
+        deptUserId.value = res.deptUserId;
       }
     } catch (e) {
       console.error('获取考核表详情失败:', e);
@@ -378,7 +702,6 @@
   };
 
   onMounted(() => {
-    getDeptTreeData();
     getTableData();
     getEvaluationDetail();
   });
@@ -418,7 +741,27 @@
     white-space: nowrap;
   }
 
-  .header-tabs-wrapper {
-    margin-bottom: 16px;
+  .add-dialog-content {
+    .description {
+      margin-bottom: 24px;
+      padding: 12px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .description-label {
+        font-weight: bold;
+        color: #333;
+      }
+
+      .description-text {
+        color: #666;
+        line-height: 1.6;
+      }
+    }
+  }
+
+
+  .dialog-footer {
+    text-align: right;
   }
 </style>

+ 15 - 36
src/views/production-safety/safetyAssessment/evaluationDepartment/evaluationDepartment.vue

@@ -24,7 +24,7 @@
                   clearable
                 >
                   <el-option
-                    v-for="item in EVALUATION_DEPARTMENT_STATUS_OPTIONS"
+                    v-for="item in EVALUATION_SYSTEM_STATUS_OPTIONS"
                     :key="item.value"
                     :label="item.label"
                     :value="item.value"
@@ -62,7 +62,7 @@
           >
             <template #status="scope">
               <span>
-                {{ EVALUATION_DEPARTMENT_STATUS_LABEL[scope.row.status] || scope.row.statusName || '-' }}
+                {{ EVALUATION_SYSTEM_STATUS_LABEL[String(scope.row.status)] || scope.row.statusName || '-' }}
               </span>
             </template>
             <template #evaluationDocument="scope">
@@ -90,17 +90,17 @@
             </template>
             <template #action="scope">
               <div class="action-container--div" style="justify-content: left">
-                <!-- 待反馈材料:显示反馈 -->
-                <template v-if="scope.row.status === 'PENDING_FEEDBACK'">
+                <!-- 待反馈(2):显示反馈 -->
+                <template v-if="Number(scope.row.status) === 2">
                   <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" />
                 </template>
-                <!-- 已完成:显示反馈和先进个人申报 -->
-                <template v-else-if="scope.row.status === 'COMPLETED'">
+                <!-- 已完成(1):显示反馈和先进个人申报 -->
+                <template v-else-if="Number(scope.row.status) === 1">
                   <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" />
                   <ActionButton text="先进个人申报" @click="handleAdvancedPerson(scope.row.id)" />
                 </template>
-                <!-- 已作废:显示反馈 -->
-                <template v-else-if="scope.row.status === 'CANCELLED'">
+                <!-- 已作废(5):显示反馈 -->
+                <template v-else-if="Number(scope.row.status) === 5">
                   <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" />
                 </template>
               </div>
@@ -119,7 +119,7 @@
   import useTableConfig from '@/hooks/useTableConfigHook';
   import ActionButton from '@/components/ActionButton.vue';
   import { TABLE_OPTIONS, EVALUATION_DEPARTMENT_TABLE_COLUMNS } from './configs/tables';
-  import { EVALUATION_DEPARTMENT_STATUS_OPTIONS, EVALUATION_DEPARTMENT_STATUS_LABEL } from './configs/status';
+  import { EVALUATION_SYSTEM_STATUS_OPTIONS, EVALUATION_SYSTEM_STATUS_LABEL } from '../evaluationSystem/configs/status';
   import { useRouter } from 'vue-router';
   import type { QueryPageRequest } from '@/types/basic-query';
   import DownloadIcon from '@/views/disaster/disaster-control/src/svg/download.svg';
@@ -143,33 +143,13 @@
     pageSize: pagination.pageSize,
     queryParam: {
       evaluationTableName: '',
-      status: '',
+      status: undefined as number | undefined,
       dateRange: null,
       startTime: '',
       endTime: '',
     },
   });
 
-  // 状态字符串到数字的映射(用于查询接口)
-  const statusStringToNumber: Record<string, number> = {
-    NOT_ISSUED: 0, // 未下发
-    COMPLETED: 1, // 已完成
-    PENDING_FEEDBACK: 2, // 待反馈材料
-    SIGNING: 3, // 签署中
-    PENDING_SIGN: 4, // 待签署
-    CANCELLED: 5, // 已作废
-  };
-
-  // 状态数字到字符串的映射(根据接口返回的数字状态转换为组件使用的字符串状态)
-  const statusNumberToString: Record<number, string> = {
-    0: 'NOT_ISSUED', // 未下发
-    1: 'COMPLETED', // 已完成
-    2: 'PENDING_FEEDBACK', // 待反馈材料
-    3: 'SIGNING', // 签署中
-    4: 'PENDING_SIGN', // 待签署
-    5: 'CANCELLED', // 已作废
-  };
-
   const handleSizeChange = (value: number) => {
     pagination.pageSize = value;
     tableQuery.pageSize = value;
@@ -196,10 +176,9 @@
         pageSize: tableQuery.pageSize,
         queryParam: {
           exName: tableQuery.queryParam.evaluationTableName || undefined,
-          status:
-            tableQuery.queryParam.status !== '' && tableQuery.queryParam.status !== null
-              ? statusStringToNumber[tableQuery.queryParam.status] ?? undefined
-              : undefined,
+          status: tableQuery.queryParam.status !== undefined && tableQuery.queryParam.status !== null
+            ? tableQuery.queryParam.status
+            : undefined,
           deptName: undefined, // 部门名称(如果需要可以添加搜索条件)
           planStartTime: tableQuery.queryParam.startTime || undefined,
           planEndTime: tableQuery.queryParam.endTime || undefined,
@@ -212,7 +191,7 @@
         tableData.value = res.records.map((item) => ({
           id: item.id,
           evaluationTableName: item.exName, // 考核表名称
-          status: statusNumberToString[item.status] || item.statusName || '', // 状态(转换为字符串
+          status: item.status, // 状态(使用数字状态码
           statusName: item.statusName, // 状态名称
           evaluationDocument: item.attachments, // 考核文档
           plannedCompletionTime: item.planEndTime || '-', // 计划完成时间(使用计划结束时间)
@@ -250,7 +229,7 @@
 
   const handleReset = () => {
     tableQuery.queryParam.evaluationTableName = '';
-    tableQuery.queryParam.status = '';
+    tableQuery.queryParam.status = undefined;
     tableQuery.queryParam.dateRange = null;
     handleSearch();
   };

+ 2 - 1
src/views/production-safety/safetyAssessment/evaluationSystem/EvaluationSystemItem.vue

@@ -50,8 +50,9 @@
         return defineAsyncComponent(() => import('./components/EvaluationSystemDetail.vue'));
       case 'evaluationSystem-target':
       case 'evaluationSystem-advanced-group':
-      case 'evaluationSystem-advanced-person':
         return defineAsyncComponent(() => import('./components/EvaluationTarget.vue'));
+      case 'evaluationSystem-advanced-person':
+        return defineAsyncComponent(() => import('./components/EvaluationSystemAdvancedPerson.vue'));
       case 'evaluationSystem-feedback':
       case 'evaluationSystem-feedback-view':
       case 'evaluationSystem-audit':

+ 812 - 0
src/views/production-safety/safetyAssessment/evaluationSystem/components/EvaluationSystemAdvancedPerson.vue

@@ -0,0 +1,812 @@
+<template>
+  <div class="safety-platform-container">
+    <header class="safety-platform-container__header">
+      <div class="evaluation-header">
+        <h1 class="evaluation-title">{{ evaluationDetail.exName || '先进个人信息' }}</h1>
+        <div class="evaluation-meta">
+          <span>考核部门: {{ evaluationDetail.deptNames || '-' }}</span>
+          <span>创建人: {{ evaluationDetail.createdUserName || '-' }}</span>
+          <span>创建时间: {{ formatDateTime(evaluationDetail.createdAt) || '-' }}</span>
+        </div>
+      </div>
+    </header>
+    <main class="safety-platform-container__main">
+      <div class="search-table-container">
+        <header>
+          <div class="act-search">
+            <section class="select-box">
+              <div class="select-box--item">
+                <span>部门:</span>
+                <el-cascader
+                  ref="deptCascaderRef"
+                  v-model="deptId"
+                  :options="deptTree"
+                  :props="cascaderDeptProp"
+                  :show-all-levels="false"
+                  placeholder="请选择部门"
+                  filterable
+                  clearable
+                  @change="handleDeptChange"
+                />
+              </div>
+              <div class="select-box--item">
+                <span>员工工号/名称:</span>
+                <el-input
+                  v-model="tableQuery.queryParam.userName"
+                  placeholder="搜索员工工号或名称"
+                  class="act-search-input"
+                />
+              </div>
+              <div class="select-box--item">
+                <span>时间范围:</span>
+                <el-date-picker
+                  v-model="tableQuery.queryParam.dateRange"
+                  type="daterange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="YYYY-MM-DD"
+                  format="YYYY-MM-DD"
+                />
+              </div>
+            </section>
+            <section class="search-btn">
+              <el-button type="primary" @click="handleSearch">查询</el-button>
+              <el-button @click="handleReset">重置</el-button>
+              <el-dropdown trigger="click" @command="selectDeptType">
+                <el-button type="primary" style="margin:0 10px;">
+                  添加
+                </el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item command="normal">普通部门</el-dropdown-item>
+                    <el-dropdown-item command="advanced">先进集体部门</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+              <el-button plain class="search-table-container--button" @click="handleExport">
+                导出
+              </el-button>
+            </section>
+          </div>
+        </header>
+
+        <div class="batch-table">
+          <BasicTable
+            ref="basicTableRef"
+            :tableData="tableData"
+            :tableConfig="tableConfig"
+            @update:pageSize="handleSizeChange"
+            @update:pageNumber="handleCurrentChange"
+          >
+            <template #action="scope">
+              <div class="action-container--div" style="justify-content: left">
+                <ActionButton text="编辑" @click="handleEdit(scope.row)" />
+                <ActionButton text="删除" @click="handleDelete(scope.row)" />
+              </div>
+            </template>
+          </BasicTable>
+        </div>
+      </div>
+    </main>
+
+    <!-- 添加/编辑先进个人对话框 -->
+    <el-dialog
+      v-model="addDialogVisible"
+      :title="`${isEditMode ? '编辑' : '新增'}先进个人 (${deptType === 'normal' ? '普通部门' : '先进集体部门'})`"
+      width="800px"
+      :close-on-click-modal="false"
+      @close="handleDialogClose"
+    >
+      <div class="add-dialog-content">
+        <div class="description">
+          <span class="description-label">说明:</span>
+          <span class="description-text">
+            评为先进集体部门,先进个人可以申报两位员工。非先进集体部门,只能申报一位员工为先进个人。
+          </span>
+        </div>
+
+        <!-- 普通部门表单 -->
+        <el-form
+          v-if="deptType === 'normal'"
+          ref="normalFormRef"
+          :model="normalForm"
+          :rules="normalFormRules"
+          label-width="140px"
+        >
+          <el-form-item label="员工工号:" prop="employeeCode">
+            <el-input
+              v-model="normalForm.employeeCode"
+              placeholder="请输入员工工号"
+              maxlength="50"
+            />
+          </el-form-item>
+          <el-form-item label="员工姓名:" prop="employeeName">
+            <el-input
+              v-model="normalForm.employeeName"
+              placeholder="请输入员工姓名"
+              maxlength="50"
+            />
+          </el-form-item>
+          <el-form-item label="员工联系方式:" prop="employeeContact">
+            <el-input
+              v-model="normalForm.employeeContact"
+              placeholder="请输入11位手机号码"
+              maxlength="11"
+              @input="handlePhoneInput"
+            />
+          </el-form-item>
+          <el-form-item label="个人先进描述:" prop="remark">
+            <el-input
+              v-model="normalForm.remark"
+              type="textarea"
+              :rows="4"
+              placeholder="请填写个人先进获取内容描述。"
+              maxlength="300"
+              show-word-limit
+            />
+          </el-form-item>
+        </el-form>
+
+        <!-- 先进集体部门表格表单 -->
+        <div v-if="deptType === 'advanced'">
+          <el-table :data="advancedFormList" border style="width: 100%">
+            <el-table-column label="编号" width="80" align="center">
+              <template #default="{ $index }">
+                {{ $index + 1 }}
+              </template>
+            </el-table-column>
+            <el-table-column label="员工工号" prop="employeeCode">
+              <template #default="{ row, $index }">
+                <el-input
+                  v-model="row.employeeCode"
+                  placeholder="请输入..."
+                  maxlength="50"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="员工姓名" prop="employeeName">
+              <template #default="{ row }">
+                <el-input
+                  v-model="row.employeeName"
+                  placeholder="请输入..."
+                  maxlength="50"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="员工联系方式" prop="employeeContact">
+              <template #default="{ row }">
+                <el-input
+                  v-model="row.employeeContact"
+                  placeholder="请输入11位手机号码"
+                  maxlength="11"
+                  @input="(val) => handlePhoneInputForTable(row, val)"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="个人先进描述" prop="remark">
+              <template #default="{ row }">
+                <el-input
+                  v-model="row.remark"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入..."
+                  maxlength="300"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" width="150" align="center">
+              <template #default="{ $index }">
+                <el-button
+                  type="primary"
+                  link
+                  :disabled="advancedFormList.length >= 2"
+                  @click="handleAddAdvancedRow"
+                >
+                  新增
+                </el-button>
+                <el-button
+                  type="danger"
+                  link
+                  @click="handleRemoveAdvancedRow($index)"
+                >
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="handleDialogClose">取消</el-button>
+          <el-button type="primary" @click="handleSave">保存</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { computed, onMounted, reactive, ref } from 'vue';
+  import { useRoute } from 'vue-router';
+  import { ElMessage, ElMessageBox } from 'element-plus';
+  import type { FormInstance, FormRules } from 'element-plus';
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import ActionButton from '@/components/ActionButton.vue';
+  import { TABLE_OPTIONS } from '../../evaluationSystem/configs/tables';
+  import { EVALUATION_ADVANCED_PERSON_TABLE_COLUMNS } from '../../evaluationSystem/configs/targetTables';
+  import type { QueryPageRequest } from '@/types/basic-query';
+  import {
+    querySecurityExamineIssueAdvancedUser,
+    querySecurityExamineDetail,
+    saveSecurityExamineDeptAdvUser,
+    deleteSecurityExamineDeptAdvUser,
+    querySecurityExamineDeptAdvUserDetail,
+    updateSecurityExamineDeptAdvUser,
+  } from '@/api/evaluationSystem';
+  import type {
+    QuerySecurityExamineIssueAdvancedUserParams,
+    EvaluationDeptAdvancedUserItem,
+    EvaluationSystemItem,
+    UpdateSecurityExamineDeptAdvUserRequest,
+  } from '@/api/evaluationSystem';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import type { DeptTree } from '@/types/dept/type';
+
+  const route = useRoute();
+
+  // 表格
+  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+
+  const { tableConfig, pagination } = useTableConfig(EVALUATION_ADVANCED_PERSON_TABLE_COLUMNS, TABLE_OPTIONS);
+
+  const tableData = ref<any[]>([]);
+
+  const tableQuery = reactive<QueryPageRequest<any>>({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {
+      deptName: '',
+      userName: '',
+      dateRange: null as any,
+      startTime: '',
+      endTime: '',
+    },
+  });
+
+  // 部门树(复用物品领取记录的部门下拉框逻辑)
+  const deptCascaderRef = ref();
+  const deptTree = ref<DeptTree[]>([]);
+  const deptId = ref<number | null>(null);
+  const cascaderDeptProp = {
+    checkStrictly: true,
+    expandTrigger: 'hover' as const,
+    value: 'id',
+    label: 'deptName',
+    emitPath: false,
+  };
+
+  const getDeptTreeData = async () => {
+    try {
+      const res = await getAllDepartments();
+      deptTree.value = res?.[0]?.children ?? [];
+    } catch (e) {
+      console.error('获取部门树失败:', e);
+    }
+  };
+
+  const handleDeptChange = () => {
+    const nodes = deptCascaderRef.value?.getCheckedNodes?.();
+    tableQuery.queryParam.deptName = nodes?.[0]?.label ?? '';
+  };
+
+  // 从路由获取考核对象ID(psemId)
+  const evaluationId = computed(() => {
+    const id = route.query.id;
+    return id ? Number(id) : undefined;
+  });
+
+  // 考核表详情
+  const evaluationDetail = ref<Partial<EvaluationSystemItem>>({});
+  const psemId = ref<number | undefined>(undefined); // 考核表ID(从接口获取)
+  const deptUserId = ref<number | undefined>(undefined); // 部门用户ID(从接口获取)
+  const currentDeptId = ref<number | undefined>(undefined); // 当前部门ID(用于保存操作)
+
+  // 添加对话框相关
+  const addDialogVisible = ref(false); // 添加对话框
+  const deptType = ref<'normal' | 'advanced'>('normal'); // 当前部门类型
+  const isEditMode = ref(false); // 是否为编辑模式
+  const currentEditRow = ref<any>(null); // 当前编辑的行数据
+  const editDetailData = ref<EvaluationDeptAdvancedUserItem | null>(null); // 编辑时的详情数据
+
+  // 普通部门表单
+  const normalFormRef = ref<FormInstance>();
+  const normalForm = reactive({
+    employeeCode: '',
+    employeeName: '',
+    employeeContact: '',
+    remark: '',
+  });
+
+  const normalFormRules: FormRules = {
+    employeeCode: [
+      { required: true, message: '请输入员工工号', trigger: 'blur' },
+    ],
+    employeeName: [
+      { required: true, message: '请输入员工姓名', trigger: 'blur' },
+    ],
+    employeeContact: [
+      { required: true, message: '请输入员工联系方式', trigger: 'blur' },
+      { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的11位手机号码', trigger: 'blur' },
+    ],
+    remark: [
+      { required: true, message: '请输入个人先进描述', trigger: 'blur' },
+      { max: 300, message: '最多输入300个字符', trigger: 'blur' },
+    ],
+  };
+
+  // 先进集体部门表单列表
+  const advancedFormList = ref<Array<{
+    employeeCode: string;
+    employeeName: string;
+    employeeContact: string;
+    remark: string;
+  }>>([
+    {
+      employeeCode: '',
+      employeeName: '',
+      employeeContact: '',
+      remark: '',
+    },
+  ]);
+
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getTableData();
+  };
+
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getTableData();
+  };
+
+  async function getTableData() {
+    tableConfig.loading = true;
+    try {
+      const params: QuerySecurityExamineIssueAdvancedUserParams = {
+        pageNumber: tableQuery.pageNumber,
+        pageSize: tableQuery.pageSize,
+        queryParam: {
+          psemId: evaluationId.value, // 考核表ID(从路由参数获取)
+          deptName: tableQuery.queryParam.deptName || undefined,
+          userName: tableQuery.queryParam.userName || undefined,
+          planStartTime: tableQuery.queryParam.startTime || undefined,
+          planEndTime: tableQuery.queryParam.endTime || undefined,
+        },
+      };
+
+      const res = await querySecurityExamineIssueAdvancedUser(params);
+      if (res) {
+        // 映射返回数据字段到表格字段(先进个人信息)
+        tableData.value = res.records.map((item: EvaluationDeptAdvancedUserItem) => ({
+          id: item.id, // 记录ID(用于删除等操作)
+          employeeCode: item.advUserStaffNo || '-', // 员工工号
+          employeeName: item.advUserName || '-', // 员工姓名
+          employeeContact: item.advUserLink || '-', // 员工联系方式
+          deptName: item.deptName || '-', // 所属部门
+          departmentLeader: item.deptUserName || '-', // 部门负责人
+          remark: item.remark || '-', // 先进个人描述
+          reportDate: item.planEndTime || '-', // 上报日期
+          // 保留原始数据,供编辑等操作使用
+          originalData: item, // 保存列表接口返回的完整原始数据
+        }));
+        pagination.total = res.totalRow;
+      }
+    } catch (e) {
+      console.error('获取先进个人信息列表失败:', e);
+      tableData.value = [];
+      pagination.total = 0;
+    } finally {
+      tableConfig.loading = false;
+    }
+  }
+
+  function handleSearch() {
+    if (tableQuery.queryParam.dateRange && tableQuery.queryParam.dateRange.length === 2) {
+      tableQuery.queryParam.startTime = tableQuery.queryParam.dateRange[0];
+      tableQuery.queryParam.endTime = tableQuery.queryParam.dateRange[1];
+    } else {
+      tableQuery.queryParam.startTime = '';
+      tableQuery.queryParam.endTime = '';
+    }
+    pagination.pageNumber = 1;
+    tableQuery.pageNumber = 1;
+    getTableData();
+  }
+
+  const handleReset = () => {
+    tableQuery.queryParam.deptName = '';
+    tableQuery.queryParam.userName = '';
+    tableQuery.queryParam.dateRange = null;
+    deptId.value = null;
+    handleSearch();
+  };
+
+  // 选择部门类型(从下拉菜单触发)
+  const selectDeptType = (type: 'normal' | 'advanced') => {
+    deptType.value = type;
+    addDialogVisible.value = true;
+    
+    // 如果是先进集体部门,初始化表格数据(默认1行)
+    if (type === 'advanced') {
+      advancedFormList.value = [
+        {
+          employeeCode: '',
+          employeeName: '',
+          employeeContact: '',
+          remark: '',
+        },
+      ];
+    }
+  };
+
+  // 处理电话号码输入(只允许数字)
+  const handlePhoneInput = (value: string) => {
+    // 只保留数字
+    normalForm.employeeContact = value.replace(/\D/g, '');
+  };
+
+  // 处理表格中电话号码输入(只允许数字)
+  const handlePhoneInputForTable = (row: any, value: string) => {
+    // 只保留数字
+    row.employeeContact = value.replace(/\D/g, '');
+  };
+
+  // 添加先进集体部门行
+  const handleAddAdvancedRow = () => {
+    if (advancedFormList.value.length < 2) {
+      advancedFormList.value.push({
+        employeeCode: '',
+        employeeName: '',
+        employeeContact: '',
+        remark: '',
+      });
+    }
+  };
+
+  // 删除先进集体部门行
+  const handleRemoveAdvancedRow = (index: number) => {
+    if (advancedFormList.value.length > 1) {
+      advancedFormList.value.splice(index, 1);
+    } else {
+      ElMessage.warning('至少需要保留一条记录');
+    }
+  };
+
+  // 关闭对话框
+  const handleDialogClose = () => {
+    addDialogVisible.value = false;
+    isEditMode.value = false;
+    currentEditRow.value = null;
+    editDetailData.value = null;
+    // 重置表单
+    if (normalFormRef.value) {
+      normalFormRef.value.resetFields();
+    }
+    normalForm.employeeCode = '';
+    normalForm.employeeName = '';
+    normalForm.employeeContact = '';
+    normalForm.remark = '';
+    advancedFormList.value = [
+      {
+        employeeCode: '',
+        employeeName: '',
+        employeeContact: '',
+        remark: '',
+      },
+    ];
+    deptType.value = 'normal';
+  };
+
+  // 验证普通部门表单
+  const validateNormalForm = (): Promise<boolean> => {
+    return new Promise((resolve) => {
+      if (!normalFormRef.value) {
+        resolve(false);
+        return;
+      }
+      normalFormRef.value.validate((valid) => {
+        resolve(valid);
+      });
+    });
+  };
+
+  // 验证先进集体部门表单
+  const validateAdvancedForm = (): boolean => {
+    const phonePattern = /^1[3-9]\d{9}$/;
+    for (let i = 0; i < advancedFormList.value.length; i++) {
+      const item = advancedFormList.value[i];
+      if (!item.employeeCode || !item.employeeName || !item.employeeContact || !item.remark) {
+        ElMessage.warning(`请填写第${i + 1}行的所有必填项`);
+        return false;
+      }
+      if (!phonePattern.test(item.employeeContact)) {
+        ElMessage.warning(`第${i + 1}行的员工联系方式请输入正确的11位手机号码`);
+        return false;
+      }
+      if (item.remark.length > 300) {
+        ElMessage.warning(`第${i + 1}行的个人先进描述最多输入300个字符`);
+        return false;
+      }
+    }
+    return true;
+  };
+
+  // 保存
+  const handleSave = async () => {
+    if (!psemId.value || !currentDeptId.value) {
+      ElMessage.error('缺少必要参数');
+      return;
+    }
+
+    let users: Array<{
+      deptId: number;
+      advUserStaffNo: string;
+      advUserName: string;
+      advUserLink: string;
+      remark: string;
+    }> = [];
+
+    if (deptType.value === 'normal') {
+      // 验证普通部门表单
+      const isValid = await validateNormalForm();
+      if (!isValid) {
+        return;
+      }
+      users = [
+        {
+          deptId: currentDeptId.value,
+          advUserStaffNo: normalForm.employeeCode,
+          advUserName: normalForm.employeeName,
+          advUserLink: normalForm.employeeContact,
+          remark: normalForm.remark,
+        },
+      ];
+    } else {
+      // 验证先进集体部门表单
+      if (!validateAdvancedForm()) {
+        return;
+      }
+      // 过滤掉空行
+      users = advancedFormList.value
+        .filter(
+          (item) =>
+            item.employeeCode || item.employeeName || item.employeeContact || item.remark,
+        )
+        .map((item) => ({
+          deptId: currentDeptId.value!,
+          advUserStaffNo: item.employeeCode,
+          advUserName: item.employeeName,
+          advUserLink: item.employeeContact,
+          remark: item.remark,
+        }));
+    }
+
+    if (users.length === 0) {
+      ElMessage.warning('请至少填写一条记录');
+      return;
+    }
+
+    try {
+      if (isEditMode.value && currentEditRow.value?.id && editDetailData.value) {
+        // 编辑模式:调用更新接口
+        // 验证表单
+        const isValid = await validateNormalForm();
+        if (!isValid) {
+          return;
+        }
+        if (!psemId.value) {
+          ElMessage.error('缺少必要参数');
+          return;
+        }
+        // 使用详情接口返回的数据作为基础,但使用表单中修改后的字段
+        const updateParams: UpdateSecurityExamineDeptAdvUserRequest = {
+          id: currentEditRow.value.id,
+          psemId: psemId.value,
+          deptName: editDetailData.value.deptName,
+          deptId: editDetailData.value.deptId || currentDeptId.value || 0,
+          deptUserId: editDetailData.value.deptUserId || deptUserId.value || 0,
+          deptUserName: editDetailData.value.deptUserName,
+          deptUserLink: editDetailData.value.deptUserLink,
+          // 使用表单中修改后的字段
+          advUserStaffNo: normalForm.employeeCode,
+          advUserName: normalForm.employeeName,
+          advUserLink: normalForm.employeeContact,
+          remark: normalForm.remark,
+        };
+        await updateSecurityExamineDeptAdvUser(updateParams);
+        ElMessage.success('更新成功');
+      } else {
+        // 新增模式:调用保存接口
+        await saveSecurityExamineDeptAdvUser({
+          psemId: psemId.value,
+          users,
+        });
+        ElMessage.success('保存成功');
+      }
+      handleDialogClose();
+      getTableData();
+    } catch (e) {
+      console.error('保存失败:', e);
+      ElMessage.error(isEditMode.value ? '更新失败' : '保存失败');
+    }
+  };
+
+  const handleEdit = async (row: any) => {
+    if (!row.id) {
+      ElMessage.error('缺少记录ID,无法编辑');
+      return;
+    }
+
+    try {
+      // 调用详情接口获取数据
+      const detail = await querySecurityExamineDeptAdvUserDetail(row.id);
+      
+      // 保存当前编辑的行数据和详情数据
+      currentEditRow.value = row;
+      editDetailData.value = detail;
+      isEditMode.value = true;
+      deptType.value = 'normal'; // 编辑时固定为普通部门
+      addDialogVisible.value = true;
+      
+      // 回填表单数据(普通部门)- 使用详情数据
+      normalForm.employeeCode = detail.advUserStaffNo || '';
+      normalForm.employeeName = detail.advUserName || '';
+      normalForm.employeeContact = detail.advUserLink || '';
+      normalForm.remark = detail.remark || '';
+    } catch (e) {
+      console.error('获取详情失败:', e);
+      ElMessage.error('获取详情失败');
+    }
+  };
+
+  const handleDelete = async (row: any) => {
+    try {
+      await ElMessageBox.confirm('确定要删除这条记录吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      });
+      
+      if (!row.id) {
+        ElMessage.error('缺少记录ID,无法删除');
+        return;
+      }
+      
+      await deleteSecurityExamineDeptAdvUser(row.id);
+      ElMessage.success('删除成功');
+      getTableData();
+    } catch (e: any) {
+      // 用户取消删除或删除失败
+      if (e !== 'cancel') {
+        console.error('删除失败:', e);
+        ElMessage.error('删除失败');
+      }
+    }
+  };
+
+  const handleExport = () => {
+    // TODO: 导出当前筛选结果
+    console.log('export advanced person list', tableQuery);
+  };
+
+  // 格式化日期时间
+  const formatDateTime = (dateTimeStr: string | undefined): string => {
+    if (!dateTimeStr) return '';
+    try {
+      const date = new Date(dateTimeStr);
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, '0');
+      const day = String(date.getDate()).padStart(2, '0');
+      const hours = String(date.getHours()).padStart(2, '0');
+      const minutes = String(date.getMinutes()).padStart(2, '0');
+      const seconds = String(date.getSeconds()).padStart(2, '0');
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    } catch (e) {
+      return dateTimeStr;
+    }
+  };
+
+  // 获取考核表详情
+  const getEvaluationDetail = async () => {
+    // 路由参数中的id是考核表ID(psemId),直接使用
+    if (!evaluationId.value) return;
+    
+    try {
+      const res = await querySecurityExamineDetail(evaluationId.value);
+      if (res) {
+        evaluationDetail.value = {
+          exName: res.exName,
+          deptNames: res.deptNames,
+          createdUserName: res.createdUserName,
+          createdAt: res.createdAt,
+        };
+        // 保存考核表ID,用于提交时使用
+        psemId.value = res.id;
+      }
+    } catch (e) {
+      console.error('获取考核表详情失败:', e);
+    }
+  };
+
+  onMounted(() => {
+    getDeptTreeData();
+    getTableData();
+    getEvaluationDetail();
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  @use '@/styles/basic-table-file.scss' as *;
+  @use '@/views/traffic/violation/style/act-search-table.scss' as *;
+
+  .safety-platform-container__header {
+    padding-bottom: 0 !important;
+  }
+
+  .evaluation-header {
+    width: 100%;
+  }
+
+  .evaluation-title {
+    font-size: 20px;
+    font-weight: bold;
+    margin: 0 0 12px 0;
+    color: #333;
+  }
+
+  .evaluation-meta {
+    margin-bottom: 12px;
+    display: flex;
+    gap: 24px;
+    font-size: 14px;
+    color: #666;
+  }
+
+  .evaluation-meta span {
+    white-space: nowrap;
+  }
+
+  .add-dialog-content {
+    .description {
+      margin-bottom: 24px;
+      padding: 12px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .description-label {
+        font-weight: bold;
+        color: #333;
+      }
+
+      .description-text {
+        color: #666;
+        line-height: 1.6;
+      }
+    }
+  }
+
+
+  .dialog-footer {
+    text-align: right;
+  }
+</style>

+ 4 - 1
src/views/production-safety/safetyAssessment/evaluationSystem/components/EvaluationSystemFeedback.vue

@@ -59,7 +59,7 @@
     <el-button @click="router.back()">取消</el-button>
     <el-button v-if="!isAudit && isSelfApproveButton" @click="openRejectDialog('review')">复核不通过</el-button>
     <el-button v-if="isAudit" @click="openRejectDialog('approve')">审核不通过</el-button>
-    <el-button type="primary" @click="handleSubmit">{{ getSubmitButtonText }}</el-button>
+    <el-button v-if="!isFromDeptView" type="primary" @click="handleSubmit">{{ getSubmitButtonText }}</el-button>
   </footer>
 
   <!-- 拒绝原因弹窗 -->
@@ -112,6 +112,9 @@
   // 判断是评分还是审核
   const isAudit = computed(() => route.query.operate === 'evaluationSystem-audit');
 
+  // 判断是否从部门考核结果视图进入(如果是,则不显示提交按钮)
+  const isFromDeptView = computed(() => route.query.fromDeptView === 'true');
+
   // 提交按钮文字
   const getSubmitButtonText = computed(() => {
     if (isAudit.value) {

+ 1 - 0
src/views/production-safety/safetyAssessment/evaluationSystem/components/EvaluationTarget.vue

@@ -645,6 +645,7 @@
       query: {
         id,
         operate: 'evaluationSystem-feedback-view',
+        fromDeptView: viewTab.value === 'dept' && operate === 'evaluationSystem-advanced-group' ? 'true' : undefined,
       },
     });
   };

+ 14 - 14
src/views/production-safety/safetyAssessment/evaluationSystem/configs/targetTables.ts

@@ -115,7 +115,7 @@ export const EVALUATION_ADVANCED_GROUP_TABLE_COLUMNS: TableColumnProps[] = [
   },
 ];
 
-// 先进个人信息表格列
+// 先进个人信息表格列(部门端)
 export const EVALUATION_ADVANCED_PERSON_TABLE_COLUMNS: TableColumnProps[] = [
   {
     label: '员工工号',
@@ -130,16 +130,16 @@ export const EVALUATION_ADVANCED_PERSON_TABLE_COLUMNS: TableColumnProps[] = [
     minWidth: '120px',
   },
   {
-    label: '所属部门',
-    prop: 'deptName',
+    label: '员工联系方式',
+    prop: 'employeeContact',
     align: 'left',
-    minWidth: '150px',
+    minWidth: '140px',
   },
   {
-    label: '联系方式',
-    prop: 'contactPhone',
+    label: '所属部门',
+    prop: 'deptName',
     align: 'left',
-    minWidth: '140px',
+    minWidth: '150px',
   },
   {
     label: '部门负责人',
@@ -148,22 +148,22 @@ export const EVALUATION_ADVANCED_PERSON_TABLE_COLUMNS: TableColumnProps[] = [
     minWidth: '140px',
   },
   {
-    label: '备注',
+    label: '先进个人描述',
     prop: 'remark',
     align: 'left',
     minWidth: '160px',
   },
   {
-    label: '考核文档',
-    prop: 'evaluationDocument',
-    slot: 'evaluationDocument',
+    label: '上报日期',
+    prop: 'reportDate',
     align: 'left',
     minWidth: '150px',
   },
   {
-    label: '计划完成时间',
-    prop: 'plannedCompletionTime',
-    align: 'left',
+    label: '操作',
+    slot: 'action',
+    fixed: 'right',
     minWidth: '150px',
+    align: 'left',
   },
 ];

+ 7 - 2
src/views/production-safety/safetyAssessment/evaluationSystem/evaluationSystem.vue

@@ -584,8 +584,13 @@
 
   // 先进个人
   const handleAdvancedIndividual = (id: number) => {
-    // TODO: 先进个人操作
-    console.log('advanced individual', id);
+    router.push({
+      name: 'EvaluationSystemItem',
+      query: {
+        id,
+        operate: 'evaluationSystem-advanced-person',
+      },
+    });
   };
 
   const handleView = (id: number) => {