filing_directory.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. 'use strict';
  2. class FilingDirectory {
  3. constructor(ctx, isAdmin, canViewAll) {
  4. this.ctx = ctx;
  5. this.isAdmin = isAdmin;
  6. this.canViewAll = canViewAll;
  7. }
  8. async add(data) {
  9. const service = this.ctx.service.filing;
  10. const spid = this.ctx.subProject.id;
  11. const treePid = String(data.tree_pid);
  12. if (treePid !== '-1') {
  13. const parent = await service.getDataById(treePid);
  14. if (!parent || parent.is_deleted || parent.spid !== spid) throw '父分类不存在';
  15. }
  16. if (data.tree_pre_id) {
  17. const previous = await service.getDataById(data.tree_pre_id);
  18. if (!previous || previous.is_deleted || previous.spid !== spid || String(previous.tree_pid) !== treePid) {
  19. throw '同级分类不存在,请刷新页面后重试';
  20. }
  21. if (Number(previous.is_fixed)) throw '固定分类不可添加同级';
  22. }
  23. if (data.name !== undefined && (typeof data.name !== 'string' || data.name.length > 100)) {
  24. throw '分类名称格式错误或超过100个字符';
  25. }
  26. const result = await service.add({ tree_pid: treePid, tree_pre_id: data.tree_pre_id, name: data.name });
  27. result.permissionMap = await this.getPermissionMap(result.create);
  28. return result;
  29. }
  30. async remove(data, { fromConfig = false } = {}) {
  31. const values = data && data.ids !== undefined ? data.ids : [data && data.id];
  32. if (!Array.isArray(values) || values.length === 0 || values.some(id => typeof id !== 'string' || !id.trim())) {
  33. throw '请选择需要删除的分类';
  34. }
  35. const ids = Array.from(new Set(values));
  36. const ctx = this.ctx;
  37. const spid = ctx.subProject.id;
  38. const service = ctx.service.filing;
  39. const transaction = await service.beginTransaction();
  40. try {
  41. const filingList = await service.getAllDataForUpdate({ spid, is_deleted: 0 }, transaction, 'id');
  42. const scope = this.getDeleteScope(filingList, ids);
  43. // 目录配置入口已校验 manage_dir;资料管理入口仍逐个检查目录权限。
  44. if (!fromConfig) {
  45. const permissionMap = await this.getPermissionMap(filingList);
  46. for (const filing of scope) {
  47. if (Number(filing.is_fixed)) throw '固定分类不可删除';
  48. const permission = permissionMap[filing.id];
  49. if (!permission || !permission.can_view || !permission.can_edit_dir) {
  50. throw '部分分类或子分类没有编辑目录权限,无法删除';
  51. }
  52. }
  53. }
  54. if (scope.some(filing => Number(filing.file_count || 0) !== 0)) {
  55. throw '此分类已存在文件,请先删除所有文件。';
  56. }
  57. const deleteIds = scope.map(filing => filing.id);
  58. const files = await service.getDirectoryFilesForUpdate(spid, deleteIds, transaction);
  59. if (files.length > 0) throw '此分类已存在文件,请先删除所有文件。';
  60. if (fromConfig && scope.some(filing => Number(filing.is_fixed))) throw '固定分类不可删除';
  61. const updateData = this.getRemainingOrders(filingList, scope);
  62. await service.deleteEmptyDirectories(spid, deleteIds, updateData, transaction);
  63. await transaction.commit();
  64. return { delete: deleteIds, update: updateData };
  65. } catch (err) {
  66. await transaction.rollback();
  67. throw err;
  68. }
  69. }
  70. async getPermissionMap(filingList) {
  71. const ctx = this.ctx;
  72. const permissionMap = await ctx.service.subProjectFilingPermission.getPermissionMap(
  73. ctx.subProject.id, ctx.session.sessionUser.accountId, filingList,
  74. ctx.subProject.permission.filing_type, ctx.subProject.permission.file_permission, this.isAdmin
  75. );
  76. if (this.canViewAll) Object.keys(permissionMap).forEach(id => { permissionMap[id].can_view = 1; });
  77. return permissionMap;
  78. }
  79. getDeleteScope(filingList, ids) {
  80. const filingMap = new Map(filingList.map(filing => [filing.id, filing]));
  81. const children = new Map();
  82. filingList.forEach(filing => {
  83. const parentId = String(filing.tree_pid);
  84. if (!children.has(parentId)) children.set(parentId, []);
  85. children.get(parentId).push(filing.id);
  86. });
  87. if (ids.some(id => !filingMap.has(id))) throw '部分分类不存在,请刷新页面后重试';
  88. const pending = ids.slice();
  89. const seen = new Set();
  90. const scope = [];
  91. for (let i = 0; i < pending.length; i++) {
  92. const id = pending[i];
  93. if (seen.has(id)) continue;
  94. seen.add(id);
  95. scope.push(filingMap.get(id));
  96. pending.push(...(children.get(id) || []));
  97. }
  98. return scope;
  99. }
  100. getRemainingOrders(filingList, scope) {
  101. const deletedIds = new Set(scope.map(filing => filing.id));
  102. const parentIds = new Set(scope.map(filing => String(filing.tree_pid)));
  103. const updateData = [];
  104. for (const parentId of parentIds) {
  105. if (deletedIds.has(parentId)) continue;
  106. const siblings = filingList.filter(filing => String(filing.tree_pid) === parentId && !deletedIds.has(filing.id));
  107. siblings.sort((a, b) => Number(a.tree_order) - Number(b.tree_order) || a.id.localeCompare(b.id));
  108. siblings.forEach((filing, index) => {
  109. if (Number(filing.tree_order) !== index + 1) updateData.push({ id: filing.id, tree_order: index + 1 });
  110. });
  111. }
  112. return updateData;
  113. }
  114. }
  115. module.exports = FilingDirectory;