ソースを参照

feat:新增教育培训计划管理(管理员),员工培训记录卡管理模快

hewei 2 ヶ月 前
コミット
b3539516b0
23 ファイル変更2724 行追加1235 行削除
  1. 145 0
      src/api/employee-training-record-card-management/index.ts
  2. 116 0
      src/api/production-education-training-plan-dept/index.ts
  3. 116 0
      src/api/production-education-training-plan/index.ts
  4. 1 1
      src/views/production-safety/productionSafetySystem/safetyOrganizationSystemManagement/configs/form.ts
  5. 189 103
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/components/educationTrainingPlanManagementDetail.vue
  6. 125 0
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/components/issueEducationTrainingPlan.vue
  7. 44 58
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/configs/form.ts
  8. 105 18
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/configs/tables.ts
  9. 282 204
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/educationTrainingPlanManagement.vue
  10. 34 28
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/educationTrainingPlanManagementItem.vue
  11. 268 109
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/components/educationTrainingPlanManagementDeptDetail.vue
  12. 111 55
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/configs/tables.ts
  13. 252 203
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/educationTrainingPlanManagementDept.vue
  14. 30 28
      src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/educationTrainingPlanManagementDeptItem.vue
  15. 216 0
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/commonTable.vue
  16. 236 0
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/commonTable2.vue
  17. 151 110
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/employeeTrainingRecordCardManagementDetail.vue
  18. 32 0
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/fillDesc.vue
  19. 28 0
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/manageRule.vue
  20. 13 58
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/configs/form.ts
  21. 31 21
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/configs/tables.ts
  22. 165 211
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/employeeTrainingRecordCardManagement.vue
  23. 34 28
      src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/employeeTrainingRecordCardManagementItem.vue

+ 145 - 0
src/api/employee-training-record-card-management/index.ts

@@ -0,0 +1,145 @@
+/*
+ * @Author: liuJie
+ * @Date: 2026-02-13 15:28:09
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-25 10:41:24
+ * @Describe: 员工培训记录卡管理
+ */
+import { http } from '@/utils/http/axios';
+import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
+
+export interface EmployeeTableType {
+    id: number;
+    serialNum: number;
+    staffNo: number;
+    staffName: string;
+    staffBirthday: Date;
+    staffIdCard: string;
+    staffAddress: string;
+    staffImg?: string;
+    deptName: string;
+    dateOfJoining: Date;
+    highestDegree: string;
+    staffJob: string;
+    jobSeniority: string;
+    technicalLvl: string;
+    professionalTitle: string;
+    statusName: string;
+    createdUserName: string;
+    createdAt: Date;
+    updatedAt: Date;
+
+}
+
+// 分页查询参数接口
+export interface EducationStaffTrainingCardQueryParam {
+    pageNumber: number;
+    pageSize: number;
+    queryParam?: {
+        numOrName?: string;
+        status?: number | string;
+        dateOfJoiningStart?: string;
+        dateOfJoiningEnd?: string;
+    };
+}
+
+// 员工培训记录卡项接口
+export interface EducationStaffTrainingCardItem {
+    id: number;
+    logType: number;
+    pestcId: number;
+    serialNum: number;
+    logDate: Date;
+    educationContentId: number;
+    educationContent: string;
+    scoreMust: number;
+    creditHour: number;
+    score: number;
+    operationCertificateNum: string;
+    trainingCompany: string;
+    educationSign: string;
+    createdUserName: string;
+    createdAt: string;
+    updatedAt: string;
+};
+
+
+/**
+ * 分页查询员工培训记录卡列表
+ * @param data 查询参数
+ */
+export function queryEducationStaffTrainingCardPage(
+    data: EducationStaffTrainingCardQueryParam
+) {
+    return http.request<QueryPageResponse<EducationStaffTrainingCardItem>>({
+        url: `/educationStaffTrainingCard/queryEducationStaffTrainingCard`,
+        method: 'post',
+        data,
+        
+    });
+}
+
+/**
+ * 删除员工培训记录卡
+ * @param id 要删除的记录卡ID
+ */
+export function deleteEducationStaffTrainingCard(id: number) {
+    return http.request<void>({
+        url: `/educationStaffTrainingCard/deleteEducationStaffTrainingCard?id=${id}`,
+        method: 'delete',
+        
+    });
+}
+
+/**
+ * @description: 安全教育培训 员工培训记录卡-记录卡详情
+ * @return {*}
+ */
+export function getEducationStaffTrainingCardDetail(id: number) {
+    return http.request<EducationStaffTrainingCardItem>({
+        url: `/educationStaffTrainingCard/queryEducationStaffTrainingCardDetail?id=${id}`,
+        method: 'get',
+        
+    });
+}
+
+
+// ______查看详情数据_____________
+
+/**
+ * @description: 安全教育培训 员工培训记录卡-员工培训记录分页查询
+ * @return {*}
+ */
+export function getEmployeeDetailTableList(data:any){
+    return http.request<QueryPageResponse<EducationStaffTrainingCardItem>>({
+        url: `/educationStaffTrainingCard/queryEducationStaffTrainingCardLog`,
+        method: 'post',
+        data,
+        
+    }); 
+}
+
+/**
+ * @description: 安全教育培训 员工培训记录卡-编辑员工培训记录分数
+ * @return {*}
+ */
+export function updateEducationStaffTrainingCardScore(data: any) {
+    return http.request<void>({
+        url: `/educationStaffTrainingCard/updateEducationStaffTrainingCardLogScore`,
+        method: 'put',
+        data,
+        
+    });
+}
+
+/**
+ * @description: 安全教育培训 员工培训记录卡-删除员工培训记录
+ * @return {*}
+ */
+export function delateEducationStaffTrainingCardScore(id: number) {
+    return http.request<void>({
+        url: `/educationStaffTrainingCard/deleteEducationStaffTrainingCardLog?id=${id}`,
+        method: 'delete',
+        
+    });
+}

+ 116 - 0
src/api/production-education-training-plan-dept/index.ts

@@ -0,0 +1,116 @@
+/*
+ * @Author: liuJie
+ * @Date: 2026-02-10 11:05:01
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-25 15:03:19
+ * @Describe: 安全教育培训模块
+ */
+import { http } from '@/utils/http/axios';
+import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
+/**
+ * 查询参数
+ */
+export interface ProductionSafetyFileQuery {
+    keyword?: string; // 文件名称/编号(模糊查询)
+    status?: number; // 状态:1-启用,0-禁用
+    classifyName?: string; // 分类名称
+    startDate?: string; // 上传日期范围-开始日期
+    endDate?: string; // 上传日期范围-结束日期
+}
+
+// 新增、编辑表单数据类型
+export interface FormDataType {
+    id?: string; // 编辑时使用
+    trainingPlanName: string;
+    categoryName: string;
+    trainingContent: string;
+    trainingObject: string;
+    trainingCount: string;
+    trainingTime: string;
+    trainingMethod: string;
+    assessmentMethod: string;
+    responsibleDeptIds: string[];
+    studyHours: number | string; 
+}
+// -------------部门--------------
+/**
+ * 获取教育培训计划管理(部门)-列表
+ */
+export function getEducationAndTrainingProgramList(params: QueryPageRequest<ProductionSafetyFileQuery>) {
+    return http.request({
+        url: '/educationTrainingPlanIssuance/queryEducationTrainingPlanIssuance',
+        method: 'post',
+        params,
+        
+    });
+}
+/**
+ * 教育培训计划管理(部门)-新增
+ */
+export function saveEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/save',
+        method: 'post',
+        data: data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(部门)-更改
+ */
+export function updateEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/update',
+        method: 'put',
+        data: data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(部门)-下发
+ */
+export function issueEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/issue',
+        method: 'put',
+        data: data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(部门)-作废
+ */
+export function cancelEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/cancel',
+        method: 'put',
+        data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(部门)-删除
+ */
+export function deleteEducationAndTrainingProgram(id: string | number) {
+    return http.request({
+        url: `/educationTrainingPlan/delete?id=${id}`,
+        method: 'delete',
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(部门)-详情
+ */
+export function queryEducationAndTrainingProgramDetail(id: string | number) {
+    return http.request({
+        url: `/educationTrainingPlan/detail?id=${id}`,
+        method: 'get',
+        
+    });
+}
+

+ 116 - 0
src/api/production-education-training-plan/index.ts

@@ -0,0 +1,116 @@
+/*
+ * @Author: liuJie
+ * @Date: 2026-02-10 11:05:01
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-12 18:01:02
+ * @Describe: 安全教育培训模块
+ */
+import { http } from '@/utils/http/axios';
+import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
+/**
+ * 查询参数
+ */
+export interface ProductionSafetyFileQuery {
+    keyword?: string; // 文件名称/编号(模糊查询)
+    status?: number; // 状态:1-启用,0-禁用
+    classifyName?: string; // 分类名称
+    startDate?: string; // 上传日期范围-开始日期
+    endDate?: string; // 上传日期范围-结束日期
+}
+
+// 新增、编辑表单数据类型
+export interface FormDataType {
+    id?: string; // 编辑时使用
+    trainingPlanName: string;
+    categoryName: string;
+    trainingContent: string;
+    trainingObject: string;
+    trainingCount: string;
+    trainingTime: string;
+    trainingMethod: string;
+    assessmentMethod: string;
+    responsibleDeptIds: string[];
+    studyHours: number | string; 
+}
+// -------------管理端--------------
+/**
+ * 获取教育培训计划管理(管理员)-列表
+ */
+export function getEducationAndTrainingProgramList(params: QueryPageRequest<ProductionSafetyFileQuery>) {
+    return http.request({
+        url: '/educationTrainingPlan/query-page',
+        method: 'post',
+        params,
+        
+    });
+}
+/**
+ * 教育培训计划管理(管理员)-新增
+ */
+export function saveEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/save',
+        method: 'post',
+        data: data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(管理员)-更改
+ */
+export function updateEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/update',
+        method: 'put',
+        data: data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(管理员)-下发
+ */
+export function issueEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/issue',
+        method: 'put',
+        data: data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(管理员)-作废
+ */
+export function cancelEducationAndTrainingProgram(data: any) { 
+    return http.request({
+        url: '/educationTrainingPlan/cancel',
+        method: 'put',
+        data,
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(管理员)-删除
+ */
+export function deleteEducationAndTrainingProgram(id: string | number) {
+    return http.request({
+        url: `/educationTrainingPlan/delete?id=${id}`,
+        method: 'delete',
+        
+    });
+}
+
+/**
+ * 教育培训计划管理(管理员)-详情
+ */
+export function queryEducationAndTrainingProgramDetail(id: string | number) {
+    return http.request({
+        url: `/educationTrainingPlan/detail?id=${id}`,
+        method: 'get',
+        
+    });
+}
+

+ 1 - 1
src/views/production-safety/productionSafetySystem/safetyOrganizationSystemManagement/configs/form.ts

@@ -70,7 +70,7 @@ export const FORM_RULES = {
     ],
     jobDuty: [
         { required: true, message: "请填写岗位职责", trigger: "blur" },
-        { min: 0, max: 300, message: "最大字数300字", trigger: "blur" },
+        { min: 1, max: 300, message: "最大字数300字", trigger: "blur" },
     ],
     status: [
         { required: true, message: "请选择状态", trigger: "blur" },

+ 189 - 103
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/components/educationTrainingPlanManagementDetail.vue

@@ -1,127 +1,213 @@
 <template>
-  <main class="safety-platform-container__main">
-    <BasicForm
-      ref="basicFormRef"
-      :formData="ruleFormData"
-      :formRules="isViewMode ? undefined : formRules"
-      :formConfig="computedFormConfig"
-    />
-  </main>
-  <footer class="safety-platform-container__footer">
-    <el-button @click="router.back()">返回</el-button>
-    <el-button v-if="!isViewMode" type="primary" @click="handleSubmit">
-      {{ isCreateMode ? '提交' : '保存' }}
-    </el-button>
-  </footer>
+    <main class="safety-platform-container__main">
+        <el-form :model="form" :rules="rules" ref="formRef" label-width="150px" style="max-width: 600px"
+            label-position="left">
+            <!-- 分类名称 -->
+            <el-form-item label="教育培训计划名称:" prop="trainingPlanName">
+                <el-input v-model="form.trainingPlanName" placeholder="输入教育培训计划名称" :disabled="isViewMode"></el-input>
+            </el-form-item>
+
+            <!-- 分类名称 -->
+            <el-form-item label="分类名称:" prop="categoryName">
+                <el-select v-model="form.categoryName" placeholder="请选择分类名称" filterable clearable
+                    :disabled="isViewMode">
+                    <el-option v-for="item in classifyNameOptions" :key="item.value" :label="item.label"
+                        :value="item.value" />
+                </el-select>
+            </el-form-item>
+
+            <!-- 培训名称(内容) -->
+            <el-form-item label="培训名称(内容):" prop="trainingContent">
+                <el-input v-model="form.trainingContent" placeholder="输入培训名称(内容)" :disabled="isViewMode" />
+            </el-form-item>
+
+            <!-- 培训对象 -->
+            <el-form-item label="培训对象:" prop="trainingObject">
+                <el-input v-model="form.trainingObject" placeholder="输入培训对象" :disabled="isViewMode" />
+            </el-form-item>
+
+            <!-- 培训人数 -->
+            <el-form-item label="培训人数:" prop="trainingCount">
+                <el-input v-model="form.trainingCount" placeholder="输入培训人数" :disabled="isViewMode" />
+            </el-form-item>
+
+            <!-- 培训时间 -->
+            <el-form-item label="培训时间:" prop="trainingTime">
+                <el-input v-model="form.trainingTime" placeholder="输入培训时间,如按需、12月等" :disabled="isViewMode" />
+            </el-form-item>
+
+            <!-- 培训方式 -->
+            <el-form-item label="培训方式:" prop="trainingMethod">
+                <el-input v-model="form.trainingMethod" placeholder="输入培训方式,如网络等" :disabled="isViewMode" />
+            </el-form-item>
+
+            <!-- 考核方式 -->
+            <el-form-item label="考核方式:" prop="assessmentMethod">
+                <el-input v-model="form.assessmentMethod" placeholder="输入考核方式,如网上学习/答题、发放材料等" :disabled="isViewMode" />
+            </el-form-item>
+
+            <!-- 培训责任部门 -->
+            <el-form-item label="培训责任部门:" prop="responsibleDeptIds">
+                <el-cascader v-model="form.responsibleDeptIds" :options="deptTree" :props="cascaderProp" clearable
+                    collapse-tags :show-all-levels="false" :max-collapse-tags="3" placeholder="选择培训责任名称"
+                    style="width: 100%" :disabled="isViewMode" />
+            </el-form-item>
+
+            <!-- 学时 -->
+            <el-form-item label="学时:" prop="studyHours">
+                <el-input v-model.number="form.studyHours" placeholder="输入学时,如6、2、8等,单位时" :disabled="isViewMode" />
+            </el-form-item>
+        </el-form>
+        <!-- 提交按钮 -->
+        <footer class="safety-platform-container__footer">
+            <el-button @click="router.back()">返回</el-button>
+            <el-button v-if="!isViewMode" type="primary" @click="handleSubmit">
+                {{ isCreateMode ? '提交' : '保存' }}
+            </el-button>
+        </footer>
+    </main>
 </template>
 
 <script setup lang="ts">
-  import { computed, onMounted, ref } from 'vue';
-  import { useRoute, useRouter } from 'vue-router';
-  import { ElMessage } from 'element-plus';
-  import BasicForm from '@/components/BasicForm.vue';
-  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
-  import { INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES } from '../configs/form';
-  import { queryInventoryDetail, saveInventory, updateInventory } from '@/api/inventory';
-
-  const router = useRouter();
-  const route = useRoute();
-
-  const operate = computed(() => (route.query.operate as string) || 'inventory-create');
-  const currentId = computed(() => Number(route.query.id));
-
-  const isCreateMode = computed(() => operate.value === 'inventory-create');
-  const isEditMode = computed(() => operate.value === 'inventory-edit');
-  const isViewMode = computed(() => operate.value === 'inventory-view');
-
-  const { ruleFormData, formRules, ruleFormConfig, cloneRuleFormData, beforeRouteLeave } =
-    useFormConfigHook(INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES);
-
-  // 查看模式下,所有字段设为只读
-  const viewFormConfig = ref(
-    INVENTORY_FORM_CONFIG.map((item) => ({
-      ...item,
-      componentProps: {
-        ...item.componentProps,
-        disabled: true,
-      },
-    })),
-  );
-
-  const computedFormConfig = computed(() => {
-    if (isViewMode.value) {
-      return viewFormConfig.value;
+import { computed, onMounted, ref, reactive } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import type { FormInstance, FormRules } from 'element-plus';
+import { FORM_RULES } from '../configs/form';
+import { queryEducationAndTrainingProgramDetail, saveEducationAndTrainingProgram, updateEducationAndTrainingProgram, type FormDataType } from '@/api/production-education-training-plan';
+import { DeptTree } from '@/types/dept/type';
+import { getAllDepartments } from '@/api/auth/dept';
+import { debounce } from 'lodash-es';
+const router = useRouter();
+const route = useRoute();
+
+const operate = computed(() => (route.query.operate as string) || 'education-training-plan-management-create');
+const currentId = computed(() => Number(route.query.id));
+
+const isCreateMode = computed(() => operate.value === 'education-training-plan-management-create');
+const isEditMode = computed(() => operate.value === 'education-training-plan-management-edit');
+const isViewMode = computed(() => operate.value === 'education-training-plan-management-view');
+
+// 表单数据
+const form = reactive<FormDataType>({
+    trainingPlanName: '',
+    categoryName: '',
+    trainingContent: '',
+    trainingObject: '',
+    trainingCount: '',
+    trainingTime: '',
+    trainingMethod: '',
+    assessmentMethod: '',
+    responsibleDeptIds: [],
+    studyHours: '',
+});
+
+// 分类名称选项
+const classifyNameOptions = ref<Array<{ label: string; value: string }>>([
+    { label: '全员安全培训', value: '全员安全培训' },
+    { label: '新员工培训', value: '新员工培训' },
+    { label: '岗位资质培训', value: '岗位资质培训' },
+    { label: '生产作业安全培训', value: '生产作业安全培训' },
+    { label: '安全管理人员培训', value: '安全管理人员培训' },
+]);
+
+
+const cascaderProp = {
+    multiple: true,
+    expandTrigger: 'hover',
+    checkStrictly: true,
+    emitPath: false,
+    value: 'id',
+    label: 'deptName',
+};
+
+// 获取级联部门数据
+const deptTree = ref<DeptTree[]>();
+const loadDeptTreeData = async () => {
+    const result = await getAllDepartments();
+    deptTree.value = result[0].children;
+};
+
+// 表单引用
+const formRef = ref<FormInstance>();
+
+// 表单验证规则
+const rules = reactive(FORM_RULES);
+
+const handleValidate = async () => {
+    if (!formRef.value) return;
+    const res = await formRef.value.validateField();
+    return res;
+};
+const parseDeptIds = (ids: string | string[] | number[] | undefined | null): number[] => {
+    if (!ids) {
+        return [];
     }
-    return ruleFormConfig.value;
-  });
-
-  const basicFormRef = ref<InstanceType<typeof BasicForm>>();
 
-  const handleValidate = async () => {
-    if (!basicFormRef.value) return;
-    const res = await basicFormRef.value.validateForm();
-    return res;
-  };
+    if (Array.isArray(ids)) {
+        return ids.map((v: any) => Number(v)).filter(id => !isNaN(id));
+    }
 
-  const getDetail = async () => {
+    return String(ids)
+        .split(',')
+        .map(Number)
+        .filter(id => !isNaN(id));
+}
+const getDetail = async () => {
     if (!currentId.value) return;
     try {
-      const res = await queryInventoryDetail(currentId.value);
-      if (res) {
-        // 映射接口字段到表单字段
-        ruleFormData.itemName = res.stuffName; // 物品名称
-        ruleFormData.warehouseDate = res.inStoreTime ? res.inStoreTime.split('T')[0] : ''; // 入库日期(YYYY-MM-DD)
-        ruleFormData.itemQuantity = res.stuffQty; // 物品数量
-        ruleFormData.remarks = res.remark || ''; // 备注
-      }
-      cloneRuleFormData();
+        const res = await queryEducationAndTrainingProgramDetail(currentId.value);
+        if (res) {
+            Object.assign(form, {
+                ...res,
+                responsibleDeptIds: parseDeptIds(res.responsibleDeptIds)
+            })
+        }
     } catch (e) {
-      console.error('获取物品库存详情失败:', e);
-      ElMessage.error('获取详情失败');
+        console.error('获取物品库存详情失败:', e);
+        ElMessage.error('获取详情失败');
     }
-  };
+};
 
-  const handleSubmit = async () => {
+const handleSubmit = debounce(async () => {
     const res = await handleValidate();
     if (!res) return;
     try {
-      const basePayload = {
-        stuffName: ruleFormData.itemName,
-        inStoreTime: ruleFormData.warehouseDate
-          ? new Date(ruleFormData.warehouseDate).toISOString()
-          : '',
-        stuffQty: ruleFormData.itemQuantity,
-        remark: ruleFormData.remarks || '',
-      };
-
-      if (isCreateMode.value) {
-        await saveInventory(basePayload);
-        ElMessage.success('创建成功');
-      } else if (isEditMode.value && currentId.value) {
-        await updateInventory({
-          id: currentId.value,
-          ...basePayload,
-        });
-        ElMessage.success('保存成功');
-      }
-
-      router.back();
+        const basePayload = {
+            ...form,
+            responsibleDeptIds: form.responsibleDeptIds.toString()
+        };
+
+        if (isCreateMode.value) {
+            await saveEducationAndTrainingProgram(basePayload);
+            ElMessage.success('创建成功');
+        } else if (isEditMode.value && currentId.value) {
+            await updateEducationAndTrainingProgram({
+                id: currentId.value,
+                ...basePayload,
+            });
+            ElMessage.success('保存成功');
+        }
+
+        router.back();
     } catch (e) {
-      console.error('保存物品库存失败:', e);
-      ElMessage.error('保存失败,请重试');
+        console.error('保存物品库存失败:', e);
+        ElMessage.error('保存失败,请重试');
     }
-  };
+}, 1000);
 
-  onMounted(() => {
-    cloneRuleFormData();
-    beforeRouteLeave();
+onMounted(() => {
+    loadDeptTreeData()
     if (isEditMode.value || isViewMode.value) {
-      getDetail();
+        getDetail();
     }
-  });
+});
 </script>
 
 <style scoped lang="scss">
-  @use '@/styles/page-details-layout.scss' as *;
-</style>
+@use '@/styles/page-details-layout.scss' as *;
 
+.el-form-item {
+    margin-bottom: 25px;
+}
+</style>

+ 125 - 0
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/components/issueEducationTrainingPlan.vue

@@ -0,0 +1,125 @@
+<script lang="ts" setup>
+import { ref, reactive, onMounted, watch } from 'vue';
+import { queryUserGroupPage } from '@/api/system/person-group';
+import { IssueWorkPlanFormRules } from '../configs/form';
+import { DistributeParameters } from '../configs/tables'
+import { type FormInstance } from 'element-plus';
+
+const props = defineProps<{
+    data: any,
+    visible
+}>();
+const emit = defineEmits(['update:visible', 'confirm'])
+/**
+ * @description: 下发参数
+ * @return {*}
+ */
+
+const issueWorkPlanForm = reactive<DistributeParameters>({
+    id: 0,
+    groupId: "",
+    startTime: "",
+    endTime: "",
+    responsibleDeptIds: "",
+})
+const dialogVisible = ref(props.visible);
+
+watch(() => props.visible, (newVal) => {
+    dialogVisible.value = newVal;
+});
+watch(dialogVisible, (newVal) => {
+    emit('update:visible', newVal);
+});
+
+watch(() => props.data, (newData) => {
+    if (!newData) return;
+    Object.assign(issueWorkPlanForm, {
+        id: newData.id,
+        responsibleDeptIds: newData.responsibleDeptIds,
+        groupId: "",
+        startTime: "",
+        endTime: "",
+    });
+}, { immediate: true, deep: true })
+
+
+/**
+ * @description: 下发rules验证
+ * @param {*} value
+ * @return {*}
+ */
+const issueWorkPlanFormRules = ref(IssueWorkPlanFormRules)
+
+
+
+const groupList = ref<any>([]);
+// 获取级联部门分组数据
+const loadGroupTreeData = async () => {
+    queryUserGroupPage({
+        pageNumber: 1,
+        pageSize: 500,
+    }).then((res) => {
+        groupList.value = res.records;
+    });
+};
+const handleCancelIssue = () => {
+    dialogVisible.value = false;
+}
+// 表单引用
+const formRef = ref<FormInstance>();
+const handleConfirmIssue = async () => {
+    if (!formRef.value) return;
+    const res = await formRef.value.validateField();
+    if (res) {
+        emit('confirm', issueWorkPlanForm)
+        handleCancelIssue()
+    }
+};
+onMounted(() => {
+    loadGroupTreeData()
+})
+</script>
+<template>
+    <div class='content'>
+        <el-dialog v-model="dialogVisible" title="下发安全教育培训计划任务" width="500" :close-on-click-modal="false"
+            :close-on-press-escape="false" @close="handleCancelIssue">
+            <div>
+                <el-form ref="formRef" :model="issueWorkPlanForm" :rules="issueWorkPlanFormRules" label-width="150px">
+                    <!-- 培训责任部门 -->
+                    <el-form-item label="培训责任部门:" prop="responsibleDeptIds">
+                        <el-select v-model="issueWorkPlanForm.responsibleDeptIds" :disabled="true" size="large"
+                            placeholder="分组名称" style="width: 100%">
+                            <el-option :label="props.data.responsibleNames" :value="props.data.responsibleDeptIds" />
+                        </el-select>
+                    </el-form-item>
+
+                    <el-form-item label="培训责任部门责任人分组:" prop="groupId">
+                        <el-select v-model="issueWorkPlanForm.groupId" size="large" placeholder="请选择培训责任部门责任人所在分组名称"
+                            style="width: 100%">
+                            <el-option v-for="group in groupList" :key="group.id" :label="group.name"
+                                :value="group.id" />
+                        </el-select>
+                    </el-form-item>
+
+                    <el-form-item label="计划开始时间:" prop="startTime">
+                        <el-date-picker v-model="issueWorkPlanForm.startTime" type="date" placeholder="请选择完成时间"
+                            style="width: 100%" />
+                    </el-form-item>
+
+                    <el-form-item label="计划完成时间:" prop="endTime">
+                        <el-date-picker v-model="issueWorkPlanForm.endTime" type="date" placeholder="请选择完成时间"
+                            style="width: 100%" />
+                    </el-form-item>
+                </el-form>
+            </div>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button @click="handleCancelIssue">取消</el-button>
+                    <el-button type="primary" @click="handleConfirmIssue">
+                        确认
+                    </el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>

+ 44 - 58
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/configs/form.ts

@@ -1,60 +1,46 @@
-import { FormConfig } from '@/types/basic-form';
+/*
+ * @Author: liuJie
+ * @Date: 2026-02-03 17:55:50
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-12 09:49:23
+ * @Describe: file describe
+ */
 
-export const INVENTORY_FORM_CONFIG: FormConfig[] = [
-  {
-    prop: 'itemName',
-    label: '物品名称:',
-    component: 'ElInput',
-    componentProps: {
-      placeholder: '请输入物品名称',
-    },
-  },
-  {
-    prop: 'warehouseDate',
-    label: '入库日期:',
-    component: 'ElDatePicker',
-    componentProps: {
-      type: 'date',
-      placeholder: '请选择入库日期',
-      valueFormat: 'YYYY-MM-DD',
-    },
-  },
-  {
-    prop: 'itemQuantity',
-    label: '物品数量:',
-    component: 'ElInputNumber',
-    componentProps: {
-      min: 1,
-      max: 99999,
-      precision: 0, // 不允许小数点,只能输入整数
-      placeholder: '请输入物品数量',
-    },
-  },
-  {
-    label: '备注:',
-    prop: 'remarks',
-    component: 'ElInput',
-    componentProps: {
-      type: 'textarea',
-      rows: 5,
-      placeholder: '请输入备注',
-    },
-  },
-];
+export const FORM_RULES = {
+    trainingPlanName: [{ required: true, message: '请输入分类名称', trigger: 'blur' }],
+    categoryName: [{ required: true, message: '请输入分类名称', trigger: 'blur' }],
+    trainingContent: [{ required: true, message: '请输入培训名称(内容)', trigger: 'blur' }],
+    trainingObject: [{ required: true, message: '请输入培训对象', trigger: 'blur' }],
+    trainingCount: [{ required: true, message: '请输入培训人数', trigger: 'blur' }],
+    trainingTime: [{ required: true, message: '请输入培训时间', trigger: 'blur' }],
+    trainingMethod: [{ required: true, message: '请输入培训方式', trigger: 'blur' }],
+    assessmentMethod: [{ required: true, message: '请输入考核方式', trigger: 'blur' }],
+    responsibleDeptIds: [
+        { required: true, type: 'array', message: '请选择培训责任部门', trigger: 'change' },
+    ],
+    studyHours: [
+        { required: true, message: '请输入学时', trigger: 'blur' },
+        { type: 'number', message: '学时必须为数字', trigger: 'blur' }, 
+    ],
+}
 
-export const INVENTORY_FORM_DATA = {
-  itemName: '',
-  warehouseDate: '',
-  itemQuantity: 1, // 最小值为1
-  remarks: '',
-};
-
-export const INVENTORY_FORM_RULES = {
-  itemName: [{ required: true, message: '请输入物品名称', trigger: 'blur' }],
-  warehouseDate: [{ required: true, message: '请选择入库日期', trigger: 'change' }],
-  itemQuantity: [
-    { required: true, message: '请输入物品数量', trigger: 'blur' },
-    { type: 'number', min: 1, message: '物品数量不能小于1', trigger: 'blur' },
-    { type: 'number', max: 99999, message: '物品数量不能大于99999', trigger: 'blur' },
-  ],
-};
+export const  IssueWorkPlanFormRules = {
+    responsibleDeptIds:[{ required: true, message: '请选择培训责任部门', trigger: 'change' }],
+    groupId: [
+        {
+            required: true,
+            validator(_rule, value, callback) {
+                const empty =
+                    value === '' ||
+                    value === null ||
+                    value === undefined ||
+                    (Array.isArray(value) && value.length === 0);
+                if (empty) callback(new Error('请选择计划执行部门分组'));
+                else callback();
+            },
+            trigger: 'change',
+        },
+    ],
+    startTime:[{ required: true, message: '请选择计划开始日期', trigger: 'change' }],
+    endTime:[{ required: true, message: '请选择计划结束日期', trigger: 'change' }],
+}

+ 105 - 18
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/configs/tables.ts

@@ -1,3 +1,10 @@
+/*
+ * @Author: liuJie
+ * @Date: 2026-02-03 17:55:50
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-12 17:42:02
+ * @Describe: file describe
+ */
 import type { TableColumnProps } from '@/types/basic-table';
 
 // 基础表格样式配置
@@ -6,57 +13,137 @@ export const TABLE_OPTIONS = {
   loading: true,
   maxHeight: 'calc(70vh - 150px)',
 };
+// 下发参数
+export interface DistributeParameters {
+    id: string|number;
+    groupId: string;
+    startTime: string;
+    endTime: string;
+    responsibleDeptIds: string;
+};
+
+// 状态选项
+export const STATUS_OPTIONS = [
+    { label: '全部', value: '' },
+    { label: '未下发', value: 1 },
+    { label: '进行中', value: 2 },
+    { label: '已完成', value: 3 },
+    { label: '已作废', value: 4 },
+];
+
+// 状态标签映射
+export const STATUS_LABEL: Record<string, string> = {
+    '1': '未下发',
+    '2': '进行中',
+    '3': '已完成',
+    '4': '已作废',
+};
 
-export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
+export const TABLE_COLUMNS: TableColumnProps[] = [
   {
     label: '编号',
     type: 'index',
     align: 'center',
     width: '80px',
+    fixed: 'left',
   },
   {
-    label: '物品名称',
-    prop: 'itemName',
+    label: '培训名称(内容)',
+    prop: 'trainingContent',
     align: 'left',
+    minWidth: '220px',
+    fixed: 'left',
+  },
+  {
+    label: '状态',
+    prop: 'statusname',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    label: '分类名称',
+    prop: 'categoryName',
+    align: 'center',
+    minWidth: '110px',
+  },
+  {
+    label: '培训计划名称',
+    prop: 'trainingPlanName',
+    align: 'center',
+    minWidth: '140px',
+  },
+  {
+    label: '培训对象',
+    prop: 'trainingObject',
+    align: 'center',
+    minWidth: '110px',
+  },
+  {
+    label: '培训人数',
+    prop: 'trainingCount',
+    align: 'center',
     minWidth: '120px',
   },
   {
-    label: '入库日期',
-    prop: 'warehouseDate',
-    align: 'left',
+    label: '培训方式',
+    prop: 'trainingMethod',
+    align: 'center',
+    minWidth: '150px',
+  },
+  {
+    label: '培训时间',
+    prop: 'trainingTime',
+    align: 'center',
     minWidth: '120px',
   },
   {
-    label: '物品数量',
-    prop: 'itemQuantity',
+    label: '考核方式',
+    prop: 'assessmentMethod',
     align: 'center',
     minWidth: '120px',
   },
   {
-    label: '经办人',
-    prop: 'handler',
+    label: '培训责任部门',
+    prop: 'responsibleNames',
     align: 'left',
-    minWidth: '120px',
+    minWidth: '200px',
+  },
+   {
+    label: '学时',
+    prop: 'studyHours',
+    align: 'center',
+    minWidth: '80px',
   },
   {
-    label: '备注',
-    prop: 'remarks',
+    label: '培训责任部门责任人所属分组名称',
+    prop: 'groupName',
     align: 'left',
+    minWidth: '280px',
+  },
+  {
+    label: '培训责任部门责任人',
+    prop: 'responsiblePersonName',
+    align: 'center',
+    minWidth: '200px',
+  },
+   {
+    label: '计划开始时间',
+    prop: 'startTime',
+    align: 'center',
     minWidth: '150px',
   },
   {
-    label: '状态',
-    prop: 'status',
-    slot: 'status',
+    label: '计划结束时间',
+    prop: 'endTime',
     align: 'center',
-    minWidth: '100px',
+    minWidth: '150px',
   },
   {
     label: '操作',
     prop: 'action',
     slot: 'action',
     fixed: 'right',
-    width: '180px',
+    width: '300px',
     align: 'left',
   },
 ];

+ 282 - 204
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/educationTrainingPlanManagement.vue

@@ -1,264 +1,342 @@
 <template>
-  <div class="safety-platform-container">
-    <header class="safety-platform-container__header">
-      <div class="breadcrumb-title"> 物品库存管理 </div>
-    </header>
-    <main class="safety-platform-container__main">
-      <div class="search-table-container">
-        <header>
-          <div style="position: relative">
-            <el-button type="primary" class="search-table-container--button" @click="handleCreate">
-              添加
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleImport">
-              导入
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleDownload">
-              导出
-            </el-button>
-          </div>
-
-          <div class="act-search">
-            <section class="select-box">
-              <div class="select-box--item">
-                <span>物品名称:</span>
-                <el-input
-                  v-model="tableQuery.queryParam.stuffName"
-                  placeholder="搜索物品名称"
-                  class="act-search-input"
-                />
-              </div>
-              <div class="select-box--item">
-                <span>状态:</span>
-                <el-select
-                  v-model="tableQuery.queryParam.status"
-                  placeholder="请选择状态"
-                  clearable
-                >
-                  <el-option label="启用" :value="true" />
-                  <el-option label="禁用" :value="false" />
-                </el-select>
-              </div>
-            </section>
-            <section class="search-btn">
-              <el-button type="primary" @click="handleSearch">查询</el-button>
-              <el-button @click="handleReset">重置</el-button>
-            </section>
-          </div>
+    <div class="safety-platform-container">
+        <header class="safety-platform-container__header">
+            <div class="breadcrumb-title"> 教育培训计划管理</div>
         </header>
+        <main class="safety-platform-container__main">
+            <div class="search-table-container">
+                <header>
+                    <div style="position: relative">
+                        <el-button type="primary" class="search-table-container--button" @click="handleCreate">
+                            添加
+                        </el-button>
+                        <!-- <el-button plain class="search-table-container--button" @click="handleImport">
+                            导入
+                        </el-button>
+                        <el-button plain class="search-table-container--button" @click="handleDownload">
+                            导出
+                        </el-button> -->
+                    </div>
+                    <div class="act-search">
+                        <section class="select-box">
+                            <div class="select-box--item">
+                                <span>培训内容/计划名称:</span>
+                                <el-input v-model="tableQuery.queryParam.keyword" placeholder="搜索培训内容或计划名称"
+                                    class="act-search-input" />
+                            </div>
+                            <div class="select-box--item">
+                                <span>状态:</span>
+                                <el-select v-model="tableQuery.queryParam.status" placeholder="请选择状态" clearable>
+                                    <el-option v-for="item in STATUS_OPTIONS" :key="item.value" :label="item.label"
+                                        :value="item.value" />
+                                </el-select>
+                            </div>
+                            <div class="select-box--item">
+                                <span>分类名称:</span>
+                                <el-select v-model="tableQuery.queryParam.categoryName" placeholder="请选择分类名称" filterable
+                                    clearable>
+                                    <el-option v-for="item in classifyNameOptions" :key="item.value" :label="item.label"
+                                        :value="item.value" />
+                                </el-select>
+                            </div>
+                            <div>
+                                <span>计划日期范围:</span>
+                                <el-date-picker v-model="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>
+                        </section>
+                    </div>
+                </header>
 
-        <div class="batch-table">
-          <BasicTable
-            ref="basicTableRef"
-            :tableData="tableData"
-            :tableConfig="tableConfig"
-            @update:pageSize="handleSizeChange"
-            @update:pageNumber="handleCurrentChange"
-          >
-            <template #status="scope">
-              <span>
-                {{ scope.row.statusName || (scope.row.status === true || scope.row.status === 'true' ? '启用' : scope.row.status === false || scope.row.status === 'false' ? '禁用' : '-') }}
-              </span>
-            </template>
-            <template #action="scope">
-              <div class="action-container--div" style="justify-content: left">
-                <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
-                <ActionButton
-                  text="删除"
-                  :popconfirm="{
-                    title: '确定要删除?',
-                  }"
-                  @confirm="handleDelete(scope.row.id)"
-                />
-                <ActionButton text="查看" @click="handleView(scope.row.id)" />
-              </div>
-            </template>
-          </BasicTable>
-        </div>
-      </div>
-    </main>
-    <BatchImport
-      v-if="batchImportVisible"
-      :visible="batchImportVisible"
-      :import-api-url="importApiUrl"
-      :template-url="templateUrl"
-      template-name="下载模板"
-      :show-template="false"
-      @close="batchImportVisible = false"
-      @update="handleUpdate"
-    />
-  </div>
+                <div class="batch-table">
+                    <BasicTable ref="basicTableRef" :tableData="tableData" :tableConfig="tableConfig"
+                        @update:pageSize="handleSizeChange" @update:pageNumber="handleCurrentChange">
+                        <template #status="scope">
+                            <span>
+                                {{
+                                    scope.row.statusName ||
+                                    (scope.row.status === true || scope.row.status === 'true'
+                                        ? '启用'
+                                        : scope.row.status === false || scope.row.status === 'false'
+                                            ? '禁用'
+                                            : '-')
+                                }}
+                            </span>
+                        </template>
+                        <template #action="scope">
+                            <div class="action-container--div" style="justify-content: left">
+                                <!-- 状态:1-未下发 2-进行中 3-已完成 4-已作废 -->
+                                <!-- 1-未下发 -->
+                                <template v-if="scope.row.status === 1">
+                                    <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
+                                    <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                                    <ActionButton text="删除" :popconfirm="{
+                                        title: '确定要删除?',
+                                    }" @confirm="handleDelete(scope.row.id)" />
+                                    <ActionButton text="下发" @click="handleIssue(scope.row)" />
+                                </template>
+                                <!-- 2-进行中 -->
+                                <template v-else-if="scope.row.status === 2">
+                                    <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                                    <ActionButton text="作废" :popconfirm="{
+                                        title: '确定要作废?',
+                                    }" @confirm="handleCancel(scope.row.id)" />
+                                </template>
+                                <!-- 3-已完成 -->
+                                <template v-else-if="scope.row.status === 3">
+                                    <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                                </template>
+                                <!-- 其他 -->
+                                <template v-else>
+                                    <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                                    <ActionButton text="删除" :popconfirm="{
+                                        title: '确定要删除?',
+                                    }" @confirm="handleDelete(scope.row.id)" />
+                                </template>
+                            </div>
+                        </template>
+                    </BasicTable>
+                </div>
+            </div>
+        </main>
+        <IssueEducationTrainingPlan v-model:visible="issueWorkPlanDialogVisible" v-model:data="issueWorkPlanParams"
+            @confirm="handleConfirmIssue" />
+        <BatchImport v-if="batchImportVisible" :visible="batchImportVisible" :import-api-url="importApiUrl"
+            :template-url="templateUrl" template-name="下载模板" :show-template="false" @close="batchImportVisible = false"
+            @update="handleUpdate" />
+    </div>
 </template>
 
 <script setup lang="ts">
-  import { onMounted, reactive, ref } from 'vue';
-  import { ElMessage } from 'element-plus';
-  import BasicTable from '@/components/BasicTable.vue';
-  import useTableConfig from '@/hooks/useTableConfigHook';
-  import ActionButton from '@/components/ActionButton.vue';
-  import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
-  import { useRouter } from 'vue-router';
-  import type { QueryPageRequest } from '@/types/basic-query';
-  import { queryInventoryManage, deleteInventory, exportInventory } from '@/api/inventory';
-  import { downloadByData } from '@/utils/file/download';
-  import BatchImport from '@/components/batch-import/BatchImport.vue';
-  import { useGlobSetting } from '@/hooks/setting';
-  import urlJoin from 'url-join';
-
-  const router = useRouter();
-
-  // 表格
-  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+import { onMounted, reactive, ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import BasicTable from '@/components/BasicTable.vue';
+import useTableConfig from '@/hooks/useTableConfigHook';
+import ActionButton from '@/components/ActionButton.vue';
+import { TABLE_OPTIONS, TABLE_COLUMNS, STATUS_OPTIONS } from './configs/tables';
+import { useRouter } from 'vue-router';
+import type { QueryPageRequest } from '@/types/basic-query';
+import { getEducationAndTrainingProgramList, issueEducationAndTrainingProgram, cancelEducationAndTrainingProgram, deleteEducationAndTrainingProgram } from '@/api/production-education-training-plan';
+import { downloadByData } from '@/utils/file/download';
+import BatchImport from '@/components/batch-import/BatchImport.vue';
+import { useGlobSetting } from '@/hooks/setting';
+import urlJoin from 'url-join';
+import IssueEducationTrainingPlan from './components/issueEducationTrainingPlan.vue';
+const router = useRouter();
 
-  const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
+// 表格
+const basicTableRef = ref<InstanceType<typeof BasicTable>>();
 
-  const tableData = ref<any[]>([]);
+const { tableConfig, pagination } = useTableConfig(TABLE_COLUMNS, TABLE_OPTIONS);
 
-  const tableQuery = reactive<QueryPageRequest<any>>({
+const tableData = ref<any[]>([]);
+// 日期范围
+const dateRange = ref<[string, string] | null>(null);
+// 分类名称选项
+const classifyNameOptions = ref<Array<{ label: string; value: string }>>([
+    { label: '全部', value: '全部' },
+    { label: '全员安全培训', value: '全员安全培训' },
+    { label: '新员工培训', value: '新员工培训' },
+    { label: '岗位资质培训', value: '岗位资质培训' },
+    { label: '生产作业安全培训', value: '生产作业安全培训' },
+    { label: '安全管理人员培训', value: '安全管理人员培训' },
+]);
+const tableQuery = reactive<QueryPageRequest<any>>({
     pageNumber: pagination.pageNumber,
     pageSize: pagination.pageSize,
     queryParam: {
-      stuffName: '', // 物品名称
-      status: true, // 状态,默认启用
-      ids: [], // 选择数据的ID
+        keyword: "",
+        status: "",
+        categoryName: "",
+        startDate: "",
+        endDate: "",
     },
-  });
+});
 
-  const handleSizeChange = (value: number) => {
+const handleSizeChange = (value: number) => {
     pagination.pageSize = value;
     tableQuery.pageSize = value;
     getTableData();
-  };
+};
 
-  const handleCurrentChange = (value: number) => {
+const handleCurrentChange = (value: number) => {
     pagination.pageNumber = value;
     tableQuery.pageNumber = value;
     getTableData();
-  };
+};
 
-
-  async function getTableData() {
+async function getTableData() {
     tableConfig.loading = true;
     try {
-      const res = await queryInventoryManage(tableQuery);
-      if (res) {
-        // 映射返回数据字段到表格字段
-        tableData.value = res.records.map((item) => ({
-          id: item.id,
-          itemName: item.stuffName, // 物品名称
-          warehouseDate: item.inStoreTime, // 入库日期
-          itemQuantity: item.stuffQty, // 物品数量
-          handler: item.createdUserName, // 经办人
-          remarks: item.remark, // 备注
-          status: item.status, // 状态:true-启用,false-禁用
-          statusName: item.statusName, // 状态名称
-        }));
-        pagination.total = res.totalRow;
-      }
+        tableQuery.queryParam.startDate = dateRange.value ? dateRange.value[0] : '';
+        tableQuery.queryParam.endDate = dateRange.value ? dateRange.value[1] : '';
+        const res = await getEducationAndTrainingProgramList(tableQuery);
+        if (res) {
+            // 映射返回数据字段到表格字段
+            tableData.value = res.records
+            pagination.total = res.totalRow;
+        }
     } catch (e) {
-      console.error('获取物品库存列表失败:', e);
-      tableData.value = [];
-      pagination.total = 0;
+        console.error('获取列表失败:', e);
+        tableData.value = [];
+        pagination.total = 0;
     } finally {
-      tableConfig.loading = false;
+        tableConfig.loading = false;
     }
-  }
+}
 
-  const handleSearch = () => {
+const handleSearch = () => {
     pagination.pageNumber = 1;
     tableQuery.pageNumber = 1;
     getTableData();
-  };
+};
 
-  const handleReset = () => {
-    tableQuery.queryParam.stuffName = '';
-    tableQuery.queryParam.status = true; // 重置为默认启用状态
-    tableQuery.queryParam.ids = [];
+const handleReset = () => {
+    pagination.pageNumber = 1;
+    Object.assign(tableQuery, {
+        pageNumber: 1,
+        pageSize: pagination.pageSize,
+        queryParam: {
+            keyword: "",
+            status: "",
+            categoryName: "",
+            startDate: "",
+            endDate: "",
+        },
+    })
+    dateRange.value = null
     handleSearch();
-  };
+};
 
-  // 批量导入
-  const batchImportVisible = ref(false);
-  const { urlPrefix } = useGlobSetting();
-  const importApiUrl = ref(urlJoin(urlPrefix, '/inventory/importInventory'));
-  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-inventory-template.xlsx');
+// 批量导入
+const batchImportVisible = ref(false);
+const { urlPrefix } = useGlobSetting();
+const importApiUrl = ref(urlJoin(urlPrefix, '/inventory/importInventory'));
+const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-inventory-template.xlsx');
 
-  const handleImport = () => {
+const handleImport = () => {
     batchImportVisible.value = true;
-  };
+};
 
-  const handleUpdate = () => {
+const handleUpdate = () => {
     batchImportVisible.value = false;
     getTableData();
-  };
+};
 
-  const handleDownload = async () => {
+const handleDownload = async () => {
     try {
-      const exportParams = {
-        stuffName: tableQuery.queryParam.stuffName || undefined,
-        status: tableQuery.queryParam.status,
-        ids: tableQuery.queryParam.ids.length > 0 ? tableQuery.queryParam.ids : undefined,
-      };
-      const response = await exportInventory(exportParams);
-      if (response) {
-        const fileName = `物品库存管理_${new Date().toISOString().split('T')[0]}.xlsx`;
-        downloadByData(response, fileName);
-        ElMessage.success('导出成功');
-      }
+        const exportParams = {
+            stuffName: tableQuery.queryParam.stuffName || undefined,
+            status: tableQuery.queryParam.status,
+            ids: tableQuery.queryParam.ids.length > 0 ? tableQuery.queryParam.ids : undefined,
+        };
+        // const response = await exportInventory(exportParams);
+        // if (response) {
+        //     const fileName = `物品库存管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        //     downloadByData(response, fileName);
+        //     ElMessage.success('导出成功');
+        // }
     } catch (e) {
-      console.error('导出物品库存失败:', e);
-      ElMessage.error('导出失败,请重试');
+        console.error('导出物品库存失败:', e);
+        ElMessage.error('导出失败,请重试');
     }
-  };
-
-  const handleCreate = () => {
+};
+/**
+ * @description: 下发
+ * @param {*} id
+ * @return {*}
+ */
+const issueWorkPlanDialogVisible = ref<boolean>(false)
+const issueWorkPlanParams = reactive<any>({})
+const handleIssue = async (value) => {
+    issueWorkPlanDialogVisible.value = true
+    Object.assign(issueWorkPlanParams, value)
+};
+// 格式化时间
+const formatDate = (date) => {
+    if (!date) return '';
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    return `${year}-${month}-${day}`; // 输出:2026-02-11
+}
+const handleConfirmIssue = async (value) => {
+    try {
+        await issueEducationAndTrainingProgram({
+            ...value,
+            startTime: formatDate(value.startTime),
+            endTime: formatDate(value.endTime),
+        });
+        ElMessage.success('下发成功');
+        getTableData();
+    } catch (e) {
+        console.error('下发工作计划失败:', e);
+        ElMessage.error('下发失败,请重试');
+    }
+};
+const handleCreate = () => {
     router.push({
-      name: 'educationTrainingPlanManagementItem',
-      query: {
-        operate: 'education-training-plan-management-create',
-      },
+        name: 'educationTrainingPlanManagementItem',
+        query: {
+            operate: 'education-training-plan-management-create',
+        },
     });
-  };
+};
 
-  const handleEdit = (id: number) => {
+const handleEdit = (id: number) => {
     router.push({
-      name: 'educationTrainingPlanManagementItem',
-      query: {
-        id,
-        operate: 'education-training-plan-management-edit',
-      },
+        name: 'educationTrainingPlanManagementItem',
+        query: {
+            id,
+            operate: 'education-training-plan-management-edit',
+        },
     });
-  };
+};
 
-  const handleDelete = async (id: number) => {
+const handleDelete = async (id: number) => {
+    try {
+        await deleteEducationAndTrainingProgram(id);
+        ElMessage.success('删除成功');
+        getTableData();
+    } catch (e) {
+        console.error('删除物品库存失败:', e);
+        ElMessage.error('删除失败,请重试');
+    }
+};
+const handleCancel = async (id: number) => {
     try {
-      await deleteInventory(id);
-      ElMessage.success('删除成功');
-      getTableData();
+        await cancelEducationAndTrainingProgram({ id });
+        ElMessage.success('作废成功');
+        getTableData();
     } catch (e) {
-      console.error('删除物品库存失败:', e);
-      ElMessage.error('删除失败,请重试');
+        console.error('作废失败:', e);
+        ElMessage.error('作废失败,请重试');
     }
-  };
+};
 
-  const handleView = (id: number) => {
+const handleView = (id: number) => {
     router.push({
-      name: 'educationTrainingPlanManagementItem',
-      query: {
-        id,
-        operate: 'education-training-plan-management-view',
-      },
+        name: 'educationTrainingPlanManagementItem',
+        query: {
+            id,
+            operate: 'education-training-plan-management-view',
+        },
     });
-  };
+};
 
-  onMounted(() => {
+onMounted(() => {
     getTableData();
-  });
+});
 </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 '@/views/traffic/violation/style/act-search-table.scss' as *;
-</style>
+@use '@/styles/page-details-layout.scss' as *;
+@use '@/styles/page-main-layout.scss' as *;
+@use '@/styles/basic-table-action.scss' as *;
+@use '@/views/traffic/violation/style/act-search-table.scss' as *;
+</style>

+ 34 - 28
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagement/educationTrainingPlanManagementItem.vue

@@ -1,44 +1,50 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-02-03 17:55:50
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-11 21:12:16
+ * @Describe: file describe
+-->
 <template>
-  <div class="safety-platform-container">
-    <header class="safety-platform-container__header">
-      <BreadcrumbBack />
-      <span class="breadcrumb-title">{{ headerTitle }}</span>
-    </header>
-    <EducationTrainingPlanManagementDetail />
-  </div>
+    <div class="safety-platform-container">
+        <header class="safety-platform-container__header">
+            <BreadcrumbBack />
+            <span class="breadcrumb-title">{{ headerTitle }}</span>
+        </header>
+        <EducationTrainingPlanManagementDetail />
+    </div>
 </template>
 
 <script setup lang="ts">
-  import { computed } from 'vue';
-  import { useRoute } from 'vue-router';
-  import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
-  import EducationTrainingPlanManagementDetail from './components/educationTrainingPlanManagementDetail.vue';
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
+import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
+import EducationTrainingPlanManagementDetail from './components/educationTrainingPlanManagementDetail.vue';
 
-  const route = useRoute();
-  const operate = route.query.operate as string;
+const route = useRoute();
+const operate = route.query.operate as string;
 
-  const headerTitle = computed(() => {
+const headerTitle = computed(() => {
     switch (operate) {
-      case 'education-training-plan-management-create':
-        return '新增物品';
-      case 'education-training-plan-management-edit':
-        return '编辑物品';
-      case 'education-training-plan-management-view':
-        return '查看物品';
-      default:
-        return '未知操作';
+        case 'education-training-plan-management-create':
+            return '新增物品新增教育培训计划(管理员)';
+        case 'education-training-plan-management-edit':
+            return '编辑教育培训计划(管理员)';
+        case 'education-training-plan-management-view':
+            return '查看教育培训计划(管理员)';
+        default:
+            return '未知操作';
     }
-  });
+});
 </script>
 
 <style scoped lang="scss">
-  @use '@/styles/page-details-layout.scss' as *;
-  @use '@/styles/page-main-layout.scss' as *;
+@use '@/styles/page-details-layout.scss' as *;
+@use '@/styles/page-main-layout.scss' as *;
 
-  .safety-platform-container__header {
+.safety-platform-container__header {
     flex-direction: row !important;
     justify-content: flex-start !important;
     gap: 8px !important;
-  }
+}
 </style>
-

+ 268 - 109
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/components/educationTrainingPlanManagementDeptDetail.vue

@@ -1,127 +1,286 @@
 <template>
-  <main class="safety-platform-container__main">
-    <BasicForm
-      ref="basicFormRef"
-      :formData="ruleFormData"
-      :formRules="isViewMode ? undefined : formRules"
-      :formConfig="computedFormConfig"
-    />
-  </main>
-  <footer class="safety-platform-container__footer">
-    <el-button @click="router.back()">返回</el-button>
-    <el-button v-if="!isViewMode" type="primary" @click="handleSubmit">
-      {{ isCreateMode ? '提交' : '保存' }}
-    </el-button>
-  </footer>
+    <main class="safety-platform-container__main">
+        <div class="page-container">
+            <!-- 标题 -->
+            <el-card shadow="never" class="mb-16">
+                <h2 class="title">
+                    全员安全生产教育培训(法律法规、安全常识、警示案例等)
+                </h2>
+                <div class="meta">
+                    <span>分类名称:全员安全培训</span>
+                    <span>创建人:李小红</span>
+                    <span>创建时间:2026-01-06 12:20:30</span>
+                </div>
+            </el-card>
+
+            <!-- 基本信息 -->
+            <el-card shadow="never" class="mb-16">
+                <template #header>
+                    <strong>基本信息</strong>
+                </template>
+
+                <el-descriptions :column="2" border>
+                    <el-descriptions-item label="教育培训计划名称">
+                        2025年度生产安全教育培训计划
+                    </el-descriptions-item>
+                    <el-descriptions-item label="状态">
+                        <el-tag type="success">进行中</el-tag>
+                    </el-descriptions-item>
+
+                    <el-descriptions-item label="培训对象">
+                        全体从业人员
+                    </el-descriptions-item>
+                    <el-descriptions-item label="培训人数">
+                        约4500人
+                    </el-descriptions-item>
+
+                    <el-descriptions-item label="培训时间">
+                        11月
+                    </el-descriptions-item>
+                    <el-descriptions-item label="培训方式">
+                        网络
+                    </el-descriptions-item>
+
+                    <el-descriptions-item label="考核方式">
+                        网上学习 / 答题
+                    </el-descriptions-item>
+                    <el-descriptions-item label="培训责任部门">
+                        安全与应急管理部教育培训中心
+                    </el-descriptions-item>
+
+                    <el-descriptions-item label="学时">
+                        6时
+                    </el-descriptions-item>
+                    <el-descriptions-item label="培训分组">
+                        培训小分队分组
+                    </el-descriptions-item>
+                </el-descriptions>
+            </el-card>
+
+            <!-- 培训课程信息 -->
+            <el-card shadow="never">
+                <template #header>
+                    <strong>培训课程信息</strong>
+                </template>
+
+                <!-- 查询区 -->
+                <el-form :inline="true" class="mb-12">
+                    <el-form-item>
+                        <el-input v-model="query.name" placeholder="搜索培训课程名称" clearable />
+                    </el-form-item>
+
+                    <el-form-item>
+                        <el-date-picker v-model="query.time" type="daterange" range-separator="至"
+                            start-placeholder="开始时间" end-placeholder="结束时间" />
+                    </el-form-item>
+
+                    <el-form-item>
+                        <el-button type="primary" @click="handleSearch">
+                            查询
+                        </el-button>
+                        <el-button @click="handleExport">
+                            导出
+                        </el-button>
+                        <el-button type="primary" @click="handleAdd">
+                            新增课程
+                        </el-button>
+                    </el-form-item>
+                </el-form>
+
+                <!-- 表格 -->
+                <el-table :data="tableData" border stripe>
+                    <el-table-column prop="id" label="编号" width="80" />
+                    <el-table-column prop="trainTime" label="培训时间" />
+                    <el-table-column prop="courseName" label="培训课程名称" />
+                    <el-table-column prop="category" label="课程所属分类" />
+                    <el-table-column prop="mode" label="培训方式" width="120" />
+                    <el-table-column prop="summary" label="培训课程简述" />
+                    <el-table-column prop="teacher" label="培训课程讲师" />
+                    <el-table-column prop="group" label="计划参与人数所属分组" />
+                    <el-table-column prop="planCount" label="计划参与人数" width="140" />
+                    <el-table-column prop="signCount" label="签到人数" width="120" />
+
+                    <el-table-column label="操作" width="280" fixed="right">
+                        <template #default="{ row }">
+                            <el-button link type="primary" @click="handleEdit(row)">
+                                编辑
+                            </el-button>
+                            <el-button link type="danger" @click="handleDelete(row)">
+                                删除
+                            </el-button>
+                            <el-button link @click="handleView(row)">
+                                查看
+                            </el-button>
+                            <el-button link @click="handleSummary(row)">
+                                小结
+                            </el-button>
+                        </template>
+                    </el-table-column>
+                </el-table>
+                <div class="pagination">
+                    <el-pagination v-model:current-page="page.current" v-model:page-size="page.size"
+                        :page-sizes="[10, 20, 50, 100]" :total="page.total"
+                        layout="total, sizes, prev, pager, next, jumper" @current-change="handlePageChange"
+                        @size-change="handleSizeChange" />
+                </div>
+            </el-card>
+        </div>
+    </main>
+
 </template>
 
 <script setup lang="ts">
-  import { computed, onMounted, ref } from 'vue';
-  import { useRoute, useRouter } from 'vue-router';
-  import { ElMessage } from 'element-plus';
-  import BasicForm from '@/components/BasicForm.vue';
-  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
-  import { INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES } from '../configs/form';
-  import { queryInventoryDetail, saveInventory, updateInventory } from '@/api/inventory';
-
-  const router = useRouter();
-  const route = useRoute();
-
-  const operate = computed(() => (route.query.operate as string) || 'inventory-create');
-  const currentId = computed(() => Number(route.query.id));
-
-  const isCreateMode = computed(() => operate.value === 'inventory-create');
-  const isEditMode = computed(() => operate.value === 'inventory-edit');
-  const isViewMode = computed(() => operate.value === 'inventory-view');
-
-  const { ruleFormData, formRules, ruleFormConfig, cloneRuleFormData, beforeRouteLeave } =
-    useFormConfigHook(INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES);
-
-  // 查看模式下,所有字段设为只读
-  const viewFormConfig = ref(
-    INVENTORY_FORM_CONFIG.map((item) => ({
-      ...item,
-      componentProps: {
-        ...item.componentProps,
-        disabled: true,
-      },
-    })),
-  );
-
-  const computedFormConfig = computed(() => {
-    if (isViewMode.value) {
-      return viewFormConfig.value;
+import { computed, onMounted, ref } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus'
+
+
+const router = useRouter();
+const route = useRoute();
+
+const operate = computed(() => (route.query.operate as string) || 'education-training-plan-management-dept-view');
+const currentId = computed(() => Number(route.query.id));
+
+const isViewMode = computed(() => operate.value === 'education-training-plan-management-dept-view');
+const query = ref({
+    name: '',
+    time: []
+})
+const page = ref({
+    current: 1,
+    size: 10,
+    total: 10
+})
+
+const handlePageChange = (current) => {
+    page.value.current = current
+    ElMessage.info(`切换到第 ${current} 页`)
+    // 这里通常触发接口请求
+}
+
+const handleSizeChange = (size) => {
+    page.value.size = size
+    page.value.current = 1
+    ElMessage.info(`每页 ${size} 条`)
+    // 这里通常触发接口请求
+}
+const tableData = ref([
+    {
+        id: 1,
+        trainTime: '2025-11',
+        courseName: '上下院安全检查表(特定区域)',
+        category: '入院三级安全教育',
+        mode: '网络',
+        summary: '安全检查要点讲解',
+        teacher: '周萍 / 孙菲亚',
+        group: '安全教育分组',
+        planCount: 20,
+        signCount: 20
+    },
+    {
+        id: 2,
+        trainTime: '2025-11',
+        courseName: '三级危险点:35KV变电站',
+        category: '入院三级安全教育',
+        mode: '面授',
+        summary: '高压设备风险讲解',
+        teacher: '周萍',
+        group: '安全教育分组',
+        planCount: 20,
+        signCount: 0
     }
-    return ruleFormConfig.value;
-  });
+])
 
-  const basicFormRef = ref<InstanceType<typeof BasicForm>>();
 
-  const handleValidate = async () => {
-    if (!basicFormRef.value) return;
-    const res = await basicFormRef.value.validateForm();
-    return res;
-  };
+// 搜索和筛选相关
+const searchQuery = ref('');
+const dateRange = ref([]);
 
-  const getDetail = async () => {
+
+const handleSearch = () => {
+    ElMessage.success('点击了查询')
+}
+
+const handleExport = () => {
+    ElMessage.success('点击了导出')
+}
+
+const handleAdd = () => {
+    ElMessage.info('点击了新增课程')
+}
+
+const handleEdit = (row) => {
+    ElMessage.info(`编辑:${row.courseName}`)
+}
+
+const handleView = (row) => {
+    ElMessage.info(`查看:${row.courseName}`)
+}
+
+const handleSummary = (row) => {
+    ElMessage.info(`小结:${row.courseName}`)
+}
+
+const handleDelete = (row) => {
+    ElMessageBox.confirm(
+        `确认删除课程「${row.courseName}」吗?`,
+        '提示',
+        { type: 'warning' }
+    ).then(() => {
+        tableData.value = tableData.value.filter(i => i.id !== row.id)
+        ElMessage.success('删除成功')
+    })
+}
+const getDetail = async () => {
     if (!currentId.value) return;
     try {
-      const res = await queryInventoryDetail(currentId.value);
-      if (res) {
-        // 映射接口字段到表单字段
-        ruleFormData.itemName = res.stuffName; // 物品名称
-        ruleFormData.warehouseDate = res.inStoreTime ? res.inStoreTime.split('T')[0] : ''; // 入库日期(YYYY-MM-DD)
-        ruleFormData.itemQuantity = res.stuffQty; // 物品数量
-        ruleFormData.remarks = res.remark || ''; // 备注
-      }
-      cloneRuleFormData();
-    } catch (e) {
-      console.error('获取物品库存详情失败:', e);
-      ElMessage.error('获取详情失败');
-    }
-  };
+        // const res = await queryInventoryDetail(currentId.value);
+        // if (res) {
+
+        // }
 
-  const handleSubmit = async () => {
-    const res = await handleValidate();
-    if (!res) return;
-    try {
-      const basePayload = {
-        stuffName: ruleFormData.itemName,
-        inStoreTime: ruleFormData.warehouseDate
-          ? new Date(ruleFormData.warehouseDate).toISOString()
-          : '',
-        stuffQty: ruleFormData.itemQuantity,
-        remark: ruleFormData.remarks || '',
-      };
-
-      if (isCreateMode.value) {
-        await saveInventory(basePayload);
-        ElMessage.success('创建成功');
-      } else if (isEditMode.value && currentId.value) {
-        await updateInventory({
-          id: currentId.value,
-          ...basePayload,
-        });
-        ElMessage.success('保存成功');
-      }
-
-      router.back();
     } catch (e) {
-      console.error('保存物品库存失败:', e);
-      ElMessage.error('保存失败,请重试');
+        console.error('获取物品库存详情失败:', e);
+        ElMessage.error('获取详情失败');
     }
-  };
+};
 
-  onMounted(() => {
-    cloneRuleFormData();
-    beforeRouteLeave();
-    if (isEditMode.value || isViewMode.value) {
-      getDetail();
-    }
-  });
+onMounted(() => {
+    getDetail();
+});
 </script>
 
 <style scoped lang="scss">
-  @use '@/styles/page-details-layout.scss' as *;
-</style>
+@use '@/styles/page-details-layout.scss' as *;
+
+.page-container {
+    padding: 16px;
+}
+
+.pagination {
+    width: 100%;
+    margin-top: 20px;
+    display: flex;
+    justify-content: flex-end;
+}
 
+.title {
+    margin: 0 0 8px;
+}
+
+.meta {
+    font-size: 13px;
+    color: #666;
+    display: flex;
+    gap: 24px;
+    margin-top: 20px;
+}
+
+.mb-12 {
+    margin-bottom: 12px;
+}
+
+.mb-16 {
+    margin-bottom: 16px;
+}
+</style>

+ 111 - 55
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/configs/tables.ts

@@ -1,62 +1,118 @@
 import type { TableColumnProps } from '@/types/basic-table';
 
+// 状态标签映射
+export const STATUS_LABEL: Record<string, string> = {
+    '1': '未下发',
+    '2': '进行中',
+    '3': '已完成',
+    '4': '已作废',
+};
+
 // 基础表格样式配置
 export const TABLE_OPTIONS = {
-  emptyText: '暂无数据',
-  loading: true,
-  maxHeight: 'calc(70vh - 150px)',
+    emptyText: '暂无数据',
+    loading: true,
+    maxHeight: 'calc(70vh - 150px)',
 };
 
-export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
-  {
-    label: '编号',
-    type: 'index',
-    align: 'center',
-    width: '80px',
-  },
-  {
-    label: '物品名称',
-    prop: 'itemName',
-    align: 'left',
-    minWidth: '120px',
-  },
-  {
-    label: '入库日期',
-    prop: 'warehouseDate',
-    align: 'left',
-    minWidth: '120px',
-  },
-  {
-    label: '物品数量',
-    prop: 'itemQuantity',
-    align: 'center',
-    minWidth: '120px',
-  },
-  {
-    label: '经办人',
-    prop: 'handler',
-    align: 'left',
-    minWidth: '120px',
-  },
-  {
-    label: '备注',
-    prop: 'remarks',
-    align: 'left',
-    minWidth: '150px',
-  },
-  {
-    label: '状态',
-    prop: 'status',
-    slot: 'status',
-    align: 'center',
-    minWidth: '100px',
-  },
-  {
-    label: '操作',
-    prop: 'action',
-    slot: 'action',
-    fixed: 'right',
-    width: '180px',
-    align: 'left',
-  },
+// 状态选项
+export const STATUS_OPTIONS = [
+    { label: '全部', value: '' },
+    { label: '未下发', value: 1 },
+    { label: '进行中', value: 2 },
+    { label: '已完成', value: 3 },
+    { label: '已作废', value: 4 },
+];
+
+export const TABLE_COLUMNS: TableColumnProps[] = [
+    {
+        label: '编号',
+        type: 'index',
+        align: 'center',
+        width: '80px',
+        fixed: 'left',
+    },
+    {
+        label: '培训名称(内容)',
+        prop: 'trainingContent',
+        align: 'left',
+        minWidth: '220px',
+        fixed: 'left',
+    },
+    {
+        label: '状态',
+        prop: 'statusName',
+        align: 'center',
+        minWidth: '100px',
+    },
+    {
+        label: '分类名称',
+        prop: 'categoryName',
+        align: 'center',
+        minWidth: '110px',
+    },
+    {
+        label: '培训计划名称',
+        prop: 'trainingPlanName',
+        align: 'center',
+        minWidth: '140px',
+    },
+    {
+        label: '培训对象',
+        prop: 'trainingObject',
+        align: 'center',
+        minWidth: '110px',
+    },
+    {
+        label: '培训人数',
+        prop: 'trainingCount',
+        align: 'center',
+        minWidth: '120px',
+    },
+    {
+        label: '培训方式',
+        prop: 'trainingMethod',
+        align: 'center',
+        minWidth: '150px',
+    },
+    {
+        label: '培训时间',
+        prop: 'trainingTime',
+        align: 'center',
+        minWidth: '120px',
+    },
+    {
+        label: '考核方式',
+        prop: 'assessmentMethod',
+        align: 'center',
+        minWidth: '120px',
+    },
+
+    {
+        label: '学时',
+        prop: 'studyHours',
+        align: 'center',
+        minWidth: '80px',
+    },
+
+    {
+        label: '计划开始时间',
+        prop: 'startTime',
+        align: 'center',
+        minWidth: '150px',
+    },
+    {
+        label: '计划结束时间',
+        prop: 'endTime',
+        align: 'center',
+        minWidth: '150px',
+    },
+    {
+        label: '操作',
+        prop: 'action',
+        slot: 'action',
+        fixed: 'right',
+        width: '300px',
+        align: 'left',
+    },
 ];

+ 252 - 203
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/educationTrainingPlanManagementDept.vue

@@ -1,264 +1,313 @@
 <template>
-  <div class="safety-platform-container">
-    <header class="safety-platform-container__header">
-      <div class="breadcrumb-title"> 物品库存管理 </div>
-    </header>
-    <main class="safety-platform-container__main">
-      <div class="search-table-container">
-        <header>
-          <div style="position: relative">
-            <el-button type="primary" class="search-table-container--button" @click="handleCreate">
-              添加
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleImport">
-              导入
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleDownload">
-              导出
-            </el-button>
-          </div>
-
-          <div class="act-search">
-            <section class="select-box">
-              <div class="select-box--item">
-                <span>物品名称:</span>
-                <el-input
-                  v-model="tableQuery.queryParam.stuffName"
-                  placeholder="搜索物品名称"
-                  class="act-search-input"
-                />
-              </div>
-              <div class="select-box--item">
-                <span>状态:</span>
-                <el-select
-                  v-model="tableQuery.queryParam.status"
-                  placeholder="请选择状态"
-                  clearable
-                >
-                  <el-option label="启用" :value="true" />
-                  <el-option label="禁用" :value="false" />
-                </el-select>
-              </div>
-            </section>
-            <section class="search-btn">
-              <el-button type="primary" @click="handleSearch">查询</el-button>
-              <el-button @click="handleReset">重置</el-button>
-            </section>
-          </div>
+    <div class="safety-platform-container">
+        <header class="safety-platform-container__header">
+            <div class="breadcrumb-title"> 教育培训计划管理(部门)</div>
         </header>
+        <main class="safety-platform-container__main">
+            <div class="search-table-container">
+                <header>
+                    <div style="position: relative">
+                        <!-- <el-button type="primary" class="search-table-container--button" @click="handleCreate">
+                            添加
+                        </el-button> -->
+                        <!-- <el-button plain class="search-table-container--button" @click="handleImport">
+                            导入
+                        </el-button>
+                        <el-button plain class="search-table-container--button" @click="handleDownload">
+                            导出
+                        </el-button> -->
+                    </div>
+                    <div class="act-search">
+                        <section class="select-box">
+                            <div class="select-box--item">
+                                <span>培训内容/计划名称:</span>
+                                <el-input v-model="tableQuery.queryParam.keyword" placeholder="搜索培训内容或计划名称"
+                                    class="act-search-input" />
+                            </div>
+                            <div class="select-box--item">
+                                <span>状态:</span>
+                                <el-select v-model="tableQuery.queryParam.status" placeholder="请选择状态" clearable>
+                                    <el-option v-for="item in STATUS_OPTIONS" :key="item.value" :label="item.label"
+                                        :value="item.value" />
+                                </el-select>
+                            </div>
+                            <div class="select-box--item">
+                                <span>分类名称:</span>
+                                <el-select v-model="tableQuery.queryParam.classifyName" placeholder="请选择分类名称" filterable
+                                    clearable>
+                                    <el-option v-for="item in classifyNameOptions" :key="item.value" :label="item.label"
+                                        :value="item.value" />
+                                </el-select>
+                            </div>
+                            <div>
+                                <span>计划日期范围:</span>
+                                <el-date-picker v-model="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>
+                        </section>
+                    </div>
+                </header>
 
-        <div class="batch-table">
-          <BasicTable
-            ref="basicTableRef"
-            :tableData="tableData"
-            :tableConfig="tableConfig"
-            @update:pageSize="handleSizeChange"
-            @update:pageNumber="handleCurrentChange"
-          >
-            <template #status="scope">
-              <span>
-                {{ scope.row.statusName || (scope.row.status === true || scope.row.status === 'true' ? '启用' : scope.row.status === false || scope.row.status === 'false' ? '禁用' : '-') }}
-              </span>
-            </template>
-            <template #action="scope">
-              <div class="action-container--div" style="justify-content: left">
-                <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
-                <ActionButton
-                  text="删除"
-                  :popconfirm="{
-                    title: '确定要删除?',
-                  }"
-                  @confirm="handleDelete(scope.row.id)"
-                />
-                <ActionButton text="查看" @click="handleView(scope.row.id)" />
-              </div>
-            </template>
-          </BasicTable>
-        </div>
-      </div>
-    </main>
-    <BatchImport
-      v-if="batchImportVisible"
-      :visible="batchImportVisible"
-      :import-api-url="importApiUrl"
-      :template-url="templateUrl"
-      template-name="下载模板"
-      :show-template="false"
-      @close="batchImportVisible = false"
-      @update="handleUpdate"
-    />
-  </div>
+                <div class="batch-table">
+                    <BasicTable ref="basicTableRef" :tableData="tableData" :tableConfig="tableConfig"
+                        @update:pageSize="handleSizeChange" @update:pageNumber="handleCurrentChange">
+                        <template #status="scope">
+                            <span>
+                                {{
+                                    scope.row.statusName ||
+                                    (scope.row.status === true || scope.row.status === 'true'
+                                        ? '启用'
+                                        : scope.row.status === false || scope.row.status === 'false'
+                                            ? '禁用'
+                                            : '-')
+                                }}
+                            </span>
+                        </template>
+                        <template #action="scope">
+                            <div class="action-container--div" style="justify-content: left">
+                                <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                            </div>
+                        </template>
+                    </BasicTable>
+                </div>
+            </div>
+        </main>
+        <BatchImport v-if="batchImportVisible" :visible="batchImportVisible" :import-api-url="importApiUrl"
+            :template-url="templateUrl" template-name="下载模板" :show-template="false" @close="batchImportVisible = false"
+            @update="handleUpdate" />
+    </div>
 </template>
 
 <script setup lang="ts">
-  import { onMounted, reactive, ref } from 'vue';
-  import { ElMessage } from 'element-plus';
-  import BasicTable from '@/components/BasicTable.vue';
-  import useTableConfig from '@/hooks/useTableConfigHook';
-  import ActionButton from '@/components/ActionButton.vue';
-  import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
-  import { useRouter } from 'vue-router';
-  import type { QueryPageRequest } from '@/types/basic-query';
-  import { queryInventoryManage, deleteInventory, exportInventory } from '@/api/inventory';
-  import { downloadByData } from '@/utils/file/download';
-  import BatchImport from '@/components/batch-import/BatchImport.vue';
-  import { useGlobSetting } from '@/hooks/setting';
-  import urlJoin from 'url-join';
-
-  const router = useRouter();
+import { onMounted, reactive, ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import BasicTable from '@/components/BasicTable.vue';
+import useTableConfig from '@/hooks/useTableConfigHook';
+import ActionButton from '@/components/ActionButton.vue';
+import { TABLE_OPTIONS, TABLE_COLUMNS, STATUS_OPTIONS } from './configs/tables';
+import { useRouter } from 'vue-router';
+import type { QueryPageRequest } from '@/types/basic-query';
+import { getEducationAndTrainingProgramList, issueEducationAndTrainingProgram, cancelEducationAndTrainingProgram, deleteEducationAndTrainingProgram } from '@/api/production-education-training-plan-dept';
+import { downloadByData } from '@/utils/file/download';
+import BatchImport from '@/components/batch-import/BatchImport.vue';
+import { useGlobSetting } from '@/hooks/setting';
+import urlJoin from 'url-join';
+const router = useRouter();
 
-  // 表格
-  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+// 表格
+const basicTableRef = ref<InstanceType<typeof BasicTable>>();
 
-  const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
+const { tableConfig, pagination } = useTableConfig(TABLE_COLUMNS, TABLE_OPTIONS);
 
-  const tableData = ref<any[]>([]);
+const tableData = ref<any[]>([]);
+// 日期范围
+const dateRange = ref<[string, string] | null>(null);
+// 分类名称选项
+const classifyNameOptions = ref<Array<{ label: string; value: string }>>([
+    { label: '全部', value: '全部' },
+    { label: '全员安全培训', value: '全员安全培训' },
+    { label: '新员工培训', value: '新员工培训' },
+    { label: '岗位资质培训', value: '岗位资质培训' },
+    { label: '生产作业安全培训', value: '生产作业安全培训' },
+    { label: '安全管理人员培训', value: '安全管理人员培训' },
+]);
 
-  const tableQuery = reactive<QueryPageRequest<any>>({
+const tableQuery = reactive<QueryPageRequest<any>>({
     pageNumber: pagination.pageNumber,
     pageSize: pagination.pageSize,
     queryParam: {
-      stuffName: '', // 物品名称
-      status: true, // 状态,默认启用
-      ids: [], // 选择数据的ID
+        keyword: "",
+        status: "",
+        categoryName: "",
+        startDate: "",
+        endDate: "",
     },
-  });
+});
 
-  const handleSizeChange = (value: number) => {
+const handleSizeChange = (value: number) => {
     pagination.pageSize = value;
     tableQuery.pageSize = value;
     getTableData();
-  };
+};
 
-  const handleCurrentChange = (value: number) => {
+const handleCurrentChange = (value: number) => {
     pagination.pageNumber = value;
     tableQuery.pageNumber = value;
     getTableData();
-  };
-
+};
 
-  async function getTableData() {
+async function getTableData() {
     tableConfig.loading = true;
     try {
-      const res = await queryInventoryManage(tableQuery);
-      if (res) {
-        // 映射返回数据字段到表格字段
-        tableData.value = res.records.map((item) => ({
-          id: item.id,
-          itemName: item.stuffName, // 物品名称
-          warehouseDate: item.inStoreTime, // 入库日期
-          itemQuantity: item.stuffQty, // 物品数量
-          handler: item.createdUserName, // 经办人
-          remarks: item.remark, // 备注
-          status: item.status, // 状态:true-启用,false-禁用
-          statusName: item.statusName, // 状态名称
-        }));
-        pagination.total = res.totalRow;
-      }
+        tableQuery.queryParam.startDate = dateRange.value ? dateRange.value[0] : '';
+        tableQuery.queryParam.endDate = dateRange.value ? dateRange.value[1] : '';
+        const res = await getEducationAndTrainingProgramList(tableQuery);
+        if (res) {
+            // 映射返回数据字段到表格字段
+            tableData.value = res.records
+            pagination.total = res.totalRow;
+        }
     } catch (e) {
-      console.error('获取物品库存列表失败:', e);
-      tableData.value = [];
-      pagination.total = 0;
+        console.error('获取物品库存列表失败:', e);
+        tableData.value = [];
+        pagination.total = 0;
     } finally {
-      tableConfig.loading = false;
+        tableConfig.loading = false;
     }
-  }
+}
 
-  const handleSearch = () => {
+const handleSearch = () => {
     pagination.pageNumber = 1;
     tableQuery.pageNumber = 1;
     getTableData();
-  };
+};
 
-  const handleReset = () => {
-    tableQuery.queryParam.stuffName = '';
-    tableQuery.queryParam.status = true; // 重置为默认启用状态
-    tableQuery.queryParam.ids = [];
+const handleReset = () => {
+    pagination.pageNumber = 1;
+    Object.assign(tableQuery, {
+        pageNumber: 1,
+        pageSize: pagination.pageSize,
+        queryParam: {
+            keyword: "",
+            status: "",
+            categoryName: "",
+            startDate: "",
+            endDate: "",
+        },
+    })
+    dateRange.value = null
     handleSearch();
-  };
+};
 
-  // 批量导入
-  const batchImportVisible = ref(false);
-  const { urlPrefix } = useGlobSetting();
-  const importApiUrl = ref(urlJoin(urlPrefix, '/inventory/importInventory'));
-  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-inventory-template.xlsx');
+// 批量导入
+const batchImportVisible = ref(false);
+const { urlPrefix } = useGlobSetting();
+const importApiUrl = ref(urlJoin(urlPrefix, '/inventory/importInventory'));
+const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-inventory-template.xlsx');
 
-  const handleImport = () => {
+const handleImport = () => {
     batchImportVisible.value = true;
-  };
+};
 
-  const handleUpdate = () => {
+const handleUpdate = () => {
     batchImportVisible.value = false;
     getTableData();
-  };
+};
 
-  const handleDownload = async () => {
+const handleDownload = async () => {
     try {
-      const exportParams = {
-        stuffName: tableQuery.queryParam.stuffName || undefined,
-        status: tableQuery.queryParam.status,
-        ids: tableQuery.queryParam.ids.length > 0 ? tableQuery.queryParam.ids : undefined,
-      };
-      const response = await exportInventory(exportParams);
-      if (response) {
-        const fileName = `物品库存管理_${new Date().toISOString().split('T')[0]}.xlsx`;
-        downloadByData(response, fileName);
-        ElMessage.success('导出成功');
-      }
+        const exportParams = {
+            stuffName: tableQuery.queryParam.stuffName || undefined,
+            status: tableQuery.queryParam.status,
+            ids: tableQuery.queryParam.ids.length > 0 ? tableQuery.queryParam.ids : undefined,
+        };
+        // const response = await exportInventory(exportParams);
+        // if (response) {
+        //     const fileName = `物品库存管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        //     downloadByData(response, fileName);
+        //     ElMessage.success('导出成功');
+        // }
     } catch (e) {
-      console.error('导出物品库存失败:', e);
-      ElMessage.error('导出失败,请重试');
+        console.error('导出物品库存失败:', e);
+        ElMessage.error('导出失败,请重试');
     }
-  };
-
-  const handleCreate = () => {
+};
+/**
+ * @description: 下发
+ * @param {*} id
+ * @return {*}
+ */
+const issueWorkPlanDialogVisible = ref<boolean>(false)
+const issueWorkPlanParams = reactive<any>({})
+const handleIssue = async (value) => {
+    issueWorkPlanDialogVisible.value = true
+    Object.assign(issueWorkPlanParams, value)
+};
+// 格式化时间
+const formatDate = (date) => {
+    if (!date) return '';
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    return `${year}-${month}-${day}`; // 输出:2026-02-11
+}
+const handleConfirmIssue = async (value) => {
+    try {
+        await issueEducationAndTrainingProgram({
+            ...value,
+            startTime: formatDate(value.startTime),
+            endTime: formatDate(value.endTime),
+        });
+        ElMessage.success('下发成功');
+        getTableData();
+    } catch (e) {
+        console.error('下发工作计划失败:', e);
+        ElMessage.error('下发失败,请重试');
+    }
+};
+const handleCreate = () => {
     router.push({
-      name: 'educationTrainingPlanManagementDeptItem',
-      query: {
-        operate: 'education-training-plan-management-dept-create',
-      },
+        name: 'educationTrainingPlanManagementItem',
+        query: {
+            operate: 'education-training-plan-management-create',
+        },
     });
-  };
+};
 
-  const handleEdit = (id: number) => {
+const handleEdit = (id: number) => {
     router.push({
-      name: 'educationTrainingPlanManagementDeptItem',
-      query: {
-        id,
-        operate: 'education-training-plan-management-dept-edit',
-      },
+        name: 'educationTrainingPlanManagementItem',
+        query: {
+            id,
+            operate: 'education-training-plan-management-edit',
+        },
     });
-  };
+};
 
-  const handleDelete = async (id: number) => {
+const handleDelete = async (id: number) => {
+    try {
+        await deleteEducationAndTrainingProgram(id);
+        ElMessage.success('删除成功');
+        getTableData();
+    } catch (e) {
+        console.error('删除物品库存失败:', e);
+        ElMessage.error('删除失败,请重试');
+    }
+};
+const handleCancel = async (id: number) => {
     try {
-      await deleteInventory(id);
-      ElMessage.success('删除成功');
-      getTableData();
+        await cancelEducationAndTrainingProgram({ id });
+        ElMessage.success('作废成功');
+        getTableData();
     } catch (e) {
-      console.error('删除物品库存失败:', e);
-      ElMessage.error('删除失败,请重试');
+        console.error('作废失败:', e);
+        ElMessage.error('作废失败,请重试');
     }
-  };
+};
 
-  const handleView = (id: number) => {
+const handleView = (id: number) => {
     router.push({
-      name: 'educationTrainingPlanManagementDeptItem',
-      query: {
-        id,
-        operate: 'education-training-plan-management-dept-view',
-      },
+        name: 'educationTrainingPlanManagementDeptItem',
+        query: {
+            id,
+            operate: 'education-training-plan-management-dept-view',
+        },
     });
-  };
+};
 
-  onMounted(() => {
+onMounted(() => {
     getTableData();
-  });
+});
 </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 '@/views/traffic/violation/style/act-search-table.scss' as *;
-</style>
+@use '@/styles/page-details-layout.scss' as *;
+@use '@/styles/page-main-layout.scss' as *;
+@use '@/styles/basic-table-action.scss' as *;
+@use '@/views/traffic/violation/style/act-search-table.scss' as *;
+</style>

+ 30 - 28
src/views/production-safety/safetyTrainingAndEducation/educationTrainingPlanManagementDept/educationTrainingPlanManagementDeptItem.vue

@@ -1,44 +1,46 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-02-03 17:55:50
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-12 22:30:34
+ * @Describe: file describe
+-->
 <template>
-  <div class="safety-platform-container">
-    <header class="safety-platform-container__header">
-      <BreadcrumbBack />
-      <span class="breadcrumb-title">{{ headerTitle }}</span>
-    </header>
-    <EducationTrainingPlanManagementDeptDetail />
-  </div>
+    <div class="safety-platform-container">
+        <header class="safety-platform-container__header">
+            <BreadcrumbBack />
+            <span class="breadcrumb-title">{{ headerTitle }}</span>
+        </header>
+        <EducationTrainingPlanManagementDeptDetail />
+    </div>
 </template>
 
 <script setup lang="ts">
-  import { computed } from 'vue';
-  import { useRoute } from 'vue-router';
-  import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
-  import EducationTrainingPlanManagementDeptDetail from './components/educationTrainingPlanManagementDeptDetail.vue';
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
+import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
+import EducationTrainingPlanManagementDeptDetail from './components/educationTrainingPlanManagementDeptDetail.vue';
 
-  const route = useRoute();
-  const operate = route.query.operate as string;
+const route = useRoute();
+const operate = route.query.operate as string;
 
-  const headerTitle = computed(() => {
+const headerTitle = computed(() => {
     switch (operate) {
-      case 'education-training-plan-management-dept-create':
-        return '新增物品';
-      case 'education-training-plan-management-dept-edit':
-        return '编辑物品';
-      case 'education-training-plan-management-dept-view':
-        return '查看物品';
-      default:
-        return '未知操作';
+        case 'education-training-plan-management-dept-view':
+            return '查看教育培训计划内容(部门)';
+        default:
+            return '未知操作';
     }
-  });
+});
 </script>
 
 <style scoped lang="scss">
-  @use '@/styles/page-details-layout.scss' as *;
-  @use '@/styles/page-main-layout.scss' as *;
+@use '@/styles/page-details-layout.scss' as *;
+@use '@/styles/page-main-layout.scss' as *;
 
-  .safety-platform-container__header {
+.safety-platform-container__header {
     flex-direction: row !important;
     justify-content: flex-start !important;
     gap: 8px !important;
-  }
+}
 </style>
-

+ 216 - 0
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/commonTable.vue

@@ -0,0 +1,216 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-02-13 16:04:29
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-25 16:04:14
+ * @Describe: file describe
+-->
+<script setup lang="ts">
+import { onMounted, ref, watch, reactive } from 'vue';
+import { ElDialog, ElPopconfirm } from 'element-plus';
+import { EDIT_EMPLOYEE_FORM_RULES } from '../configs/form';
+import { getEmployeeDetailTableList, type EmployeeTableType, updateEducationStaffTrainingCardScore, delateEducationStaffTrainingCardScore } from '@/api/employee-training-record-card-management';
+const props = defineProps({
+    index: {
+        type: Number,
+        default: 1
+    },
+    id: {
+        type: Number,
+        default: 0
+    }
+})
+const rules = ref(EDIT_EMPLOYEE_FORM_RULES)
+const tabName = ref('')
+
+const pagination = reactive({
+    pageNumber: 1,
+    pageSize: 10,
+    total: 0
+})
+// 日期范围
+const dateRange = ref<[string, string] | null>(null);
+
+const tableQuery = reactive({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {
+        logType: props.index,
+        pestcId: props.id,
+        keyWord: "",
+        dateStart: "",
+        dateEnd: ""
+    },
+});
+const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getActionTableList();
+};
+
+const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getActionTableList();
+};
+// 格式化时间
+const formatDate = (date) => {
+    if (!date) return '';
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    return `${year}-${month}-${day}`; // 输出:2026-02-11
+}
+
+let tableData = ref<any[]>([])
+const getActionTableList = async () => {
+    tableQuery.queryParam.dateStart = dateRange.value ? formatDate(dateRange.value[0]) : '';
+    tableQuery.queryParam.dateEnd = dateRange.value ? formatDate(dateRange.value[1]) : '';
+    try {
+        const res = await getEmployeeDetailTableList(tableQuery)
+        if (res) {
+            tableData.value = res.records;
+            pagination.total = res.totalRow;
+        }
+    } catch (e) {
+        tableData.value = [];
+        pagination.total = 0;
+    }
+}
+
+watch(() => props.index, (val) => {
+    if (val === 1 || val === 2) {
+        tableQuery.queryParam.logType = val
+        getActionTableList()
+    }
+}, { immediate: true, deep: true })
+
+const ediDialogVisible = ref(false)
+const formData = reactive({
+    id: 0,
+    scoreMust: 0,
+})
+const editHandle = (row) => {
+    Object.assign(formData, {
+        id: row.id || '',
+        scoreMust: row.scoreMust,
+    })
+    ediDialogVisible.value = true
+}
+const deleteHandle = (id) => {
+    try {
+        delateEducationStaffTrainingCardScore(id)
+        getActionTableList()
+    } catch (e) {
+        console.error('删除失败', e)
+    }
+}
+
+const cancelHandle = () => {
+    ediDialogVisible.value = false
+}
+const confirmHandle = async () => {
+    ediDialogVisible.value = false
+    formData.scoreMust = Number(formData.scoreMust)
+    try {
+        await updateEducationStaffTrainingCardScore(formData)
+        getActionTableList();
+    } catch (e) {
+        console.error('保存失败', e)
+    }
+}
+const handleSearch = () => {
+    pagination.pageNumber = 1;
+    tableQuery.pageNumber = 1;
+    getActionTableList();
+};
+
+const handleReset = () => {
+    tableQuery.queryParam.keyWord = '';
+    tableQuery.queryParam.dateStart = '';
+    tableQuery.queryParam.dateEnd = '';
+    dateRange.value = null;
+    tableQuery.pageNumber = 1;
+    handleSearch();
+};
+
+</script>
+<template>
+    <div>
+        <!-- 查询区 -->
+        <el-form :inline="true" class="mb-12">
+            <el-form-item>
+                <el-date-picker type="daterange" start-placeholder="开始时间" end-placeholder="结束时间" v-model="dateRange" />
+            </el-form-item>
+            <el-form-item>
+                <el-input placeholder="搜索关键词" v-model="tableQuery.queryParam.keyWord" />
+            </el-form-item>
+            <el-form-item>
+                <el-button type="primary" @click="handleSearch">搜索</el-button>
+                <el-button type="default" @click="handleReset">重置</el-button>
+                <!-- <el-button type="primary">导出</el-button>
+                <el-button type="danger">删除</el-button> -->
+            </el-form-item>
+        </el-form>
+
+        <!-- 表格 -->
+        <el-table border stripe :data="tableData">
+            <el-table-column type="selection" width="50" />
+            <el-table-column label="编号" prop="serialNum" width="100" />
+            <el-table-column label="日期" prop="logDate" width="200" />
+            <el-table-column label="教育内容" prop="educationContent" width="280" />
+            <el-table-column label="学时" prop="creditHour">
+                <template #default="scope">
+                    <span>{{ scope.row.creditHour }}时</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="成绩" prop="scoreMust">
+                <template #default="scope">
+                    <span>{{ scope.row.scoreMust }}分</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="受教育者签字" prop="educationSign" />
+            <el-table-column label="操作" width="220">
+                <template #default="scope">
+                    <el-button link type="primary" @click="editHandle(scope.row)">编辑</el-button>
+                    <el-popconfirm title="确定要删除该条记录吗?" placement="top" @confirm="deleteHandle(scope.row.id)">
+                        <template #reference>
+                            <el-button link type="danger">删除</el-button>
+                        </template>
+                    </el-popconfirm>
+                </template>
+            </el-table-column>
+        </el-table>
+
+        <!-- 分页 -->
+        <div class="pagination">
+            <el-pagination layout="total, prev, pager, next" :total="pagination.total" :page-size="pagination.pageSize"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+        </div>
+
+        <!-- 编辑 -->
+        <el-dialog v-model="ediDialogVisible" title="编辑内容" width="500px">
+            <el-form :rules="rules" :model="formData" label-width="120px">
+                <el-form-item label="成绩分数:" required prop="scoreMust">
+                    <el-input v-model="formData.scoreMust" placeholder="输入成绩分数,单位分,0-200" />
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <el-button @click="cancelHandle">取 消</el-button>
+                <el-button type="primary" @click="confirmHandle">保存</el-button>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<style scoped>
+.mb-12 {
+    margin-bottom: 12px;
+}
+
+.pagination {
+    margin-top: 16px;
+    display: flex;
+    justify-content: flex-end;
+}
+</style>

+ 236 - 0
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/commonTable2.vue

@@ -0,0 +1,236 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-02-13 16:04:29
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-25 16:10:44
+ * @Describe: file describe
+-->
+<script setup lang="ts">
+import { ref, watch, reactive, onMounted } from 'vue';
+import { ElDialog, ElPopconfirm } from 'element-plus';
+import { EDIT_EMPLOYEE_FORM_RULES } from '../configs/form';
+import { getEmployeeDetailTableList, type EmployeeTableType, updateEducationStaffTrainingCardScore, delateEducationStaffTrainingCardScore } from '@/api/employee-training-record-card-management';
+const props = defineProps({
+    index: {
+        type: Number,
+        default: 1
+    },
+    id: {
+        type: Number,
+        default: 0
+    }
+})
+const rules = ref(EDIT_EMPLOYEE_FORM_RULES)
+
+
+const pagination = reactive({
+    pageNumber: 1,
+    pageSize: 10,
+    total: 0
+})
+// 日期范围
+const dateRange = ref<[string, string] | null>(null);
+
+const tableQuery = reactive({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {
+        logType: props.index,
+        pestcId: props.id,
+        keyword: "",
+        dateStart: "",
+        dateEnd: ""
+    },
+});
+const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getActionTableList();
+};
+
+const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getActionTableList();
+};
+// 格式化时间
+const formatDate = (date) => {
+    if (!date) return '';
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    return `${year}-${month}-${day}`; // 输出:2026-02-11
+}
+let tableData = ref<any[]>([])
+const getActionTableList = async () => {
+    tableQuery.queryParam.dateStart = dateRange.value ? formatDate(dateRange.value[0]) : '';
+    tableQuery.queryParam.dateEnd = dateRange.value ? formatDate(dateRange.value[1]) : '';
+
+    try {
+        const res = await getEmployeeDetailTableList(tableQuery)
+        if (res) {
+            tableData.value = res.records;
+            pagination.total = res.totalRow;
+        }
+    } catch (e) {
+        tableData.value = [];
+        pagination.total = 0;
+    }
+}
+watch(() => props.index, (val) => {
+    if (val === 3 || val === 4) {
+        tableQuery.queryParam.logType = val
+        getActionTableList()
+    }
+}, { immediate: true, deep: true })
+
+
+const ediDialogVisible = ref(false)
+const formData = reactive({
+    id: 0,
+    educationContent: '',
+    scoreMust: '',
+    score: '',
+    operationCertificateNum: '',
+})
+const editHandle = (row) => {
+    Object.assign(formData, {
+        id: row.id,
+        educationContent: row.educationContent,
+        scoreMust: row.scoreMust,
+        score: row.score,
+        operationCertificateNum: row.operationCertificateNum,
+    })
+    ediDialogVisible.value = true
+}
+const deleteHandle = (id) => {
+    try {
+        delateEducationStaffTrainingCardScore(id)
+        getActionTableList()
+    } catch (e) {
+        console.error('删除失败', e)
+    }
+}
+
+const cancelHandle = () => {
+    ediDialogVisible.value = false
+}
+const confirmHandle = async () => {
+    ediDialogVisible.value = false
+    try {
+        await updateEducationStaffTrainingCardScore(formData)
+        getActionTableList();
+    } catch (e) {
+        console.error('保存失败', e)
+    }
+}
+const handleSearch = () => {
+    pagination.pageNumber = 1;
+    tableQuery.pageNumber = 1;
+    getActionTableList();
+};
+
+const handleReset = () => {
+    tableQuery.queryParam.keyword = '';
+    tableQuery.queryParam.dateStart = '';
+    tableQuery.queryParam.dateEnd = '';
+    dateRange.value = null;
+    tableQuery.pageNumber = 1;
+    handleSearch();
+};
+
+</script>
+<template>
+    <div>
+        <!-- 查询区 -->
+        <el-form :inline="true" class="mb-12">
+            <el-form-item>
+                <el-date-picker type="daterange" start-placeholder="开始时间" end-placeholder="结束时间" />
+            </el-form-item>
+            <el-form-item>
+                <el-input placeholder="搜索关键词" v-model="tableQuery.queryParam.keyword" />
+            </el-form-item>
+            <el-form-item>
+                <el-button type="primary" @click="handleSearch">搜索</el-button>
+                <el-button type="default" @click="handleReset">重置</el-button>
+                <!-- <el-button type="primary">导出</el-button>
+                <el-button type="danger">删除</el-button> -->
+            </el-form-item>
+        </el-form>
+
+        <!-- 表格 -->
+        <el-table border stripe :data="tableData">
+            <el-table-column type="selection" width="50" />
+            <el-table-column label="编号" prop="serialNum" width="100" />
+            <el-table-column label="日期" prop="logDate" width="200" />
+            <el-table-column label="工种名称" prop="educationContent" width="180" />
+            <el-table-column label="考核成绩-应知" prop="score">
+                <template #default="scope">
+                    <span>{{ scope.row.score }}分</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="考核成绩-应会" prop="scoreMust">
+                <template #default="scope">
+                    <span>{{ scope.row.scoreMust }}分</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="操作证号" prop="operationCertificateNum" />
+            <el-table-column label="培训单位" prop="trainingCompany" />
+            <el-table-column label="学时" prop="creditHour">
+                <template #default="scope">
+                    <span>{{ scope.row.creditHour }}时</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="操作" width="220">
+                <template #default="scope">
+                    <el-button link type="primary" @click="editHandle(scope.row)">编辑</el-button>
+                    <el-popconfirm title="确定要删除该条记录吗?" placement="top" @confirm="deleteHandle(scope.row.id)">
+                        <template #reference>
+                            <el-button link type="danger">删除</el-button>
+                        </template>
+                    </el-popconfirm>
+                </template>
+            </el-table-column>
+        </el-table>
+
+        <!-- 分页 -->
+        <div class="pagination">
+            <el-pagination layout="total, prev, pager, next" :total="pagination.total" :page-size="pagination.pageSize"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+        </div>
+
+        <!-- 编辑 -->
+        <el-dialog v-model="ediDialogVisible" title="编辑内容" width="550px">
+            <el-form :rules="rules" :model="formData" label-width="140px">
+                <el-form-item label="工种名称:" prop="educationContent">
+                    <el-input v-model="formData.educationContent" placeholder="输入工种名称" />
+                </el-form-item>
+                <el-form-item label="考核成绩-应知:" prop="score">
+                    <el-input v-model="formData.score" placeholder="输入成绩分数,单位分,0-200" />
+                </el-form-item>
+                <el-form-item label="考核成绩-应会:" prop="scoreMust">
+                    <el-input v-model="formData.scoreMust" placeholder="输入成绩分数,单位分,0-200" />
+                </el-form-item>
+                <el-form-item label="操作证号:" prop="operationCertificateNum">
+                    <el-input v-model="formData.operationCertificateNum" placeholder="输入操作证号" />
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <el-button @click="cancelHandle">取 消</el-button>
+                <el-button type="primary" @click="confirmHandle">保存</el-button>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<style scoped>
+.mb-12 {
+    margin-bottom: 12px;
+}
+
+.pagination {
+    margin-top: 16px;
+    display: flex;
+    justify-content: flex-end;
+}
+</style>

+ 151 - 110
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/employeeTrainingRecordCardManagementDetail.vue

@@ -1,127 +1,168 @@
 <template>
-  <main class="safety-platform-container__main">
-    <BasicForm
-      ref="basicFormRef"
-      :formData="ruleFormData"
-      :formRules="isViewMode ? undefined : formRules"
-      :formConfig="computedFormConfig"
-    />
-  </main>
-  <footer class="safety-platform-container__footer">
-    <el-button @click="router.back()">返回</el-button>
-    <el-button v-if="!isViewMode" type="primary" @click="handleSubmit">
-      {{ isCreateMode ? '提交' : '保存' }}
-    </el-button>
-  </footer>
+    <main class="safety-platform-container__main">
+        <div class="page-container">
+            <!-- 标题 -->
+            <el-card shadow="never" class="mb-16">
+                <h2>上飞院职工安全生产培训记录卡</h2>
+                <div class="meta">
+                    <span>创建人:{{ employeeDetail.createdUserName }}</span>
+                    <span>创建时间:{{ employeeDetail.createdAt }}</span>
+                </div>
+            </el-card>
+
+            <!-- 基本信息 -->
+            <el-card shadow="never" class="mb-16">
+                <template #header>
+                    <strong>基本信息</strong>
+                </template>
+
+                <el-descriptions :column="2" border>
+                    <el-descriptions-item label="工号">{{ employeeDetail.staffNo }}</el-descriptions-item>
+                    <el-descriptions-item label="状态">
+                        <el-tag type="success">{{ employeeDetail.statusName }}</el-tag>
+                    </el-descriptions-item>
+
+                    <el-descriptions-item label="姓名">{{ employeeDetail.staffName }}</el-descriptions-item>
+                    <el-descriptions-item label="出生年月">{{ employeeDetail.staffBirthday }}</el-descriptions-item>
+                    <el-descriptions-item label="身份证号">
+                        {{ employeeDetail.staffIdCard }}
+                    </el-descriptions-item>
+                    <el-descriptions-item label="所/中心/部门">
+                        {{ employeeDetail.deptName }}
+                    </el-descriptions-item>
+
+                    <el-descriptions-item label="家庭住址">
+                        {{ employeeDetail.staffAddress }}
+                    </el-descriptions-item>
+                    <el-descriptions-item label="入职日期">{{ employeeDetail.dateOfJoining }}</el-descriptions-item>
+
+                    <el-descriptions-item label="文化程度">{{ employeeDetail.highestDegree }}</el-descriptions-item>
+                    <el-descriptions-item label="从事岗位">{{ employeeDetail.staffJob }}</el-descriptions-item>
+
+                    <el-descriptions-item label="本岗位工龄">{{ employeeDetail.jobSeniority }}年</el-descriptions-item>
+                    <el-descriptions-item label="技术等级">{{ employeeDetail.technicalLvl }}级</el-descriptions-item>
+
+                    <el-descriptions-item label="职称">{{ employeeDetail.professionalTitle }}</el-descriptions-item>
+                    <el-descriptions-item label="照片">
+                        <img :src="employeeDetail.staffImg" v-if="employeeDetail.staffImg" alt="">
+                        <div class="photo-placeholder" v-else></div>
+                    </el-descriptions-item>
+                </el-descriptions>
+            </el-card>
+
+            <!-- 底部 Tab 区 -->
+            <el-card shadow="never">
+                <el-tabs v-model="activeTab" @tab-change="handleTabChange">
+                    <el-tab-pane label="填写说明" :name="0" />
+                    <el-tab-pane label="入院三级安全教育" :name="1" />
+                    <el-tab-pane label="安全生产继续教育" :name="2" />
+                    <el-tab-pane label="特种作业培训考核" :name="3" />
+                    <el-tab-pane label="特种作业复训考核" :name="4" />
+                    <el-tab-pane label="安全生产培训记录卡管理规定" :name="5" />
+                </el-tabs>
+
+                <!-- Tab 内容 -->
+                <div class="tab-content">
+                    <el-card shadow="never">
+                        <FillDesc v-if="activeTab === 0" />
+
+                        <CommonTable :id="employeeDetail.id" :index="activeTab"
+                            v-if="activeTab >= 1 && activeTab <= 2" />
+                        <CommonTable2 :id="employeeDetail.id" :index="activeTab"
+                            v-if="activeTab >= 3 && activeTab <= 4" />
+                        <ManageRule v-if="activeTab === 5" />
+                    </el-card>
+                </div>
+            </el-card>
+
+            <div class="footer">
+                <el-button>取消</el-button>
+            </div>
+        </div>
+    </main>
 </template>
 
 <script setup lang="ts">
-  import { computed, onMounted, ref } from 'vue';
-  import { useRoute, useRouter } from 'vue-router';
-  import { ElMessage } from 'element-plus';
-  import BasicForm from '@/components/BasicForm.vue';
-  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
-  import { INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES } from '../configs/form';
-  import { queryInventoryDetail, saveInventory, updateInventory } from '@/api/inventory';
-
-  const router = useRouter();
-  const route = useRoute();
-
-  const operate = computed(() => (route.query.operate as string) || 'inventory-create');
-  const currentId = computed(() => Number(route.query.id));
-
-  const isCreateMode = computed(() => operate.value === 'inventory-create');
-  const isEditMode = computed(() => operate.value === 'inventory-edit');
-  const isViewMode = computed(() => operate.value === 'inventory-view');
-
-  const { ruleFormData, formRules, ruleFormConfig, cloneRuleFormData, beforeRouteLeave } =
-    useFormConfigHook(INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES);
-
-  // 查看模式下,所有字段设为只读
-  const viewFormConfig = ref(
-    INVENTORY_FORM_CONFIG.map((item) => ({
-      ...item,
-      componentProps: {
-        ...item.componentProps,
-        disabled: true,
-      },
-    })),
-  );
-
-  const computedFormConfig = computed(() => {
-    if (isViewMode.value) {
-      return viewFormConfig.value;
-    }
-    return ruleFormConfig.value;
-  });
+import { computed, onMounted, ref, reactive } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import { getEducationStaffTrainingCardDetail, getEmployeeDetailTableList, type EmployeeTableType } from '@/api/employee-training-record-card-management';
+import FillDesc from './fillDesc.vue'
+import CommonTable from './commonTable.vue'
+import CommonTable2 from './commonTable2.vue'
+import ManageRule from './manageRule.vue'
+
+const activeTab = ref(0)
+
+const router = useRouter();
+const route = useRoute();
 
-  const basicFormRef = ref<InstanceType<typeof BasicForm>>();
+const operate = computed(() => (route.query.operate as string) || 'inventory-create');
+const currentId = computed(() => Number(route.query.id));
 
-  const handleValidate = async () => {
-    if (!basicFormRef.value) return;
-    const res = await basicFormRef.value.validateForm();
-    return res;
-  };
 
-  const getDetail = async () => {
+
+const handleTabChange = (name) => {
+    activeTab.value = Number(name)
+}
+let employeeDetail = reactive({}) as EmployeeTableType
+const getDetail = async () => {
     if (!currentId.value) return;
     try {
-      const res = await queryInventoryDetail(currentId.value);
-      if (res) {
-        // 映射接口字段到表单字段
-        ruleFormData.itemName = res.stuffName; // 物品名称
-        ruleFormData.warehouseDate = res.inStoreTime ? res.inStoreTime.split('T')[0] : ''; // 入库日期(YYYY-MM-DD)
-        ruleFormData.itemQuantity = res.stuffQty; // 物品数量
-        ruleFormData.remarks = res.remark || ''; // 备注
-      }
-      cloneRuleFormData();
+        const res = await getEducationStaffTrainingCardDetail(currentId.value);
+        if (res) {
+            // 映射接口字段到表单字段
+            Object.assign(employeeDetail, res);
+        }
     } catch (e) {
-      console.error('获取物品库存详情失败:', e);
-      ElMessage.error('获取详情失败');
+        console.error('获取物品库存详情失败:', e);
+        ElMessage.error('获取详情失败');
     }
-  };
+};
 
-  const handleSubmit = async () => {
-    const res = await handleValidate();
-    if (!res) return;
-    try {
-      const basePayload = {
-        stuffName: ruleFormData.itemName,
-        inStoreTime: ruleFormData.warehouseDate
-          ? new Date(ruleFormData.warehouseDate).toISOString()
-          : '',
-        stuffQty: ruleFormData.itemQuantity,
-        remark: ruleFormData.remarks || '',
-      };
-
-      if (isCreateMode.value) {
-        await saveInventory(basePayload);
-        ElMessage.success('创建成功');
-      } else if (isEditMode.value && currentId.value) {
-        await updateInventory({
-          id: currentId.value,
-          ...basePayload,
-        });
-        ElMessage.success('保存成功');
-      }
-
-      router.back();
-    } catch (e) {
-      console.error('保存物品库存失败:', e);
-      ElMessage.error('保存失败,请重试');
-    }
-  };
 
-  onMounted(() => {
-    cloneRuleFormData();
-    beforeRouteLeave();
-    if (isEditMode.value || isViewMode.value) {
-      getDetail();
-    }
-  });
+onMounted(() => {
+    getDetail();
+});
 </script>
 
 <style scoped lang="scss">
-  @use '@/styles/page-details-layout.scss' as *;
+@use '@/styles/page-details-layout.scss' as *;
+
+.page-container {
+    padding: 16px;
+}
+
+.mb-16 {
+    margin-bottom: 16px;
+}
+
+.meta {
+    margin-top: 16px;
+    font-size: 13px;
+    color: #666;
+    display: flex;
+    gap: 24px;
+}
+
+.photo-placeholder {
+    width: 80px;
+    height: 80px;
+    border: 1px solid #dcdfe6;
+    background: repeating-linear-gradient(45deg,
+            #eee,
+            #eee 10px,
+            #fff 10px,
+            #fff 20px);
+}
+
+.tab-content {
+    margin-top: 16px;
+}
+
+.footer {
+    margin-top: 24px;
+    display: flex;
+    justify-content: flex-end;
+}
 </style>
-

+ 32 - 0
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/fillDesc.vue

@@ -0,0 +1,32 @@
+<script lang="ts" setup>
+
+</script>
+<template>
+    <div class='content'>
+        <pre>
+一、填卡说明:
+
+    1.本卡适用于生产经营单位(事业单位)每一员工,一人一卡。填写应准确、清晰,字迹工整。
+
+    2.员工本人对记录卡要按时、规范填写,不得留有空缺,培训成绩要真实,不得弄虚作假,不得随意填写。
+
+    3.如遇填写不下的栏目,可另外附页。
+
+    4.本卡由安委办、各所、中心、部门负责管理。
+
+二、培训重点要求
+
+    1.职工三级安全生产教育培训主要内容:
+        (1)厂(院)级安全教育包括:安全生产基本知识;本单位安全生产规章制度:劳动纪律;作业场所和工作岗位存在的危险因素、防范措施及应急措施;事故案例等。
+        (2)车间(所、中心、部门)级安全教育包括:本车间(所、中心、部门)安全生产状况和规章制度;作业场所和工作岗位存在的危险因素、防范措施及应急措施;事故案例等。
+        (3)班组(岗位)级安全教育包括:岗位安全操作规程;生产设备、安全装置、劳动防护用品(用具)的性能及正确使用方法;事故案例等。
+
+    2.新入职员工三级安全生产教育培训时间不得少于24小时。生产、经营、运输、储存、使用危险物品或者处置废弃危险物品等危险性较大的岗位,三级安全生产教育培训时间不得少于48小时。
+
+    3.安全生产继续教育
+        主要是指:安全生产法律法规教育;采用新技术、新工艺、新材料、新设备的安全生产教育:安全技能培训;事故案例教育;
+        全市性或全厂性的重大安全生产活动教育;因病因伤半年后的复工教育;违章行为被查实、举报或因违章造成险肇以上事故的安全强化教育:发生重大事故后的安全生产教育等。
+        </pre>
+    </div>
+</template>
+<style lang="scss" scoped></style>

+ 28 - 0
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/components/manageRule.vue

@@ -0,0 +1,28 @@
+<script lang="ts" setup>
+
+</script>
+<template>
+    <div class='content'>
+        <p>1. 各所、中心、部门应指定专门管理人员管理本所、中心、部门员工的安全生产培训记录卡。</p>
+
+        <p>2. 员工负责在本人安全生产培训记录卡上对本人每次的安全培训进行记录。</p>
+
+        <p>3. 各所、中心、部门的安全生产培训记录卡管理人员应妥善保管安全生产培训记录卡,指导员工及时、正确填写。</p>
+
+        <p>4. 各所、中心、部门的安全生产培训记录卡管理人员定期将员工签字版安全生产培训记录卡扫描件、及汇总表提交安委办归档(每人一档,文件名请按照“工号-姓名-(所、中心)-部门-上飞院职工安全生产培训记录卡”命名)。</p>
+
+        <p>5. 若员工岗位调动、转岗、换岗,则在重新上岗前必须接受新部门的安全培训并记录,安全生产培训记录卡跟随本人至新部门。</p>
+
+        <p>6. 安委办每年定期(一般每年第三季度)对各所、中心、部门的安全培训开展情况和安全生产培训记录卡填写情况进行检查。</p>
+
+        <p>7. 新入职员工三级安全生产教育培训和继续教育每人每年时间不得少于24小时。</p>
+
+    </div>
+</template>
+<style lang="scss" scoped>
+p {
+    margin-bottom: 12px;
+    line-height: 1.7;
+    font-size: 13px;
+}
+</style>

+ 13 - 58
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/configs/form.ts

@@ -1,60 +1,15 @@
+/*
+ * @Author: liuJie
+ * @Date: 2026-02-03 17:55:50
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-25 13:28:34
+ * @Describe: file describe
+ */
 import { FormConfig } from '@/types/basic-form';
 
-export const INVENTORY_FORM_CONFIG: FormConfig[] = [
-  {
-    prop: 'itemName',
-    label: '物品名称:',
-    component: 'ElInput',
-    componentProps: {
-      placeholder: '请输入物品名称',
-    },
-  },
-  {
-    prop: 'warehouseDate',
-    label: '入库日期:',
-    component: 'ElDatePicker',
-    componentProps: {
-      type: 'date',
-      placeholder: '请选择入库日期',
-      valueFormat: 'YYYY-MM-DD',
-    },
-  },
-  {
-    prop: 'itemQuantity',
-    label: '物品数量:',
-    component: 'ElInputNumber',
-    componentProps: {
-      min: 1,
-      max: 99999,
-      precision: 0, // 不允许小数点,只能输入整数
-      placeholder: '请输入物品数量',
-    },
-  },
-  {
-    label: '备注:',
-    prop: 'remarks',
-    component: 'ElInput',
-    componentProps: {
-      type: 'textarea',
-      rows: 5,
-      placeholder: '请输入备注',
-    },
-  },
-];
-
-export const INVENTORY_FORM_DATA = {
-  itemName: '',
-  warehouseDate: '',
-  itemQuantity: 1, // 最小值为1
-  remarks: '',
-};
-
-export const INVENTORY_FORM_RULES = {
-  itemName: [{ required: true, message: '请输入物品名称', trigger: 'blur' }],
-  warehouseDate: [{ required: true, message: '请选择入库日期', trigger: 'change' }],
-  itemQuantity: [
-    { required: true, message: '请输入物品数量', trigger: 'blur' },
-    { type: 'number', min: 1, message: '物品数量不能小于1', trigger: 'blur' },
-    { type: 'number', max: 99999, message: '物品数量不能大于99999', trigger: 'blur' },
-  ],
-};
+export const EDIT_EMPLOYEE_FORM_RULES = {
+    educationContent: [{ required: true, message: '请输入工种名称', trigger: 'blur' }],
+    scoreMust: [{ required: true, message: '请输入成绩', trigger: 'blur' }],
+    score: [{ required: true, message: '请输入成绩', trigger: 'blur' }],
+    operationCertificateNum: [{ required: true, message: '请输入操作证号', trigger: 'blur' }],
+}

+ 31 - 21
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/configs/tables.ts

@@ -1,3 +1,10 @@
+/*
+ * @Author: liuJie
+ * @Date: 2026-02-03 17:55:50
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-24 17:33:42
+ * @Describe: file describe
+ */
 import type { TableColumnProps } from '@/types/basic-table';
 
 // 基础表格样式配置
@@ -7,49 +14,52 @@ export const TABLE_OPTIONS = {
   maxHeight: 'calc(70vh - 150px)',
 };
 
-export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
+export const TABLE_COLUMNS: TableColumnProps[] = [
   {
     label: '编号',
-    type: 'index',
+    prop: 'serialNum',
     align: 'center',
     width: '80px',
   },
   {
-    label: '物品名称',
-    prop: 'itemName',
+    label: '员工工号',
+    prop: 'staffNo',
     align: 'left',
-    minWidth: '120px',
   },
   {
-    label: '入库日期',
-    prop: 'warehouseDate',
+    label: '状态',
+    prop: 'statusName',
     align: 'left',
-    minWidth: '120px',
   },
   {
-    label: '物品数量',
-    prop: 'itemQuantity',
+    label: '员工姓名',
+    prop: 'staffName',
     align: 'center',
-    minWidth: '120px',
   },
   {
-    label: '经办人',
-    prop: 'handler',
+    label: '从事岗位',
+    prop: 'staffJob',
     align: 'left',
-    minWidth: '120px',
   },
   {
-    label: '备注',
-    prop: 'remarks',
+    label: '文化程度',
+    prop: 'highestDegree',
     align: 'left',
-    minWidth: '150px',
   },
   {
-    label: '状态',
-    prop: 'status',
-    slot: 'status',
+    label: '本岗位工龄',
+    prop: 'jobSeniority',
+    align: 'center',
+  },
+  {
+    label: '职称',
+    prop: 'professionalTitle',
+    align: 'left',
+  },
+  {
+    label: '入职日期',
+    prop: 'dateOfJoining',
     align: 'center',
-    minWidth: '100px',
   },
   {
     label: '操作',

+ 165 - 211
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/employeeTrainingRecordCardManagement.vue

@@ -1,264 +1,218 @@
 <template>
-  <div class="safety-platform-container">
-    <header class="safety-platform-container__header">
-      <div class="breadcrumb-title"> 物品库存管理 </div>
-    </header>
-    <main class="safety-platform-container__main">
-      <div class="search-table-container">
-        <header>
-          <div style="position: relative">
-            <el-button type="primary" class="search-table-container--button" @click="handleCreate">
-              添加
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleImport">
-              导入
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleDownload">
-              导出
-            </el-button>
-          </div>
-
-          <div class="act-search">
-            <section class="select-box">
-              <div class="select-box--item">
-                <span>物品名称:</span>
-                <el-input
-                  v-model="tableQuery.queryParam.stuffName"
-                  placeholder="搜索物品名称"
-                  class="act-search-input"
-                />
-              </div>
-              <div class="select-box--item">
-                <span>状态:</span>
-                <el-select
-                  v-model="tableQuery.queryParam.status"
-                  placeholder="请选择状态"
-                  clearable
-                >
-                  <el-option label="启用" :value="true" />
-                  <el-option label="禁用" :value="false" />
-                </el-select>
-              </div>
-            </section>
-            <section class="search-btn">
-              <el-button type="primary" @click="handleSearch">查询</el-button>
-              <el-button @click="handleReset">重置</el-button>
-            </section>
-          </div>
+    <div class="safety-platform-container">
+        <header class="safety-platform-container__header">
+            <div class="breadcrumb-title"> 员工培训记录卡管理 </div>
         </header>
-
-        <div class="batch-table">
-          <BasicTable
-            ref="basicTableRef"
-            :tableData="tableData"
-            :tableConfig="tableConfig"
-            @update:pageSize="handleSizeChange"
-            @update:pageNumber="handleCurrentChange"
-          >
-            <template #status="scope">
-              <span>
-                {{ scope.row.statusName || (scope.row.status === true || scope.row.status === 'true' ? '启用' : scope.row.status === false || scope.row.status === 'false' ? '禁用' : '-') }}
-              </span>
-            </template>
-            <template #action="scope">
-              <div class="action-container--div" style="justify-content: left">
-                <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
-                <ActionButton
-                  text="删除"
-                  :popconfirm="{
-                    title: '确定要删除?',
-                  }"
-                  @confirm="handleDelete(scope.row.id)"
-                />
-                <ActionButton text="查看" @click="handleView(scope.row.id)" />
-              </div>
-            </template>
-          </BasicTable>
-        </div>
-      </div>
-    </main>
-    <BatchImport
-      v-if="batchImportVisible"
-      :visible="batchImportVisible"
-      :import-api-url="importApiUrl"
-      :template-url="templateUrl"
-      template-name="下载模板"
-      :show-template="false"
-      @close="batchImportVisible = false"
-      @update="handleUpdate"
-    />
-  </div>
+        <main class="safety-platform-container__main">
+            <div class="search-table-container">
+                <header>
+                    <div style="position: relative">
+                        <!-- <el-button plain class="search-table-container--button" @click="handleImport">
+                            导入
+                        </el-button>
+                        <el-button plain class="search-table-container--button" @click="handleDownload">
+                            导出
+                        </el-button> -->
+                    </div>
+
+                    <div class="act-search">
+                        <section class="select-box">
+                            <div class="select-box--item">
+                                <span>员工工号或姓名:</span>
+                                <el-input v-model="tableQuery.queryParam.numOrName" placeholder="搜索员工工号或姓名"
+                                    class="act-search-input" />
+                            </div>
+                            <div class="select-box--item">
+                                <span>状态:</span>
+                                <el-select v-model="tableQuery.queryParam.status" placeholder="请选择状态" clearable>
+                                    <el-option label="全部" value="" />
+                                    <el-option label="启用" :value="1" />
+                                    <el-option label="禁用" :value="0" />
+                                </el-select>
+                            </div>
+                            <div>
+                                <span>入职日期范围:</span>
+                                <el-date-picker v-model="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>
+                        </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="删除" :popconfirm="{
+                                    title: '确定要删除?',
+                                }" @confirm="handleDelete(scope.row.id)" />
+                                <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                            </div>
+                        </template>
+                    </BasicTable>
+                </div>
+            </div>
+        </main>
+        <BatchImport v-if="batchImportVisible" :visible="batchImportVisible" :import-api-url="importApiUrl"
+            :template-url="templateUrl" template-name="下载模板" :show-template="false" @close="batchImportVisible = false"
+            @update="handleUpdate" />
+    </div>
 </template>
 
 <script setup lang="ts">
-  import { onMounted, reactive, ref } from 'vue';
-  import { ElMessage } from 'element-plus';
-  import BasicTable from '@/components/BasicTable.vue';
-  import useTableConfig from '@/hooks/useTableConfigHook';
-  import ActionButton from '@/components/ActionButton.vue';
-  import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
-  import { useRouter } from 'vue-router';
-  import type { QueryPageRequest } from '@/types/basic-query';
-  import { queryInventoryManage, deleteInventory, exportInventory } from '@/api/inventory';
-  import { downloadByData } from '@/utils/file/download';
-  import BatchImport from '@/components/batch-import/BatchImport.vue';
-  import { useGlobSetting } from '@/hooks/setting';
-  import urlJoin from 'url-join';
-
-  const router = useRouter();
-
-  // 表格
-  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
-
-  const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
-
-  const tableData = ref<any[]>([]);
-
-  const tableQuery = reactive<QueryPageRequest<any>>({
+import { onMounted, reactive, ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import BasicTable from '@/components/BasicTable.vue';
+import useTableConfig from '@/hooks/useTableConfigHook';
+import ActionButton from '@/components/ActionButton.vue';
+import { TABLE_OPTIONS, TABLE_COLUMNS } from './configs/tables';
+import { useRouter } from 'vue-router';
+import type { QueryPageRequest } from '@/types/basic-query';
+import { queryEducationStaffTrainingCardPage, deleteEducationStaffTrainingCard } from '@/api/employee-training-record-card-management';
+import { downloadByData } from '@/utils/file/download';
+import BatchImport from '@/components/batch-import/BatchImport.vue';
+import { useGlobSetting } from '@/hooks/setting';
+import urlJoin from 'url-join';
+
+const router = useRouter();
+
+// 表格
+const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+
+const { tableConfig, pagination } = useTableConfig(TABLE_COLUMNS, TABLE_OPTIONS);
+
+const tableData = ref<any[]>([]);
+// 日期范围
+const dateRange = ref<[string, string] | null>(null);
+
+const tableQuery = reactive<QueryPageRequest<any>>({
     pageNumber: pagination.pageNumber,
     pageSize: pagination.pageSize,
     queryParam: {
-      stuffName: '', // 物品名称
-      status: true, // 状态,默认启用
-      ids: [], // 选择数据的ID
+        numOrName: "",
+        status: "",
+        dateOfJoiningStart: "",
+        dateOfJoiningEnd: ""
     },
-  });
+});
 
-  const handleSizeChange = (value: number) => {
+const handleSizeChange = (value: number) => {
     pagination.pageSize = value;
     tableQuery.pageSize = value;
     getTableData();
-  };
+};
 
-  const handleCurrentChange = (value: number) => {
+const handleCurrentChange = (value: number) => {
     pagination.pageNumber = value;
     tableQuery.pageNumber = value;
     getTableData();
-  };
+};
 
 
-  async function getTableData() {
+async function getTableData() {
     tableConfig.loading = true;
+    tableQuery.queryParam.dateOfJoiningStart = dateRange.value ? dateRange.value[0] : '';
+    tableQuery.queryParam.dateOfJoiningEnd = dateRange.value ? dateRange.value[1] : '';
     try {
-      const res = await queryInventoryManage(tableQuery);
-      if (res) {
-        // 映射返回数据字段到表格字段
-        tableData.value = res.records.map((item) => ({
-          id: item.id,
-          itemName: item.stuffName, // 物品名称
-          warehouseDate: item.inStoreTime, // 入库日期
-          itemQuantity: item.stuffQty, // 物品数量
-          handler: item.createdUserName, // 经办人
-          remarks: item.remark, // 备注
-          status: item.status, // 状态:true-启用,false-禁用
-          statusName: item.statusName, // 状态名称
-        }));
-        pagination.total = res.totalRow;
-      }
+        const res = await queryEducationStaffTrainingCardPage(tableQuery);
+        if (res) {
+            tableData.value = res.records;
+            pagination.total = res.totalRow;
+        }
     } catch (e) {
-      console.error('获取物品库存列表失败:', e);
-      tableData.value = [];
-      pagination.total = 0;
+        tableData.value = [];
+        pagination.total = 0;
     } finally {
-      tableConfig.loading = false;
+        tableConfig.loading = false;
     }
-  }
+}
 
-  const handleSearch = () => {
+const handleSearch = () => {
     pagination.pageNumber = 1;
     tableQuery.pageNumber = 1;
     getTableData();
-  };
-
-  const handleReset = () => {
-    tableQuery.queryParam.stuffName = '';
-    tableQuery.queryParam.status = true; // 重置为默认启用状态
-    tableQuery.queryParam.ids = [];
+};
+
+const handleReset = () => {
+    tableQuery.queryParam.numOrName = '';
+    tableQuery.queryParam.status = '';
+    tableQuery.queryParam.dateOfJoiningStart = '';
+    tableQuery.queryParam.dateOfJoiningEnd = '';
+    dateRange.value = null;
+    tableQuery.pageNumber = 1;
     handleSearch();
-  };
+};
 
-  // 批量导入
-  const batchImportVisible = ref(false);
-  const { urlPrefix } = useGlobSetting();
-  const importApiUrl = ref(urlJoin(urlPrefix, '/inventory/importInventory'));
-  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-inventory-template.xlsx');
+// 批量导入
+const batchImportVisible = ref(false);
+const { urlPrefix } = useGlobSetting();
+const importApiUrl = ref(urlJoin(urlPrefix, '/inventory/importInventory'));
+const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-inventory-template.xlsx');
 
-  const handleImport = () => {
+const handleImport = () => {
     batchImportVisible.value = true;
-  };
+};
 
-  const handleUpdate = () => {
+const handleUpdate = () => {
     batchImportVisible.value = false;
     getTableData();
-  };
+};
 
-  const handleDownload = async () => {
+const handleDownload = async () => {
     try {
-      const exportParams = {
-        stuffName: tableQuery.queryParam.stuffName || undefined,
-        status: tableQuery.queryParam.status,
-        ids: tableQuery.queryParam.ids.length > 0 ? tableQuery.queryParam.ids : undefined,
-      };
-      const response = await exportInventory(exportParams);
-      if (response) {
-        const fileName = `物品库存管理_${new Date().toISOString().split('T')[0]}.xlsx`;
-        downloadByData(response, fileName);
-        ElMessage.success('导出成功');
-      }
+        const exportParams = {
+            stuffName: tableQuery.queryParam.stuffName || undefined,
+            status: tableQuery.queryParam.status,
+            ids: tableQuery.queryParam.ids.length > 0 ? tableQuery.queryParam.ids : undefined,
+        };
+        // const response = await exportInventory(exportParams);
+        // if (response) {
+        //     const fileName = `物品库存管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        //     downloadByData(response, fileName);
+        //     ElMessage.success('导出成功');
+        // }
     } catch (e) {
-      console.error('导出物品库存失败:', e);
-      ElMessage.error('导出失败,请重试');
+        console.error('导出物品库存失败:', e);
+        ElMessage.error('导出失败,请重试');
     }
-  };
+};
 
-  const handleCreate = () => {
-    router.push({
-      name: 'employeeTrainingRecordCardManagementItem',
-      query: {
-        operate: 'employee-training-record-card-management-create',
-      },
-    });
-  };
-
-  const handleEdit = (id: number) => {
-    router.push({
-      name: 'employeeTrainingRecordCardManagementItem',
-      query: {
-        id,
-        operate: 'employee-training-record-card-management-edit',
-      },
-    });
-  };
 
-  const handleDelete = async (id: number) => {
+const handleDelete = async (id: number) => {
     try {
-      await deleteInventory(id);
-      ElMessage.success('删除成功');
-      getTableData();
+        await deleteEducationStaffTrainingCard(id);
+        ElMessage.success('删除成功');
+        getTableData();
     } catch (e) {
-      console.error('删除物品库存失败:', e);
-      ElMessage.error('删除失败,请重试');
+        console.error('删除失败:', e);
+        ElMessage.error('删除失败,请重试');
     }
-  };
+};
 
-  const handleView = (id: number) => {
+const handleView = (id: number) => {
     router.push({
-      name: 'employeeTrainingRecordCardManagementItem',
-      query: {
-        id,
-        operate: 'employee-training-record-card-management-view',
-      },
+        name: 'employeeTrainingRecordCardManagementItem',
+        query: {
+            id,
+            operate: 'employee-training-record-card-management-view',
+        },
     });
-  };
+};
 
-  onMounted(() => {
+onMounted(() => {
     getTableData();
-  });
+});
 </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 '@/views/traffic/violation/style/act-search-table.scss' as *;
+@use '@/styles/page-details-layout.scss' as *;
+@use '@/styles/page-main-layout.scss' as *;
+@use '@/styles/basic-table-action.scss' as *;
+@use '@/views/traffic/violation/style/act-search-table.scss' as *;
 </style>

+ 34 - 28
src/views/production-safety/safetyTrainingAndEducation/employeeTrainingRecordCardManagement/employeeTrainingRecordCardManagementItem.vue

@@ -1,44 +1,50 @@
+<!--
+ * @Author: liuJie
+ * @Date: 2026-02-03 17:55:50
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-02-24 17:29:40
+ * @Describe: file describe
+-->
 <template>
-  <div class="safety-platform-container">
-    <header class="safety-platform-container__header">
-      <BreadcrumbBack />
-      <span class="breadcrumb-title">{{ headerTitle }}</span>
-    </header>
-    <EmployeeTrainingRecordCardManagementDetail />
-  </div>
+    <div class="safety-platform-container">
+        <header class="safety-platform-container__header">
+            <BreadcrumbBack />
+            <span class="breadcrumb-title">{{ headerTitle }}</span>
+        </header>
+        <EmployeeTrainingRecordCardManagementDetail />
+    </div>
 </template>
 
 <script setup lang="ts">
-  import { computed } from 'vue';
-  import { useRoute } from 'vue-router';
-  import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
-  import EmployeeTrainingRecordCardManagementDetail from './components/employeeTrainingRecordCardManagementDetail.vue';
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
+import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
+import EmployeeTrainingRecordCardManagementDetail from './components/employeeTrainingRecordCardManagementDetail.vue';
 
-  const route = useRoute();
-  const operate = route.query.operate as string;
+const route = useRoute();
+const operate = route.query.operate as string;
 
-  const headerTitle = computed(() => {
+const headerTitle = computed(() => {
     switch (operate) {
-      case 'employee-training-record-card-management-create':
-        return '新增物品';
-      case 'employee-training-record-card-management-edit':
-        return '编辑物品';
-      case 'employee-training-record-card-management-view':
-        return '查看物品';
-      default:
-        return '未知操作';
+        case 'employee-training-record-card-management-create':
+            return '新增员工培训记录卡';
+        case 'employee-training-record-card-management-edit':
+            return '编辑员工培训记录卡';
+        case 'employee-training-record-card-management-view':
+            return '查看员工培训记录卡';
+        default:
+            return '未知操作';
     }
-  });
+});
 </script>
 
 <style scoped lang="scss">
-  @use '@/styles/page-details-layout.scss' as *;
-  @use '@/styles/page-main-layout.scss' as *;
+@use '@/styles/page-details-layout.scss' as *;
+@use '@/styles/page-main-layout.scss' as *;
 
-  .safety-platform-container__header {
+.safety-platform-container__header {
     flex-direction: row !important;
     justify-content: flex-start !important;
     gap: 8px !important;
-  }
+}
 </style>
-