filing_directory.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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) {
  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. const permissionMap = await this.getPermissionMap(filingList);
  44. for (const filing of scope) {
  45. if (Number(filing.is_fixed)) throw '固定分类不可删除';
  46. const permission = permissionMap[filing.id];
  47. if (!permission || !permission.can_view || !permission.can_edit_dir) {
  48. throw '部分分类或子分类没有编辑目录权限,无法删除';
  49. }
  50. }
  51. if (scope.some(filing => Number(filing.file_count || 0) !== 0)) {
  52. throw '此分类已存在文件,请先删除所有文件。';
  53. }
  54. const deleteIds = scope.map(filing => filing.id);
  55. const files = await service.getDirectoryFilesForUpdate(spid, deleteIds, transaction);
  56. if (files.length > 0) throw '此分类已存在文件,请先删除所有文件。';
  57. const updateData = this.getRemainingOrders(filingList, scope);
  58. await service.deleteEmptyDirectories(spid, deleteIds, updateData, transaction);
  59. await transaction.commit();
  60. return { delete: deleteIds, update: updateData };
  61. } catch (err) {
  62. await transaction.rollback();
  63. throw err;
  64. }
  65. }
  66. async getPermissionMap(filingList) {
  67. const ctx = this.ctx;
  68. const permissionMap = await ctx.service.subProjectFilingPermission.getPermissionMap(
  69. ctx.subProject.id, ctx.session.sessionUser.accountId, filingList,
  70. ctx.subProject.permission.filing_type, ctx.subProject.permission.file_permission, this.isAdmin
  71. );
  72. if (this.canViewAll) Object.keys(permissionMap).forEach(id => { permissionMap[id].can_view = 1; });
  73. return permissionMap;
  74. }
  75. getDeleteScope(filingList, ids) {
  76. const filingMap = new Map(filingList.map(filing => [filing.id, filing]));
  77. const children = new Map();
  78. filingList.forEach(filing => {
  79. const parentId = String(filing.tree_pid);
  80. if (!children.has(parentId)) children.set(parentId, []);
  81. children.get(parentId).push(filing.id);
  82. });
  83. if (ids.some(id => !filingMap.has(id))) throw '部分分类不存在,请刷新页面后重试';
  84. const pending = ids.slice();
  85. const seen = new Set();
  86. const scope = [];
  87. for (let i = 0; i < pending.length; i++) {
  88. const id = pending[i];
  89. if (seen.has(id)) continue;
  90. seen.add(id);
  91. scope.push(filingMap.get(id));
  92. pending.push(...(children.get(id) || []));
  93. }
  94. return scope;
  95. }
  96. getRemainingOrders(filingList, scope) {
  97. const deletedIds = new Set(scope.map(filing => filing.id));
  98. const parentIds = new Set(scope.map(filing => String(filing.tree_pid)));
  99. const updateData = [];
  100. for (const parentId of parentIds) {
  101. if (deletedIds.has(parentId)) continue;
  102. const siblings = filingList.filter(filing => String(filing.tree_pid) === parentId && !deletedIds.has(filing.id));
  103. siblings.sort((a, b) => Number(a.tree_order) - Number(b.tree_order) || a.id.localeCompare(b.id));
  104. siblings.forEach((filing, index) => {
  105. if (Number(filing.tree_order) !== index + 1) updateData.push({ id: filing.id, tree_order: index + 1 });
  106. });
  107. }
  108. return updateData;
  109. }
  110. }
  111. module.exports = FilingDirectory;