'use strict'; class FilingDirectory { constructor(ctx, isAdmin, canViewAll) { this.ctx = ctx; this.isAdmin = isAdmin; this.canViewAll = canViewAll; } async add(data) { const service = this.ctx.service.filing; const spid = this.ctx.subProject.id; const treePid = String(data.tree_pid); if (treePid !== '-1') { const parent = await service.getDataById(treePid); if (!parent || parent.is_deleted || parent.spid !== spid) throw '父分类不存在'; } if (data.tree_pre_id) { const previous = await service.getDataById(data.tree_pre_id); if (!previous || previous.is_deleted || previous.spid !== spid || String(previous.tree_pid) !== treePid) { throw '同级分类不存在,请刷新页面后重试'; } if (Number(previous.is_fixed)) throw '固定分类不可添加同级'; } if (data.name !== undefined && (typeof data.name !== 'string' || data.name.length > 100)) { throw '分类名称格式错误或超过100个字符'; } const result = await service.add({ tree_pid: treePid, tree_pre_id: data.tree_pre_id, name: data.name }); result.permissionMap = await this.getPermissionMap(result.create); return result; } async remove(data, { fromConfig = false } = {}) { const values = data && data.ids !== undefined ? data.ids : [data && data.id]; if (!Array.isArray(values) || values.length === 0 || values.some(id => typeof id !== 'string' || !id.trim())) { throw '请选择需要删除的分类'; } const ids = Array.from(new Set(values)); const ctx = this.ctx; const spid = ctx.subProject.id; const service = ctx.service.filing; const transaction = await service.beginTransaction(); try { const filingList = await service.getAllDataForUpdate({ spid, is_deleted: 0 }, transaction, 'id'); const scope = this.getDeleteScope(filingList, ids); // 目录配置入口已校验 manage_dir;资料管理入口仍逐个检查目录权限。 if (!fromConfig) { const permissionMap = await this.getPermissionMap(filingList); for (const filing of scope) { if (Number(filing.is_fixed)) throw '固定分类不可删除'; const permission = permissionMap[filing.id]; if (!permission || !permission.can_view || !permission.can_edit_dir) { throw '部分分类或子分类没有编辑目录权限,无法删除'; } } } if (scope.some(filing => Number(filing.file_count || 0) !== 0)) { throw '此分类已存在文件,请先删除所有文件。'; } const deleteIds = scope.map(filing => filing.id); const files = await service.getDirectoryFilesForUpdate(spid, deleteIds, transaction); if (files.length > 0) throw '此分类已存在文件,请先删除所有文件。'; if (fromConfig && scope.some(filing => Number(filing.is_fixed))) throw '固定分类不可删除'; const updateData = this.getRemainingOrders(filingList, scope); await service.deleteEmptyDirectories(spid, deleteIds, updateData, transaction); await transaction.commit(); return { delete: deleteIds, update: updateData }; } catch (err) { await transaction.rollback(); throw err; } } async getPermissionMap(filingList) { const ctx = this.ctx; const permissionMap = await ctx.service.subProjectFilingPermission.getPermissionMap( ctx.subProject.id, ctx.session.sessionUser.accountId, filingList, ctx.subProject.permission.filing_type, ctx.subProject.permission.file_permission, this.isAdmin ); if (this.canViewAll) Object.keys(permissionMap).forEach(id => { permissionMap[id].can_view = 1; }); return permissionMap; } getDeleteScope(filingList, ids) { const filingMap = new Map(filingList.map(filing => [filing.id, filing])); const children = new Map(); filingList.forEach(filing => { const parentId = String(filing.tree_pid); if (!children.has(parentId)) children.set(parentId, []); children.get(parentId).push(filing.id); }); if (ids.some(id => !filingMap.has(id))) throw '部分分类不存在,请刷新页面后重试'; const pending = ids.slice(); const seen = new Set(); const scope = []; for (let i = 0; i < pending.length; i++) { const id = pending[i]; if (seen.has(id)) continue; seen.add(id); scope.push(filingMap.get(id)); pending.push(...(children.get(id) || [])); } return scope; } getRemainingOrders(filingList, scope) { const deletedIds = new Set(scope.map(filing => filing.id)); const parentIds = new Set(scope.map(filing => String(filing.tree_pid))); const updateData = []; for (const parentId of parentIds) { if (deletedIds.has(parentId)) continue; const siblings = filingList.filter(filing => String(filing.tree_pid) === parentId && !deletedIds.has(filing.id)); siblings.sort((a, b) => Number(a.tree_order) - Number(b.tree_order) || a.id.localeCompare(b.id)); siblings.forEach((filing, index) => { if (Number(filing.tree_order) !== index + 1) updateData.push({ id: filing.id, tree_order: index + 1 }); }); } return updateData; } } module.exports = FilingDirectory;