Przeglądaj źródła

fix: 安全文化活动管理下发完成

xiaweibo 2 miesięcy temu
rodzic
commit
55ccd23c09

+ 26 - 0
src/api/drawLessons/index.ts

@@ -64,6 +64,20 @@ export function queryDrawLessonsAdminPage(
   });
 }
 
+/**
+ * 2.1 分页查询举一反三
+ * POST /api/drawLessons/admin/queryPage
+ */
+export function queryDrawLessonsAdminDeptPage(
+  query: QueryPageRequest<DrawLessonsQueryParam>,
+) {
+  return http.request<QueryPageResponse<DrawLessonsItem>>({
+    url: '/drawLessons/dept/queryPage',
+    method: 'post',
+    data: query,
+  });
+}
+
 /**
  * 2.2 查询举一反三详情
  * GET /api/drawLessons/admin/queryDetail?id=xxx
@@ -76,6 +90,18 @@ export function getDrawLessonsAdminDetail(id: number) {
   });
 }
 
+/**
+ * 2.2 查询举一反三详情
+ * GET /api/drawLessons/admin/queryDetail?id=xxx
+ */
+export function getDrawLessonsAdminDeptDetail(id: number) {
+  return http.request<DrawLessonsItem>({
+    url: '/drawLessons/dept/queryDetail',
+    method: 'get',
+    params: { id },
+  });
+}
+
 /**
  * 2.3 新增举一反三
  * POST /api/drawLessons/admin/save

+ 22 - 0
src/api/safety-culture/index.ts

@@ -108,6 +108,15 @@ export interface ActivityRegistrationTargetItem {
   subtractScore: number; // 减分项分数
 }
 
+
+export interface IssueHiddenDangerRequest {
+  id: number;
+  specificDeptId: string;
+  specificPersonId: string;
+  startTime: string;
+  endTime: string;
+}
+
 // =============================== 事故案例管理 ============================
 
 /**
@@ -467,4 +476,17 @@ export function exportAccidentCaseManagementFile(params?: ProductionSafetyFileEx
   }, {
     isTransformResponse: false,
   });
+}
+
+/**
+ * 安全文化活动下发
+ * PUT /api/safetyCulture/activity/assign
+ */
+
+export function activityDistribution(data: IssueHiddenDangerRequest) {
+  return http.request({
+    url: '/safetyCulture/activity/assign',
+    method: 'put',
+    data,
+  });
 }

+ 21 - 0
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/oneByOneManagement/configs/tables.ts

@@ -58,6 +58,27 @@ export const DRAW_LESSONS_TABLE_COLUMNS: TableColumnProps[] = [
     minWidth: '140px',
     showOverflowTooltip: true,
   },
+  {
+    label: '下发数',
+    prop: 'issueCount',
+    slot: 'issueCount',
+    align: 'center',
+    width: '120px',
+  },
+  {
+    label: '反馈人数',
+    prop: 'feedbackCount',
+    slot: 'feedbackCount',
+    align: 'center',
+    width: '120px',
+  },
+  {
+    label: '反馈比例',
+    prop: 'feedbackRatio',
+    slot: 'feedbackRatio',
+    align: 'center',
+    width: '120px',
+  },
   {
     label: '计划完成时间',
     prop: 'associationOtTimeLimit',

+ 7 - 4
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/oneByOneManagementDept/components/oneByOneManagementDeptDetail.vue

@@ -66,7 +66,7 @@
           <span>是否存在问题</span>
         </h4>
         <div class="detail-ct detail-ct--radio">
-          <el-radio-group v-model="hasProblem" class="has-problem-radio">
+          <el-radio-group v-model="hasProblem" :disabled="isViewMode" class="has-problem-radio">
             <el-radio :label="false">否</el-radio>
             <el-radio :label="true">是</el-radio>
           </el-radio-group>
@@ -151,7 +151,7 @@
     </main>
     <footer class="safety-platform-container__footer">
       <el-button @click="router.back()">返回</el-button>
-      <el-button type="primary" @click="handleSubmit">
+      <el-button type="primary" @click="handleSubmit" v-if="!isViewMode">
         提交
       </el-button>
     </footer>
@@ -204,7 +204,7 @@
   import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
   import type { FileItem } from '@/components/UploadFiles/types';
   import { formatAttachmentList } from '@/components/UploadFiles/utils';
-  import { getDrawLessonsAdminDetail } from '@/api/drawLessons';
+  import { getDrawLessonsAdminDeptDetail } from '@/api/drawLessons';
   import { submitDrawLessonsDeptFeedback, type DeptFeedbackRequest } from '@/api/drawLessons';
   import { FILE_TYPE_ICON } from '@/components/UploadFiles/constants';
   import DownloadIcon from '@/views/disaster/disaster-control/src/svg/download.svg';
@@ -214,6 +214,8 @@
   const route = useRoute();
 
   const currentId = computed(() => Number(route.query.id));
+  const isViewMode = computed(() => route.query.operate === 'one-by-one-dept-view');
+
 
   /** 是否存在问题:否/是,为是时材料上传显示选择附件 */
   const hasProblem = ref(false);
@@ -335,10 +337,11 @@
   const getDetail = async () => {
     if (!currentId.value) return;
     try {
-      const res = await getDrawLessonsAdminDetail(currentId.value);
+      const res = await getDrawLessonsAdminDeptDetail(currentId.value);
       const data = (res as any)?.data ?? res;
       if (data && typeof data === 'object') {
         detailData.value = data;
+        hasProblem.value = Number(data.feedbackHasIssue) === 1 ? true : false;
       }
     } catch (e) {
       console.error('获取举一反三详情失败:', e);

+ 1 - 1
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/oneByOneManagementDept/configs/tables.ts

@@ -59,7 +59,7 @@ export const DRAW_LESSONS_DEPT_TABLE_COLUMNS: TableColumnProps[] = [
     prop: 'action',
     slot: 'action',
     fixed: 'right',
-    width: '100px',
+    width: '140px',
     align: 'left',
   },
 ];

+ 20 - 4
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/oneByOneManagementDept/oneByOneManagementDept.vue

@@ -72,7 +72,11 @@
                 <ActionButton
                   v-if="scope.row.statusId === 3"
                   text="反馈"
-                  @click="handleFeedback(scope.row.id)"
+                  @click="handleFeedback(scope.row.associationOtId)"
+                />
+                <ActionButton
+                  text="查看"
+                  @click="handleView(scope.row.associationOtId)"
                 />
               </div>
             </template>
@@ -103,7 +107,7 @@
   import { useRouter } from 'vue-router';
   import type { QueryPageRequest } from '@/types/basic-query';
   import {
-    queryDrawLessonsAdminPage,
+    queryDrawLessonsAdminDeptPage,
     type DrawLessonsQueryParam,
   } from '@/api/drawLessons';
   import { downloadByData } from '@/utils/file/download';
@@ -159,7 +163,7 @@
     applyPlanDateRange();
     tableConfig.loading = true;
     try {
-      const res = await queryDrawLessonsAdminPage(tableQuery);
+      const res = await queryDrawLessonsAdminDeptPage(tableQuery);
       if (res) {
         // 这里暂时共用管理员侧分页接口,后端如有部门侧接口再调整
         tableData.value = res.records.map((item: any) => ({
@@ -170,6 +174,7 @@
           associationOtObligationDeptName: item.associationOtObligationDeptName,
           associationOneThree: item.associationOneThree,
           associationOtTimeLimit: item.associationOtTimeLimit,
+          associationOtId: item.associationOtId,
           planCompleteTime: item.planCompleteTime ?? item.associationOtTimeLimit,
         }));
         pagination.total = (res as any).totalRow ?? (res as any).total ?? 0;
@@ -204,7 +209,7 @@
   const handleDownload = async () => {
     try {
       // 后端如有专门导出接口,可在此替换
-      await queryDrawLessonsAdminPage(tableQuery);
+      await queryDrawLessonsAdminDeptPage(tableQuery);
       ElMessage.success('导出逻辑待实现');
     } catch (e) {
       console.error('导出举一反三失败:', e);
@@ -232,6 +237,17 @@
     });
   };
 
+  /** 查看:跳转详情页,操作仅根据状态显示 */
+  const handleView = (id: number) => {
+    router.push({
+      name: 'oneByOneManagementDeptItem',
+      query: {
+        id: String(id),
+        operate: 'one-by-one-dept-view',
+      },
+    });
+  };
+
   onMounted(() => {
     getTableData();
   });

+ 1 - 1
src/views/production-safety/safety-culture/safetyCultureActivityManagement/configs/tables.ts

@@ -88,7 +88,7 @@ export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
     prop: 'action',
     slot: 'action',
     fixed: 'right',
-    width: '180px',
+    width: '250px',
     align: 'left',
   },
 ];

+ 117 - 73
src/views/production-safety/safety-culture/safetyCultureActivityManagement/safetyCultureActivityManagement.vue

@@ -62,48 +62,57 @@
             </template>
             <template #action="scope">
               <div class="action-container--div" style="justify-content: left">
-                <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
-                <ActionButton text="删除" :popconfirm="{
+                <ActionButton text="编辑" v-if="scope.row.status === 1" @click="handleEdit(scope.row.id)" />
+                <ActionButton text="删除" v-if="scope.row.status === 1" :popconfirm="{
                   title: '确定要删除?',
                 }" @confirm="handleDelete(scope.row.id)" />
-                <!-- <ActionButton text="查看" @click="handleView(scope.row.id)" /> -->
-                <ActionButton text="下发" @click="handleDispatch(scope.row.id)" />
+                <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                <ActionButton text="下发" @click="handleDispatch(scope.row.id)" v-if="scope.row.status === 1"/>
+                <ActionButton text="活动报名" @click="" v-if="scope.row.status !== 1"/>
               </div>
             </template>
           </BasicTable>
         </div>
       </div>
       
-      <el-dialog v-model="issueDialogVisible" title="安全文化活动下发" width="480px" destroy-on-close>
-        <el-form :model="issueForm" label-width="130px" class="issue-dialog-form">
-          <el-form-item label="负责人部门名称:">
+      <el-dialog
+        v-model="showIssueDialog"
+        title="安全文化活动下发"
+        width="500px"
+        destroy-on-close
+        @open="onIssueDialogOpen"
+      >
+        <el-form ref="issueFormRef" :model="issueForm" :rules="issueRules" label-width="140px">
+          <el-form-item label="整改责任部门" prop="rectificationDepartmentId">
             <el-cascader
-              ref="issueDeptCascaderRef"
-              v-model="issueDeptIds"
-              :options="deptTree"
+              v-model="issueForm.rectificationDepartmentId"
+              :options="issueDeptTree"
               :props="cascaderDeptProp"
               :show-all-levels="false"
-              placeholder="请选择部门(可多选)"
+              placeholder="请选择整改责任部门"
               filterable
               clearable
-              collapse-tags
-              collapse-tags-tooltip
               style="width: 100%"
-              @change="handleIssueDeptChange"
+              @change="onIssueDeptChange"
             />
           </el-form-item>
-          <el-form-item label="负责人名称:">
+          <el-form-item label="整改负责人" prop="rectificationResponsibleUserId">
             <el-select
-              v-model="issueForm.userGroupId"
-              placeholder="请选择用户组"
+              v-model="issueForm.rectificationResponsibleUserId"
+              placeholder="选择整改负责人"
               filterable
               clearable
               style="width: 100%"
             >
-              <el-option v-for="item in userGroupOptions" :key="item.id" :label="item.name" :value="item.id" />
+              <el-option
+                v-for="user in issueUserList"
+                :key="user.id"
+                :label="user.realname ?? user.username"
+                :value="user.id"
+              />
             </el-select>
           </el-form-item>
-          <el-form-item label="计划开始日期:">
+          <el-form-item label="计划开始日期:" prop="startDate">
             <el-date-picker
               v-model="issueForm.startDate"
               type="date"
@@ -119,7 +128,7 @@
               }"
             />
           </el-form-item>
-          <el-form-item label="计划结束日期:">
+          <el-form-item label="计划结束日期:" prop="endDate">
             <el-date-picker
               v-model="issueForm.endDate"
               type="date"
@@ -137,10 +146,8 @@
           </el-form-item>
         </el-form>
         <template #footer>
-          <span class="dialog-footer">
-            <el-button @click="issueDialogVisible = false">取消</el-button>
-            <el-button type="primary" @click="handleIssueConfirm">确定</el-button>
-          </span>
+          <el-button @click="showIssueDialog = false">取消</el-button>
+          <el-button type="primary" @click="handleIssueSave">保存</el-button>
         </template>
       </el-dialog>
 
@@ -163,6 +170,7 @@ import {
   safetyCultureActivityManagementFilePage,
   deleteSafetyCultureActivityManagement,
   getAllDepartments,
+  activityDistribution,
   type safetyCultureFileQuery,
   type safetyCultureFilePageQuery,
 } from '@/api/safety-culture';
@@ -172,21 +180,37 @@ import BatchImport from '@/components/batch-import/BatchImport.vue';
 import { useGlobSetting } from '@/hooks/setting';
 import urlJoin from 'url-join';
 import { http } from '@/utils/http/axios';
-
+import { queryAvailableUserList } from '@/api/production-safety/responsibility-implementation';
 
 const router = useRouter();
 
-// 下发弹窗相关
-const issueDialogVisible = ref(false);
-const currentIssueId = ref<number | null>(null);
-const issueForm = reactive({
-  departmentName: '',
-  startDate: '',
-  endDate: '',
-  userGroupId: undefined as number | undefined,
-  deptSelfApproveUserId: undefined as number | undefined, // 部门自评审核人ID
+/** 下发弹窗:点击下发打开弹窗,弹窗内部门用 queryAllDeptTree、负责人用 queryAvailableUserList,点击保存才触发下发接口 */
+const showIssueDialog = ref(false);
+const distributionId = ref<number>(0);
+const issueFormRef = ref();
+const issueForm = ref({
+  rectificationDepartmentId: undefined as number | undefined,
+  rectificationResponsibleUserId: undefined as number | undefined,
+  rectificationResponsiblePersonName: '' as string,
+  startDate: '' as string,
+  endDate: '' as string,
 });
-const issueDeptIds = ref<number[]>([]);
+const issueRules = {
+  rectificationDepartmentId: [{ required: true, message: '请选择整改责任部门', trigger: 'change' }],
+  rectificationResponsibleUserId: [{ required: true, message: '请选择整改负责人', trigger: 'change' }],
+  startDate: [{ required: true, message: '请选择计划开始日期', trigger: 'change' }],
+  endDate: [{ required: true, message: '请选择计划结束日期', trigger: 'change' }],
+};
+/** 下发弹窗部门树,与新增隐患台账复查人员所属部门一致(getAllDepartments 取第一级 children) */
+const cascaderDeptProp = {
+  checkStrictly: true,
+  expandTrigger: 'hover' as const,
+  value: 'id',
+  label: 'deptName',
+  emitPath: false,
+};
+const issueDeptTree = ref<DeptTree[]>([]);
+const issueUserList = ref<Array<{ id: number; realname?: string; username?: string }>>([]);
 
 // 表格
 const basicTableRef = ref<InstanceType<typeof BasicTable>>();
@@ -472,62 +496,82 @@ const activityRegistration = async (id: number) => {
   });
 };
 
-const handleIssueConfirm = async () => {
-  if (!currentIssueId.value) {
-    ElMessage.error('缺少考核表ID');
-    return;
-  }
-  if (!issueDeptIds.value?.length) {
-    ElMessage.error('请至少选择一个部门');
-    return;
+const onIssueDialogOpen = async () => {
+  try {
+    const [deptRes, userRes] = await Promise.all([
+      getAllDepartments(),
+      queryAvailableUserList({ pageNumber: 1, pageSize: 9999, queryParam: {} }),
+    ]);
+    const fullTree = (deptRes as DeptTree[]) ?? [];
+    issueDeptTree.value = Array.isArray(fullTree) && fullTree[0]?.children ? fullTree[0].children : [];
+    issueUserList.value = (userRes as any)?.records ?? [];
+  } catch (e) {
+    console.error('获取部门/用户列表失败:', e);
+    ElMessage.error(e?.message || e?.data || '加载部门或负责人列表失败');
+    issueDeptTree.value = [];
+    issueUserList.value = [];
   }
+};
+
+const onIssueDeptChange = () => {
+  issueForm.value.rectificationResponsibleUserId = undefined;
+  issueForm.value.rectificationResponsiblePersonName = '';
+};
+
+const handleDispatch = (id: number) => {
+  distributionId.value = id;
+  showIssueDialog.value = true;
+};
 
-  // 验证日期:开始日期不能大于结束日期
-  if (issueForm.startDate && issueForm.endDate) {
-    const startDate = new Date(issueForm.startDate);
-    const endDate = new Date(issueForm.endDate);
-    if (startDate > endDate) {
-      ElMessage.error('计划开始日期不能大于计划结束日期');
-      return;
+/** 从部门树中根据 id 查找部门名称 */
+function findDeptNameById(nodes: DeptTree[] | undefined, id: number): string {
+  if (!nodes?.length) return '';
+  for (const n of nodes) {
+    if (n.id === id) return n.deptName ?? '';
+    if (n.children?.length) {
+      const found = findDeptNameById(n.children, id);
+      if (found) return found;
     }
   }
+  return '';
+};
 
+const handleIssueSave = async () => {
+  await issueFormRef.value?.validate?.().catch(() => {});
+  const { rectificationDepartmentId, rectificationResponsibleUserId } = issueForm.value;
+  if (rectificationDepartmentId == null || rectificationResponsibleUserId == null) {
+    ElMessage.warning('请选择整改责任部门和整改负责人');
+    return;
+  }
+  if (!issueForm.value.startDate || !issueForm.value.endDate) {
+    ElMessage.warning('请选择计划开始日期和计划结束日期');
+    return;
+  }
+  const selectedUser = issueUserList.value.find((u) => u.id === rectificationResponsibleUserId);
+  const personName = selectedUser?.realname ?? selectedUser?.username ?? '';
+  const deptName = findDeptNameById(issueDeptTree.value, rectificationDepartmentId);
   try {
-    const payload = {
-      id: currentIssueId.value,
-      deptNames: issueForm.departmentName,
-      deptIds: issueDeptIds.value,
-      getUserGroupId: issueForm.userGroupId,
-      deptSelfApproveUserId: issueForm.deptSelfApproveUserId,
-      planStartTime: issueForm.startDate || undefined,
-      planEndTime: issueForm.endDate || undefined,
-    };
-    // await saveSecurityExamineIssue(payload);
+    await activityDistribution({
+      id: distributionId.value,
+      specificDeptId: String(rectificationDepartmentId),
+      specificPersonId: String(rectificationResponsibleUserId),
+      startTime: issueForm.value.startDate,
+      endTime: issueForm.value.endDate,
+    });
     ElMessage.success('下发成功');
-    // issueDialogVisible.value = false;
-    // getTableData();
+    showIssueDialog.value = false;
+    getTableData();
   } catch (e) {
     console.error('下发失败:', e);
     ElMessage.error(e?.message || e?.data || '下发失败,请重试');
   }
 };
 
-const handleDispatch = async (id: number) => {
-  issueDialogVisible.value = true;
-};
-
-const getDeptData = () => {
-  getAllDepartments().then((res) => {
-    firstLevelDepts.value = formatDeptTree(res);
-  });
-};
-
 onMounted(() => {
   loadDeptNameMap().finally(() => {
     getTableData();
   });
   // loginSw();
-  getDeptData();
 });
 </script>