/**
|
* 标准库树通用工具
|
*
|
* 标准库固定两级:code=[1] 为行业,code=[2] 为标准。
|
* 兼容没有 code 的旧接口数据时,再回退到 children 判断叶子。
|
* 树路径统一由 " - " 连接,格式与历史实现逐字节保持一致:
|
* 顶层真实节点的 parent 是 Element UI 的虚拟根,因此根节点会进入路径。
|
*/
|
|
// 是否叶子(标准)
|
export function isLeaf(data) {
|
if (!data) return true;
|
if (data.code === '[1]') return false;
|
if (data.code === '[2]') return true;
|
const children = data.children;
|
return children === null || children === undefined || children.length === 0;
|
}
|
|
// 祖先 label 列表:含根,顺序为 根 -> 叶
|
export function getAncestorLabels(node) {
|
const labels = [];
|
let cur = node;
|
while (cur && cur.parent) {
|
labels.push(cur.label);
|
cur = cur.parent;
|
}
|
labels.reverse();
|
return labels;
|
}
|
|
// 复刻原 getNodeParent 的路径格式
|
// leafMarker:标准库传 'null',下单侧传 ''
|
// 叶子判定必须与 isLeaf 一致,否则 children 为 undefined / 空数组的叶子会丢失标记段
|
export function buildSelectTree(node, leafMarker = '') {
|
const tokens = [];
|
let cur = node;
|
while (cur && cur.parent) {
|
if (isLeaf(cur.data)) {
|
tokens.push(cur.label, leafMarker);
|
} else {
|
tokens.push(cur.label);
|
}
|
cur = cur.parent;
|
}
|
tokens.reverse();
|
return tokens.join(' - ');
|
}
|
|
// 路径末段是否为叶子(标准):buildSelectTree 会在叶子前插入标记段
|
// 用它判断无需依赖 el-tree 节点对象,模板回填路径后同样适用
|
export function isLeafPath(path) {
|
if (!path) return false;
|
const tokens = path.split(' - ');
|
if (tokens.length < 2) return false;
|
const marker = tokens[tokens.length - 2];
|
return marker === '' || marker === 'null';
|
}
|
|
// 按祖先位置映射订单实体字段
|
// 缺失的非叶子层级填空串,model 取叶子 label(叶子即标准)
|
export function deriveTreeFields(node) {
|
const labels = getAncestorLabels(node);
|
const n = labels.length;
|
const at = (i) => (i < n - 1 ? labels[i] : '');
|
return {
|
labels,
|
factory: at(0),
|
laboratory: at(1),
|
sampleType: at(2),
|
sample: at(3),
|
model: n ? labels[n - 1] : '',
|
};
|
}
|
|
// 去掉路径末段,用于「当前是叶子但查不到标准」时回退到父级查询
|
export function dropLastLabel(path) {
|
if (!path) return '';
|
const idx = path.lastIndexOf(' - ');
|
return idx === -1 ? '' : path.slice(0, idx);
|
}
|