ソースを参照

feat(inspectionProjectTask): 添加人员选择下拉框组件并优化部门选择逻辑

xieyong 5 日 前
親
コミット
c043977cce

+ 40 - 0
src/components/CommomSelect/dept-select.vue

@@ -8,8 +8,11 @@
     value-key="id"
     default-expand-all
     :placeholder="placeholder"
+    :filterable="filterable"
+    :filter-method="deptFilterMethod"
     @input="updateValue"
     @change="changeChoose"
+    @visible-change="visibleChange"
     ref="treeSelect"
     v-bind="$attrs"
   />
@@ -25,6 +28,16 @@
       placeholder: {
         type: String,
         default: '请选择'
+      },
+      // 是否在下拉框内显示搜索框
+      filterable: {
+        type: Boolean,
+        default: false
+      },
+      // 自定义搜索过滤方法(关键字, 节点数据),不传则默认按部门名称/部门编码匹配
+      filterMethod: {
+        type: Function,
+        default: null
       }
     },
     data() {
@@ -32,10 +45,27 @@
         treeData: []
       };
     },
+    computed: {
+      // 传给 ele-tree-select 的过滤方法
+      deptFilterMethod() {
+        return this.filterMethod || this.defaultFilterMethod;
+      }
+    },
     created() {
       this.getData();
     },
     methods: {
+      // 默认过滤:按部门名称或部门编码模糊匹配(不区分大小写)
+      defaultFilterMethod(keyword, data) {
+        const key = (keyword || '').trim().toLowerCase();
+        if (!key) {
+          return true;
+        }
+        return (
+          (data.name || '').toLowerCase().includes(key) ||
+          (data.groupCode || '').toLowerCase().includes(key)
+        );
+      },
       async getData(parmas = {}) {
         const data = await listOrganizations(parmas);
         this.treeData = this.$util.toTreeData({
@@ -55,6 +85,16 @@
           this.$refs.treeSelect.getNodeByValue(val)
         );
       },
+      // 下拉框展开/收起时清空上一次的搜索关键字,保证每次打开都是空的
+      visibleChange() {
+        this.$nextTick(() => {
+          const treeSelect = this.$refs.treeSelect;
+          if (treeSelect && treeSelect.keywords) {
+            treeSelect.keywords = '';
+            treeSelect.filterNode();
+          }
+        });
+      },
       async locateByName(code) {
         await this.getData();
         const res = this.findNodesByNameWithPath(this.treeData, code);

+ 218 - 0
src/components/CommomSelect/user-select.vue

@@ -0,0 +1,218 @@
+<!-- 人员选择下拉框(面板内带搜索框,仅可选所选部门下的人员) -->
+<template>
+  <ele-basic-select
+    :value="value || ''"
+    :selected-label="selectedLabel"
+    :selected="[]"
+    :visible="visible"
+    :placeholder="placeholder"
+    clearable
+    popper-class="ele-tree-select-dropdown"
+    @update:visible="updateVisible"
+    @clear="clearValue"
+  >
+    <!-- 搜索框 -->
+    <div class="ele-tree-select-search">
+      <el-input
+        v-model="keyword"
+        clearable
+        size="mini"
+        placeholder="搜索姓名/工号/账号"
+        prefix-icon="el-icon-search"
+      />
+    </div>
+    <!-- 人员列表 -->
+    <div class="user-select-list">
+      <div
+        v-for="item in filteredList"
+        :key="item.id"
+        class="user-select-item"
+        :class="{ 'is-active': item.id == value }"
+        @click="selectItem(item)"
+      >
+        <span class="user-select-name">{{ item.name }}</span>
+        <span v-if="item.jobNumber" class="user-select-job">
+          {{ item.jobNumber }}
+        </span>
+      </div>
+      <div v-if="!filteredList.length" class="user-select-empty">
+        {{ emptyText }}
+      </div>
+    </div>
+  </ele-basic-select>
+</template>
+
+<script>
+  import { getUserPage } from '@/api/system/organization';
+  export default {
+    name: 'UserSelect',
+    props: {
+      // 选中的数据(v-model)
+      value: [Number, String],
+      // 部门id,必须先选择部门才能选择人员
+      groupId: [Number, String],
+      // 已选人员姓名(列表未加载完成时用于回显)
+      label: {
+        type: String,
+        default: ''
+      },
+      // 提示信息
+      placeholder: {
+        type: String,
+        default: '请选择'
+      }
+    },
+    data() {
+      return {
+        visible: false,
+        keyword: '',
+        // 部门人员列表
+        userList: [],
+        loading: false,
+        // 请求序号,避免并发请求返回顺序错乱
+        reqId: 0
+      };
+    },
+    computed: {
+      // 回显文本
+      selectedLabel() {
+        const user = this.userList.find((item) => item.id == this.value);
+        return user ? user.name : this.label || '';
+      },
+      // 搜索过滤后的列表(姓名/工号/账号)
+      filteredList() {
+        const key = (this.keyword || '').trim().toLowerCase();
+        if (!key) {
+          return this.userList;
+        }
+        return this.userList.filter((item) => {
+          return (
+            (item.name || '').toLowerCase().includes(key) ||
+            (item.jobNumber || '').toLowerCase().includes(key) ||
+            (item.loginName || '').toLowerCase().includes(key)
+          );
+        });
+      },
+      // 空列表提示
+      emptyText() {
+        if (!this.groupId) {
+          return '请先选择部门';
+        }
+        if (this.loading) {
+          return '加载中...';
+        }
+        if (!this.userList.length) {
+          return '该部门暂无人员';
+        }
+        return '未匹配到人员';
+      }
+    },
+    watch: {
+      // 部门变化后重新查询人员(已选人员由父组件清空)
+      groupId(val, oldVal) {
+        if (val == oldVal) {
+          return;
+        }
+        // 清空旧部门的人员与搜索条件,避免展示过期数据
+        this.userList = [];
+        this.keyword = '';
+        this.visible = false;
+        if (this.groupId) {
+          this.getData();
+        }
+      }
+    },
+    created() {
+      if (this.groupId) {
+        this.getData();
+      }
+    },
+    methods: {
+      // 获取所选部门下的人员
+      async getData() {
+        if (!this.groupId) {
+          this.userList = [];
+          return;
+        }
+        const reqId = ++this.reqId;
+        this.loading = true;
+        try {
+          const res = await getUserPage({
+            pageNum: 1,
+            size: -1,
+            groupId: this.groupId
+          });
+          if (reqId !== this.reqId) {
+            return;
+          }
+          this.userList = res.list || [];
+        } catch (error) {
+          this.userList = [];
+        } finally {
+          if (reqId === this.reqId) {
+            this.loading = false;
+          }
+        }
+      },
+      updateVisible(visible) {
+        this.visible = visible;
+        if (visible) {
+          this.keyword = '';
+          if (this.groupId && !this.userList.length) {
+            this.getData();
+          }
+        }
+      },
+      selectItem(item) {
+        this.$emit('input', item.id);
+        this.$emit('change', item);
+        this.visible = false;
+        this.keyword = '';
+      },
+      clearValue() {
+        this.$emit('input', null);
+        this.$emit('change', null);
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  .user-select-list {
+    max-height: 274px;
+    overflow-y: auto;
+  }
+  .user-select-item {
+    height: 34px;
+    line-height: 34px;
+    padding: 0 20px;
+    font-size: 14px;
+    color: #606266;
+    cursor: pointer;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    &:hover {
+      background-color: #f5f7fa;
+    }
+    &.is-active {
+      color: #409eff;
+      font-weight: 600;
+    }
+  }
+  .user-select-name {
+    margin-right: 10px;
+  }
+  .user-select-job {
+    color: #909399;
+    font-size: 12px;
+  }
+  .user-select-empty {
+    height: 34px;
+    line-height: 34px;
+    padding: 0 20px;
+    color: #909399;
+    font-size: 14px;
+    text-align: center;
+  }
+</style>

+ 26 - 61
src/views/inspectionProjectTask/components/inspectionProjectTaskSend.vue

@@ -89,23 +89,18 @@
             <deptSelect
               v-model="form.executeDeptId"
               @changeGroup="searchDeptNodeClick"
+              filterable
             /> </el-form-item
         ></el-col>
         <el-col :span="8">
           <el-form-item label="执行人" prop="executeUserId">
-            <el-select
+            <userSelect
               v-model="form.executeUserId"
+              :group-id="form.executeDeptId"
+              :label="form.executeUserName"
               @change="changeExecutor"
-              filterable
-              style="width: 100%"
-            >
-              <el-option
-                v-for="item in executorList"
-                :key="item.id"
-                :value="item.id"
-                :label="item.name"
-              ></el-option>
-            </el-select> </el-form-item></el-col
+              :placeholder="form.executeDeptId ? '请选择人员' : '请先选择部门'"
+            /> </el-form-item></el-col
       ></el-row>
       <el-row v-else>
         <el-col :span="8">
@@ -114,23 +109,18 @@
               v-model="form.receiveDeptId"
               @changeGroup="searchDeptNodeClick"
               ref="deptSelect"
+              filterable
             /> </el-form-item
         ></el-col>
         <el-col :span="8">
           <el-form-item label="接收人" prop="receiveUserId">
-            <el-select
+            <userSelect
               v-model="form.receiveUserId"
+              :group-id="form.receiveDeptId"
+              :label="form.receiveUserName"
               @change="changeExecutor"
-              filterable
-              style="width: 100%"
-            >
-              <el-option
-                v-for="item in executorList"
-                :key="item.id"
-                :value="item.id"
-                :label="item.name"
-              ></el-option>
-            </el-select> </el-form-item></el-col
+              :placeholder="form.receiveDeptId ? '请选择人员' : '请先选择部门'"
+            /> </el-form-item></el-col
       ></el-row>
       <el-row>
         <el-col :span="8">
@@ -168,7 +158,7 @@
   } from '@/api/inspectionProjectRequest';
   import { inspectionProjectStatus } from '@/enum/dict.js';
   import deptSelect from '@/components/CommomSelect/dept-select.vue';
-  import { getUserPage } from '@/api/system/organization';
+  import userSelect from '@/components/CommomSelect/user-select.vue';
   import { recordingMethodList } from '@/utils/util.js';
   import { getCode } from '@/api/login/index.js';
   const defaultForm = {
@@ -186,7 +176,7 @@
     type: 1
   };
   export default {
-    components: { deptSelect },
+    components: { deptSelect, userSelect },
 
     data() {
       return {
@@ -194,7 +184,6 @@
         recordingMethodList,
         pgaeName: '',
         form: { ...defaultForm },
-        executorList: [],
         selection: [],
         list: [],
         templateLis: [],
@@ -499,15 +488,6 @@
         this.templateIdS = [];
         if (pgaeName == 'inspectionProjectRequest') {
           this.form = await getQualityInspectionItemById(row.id);
-          this.getUserList(
-            {
-              groupId:
-                this.type == 1
-                  ? this.form.executeDeptId
-                  : this.form.receiveDeptId
-            },
-            true
-          );
           const list =
             row.recordingMethod == 1
               ? this.form.templateList
@@ -545,47 +525,32 @@
       searchDeptNodeClick(info, row) {
         let depKey = this.type == 1 ? 'executeDeptId' : 'receiveDeptId';
         let depNameKey = this.type == 1 ? 'executeDeptName' : 'receiveDeptName';
+        let userKey = this.type == 1 ? 'executeUserId' : 'receiveUserId';
+        let userNameKey =
+          this.type == 1 ? 'executeUserName' : 'receiveUserName';
 
         if (info) {
-          const params = { groupId: info };
           this.form[depKey] = info;
           this.form[depNameKey] = row.name;
-          this.getUserList(params);
         } else {
           this.form[depKey] = null;
           this.form[depNameKey] = null;
-          this.executorList = [];
         }
+        // 部门变化后人员范围变化,清空已选人员
+        this.form[userKey] = null;
+        this.form[userNameKey] = null;
       },
-      // 获取人员
-      async getUserList(params, init) {
+      // 选中/清空人员
+      changeExecutor(user) {
         let userKey = this.type == 1 ? 'executeUserId' : 'receiveUserId';
         let userNameKey =
           this.type == 1 ? 'executeUserName' : 'receiveUserName';
-        try {
-          let data = { pageNum: 1, size: -1 };
-
-          if (params) {
-            data = Object.assign(data, params);
-          }
-          const res = await getUserPage(data);
-          this.executorList = res.list;
-          if (init) {
-            return;
-          }
+        if (user) {
+          this.form[userKey] = user.id;
+          this.form[userNameKey] = user.name;
+        } else {
           this.form[userKey] = null;
           this.form[userNameKey] = null;
-        } catch (error) {}
-      },
-      changeExecutor(val) {
-        let userKey = this.type == 1 ? 'executeUserId' : 'receiveUserId';
-        let userNameKey =
-          this.type == 1 ? 'executeUserName' : 'receiveUserName';
-        if (val) {
-          this.form[userKey] = val;
-          this.form[userNameKey] = this.executorList.find(
-            (item) => item.id === val
-          ).name;
         }
       },
       save() {