@dssp/project 1.0.0-alpha.8 → 1.0.0-alpha.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/dist-client/index.d.ts +1 -0
  2. package/dist-client/index.js +1 -1
  3. package/dist-client/index.js.map +1 -1
  4. package/dist-client/pages/lib/chatbot-widget.d.ts +53 -0
  5. package/dist-client/pages/lib/chatbot-widget.js +631 -0
  6. package/dist-client/pages/lib/chatbot-widget.js.map +1 -0
  7. package/dist-client/pages/lib/select2-component.d.ts +1 -1
  8. package/dist-client/pages/lib/select2-component.js +35 -35
  9. package/dist-client/pages/lib/select2-component.js.map +1 -1
  10. package/dist-client/pages/project/component/pagenation.d.ts +18 -0
  11. package/dist-client/pages/project/component/pagenation.js +142 -0
  12. package/dist-client/pages/project/component/pagenation.js.map +1 -0
  13. package/dist-client/pages/project/component/project-update-header.js +26 -3
  14. package/dist-client/pages/project/component/project-update-header.js.map +1 -1
  15. package/dist-client/pages/project/popup/checklist/task-checklist-attachment-list-popup.d.ts +1 -0
  16. package/dist-client/pages/project/popup/checklist/task-checklist-attachment-list-popup.js +308 -0
  17. package/dist-client/pages/project/popup/checklist/task-checklist-attachment-list-popup.js.map +1 -0
  18. package/dist-client/pages/project/popup/checklist/task-checklist-comment-list-popup.d.ts +1 -0
  19. package/dist-client/pages/project/popup/checklist/task-checklist-comment-list-popup.js +356 -0
  20. package/dist-client/pages/project/popup/checklist/task-checklist-comment-list-popup.js.map +1 -0
  21. package/dist-client/pages/project/popup/checklist/task-checklist-create-popup.d.ts +1 -0
  22. package/dist-client/pages/project/popup/checklist/task-checklist-create-popup.js +681 -0
  23. package/dist-client/pages/project/popup/checklist/task-checklist-create-popup.js.map +1 -0
  24. package/dist-client/pages/project/popup/checklist/task-checklist-view.d.ts +32 -0
  25. package/dist-client/pages/project/popup/checklist/task-checklist-view.js +620 -0
  26. package/dist-client/pages/project/popup/checklist/task-checklist-view.js.map +1 -0
  27. package/dist-client/pages/project/popup/popup-plan-export.js +8 -2
  28. package/dist-client/pages/project/popup/popup-plan-export.js.map +1 -1
  29. package/dist-client/pages/project/popup/{popup-schedule-upload.d.ts → popup-task-upload.d.ts} +1 -1
  30. package/dist-client/pages/project/popup/{popup-schedule-upload.js → popup-task-upload.js} +9 -9
  31. package/dist-client/pages/project/popup/popup-task-upload.js.map +1 -0
  32. package/dist-client/pages/project/project-completed-list.d.ts +5 -0
  33. package/dist-client/pages/project/project-completed-list.js +32 -3
  34. package/dist-client/pages/project/project-completed-list.js.map +1 -1
  35. package/dist-client/pages/project/project-detail.d.ts +6 -0
  36. package/dist-client/pages/project/project-detail.js +222 -89
  37. package/dist-client/pages/project/project-detail.js.map +1 -1
  38. package/dist-client/pages/project/project-list.d.ts +57 -0
  39. package/dist-client/pages/project/project-list.js +80 -9
  40. package/dist-client/pages/project/project-list.js.map +1 -1
  41. package/dist-client/pages/project/project-plan-management.js +3 -1
  42. package/dist-client/pages/project/project-plan-management.js.map +1 -1
  43. package/dist-client/pages/project/project-setting-list.d.ts +7 -0
  44. package/dist-client/pages/project/project-setting-list.js +61 -7
  45. package/dist-client/pages/project/project-setting-list.js.map +1 -1
  46. package/dist-client/pages/project/{project-schedule-list.d.ts → project-task-list.d.ts} +2 -2
  47. package/dist-client/pages/project/{project-schedule-list.js → project-task-list.js} +11 -11
  48. package/dist-client/pages/project/project-task-list.js.map +1 -0
  49. package/dist-client/pages/project/{project-schedule.d.ts → project-task.d.ts} +17 -4
  50. package/dist-client/pages/project/project-task.js +688 -0
  51. package/dist-client/pages/project/project-task.js.map +1 -0
  52. package/dist-client/pages/project/project-update.d.ts +34 -0
  53. package/dist-client/pages/project/project-update.js +505 -35
  54. package/dist-client/pages/project/project-update.js.map +1 -1
  55. package/dist-client/pages/resource/construction-type-management.js +14 -0
  56. package/dist-client/pages/resource/construction-type-management.js.map +1 -1
  57. package/dist-client/pages/resource/resource-list-page.d.ts +1 -2
  58. package/dist-client/pages/resource/resource-list-page.js +1 -2
  59. package/dist-client/pages/resource/resource-list-page.js.map +1 -1
  60. package/dist-client/pages/task/task-list-page.d.ts +1 -2
  61. package/dist-client/pages/task/task-list-page.js +1 -2
  62. package/dist-client/pages/task/task-list-page.js.map +1 -1
  63. package/dist-client/pages/task-resource/task-resource-list-page.d.ts +1 -2
  64. package/dist-client/pages/task-resource/task-resource-list-page.js +1 -2
  65. package/dist-client/pages/task-resource/task-resource-list-page.js.map +1 -1
  66. package/dist-client/route.d.ts +1 -1
  67. package/dist-client/route.js +4 -4
  68. package/dist-client/route.js.map +1 -1
  69. package/dist-client/tsconfig.tsbuildinfo +1 -1
  70. package/dist-server/controllers/parse-excel.js.map +1 -1
  71. package/dist-server/migrations/1723861466414-seed-codes.js +1 -1
  72. package/dist-server/migrations/1723861466414-seed-codes.js.map +1 -1
  73. package/dist-server/service/construction-type/construction-type-query.d.ts +2 -2
  74. package/dist-server/service/construction-type/construction-type-query.js +5 -10
  75. package/dist-server/service/construction-type/construction-type-query.js.map +1 -1
  76. package/dist-server/service/construction-type/construction-type-type.d.ts +1 -0
  77. package/dist-server/service/construction-type/construction-type-type.js +4 -0
  78. package/dist-server/service/construction-type/construction-type-type.js.map +1 -1
  79. package/dist-server/service/construction-type/construction-type.d.ts +1 -0
  80. package/dist-server/service/construction-type/construction-type.js +5 -0
  81. package/dist-server/service/construction-type/construction-type.js.map +1 -1
  82. package/dist-server/service/index.d.ts +2 -2
  83. package/dist-server/service/index.js +5 -2
  84. package/dist-server/service/index.js.map +1 -1
  85. package/dist-server/service/inspection-drawing-type/inspection-drawing-type-query.d.ts +2 -2
  86. package/dist-server/service/inspection-drawing-type/inspection-drawing-type-query.js +5 -10
  87. package/dist-server/service/inspection-drawing-type/inspection-drawing-type-query.js.map +1 -1
  88. package/dist-server/service/manager/manager-query.d.ts +1 -1
  89. package/dist-server/service/manager/manager-query.js +2 -6
  90. package/dist-server/service/manager/manager-query.js.map +1 -1
  91. package/dist-server/service/project/issue-project-code.d.ts +7 -0
  92. package/dist-server/service/project/issue-project-code.js +27 -0
  93. package/dist-server/service/project/issue-project-code.js.map +1 -0
  94. package/dist-server/service/project/project-mutation.d.ts +2 -0
  95. package/dist-server/service/project/project-mutation.js +98 -9
  96. package/dist-server/service/project/project-mutation.js.map +1 -1
  97. package/dist-server/service/project/project-query.d.ts +13 -2
  98. package/dist-server/service/project/project-query.js +138 -13
  99. package/dist-server/service/project/project-query.js.map +1 -1
  100. package/dist-server/service/project/project-type.d.ts +8 -1
  101. package/dist-server/service/project/project-type.js +27 -1
  102. package/dist-server/service/project/project-type.js.map +1 -1
  103. package/dist-server/service/project/project.d.ts +22 -0
  104. package/dist-server/service/project/project.js +80 -2
  105. package/dist-server/service/project/project.js.map +1 -1
  106. package/dist-server/service/resource/resource-mutation.js +5 -6
  107. package/dist-server/service/resource/resource-mutation.js.map +1 -1
  108. package/dist-server/service/resource/resource-query.d.ts +2 -2
  109. package/dist-server/service/resource/resource-query.js +5 -10
  110. package/dist-server/service/resource/resource-query.js.map +1 -1
  111. package/dist-server/service/task/task-query.d.ts +2 -0
  112. package/dist-server/service/task/task-query.js +11 -0
  113. package/dist-server/service/task/task-query.js.map +1 -1
  114. package/dist-server/service/task/task.d.ts +2 -0
  115. package/dist-server/service/task/task.js +6 -0
  116. package/dist-server/service/task/task.js.map +1 -1
  117. package/dist-server/service/task-checklist-binding/index.d.ts +5 -0
  118. package/dist-server/service/task-checklist-binding/index.js +9 -0
  119. package/dist-server/service/task-checklist-binding/index.js.map +1 -0
  120. package/dist-server/service/task-checklist-binding/task-checklist-binding-mutation.d.ts +5 -0
  121. package/dist-server/service/task-checklist-binding/task-checklist-binding-mutation.js +186 -0
  122. package/dist-server/service/task-checklist-binding/task-checklist-binding-mutation.js.map +1 -0
  123. package/dist-server/service/task-checklist-binding/task-checklist-binding-query.d.ts +8 -0
  124. package/dist-server/service/task-checklist-binding/task-checklist-binding-query.js +61 -0
  125. package/dist-server/service/task-checklist-binding/task-checklist-binding-query.js.map +1 -0
  126. package/dist-server/service/task-checklist-binding/task-checklist-binding-type.d.ts +15 -0
  127. package/dist-server/service/task-checklist-binding/task-checklist-binding-type.js +57 -0
  128. package/dist-server/service/task-checklist-binding/task-checklist-binding-type.js.map +1 -0
  129. package/dist-server/service/task-checklist-binding/task-checklist-binding.d.ts +22 -0
  130. package/dist-server/service/task-checklist-binding/task-checklist-binding.js +106 -0
  131. package/dist-server/service/task-checklist-binding/task-checklist-binding.js.map +1 -0
  132. package/dist-server/service/task-resource/task-resource-query.d.ts +2 -2
  133. package/dist-server/service/task-resource/task-resource-query.js +4 -9
  134. package/dist-server/service/task-resource/task-resource-query.js.map +1 -1
  135. package/dist-server/service/worker-type/worker-type-query.d.ts +2 -2
  136. package/dist-server/service/worker-type/worker-type-query.js +5 -10
  137. package/dist-server/service/worker-type/worker-type-query.js.map +1 -1
  138. package/dist-server/tsconfig.tsbuildinfo +1 -1
  139. package/package.json +15 -13
  140. package/things-factory.config.js +3 -3
  141. package/translations/en.json +10 -9
  142. package/translations/ja.json +15 -1
  143. package/translations/ko.json +3 -0
  144. package/translations/ms.json +15 -1
  145. package/translations/zh.json +15 -1
  146. package/dist-client/pages/project/popup/popup-schedule-upload.js.map +0 -1
  147. package/dist-client/pages/project/project-schedule-list.js.map +0 -1
  148. package/dist-client/pages/project/project-schedule.js +0 -407
  149. package/dist-client/pages/project/project-schedule.js.map +0 -1
@@ -9,12 +9,17 @@ const shell_1 = require("@things-factory/shell");
9
9
  const attachment_base_1 = require("@things-factory/attachment-base");
10
10
  const project_1 = require("./project");
11
11
  const project_type_1 = require("./project-type");
12
+ const issue_project_code_1 = require("./issue-project-code");
12
13
  const building_complex_1 = require("@dssp/building-complex");
13
14
  const headless_pdf_to_image_1 = require("@things-factory/board-service/dist-server/controllers/headless-pdf-to-image");
14
15
  const parse_excel_1 = require("../../controllers/parse-excel");
15
16
  const fs = tslib_1.__importStar(require("fs"));
16
17
  const path = tslib_1.__importStar(require("path"));
17
18
  const archiver_1 = tslib_1.__importDefault(require("archiver"));
19
+ const env_1 = require("@things-factory/env");
20
+ const PROJECT_DOMAIN_EXT_TYPE = 'project';
21
+ const PROJECT_TEMPLATE_SUBDOMAIN = 'project-template';
22
+ const projectType = env_1.config.get('projectType', project_1.ProjectType.DSSP);
18
23
  let ProjectMutation = class ProjectMutation {
19
24
  async createProject(project, context) {
20
25
  const { domain, user, tx } = context.state;
@@ -27,7 +32,9 @@ let ProjectMutation = class ProjectMutation {
27
32
  });
28
33
  const result = await projectRepo.save({
29
34
  name: project.name,
35
+ documentNaming: project.name,
30
36
  buildingComplex: newBuildingComplex,
37
+ projectType,
31
38
  domain,
32
39
  creator: user,
33
40
  updater: user
@@ -44,8 +51,7 @@ let ProjectMutation = class ProjectMutation {
44
51
  const buildingComplex = project.buildingComplex;
45
52
  const buildings = ((_a = project.buildingComplex) === null || _a === void 0 ? void 0 : _a.buildings) || [];
46
53
  // 1. 프로젝트 수정
47
- const projectState = project.totalProgress == 100 ? project_1.ProjectState.COMPLETED : project_1.ProjectState.ONGOING;
48
- const projectResult = await projectRepo.save(Object.assign(Object.assign({}, project), { state: projectState, updater: user }));
54
+ const projectResult = await projectRepo.save(Object.assign(Object.assign({}, project), { updater: user }));
49
55
  // 2. 단지 정보 수정
50
56
  await buildingComplexRepo.save(Object.assign(Object.assign({}, buildingComplex), { updater: user }));
51
57
  // 2-1. 프로젝트 메인 이미지 첨부파일 나머지 삭제 후 저장
@@ -167,11 +173,11 @@ let ProjectMutation = class ProjectMutation {
167
173
  }
168
174
  async uploadProjectScheduleTable(param, context) {
169
175
  var _a, e_1, _b, _c;
170
- const { domain, user, tx } = context.state;
176
+ const { user, tx } = context.state;
171
177
  const { projectId, scheduleTable } = param;
172
178
  const projectRepo = (0, shell_1.getRepository)(project_1.Project, tx);
173
179
  const project = await projectRepo.findOne({
174
- where: { domain: { id: domain.id }, id: projectId }
180
+ where: { id: projectId }
175
181
  });
176
182
  const { createReadStream, filename, mimetype } = await scheduleTable;
177
183
  const stream = createReadStream();
@@ -197,19 +203,19 @@ let ProjectMutation = class ProjectMutation {
197
203
  return true;
198
204
  }
199
205
  async deleteProject(id, context) {
200
- const { domain, tx } = context.state;
201
- await (0, shell_1.getRepository)(project_1.Project, tx).delete({ domain: { id: domain.id }, id });
206
+ const { tx } = context.state;
207
+ await (0, shell_1.getRepository)(project_1.Project, tx).delete({ id });
202
208
  await (0, attachment_base_1.deleteAttachmentsByRef)(null, { refBys: [id] }, context);
203
209
  return true;
204
210
  }
205
211
  async downloadPlanFiles(fileIds, context) {
206
- const { domain, tx } = context.state;
212
+ const { tx } = context.state;
207
213
  if (!fileIds || fileIds.length === 0) {
208
214
  throw new Error('다운로드할 파일을 선택해주세요.');
209
215
  }
210
216
  // 첨부파일 정보 조회
211
217
  const attachments = await tx.getRepository(attachment_base_1.Attachment).find({
212
- where: { domain: { id: domain.id }, id: (0, typeorm_1.In)(fileIds) }
218
+ where: { id: (0, typeorm_1.In)(fileIds) }
213
219
  });
214
220
  if (attachments.length === 0) {
215
221
  throw new Error('선택된 파일을 찾을 수 없습니다.');
@@ -263,6 +269,71 @@ let ProjectMutation = class ProjectMutation {
263
269
  }
264
270
  });
265
271
  }
272
+ async promoteProjectToTenant(projectId, context) {
273
+ var _a;
274
+ const { user, tx } = context.state;
275
+ const projectRepo = tx.getRepository(project_1.Project);
276
+ const domainRepo = tx.getRepository(shell_1.Domain);
277
+ const project = await projectRepo.findOne({
278
+ where: { id: projectId }
279
+ });
280
+ if (!project) {
281
+ throw new Error(`프로젝트를 찾을 수 없습니다: ${projectId}`);
282
+ }
283
+ // 이미 활성 테넌트인 경우 차단 (강등 상태는 재승격 허용)
284
+ if (project.code) {
285
+ const existing = await domainRepo.findOne({
286
+ where: { subdomain: project.code, extType: PROJECT_DOMAIN_EXT_TYPE }
287
+ });
288
+ if (existing) {
289
+ throw new Error(`이미 테넌트로 승격된 프로젝트입니다: ${project.code}`);
290
+ }
291
+ }
292
+ // 템플릿 Domain 조회 — 모든 프로젝트 도메인의 parent. Role 상속의 단일 진실.
293
+ // subdomain 만으로 식별 — 어드민에서 수동 생성된 도메인의 extType 이
294
+ // NULL/대소문자 차이로 누락되어 false-negative 가 자주 발생하므로.
295
+ const templateDomain = await domainRepo.findOne({
296
+ where: { subdomain: PROJECT_TEMPLATE_SUBDOMAIN }
297
+ });
298
+ if (!templateDomain) {
299
+ throw new Error(`프로젝트 템플릿 Domain (subdomain='${PROJECT_TEMPLATE_SUBDOMAIN}') 이 존재하지 않습니다. 어드민에서 먼저 생성하세요.`);
300
+ }
301
+ // 코드가 없으면 발번 (재승격 시에는 기존 코드 재사용)
302
+ const code = (_a = project.code) !== null && _a !== void 0 ? _a : (await (0, issue_project_code_1.issueProjectCode)(tx));
303
+ await domainRepo.save({
304
+ name: project.name,
305
+ subdomain: code,
306
+ extType: PROJECT_DOMAIN_EXT_TYPE,
307
+ parent: templateDomain,
308
+ owner: user.id
309
+ });
310
+ if (!project.code) {
311
+ await projectRepo.update({ id: projectId }, { code });
312
+ project.code = code;
313
+ }
314
+ return project;
315
+ }
316
+ async demoteProjectTenant(projectId, context) {
317
+ const { tx } = context.state;
318
+ const project = await tx.getRepository(project_1.Project).findOne({
319
+ where: { id: projectId }
320
+ });
321
+ if (!project) {
322
+ throw new Error(`프로젝트를 찾을 수 없습니다: ${projectId}`);
323
+ }
324
+ if (!project.code) {
325
+ throw new Error('승격된 적이 없는 프로젝트입니다.');
326
+ }
327
+ const domainRepo = tx.getRepository(shell_1.Domain);
328
+ const tenantDomain = await domainRepo.findOne({
329
+ where: { subdomain: project.code, extType: PROJECT_DOMAIN_EXT_TYPE }
330
+ });
331
+ if (!tenantDomain) {
332
+ throw new Error('이미 강등된 프로젝트입니다.');
333
+ }
334
+ await domainRepo.softDelete({ id: tenantDomain.id });
335
+ return true;
336
+ }
266
337
  };
267
338
  exports.ProjectMutation = ProjectMutation;
268
339
  tslib_1.__decorate([
@@ -276,7 +347,7 @@ tslib_1.__decorate([
276
347
  ], ProjectMutation.prototype, "createProject", null);
277
348
  tslib_1.__decorate([
278
349
  (0, type_graphql_1.Directive)('@transaction'),
279
- (0, type_graphql_1.Mutation)(returns => project_1.Project, { description: '프로젝트 업데이트' }),
350
+ (0, type_graphql_1.Mutation)(returns => project_1.Project, { description: '프로젝트 업데이트 (중복 사용 금지)' }),
280
351
  tslib_1.__param(0, (0, type_graphql_1.Arg)('project')),
281
352
  tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
282
353
  tslib_1.__metadata("design:type", Function),
@@ -319,6 +390,24 @@ tslib_1.__decorate([
319
390
  tslib_1.__metadata("design:paramtypes", [Array, Object]),
320
391
  tslib_1.__metadata("design:returntype", Promise)
321
392
  ], ProjectMutation.prototype, "downloadPlanFiles", null);
393
+ tslib_1.__decorate([
394
+ (0, type_graphql_1.Directive)('@transaction'),
395
+ (0, type_graphql_1.Mutation)(returns => project_1.Project, { description: '프로젝트를 테넌트로 승격 (관리번호 발번 + project 카테고리 Domain 생성)' }),
396
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('projectId')),
397
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
398
+ tslib_1.__metadata("design:type", Function),
399
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
400
+ tslib_1.__metadata("design:returntype", Promise)
401
+ ], ProjectMutation.prototype, "promoteProjectToTenant", null);
402
+ tslib_1.__decorate([
403
+ (0, type_graphql_1.Directive)('@transaction'),
404
+ (0, type_graphql_1.Mutation)(returns => Boolean, { description: '프로젝트 테넌트 강등 (Domain soft-delete, Project.code 보존)' }),
405
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('projectId')),
406
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
407
+ tslib_1.__metadata("design:type", Function),
408
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
409
+ tslib_1.__metadata("design:returntype", Promise)
410
+ ], ProjectMutation.prototype, "demoteProjectTenant", null);
322
411
  exports.ProjectMutation = ProjectMutation = tslib_1.__decorate([
323
412
  (0, type_graphql_1.Resolver)(project_1.Project)
324
413
  ], ProjectMutation);
@@ -1 +1 @@
1
- {"version":3,"file":"project-mutation.js","sourceRoot":"","sources":["../../../server/service/project/project-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'\nimport { In } from 'typeorm'\nimport { getRepository } from '@things-factory/shell'\nimport {\n Attachment,\n createAttachment,\n deleteAttachmentsByRef,\n ATTACHMENT_PATH,\n deleteAttachment\n} from '@things-factory/attachment-base'\nimport { Project, ProjectState } from './project'\nimport { NewProject, ProjectPatch, UploadProjectScheduleTable } from './project-type'\nimport { BuildingComplex, Building, BuildingLevel } from '@dssp/building-complex'\nimport { pdfToImage } from '@things-factory/board-service/dist-server/controllers/headless-pdf-to-image'\nimport { parseExcelAndImportTasks } from '../../controllers/parse-excel'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport archiver from 'archiver'\n\n@Resolver(Project)\nexport class ProjectMutation {\n @Directive('@transaction')\n @Mutation(returns => Project, { description: '프로젝트 생성' })\n async createProject(@Arg('project') project: NewProject, @Ctx() context: ResolverContext): Promise<Project> {\n const { domain, user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n const buildingComplexRepo = getRepository(BuildingComplex, tx)\n\n const newBuildingComplex = await buildingComplexRepo.save({\n domain,\n creator: user,\n updater: user\n })\n\n const result = await projectRepo.save({\n name: project.name,\n buildingComplex: newBuildingComplex,\n domain,\n creator: user,\n updater: user\n })\n\n return result\n }\n\n @Directive('@transaction')\n @Mutation(returns => Project, { description: '프로젝트 업데이트' })\n async updateProject(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {\n const { user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n const buildingComplexRepo = getRepository(BuildingComplex, tx)\n const buildingRepo = getRepository(Building, tx)\n const buildingLevelRepo = getRepository(BuildingLevel, tx)\n\n const buildingComplex = project.buildingComplex\n const buildings = project.buildingComplex?.buildings || []\n\n // 1. 프로젝트 수정\n const projectState = project.totalProgress == 100 ? ProjectState.COMPLETED : ProjectState.ONGOING\n const projectResult = await projectRepo.save({ ...project, state: projectState, updater: user })\n\n // 2. 단지 정보 수정\n await buildingComplexRepo.save({ ...buildingComplex, updater: user })\n\n // 2-1. 프로젝트 메인 이미지 첨부파일 나머지 삭제 후 저장\n await createAttachmentAfterDelete(context, project?.mainPhotoUpload, project.id, Project.name)\n\n // 2-2. 단지 BIM 이미지 첨부파일 나머지 삭제 후 저장\n await createAttachmentAfterDelete(context, buildingComplex?.drawingUpload, buildingComplex.id, BuildingComplex.name + '_bim')\n\n // 3. 동의 층 정보가 바뀌었으면 층 초기화 후 다시 생성\n const originBuilding = await buildingRepo.findBy({ buildingComplex: { id: buildingComplex.id } }) // 이전 동 정보 가져오기\n const afterBuilding = buildings.reduce((acc, building) => ({ ...acc, [building.name]: building.floorCount }), {}) // 비교용으로 수정된 동 정보 데이터 파싱\n const afterBasement = buildings.reduce((acc, building) => ({ ...acc, [building.name]: building.basementFloorCount || 0 }), {}) // 비교용으로 수정된 지하 정보 데이터 파싱\n const isBuidlingChanged = originBuilding.some(\n building =>\n afterBuilding[building.name] !== building.floorCount || afterBasement[building.name] !== building.basementFloorCount\n ) // 층 개수가 달라진 동이 있는지 확인\n\n // 동의 층 개수가 달라지면 모든 층의 데이터 제거 후 생성\n if (isBuidlingChanged || originBuilding.length !== buildings.length) {\n // 3-1. 기존 동/층 첨부파일 및 데이터 제거\n const buildingIds = originBuilding.map((building: Building) => building.id)\n const buildingLevels = await buildingLevelRepo.findBy({ building: { id: In(buildingIds) } })\n const buildingLevelIds = buildingLevels.map((buildingLevel: BuildingLevel) => buildingLevel.id)\n\n await buildingLevelRepo.softDelete({ building: { id: In(buildingIds) } })\n await buildingRepo.softDelete({ id: In(buildingIds) })\n await deleteAttachmentsByRef(null, { refBys: [...buildingIds, ...buildingLevelIds] }, context)\n\n // 3-2. 단지 내 동 정보들 생성\n for (let buildingKey in buildings) {\n const building = buildings[buildingKey]\n const newBuilding = await buildingRepo.save({\n buildingComplex: buildingComplex,\n name: building.name,\n floorCount: building.floorCount,\n hasBasement: building.hasBasement,\n basementFloorCount: building.hasBasement ? building.basementFloorCount : 0,\n updater: user,\n creator: user\n })\n\n // 3-3. 동별로 for문 돌면서 층 데이터 개수대로 생성\n for (let i = 1; i <= building.floorCount; i++) {\n await buildingLevelRepo.save({ building: newBuilding, floor: i, creator: user })\n }\n\n // 3-4. 지하층 층 데이터 생성\n if (building.hasBasement) {\n for (let i = 1; i <= building.basementFloorCount; i++) {\n await buildingLevelRepo.save({ building: newBuilding, floor: -i, creator: user })\n }\n }\n }\n }\n\n return projectResult\n }\n\n @Directive('@transaction')\n @Mutation(returns => Project, { description: '프로젝트 도면 업데이트' })\n async updateProjectPlan(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {\n const { user, tx, domain } = context.state\n const projectRepo = getRepository(Project, tx)\n const buildingComplexRepo = getRepository(BuildingComplex, tx)\n const buildingRepo = getRepository(Building, tx)\n const buildingLevelRepo = getRepository(BuildingLevel, tx)\n const attachmentRepo = getRepository(Attachment, tx)\n const buildingComplex = project.buildingComplex\n const buildings = project.buildingComplex?.buildings || []\n\n // 1. 프로젝트 수정 시간 업데이트\n const projectResult = await projectRepo.save({ ...project, updater: user })\n\n // 2. 단지 축척 정보 수정\n await buildingComplexRepo.save({ ...buildingComplex, updater: user })\n\n for (let buildingKey in buildings) {\n const building = buildings[buildingKey]\n\n for (let buildingLevelKey in building.buildingLevels) {\n const buildingLevel = building.buildingLevels[buildingLevelKey]\n\n // 3. 층별 도면 이미지 저장\n const mainDrawingAttatchment = await createAttachmentAfterDelete(\n context,\n buildingLevel.mainDrawingUpload,\n buildingLevel.id,\n BuildingLevel.name + '_mainDrawing'\n )\n // 첨부된 PDF가 있으면 PDF 파일대로 썸네일 생성\n if (mainDrawingAttatchment) {\n const mainDrawingUpload = await buildingLevel.mainDrawingUpload\n const pdfPath = `/${ATTACHMENT_PATH}/${mainDrawingAttatchment.path}` // TODO ATTACHMENT_PATH 제거, mainDrawingAttachment.fullpath 로 해도 될 것 같은데...\n const fileName = mainDrawingUpload.filename.replace('.pdf', '')\n const pngFile = await pdfToImage({ pdfPath, fileName })\n await createAttachmentAfterDelete(context, pngFile, buildingLevel.id, BuildingLevel.name + '_mainDrawing_image')\n\n const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })\n await createAttachmentAfterDelete(\n context,\n pngThumbnailFile,\n buildingLevel.id,\n BuildingLevel.name + '_mainDrawing_thumbnail'\n )\n }\n\n // 3-1. 입면도 파일 저장\n const elevationDrawingAttatchment = await createAttachmentAfterDelete(\n context,\n buildingLevel.elevationDrawingUpload,\n buildingLevel.id,\n BuildingLevel.name + '_elevationDrawing'\n )\n if (elevationDrawingAttatchment) {\n const elevationDrawingUpload = await buildingLevel.elevationDrawingUpload\n const pdfPath = `/${ATTACHMENT_PATH}/${elevationDrawingAttatchment.path}`\n const fileName = elevationDrawingUpload.filename.replace('.pdf', '')\n const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })\n await createAttachmentAfterDelete(\n context,\n pngThumbnailFile,\n buildingLevel.id,\n BuildingLevel.name + '_elevationDrawing_thumbnail'\n )\n }\n\n // 3-2. 철근배분도 파일 저장\n const rebarDistributionDrawingAttatchment = await createAttachmentAfterDelete(\n context,\n buildingLevel.rebarDistributionDrawingUpload,\n buildingLevel.id,\n BuildingLevel.name + '_rebarDistributionDrawing'\n )\n if (rebarDistributionDrawingAttatchment) {\n const rebarDistributionDrawingUpload = await buildingLevel.rebarDistributionDrawingUpload\n const pdfPath = `/${ATTACHMENT_PATH}/${rebarDistributionDrawingAttatchment.path}`\n const fileName = rebarDistributionDrawingUpload.filename.replace('.pdf', '')\n const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })\n await createAttachmentAfterDelete(\n context,\n pngThumbnailFile,\n buildingLevel.id,\n BuildingLevel.name + '_rebarDistributionDrawing_thumbnail'\n )\n }\n\n // 3-3. 기타 도면 파일 저장\n const etcDrawingRefType = BuildingLevel.name + '_etcDrawings'\n\n // 기존 첨부 파일 중 제거된 것들 삭제\n const etcDrawings = await attachmentRepo.find({ where: { refType: etcDrawingRefType, refBy: buildingLevel.id } })\n for (let etcDrawing of etcDrawings) {\n if (!buildingLevel.etcDrawingIds.includes(etcDrawing.id)) {\n await deleteAttachment(null, { id: etcDrawing.id }, context)\n }\n }\n\n // 업로드\n if (buildingLevel.etcDrawingsUpload?.length > 0) {\n for (let etcDrawing of buildingLevel.etcDrawingsUpload) {\n await createAttachment(\n null,\n { attachment: { file: etcDrawing, refType: etcDrawingRefType, refBy: buildingLevel.id } },\n context\n )\n }\n }\n\n // 3-4. 층 업데이트 시간 갱신\n await buildingLevelRepo.save({ ...buildingLevel, updater: user })\n }\n\n // 4. 동별 도면 이미지 저장\n await createAttachmentAfterDelete(context, building?.drawingUpload, building.id, Building.name)\n\n // 4-1. 동 업데이트 시간 갱신\n await buildingRepo.save({ ...building, updater: user })\n }\n\n return projectResult\n }\n\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: '프로젝트 공정표 업로드' })\n async uploadProjectScheduleTable(\n @Arg('param') param: UploadProjectScheduleTable,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, user, tx } = context.state\n const { projectId, scheduleTable } = param\n\n const projectRepo = getRepository(Project, tx)\n const project = await projectRepo.findOne({\n where: { domain: { id: domain.id }, id: projectId }\n })\n\n const { createReadStream, filename, mimetype } = await scheduleTable\n\n const stream = createReadStream()\n\n const chunks = []\n for await (const chunk of stream) {\n chunks.push(chunk)\n }\n\n const buffer = Buffer.concat(chunks)\n\n await parseExcelAndImportTasks(buffer, project, context)\n // await parseExcelAndImportTasks(attachment.fullpath, project, context)\n\n return true\n }\n\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: 'To delete Project' })\n async deleteProject(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, tx } = context.state\n\n await getRepository(Project, tx).delete({ domain: { id: domain.id }, id })\n await deleteAttachmentsByRef(null, { refBys: [id] }, context)\n\n return true\n }\n\n @Directive('@transaction')\n @Mutation(returns => String, { description: '선택된 도면 파일들을 ZIP으로 압축하여 다운로드 URL 반환' })\n async downloadPlanFiles(@Arg('fileIds', type => [String]) fileIds: string[], @Ctx() context: ResolverContext): Promise<string> {\n const { domain, tx } = context.state\n\n if (!fileIds || fileIds.length === 0) {\n throw new Error('다운로드할 파일을 선택해주세요.')\n }\n\n // 첨부파일 정보 조회\n const attachments = await tx.getRepository(Attachment).find({\n where: { domain: { id: domain.id }, id: In(fileIds) }\n })\n\n if (attachments.length === 0) {\n throw new Error('선택된 파일을 찾을 수 없습니다.')\n }\n\n // ZIP 파일 생성 - 동과 층 정보를 포함한 파일명\n const zipFileName = `download.zip`\n const tempDir = path.join(process.cwd(), 'temp')\n const zipFilePath = path.join(tempDir, zipFileName)\n\n // temp 디렉토리 생성\n if (!fs.existsSync(tempDir)) {\n fs.mkdirSync(tempDir, { recursive: true })\n }\n\n const output = fs.createWriteStream(zipFilePath)\n const archive = archiver('zip', {\n zlib: { level: 9 } // 최대 압축\n })\n\n return new Promise(async (resolve, reject) => {\n output.on('close', () => {\n // ZIP 파일을 Base64로 인코딩하여 반환\n const zipBuffer = fs.readFileSync(zipFilePath)\n const base64Data = zipBuffer.toString('base64')\n const dataUrl = `data:application/zip;base64,${base64Data}`\n\n // 임시 파일 삭제\n fs.unlinkSync(zipFilePath)\n resolve(dataUrl)\n })\n\n archive.on('error', err => {\n reject(err)\n })\n archive.pipe(output)\n\n try {\n // 각 첨부파일을 ZIP에 추가\n for (const attachment of attachments) {\n try {\n const fileUrl = `http://localhost:3000${attachment.fullpath}`\n const response = await fetch(fileUrl)\n if (response.ok) {\n const buffer = await response.arrayBuffer()\n const fileName = attachment.name || path.basename(attachment.fullpath)\n archive.append(Buffer.from(buffer), { name: fileName })\n }\n } catch (error) {\n console.error('Error processing attachment:', attachment.fullpath, error)\n }\n }\n\n archive.finalize()\n } catch (error) {\n reject(error)\n }\n })\n }\n}\n\nexport async function createAttachmentAfterDelete(context: ResolverContext, file: any, refBy: any, refType: any) {\n if (file === undefined) {\n return null\n }\n\n const { tx } = context.state\n\n // 기존 첨부 파일이 있으면 삭제\n await deleteAttachmentsByRef(null, { refBys: [refBy], refType }, context)\n\n let result = await createAttachment(null, { attachment: { file, refType, refBy } }, context)\n\n return await getRepository(Attachment, tx).findOne({ where: { id: result.id } })\n}\n"]}
1
+ {"version":3,"file":"project-mutation.js","sourceRoot":"","sources":["../../../server/service/project/project-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'\nimport { In } from 'typeorm'\nimport { Domain, getRepository } from '@things-factory/shell'\nimport {\n Attachment,\n createAttachment,\n deleteAttachmentsByRef,\n ATTACHMENT_PATH,\n deleteAttachment\n} from '@things-factory/attachment-base'\nimport { Project, ProjectType } from './project'\nimport { NewProject, ProjectPatch, UploadProjectScheduleTable } from './project-type'\nimport { issueProjectCode } from './issue-project-code'\nimport { BuildingComplex, Building, BuildingLevel } from '@dssp/building-complex'\nimport { pdfToImage } from '@things-factory/board-service/dist-server/controllers/headless-pdf-to-image'\nimport { parseExcelAndImportTasks } from '../../controllers/parse-excel'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport archiver from 'archiver'\nimport { config } from '@things-factory/env'\n\nconst PROJECT_DOMAIN_EXT_TYPE = 'project'\nconst PROJECT_TEMPLATE_SUBDOMAIN = 'project-template'\n\nconst projectType = config.get('projectType', ProjectType.DSSP)\n\n@Resolver(Project)\nexport class ProjectMutation {\n @Directive('@transaction')\n @Mutation(returns => Project, { description: '프로젝트 생성' })\n async createProject(@Arg('project') project: NewProject, @Ctx() context: ResolverContext): Promise<Project> {\n const { domain, user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n const buildingComplexRepo = getRepository(BuildingComplex, tx)\n\n const newBuildingComplex = await buildingComplexRepo.save({\n domain,\n creator: user,\n updater: user\n })\n\n const result = await projectRepo.save({\n name: project.name,\n documentNaming: project.name,\n buildingComplex: newBuildingComplex,\n projectType,\n domain,\n creator: user,\n updater: user\n })\n\n return result\n }\n\n @Directive('@transaction')\n @Mutation(returns => Project, { description: '프로젝트 업데이트 (중복 사용 금지)' })\n async updateProject(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {\n const { user, tx } = context.state\n const projectRepo = getRepository(Project, tx)\n const buildingComplexRepo = getRepository(BuildingComplex, tx)\n const buildingRepo = getRepository(Building, tx)\n const buildingLevelRepo = getRepository(BuildingLevel, tx)\n\n const buildingComplex = project.buildingComplex\n const buildings = project.buildingComplex?.buildings || []\n\n // 1. 프로젝트 수정\n const projectResult = await projectRepo.save({ ...project, updater: user })\n\n // 2. 단지 정보 수정\n await buildingComplexRepo.save({ ...buildingComplex, updater: user })\n\n // 2-1. 프로젝트 메인 이미지 첨부파일 나머지 삭제 후 저장\n await createAttachmentAfterDelete(context, project?.mainPhotoUpload, project.id, Project.name)\n\n // 2-2. 단지 BIM 이미지 첨부파일 나머지 삭제 후 저장\n await createAttachmentAfterDelete(context, buildingComplex?.drawingUpload, buildingComplex.id, BuildingComplex.name + '_bim')\n\n // 3. 동의 층 정보가 바뀌었으면 층 초기화 후 다시 생성\n const originBuilding = await buildingRepo.findBy({ buildingComplex: { id: buildingComplex.id } }) // 이전 동 정보 가져오기\n const afterBuilding = buildings.reduce((acc, building) => ({ ...acc, [building.name]: building.floorCount }), {}) // 비교용으로 수정된 동 정보 데이터 파싱\n const afterBasement = buildings.reduce((acc, building) => ({ ...acc, [building.name]: building.basementFloorCount || 0 }), {}) // 비교용으로 수정된 지하 정보 데이터 파싱\n const isBuidlingChanged = originBuilding.some(\n building =>\n afterBuilding[building.name] !== building.floorCount || afterBasement[building.name] !== building.basementFloorCount\n ) // 층 개수가 달라진 동이 있는지 확인\n\n // 동의 층 개수가 달라지면 모든 층의 데이터 제거 후 생성\n if (isBuidlingChanged || originBuilding.length !== buildings.length) {\n // 3-1. 기존 동/층 첨부파일 및 데이터 제거\n const buildingIds = originBuilding.map((building: Building) => building.id)\n const buildingLevels = await buildingLevelRepo.findBy({ building: { id: In(buildingIds) } })\n const buildingLevelIds = buildingLevels.map((buildingLevel: BuildingLevel) => buildingLevel.id)\n\n await buildingLevelRepo.softDelete({ building: { id: In(buildingIds) } })\n await buildingRepo.softDelete({ id: In(buildingIds) })\n await deleteAttachmentsByRef(null, { refBys: [...buildingIds, ...buildingLevelIds] }, context)\n\n // 3-2. 단지 내 동 정보들 생성\n for (let buildingKey in buildings) {\n const building = buildings[buildingKey]\n const newBuilding = await buildingRepo.save({\n buildingComplex: buildingComplex,\n name: building.name,\n floorCount: building.floorCount,\n hasBasement: building.hasBasement,\n basementFloorCount: building.hasBasement ? building.basementFloorCount : 0,\n updater: user,\n creator: user\n })\n\n // 3-3. 동별로 for문 돌면서 층 데이터 개수대로 생성\n for (let i = 1; i <= building.floorCount; i++) {\n await buildingLevelRepo.save({ building: newBuilding, floor: i, creator: user })\n }\n\n // 3-4. 지하층 층 데이터 생성\n if (building.hasBasement) {\n for (let i = 1; i <= building.basementFloorCount; i++) {\n await buildingLevelRepo.save({ building: newBuilding, floor: -i, creator: user })\n }\n }\n }\n }\n\n return projectResult\n }\n\n @Directive('@transaction')\n @Mutation(returns => Project, { description: '프로젝트 도면 업데이트' })\n async updateProjectPlan(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {\n const { user, tx, domain } = context.state\n const projectRepo = getRepository(Project, tx)\n const buildingComplexRepo = getRepository(BuildingComplex, tx)\n const buildingRepo = getRepository(Building, tx)\n const buildingLevelRepo = getRepository(BuildingLevel, tx)\n const attachmentRepo = getRepository(Attachment, tx)\n const buildingComplex = project.buildingComplex\n const buildings = project.buildingComplex?.buildings || []\n\n // 1. 프로젝트 수정 시간 업데이트\n const projectResult = await projectRepo.save({ ...project, updater: user })\n\n // 2. 단지 축척 정보 수정\n await buildingComplexRepo.save({ ...buildingComplex, updater: user })\n\n for (let buildingKey in buildings) {\n const building = buildings[buildingKey]\n\n for (let buildingLevelKey in building.buildingLevels) {\n const buildingLevel = building.buildingLevels[buildingLevelKey]\n\n // 3. 층별 도면 이미지 저장\n const mainDrawingAttatchment = await createAttachmentAfterDelete(\n context,\n buildingLevel.mainDrawingUpload,\n buildingLevel.id,\n BuildingLevel.name + '_mainDrawing'\n )\n // 첨부된 PDF가 있으면 PDF 파일대로 썸네일 생성\n if (mainDrawingAttatchment) {\n const mainDrawingUpload = await buildingLevel.mainDrawingUpload\n const pdfPath = `/${ATTACHMENT_PATH}/${mainDrawingAttatchment.path}` // TODO ATTACHMENT_PATH 제거, mainDrawingAttachment.fullpath 로 해도 될 것 같은데...\n const fileName = mainDrawingUpload.filename.replace('.pdf', '')\n const pngFile = await pdfToImage({ pdfPath, fileName })\n await createAttachmentAfterDelete(context, pngFile, buildingLevel.id, BuildingLevel.name + '_mainDrawing_image')\n\n const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })\n await createAttachmentAfterDelete(\n context,\n pngThumbnailFile,\n buildingLevel.id,\n BuildingLevel.name + '_mainDrawing_thumbnail'\n )\n }\n\n // 3-1. 입면도 파일 저장\n const elevationDrawingAttatchment = await createAttachmentAfterDelete(\n context,\n buildingLevel.elevationDrawingUpload,\n buildingLevel.id,\n BuildingLevel.name + '_elevationDrawing'\n )\n if (elevationDrawingAttatchment) {\n const elevationDrawingUpload = await buildingLevel.elevationDrawingUpload\n const pdfPath = `/${ATTACHMENT_PATH}/${elevationDrawingAttatchment.path}`\n const fileName = elevationDrawingUpload.filename.replace('.pdf', '')\n const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })\n await createAttachmentAfterDelete(\n context,\n pngThumbnailFile,\n buildingLevel.id,\n BuildingLevel.name + '_elevationDrawing_thumbnail'\n )\n }\n\n // 3-2. 철근배분도 파일 저장\n const rebarDistributionDrawingAttatchment = await createAttachmentAfterDelete(\n context,\n buildingLevel.rebarDistributionDrawingUpload,\n buildingLevel.id,\n BuildingLevel.name + '_rebarDistributionDrawing'\n )\n if (rebarDistributionDrawingAttatchment) {\n const rebarDistributionDrawingUpload = await buildingLevel.rebarDistributionDrawingUpload\n const pdfPath = `/${ATTACHMENT_PATH}/${rebarDistributionDrawingAttatchment.path}`\n const fileName = rebarDistributionDrawingUpload.filename.replace('.pdf', '')\n const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })\n await createAttachmentAfterDelete(\n context,\n pngThumbnailFile,\n buildingLevel.id,\n BuildingLevel.name + '_rebarDistributionDrawing_thumbnail'\n )\n }\n\n // 3-3. 기타 도면 파일 저장\n const etcDrawingRefType = BuildingLevel.name + '_etcDrawings'\n\n // 기존 첨부 파일 중 제거된 것들 삭제\n const etcDrawings = await attachmentRepo.find({ where: { refType: etcDrawingRefType, refBy: buildingLevel.id } })\n for (let etcDrawing of etcDrawings) {\n if (!buildingLevel.etcDrawingIds.includes(etcDrawing.id)) {\n await deleteAttachment(null, { id: etcDrawing.id }, context)\n }\n }\n\n // 업로드\n if (buildingLevel.etcDrawingsUpload?.length > 0) {\n for (let etcDrawing of buildingLevel.etcDrawingsUpload) {\n await createAttachment(\n null,\n { attachment: { file: etcDrawing, refType: etcDrawingRefType, refBy: buildingLevel.id } },\n context\n )\n }\n }\n\n // 3-4. 층 업데이트 시간 갱신\n await buildingLevelRepo.save({ ...buildingLevel, updater: user })\n }\n\n // 4. 동별 도면 이미지 저장\n await createAttachmentAfterDelete(context, building?.drawingUpload, building.id, Building.name)\n\n // 4-1. 동 업데이트 시간 갱신\n await buildingRepo.save({ ...building, updater: user })\n }\n\n return projectResult\n }\n\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: '프로젝트 공정표 업로드' })\n async uploadProjectScheduleTable(\n @Arg('param') param: UploadProjectScheduleTable,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { user, tx } = context.state\n const { projectId, scheduleTable } = param\n\n const projectRepo = getRepository(Project, tx)\n const project = await projectRepo.findOne({\n where: { id: projectId }\n })\n\n const { createReadStream, filename, mimetype } = await scheduleTable\n\n const stream = createReadStream()\n\n const chunks = []\n for await (const chunk of stream) {\n chunks.push(chunk)\n }\n\n const buffer = Buffer.concat(chunks)\n\n await parseExcelAndImportTasks(buffer, project, context)\n // await parseExcelAndImportTasks(attachment.fullpath, project, context)\n\n return true\n }\n\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: 'To delete Project' })\n async deleteProject(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { tx } = context.state\n\n await getRepository(Project, tx).delete({ id })\n await deleteAttachmentsByRef(null, { refBys: [id] }, context)\n\n return true\n }\n\n @Directive('@transaction')\n @Mutation(returns => String, { description: '선택된 도면 파일들을 ZIP으로 압축하여 다운로드 URL 반환' })\n async downloadPlanFiles(@Arg('fileIds', type => [String]) fileIds: string[], @Ctx() context: ResolverContext): Promise<string> {\n const { tx } = context.state\n\n if (!fileIds || fileIds.length === 0) {\n throw new Error('다운로드할 파일을 선택해주세요.')\n }\n\n // 첨부파일 정보 조회\n const attachments = await tx.getRepository(Attachment).find({\n where: { id: In(fileIds) }\n })\n\n if (attachments.length === 0) {\n throw new Error('선택된 파일을 찾을 수 없습니다.')\n }\n\n // ZIP 파일 생성 - 동과 층 정보를 포함한 파일명\n const zipFileName = `download.zip`\n const tempDir = path.join(process.cwd(), 'temp')\n const zipFilePath = path.join(tempDir, zipFileName)\n\n // temp 디렉토리 생성\n if (!fs.existsSync(tempDir)) {\n fs.mkdirSync(tempDir, { recursive: true })\n }\n\n const output = fs.createWriteStream(zipFilePath)\n const archive = archiver('zip', {\n zlib: { level: 9 } // 최대 압축\n })\n\n return new Promise(async (resolve, reject) => {\n output.on('close', () => {\n // ZIP 파일을 Base64로 인코딩하여 반환\n const zipBuffer = fs.readFileSync(zipFilePath)\n const base64Data = zipBuffer.toString('base64')\n const dataUrl = `data:application/zip;base64,${base64Data}`\n\n // 임시 파일 삭제\n fs.unlinkSync(zipFilePath)\n resolve(dataUrl)\n })\n\n archive.on('error', err => {\n reject(err)\n })\n archive.pipe(output)\n\n try {\n // 각 첨부파일을 ZIP에 추가\n for (const attachment of attachments) {\n try {\n const fileUrl = `http://localhost:3000${attachment.fullpath}`\n const response = await fetch(fileUrl)\n if (response.ok) {\n const buffer = await response.arrayBuffer()\n const fileName = attachment.name || path.basename(attachment.fullpath)\n archive.append(Buffer.from(buffer), { name: fileName })\n }\n } catch (error) {\n console.error('Error processing attachment:', attachment.fullpath, error)\n }\n }\n\n archive.finalize()\n } catch (error) {\n reject(error)\n }\n })\n }\n\n @Directive('@transaction')\n @Mutation(returns => Project, { description: '프로젝트를 테넌트로 승격 (관리번호 발번 + project 카테고리 Domain 생성)' })\n async promoteProjectToTenant(@Arg('projectId') projectId: string, @Ctx() context: ResolverContext): Promise<Project> {\n const { user, tx } = context.state\n\n const projectRepo = tx.getRepository(Project)\n const domainRepo = tx.getRepository(Domain)\n\n const project = await projectRepo.findOne({\n where: { id: projectId }\n })\n\n if (!project) {\n throw new Error(`프로젝트를 찾을 수 없습니다: ${projectId}`)\n }\n\n // 이미 활성 테넌트인 경우 차단 (강등 상태는 재승격 허용)\n if (project.code) {\n const existing = await domainRepo.findOne({\n where: { subdomain: project.code, extType: PROJECT_DOMAIN_EXT_TYPE }\n })\n if (existing) {\n throw new Error(`이미 테넌트로 승격된 프로젝트입니다: ${project.code}`)\n }\n }\n\n // 템플릿 Domain 조회 — 모든 프로젝트 도메인의 parent. Role 상속의 단일 진실.\n // subdomain 만으로 식별 — 어드민에서 수동 생성된 도메인의 extType 이\n // NULL/대소문자 차이로 누락되어 false-negative 가 자주 발생하므로.\n const templateDomain = await domainRepo.findOne({\n where: { subdomain: PROJECT_TEMPLATE_SUBDOMAIN }\n })\n if (!templateDomain) {\n throw new Error(\n `프로젝트 템플릿 Domain (subdomain='${PROJECT_TEMPLATE_SUBDOMAIN}') 이 존재하지 않습니다. 어드민에서 먼저 생성하세요.`\n )\n }\n\n // 코드가 없으면 발번 (재승격 시에는 기존 코드 재사용)\n const code = project.code ?? (await issueProjectCode(tx))\n\n await domainRepo.save({\n name: project.name,\n subdomain: code,\n extType: PROJECT_DOMAIN_EXT_TYPE,\n parent: templateDomain,\n owner: user.id\n })\n\n if (!project.code) {\n await projectRepo.update({ id: projectId }, { code })\n project.code = code\n }\n\n return project\n }\n\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: '프로젝트 테넌트 강등 (Domain soft-delete, Project.code 보존)' })\n async demoteProjectTenant(@Arg('projectId') projectId: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { tx } = context.state\n\n const project = await tx.getRepository(Project).findOne({\n where: { id: projectId }\n })\n\n if (!project) {\n throw new Error(`프로젝트를 찾을 수 없습니다: ${projectId}`)\n }\n\n if (!project.code) {\n throw new Error('승격된 적이 없는 프로젝트입니다.')\n }\n\n const domainRepo = tx.getRepository(Domain)\n const tenantDomain = await domainRepo.findOne({\n where: { subdomain: project.code, extType: PROJECT_DOMAIN_EXT_TYPE }\n })\n\n if (!tenantDomain) {\n throw new Error('이미 강등된 프로젝트입니다.')\n }\n\n await domainRepo.softDelete({ id: tenantDomain.id })\n\n return true\n }\n}\n\nexport async function createAttachmentAfterDelete(context: ResolverContext, file: any, refBy: any, refType: any) {\n if (file === undefined) {\n return null\n }\n\n const { tx } = context.state\n\n // 기존 첨부 파일이 있으면 삭제\n await deleteAttachmentsByRef(null, { refBys: [refBy], refType }, context)\n\n let result = await createAttachment(null, { attachment: { file, refType, refBy } }, context)\n\n return await getRepository(Attachment, tx).findOne({ where: { id: result.id } })\n}\n"]}
@@ -7,14 +7,25 @@ import { Attachment } from '@things-factory/attachment-base';
7
7
  import { BuildingComplex } from '@dssp/building-complex';
8
8
  export declare class ProjectQuery {
9
9
  project(id: string, context: ResolverContext): Promise<Project>;
10
- projects(params: ListParam, context: ResolverContext): Promise<ProjectList>;
11
- projectByBuildingComplexId(buildingComplexId: string, context: ResolverContext): Promise<Project>;
10
+ currentProject(context: ResolverContext): Promise<Project>;
11
+ projects(params: ListParam): Promise<ProjectList>;
12
+ projectByBuildingComplexId(buildingComplexId: string): Promise<Project>;
13
+ projectByBuildingLevelId(buildingLevelId: string, context: ResolverContext): Promise<Project>;
14
+ currentProjectType(): Promise<string>;
12
15
  rootTasks(project: Project): Promise<Task[]>;
13
16
  mainPhoto(project: Project): Promise<string | Attachment>;
14
17
  scheduleTable(project: Project): Promise<Attachment | undefined>;
18
+ completeReport(project: Project): Promise<Attachment | undefined>;
15
19
  buildingComplex(project: Project): Promise<BuildingComplex>;
16
20
  domain(project: Project): Promise<Domain>;
21
+ tenantDomain(project: Project): Promise<Domain | null>;
17
22
  updater(project: Project): Promise<User>;
18
23
  creator(project: Project): Promise<User>;
19
24
  projectType(project: Project): Promise<string>;
25
+ kpi(project: Project): Promise<number>;
26
+ kpiValues(project: Project): Promise<KpiValuesObject[]>;
27
+ }
28
+ export declare class KpiValuesObject {
29
+ kpiName: string;
30
+ value: number;
20
31
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProjectQuery = void 0;
3
+ exports.KpiValuesObject = exports.ProjectQuery = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const type_graphql_1 = require("type-graphql");
6
6
  const typeorm_1 = require("typeorm");
@@ -12,30 +12,61 @@ const project_type_1 = require("./project-type");
12
12
  const attachment_base_1 = require("@things-factory/attachment-base");
13
13
  const building_complex_1 = require("@dssp/building-complex");
14
14
  const env_1 = require("@things-factory/env");
15
+ const kpi_1 = require("@things-factory/kpi");
16
+ const projectType = env_1.config.get('projectType', project_1.ProjectType.DSSP);
15
17
  let ProjectQuery = class ProjectQuery {
16
18
  async project(id, context) {
17
19
  const { domain } = context.state;
20
+ // 프로젝트 테넌트 컨텍스트에서는 운영자 도메인 소속 프로젝트를 직접 조회 (domain 필터 제외).
21
+ // 단 안전을 위해 project.code 가 현재 tenant subdomain 과 일치해야 함.
22
+ if (domain.extType === 'project') {
23
+ return await (0, shell_1.getRepository)(project_1.Project).findOne({
24
+ where: { id, code: domain.subdomain }
25
+ });
26
+ }
18
27
  return await (0, shell_1.getRepository)(project_1.Project).findOne({
19
- where: { domain: { id: domain.id }, id }
28
+ where: { id }
20
29
  });
21
30
  }
22
- async projects(params, context) {
31
+ async currentProject(context) {
23
32
  const { domain } = context.state;
33
+ if (domain.extType !== 'project' || !domain.subdomain)
34
+ return null;
35
+ return await (0, shell_1.getRepository)(project_1.Project).findOne({
36
+ where: { code: domain.subdomain }
37
+ });
38
+ }
39
+ async projects(params) {
24
40
  const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
25
- domain,
26
41
  params,
27
42
  repository: (0, shell_1.getRepository)(project_1.Project),
43
+ alias: 'p',
28
44
  searchables: ['name', 'description', 'state']
29
45
  });
46
+ if (projectType !== project_1.ProjectType.DKPI) {
47
+ queryBuilder.andWhere('p.project_type != :dkpi', { dkpi: project_1.ProjectType.DKPI });
48
+ }
30
49
  const [items, total] = await queryBuilder.getManyAndCount();
31
50
  return { items, total };
32
51
  }
33
- async projectByBuildingComplexId(buildingComplexId, context) {
34
- const { domain } = context.state;
52
+ async projectByBuildingComplexId(buildingComplexId) {
35
53
  return await (0, shell_1.getRepository)(project_1.Project).findOne({
36
- where: { domain: { id: domain.id }, buildingComplex: { id: buildingComplexId } }
54
+ where: { buildingComplex: { id: buildingComplexId } }
37
55
  });
38
56
  }
57
+ async projectByBuildingLevelId(buildingLevelId, context) {
58
+ const queryBuilder = (0, shell_1.getRepository)(project_1.Project)
59
+ .createQueryBuilder('p')
60
+ .innerJoin('building_complexes', 'bc', 'p.building_complex_id = bc.id')
61
+ .innerJoin('buildings', 'b', 'b.building_complex_id = bc.id')
62
+ .innerJoin('building_levels', 'bl', 'bl.building_id = b.id')
63
+ .where('bl.id = :buildingLevelId', { buildingLevelId });
64
+ const result = await queryBuilder.getOne();
65
+ return result;
66
+ }
67
+ async currentProjectType() {
68
+ return env_1.config.get('projectType', project_1.ProjectType.DSSP);
69
+ }
39
70
  async rootTasks(project) {
40
71
  return await (0, shell_1.getRepository)(task_1.Task).find({
41
72
  where: {
@@ -47,8 +78,8 @@ let ProjectQuery = class ProjectQuery {
47
78
  async mainPhoto(project) {
48
79
  const attachment = await (0, shell_1.getRepository)(attachment_base_1.Attachment).findOne({
49
80
  where: {
50
- domain: { id: project.domainId },
51
- refBy: project.id
81
+ refBy: project.id,
82
+ refType: project_1.Project.name
52
83
  },
53
84
  order: { createdAt: 'ASC' }
54
85
  });
@@ -57,19 +88,34 @@ let ProjectQuery = class ProjectQuery {
57
88
  async scheduleTable(project) {
58
89
  const attachment = await (0, shell_1.getRepository)(attachment_base_1.Attachment).findOne({
59
90
  where: {
60
- domain: { id: project.domainId },
61
91
  refBy: project.id,
62
92
  refType: project_1.Project.name + '_schedule_table'
63
93
  }
64
94
  });
65
95
  return attachment;
66
96
  }
97
+ async completeReport(project) {
98
+ if (!project.completeReportId) {
99
+ return undefined;
100
+ }
101
+ const attachment = await (0, shell_1.getRepository)(attachment_base_1.Attachment).findOne({
102
+ where: { id: project.completeReportId }
103
+ });
104
+ return attachment;
105
+ }
67
106
  async buildingComplex(project) {
68
107
  return await (0, shell_1.getRepository)(building_complex_1.BuildingComplex).findOneBy({ id: project.buildingComplexId });
69
108
  }
70
109
  async domain(project) {
71
110
  return await (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: project.domainId });
72
111
  }
112
+ async tenantDomain(project) {
113
+ if (!project.code)
114
+ return null;
115
+ return await (0, shell_1.getRepository)(shell_1.Domain).findOne({
116
+ where: { subdomain: project.code, extType: 'project' }
117
+ });
118
+ }
73
119
  async updater(project) {
74
120
  return await (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: project.updaterId });
75
121
  }
@@ -79,6 +125,18 @@ let ProjectQuery = class ProjectQuery {
79
125
  async projectType(project) {
80
126
  return env_1.config.get('projectType', project_1.ProjectType.DSSP);
81
127
  }
128
+ async kpi(project) {
129
+ const kpi = await (0, shell_1.getRepository)(kpi_1.Kpi).findOneBy({ name: 'Z. 전체스코어' });
130
+ const kpiValue = await (0, shell_1.getRepository)(kpi_1.KpiValue).findOneBy({ group: project.id, kpi: { id: kpi.id } });
131
+ return kpiValue ? (kpiValue.value || 0) * 100 : project.kpi;
132
+ }
133
+ async kpiValues(project) {
134
+ const kpiValues = await (0, shell_1.getRepository)(kpi_1.KpiValue).find({
135
+ where: { group: project.id },
136
+ relations: ['kpi']
137
+ });
138
+ return kpiValues ? kpiValues.map(kpiValue => ({ kpiName: kpiValue.kpi.name, value: kpiValue.value || 0 })) : [];
139
+ }
82
140
  };
83
141
  exports.ProjectQuery = ProjectQuery;
84
142
  tslib_1.__decorate([
@@ -89,22 +147,44 @@ tslib_1.__decorate([
89
147
  tslib_1.__metadata("design:paramtypes", [String, Object]),
90
148
  tslib_1.__metadata("design:returntype", Promise)
91
149
  ], ProjectQuery.prototype, "project", null);
150
+ tslib_1.__decorate([
151
+ (0, type_graphql_1.Query)(returns => project_1.Project, {
152
+ nullable: true,
153
+ description: '현재 테넌트 컨텍스트(extType=project)의 프로젝트. subdomain(=Project.code) 으로 조회.'
154
+ }),
155
+ tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
156
+ tslib_1.__metadata("design:type", Function),
157
+ tslib_1.__metadata("design:paramtypes", [Object]),
158
+ tslib_1.__metadata("design:returntype", Promise)
159
+ ], ProjectQuery.prototype, "currentProject", null);
92
160
  tslib_1.__decorate([
93
161
  (0, type_graphql_1.Query)(returns => project_type_1.ProjectList, { description: '프로젝트 리스트' }),
94
162
  tslib_1.__param(0, (0, type_graphql_1.Args)()),
95
- tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
96
163
  tslib_1.__metadata("design:type", Function),
97
- tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
164
+ tslib_1.__metadata("design:paramtypes", [shell_1.ListParam]),
98
165
  tslib_1.__metadata("design:returntype", Promise)
99
166
  ], ProjectQuery.prototype, "projects", null);
100
167
  tslib_1.__decorate([
101
168
  (0, type_graphql_1.Query)(returns => project_1.Project, { nullable: true, description: 'To fetch a Project' }),
102
169
  tslib_1.__param(0, (0, type_graphql_1.Arg)('buildingComplexId')),
170
+ tslib_1.__metadata("design:type", Function),
171
+ tslib_1.__metadata("design:paramtypes", [String]),
172
+ tslib_1.__metadata("design:returntype", Promise)
173
+ ], ProjectQuery.prototype, "projectByBuildingComplexId", null);
174
+ tslib_1.__decorate([
175
+ (0, type_graphql_1.Query)(returns => project_1.Project, { description: 'To fetch Project' }),
176
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('buildingLevelId')),
103
177
  tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
104
178
  tslib_1.__metadata("design:type", Function),
105
179
  tslib_1.__metadata("design:paramtypes", [String, Object]),
106
180
  tslib_1.__metadata("design:returntype", Promise)
107
- ], ProjectQuery.prototype, "projectByBuildingComplexId", null);
181
+ ], ProjectQuery.prototype, "projectByBuildingLevelId", null);
182
+ tslib_1.__decorate([
183
+ (0, type_graphql_1.Query)(returns => String, { description: '프로젝트 타입 조회' }),
184
+ tslib_1.__metadata("design:type", Function),
185
+ tslib_1.__metadata("design:paramtypes", []),
186
+ tslib_1.__metadata("design:returntype", Promise)
187
+ ], ProjectQuery.prototype, "currentProjectType", null);
108
188
  tslib_1.__decorate([
109
189
  (0, type_graphql_1.FieldResolver)(type => [task_1.Task], { nullable: true }),
110
190
  tslib_1.__param(0, (0, type_graphql_1.Root)()),
@@ -126,6 +206,13 @@ tslib_1.__decorate([
126
206
  tslib_1.__metadata("design:paramtypes", [project_1.Project]),
127
207
  tslib_1.__metadata("design:returntype", Promise)
128
208
  ], ProjectQuery.prototype, "scheduleTable", null);
209
+ tslib_1.__decorate([
210
+ (0, type_graphql_1.FieldResolver)(type => attachment_base_1.Attachment),
211
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
212
+ tslib_1.__metadata("design:type", Function),
213
+ tslib_1.__metadata("design:paramtypes", [project_1.Project]),
214
+ tslib_1.__metadata("design:returntype", Promise)
215
+ ], ProjectQuery.prototype, "completeReport", null);
129
216
  tslib_1.__decorate([
130
217
  (0, type_graphql_1.FieldResolver)(type => building_complex_1.BuildingComplex),
131
218
  tslib_1.__param(0, (0, type_graphql_1.Root)()),
@@ -140,6 +227,16 @@ tslib_1.__decorate([
140
227
  tslib_1.__metadata("design:paramtypes", [project_1.Project]),
141
228
  tslib_1.__metadata("design:returntype", Promise)
142
229
  ], ProjectQuery.prototype, "domain", null);
230
+ tslib_1.__decorate([
231
+ (0, type_graphql_1.FieldResolver)(type => shell_1.Domain, {
232
+ nullable: true,
233
+ description: '활성 테넌트 Domain (extType=project). 미승격 또는 강등 상태이면 null'
234
+ }),
235
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
236
+ tslib_1.__metadata("design:type", Function),
237
+ tslib_1.__metadata("design:paramtypes", [project_1.Project]),
238
+ tslib_1.__metadata("design:returntype", Promise)
239
+ ], ProjectQuery.prototype, "tenantDomain", null);
143
240
  tslib_1.__decorate([
144
241
  (0, type_graphql_1.FieldResolver)(type => auth_base_1.User),
145
242
  tslib_1.__param(0, (0, type_graphql_1.Root)()),
@@ -161,7 +258,35 @@ tslib_1.__decorate([
161
258
  tslib_1.__metadata("design:paramtypes", [project_1.Project]),
162
259
  tslib_1.__metadata("design:returntype", Promise)
163
260
  ], ProjectQuery.prototype, "projectType", null);
261
+ tslib_1.__decorate([
262
+ (0, type_graphql_1.FieldResolver)(type => Number),
263
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
264
+ tslib_1.__metadata("design:type", Function),
265
+ tslib_1.__metadata("design:paramtypes", [project_1.Project]),
266
+ tslib_1.__metadata("design:returntype", Promise)
267
+ ], ProjectQuery.prototype, "kpi", null);
268
+ tslib_1.__decorate([
269
+ (0, type_graphql_1.FieldResolver)(type => [KpiValuesObject]),
270
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
271
+ tslib_1.__metadata("design:type", Function),
272
+ tslib_1.__metadata("design:paramtypes", [project_1.Project]),
273
+ tslib_1.__metadata("design:returntype", Promise)
274
+ ], ProjectQuery.prototype, "kpiValues", null);
164
275
  exports.ProjectQuery = ProjectQuery = tslib_1.__decorate([
165
276
  (0, type_graphql_1.Resolver)(project_1.Project)
166
277
  ], ProjectQuery);
278
+ let KpiValuesObject = class KpiValuesObject {
279
+ };
280
+ exports.KpiValuesObject = KpiValuesObject;
281
+ tslib_1.__decorate([
282
+ (0, type_graphql_1.Field)(type => String),
283
+ tslib_1.__metadata("design:type", String)
284
+ ], KpiValuesObject.prototype, "kpiName", void 0);
285
+ tslib_1.__decorate([
286
+ (0, type_graphql_1.Field)(type => Number),
287
+ tslib_1.__metadata("design:type", Number)
288
+ ], KpiValuesObject.prototype, "value", void 0);
289
+ exports.KpiValuesObject = KpiValuesObject = tslib_1.__decorate([
290
+ (0, type_graphql_1.ObjectType)()
291
+ ], KpiValuesObject);
167
292
  //# sourceMappingURL=project-query.js.map