Преглед изворни кода

feat(系统管理): 人员档案拆分所属机构与主所属部门并修正隶属部门级联

1. 新增只读「所属机构」字段,取机构树一级节点,仅用于展示与级联数据源,不提交后端;2. 编辑回填改用详情的 deptId/deptName 作为主所属部门,groupId/groupName 不再承载机构语义,机构匹配失败给出提示;3. 主所属部门下拉与隶属部门级联改为基于所属机构子树的 mainDeptTree/affiDeptTree;4. 隶属部门 deptIds 兼容逗号分隔字符串;5. 列表新增「所属机构」列,主所属部门列改用 deptName。
lihaiting пре 11 часа
родитељ
комит
0916865c49

+ 126 - 22
src/views/system/organization/components/org-user-edit.vue

@@ -46,10 +46,19 @@
               ></el-option>
             </el-select>
           </el-form-item>
-          <el-form-item label="主所属部门:" prop="groupId">
+          <!-- 所属机构仅作展示与级联数据源,不提交后端;新增取机构树一级节点(公司),编辑按详情 groupName 匹配回填 -->
+          <el-form-item label="所属机构:" prop="orgId">
             <org-select
               :data="institutionList"
-              placeholder="请选择所属机构"
+              :value="form.orgId"
+              disabled
+              placeholder="所属机构"
+            />
+          </el-form-item>
+          <el-form-item label="主所属部门:" prop="groupId">
+            <org-select
+              :data="mainDeptTree"
+              placeholder="请选择主所属部门"
               v-model="form.groupId"
               :disabled="!!form.loginName"
               @checkedKeys="checkedKeys"
@@ -59,7 +68,7 @@
           <el-form-item label="隶属部门:">
             <el-cascader
               class="ele-block"
-              :options="organization"
+              :options="affiDeptTree"
               placeholder="请选择隶属部门"
               :props="defaultProps"
               ref="deptRef"
@@ -1187,10 +1196,14 @@
         educationExperienceList: [],
         socialSecurityList: [],
         deptIds: [],
-        deptName: '',
+        // 主所属部门:提交时用 groupId/groupName 承载;
+        // 编辑回填时详情的 deptId/deptName 映射到这两个字段(详情的 groupId/groupName 是机构,只用于所属机构回显)
+        deptNames: '',
         isEnabled: 1,
         groupId: null,
         groupName: null,
+        // 所属机构(仅前端展示/级联用,不提交后端)
+        orgId: null,
         name: '',
         sex: null,
         email: '',
@@ -1217,7 +1230,10 @@
         // 表单验证规则
         rules: {
           groupId: [
-            { required: true, message: '请选择所属机构', trigger: 'blur' }
+            { required: true, message: '请选择主所属部门', trigger: 'blur' }
+          ],
+          orgId: [
+            { required: true, message: '所属机构不能为空', trigger: 'change' }
           ],
           name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
           sex: [{ required: true, message: '请选择性别', trigger: 'blur' }],
@@ -1352,8 +1368,18 @@
           this.form.postId = val;
         }
       },
-      organization() {
-        return this.setList(this.organizationList);
+      // 主所属部门可选项:所属机构节点(仅展示、置灰不可选)+ 其下部门(单选)
+      mainDeptTree() {
+        const node = this.findOrgNode(this.organizationList, this.form.orgId);
+        // 机构节点本身置灰,防止选到公司;历史数据主部门指向机构节点时也能回显名称
+        return node ? this.cloneOrgTree([node], true, this.form.orgId) : [];
+      },
+      // 隶属部门可选项:所属机构下的部门(多选,主所属部门节点禁选)
+      affiDeptTree() {
+        const node = this.findOrgNode(this.organizationList, this.form.orgId);
+        return node?.children
+          ? this.cloneOrgTree(node.children, true, this.form.groupId)
+          : [];
       },
       identityPhotosColumns() {
         return [
@@ -1823,14 +1849,51 @@
 
         this.professionList = res.list || [];
       },
-      setList(list) {
-        return list.map((val) => {
-          val['disabled'] = val.id == this.form.groupId;
-          if (val.children) {
-            val.children = this.setList(val.children);
+      /* 按 id 在机构树中查找节点 */
+      findOrgNode(nodes, id) {
+        for (const node of nodes || []) {
+          if (node.id == id) return node;
+          if (node.children) {
+            const found = this.findOrgNode(node.children, id);
+            if (found) return found;
           }
-          return val;
-        });
+        }
+        return null;
+      },
+      /* 按 id 在机构树中查找节点(返回根到目标的路径数组) */
+      findOrgNodePath(nodes, id, trail = []) {
+        for (const node of nodes || []) {
+          if (node.id == id) return [...trail, node];
+          if (node.children) {
+            const found = this.findOrgNodePath(node.children, id, [
+              ...trail,
+              node
+            ]);
+            if (found) return found;
+          }
+        }
+        return null;
+      },
+      /* 按名称在机构树中查找节点 */
+      findOrgNodeByName(nodes, name) {
+        for (const node of nodes || []) {
+          if (node.name == name) return node;
+          if (node.children) {
+            const found = this.findOrgNodeByName(node.children, name);
+            if (found) return found;
+          }
+        }
+        return null;
+      },
+      /* 深拷贝机构子树;markDisabledId 对应节点置灰(隶属部门不可与主所属部门重复) */
+      cloneOrgTree(nodes, markDisabled, markDisabledId) {
+        return (nodes || []).map((node) => ({
+          ...node,
+          disabled: markDisabled ? node.id == markDisabledId : false,
+          children: node.children
+            ? this.cloneOrgTree(node.children, markDisabled, markDisabledId)
+            : undefined
+        }));
       },
       addIdentityPhotos() {
         this.form.identityPhotos.push({
@@ -1946,8 +2009,17 @@
           // }
           let formData = JSON.parse(JSON.stringify(this.form));
           // 以下字段接口已废弃,提交非空数据会被后端拒绝,改由对应业务模块维护
-          ['skills', 'trainRecords', 'attendanceRecords', 'contracts'].forEach(
-            (key) => {
+          // orgId 为前端展示/级联用的所属机构,不提交后端;
+          // deptId/deptName 是详情返回的原始字段,提交时主所属部门由 groupId/groupName 承载,一并删除
+          [
+            'skills',
+            'trainRecords',
+            'attendanceRecords',
+            'contracts',
+            'orgId',
+            'deptId',
+            'deptName'
+          ].forEach((key) => {
               delete formData[key];
             }
           );
@@ -2007,19 +2079,20 @@
       },
       handleChange() {
         let arr = Array.from(this.$refs.deptRef.getCheckedNodes());
-        this.form.deptName = arr.map((i) => i.label).join('/') || '';
+        this.form.deptNames = arr.map((i) => i.label).join('/') || '';
         this.form.deptIds = this.form.deptIds || [];
       },
-      checkedKeys(value) {
+      checkedKeys() {
+        // 主所属部门名称(提交字段即 groupName)
         this.getLabelName(this.institutionList, (i) => {
           if (i.id == this.form.groupId) {
             return (this.form.groupName = i.name);
           }
         });
-        this.form.deptIds = this.form.deptIds.filter(
+        // 隶属部门里去掉与主所属部门重复的
+        this.form.deptIds = (this.form.deptIds || []).filter(
           (item) => item != this.form.groupId
         );
-        console.log(this.form.groupName);
       },
       /* 搜索直属上级 */
       async searchManager(keyword) {
@@ -2068,7 +2141,32 @@
               listKeys.forEach((key) => {
                 listDefaults[key] = Array.isArray(res[key]) ? res[key] : [];
               });
-              this.form = { ...res, ...listDefaults };
+              // 编辑回填:详情的 groupId/groupName 是机构,只用于所属机构(orgId)回显,不进提交字段;
+              // 提交时 groupId/groupName 的含义是主所属部门,故用详情的 deptId/deptName 映射过来
+              const orgNode = this.findOrgNodeByName(
+                this.organizationList,
+                res.groupName
+              );
+              this.form = {
+                ...res,
+                ...listDefaults,
+                orgId: orgNode ? orgNode.id : null,
+                groupId: res.deptId ?? null,
+                groupName: res.deptName ?? null
+              };
+              if (!orgNode) {
+                this.$message.error(
+                  res.groupName
+                    ? `所属机构「${res.groupName}」在组织架构中未匹配到,请后端补充`
+                    : '所属机构字段接口未返回,请后端补充'
+                );
+              }
+              // 隶属部门 ids:详情若返回逗号分隔字符串则拆成数组,供级联多选回显
+              this.form.deptIds = Array.isArray(res.deptIds)
+                ? res.deptIds
+                : res.deptIds != null && res.deptIds !== ''
+                ? String(res.deptIds).split(',')
+                : [];
               // 教育经历:历史数据只存在主表的毕业院校/学历/专业/毕业时间,
               // 明细为空时用主表字段回填一行,避免打开编辑看不到已有学历信息
               if (!this.form.educationExperienceList.length) {
@@ -2131,7 +2229,13 @@
             // console.log('this.form',this.form)
           } else {
             this.city = null;
-            this.form.groupId = this.organizationId;
+            // 新增:所属机构(orgId)取机构树的一级节点(公司),
+            // 即左树选中节点向上追溯到顶,不是点到哪就显示哪;仅展示/级联用,不提交
+            const orgPath = this.findOrgNodePath(
+              this.organizationList,
+              this.organizationId
+            );
+            this.form.orgId = orgPath ? orgPath[0].id : null;
             this.isUpdate = false;
           }
         } else {

+ 8 - 0
src/views/system/organization/components/org-user-list.vue

@@ -289,7 +289,15 @@
             minWidth: 110
           },
           {
+            // 所属机构(groupName)
             prop: 'groupName',
+            label: '所属机构',
+            showOverflowTooltip: true,
+            minWidth: 110
+          },
+          {
+            // 详情/列表口径一致:groupName 是机构,主所属部门名称在 deptName
+            prop: 'deptName',
             label: '主所属部门',
             showOverflowTooltip: true,
             minWidth: 110