Browse Source

完成预防检查

chauncey 11 months ago
parent
commit
821ecd4ef6

+ 11 - 0
src/api/disaster-precaution/index.ts

@@ -177,3 +177,14 @@ export const getTaskTemplateDetail = (templateId: number) => {
     params: { templateId },
   });
 };
+
+/**
+ * 添加检查人员
+ */
+export const updateTaskInspector = (data: { id: number; inspectorIdList: number[] }) => {
+  return http.request({
+    url: '/preventInspectTask/updateTaskInspector',
+    method: 'post',
+    data,
+  });
+};

+ 0 - 6
src/types/push-object/index.ts

@@ -1,6 +0,0 @@
-export interface UserInfo {
-  id: number;
-  realname: string;
-  username: string;
-  isSelected?: boolean;
-}

+ 226 - 0
src/views/disaster/components/InspectorSelect.vue

@@ -0,0 +1,226 @@
+<template>
+  <div class="inspector-select">
+    <div class="left">
+      <div class="filter-title">
+        <el-input v-model="queryContent" placeholder="请输入搜索的内容" clearable />
+      </div>
+      <div class="filter-result">
+        <el-tree
+          ref="treeRef"
+          :data="treeData"
+          node-key="id"
+          show-checkbox
+          :props="{
+            label: 'label',
+            children: 'children',
+            disabled: (data) => !data.isUser || disabledIds.includes(data.id),
+          }"
+          placeholder="请选择任务检查人"
+          filterable
+          check-strictly
+          default-expand-all
+          :filter-node-method="filterNode"
+          @check-change="handleCheckChange"
+        >
+          <template #empty>
+            <div class="empty">
+              <img :src="empty" alt="" />
+              <div>暂无数据</div>
+            </div>
+          </template>
+        </el-tree>
+      </div>
+    </div>
+    <div class="right">
+      <div class="head">
+        <span>已选择:{{ selectedPersonList.length }}人</span>
+      </div>
+      <div class="selected">
+        <el-tag
+          v-for="person in selectedPersonList"
+          :key="person.id"
+          :closable="!person.checked"
+          @close="handleTagClose(person.id)"
+        >
+          {{ person.realname }}({{ person.staffNo }})
+        </el-tag>
+      </div>
+      <div class="footer">
+        <el-button @click="emit('cancel')">取消</el-button>
+        <el-button type="primary" @click="handleSubmit">确定</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { onMounted, ref, watch, computed } from 'vue';
+  import empty from 'assets/images/empty@1X.png';
+  import type { TreeNode } from '@/views/disaster/types';
+  import type { PersonGroupItem } from '@/types/person-group/type';
+  import { ElMessage, type ElTree } from 'element-plus';
+  import { useUserInfoHook } from '@/views/disaster/hooks/userInfo';
+  import { updateTaskInspector } from '@/api/disaster-precaution';
+
+  const { getUserFirstLevelTreeList, treeData, id: userId } = useUserInfoHook();
+
+  const props = defineProps<{
+    customUserList: PersonGroupItem[];
+    currentTaskId: number | undefined;
+  }>();
+  interface Tree {
+    [key: string]: any;
+  }
+  const queryContent = ref('');
+  const treeRef = ref<InstanceType<typeof ElTree>>();
+  const selectedPersonList = ref<PersonGroupItem[]>([]);
+  const filterNode = (
+    value: string,
+    data: Tree,
+    node: {
+      parent: { label: string; parent: any; level: number };
+      label: string;
+      level: number;
+    },
+  ) => {
+    if (!value) return true;
+    let parentNode = node.parent,
+      labels = [node.label],
+      level = 1;
+    while (level < node.level) {
+      labels = [...labels, parentNode.label];
+      parentNode = parentNode.parent;
+      level++;
+    }
+    return labels.some((label) => label.indexOf(value) !== -1);
+  };
+
+  // 需要禁用的用户ID列表
+  const disabledIds = computed(() => {
+    const selectedIds = selectedPersonList.value.filter((item) => item.checked).map((item) => item.id);
+    const ids = Array.from(new Set([userId, ...selectedIds]));
+    return ids;
+  });
+  const removeSelectedPerson = (id: number) => {
+    const index = selectedPersonList.value.findIndex((item) => item.id === id);
+    if (index !== -1) {
+      selectedPersonList.value.splice(index, 1);
+    }
+  };
+  const handleCheckChange = (node: TreeNode, checked: boolean) => {
+    if (checked) {
+      const selectedPerson = {
+        id: node.id,
+        realname: node.label.split('(')[0],
+        staffNo: node.staffNo || '',
+        checked: false,
+      };
+      selectedPersonList.value.push(selectedPerson);
+    } else {
+      removeSelectedPerson(node.id);
+    }
+  };
+  const handleTagClose = (id) => {
+    const index = selectedPersonList.value.findIndex((item) => item.id === id);
+    if (index !== -1) {
+      selectedPersonList.value.splice(index, 1);
+      treeRef.value!.setChecked(id, false, true);
+    }
+  };
+  const emit = defineEmits(['cancel']);
+  const handleSubmit = async () => {
+    if (!props.currentTaskId) return;
+    const ids = selectedPersonList.value.map((item) => item.id);
+    await updateTaskInspector({
+      id: props.currentTaskId,
+      inspectorIdList: ids,
+    });
+    ElMessage.success('添加检查人员成功');
+    emit('cancel');
+  };
+  onMounted(async () => {
+    await getUserFirstLevelTreeList();
+  });
+  watch(queryContent, (val) => {
+    treeRef.value!.filter(val);
+  });
+  watch(
+    () => props.customUserList,
+    (newVal) => {
+      selectedPersonList.value = newVal;
+    },
+    {
+      immediate: true,
+    },
+  );
+</script>
+
+<style lang="scss" scoped>
+  .inspector-select {
+    display: flex;
+    width: 100%;
+    height: 600px;
+    .left {
+      display: flex;
+      flex-direction: column;
+      gap: 10px;
+      width: 50%;
+      height: 100%;
+      padding: 0 5px;
+      border-right: 1px solid rgba($text-color, 0.1);
+    }
+    .filter-result {
+      flex: 1;
+      overflow-y: auto;
+      .el-tree {
+        width: 100%;
+        height: 100%;
+      }
+      .empty,
+      img {
+        width: 100%;
+      }
+      .empty {
+        @include flex-center;
+        flex-direction: column;
+        height: 100%;
+        gap: 5px;
+      }
+    }
+    .select-type {
+      width: 75px;
+    }
+    .right {
+      display: flex;
+      flex-direction: column;
+      flex: 1;
+      height: 100%;
+      position: relative;
+      margin-left: 16px;
+      gap: 20px;
+      .head {
+        display: flex;
+        align-items: center;
+        font-weight: 400;
+        font-size: 16px;
+        color: rgba($text-color, 0.88);
+        line-height: 22px;
+        margin: 6px 0 6px;
+      }
+      .selected {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 8px;
+        overflow-y: auto;
+        max-height: calc(100% - 120px);
+      }
+      .footer {
+        display: flex;
+        gap: 6px;
+        position: absolute;
+        right: 24px;
+        bottom: 20px;
+      }
+    }
+  }
+</style>

+ 0 - 222
src/views/disaster/components/User.vue

@@ -1,222 +0,0 @@
-<template>
-  <div class="User">
-    <div class="left">
-      <div class="filter-title">
-        <el-input v-model="queryContent" placeholder="请输入搜索的内容" clearable>
-          <template #prepend>
-            <el-select v-model="selectType" class="select-type">
-              <el-option v-for="item in searchOptions" :key="item.value" :value="item.value" :label="item.label" />
-            </el-select>
-          </template>
-        </el-input>
-        <el-button type="primary" @click="handleSearch">搜 索</el-button>
-      </div>
-      <div class="filter-result" v-loading="loading">
-        <div class="empty" v-if="nodeData[0].children.length === 0">
-          <img :src="empty" alt="" />
-          <div>暂无数据</div>
-        </div>
-        <el-tree
-          v-else
-          ref="treeRef"
-          :data="nodeData"
-          show-checkbox
-          node-key="id"
-          :props="defaultProps"
-          :default-expand-all="true"
-          style="padding: 10px 0"
-          @check-change="handleCheckChange"
-        />
-      </div>
-    </div>
-    <div class="right">
-      <div class="head">
-        <span>已选择:{{ selectedPersonList.length }}人</span>
-      </div>
-      <div class="selected">
-        <el-tag
-          v-for="person in selectedPersonList"
-          :key="person.id"
-          closable
-          @close="handleRemoveSelectedPerson(person.id)"
-        >
-          {{ person.name }}
-        </el-tag>
-      </div>
-      <div class="footer">
-        <el-button @click="emit('cancel')">取消</el-button>
-        <el-button type="primary" @click="handleSubmit">确定</el-button>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { nextTick, ref, watch } from 'vue';
-  import empty from 'assets/images/empty@1X.png';
-  // import { queryAvailableUserList } from '@/api/push-object';
-  import type { TreeNodeData } from '@/views/disaster/types';
-  import type { UserInfo } from '@/types/push-object';
-  import type { ElTree } from 'element-plus';
-  const props = defineProps<{
-    customUserList: UserInfo[];
-  }>();
-  const loading = ref(false);
-  const queryContent = ref('');
-  const treeRef = ref<InstanceType<typeof ElTree>>();
-  const nodeData = ref<TreeNodeData[]>([
-    {
-      id: -1,
-      name: '全部',
-      children: [],
-    },
-  ]);
-  const searchResult = ref<TreeNodeData[]>([]);
-  const selectedPersonList = ref<TreeNodeData[]>([]);
-  const defaultProps = {
-    children: 'children',
-    label: 'name',
-  };
-  const searchOptions = ref([
-    { value: 'realname', label: '姓名' },
-    { value: 'username', label: '工号' },
-  ]);
-  const selectType = ref(searchOptions.value[0].value);
-  const getUserList = async () => {
-    // loading.value = true;
-    // const res = await queryAvailableUserList();
-    // searchResult.value = res.map((user) => {
-    //   return {
-    //     id: user.id,
-    //     name: `${user.username}-${user.realname}`,
-    //     children: [],
-    //   };
-    // });
-    // nodeData.value[0].children = searchResult.value;
-    // const selectedIds = selectedPersonList.value.map((item) => item.id);
-    // await nextTick();
-    // treeRef.value?.setCheckedKeys(selectedIds);
-    // loading.value = false;
-  };
-  const handleSearch = () => {
-    getUserList();
-  };
-  const removeSelectedPerson = (id: number) => {
-    const index = selectedPersonList.value.findIndex((item) => item.id === id);
-    if (index !== -1) {
-      selectedPersonList.value.splice(index, 1);
-    }
-  };
-  const handleCheckChange = (node: TreeNodeData, checked: boolean) => {
-    if (node.children.length) return;
-    if (checked) {
-      const exists = selectedPersonList.value.find((item) => item.id === node.id);
-      if (exists) return;
-      selectedPersonList.value.push(node);
-    } else {
-      removeSelectedPerson(node.id);
-    }
-  };
-  const handleRemoveSelectedPerson = (id: number) => {
-    removeSelectedPerson(id);
-    if (!treeRef.value) return;
-    treeRef.value.setChecked(id, false, true);
-  };
-  const emit = defineEmits(['cancel', 'submit']);
-  const handleSubmit = () => {
-    const userList = selectedPersonList.value.map((item) => {
-      return {
-        id: item.id,
-        username: item.name.split('-')[0],
-        realname: item.name.split('-')[1],
-      };
-    });
-    emit('submit', userList);
-    emit('cancel');
-  };
-  watch(
-    () => props.customUserList,
-    (newVal) => {
-      selectedPersonList.value = newVal.map((item) => {
-        return {
-          id: item.id,
-          name: `${item.username}-${item.realname}`,
-          children: [],
-        };
-      });
-    },
-    {
-      immediate: true,
-    },
-  );
-</script>
-
-<style lang="scss" scoped>
-  .User {
-    display: flex;
-    width: 100%;
-    height: 100%;
-    .left {
-      display: flex;
-      flex-direction: column;
-      width: 50%;
-      height: 100%;
-      padding: 0 5px;
-      border-right: 1px solid rgba($text-color, 0.1);
-    }
-    .filter-title {
-      @include flex-center;
-      gap: 10px;
-      justify-content: space-between;
-    }
-    .filter-result {
-      flex: 1;
-      overflow-y: auto;
-      .empty,
-      img {
-        width: 100%;
-      }
-      .empty {
-        @include flex-center;
-        flex-direction: column;
-        height: 100%;
-        gap: 5px;
-      }
-    }
-    .select-type {
-      width: 75px;
-    }
-    .right {
-      display: flex;
-      flex-direction: column;
-      flex: 1;
-      height: 100%;
-      position: relative;
-      margin-left: 16px;
-      gap: 20px;
-      .head {
-        display: flex;
-        align-items: center;
-        font-weight: 400;
-        font-size: 16px;
-        color: rgba($text-color, 0.88);
-        line-height: 22px;
-        margin: 6px 0 6px;
-      }
-      .selected {
-        display: flex;
-        flex-wrap: wrap;
-        gap: 8px;
-        overflow-y: auto;
-        max-height: calc(100% - 120px);
-      }
-      .footer {
-        display: flex;
-        gap: 6px;
-        position: absolute;
-        right: 24px;
-        bottom: 20px;
-      }
-    }
-  }
-</style>

+ 21 - 14
src/views/disaster/disaster-precaution/PageTaskExecution.vue

@@ -40,7 +40,7 @@
               <!-- 仅检查责任人可以看到 -->
               <ActionButton
                 text="添加检查人"
-                @click="handleAddCheckUser(scope.row)"
+                @click="handleAddCheckUser(scope.row.id)"
                 v-if="scope.row.userTypeList.includes(USER_TYPE.CHECK_RESPONSIBLE)"
               />
             </div>
@@ -81,6 +81,13 @@
         </BasicTable>
       </div>
     </main>
+    <el-dialog v-model="userInfo" title="添加检查人" destroy-on-close>
+      <InspectorSelect
+        :customUserList="currentTaskInspectorList"
+        :currentTaskId="currentTaskId"
+        @cancel="userInfo = false"
+      />
+    </el-dialog>
   </div>
 </template>
 
@@ -89,6 +96,7 @@
   import BasicTable from '@/components/BasicTable.vue';
   import ActionButton from '@/components/ActionButton.vue';
   import Search from '@/views/disaster/components/Search.vue';
+  import InspectorSelect from '@/views/disaster/components/InspectorSelect.vue';
   import useTableConfig from '@/hooks/useTableConfigHook';
   import {
     getTaskExecutionList,
@@ -104,7 +112,7 @@
   import type { TaskExecutionListQuery } from '@/types/disaster-precaution';
   import type { QueryPageRequest } from '@/types/disaster';
   import { USER_TYPE } from './src/constants/task-execution';
-  import type { UserInfo } from '@/types/push-object';
+  import type { PersonGroupItem } from '@/types/person-group/type';
   import { useRouter } from 'vue-router';
   import { ElMessage } from 'element-plus';
 
@@ -147,18 +155,17 @@
     getTableData();
   };
   const currentTaskId = ref<number>();
-  const currentTaskInspectorList = ref<UserInfo[]>([]);
-  const handleAddCheckUser = async (row: TaskExecutionListResponse) => {
-    currentTaskId.value = row.id;
-    console.log(row);
-    // const res = await getTaskInspectorList(currentTaskId.value);
-    // currentTaskInspectorList.value = res.map((item) => {
-    //   return {
-    //     ...item,
-    //     isSelected: true,
-    //   };
-    // });
-    // userInfo.value = true;
+  const currentTaskInspectorList = ref<PersonGroupItem[]>([]);
+  const handleAddCheckUser = async (id: number) => {
+    currentTaskId.value = id;
+    const res = await getTaskInspectorList(currentTaskId.value);
+    currentTaskInspectorList.value = res.map((item) => {
+      return {
+        ...item,
+        checked: true,
+      };
+    });
+    userInfo.value = true;
   };
   const defaultRouterName = 'disaster-precaution-task-execution-detail';
   const handleCheckItem = (id: number, operationType: 'check' | 'approve' | 'view') => {

+ 6 - 60
src/views/disaster/disaster-precaution/PageTaskExecutionDetail.vue

@@ -32,7 +32,7 @@
               :props="{
                 label: 'label',
                 children: 'children',
-                disabled: (data) => !data.isUser || (data.staffNo && disabledStaffNos.includes(data.staffNo)),
+                disabled: (data) => !data.isUser || (data.id && disabledIds.includes(data.id)),
               }"
               placeholder="请选择审批领导"
               check-strictly
@@ -57,9 +57,7 @@
   import BackIcon from 'assets/svg/back.svg';
   import TemplateTableMerge from './src/components/TemplateTableMerge.vue';
   import { getTaskExecutionDetail, saveTaskDetail, saveTaskApproval } from '@/api/disaster-precaution';
-  import { getUserFirstLevelTree } from '@/api/system/person-group';
   import { useUserInfoHook } from '@/views/disaster/hooks/userInfo';
-  import type { QueryUserFirstLevelTreeRes } from '@/types/person-group/type';
   import type {
     TaskExecutionDetailResponse,
     TemplateDetailResponse,
@@ -67,22 +65,14 @@
     SaveTaskDetailRequest,
   } from '@/types/disaster-precaution';
 
-  const { staffNo } = useUserInfoHook();
+  const { getUserFirstLevelTreeList, treeData, id: userId } = useUserInfoHook();
 
-  // 需要禁用的工号列表
-  const disabledStaffNos = computed(() => {
-    const staffNos = [staffNo];
-    return staffNos;
+  // 需要禁用的用户ID列表
+  const disabledIds = computed(() => {
+    const ids = [userId];
+    return ids;
   });
 
-  interface TreeNode {
-    id: number;
-    label: string;
-    children?: TreeNode[];
-    isUser: boolean;
-    staffNo?: string;
-  }
-
   interface FormModel {
     reviewerId: number | undefined;
   }
@@ -100,45 +90,6 @@
   const operationType = String(route.query.operationType) as OperationType;
   const taskExecutionDetailList = ref<TaskExecutionDetailResponse>();
   const templateDetailList = ref<TemplateDetailResponse>();
-  const userFirstLevelTreeList = ref<QueryUserFirstLevelTreeRes>();
-
-  // 将组织树数据转换为树形选择器所需的格式
-  const treeData = computed<TreeNode[]>(() => {
-    if (!userFirstLevelTreeList.value) return [];
-
-    // 将组织树转换为树形选择器需要的格式
-    const convertToTreeData = (tree: QueryUserFirstLevelTreeRes): TreeNode => {
-      const node: TreeNode = {
-        id: tree.id,
-        label: tree.deptName,
-        isUser: false,
-        children: [],
-      };
-
-      // 添加部门下的用户
-      if (tree.userList && tree.userList.length) {
-        const userNodes: TreeNode[] = tree.userList.map((user) => ({
-          id: user.id,
-          label: user.realname,
-          isUser: true,
-          staffNo: user.staffNo,
-        }));
-        node.children = node.children || [];
-        node.children = [...node.children, ...userNodes];
-      }
-
-      // 添加子部门
-      if (tree.children && tree.children.length) {
-        const childNodes = tree.children.map((child) => convertToTreeData(child));
-        node.children = node.children || [];
-        node.children = [...node.children, ...childNodes];
-      }
-
-      return node;
-    };
-
-    return [convertToTreeData(userFirstLevelTreeList.value)];
-  });
 
   const getTaskExecutionDetailList = async () => {
     const res = await getTaskExecutionDetail(id);
@@ -149,11 +100,6 @@
     templateDetailList.value = JSON.parse(res.detail) as TemplateDetailResponse;
   };
 
-  const getUserFirstLevelTreeList = async () => {
-    const res = await getUserFirstLevelTree();
-    userFirstLevelTreeList.value = res;
-  };
-
   // 处理验证状态变化
   const handleValidateChange = (isValid: boolean) => {
     isFormValid.value = Boolean(isValid);

+ 14 - 10
src/views/disaster/disaster-precaution/src/components/Compliance.vue

@@ -16,28 +16,32 @@
 
 <script lang="ts" setup>
   import { ref, watch } from 'vue';
+  import { COMPLIANCE } from '../constants/template-detail';
   const radioOptions = [
-    { label: '符合', value: 1 },
-    { label: '不符合', value: 2 },
-    { label: '不涉及', value: 3 },
+    { label: '符合', value: COMPLIANCE.ACCORDANCE },
+    { label: '不符合', value: COMPLIANCE.NOT_ACCORDANCE },
+    { label: '不涉及', value: COMPLIANCE.NOT_INVOLVED },
   ];
   const props = defineProps<{
     radioValue: number;
   }>();
-  
+
   const emit = defineEmits(['update:radioValue']);
-  
+
   const radioValueModel = ref(props.radioValue);
-  
+
   // 监听输入值变化,向父组件发送更新事件
   watch(radioValueModel, (newValue) => {
     emit('update:radioValue', newValue);
   });
-  
+
   // 监听props变化,更新本地值
-  watch(() => props.radioValue, (newValue) => {
-    radioValueModel.value = newValue;
-  });
+  watch(
+    () => props.radioValue,
+    (newValue) => {
+      radioValueModel.value = newValue;
+    },
+  );
 </script>
 
 <style lang="scss" scoped>

+ 4 - 3
src/views/disaster/disaster-precaution/src/components/TemplateTableMerge.vue

@@ -96,6 +96,7 @@
   import ActualSituation from './ActualSituation.vue';
   import type { ContentItem } from '@/types/disaster-precaution';
   import { useUserInfoHook } from '@/views/disaster/hooks/userInfo';
+  import { COMPLIANCE } from '../constants/template-detail';
 
   const { realname } = useUserInfoHook();
 
@@ -249,9 +250,9 @@
     const allComplianceSelected = mainData.every((item) => item.compliance !== null && item.compliance !== undefined);
 
     // 检查所有行是否都填写了实际情况
-    const allActualSituationFilled = mainData.every(
-      (item) => item.actualSituation && item.actualSituation.trim() !== '',
-    );
+    const allActualSituationFilled = mainData
+      .filter((item) => item.compliance === COMPLIANCE.NOT_ACCORDANCE)
+      .every((item) => item.actualSituation && item.actualSituation.trim() !== '');
 
     // 检查结论是否已填写
     const resultFilled = props.resultData.executeResult && props.resultData.executeResult.trim() !== '';

+ 9 - 449
src/views/disaster/disaster-precaution/src/constants/template-detail.ts

@@ -5,462 +5,22 @@ import Previous from '../images/previous@1X.png';
 import Midterm from '../images/midterm@1X.png';
 import Later from '../images/later@1X.png';
 import { INSPECT_TYPE } from './task-execution';
-// 模板前、中、后期数据
-export const PREVIOUS_TEMPLATE_DATA = [
-  {
-    inspectItem: '组织管理',
-    inspectStandard: '1.是否成立专项组织机构(领导小组、应急办公室、抢险队伍),明确工作职责。',
-    inspectMethod: '查文件资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '组织管理',
-    inspectStandard: '2.是否召开工作动员会,传达上级会议精神,落实专项工作。',
-    inspectMethod: '查文件资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '组织管理',
-    inspectStandard: '3.是否按照要求组织进行专项安全检查,是否有整改计划及落实整改。',
-    inspectMethod: '查检查记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '制度措施',
-    inspectStandard: '1.是否建立和修订完善有关规章制度、岗位责任及各类案。',
-    inspectMethod: '查文件资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '制度措施',
-    inspectStandard: '2.是否及时制订专项预案、应急预案等,措施是否有效。',
-    inspectMethod: '查文件资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '制度措施',
-    inspectStandard: '3.是否有计划开展专项应急演练。',
-    inspectMethod: '查演练记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '设施设备',
-    inspectStandard: '1.抽排水设备检查、维修是否完成,排水设备是否完好。',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '设施设备',
-    inspectStandard: '2.是否对建筑、厂房、仓库等地易漏水漏雨的地方对进行全面排查统计,是否有应急情况的封堵措施。',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '设施设备',
-    inspectStandard: '3.重点建筑、厂房、飞机型号设施设备仓库防雷接地设备是否有效。',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '通信报讯',
-    inspectStandard: '1.通信是否有保证,通讯联络是否畅通,是否备有应急电话。',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '通信报讯',
-    inspectStandard: '2.与当地应急部门联络方式和报讯是否明确。',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '物资保障',
-    inspectStandard: '1.是否有应急物资采购计划,应急物资是否备足,是否建立物资台账。',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '物资保障',
-    inspectStandard: '2.车辆后勤、应急救援是否有保障。',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '往年情况',
-    inspectStandard: '历年受灾和新近发现问题处理情况,存在问题整改计划,措施落实',
-    inspectMethod: '查现场、有关记录',
-    compliance: null,
-    actualSituation: '',
-  },
-];
-
-export const MIDTERM_TEMPLATE_DATA = [
-  {
-    inspectItem: '防台防汛组织机构运作情况',
-    inspectStandard: '1.领导小组和应急办公室是否按照应急信息要求进行值班。',
-    inspectMethod: '查记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '防台防汛组织机构运作情况',
-    inspectStandard: '2.领导小组是否有效开展工作进行检查、督促、及时落实和传达上级工作要求。',
-    inspectMethod: '查记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '防台防汛组织机构运作情况',
-    inspectStandard: '3.是否召开台汛前部署会议,是否有会议纪要。',
-    inspectMethod: '查文件、记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '措施落实情况',
-    inspectStandard: '1.对台汛前检查查遗留问题是否有措施,落实整改。',
-    inspectMethod: '查报告、记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '措施落实情况',
-    inspectStandard: '2.人员防范知识、风险信息、预警等宣传教育工作落实措施情况。',
-    inspectMethod: '记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '措施落实情况',
-    inspectStandard: '3.工地简易房、板房、低洼地、临时建筑、简陋屋棚等人员疏散措施落实情况。',
-    inspectMethod: '现场',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '措施落实情况',
-    inspectStandard: '4.日常防台汛自查中发现问题是否进行了处理或落实措施。',
-    inspectMethod: '查报告、记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '措施落实情况',
-    inspectStandard: '5.是否按计划开展防台汛预案演练。',
-    inspectMethod: '查记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '措施落实情况',
-    inspectStandard: '6.预案修订完善后的宣贯措施落实情况。',
-    inspectMethod: '查记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '措施落实情况',
-    inspectStandard: '7.各类相关的临时标识是否明确清晰。',
-    inspectMethod: '现场',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '1.建筑、仓库、厂房检查门窗、玻璃是否完好,并全部关闭。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '2.建筑、仓库、厂房屋顶无漏水,(硝盐炉)重点部位是否有应急防护措施。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '3.建筑、仓库、厂房面积较大的门,要在里面设置档杆或斜撑,防被吹坏措施。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '4.建筑、仓库、厂房检查大门遮雨棚是否有锈蚀、松动、断裂等异常,并及时排除加固。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '5.建筑、仓库、厂房关闭通风窗、排风孔,防止雨水进入厂房措施是否有效。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '6.建筑、仓库、厂房顶部物料、垃圾等是否清理完毕;悬挂物清理或加固。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard:
-      '7.防止库房积水(地势低洼的库房门口应设置足够高度防洪沙袋,沙袋间需加添黄土),地势低洼处库房内的电器设备要离开地面。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '8.交配电系统固定线路支架是否松动、断裂。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '9.交配电系统临时线路拆除,电线收好。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '10.室外配电箱(柜)门锁牢,并做好防雨措施,检查基座是否牢固,防止被风吹倒。配电板全部收回仓库。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '11.切断公司全部动力设备(照明电源除外)的电源。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '12.危险品库房、油库油罐、液化气站、天然气站等重点区域防雷接地装置完好可靠。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '13.建筑物和构筑物的防雷接地装置连接可靠。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '14.增加保安值班岗亭配重,棚顶四个角落采用绳索斜拉固定。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '15.检查车棚、风雨棚是否有锈蚀、松动、断裂等异常,并及时排除加固。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施设备',
-    inspectStandard: '16.飞机等露天大型设施设备是否按要求采取系流等固定措施。',
-    inspectMethod: '现场、统计资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard:
-      '1.台风来临前48小时前开始对建筑物、构筑物(仓库、车间为重点)周围排水设施进行检查,做好清淤疏通作业,保证排水设施可靠运行。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard: '2.台风来临前24小时开始对电子主播设备的排水设备进行检查,做好清淤疏通作业,保证排水设施可靠运行。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard: '3.排水困难的地势低洼区域、重点区域、重点设备附近安置排水泵,做好应急准备。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard: '4.检查区域内指示牌、广告牌文采是否牢固,必要时做好拆除处理。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard: '5.已倾倒的移动指示牌、栏杆等放倒处理。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard: '6.外场物品堆放高度要安全符合要求。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard: '7.过高的物品要降低码放高度。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '周边环境',
-    inspectStandard: '8.物资防雨措施落实到位。',
-    inspectMethod: '现场记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '通讯报讯',
-    inspectStandard: '1.通讯是否发生过故障,讯情、灾情是否按规定上报或汇报。',
-    inspectMethod: '查报告、记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '通讯报讯',
-    inspectStandard: '2.通信设备、电气设备是否遭受雷击等自然灾害的影响。',
-    inspectMethod: '查报告、记录',
-    compliance: null,
-    actualSituation: '',
-  },
-];
 
-export const LATER_TEMPLATE_DATA = [
-  {
-    inspectItem: '防台汛管理',
-    inspectStandard: '1.各级防台汛机构值班、防台汛检查是否有效。',
-    inspectMethod: '台账记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '防台汛管理',
-    inspectStandard: '2.历次防台汛检查发现的主要问题是否整改完成,或采取措施。',
-    inspectMethod: '台账记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '防台汛管理',
-    inspectStandard: '3.开展几次防台汛演练,分别是什么预案或专业的演练。',
-    inspectMethod: '台账记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施',
-    inspectStandard: '1.建筑、仓库、厂房是否存在漏雨、损坏等情况;排水设施在台汛期是否出现过异常;异常事件简述。',
-    inspectMethod: '现场资料',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施',
-    inspectStandard: '2.建筑、仓库、厂房排水系统在台汛期是否出现过堵塞,堵塞事件简述。',
-    inspectMethod: '记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施',
-    inspectStandard: '3.是否发生过局部或全单位范围停电现象,其发生过几次及主要原因。',
-    inspectMethod: '记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '各类设施',
-    inspectStandard: '4.重点建筑、厂房、仓库防雷接地装置是否出现故障,共几次及主要原因。',
-    inspectMethod: '记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '通讯报讯',
-    inspectStandard: '1.通讯是否发生过故障;讯情、灾情是否按规定上报或汇报。',
-    inspectMethod: '台账记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '通讯报讯',
-    inspectStandard: '2.通信设备、电气设备是否遭受雷击等自然灾害的影响。',
-    inspectMethod: '台账记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '其他',
-    inspectStandard: '1.台汛期发生过什么紧急的防台防汛事件,对防台防汛造成什么影响。',
-    inspectMethod: '记录',
-    compliance: null,
-    actualSituation: '',
-  },
-  {
-    inspectItem: '其他',
-    inspectStandard: '2.是否及时启动过防台应急预案。',
-    inspectMethod: '记录',
-    compliance: null,
-    actualSituation: '',
-  },
-];
 export const TASK_TEMPLATE_LIST = [
   {
     id: INSPECT_TYPE.Previous,
     name: '台讯前期安全检查模版',
-    img: Previous,
-    data: PREVIOUS_TEMPLATE_DATA,
+    img: Previous
   },
   {
     id: INSPECT_TYPE.Midterm,
     name: '台讯中期安全检查任务模版',
-    img: Midterm,
-    data: MIDTERM_TEMPLATE_DATA,
+    img: Midterm
   },
   {
     id: INSPECT_TYPE.Later,
     name: '台讯后期安全检查模版',
-    img: Later,
-    data: LATER_TEMPLATE_DATA,
+    img: Later
   },
 ];
 
@@ -474,12 +34,6 @@ export const TASK_TEMPLATE_HEADER = [
     content: '对照公司领导及工作会议、通知或相关文件精神要求。',
   },
 ];
-export const TASK_TEMPLATE_FOOTER = [
-  {
-    inspectionResult: '检查结论及存在问题',
-    selfExamination: '自检意见',
-  },
-];
 export const TASK_TEMPLATE_MAIN_COLUMNS = [
   { prop: 'index', label: '序号', width: 60 },
   { prop: 'inspectItem', label: '检查项目', width: 225 },
@@ -487,3 +41,9 @@ export const TASK_TEMPLATE_MAIN_COLUMNS = [
   { prop: 'inspectMethod', label: '检查方法', width: 225 },
 ];
 export const MERGE_FIELDS = ['index', 'inspectItem', 'inspectMethod'];
+
+export enum COMPLIANCE {
+  ACCORDANCE = 1,
+  NOT_ACCORDANCE,
+  NOT_INVOLVED,
+}

+ 50 - 0
src/views/disaster/hooks/userInfo.ts

@@ -1,5 +1,9 @@
 import { useUserStore } from '@/store/modules/user';
 import { storeToRefs } from 'pinia';
+import { computed, ref } from 'vue';
+import type { QueryUserFirstLevelTreeRes } from '@/types/person-group/type';
+import { getUserFirstLevelTree } from '@/api/system/person-group';
+import type { TreeNode } from '@/views/disaster/types';
 
 const userStore = useUserStore();
 const { getUserInfo } = storeToRefs(userStore);
@@ -8,12 +12,58 @@ const { getUserInfo } = storeToRefs(userStore);
  */
 export const useUserInfoHook = () => {
   const userInfo = getUserInfo.value;
+  const id = userInfo.id;
   const staffNo = userInfo.staffNo;
   const realname = userInfo.realname;
   const permissions = userInfo.permissions;
+  const userFirstLevelTreeList = ref<QueryUserFirstLevelTreeRes>();
+  const getUserFirstLevelTreeList = async () => {
+    const res = await getUserFirstLevelTree();
+    userFirstLevelTreeList.value = res;
+  };
+  // 将组织树数据转换为树形选择器所需的格式
+  const treeData = computed<TreeNode[]>(() => {
+    if (!userFirstLevelTreeList.value) return [];
+
+    // 将组织树转换为树形选择器需要的格式
+    const convertToTreeData = (tree: QueryUserFirstLevelTreeRes): TreeNode => {
+      const node: TreeNode = {
+        id: tree.id,
+        label: tree.deptName,
+        isUser: false,
+        children: [],
+      };
+
+      // 添加部门下的用户
+      if (tree.userList && tree.userList.length) {
+        const userNodes: TreeNode[] = tree.userList.map((user) => ({
+          id: user.id,
+          label: `${user.realname}(${user.staffNo})`,
+          isUser: true,
+          staffNo: user.staffNo,
+        }));
+        node.children = node.children || [];
+        node.children = [...node.children, ...userNodes];
+      }
+
+      // 添加子部门
+      if (tree.children && tree.children.length) {
+        const childNodes = tree.children.map((child) => convertToTreeData(child));
+        node.children = node.children || [];
+        node.children = [...node.children, ...childNodes];
+      }
+
+      return node;
+    };
+
+    return [convertToTreeData(userFirstLevelTreeList.value)];
+  });
   return {
+    id,
     realname,
     permissions,
     staffNo,
+    treeData,
+    getUserFirstLevelTreeList,
   };
 };

+ 5 - 3
src/views/disaster/types/index.ts

@@ -1,7 +1,9 @@
-export interface TreeNodeData {
+export interface TreeNode {
   id: number;
-  name: string;
-  children: TreeNodeData[];
+  label: string;
+  children?: TreeNode[];
+  isUser: boolean;
+  staffNo?: string;
 }
 
 export interface FileItem {