修复组织树上级节点人员汇总
This commit is contained in:
parent
6d87a2e1cd
commit
30fb7af159
@ -95,6 +95,7 @@ import { computed, defineComponent, h, ref, watch } from "vue";
|
||||
|
||||
import PaginationBar from "./PaginationBar.vue";
|
||||
import StatusBadge from "./StatusBadge.vue";
|
||||
import { collectOrganizationEmployees, countOrganizationEmployees } from "../utils/orgTreeEmployees";
|
||||
import { usePagination } from "../utils/pagination";
|
||||
|
||||
const props = defineProps({
|
||||
@ -228,7 +229,7 @@ const requestedNode = computed(() => findNodeById(organizationNodes.value, props
|
||||
const selectedNode = computed(() => requestedNode.value || firstRootNode.value);
|
||||
const effectiveSelectedNodeId = computed(() => getNodeId(selectedNode.value) ?? "");
|
||||
const selectedNodeLabel = computed(() => selectedNode.value ? nodeLabel(selectedNode.value) : "未选择组织");
|
||||
const selectedEmployees = computed(() => Array.isArray(selectedNode.value?.employees) ? selectedNode.value.employees : []);
|
||||
const selectedEmployees = computed(() => collectOrganizationEmployees(selectedNode.value));
|
||||
const canAddEmployee = computed(() => ["DEPARTMENT", "GROUP"].includes(selectedNode.value?.node_type));
|
||||
const filteredEmployees = computed(() => {
|
||||
const keyword = searchKeyword.value.trim().toLowerCase();
|
||||
@ -358,25 +359,7 @@ function nodeTypeShortLabel(type) {
|
||||
}
|
||||
|
||||
function employeeCount(node) {
|
||||
const employeeKeys = new Set();
|
||||
collectEmployeeKeys(node, employeeKeys);
|
||||
return employeeKeys.size;
|
||||
}
|
||||
|
||||
function collectEmployeeKeys(node, employeeKeys) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
for (const employee of Array.isArray(node.employees) ? node.employees : []) {
|
||||
employeeKeys.add(String(employeeKey(employee)));
|
||||
}
|
||||
for (const child of Array.isArray(node.children) ? node.children : []) {
|
||||
if (isOrganizationNode(child)) {
|
||||
collectEmployeeKeys(child, employeeKeys);
|
||||
} else if (child?.employee_id) {
|
||||
employeeKeys.add(String(employeeKey(child)));
|
||||
}
|
||||
}
|
||||
return countOrganizationEmployees(node);
|
||||
}
|
||||
|
||||
function toggleNode(node) {
|
||||
@ -437,8 +420,8 @@ function employeeKey(employee) {
|
||||
function employeeWithParent(employee) {
|
||||
return {
|
||||
...employee,
|
||||
parent_node_id: getNodeId(selectedNode.value),
|
||||
parent_node_label: nodeLabel(selectedNode.value)
|
||||
parent_node_id: employee?.parent_node_id ?? getNodeId(selectedNode.value),
|
||||
parent_node_label: employee?.parent_node_label ?? nodeLabel(selectedNode.value)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
68
frontend/src/utils/orgTreeEmployees.js
Normal file
68
frontend/src/utils/orgTreeEmployees.js
Normal file
@ -0,0 +1,68 @@
|
||||
export function collectOrganizationEmployees(node) {
|
||||
const employees = [];
|
||||
const seenKeys = new Set();
|
||||
|
||||
collectFromNode(node, node, employees, seenKeys);
|
||||
return employees;
|
||||
}
|
||||
|
||||
export function countOrganizationEmployees(node) {
|
||||
return collectOrganizationEmployees(node).length;
|
||||
}
|
||||
|
||||
function collectFromNode(node, parentNode, employees, seenKeys) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEmployeeNode(node)) {
|
||||
appendEmployee(node, parentNode, employees, seenKeys);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const employee of Array.isArray(node.employees) ? node.employees : []) {
|
||||
appendEmployee(employee, node, employees, seenKeys);
|
||||
}
|
||||
|
||||
for (const child of Array.isArray(node.children) ? node.children : []) {
|
||||
if (isOrganizationNode(child)) {
|
||||
collectFromNode(child, child, employees, seenKeys);
|
||||
} else if (isEmployeeNode(child)) {
|
||||
appendEmployee(child, node, employees, seenKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function appendEmployee(employee, parentNode, employees, seenKeys) {
|
||||
const key = employeeKey(employee);
|
||||
if (!key || seenKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seenKeys.add(key);
|
||||
employees.push({
|
||||
...employee,
|
||||
parent_node_id: employee.parent_node_id ?? nodeId(parentNode),
|
||||
parent_node_label: employee.parent_node_label ?? nodeLabel(parentNode)
|
||||
});
|
||||
}
|
||||
|
||||
function isOrganizationNode(node) {
|
||||
return Boolean(node) && node.node_type !== "EMPLOYEE" && !node.employee_id;
|
||||
}
|
||||
|
||||
function isEmployeeNode(node) {
|
||||
return Boolean(node) && (node.node_type === "EMPLOYEE" || Boolean(node.employee_id));
|
||||
}
|
||||
|
||||
function employeeKey(employee) {
|
||||
return String(employee?.employee_id ?? employee?.user_id ?? employee?.username ?? employee?.mobile ?? employee?.phone ?? "");
|
||||
}
|
||||
|
||||
function nodeId(node) {
|
||||
return node?.node_id ?? node?.id ?? node?.value ?? "";
|
||||
}
|
||||
|
||||
function nodeLabel(node) {
|
||||
return node?.node_label || node?.label || node?.name || "";
|
||||
}
|
||||
68
frontend/src/utils/orgTreeEmployees.test.js
Normal file
68
frontend/src/utils/orgTreeEmployees.test.js
Normal file
@ -0,0 +1,68 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
|
||||
import { collectOrganizationEmployees, countOrganizationEmployees } from "./orgTreeEmployees.js";
|
||||
|
||||
describe("organization tree employee aggregation", () => {
|
||||
it("collects employees from the selected organization and all descendant organizations", () => {
|
||||
const branch = {
|
||||
node_id: 10,
|
||||
node_type: "BRANCH",
|
||||
node_label: "旭升车间",
|
||||
employees: [
|
||||
{ employee_id: 1, employee_name: "直属主管", mobile: "13000000001" }
|
||||
],
|
||||
children: [
|
||||
{
|
||||
node_id: 11,
|
||||
node_type: "DEPARTMENT",
|
||||
node_label: "旭升加工部",
|
||||
employees: [
|
||||
{ employee_id: 2, employee_name: "张三", mobile: "13000000002" },
|
||||
{ employee_id: 3, employee_name: "李四", mobile: "13000000003" }
|
||||
],
|
||||
children: [
|
||||
{
|
||||
node_id: 12,
|
||||
node_type: "GROUP",
|
||||
node_label: "冲压小组",
|
||||
employees: [
|
||||
{ employee_id: 4, employee_name: "王五", mobile: "13000000004" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const employees = collectOrganizationEmployees(branch);
|
||||
|
||||
assert.deepEqual(employees.map((employee) => employee.employee_name), ["直属主管", "张三", "李四", "王五"]);
|
||||
assert.equal(employees[1].parent_node_id, 11);
|
||||
assert.equal(employees[1].parent_node_label, "旭升加工部");
|
||||
assert.equal(countOrganizationEmployees(branch), 4);
|
||||
});
|
||||
|
||||
it("deduplicates employees that appear in multiple descendant branches", () => {
|
||||
const employee = { employee_id: 9, employee_name: "重复人员", mobile: "13000000009" };
|
||||
const branch = {
|
||||
node_id: 20,
|
||||
node_type: "BRANCH",
|
||||
node_label: "嘉恒车间",
|
||||
employees: [employee],
|
||||
children: [
|
||||
{
|
||||
node_id: 21,
|
||||
node_type: "DEPARTMENT",
|
||||
node_label: "嘉恒生产部",
|
||||
employees: [employee]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const employees = collectOrganizationEmployees(branch);
|
||||
|
||||
assert.equal(employees.length, 1);
|
||||
assert.equal(countOrganizationEmployees(branch), 1);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user