No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 

158 líneas
5.1 KiB

  1. const Base = require('../base.js');
  2. module.exports = class extends Base {
  3. // 权限校验:所有操作需要 patient:export 权限
  4. async __before() {
  5. const ret = await super.__before();
  6. // 父类已处理(未登录等),直接返回
  7. if (ret === false) return false;
  8. // 非页面请求时 loadUserPermissions 未执行,需手动加载
  9. if (this.isAjax() && this.adminUser && !this.userPermissions) {
  10. await this.loadUserPermissions();
  11. }
  12. const hasPermission = this.isSuperAdmin || (this.userPermissions || []).includes('patient:export');
  13. if (!hasPermission) {
  14. if (this.isAjax()) {
  15. return this.fail('暂无操作权限');
  16. }
  17. return this.redirect('/admin/dashboard.html');
  18. }
  19. }
  20. // 下载管理页面
  21. async indexAction() {
  22. this.assign('currentPage', 'export_task');
  23. this.assign('pageTitle', '下载管理');
  24. this.assign('breadcrumb', [{ name: '下载管理' }]);
  25. this.assign('adminUser', this.adminUser || {});
  26. return this.display();
  27. }
  28. // 获取任务列表
  29. async listAction() {
  30. const { page = 1, pageSize = 10, status } = this.get();
  31. const model = this.model('export_task');
  32. const list = await model.getList({ page, pageSize, status });
  33. return this.success(list);
  34. }
  35. // 查询单个任务状态(轮询用)
  36. async statusAction() {
  37. const { id } = this.get();
  38. if (!id) return this.fail('参数错误');
  39. const task = await this.model('export_task')
  40. .field('id, task_no, status, total_files, processed_files, file_url, file_size, error_log, finished_at')
  41. .where({ id, is_deleted: 0 })
  42. .find();
  43. if (think.isEmpty(task)) return this.fail('任务不存在');
  44. return this.success(task);
  45. }
  46. // 批量查询任务状态(轮询用)
  47. async batchStatusAction() {
  48. const { ids } = this.get();
  49. if (!ids) return this.success([]);
  50. const idArr = ids.split(',').map(Number).filter(Boolean);
  51. if (!idArr.length) return this.success([]);
  52. const tasks = await this.model('export_task')
  53. .field('id, status, processed_files, total_files, file_url, file_size')
  54. .where({ id: ['in', idArr], is_deleted: 0 })
  55. .select();
  56. return this.success(tasks);
  57. }
  58. // 创建导出任务
  59. async createAction() {
  60. const { file_types, filter_params } = this.post();
  61. if (!file_types || !file_types.length) {
  62. return this.fail('请选择要导出的附件类型');
  63. }
  64. // 全局只允许一个打包中的任务
  65. const processing = await this.model('export_task').where({
  66. is_deleted: 0,
  67. status: ['in', [0, 1]]
  68. }).find();
  69. if (!think.isEmpty(processing)) {
  70. return this.json({ code: 1001, msg: '有任务正在打包中,请稍后再试' });
  71. }
  72. const model = this.model('export_task');
  73. const taskNo = model.generateTaskNo();
  74. // 构建标题
  75. const typeLabels = { id_photos: '实名认证照片', documents: '上传资料', signs: '签字材料', sample_photos: '送检信息附件' };
  76. const title = file_types.map(t => typeLabels[t] || t).join('、');
  77. const id = await model.add({
  78. task_no: taskNo,
  79. title,
  80. status: 0,
  81. file_types: JSON.stringify(file_types),
  82. filter_params: JSON.stringify(filter_params || {}),
  83. create_by: this.adminUser?.id || 0,
  84. create_by_name: this.adminUser?.nickname || this.adminUser?.username || ''
  85. });
  86. await this.log('export', '下载管理', `创建导出任务「${title}」编号:${taskNo}`);
  87. // 触发后台处理
  88. const exportService = this.service('export');
  89. // 异步执行,不等待
  90. setImmediate(() => exportService.startProcessing());
  91. return this.success({ id, task_no: taskNo });
  92. }
  93. // 删除任务(软删除)
  94. async deleteAction() {
  95. const { id } = this.post();
  96. if (!id) return this.fail('参数错误');
  97. const task = await this.model('export_task')
  98. .where({ id, is_deleted: 0 })
  99. .find();
  100. if (think.isEmpty(task)) return this.fail('任务不存在');
  101. // 打包中的任务不允许删除
  102. if (task.status === 1) {
  103. return this.fail('打包中的任务不能删除');
  104. }
  105. await this.model('export_task').where({ id }).update({ is_deleted: 1 });
  106. await this.log('delete', '下载管理', `删除导出任务(${task.task_no})`);
  107. return this.success();
  108. }
  109. // 重试失败的任务
  110. async retryAction() {
  111. const { id } = this.post();
  112. if (!id) return this.fail('参数错误');
  113. const task = await this.model('export_task')
  114. .where({ id, is_deleted: 0 })
  115. .find();
  116. if (think.isEmpty(task)) return this.fail('任务不存在');
  117. if (task.status !== 3) return this.fail('只有失败的任务可以重试');
  118. await this.model('export_task').where({ id }).update({
  119. status: 0,
  120. error_log: '',
  121. started_at: null,
  122. finished_at: null,
  123. processed_files: 0,
  124. total_files: 0,
  125. file_url: '',
  126. file_size: 0
  127. });
  128. await this.log('edit', '下载管理', `重试导出任务(${task.task_no})`);
  129. const exportService = this.service('export');
  130. setImmediate(() => exportService.startProcessing());
  131. return this.success();
  132. }
  133. };