From 2181ef38dfc68d3bef9b650c8e966d65cd543f8e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 19 Sep 2026 01:14:06 +0000 Subject: [PATCH] fix(web): set tree batch default max depth to 5 Align with VIP: default recursive batch depth is 5 (checked folder = depth 0). Still configurable via batchMaxDepth; warn when remaining folders hit the cap. Co-authored-by: qaiu --- web-front/src/components/DirectoryTree.vue | 2 +- web-front/src/utils/batchTreeCollect.js | 15 ++++-- web-front/src/utils/batchTreeCollect.spec.js | 49 ++++++++++++++++++-- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/web-front/src/components/DirectoryTree.vue b/web-front/src/components/DirectoryTree.vue index 06ee87d..7cdefdb 100644 --- a/web-front/src/components/DirectoryTree.vue +++ b/web-front/src/components/DirectoryTree.vue @@ -489,7 +489,7 @@ export default { type: String, default: 'pane' // 'pane' or 'tree' }, - // 树批量勾选文件夹时的最大展开深度;用户勾选的文件夹为第 0 层,默认 4 + // 树批量勾选文件夹时的最大展开深度;用户勾选的文件夹为第 0 层,默认 5 batchMaxDepth: { type: Number, default: DEFAULT_BATCH_MAX_DEPTH diff --git a/web-front/src/utils/batchTreeCollect.js b/web-front/src/utils/batchTreeCollect.js index 7445fa8..f531534 100644 --- a/web-front/src/utils/batchTreeCollect.js +++ b/web-front/src/utils/batchTreeCollect.js @@ -4,12 +4,12 @@ * Depth convention (checked folder = depth 0): * - 用户勾选的文件夹为第 0 层。 * - 其直接子项为第 1 层。 - * - 当 depth < maxDepth 时继续展开子文件夹;默认 maxDepth = 4, - * 即最多再向下展开 4 层(第 0/1/2/3 层会 load,第 4 层文件夹不再展开)。 + * - 当 depth < maxDepth 时继续展开子文件夹;默认 maxDepth = 5, + * 即最多再向下展开 5 层(第 0/1/2/3/4 层会 load,第 5 层文件夹不再展开)。 * - 触及上限时若仍有未加载/剩余子文件夹,标记 depthExceeded,由 UI 提示跳过。 */ -const DEFAULT_BATCH_MAX_DEPTH = 4 +const DEFAULT_BATCH_MAX_DEPTH = 5 function getTreeNodeId(item) { if (!item) return '' @@ -104,8 +104,13 @@ async function collectFolderFiles(opts) { if (!node) return ctx if (depth >= maxDepth) { - collectAlreadyLoadedFiles(node, isDownloadable, ctx) - if (hasUnexploredFolders(node)) { + // 未 load 的节点在真实 el-tree 中没有 childNodes,不能把预置子项算进去 + if (node.loaded) { + collectAlreadyLoadedFiles(node, isDownloadable, ctx) + if (hasUnexploredFolders(node)) { + ctx.depthExceeded = true + } + } else if (isFolderNode(node.data)) { ctx.depthExceeded = true } return ctx diff --git a/web-front/src/utils/batchTreeCollect.spec.js b/web-front/src/utils/batchTreeCollect.spec.js index ff810b6..c10f42a 100644 --- a/web-front/src/utils/batchTreeCollect.spec.js +++ b/web-front/src/utils/batchTreeCollect.spec.js @@ -71,8 +71,8 @@ function createStore(rootNode) { } describe('batchTreeCollect helpers', () => { - it('uses checked folder as depth 0 and defaults max depth to 4', () => { - assert.equal(DEFAULT_BATCH_MAX_DEPTH, 4) + it('uses checked folder as depth 0 and defaults max depth to 5', () => { + assert.equal(DEFAULT_BATCH_MAX_DEPTH, 5) assert.equal(getTreeNodeId({ id: 'root' }), 'root') assert.equal(normalizeTreeItem({ fileId: 'abc', fileType: 'folder' }).id, 'fid:abc') assert.equal(normalizeTreeItem({ fileId: 'abc', fileType: 'folder' }).isLeaf, false) @@ -105,12 +105,55 @@ describe('batchTreeCollect helpers', () => { assert.deepEqual(ctx.files.map((f) => f.fileName).sort(), ['a.txt', 'b.txt']) }) + it('default depth 5 expands four descendant folders then stops', async () => { + // depth 0 root → 1 d1 → 2 d2 → 3 d3 → 4 d4 → 5 d5 (cap, still has leftover folder) + const skipped = file('skipped.txt') + const capFile = file('cap.txt') + const d5 = folder('d5') + const d4 = folder('d4') + const d3 = folder('d3') + const d2 = folder('d2') + const d1 = folder('d1') + const root = folder('root') + const tree = makeNode(root, [ + makeNode(d1, [ + makeNode(d2, [ + makeNode(d3, [ + makeNode(d4, [ + makeNode(d5, [ + makeNode(capFile), + makeNode(folder('d6'), [makeNode(skipped)], { loaded: false, expanded: false }) + ], { loaded: true }) + ]) + ]) + ]) + ]) + ]) + const store = createStore(tree) + const loadedIds = [] + const ctx = await collectFolderFiles({ + folderData: root, + maxDepth: DEFAULT_BATCH_MAX_DEPTH, + getNode: store.getNode, + ensureLoaded: async (node) => { + loadedIds.push(node.data.fileName) + return store.ensureLoaded(node) + }, + isDownloadable: store.isDownloadable + }) + assert.equal(ctx.depthExceeded, true) + assert.deepEqual(ctx.files.map((f) => f.fileName), ['cap.txt']) + assert.ok(!ctx.files.some((f) => f.fileName === 'skipped.txt')) + assert.ok(loadedIds.includes('d4')) + assert.ok(!loadedIds.includes('d5')) + }) + it('stops expanding at maxDepth and warns when remaining folders exist', async () => { // depth 0: root // depth 1: d1 // depth 2: d2 // depth 3: d3 - // depth 4: d4 (cap) — still has child folder d5 + // depth 4: d4 (cap when maxDepth=4) — still has child folder d5 const deepFile = file('deep.txt') const skipped = file('skipped.txt') const d5 = folder('d5')