소스 검색

feat:安全教育培训新增签到名单功能

sunqijun 2 주 전
부모
커밋
aa99bff947

+ 24 - 1
src/api/production-education-training-plan-dept/index.ts

@@ -160,6 +160,29 @@ export function queryEducationAndTrainingProgramDetail(id: string | number) {
   });
 }
 
+/**
+ * 教育培训计划管理(部门)-签到部门名单
+ */
+export function querySignInDepartmentList(data) {
+  return http.request({
+    url: `/educationTrainingPlanIssuance/querySignInDepartmentList`,
+    method: 'post',
+    data,
+  });
+}
+
+/**
+ * 教育培训计划管理(部门)-导出签到部门名单
+ */
+export function exportSignInDepartmentList(data) {
+  return http.request({
+    url: `/educationTrainingPlanIssuance/exportSignInDepartmentList`,
+    method: 'post',
+    responseType: 'blob',
+    data,
+  }, { isTransformResponse: false });
+}
+
 /**
  * @description: 导出
  * @param {ProductionSafetyFileQuery} params
@@ -172,7 +195,7 @@ export function exportTableData(params: ProductionSafetyFileQuery){
         method: 'post',
         responseType: 'blob',
         params,
-        },
+    },
         { isTransformResponse: false },
     );
 }

+ 194 - 6
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/components/educationTrainingPlanManagementDeptDetail.vue

@@ -102,6 +102,7 @@
                 <el-button link type="primary" @click="handleEdit(scope.row)"> 编辑 </el-button>
                 <el-button link type="primary" @click="handleDelete(scope.row)"> 删除 </el-button>
                 <el-button link type="primary" @click="handleView(scope.row)"> 查看 </el-button>
+                <el-button link type="primary" @click="handleSignInList(scope.row)"> 签到名单 </el-button>
               </div>
             </template>
           </BasicTable>
@@ -109,6 +110,70 @@
       </el-card>
     </div>
     <AddTrainingInformation :state="type" v-model:visible="showAddTrainingInfo" :currentId="currentTableId" @save-success="handleSearch" />
+    <!-- 签到名单 -->
+    <el-dialog v-model="signInDialogVisible" width="70%" :title="'签到名单'">
+        <el-form>
+            <el-row >
+                <el-col :span="16">
+                    <el-row :gutter="12">
+                        <el-col :span="6">
+                            <el-form-item>
+                                <el-input v-model="signInParams.queryParam.keywords" placeholder="搜索工号/姓名" clearable />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :span="8">
+                            <el-form-item>
+                                <el-select v-model="signInParams.queryParam.deptIds" collapse-tags collapse-tags-tooltip :max-collapse-tags="1" multiple  clearable placeholder="请选择使用部门" style="width: 100%;">
+                                    <el-option :label="item.deptName" :value="item.id"  v-for="item in deptTreeOne" :key="item.id" />
+                                </el-select>
+                                <!-- <el-cascader
+                                    v-model="signInParams.queryParam.deptIds"
+                                    :options="deptTreeOne"
+                                    :props="deptCascaderProps"
+                                    :show-all-levels="false"
+                                    placeholder="请选择使用部门"
+                                    filterable
+                                    collapse-tags
+                                    collapse-tags-tooltip
+                                    :max-collapse-tags="2"
+                                    style="width: 100%;"
+                                    clearable
+                                /> -->
+                            </el-form-item>
+                        </el-col>
+                        <el-col :span="9">
+                            <el-form-item>
+                                <el-date-picker
+                                    v-model="signInDateRange"
+                                    type="daterange"
+                                    range-separator="至"
+                                    start-placeholder="开始时间"
+                                    end-placeholder="结束时间"
+                                    value-format="YYYY-MM-DD"
+                                    format="YYYY-MM-DD"
+                                />
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                </el-col>
+                <el-col :span="8">
+                    <div class="search-btn">
+                        <el-button type="primary" @click="handleSignInSearch"> 查询 </el-button>
+                        <el-button @click="handleSignInReset"> 重置 </el-button>
+                        <el-button @click="handleSignInExport"> 导出 </el-button>
+                    </div>
+                </el-col>
+            </el-row>
+        </el-form>
+            <div class="batch-table">
+                <BasicTable
+                    :tableData="signInTableData"
+                    :tableConfig="signInTableConfig"
+                    @update:pageSize="handleSignInSizeChange"
+                    @update:pageNumber="handleSignInCurrentChange"
+                />
+            </div>
+    </el-dialog>
   </main>
 </template>
 
@@ -121,6 +186,8 @@
     queryEducationAndTrainingProgramDetail,
     deleteTrainingInformation,
     exportEducationTrainingPlanCourseData,
+    querySignInDepartmentList,
+    exportSignInDepartmentList,
     type TableParamsType,
   } from '@/api/production-education-training-plan-dept';
   import AddTrainingInformation from './addTrainingInformation.vue';
@@ -129,7 +196,9 @@
   import { Plus } from '@element-plus/icons-vue';
   import BasicTable from '@/components/BasicTable.vue';
   import useTableConfig from '@/hooks/useTableConfigHook';
-  import { TABLE_OPTIONS, COURSE_TABLE_COLUMNS } from '../configs/tables';
+  import { TABLE_OPTIONS, COURSE_TABLE_COLUMNS, SIGN_IN_TABLE_COLUMNS, SIGN_IN_TABLE_CONFIG } from '../configs/tables';
+  import type { DeptTree } from '@/types/dept/type';
+  import { getAllDepartments } from '@/api/auth/dept';
 
   const router = useRouter();
   const route = useRoute();
@@ -162,13 +231,15 @@
 
   const { tableConfig, pagination } = useTableConfig(COURSE_TABLE_COLUMNS, TABLE_OPTIONS);
 
+  const { tableConfig:signInTableConfig, pagination:signInPagination } = useTableConfig(SIGN_IN_TABLE_COLUMNS, SIGN_IN_TABLE_CONFIG);
+
   const tableData = ref([]);
   const type = ref('add');
   const showAddTrainingInfo = ref(false);
   const currentTableId = ref('');
   // 搜索和筛选相关
   const dateRange = ref([]);
-
+  const signInDateRange = ref([]);
   const tableQuery = reactive<QueryPageRequest<TableParamsType>>({
     pageNumber: pagination.pageNumber,
     pageSize: pagination.pageSize,
@@ -179,7 +250,27 @@
       dateEnd: undefined, //dateRange.value[1],
     },
   });
-
+  const deptTreeOne = ref<DeptTree[]>([]);
+  const deptCascaderProps = {
+    expandTrigger: 'click',
+    checkStrictly: true,
+    emitPath: false,
+    value: 'id',
+    label: 'deptName',
+    multiple: true,
+  };
+  const getDeptTreeData = async () => {
+    try {
+      const res = await getAllDepartments();
+      deptTreeOne.value = res?.[0]?.children.map(item => ({
+        ...item,
+        children: []
+      }));
+    } catch (e) {
+      console.error('获取部门树失败:', e);
+      deptTreeOne.value = [];
+    }
+  };
   const handleCurrentChange = (value: number) => {
     pagination.pageNumber = value;
     tableQuery.pageNumber = value;
@@ -246,6 +337,96 @@
     showAddTrainingInfo.value = true;
   };
 
+  const signInTableData = ref([]);
+  const signInDialogVisible = ref(false);
+  const signInParams = reactive({
+    pageNumber: signInPagination.pageNumber,
+    pageSize: signInPagination.pageSize,
+    queryParam: {
+      id: undefined,
+      keywords: undefined, // 搜索工号/姓名
+      deptIds: undefined,
+      startDate: undefined,
+      endDate: undefined,
+    },
+  })
+  // 打开签到名单弹窗
+  const handleSignInList = async (row)=>{
+    signInDialogVisible.value = true;
+    signInParams.queryParam.id = row.id;
+    signInTableData.value = [];
+    getSignInList();
+  }
+ // 查询签到名单
+  const handleSignInSearch = ()=>{
+    signInParams.pageNumber = 1;
+    if(signInDateRange.value){
+        signInParams.queryParam.startDate = signInDateRange.value[0];
+        signInParams.queryParam.endDate = signInDateRange.value[1];
+    } else {
+        signInParams.queryParam.startDate = undefined;
+        signInParams.queryParam.endDate = undefined;
+    }
+    getSignInList();
+  }
+  // 重置签到名单搜索
+  const handleSignInReset = ()=>{
+    signInParams.pageNumber = 1;
+    signInParams.queryParam.keywords = undefined;
+    signInParams.queryParam.deptIds = undefined;
+    signInParams.queryParam.startDate = undefined;
+    signInParams.queryParam.endDate = undefined;
+    signInDateRange.value = [];
+    signInTableData.value = [];
+    getSignInList();
+  }
+  // 获取签到名单
+    const getSignInList = async ()=>{
+        signInTableConfig.loading = true;
+        try {
+           const res = await querySignInDepartmentList(signInParams);
+           if(res){
+                signInTableData.value = res.records || [];
+                signInPagination.total = res.totalRow;
+           }else {
+                signInTableData.value = [];
+                signInPagination.total = 0;
+           }
+        } catch (error) {
+            console.error('获取签到名单失败:', error);
+            signInTableData.value = [];
+            signInPagination.total = 0;
+        } finally {
+            signInTableConfig.loading = false;
+        }
+    }
+    // 导出签到名单
+  const handleSignInExport = async ()=>{
+    try {       
+       const response = await exportSignInDepartmentList(signInParams.queryParam)
+       if (response) {
+           const fileName = `签到名单_${new Date().toISOString().split('T')[0]}.xlsx`;
+           downloadByData(response, fileName);
+           ElMessage.success('导出成功');
+       }
+    } catch (e) {
+      console.error('导出签到名单失败:', e);
+        ElMessage.error('导出失败,请重试');
+    }
+  };
+  // 分页
+const handleSignInSizeChange = (value: number) => {
+    signInPagination.pageSize = value;
+    signInParams.pageSize = value;
+    getSignInList();
+  };
+//   分页
+  const handleSignInCurrentChange = (value: number) => {
+    signInPagination.pageNumber = value;
+    signInParams.pageNumber = value;
+    getSignInList();
+  };
+
   const handleDelete = (row) => {
     ElMessageBox.confirm(`确认删除课程「${row.courseName}」吗?`, '提示', { type: 'warning' }).then(async () => {
       await deleteTrainingInformation(row.id);
@@ -284,9 +465,10 @@
     }
   };
 
-  onMounted(() => {
-    getDetail();
-    getTableList();
+  onMounted(async () => {
+   await getDetail();
+   await getTableList();
+   await getDeptTreeData();
   });
 </script>
 
@@ -326,4 +508,10 @@
   .mb-16 {
     margin-bottom: 16px;
   }
+  .search-btn {
+    display: flex;
+    gap: 8px;
+    justify-content: flex-end;
+    align-items: flex-end;
+  }
 </style>

+ 39 - 1
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/configs/tables.ts

@@ -185,4 +185,42 @@ export const COURSE_TABLE_COLUMNS: TableColumnProps[] = [
     width: '300px',
     align: 'left',
   },
-];
+];
+
+export const SIGN_IN_TABLE_COLUMNS: TableColumnProps[] = [
+  {
+    label: '编号',
+    type: 'index',
+    align: 'center',
+    width: '80px',
+  },
+  {
+    label: '签到时间',
+    prop: 'signTime',
+    align: 'center',
+    minWidth: '200px',
+  },
+  {
+    label: '工号',
+    prop: 'staffNo',
+    align: 'center',
+    minWidth: '150px',
+  },
+  {
+    label: '姓名',
+    prop: 'realName',
+    align: 'center',
+    minWidth: '150px',
+  },
+  {
+    label: '所属部门',
+    prop: 'deptName',
+    align: 'center',
+    minWidth: '200px',
+  },
+];
+
+export const SIGN_IN_TABLE_CONFIG = {
+  ...TABLE_OPTIONS,
+//   maxHeight: '400px',
+};