Files
labelmain-demo/components/tree-select/libs/util.ts
zhangheng fb3ffe3dfd refactor: remove unused dead-code exports flagged by react-doctor
Low-risk subset only — each verified to have zero external references
(tsc + eslint green); API clients, stores, icons and constants left
untouched.

- libs/util.ts: unexport `is` (still used internally by isNumber)
- components/tree-select/libs/util.ts: drop unused recursive `findLabel`
- app/person/workload/config.ts: drop unused `dimensionOpts`
- components/login/libs/session-cache.ts: drop unused `getCachedSession`
- components/setting/PageSurface.tsx: drop 3 unused layout components
  (SettingTableViewport, SettingSectionHeader, SettingFilterStack)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 12:39:27 +08:00

208 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { TreeNodeData } from "@mantine/core"
const TREE_PATH_SEPARATOR = " / "
/**
* 判断一个节点本身是否命中
* 父节点看 label(group_name),叶子看 label(member_name)
*/
const nodeMatch = (node: TreeNodeData, search: string): boolean => {
if (!search) return true // 空搜索默认全过
const text = String(node.label).toLowerCase()
return text.includes(search.toLowerCase())
}
/* -------------------------------------------------
* 1. DFS 自上而下,匹配即保留,否则剪掉整枝
* ------------------------------------------------- */
export const filterTreeData_dfs = (
treeData: TreeNodeData[],
searchName: string
): TreeNodeData[] => {
if (!searchName.trim()) return treeData // 空搜索直接返回原树
const loop = (list: TreeNodeData[]): TreeNodeData[] => {
const result: TreeNodeData[] = []
for (const n of list) {
// 1. 只要节点本身命中就整枝保留children 不用再判断)
if (nodeMatch(n, searchName)) {
result.push({ ...n }) // 浅拷贝一份,避免污染原树
continue
}
// 2. 本身没命中,再看 children 有没有命中
if (n.children) {
const newChildren = loop(n.children)
if (newChildren.length) {
result.push({ ...n, children: newChildren })
}
}
}
return result
}
return loop(treeData)
}
// 辅助:根据 value 查找 label
export interface FindResult {
path: string // 完整 label 路径,用 / 分隔
node: TreeNodeData | null
}
export interface TreeValueMeta {
path: string
node: TreeNodeData
}
export const buildTreeValueMap = (
nodes: TreeNodeData[],
pathArr: string[] = [],
acc: Record<string, TreeValueMeta> = {}
): Record<string, TreeValueMeta> => {
for (const node of nodes) {
const currentPath = [...pathArr, String(node.label)]
acc[node.value] = {
path: currentPath.join(TREE_PATH_SEPARATOR),
node,
}
if (node.children?.length) {
buildTreeValueMap(node.children, currentPath, acc)
}
}
return acc
}
export const findNodesByValues = (
valueMap: Record<string, TreeValueMeta>,
targetValues: string[]
): TreeNodeData[] =>
targetValues.reduce<TreeNodeData[]>((acc, value) => {
const targetNode = valueMap[value]?.node
if (targetNode) {
acc.push(targetNode)
}
return acc
}, [])
export const getLabelsByValues = (
valueMap: Record<string, TreeValueMeta>,
targetValues: string[]
): string[] =>
targetValues.reduce<string[]>((acc, value) => {
const label = valueMap[value]?.path
if (label) {
acc.push(label)
}
return acc
}, [])
const findNodeByValue = (
nodes: TreeNodeData[],
targetValue: string
): TreeNodeData | null => {
for (const node of nodes) {
if (node.value === targetValue) {
return node
}
if (node.children?.length) {
const found = findNodeByValue(node.children, targetValue)
if (found) {
return found
}
}
}
return null
}
const collectLeafValues = (
nodes: TreeNodeData[],
acc: string[] = []
): string[] => {
for (const node of nodes) {
if (node.children?.length) {
collectLeafValues(node.children, acc)
} else {
acc.push(node.value)
}
}
return acc
}
export const getDescendantLeafValues = (
nodes: TreeNodeData[],
targetValue: string
): string[] => {
const targetNode = findNodeByValue(nodes, targetValue)
if (!targetNode) {
return []
}
if (!targetNode.children?.length) {
return [targetNode.value]
}
return collectLeafValues(targetNode.children)
}
export const getStateFromDataByName = (
data: TreeNodeData[],
record: Record<string, any> = {}
): Record<string, any> => {
let result = data?.reduce((acc, item) => {
let child_acc = {}
if (item.children && item.children?.length) {
acc[item.value] = true
child_acc = getStateFromDataByName(item.children, record)
}
return { ...acc, ...child_acc }
}, record)
return result
}
export interface UserTreeData {
title?: string
value?: string | number
children?: UserTreeData[]
disabled?: boolean
}
export function formatUserTreeOptions(nodes: UserTreeData[]): TreeNodeData[] {
return nodes.flatMap((node) => {
const children = formatUserTreeOptions(node.children ?? [])
const title = String(node.title ?? "").trim()
const rawValue = node.value
const shouldSkipCurrentNode =
node.disabled ||
rawValue === undefined ||
rawValue === null ||
!title ||
(typeof rawValue === "string" &&
rawValue.includes("-") &&
children.length === 0)
if (shouldSkipCurrentNode) {
return children
}
return [
{
label: title,
value: String(rawValue),
children: children.length > 0 ? children : undefined,
},
]
})
}