/** * 往来单位分类树页面级纯函数(views/base/othercompany/utils.js)。 * * 重点是 buildCategoryTree 不能污染原始行:buildTree 会就地往行对象上挂 children, * 若直接在 categories 的行上构建,重复构建会累积出重复子节点。 */ import { describe, expect, it } from 'vitest' import { ALL_CATEGORY_KEY, addRowUpdate, applyCategoryPosition, buildCategoryTree, findNodePosition, hasChildCategory, nextSiblingXh, rebuildTreePositions, renumberSiblings, } from '@/views/base/othercompany/utils' function category(over = {}) { return { b_id: 'a', b_parent_id: null, b_depth: 0, b_path: '/a/', b_name: 'A', b_xh: 10, b_canuse: 1, ...over, } } describe('othercompany 分类树工具:buildCategoryTree', () => { it('按 b_parent_id 建树并按 b_xh 排序', () => { const rows = [ category({ b_id: 'b', b_xh: 20, b_name: 'B' }), category({ b_id: 'a', b_xh: 10, b_name: 'A' }), category({ b_id: 'a1', b_parent_id: 'a', b_depth: 1, b_path: '/a/a1/', b_name: 'A1' }), ] const tree = buildCategoryTree(rows) expect(tree.map((node) => node.b_id)).toEqual(['a', 'b']) expect(tree[0].children.map((node) => node.b_id)).toEqual(['a1']) }) it('不污染原始行,重复构建不会累积出重复子节点', () => { const rows = [ category({ b_id: 'a' }), category({ b_id: 'a1', b_parent_id: 'a', b_depth: 1, b_path: '/a/a1/' }), ] buildCategoryTree(rows) // buildTree 的 children 挂在浅拷贝上,原始行保持干净 expect(rows[0].children).toBeUndefined() const tree = buildCategoryTree(rows) expect(tree[0].children).toHaveLength(1) expect(tree[0].children[0].b_id).toBe('a1') }) }) describe('othercompany 分类树工具:位置派生', () => { it('根节点的 b_depth 为 0、b_path 为 /编码/', () => { const row = { b_id: 'a' } applyCategoryPosition(row, null) expect(row).toMatchObject({ b_depth: 0, b_path: '/a/' }) }) it('子节点继承父级路径并递增层级', () => { const row = { b_id: 'a1' } applyCategoryPosition(row, { b_depth: 2, b_path: '/a/b/' }) expect(row).toMatchObject({ b_depth: 3, b_path: '/a/b/a1/' }) }) }) describe('othercompany 分类树工具:排序号与子分类判定', () => { it('同级最大 b_xh 加 10,无同级时取 10', () => { const rows = [ category({ b_id: 'a', b_xh: 10 }), category({ b_id: 'b', b_xh: 30 }), category({ b_id: 'a1', b_parent_id: 'a', b_xh: 90 }), ] expect(nextSiblingXh(rows, null)).toBe(40) expect(nextSiblingXh(rows, 'a')).toBe(100) expect(nextSiblingXh(rows, 'not-exist')).toBe(10) expect(nextSiblingXh([], null)).toBe(10) }) it('hasChildCategory 只看直接子分类', () => { const rows = [ category({ b_id: 'a' }), category({ b_id: 'a1', b_parent_id: 'a' }), category({ b_id: 'a1x', b_parent_id: 'a1' }), ] expect(hasChildCategory(rows, 'a')).toBe(true) expect(hasChildCategory(rows, 'a1')).toBe(true) expect(hasChildCategory(rows, 'a1x')).toBe(false) }) }) describe('othercompany 分类树工具:重排与重建位置', () => { it('renumberSiblings 按 10 步长重排并只收集变化的行', () => { const a = { b_id: 'a', b_xh: 30 } const b = { b_id: 'b', b_xh: 10 } const updated = [] renumberSiblings([a, b], updated) expect([a.b_xh, b.b_xh]).toEqual([10, 20]) expect(updated).toEqual([ { b_id: 'a', b_xh: 10 }, { b_id: 'b', b_xh: 20 }, ]) }) it('rebuildTreePositions 整树收敛 b_depth / b_path,未变化的不重复收集', () => { const tree = [ { b_id: 'a', b_depth: 0, b_path: '/a/', children: [{ b_id: 'a1', b_depth: 9, b_path: '/stale/', children: [] }], }, ] const updated = [] rebuildTreePositions(tree, updated) expect(tree[0].children[0]).toMatchObject({ b_depth: 1, b_path: '/a/a1/' }) // 根节点本来就是 0 / '/a/',不该产生一条无意义的 update expect(updated).toEqual([{ b_id: 'a1', b_depth: 1, b_path: '/a/a1/' }]) }) it('addRowUpdate 按 b_id 合并字段,避免同节点多条 update', () => { const updated = [] addRowUpdate(updated, { b_id: 'a', b_xh: 20 }) addRowUpdate(updated, { b_id: 'a', b_parent_id: 'p' }) addRowUpdate(updated, { b_id: 'b', b_xh: 10 }) expect(updated).toEqual([ { b_id: 'a', b_xh: 20, b_parent_id: 'p' }, { b_id: 'b', b_xh: 10 }, ]) }) it('findNodePosition 返回所在父数组与索引', () => { const tree = [{ b_id: 'a', children: [{ b_id: 'a1' }, { b_id: 'a2' }] }] expect(findNodePosition(tree, 'a')).toMatchObject({ index: 0 }) const found = findNodePosition(tree, 'a2') expect(found.index).toBe(1) expect(found.list.map((node) => node.b_id)).toEqual(['a1', 'a2']) expect(findNodePosition(tree, 'not-exist')).toBe(null) }) }) describe('othercompany 分类树工具:虚拟根键', () => { it('与 FmsTree 的 rootKey 约定保持一致', () => { expect(ALL_CATEGORY_KEY).toBe('__fms_tree_root__') }) })