✨ 评分减分累计与最高扣分、用户部门标签联动树,并修复对账导入与结算调整等

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-23 04:28:22 +08:00
parent 8d9fe998c0
commit 2a5eca8393
17 changed files with 691 additions and 307 deletions
+105 -2
View File
@@ -115,9 +115,10 @@
<template #deptName="{ row }">
<template v-if="formatDeptNames(row.deptName).length">
<el-tag
v-for="name in formatDeptNames(row.deptName)"
:key="name"
v-for="(name, index) in formatDeptNames(row.deptName)"
:key="`${row.id}-${index}-${name}`"
class="user-dept-tag"
@click.stop="handleDeptTagClick(row, index)"
>{{ name }}</el-tag>
</template>
<span v-else>-</span>
@@ -666,6 +667,104 @@ export default {
this.page.currentPage = 1;
this.onLoad(this.page);
},
formatDeptIds(deptId) {
if (!deptId && deptId !== 0) {
return [];
}
return String(deptId)
.split(',')
.map(item => item.trim())
.filter(Boolean);
},
handleDeptTagClick(row, index) {
const deptIds = this.formatDeptIds(row.deptId);
let deptId = deptIds[index];
if (!deptId) {
const names = this.formatDeptNames(row.deptName);
deptId = this.findDeptIdByName(names[index]);
}
if (!deptId) {
this.$message.warning('未找到对应组织');
return;
}
this.selectDeptOnTree(deptId);
},
findDeptIdByName(name, tree = this.permissionDeptTree) {
if (!name) return null;
for (const node of tree || []) {
if (node.title === name || node.deptName === name || node.label === name) {
return node.id;
}
const matched = this.findDeptIdByName(name, node.children);
if (matched != null) return matched;
}
return null;
},
/**
* 展开左侧懒加载组织树到目标节点并设为选中,同时按该组织筛选用户列表
*/
async selectDeptOnTree(deptId) {
if (deptId == null || deptId === '') return;
if (!this.permissionDeptTree?.length) {
const tenantId = this.userInfo.tenantId || this.website.tenantId;
try {
const res = await getDeptTree(tenantId);
this.permissionDeptTree = res.data.data || [];
} catch (error) {
this.$message.error('组织树加载失败');
return;
}
}
const path = this.findDeptPath(deptId);
if (!path?.length) {
this.$message.warning('未在组织树中找到该部门');
return;
}
const tree = this.$refs.deptTree;
if (!tree) return;
for (let i = 0; i < path.length - 1; i++) {
await this.expandLazyTreeNode(path[i]);
}
await this.$nextTick();
const targetId = path[path.length - 1];
tree.setCurrentKey?.(targetId);
this.$nextTick(() => {
const currentEl = tree.$el?.querySelector?.('.el-tree-node.is-current');
currentEl?.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' });
});
if (String(this.treeDeptId) === String(targetId)) {
return;
}
this.treeDeptId = targetId;
this.page.currentPage = 1;
this.onLoad(this.page);
},
expandLazyTreeNode(key) {
return new Promise(resolve => {
const tree = this.$refs.deptTree;
if (!tree?.getNode) {
resolve();
return;
}
const tryExpand = (retries = 40) => {
const node = tree.getNode(key);
if (!node) {
if (retries <= 0) {
resolve();
return;
}
setTimeout(() => tryExpand(retries - 1), 50);
return;
}
if (node.expanded || node.isLeaf) {
resolve();
return;
}
node.expand(() => resolve());
};
tryExpand();
});
},
handleDropdownCommand(command, row, index) {
if (command === 'setLeader') {
this.handleSetLeader(row);
@@ -1537,6 +1636,10 @@ export default {
justify-content: flex-start;
}
.user-dept-tag {
cursor: pointer;
}
.user-dept-tag + .user-dept-tag {
margin-left: 6px;
}