Browse Source

feat: 添加部门选择弹框功能,优化部门字段交互体验

xieyong 23 hours ago
parent
commit
438f01bd8a

+ 150 - 0
src/components/CommomSelect/dept-select-dialog.vue

@@ -0,0 +1,150 @@
+<!--
+  部门选择弹框(单选)
+  用于把「部门」字段的下拉选择改为弹框选择:
+  点击输入框打开弹框,弹框内可按部门名称搜索,选中节点后点「确定」返回所选部门。
+-->
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :before-close="handleClose"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    top="8vh"
+    width="520px"
+  >
+    <el-input
+      v-model="keyword"
+      placeholder="请输入部门名称"
+      clearable
+      prefix-icon="el-icon-search"
+      class="dept-search"
+      @input="handleSearch"
+    />
+    <el-tree
+      ref="tree"
+      v-loading="treeLoading"
+      :data="treeData"
+      :props="treeProps"
+      node-key="id"
+      highlight-current
+      default-expand-all
+      :expand-on-click-node="false"
+      :filter-node-method="filterNode"
+      class="dept-tree"
+      @node-click="handleNodeClick"
+    />
+    <div slot="footer" class="dialog-footer">
+      <el-button type="primary" size="small" @click="handleConfirm"
+        >确定</el-button
+      >
+      <el-button size="small" @click="handleClose">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  import { listOrganizations } from '@/api/system/organization';
+
+  export default {
+    props: {
+      // 弹框标题
+      title: {
+        type: String,
+        default: '选择部门'
+      }
+    },
+    data() {
+      return {
+        visible: false,
+        treeLoading: false,
+        // 搜索关键字
+        keyword: '',
+        // 部门树数据
+        treeData: [],
+        // 当前选中的部门节点
+        currentNode: null,
+        treeProps: {
+          children: 'children',
+          label: 'name'
+        }
+      };
+    },
+    methods: {
+      /**
+       * 打开弹框
+       * @param current 当前已选部门 { id, name },用于回显高亮
+       */
+      async open(current) {
+        this.visible = true;
+        this.keyword = '';
+        this.currentNode = current ? { ...current } : null;
+        if (!this.treeData.length) {
+          await this.loadData();
+        }
+        this.$nextTick(() => {
+          if (current && current.id && this.$refs.tree) {
+            this.$refs.tree.setCurrentKey(current.id);
+          }
+        });
+      },
+      // 加载部门树数据
+      async loadData() {
+        this.treeLoading = true;
+        try {
+          const data = await listOrganizations({});
+          this.treeData = this.$util.toTreeData({
+            data: data || [],
+            idField: 'id',
+            parentIdField: 'parentId'
+          });
+        } catch (e) {
+          console.error('查询部门列表失败', e);
+          this.treeData = [];
+        } finally {
+          this.treeLoading = false;
+        }
+      },
+      // 部门名称模糊搜索
+      handleSearch(value) {
+        this.$refs.tree && this.$refs.tree.filter(value);
+      },
+      // 搜索过滤:部门名称包含关键字即保留
+      filterNode(value, data) {
+        if (!value) {
+          return true;
+        }
+        return (data.name || '').includes(value);
+      },
+      // 点击树节点选中
+      handleNodeClick(data) {
+        this.currentNode = data;
+      },
+      // 确定:返回所选部门
+      handleConfirm() {
+        if (!this.currentNode) {
+          return this.$message.warning('请至少选择一个部门');
+        }
+        this.$emit('changeParent', this.currentNode);
+        this.handleClose();
+      },
+      // 关闭弹框
+      handleClose() {
+        this.visible = false;
+        this.currentNode = null;
+        this.keyword = '';
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  .dept-search {
+    margin-bottom: 10px;
+  }
+  .dept-tree {
+    max-height: 50vh;
+    overflow: auto;
+  }
+</style>

+ 84 - 14
src/views/DangerousWorkList/components/workTicketForm.vue

@@ -5,7 +5,7 @@
       scope: 'all'   人员范围为全部人员,与申请单位/作业单位无关;改用人员选择弹框
                     (弹框内可按姓名/工号/账号搜索并分页),点击输入框即打开弹框
       multiple: true 多选,提交时名称与 id 用逗号连接
-  - 部门字段 dept:提交部门名称并附带部门 id
+  - 部门字段 dept:点击输入框打开部门选择弹框(弹框内可按部门名称搜索),提交部门名称并附带部门 id
   - 日期字段 date:el-date-picker 日期时间选择
   - 子表:可新增/删除行
 -->
@@ -79,15 +79,22 @@
                   value-format="yyyy-MM-dd HH:mm:ss"
                   style="width: 100%"
                 />
-                <dept-select
+                <!-- 部门字段:点击输入框打开部门选择弹框 -->
+                <el-input
                   v-else-if="field.type === 'dept'"
-                  v-model="formData[field.id]"
-                  :init="false"
-                  :selectList="deptList"
+                  class="dept-picker"
+                  :value="getDeptDisplay(field)"
+                  readonly
                   :placeholder="field.placeholder || '请选择部门'"
                   style="width: 100%"
-                  @changeGroup="onDeptChange(field, $event)"
-                />
+                  @click.native="onDeptInputClick(field, $event)"
+                >
+                  <i
+                    v-if="formData[field.id]"
+                    class="el-icon-circle-close dept-clear"
+                    @click.stop="clearDept(field)"
+                  ></i>
+                </el-input>
                 <!-- 全量人员:点击输入框打开人员选择弹框(单选/多选同一样式) -->
                 <el-input
                   v-else-if="field.type === 'person' && field.scope === 'all'"
@@ -205,12 +212,15 @@
       :selected-list="dialogSelectedList"
       @changeParent="onUserSelected"
     />
+
+    <!-- 部门选择弹框(部门名称搜索 + 部门树) -->
+    <dept-select-dialog ref="deptSelectRef" @changeParent="onDeptSelected" />
   </div>
 </template>
 
 <script>
   import PersonSelect from '@/components/CommomSelect/person-select.vue';
-  import DeptSelect from '@/components/CommomSelect/dept-select.vue';
+  import DeptSelectDialog from '@/components/CommomSelect/dept-select-dialog.vue';
   import UserSelect from '@/components/user-select/user-select.vue';
   import FileMain from '@/components/addDoc/index.vue';
   import SignCanvas from '@/components/upload/signCanvas.vue';
@@ -218,7 +228,13 @@
   import { getTemplateFields } from '../templates';
 
   export default {
-    components: { PersonSelect, DeptSelect, UserSelect, FileMain, SignCanvas },
+    components: {
+      PersonSelect,
+      DeptSelectDialog,
+      UserSelect,
+      FileMain,
+      SignCanvas
+    },
     props: {
       // 模板 schema
       template: {
@@ -261,7 +277,9 @@
         // 签名文件 id { 字段id: 文件id }
         signFileIds: {},
         // 当前正在选人的字段
-        currentSelectField: null
+        currentSelectField: null,
+        // 当前正在选部门的字段
+        currentDeptField: null
       };
     },
     computed: {
@@ -558,10 +576,46 @@
         });
         this.personList = linked;
       },
-      // 部门变更
-      onDeptChange(field, deptId) {
-        const dept = this.deptList.find((item) => item.id === deptId);
-        this.setFieldName(field.id, deptId, dept?.name || '');
+      // 部门字段回显文本
+      getDeptDisplay(field) {
+        const value = this.formData[field.id];
+        if (!value) {
+          return '';
+        }
+        return this.getFieldName(field.id, value) || '';
+      },
+      // 点击部门输入框打开部门选择弹框
+      // element-ui 的 el-input 不会向外派发 click 事件,这里用 .native 监听根元素
+      onDeptInputClick(field) {
+        this.openDeptSelect(field);
+      },
+      // 打开部门选择弹框
+      openDeptSelect(field) {
+        this.currentDeptField = field;
+        const value = this.formData[field.id];
+        const current = value
+          ? { id: value, name: this.getFieldName(field.id, value) || '' }
+          : null;
+        // 等当前字段的已选部门同步到弹框后再打开,保证回显正确
+        this.$nextTick(() => {
+          this.$refs.deptSelectRef && this.$refs.deptSelectRef.open(current);
+        });
+      },
+      // 弹框选择结果
+      onDeptSelected(data) {
+        const field = this.currentDeptField;
+        if (!field || !data) {
+          return;
+        }
+        this.$set(this.formData, field.id, data.id);
+        this.setFieldName(field.id, data.id, data.name || '');
+        // 部门变更后刷新部门联动的人员候选列表
+        this.loadPersonList(this.getPersonDeptId());
+      },
+      // 清空已选部门
+      clearDept(field) {
+        this.$set(this.formData, field.id, '');
+        this.$set(this.fieldNames, field.id, {});
         this.loadPersonList(this.getPersonDeptId());
       },
       // 人员变更(部门联动字段)
@@ -849,6 +903,22 @@
         cursor: pointer;
       }
     }
+    /* 部门选择输入框:点击打开部门选择弹框 */
+    .dept-picker {
+      ::v-deep .el-input__inner {
+        cursor: pointer;
+        /* 给右侧的清除图标留出空间,避免部门名称被遮挡 */
+        padding-right: 30px;
+      }
+    }
+    .dept-clear {
+      cursor: pointer;
+      color: #c0c4cc;
+
+      &:hover {
+        color: #909399;
+      }
+    }
     /* 附件上传、手写签名单独占一行 */
     .field-upload,
     .field-sign {