فهرست منبع

feat: 创建计划与方案

sunqijun 3 ماه پیش
والد
کامیت
3ac2e078be

+ 26 - 0
src/api/production-safety/responsibility-implementation/index.ts

@@ -679,3 +679,29 @@ export function safetyHazardInventoryQueryPlanDetail(id) {
     method: 'get',
   });
 }
+
+/**
+ * 保存安全整改计划与方案 
+ * @param params - 安全整改计划与方案数据
+ * @returns Promise<void>
+ */
+export function safetyHazardInventorySavePlan(params) {
+  return http.request({
+    url: `/safetyHazardInventory/savePlan`,
+    method: 'post',
+    params
+  });
+}
+
+/**
+ * 更新安全整改计划与方案 
+ * @param params - 更新后的安全整改计划与方案数据(需包含 ID)
+ * @returns Promise<void>
+ */
+export function safetyHazardInventoryUpdatePlan(params) {
+  return http.request({
+    url: `/safetyHazardInventory/updatePlan`,
+    method: 'put',
+    params
+  });
+}

+ 15 - 0
src/router/routers/production-safety-router/risk-identification-and-control.ts

@@ -166,6 +166,21 @@
             hidden: false,
             noCache: false,
           }
+        },
+        // 重点部位监控管理
+        {
+          id: 93007,
+          parentId: 90014,
+          name: 'keySiteMonitorManage',
+          path: 'key-site-monitor-manage',
+          component: '/production-safety/risk-identification-and-control/key-site-monitor-manage',
+          meta: {
+            title: '重点部位监控管理',
+            icon: 'OverviewIcon',
+            isRoot: false,
+            hidden: false,
+            noCache: false,
+          }
         }],
     }];
      

+ 274 - 0
src/views/production-safety/risk-identification-and-control/hazard-manage/components/PlansAndProgramsDialog.vue

@@ -0,0 +1,274 @@
+<template>
+  <el-dialog
+    :model-value="props.modelValue"
+    @update:model-value="$emit('update:modelValue', $event)"
+    :title="props.dialogInfo.title"
+    width="600"
+    @close="clearData"
+  >
+    <el-form ref="formRef" label-width="auto" :model="formData" :rules="rules">
+      <el-form-item label="计划和名称" prop="planName">
+        <el-input :disabled="isView" v-model="formData.planName" size="large" />
+      </el-form-item>
+      <el-form-item label="执行部门" prop="execDepartmentId">
+        <el-cascader
+          :disabled="isView"
+          style="width: 100%"
+          v-model="formData.execDepartmentId"
+          size="large"
+          ref="cascaderRef"
+          :options="firstLevelDepts"
+          :props="cascaderProp"
+          :show-all-levels="false"
+          placeholder="请选择责任部门"
+          filterable
+          @change="handleChangeDept('execDepartmentId')"
+        />
+      </el-form-item>
+
+      <el-form-item label="执行人" prop="executor">
+        <el-select
+          :disabled="isView"
+          multiple
+          v-model="formData.executor"
+          placeholder="请选择"
+          size="large"
+          style="width: 100%"
+          filterable
+        >
+          <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="计划内容" prop="planContent">
+        <el-input :disabled="isView" v-model="formData.planContent" type="textarea" :rows="6" size="large" />
+      </el-form-item>
+      <el-form-item prop="planStartDate" label="计划开始日期">
+        <el-date-picker
+          :disabled="isView"
+          v-model="formData.planStartDate"
+          size="large"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          style="width: 100%"
+          placeholder="计划开始日期"
+        />
+      </el-form-item>
+      <el-form-item prop="planEndDate" label="计划结束日期">
+        <el-date-picker
+          :disabled="isView"
+          v-model="formData.planEndDate"
+          style="width: 100%"
+          size="large"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          placeholder="计划结束日期"
+        />
+      </el-form-item>
+      <el-form-item prop="teamName" label="是否推送">
+        <el-radio-group :disabled="isView" v-model="formData.status">
+          <el-radio :value="1">待开始</el-radio>
+          <el-radio :value="2">进行中</el-radio>
+          <el-radio :value="3">已完成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div>
+        <el-button type="primary" @click="submitForm" :loading="submitLoading" :disabled="isView"> 保存 </el-button>
+        <el-button @click="handleCancel">取消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+  import { ref, reactive, watch, onMounted, computed } from 'vue';
+  import type { FormInstance, FormRules } from 'element-plus';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import dayjs from 'dayjs';
+  import {
+    queryAvailableUserList,
+    safetyHazardInventoryQueryPlanDetail,
+  } from '@/api/production-safety/responsibility-implementation';
+
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
+  const props = defineProps<{
+    modelValue: boolean;
+    dialogInfo: { [key: string]: any };
+  }>();
+  const formRef = ref<FormInstance>();
+  const emit = defineEmits(['close', 'submit', 'update:modelValue']);
+  const submitLoading = ref(false);
+  const showDialog = ref(false);
+  const firstLevelDepts = ref<any[]>([]);
+  const cascaderProp = {
+    expandTrigger: 'click',
+    checkStrictly: true,
+    value: 'id',
+    label: 'deptName',
+  };
+  const cascaderRef = ref<any>();
+  const userOptions = ref<any[]>([]);
+  const isView = computed(() => props.dialogInfo.type === 'view');
+
+  const formData = reactive<any>({
+    planName: '',
+    execDepartment: '',
+    execDepartmentId: [],
+    planStartDate: null,
+    planEndDate: null,
+    status: 1,
+    executor: '',
+    planContent: '',
+  });
+  const rules = reactive<Record<string, any>>({
+    planName: [{ required: true, message: '请输入计划和名称' }],
+    planContent: [{ required: true, message: '请输入计划内容' }],
+    execDepartment: [{ required: true, message: '请输入执行部门' }],
+    planStartDate: [
+      { required: true, message: '请选择计划开始日期' },
+      {
+        validator: (rule, value) => {
+          return new Promise((resolve, reject) => {
+            if (value && formData.planEndDate) {
+              if (dayjs(value).isAfter(formData.planEndDate)) {
+                reject(new Error('开始日期不能大于结束日期'));
+                return;
+              }
+            }
+            resolve(true);
+          });
+        },
+      },
+    ],
+    planEndDate: [
+      { required: true, message: '请选择计划结束日期' },
+      {
+        validator: (rule, value) => {
+          return new Promise((resolve, reject) => {
+            if (value && formData.planStartDate) {
+              if (dayjs(value).isBefore(formData.planStartDate)) {
+                reject(new Error('结束日期不能小于开始日期'));
+                return;
+              }
+            }
+            resolve(true);
+          });
+        },
+      },
+    ],
+    executor: [{ required: true, message: '请输入执行人' }],
+  });
+
+  const handleQueryAvailableUserList = (deptName, realname = '') => {
+    return queryAvailableUserList({
+      pageNumber: 1,
+      pageSize: 200,
+      queryParam: {
+        deptName,
+        realname,
+      },
+    }).then((res: any) => {
+      userOptions.value = (res.records || []).map((u: any) => ({
+        value: u.userId || u.id,
+        label: u.realname,
+      }));
+      // switch (prop) {
+      //   case 'safetyResponsibleCenter':
+      //     formValue.safetyCenterManager = null;
+      //     safetyCenterManagerOptions.value = (res.records || []).map((u: any) => ({
+      //       value: u.userId || u.id,
+      //       label: u.realname,
+      //     }));
+      //     break;
+      //   case 'safetyResponsibleDepartment':
+      //     alert('');
+      //     formValue.safetyDepartmentManager = null;
+      //     formValue.safetySpecificPerson = null;
+      //     safetyDepartmentUserOptions.value = (res.records || []).map((u: any) => ({
+      //       value: u.userId || u.id,
+      //       label: u.realname,
+      //     }));
+      //     break;
+      //   default:
+      //     break;
+      // }
+    });
+  };
+
+  function dialogShow() {
+    showDialog.value = true;
+  }
+  function dialogHide() {
+    showDialog.value = false;
+  }
+
+  const getDeptData = () => {
+    return getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+
+  const handleChangeDept = (prop) => {
+    const cascader = cascaderRef.value;
+    const deptInfo = cascader?.getCheckedNodes();
+    formData['execDepartmentId'] = deptInfo[0].pathValues;
+    formData['execDepartment'] = deptInfo[0].label;
+    formRef.value?.validateField('execDepartment');
+    // nextTick(() => {
+    //   handleQueryAvailableUserList(deptInfo[0].label, prop);
+    // });
+  };
+
+  const handleCancel = () => {
+    emit('update:modelValue', false);
+  };
+  function clearData() {
+    formRef.value?.resetFields();
+    Object.assign(formData, {
+      planName: '',
+      execDepartment: '',
+      planStartDate: null,
+      planEndDate: null,
+      status: 0,
+      execPerson: '',
+    });
+  }
+
+  function submitForm() {
+    formRef.value?.validate((valid) => {
+      if (!valid) {
+        return;
+      }
+      emit('submit', formData, submitLoading);
+    });
+  }
+
+  const handlesafetyHazardInventoryQueryPlanDetail = async (id) => {
+    const res = await safetyHazardInventoryQueryPlanDetail(id as string);
+    return res;
+  };
+
+  onMounted(async () => {
+    await Promise.all([getDeptData(), handleQueryAvailableUserList('')]);
+    if (props.dialogInfo.type !== 'add') {
+      handlesafetyHazardInventoryQueryPlanDetail(props.dialogInfo.currentRow.id).then((res) => {
+        Object.assign(formData, {
+          ...res,
+          execDepartmentId: res.execDepartmentId ? res.execDepartmentId.split(',').map((item) => Number(item)) : [],
+          executor: res.executor ? res.executor.split(',').map((item) => Number(item)) : [],
+        });
+      });
+    }
+  });
+
+  defineExpose({
+    submitLoading,
+    dialogShow,
+    dialogHide,
+  });
+</script>
+
+<style scoped lang="scss"></style>

+ 78 - 20
src/views/production-safety/risk-identification-and-control/hazard-manage/create-plan.vue

@@ -53,7 +53,7 @@
         </el-form>
 
         <div>
-          <el-button type="primary" @click="$router.push({ name: 'hazardManageAdd' })">添加 </el-button>
+          <el-button type="primary" @click="handleAddPlan">添加 </el-button>
           <el-button type="primary" @click="queryTableList">查询</el-button>
           <el-button @click="handleRestParams">重置</el-button>
         </div>
@@ -62,24 +62,24 @@
       <div class="table-content">
         <el-table :data="tableData.data">
           <el-table-column type="index" label="序号" width="80" />
-          <el-table-column label="计划/方案名称" prop="planName" width="180" />
+          <el-table-column label="计划/方案名称" prop="planName" width="180">
+            <template #default="scope">
+              <el-link type="primary" underline @click="handleShowPlan(scope)">
+                {{ scope.row.planName }}
+              </el-link>
+            </template>
+          </el-table-column>
 
-          <el-table-column label="状态" prop="statusName" width="80" />
+          <el-table-column label="状态" prop="statusName" width="100" />
           <el-table-column label="执行部门" prop="executorName" width="180" />
           <el-table-column label="执行人" prop="executor" width="130" />
           <el-table-column label="计划/方案描述" prop="planContent" width="180" />
-          <el-table-column label="计划开始时间" prop="planStartDate" width="180" />
-          <el-table-column label="计划结束时间" prop="planEndDate" width="180" />
+          <el-table-column label="计划开始时间" prop="planStartDate" width="220" />
+          <el-table-column label="计划结束时间" prop="planEndDate" width="220" />
 
           <el-table-column fixed="right" min-width="240" label="操作">
             <template #default="scope">
-              <el-button
-                type="primary"
-                link
-                @click="$router.push({ name: 'hazardManageEdit', query: { id: scope.row.id } })"
-              >
-                编辑
-              </el-button>
+              <el-button type="primary" link @click="handleEditPlan(scope)"> 编辑 </el-button>
 
               <el-button type="primary" link @click="handleConfirmDeleteRow(scope)">删除</el-button>
             </template>
@@ -98,6 +98,12 @@
       </div>
     </main>
   </div>
+  <PlansAndProgramsDialog
+    v-if="planDialogOpen"
+    v-model.visible="planDialogOpen"
+    :dialogInfo="dialogInfo"
+    @submit="handlePlanSubmit"
+  />
 </template>
 <script lang="ts" setup>
   import { onMounted, reactive, ref } from 'vue';
@@ -107,6 +113,8 @@
     safetyHazardInventoryQueryPlanAndSchemePage,
     safetyHazardInventoryDeletePlan,
     safetyHazardInventoryQueryPlanDetail,
+    safetyHazardInventorySavePlan,
+    safetyHazardInventoryUpdatePlan,
   } from '@/api/production-safety/responsibility-implementation';
   import { omit } from 'lodash-es';
   import { useUserInfoHook } from '@/hooks/useUserInfoHook';
@@ -114,6 +122,8 @@
   import { downloadFile } from '@/views/disaster/utils';
   import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
   import { getAllDepartments } from '@/api/auth/dept';
+  import PlansAndProgramsDialog from './components/PlansAndProgramsDialog.vue';
+  import { exec } from 'child_process';
 
   const router = useRouter();
   const route = useRoute();
@@ -127,6 +137,7 @@
     label: 'deptName',
   };
   const activeTab = ref('');
+  const planDialogOpen = ref(false);
   const queryParams = reactive<any>({
     pageNumber: 1,
     pageSize: 10,
@@ -148,6 +159,59 @@
     total: 0,
   });
 
+  const dialogInfo = reactive<any>({
+    title: '新增风险源计划与方案',
+    currentRow: null,
+    type: 'add',
+  });
+
+  const handleAddPlan = () => {
+    planDialogOpen.value = true;
+    dialogInfo.title = '新增风险源计划与方案';
+    dialogInfo.type = 'add';
+  };
+
+  const handleEditPlan = async (scope: any) => {
+    dialogInfo.currentRow = scope.row;
+    dialogInfo.title = '编辑风险源计划与方案';
+    dialogInfo.type = 'edit';
+    planDialogOpen.value = true;
+  };
+
+  const handleShowPlan = async (scope: any) => {
+    dialogInfo.currentRow = scope.row;
+    dialogInfo.title = '查看风险源计划与方案';
+    dialogInfo.type = 'view';
+    planDialogOpen.value = true;
+  };
+
+  const handleClosePlanDialog = () => {
+    planDialogOpen.value = false;
+    dialogInfo.currentRow = null;
+    dialogInfo.type = '';
+    dialogInfo.title = '';
+  };
+
+  const handlePlanSubmit = (formData, loading) => {
+    const req = dialogInfo.type === 'edit' ? safetyHazardInventoryUpdatePlan : safetyHazardInventorySavePlan;
+    loading.value = true;
+    req({
+      ...formData,
+      id: dialogInfo.type === 'edit' ? dialogInfo.currentRow.id : undefined,
+      hazardListId: route.query.id,
+      execDepartmentId: formData.execDepartmentId.join(','),
+      executor: formData.executor.join(','),
+    })
+      .then(() => {
+        handleClosePlanDialog();
+        queryTableList();
+        ElMessage.success('操作成功!');
+      })
+      .finally(() => {
+        loading.value = false;
+      });
+  };
+
   const handleSizeChange = (value) => {};
   const handleCurrentChange = (value) => {
     queryParams.pageNumber = value;
@@ -176,7 +240,6 @@
   const queryTableList = () => {
     safetyHazardInventoryQueryPlanAndSchemePage({
       ...queryParams,
-
       queryParam: {
         ...omit(queryParams.queryParam, ['date', 'responsibleDepartmentId']),
         hazardListId: route.query.id,
@@ -185,8 +248,9 @@
         endTime: queryParams.queryParam.date ? queryParams.queryParam.date[1] : undefined,
       },
     }).then((res) => {
-      tableData.data = res.records;
+      tableData.data = res.page.records;
       tableData.total = res.totalRow;
+      Object.assign(detailData, res);
     });
   };
   const handleRestParams = () => {
@@ -203,14 +267,8 @@
     queryTableList();
   };
 
-  const handlesafetyHazardInventoryQueryPlanDetail = async () => {
-    const res = await safetyHazardInventoryQueryPlanDetail(route.query.id as string);
-    Object.assign(detailData, res);
-  };
-
   onMounted(async () => {
     await getDeptData();
-    handlesafetyHazardInventoryQueryPlanDetail();
     queryTableList();
   });
 </script>

+ 1 - 0
src/views/production-safety/risk-identification-and-control/key-site-monitor-manage/index.vue

@@ -0,0 +1 @@
+<template>list minitor</template>

+ 1 - 1
utils/devProxy/staff/proxy.ts

@@ -3,7 +3,7 @@ import path from 'path';
 
 // staff环境
 const proxyStaff: PROXY_TYPE = {
-  serverHost: 'http://192.168.6.42:8802/',
+  serverHost: 'http://192.168.21.154:8802/',
   // serverHost: 'http://192.168.20.4:8802/',
   skyeyeLoginHost: 'http://192.168.6.42:7000/skyeye-login/#/',
   skyeyePlatformHost: 'http://192.168.6.42:7000/skyeye-pc/#/',