Forráskód Böngészése

feat: 危险作业管理接入真实接口,新增批量删除与查看

xieyong 6 napja
szülő
commit
78e2d61f4f

+ 171 - 55
src/views/DangerousWorkManagement/add.vue

@@ -30,23 +30,26 @@
 
       <el-row :gutter="20">
         <el-col :span="12">
-          <el-form-item label="申请单位:" prop="applyDept">
+          <el-form-item label="申请单位:" prop="applyDeptId">
             <dept-select
-              v-model="form.applyDept"
+              v-model="form.applyDeptId"
               placeholder="请选择申请单位"
               style="width: 100%"
+              disabled
               @changeGroup="onDeptChange"
             />
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="申请人:" prop="applyUser">
+          <el-form-item label="申请人:" prop="applicantId">
             <person-select
               ref="personRef"
-              v-model="form.applyUser"
+              v-model="form.applicantId"
               :init="false"
+              :selectList="personList"
               placeholder="请选择申请人"
               style="width: 100%"
+              disabled
               @selfChange="onPersonChange"
             />
           </el-form-item>
@@ -57,10 +60,11 @@
         <el-col :span="12">
           <el-form-item label="作业地点:" prop="workLocation">
             <area-select
-              v-model="form.workLocation"
+              v-model="form.areaId"
               :data="areaTreeList"
               placeholder="请选择作业地点"
               style="width: 100%"
+              @checkedKeys="onAreaChange"
             />
           </el-form-item>
         </el-col>
@@ -102,7 +106,13 @@
     </el-form>
 
     <template v-slot:footer>
-      <el-button v-if="!isView" type="primary" @click="save()" :loading="loading">保存</el-button>
+      <el-button
+        v-if="!isView"
+        type="primary"
+        @click="save()"
+        :loading="loading"
+        >保存</el-button
+      >
       <el-button @click="cancel">{{ isView ? '关闭' : '取消' }}</el-button>
     </template>
   </ele-modal>
@@ -112,14 +122,23 @@
   import AreaSelect from '@/components/RegionsSelect/area-cascader.vue';
   import DeptSelect from '@/components/CommomSelect/dept-select.vue';
   import personSelect from '@/components/CommomSelect/person-select.vue';
-  import { basicAreaPageAPI } from '@/api/factoryModel';
+  import areaMixin from '@/mixins/areaMixin';
+  import { getById, save, update } from '@/api/dangerousWork';
+  import {
+    listOrganizations,
+    getUserPage,
+    getUserDetail
+  } from '@/api/system/organization';
 
   const defForm = {
+    id: '',
     workCode: '',
     workName: '',
-    applyDept: '',
-    applyUser: '',
-    applyUserName: '',
+    applyDeptId: '',
+    applyDeptName: '',
+    applicantId: '',
+    applicantName: '',
+    areaId: '',
     workLocation: '',
     startTime: '',
     endTime: '',
@@ -132,21 +151,23 @@
       DeptSelect,
       personSelect
     },
+    mixins: [areaMixin],
     data() {
       return {
         visible: false,
         loading: false,
         dialogType: 'add',
         form: { ...defForm },
-        areaTreeList: [],
+        // 申请人下拉选项,新增时只放当前登录用户,保证能显示名称
+        personList: [],
         rules: {
           workName: [
             { required: true, message: '请输入作业名称', trigger: 'blur' }
           ],
-          applyDept: [
+          applyDeptId: [
             { required: true, message: '请选择申请单位', trigger: 'change' }
           ],
-          applyUser: [
+          applicantId: [
             { required: true, message: '请选择申请人', trigger: 'change' }
           ],
           workLocation: [
@@ -172,61 +193,141 @@
       },
       isView() {
         return this.dialogType === 'view';
+      },
+      isAdd() {
+        return this.dialogType === 'add';
       }
     },
-    created() {
-      this.getAreaTree();
-    },
     methods: {
-      // 获取区域树
-      async getAreaTree() {
-        try {
-          const list = await basicAreaPageAPI({
-            pageNum: 1,
-            size: 9999
-          });
-          this.areaTreeList = this.$util.toTreeData({
-            data: list,
-            parentid: 'parentId',
-            nodeKey: 'id'
-          });
-        } catch (e) {
-          console.error('获取区域数据失败', e);
-        }
-      },
       // 部门变更时重置人员
       onDeptChange(deptId) {
-        this.form.applyUser = '';
-        this.form.applyUserName = '';
+        this.form.applicantId = '';
+        this.form.applicantName = '';
         if (deptId) {
-          this.$refs.personRef.getList({ groupId: deptId });
+          this.loadPersonList(deptId);
         }
         this.$nextTick(() => {
-          this.$refs.form.validateField('applyUser');
+          this.$refs.form.validateField('applicantId');
         });
       },
       // 人员选择回调
       onPersonChange(_val, item) {
-        this.form.applyUserName = item ? item.name : '';
+        this.form.applicantName = item ? item.name : '';
+      },
+      // 区域选择回调,记录区域全路径名称
+      onAreaChange(nodeInfo) {
+        this.form.workLocation =
+          nodeInfo && nodeInfo[0]?.pathLabels?.join('/')
+            ? nodeInfo[0].pathLabels.join('/')
+            : '';
       },
-      open(row, type = 'add') {
+      // 新增时的默认申请单位与申请人,取当前登录用户
+      getLoginUserForm() {
+        const userInfo = this.$store.state.user.info || {};
+        return {
+          // 申请单位取用户所属部门(deptIds),不是公司(groupId)
+          applyDeptId: userInfo.deptIds?.[0] || '',
+          applicantId: userInfo.userId || '',
+          applicantName: ''
+        };
+      },
+      // 登录信息里没有可靠的姓名字段,按用户id查一次,保证能回显姓名
+      async loadLoginUserName() {
+        const applicantId = this.form.applicantId;
+        if (!applicantId) return;
+        try {
+          const detail = await getUserDetail(applicantId);
+          const name = detail?.name || '';
+          if (name) {
+            this.form.applicantName = name;
+            this.personList = [{ id: applicantId, name }];
+          }
+        } catch (e) {
+          console.error('查询当前用户信息失败', e);
+        }
+      },
+      // 查询申请单位名称
+      async loadDeptName(deptId) {
+        if (!deptId) return;
+        const userInfo = this.$store.state.user.info || {};
+        try {
+          const list = await listOrganizations({});
+          const dept = (list || []).find((item) => item.id == deptId);
+          if (dept) {
+            this.form.applyDeptName = dept.name;
+            return;
+          }
+        } catch (e) {
+          console.error('查询申请单位失败', e);
+        }
+        this.form.applyDeptName = userInfo.deptName || userInfo.groupName || '';
+      },
+      // 加载人员列表,并把申请人补进下拉,保证能回显姓名
+      async loadPersonList(deptId, applicant) {
+        const list = [];
+        if (deptId) {
+          try {
+            const res = await getUserPage({
+              pageNum: 1,
+              size: -1,
+              groupId: deptId
+            });
+            list.push(...(res?.list || []));
+          } catch (e) {
+            console.error('查询人员列表失败', e);
+          }
+        }
+        if (applicant?.id && !list.find((item) => item.id == applicant.id)) {
+          list.unshift({ id: applicant.id, name: applicant.name });
+        }
+        this.personList = list;
+      },
+      async open(row, type = 'add') {
         this.visible = true;
         this.dialogType = type;
         if (row && row.id) {
-          this.form = { ...defForm, ...row };
+          // 编辑/查看时查询详情,保证数据最新
+          let detail = row;
+          try {
+            detail = (await getById(row.id)) || row;
+          } catch (e) {
+            console.error('查询危险作业详情失败', e);
+          }
+          this.form = {
+            ...defForm,
+            id: detail.id,
+            workCode: detail.workCode || '',
+            workName: detail.workName || '',
+            applyDeptId: detail.applyDeptId || '',
+            applyDeptName: detail.applyDeptName || '',
+            applicantId: detail.applicantId || '',
+            applicantName: detail.applicantName || '',
+            // 作业地点保存的是区域名称,回显时反查区域id
+            workLocation: detail.workLocation || '',
+            areaId: this.getAreaIdByName(detail.workLocation),
+            startTime: detail.startTime || '',
+            endTime: detail.endTime || '',
+            remark: detail.remark || ''
+          };
+          this.loadPersonList(this.form.applyDeptId, {
+            id: this.form.applicantId,
+            name: this.form.applicantName
+          });
         } else {
-          this.form = { ...defForm };
+          const loginUser = this.getLoginUserForm();
+          this.form = { ...defForm, ...loginUser };
+          this.personList = [];
+          this.loadDeptName(loginUser.applyDeptId);
+          // 姓名等接口返回后回填,否则下拉会显示用户id
+          this.loadLoginUserName();
         }
         this.$nextTick(() => {
           this.$refs.form && this.$refs.form.clearValidate();
-          // 编辑时若已有部门,加载对应人员列表
-          if (this.form.applyDept) {
-            this.$refs.personRef.getList({ groupId: this.form.applyDept });
-          }
         });
       },
       cancel() {
         this.form = { ...defForm };
+        this.personList = [];
         this.visible = false;
         this.$refs.form && this.$refs.form.clearValidate();
       },
@@ -236,19 +337,34 @@
           return;
         }
         this.$refs.form.validate((valid) => {
-          if (valid) {
-            this.loading = true;
-            setTimeout(() => {
-              this.loading = false;
-              const messageMap = {
-                add: '添加成功',
-                edit: '编辑成功'
-              };
-              this.$message.success(messageMap[this.dialogType] || '保存成功');
+          if (!valid) {
+            return;
+          }
+          // 注意:新增/修改危险作业不传 ticketList,作业票在「危险作业票管理」中单独申请
+          const params = {
+            id: this.form.id || undefined,
+            workName: this.form.workName,
+            applyDeptId: this.form.applyDeptId,
+            applyDeptName: this.form.applyDeptName,
+            applicantId: this.form.applicantId,
+            applicantName: this.form.applicantName,
+            workLocation: this.form.workLocation,
+            startTime: this.form.startTime,
+            endTime: this.form.endTime,
+            remark: this.form.remark
+          };
+          const isEdit = !!this.form.id;
+          this.loading = true;
+          (isEdit ? update(params) : save(params))
+            .then(() => {
+              this.$message.success(isEdit ? '编辑成功' : '添加成功');
               this.cancel();
               this.$emit('reload');
-            }, 500);
-          }
+            })
+            .catch(() => {})
+            .finally(() => {
+              this.loading = false;
+            });
         });
       }
     }

+ 154 - 20
src/views/DangerousWorkManagement/index.vue

@@ -5,6 +5,7 @@
         <!-- 搜索区域 -->
         <div class="search-area">
           <seek-page
+            ref="seekPage"
             :seekList="seekList"
             @search="handleSearch"
             :formLength="4"
@@ -21,6 +22,7 @@
             :cache-key="cacheKeyUrl"
             height="calc(100vh - 320px)"
             @columns-change="handleColumnChange"
+            @selection-change="handleSelectionChange"
           >
             <template v-slot:toolbar>
               <div class="toolbar-left">
@@ -31,8 +33,19 @@
                   @click="handleAdd"
                   >新增</el-button
                 >
+                <el-button
+                  type="danger"
+                  size="small"
+                  icon="el-icon-delete"
+                  :disabled="!selectedRows.length"
+                  @click="handleBatchDelete"
+                  >批量删除</el-button
+                >
               </div>
             </template>
+            <template v-slot:ticketCount="{ row }">
+              <span>{{ row.ticketList?.length || '-' }}</span>
+            </template>
             <template v-slot:action="{ row }">
               <div class="action-links">
                 <el-link
@@ -41,6 +54,12 @@
                   @click="handleWorkTicket(row)"
                   >作业票管理</el-link
                 >
+                <el-link
+                  type="primary"
+                  :underline="false"
+                  @click="handleView(row)"
+                  >查看</el-link
+                >
                 <el-link
                   type="primary"
                   :underline="false"
@@ -71,6 +90,7 @@
   import add from './add.vue';
   import WorkTicketDialog from '@/views/DangerousWorkList/workTicketDialog.vue';
   import tabMixins from '@/mixins/tableColumnsMixin';
+  import { page as getPage, remove, toSortParams } from '@/api/dangerousWork';
   export default {
     components: {
       add,
@@ -80,8 +100,18 @@
 
     data() {
       return {
+        // 表格选中的数据
+        selectedRows: [],
         // 表格列配置
         columns: [
+          {
+            columnKey: 'selection',
+            type: 'selection',
+            width: 50,
+            align: 'center',
+            reserveSelection: true,
+            fixed: 'left'
+          },
           {
             columnKey: 'index',
             label: '序号',
@@ -104,13 +134,13 @@
             showOverflowTooltip: true
           },
           {
-            prop: 'applyDept',
+            prop: 'applyDeptName',
             label: '申请单位',
             align: 'center',
             minWidth: 120
           },
           {
-            prop: 'applyUser',
+            prop: 'applicantName',
             label: '申请人',
             align: 'center',
             minWidth: 120,
@@ -127,29 +157,34 @@
             prop: 'startTime',
             label: '作业开始时间',
             align: 'center',
-            minWidth: 160
+            minWidth: 160,
+            sortable: true
           },
           {
             prop: 'endTime',
             label: '作业结束时间',
             align: 'center',
-            minWidth: 160
+            minWidth: 160,
+            sortable: true
           },
           {
-            prop: 'status',
-            label: '状态',
+            prop: 'ticketCount',
+            label: '作业票',
             align: 'center',
-            minWidth: 100
+            minWidth: 100,
+            slot: 'ticketCount'
           },
           {
             columnKey: 'action',
             label: '操作',
-            width: 200,
+            width: 260,
             align: 'center',
             slot: 'action'
           }
         ],
-        cacheKeyUrl: 'ehs-dangerousWork-list'
+        cacheKeyUrl: 'ehs-dangerousWork-list',
+        // 是否已完成首次初始化(keep-alive 首次进入不重置,避免重复请求)
+        inited: false
       };
     },
     computed: {
@@ -161,15 +196,63 @@
             type: 'input',
             width: 220,
             placeholder: '请输入作业名称'
+          },
+          {
+            label: '作业编码:',
+            value: 'workCode',
+            type: 'input',
+            width: 220,
+            placeholder: '请输入作业编码'
+          },
+          {
+            label: '申请人:',
+            value: 'applicantName',
+            type: 'input',
+            width: 220,
+            placeholder: '请输入申请人'
+          },
+          {
+            label: '申请单位:',
+            value: 'applyDeptId',
+            type: 'deptSelect',
+            width: 240,
+            placeholder: '请选择申请单位'
+          },
+          {
+            label: '作业开始时间:',
+            value: 'startTime',
+            type: 'date',
+            dateType: 'datetimerange',
+            width: 360,
+            valueAr: ['startTimeBegin', 'startTimeEnd'],
+            placeholder: '请选择作业开始时间'
           }
         ];
       }
     },
     mounted() {},
+    // 每次进入菜单都回到初始值:页码第一页、搜索条件清空
+    activated() {
+      if (!this.inited) {
+        this.inited = true;
+        return;
+      }
+      this.resetSearch();
+    },
     methods: {
+      // 重置为初始值(页码、搜索条件、选中项)
+      resetSearch() {
+        this.clearSelection();
+        if (this.$refs.seekPage) {
+          // seek-page 的 reset 会清空条件并触发 search -> reload({ page: 1 })
+          this.$refs.seekPage.reset();
+        } else {
+          this.$refs.table.reload({ page: 1, where: {} });
+        }
+      },
       // 作业票管理
       handleWorkTicket(row) {
-        this.$refs.ticketDialogRef.open(row.id);
+        this.$refs.ticketDialogRef.open(row);
       },
       // 新增危险作业
       handleAdd() {
@@ -186,14 +269,55 @@
 
       // 删除
       handleDelete(row) {
-        this.$confirm('确认删除吗?', '提示', {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning'
-        })
+        this.$confirm(
+          '确认删除吗?删除后该危险作业下的作业票将一并删除。',
+          '提示',
+          {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }
+        )
           .then(() => {
-            this.$message.success('删除成功');
-            this.$refs.table.reload();
+            remove([row.id]).then(() => {
+              this.$message.success('删除成功');
+              this.clearSelection();
+              this.$refs.table.reload();
+            });
+          })
+          .catch(() => {});
+      },
+      // 多选
+      handleSelectionChange(rows) {
+        this.selectedRows = rows || [];
+      },
+      // 清空选中项
+      clearSelection() {
+        this.selectedRows = [];
+        this.$refs.table && this.$refs.table.clearSelection();
+      },
+      // 批量删除
+      handleBatchDelete() {
+        const ids = this.selectedRows.map((row) => row.id);
+        if (!ids.length) {
+          this.$message.warning('请至少选择一条数据');
+          return;
+        }
+        this.$confirm(
+          `确认删除选中的 ${ids.length} 条危险作业吗?其下作业票将一并删除。`,
+          '提示',
+          {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }
+        )
+          .then(() => {
+            remove(ids).then(() => {
+              this.$message.success('删除成功');
+              this.clearSelection();
+              this.$refs.table.reload({ page: 1 });
+            });
           })
           .catch(() => {});
       },
@@ -203,14 +327,24 @@
       },
 
       // 表格数据源
-      datasource({ page, limit, where, order }) {
+      async datasource({ page, limit, where, order }) {
         const body = {
           ...where,
-          ...order,
+          ...toSortParams(order),
           pageNum: page,
           size: limit
         };
-        return [{}];
+        // 去掉未填写的查询条件,避免空字符串传给后端类型转换报错
+        Object.keys(body).forEach((key) => {
+          if (
+            body[key] === '' ||
+            body[key] === null ||
+            body[key] === undefined
+          ) {
+            delete body[key];
+          }
+        });
+        return await getPage(body);
       }
     }
   };