@dssp/project 1.0.0-alpha.0 → 1.0.0-alpha.1

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 (97) hide show
  1. package/dist-client/tsconfig.tsbuildinfo +1 -1
  2. package/package.json +3 -3
  3. package/client/bootstrap.ts +0 -0
  4. package/client/index.ts +0 -0
  5. package/client/pages/lib/select2-component.ts +0 -175
  6. package/client/pages/lib/waether.ts +0 -159
  7. package/client/pages/project/component/project-update-header.ts +0 -88
  8. package/client/pages/project/popup/popup-plan-upload.ts +0 -138
  9. package/client/pages/project/popup/popup-project-create.ts +0 -147
  10. package/client/pages/project/popup/popup-schedule-upload.ts +0 -102
  11. package/client/pages/project/project-completed-list.ts +0 -281
  12. package/client/pages/project/project-detail.ts +0 -738
  13. package/client/pages/project/project-list.ts +0 -418
  14. package/client/pages/project/project-plan-management.ts +0 -476
  15. package/client/pages/project/project-schedule-list.ts +0 -294
  16. package/client/pages/project/project-schedule.ts +0 -393
  17. package/client/pages/project/project-setting-list.ts +0 -393
  18. package/client/pages/project/project-update.ts +0 -876
  19. package/client/pages/resource/construction-detail-type-popup.ts +0 -201
  20. package/client/pages/resource/construction-type-management.ts +0 -212
  21. package/client/pages/resource/inspection-drawing-type-management.ts +0 -245
  22. package/client/pages/resource/inspection-part-popup.ts +0 -201
  23. package/client/pages/resource/resource-importer.ts +0 -97
  24. package/client/pages/resource/resource-list-page.ts +0 -356
  25. package/client/pages/resource/worker-type-management.ts +0 -192
  26. package/client/pages/task/task-importer.ts +0 -94
  27. package/client/pages/task/task-list-page.ts +0 -340
  28. package/client/pages/task-resource/task-resource-importer.ts +0 -97
  29. package/client/pages/task-resource/task-resource-list-page.ts +0 -356
  30. package/client/route.ts +0 -55
  31. package/client/tsconfig.json +0 -11
  32. package/server/controllers/export-tasks.ts +0 -40
  33. package/server/controllers/import-task.ts +0 -134
  34. package/server/controllers/index.ts +0 -0
  35. package/server/controllers/parse-excel.ts +0 -86
  36. package/server/controllers/types.ts +0 -20
  37. package/server/index.ts +0 -4
  38. package/server/middlewares/index.ts +0 -3
  39. package/server/migrations/1723861466413-seed-roles.ts +0 -128
  40. package/server/migrations/1723861466414-seed-codes.ts +0 -157
  41. package/server/migrations/1723861476419-seed-resources.ts +0 -62
  42. package/server/migrations/1723861478420-seed-/bsample-project.ts +0 -87
  43. package/server/migrations/1723861478421-seed-/bsample-tasks.ts +0 -194
  44. package/server/migrations/index.ts +0 -9
  45. package/server/routes.ts +0 -108
  46. package/server/service/construction-detail-type/construction-detail-type-mutation.ts +0 -57
  47. package/server/service/construction-detail-type/construction-detail-type-query.ts +0 -31
  48. package/server/service/construction-detail-type/construction-detail-type-type.ts +0 -26
  49. package/server/service/construction-detail-type/construction-detail-type.ts +0 -52
  50. package/server/service/construction-detail-type/index.ts +0 -6
  51. package/server/service/construction-type/construction-type-mutation.ts +0 -66
  52. package/server/service/construction-type/construction-type-query.ts +0 -56
  53. package/server/service/construction-type/construction-type-type.ts +0 -26
  54. package/server/service/construction-type/construction-type.ts +0 -74
  55. package/server/service/construction-type/index.ts +0 -6
  56. package/server/service/index.ts +0 -56
  57. package/server/service/inspection-drawing-type/index.ts +0 -6
  58. package/server/service/inspection-drawing-type/inspection-drawing-type-mutation.ts +0 -69
  59. package/server/service/inspection-drawing-type/inspection-drawing-type-query.ts +0 -55
  60. package/server/service/inspection-drawing-type/inspection-drawing-type-type.ts +0 -23
  61. package/server/service/inspection-drawing-type/inspection-drawing-type.ts +0 -68
  62. package/server/service/inspection-part/index.ts +0 -6
  63. package/server/service/inspection-part/inspection-part-mutation.ts +0 -52
  64. package/server/service/inspection-part/inspection-part-query.ts +0 -41
  65. package/server/service/inspection-part/inspection-part-type.ts +0 -26
  66. package/server/service/inspection-part/inspection-part.ts +0 -51
  67. package/server/service/manager/index.ts +0 -6
  68. package/server/service/manager/manager-mutation.ts +0 -42
  69. package/server/service/manager/manager-query.ts +0 -28
  70. package/server/service/manager/manager-type.ts +0 -40
  71. package/server/service/manager/manager.ts +0 -29
  72. package/server/service/project/index.ts +0 -6
  73. package/server/service/project/project-mutation.ts +0 -255
  74. package/server/service/project/project-query.ts +0 -105
  75. package/server/service/project/project-type.ts +0 -72
  76. package/server/service/project/project.ts +0 -134
  77. package/server/service/resource/index.ts +0 -7
  78. package/server/service/resource/resource-mutation.ts +0 -137
  79. package/server/service/resource/resource-query.ts +0 -50
  80. package/server/service/resource/resource-type.ts +0 -41
  81. package/server/service/resource/resource.ts +0 -82
  82. package/server/service/task/index.ts +0 -6
  83. package/server/service/task/task-mutation.ts +0 -135
  84. package/server/service/task/task-query.ts +0 -169
  85. package/server/service/task/task-type.ts +0 -75
  86. package/server/service/task/task.ts +0 -130
  87. package/server/service/task-resource/index.ts +0 -7
  88. package/server/service/task-resource/task-resource-mutation.ts +0 -140
  89. package/server/service/task-resource/task-resource-query.ts +0 -36
  90. package/server/service/task-resource/task-resource-type.ts +0 -41
  91. package/server/service/task-resource/task-resource.ts +0 -51
  92. package/server/service/worker-type/index.ts +0 -6
  93. package/server/service/worker-type/worker-type-mutation.ts +0 -66
  94. package/server/service/worker-type/worker-type-query.ts +0 -47
  95. package/server/service/worker-type/worker-type-type.ts +0 -26
  96. package/server/service/worker-type/worker-type.ts +0 -68
  97. package/server/tsconfig.json +0 -10
@@ -1,255 +0,0 @@
1
- import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
- import { In } from 'typeorm'
3
- import { getRepository } from '@things-factory/shell'
4
- import { Attachment, createAttachment, deleteAttachmentsByRef, ATTACHMENT_PATH } from '@things-factory/attachment-base'
5
- import { Project, ProjectState } from './project'
6
- import { NewProject, ProjectPatch, UploadProjectScheduleTable } from './project-type'
7
- import { BuildingComplex, Building, BuildingLevel } from '@dssp/building-complex'
8
- import { pdfToImage } from '@things-factory/board-service/dist-server/controllers/headless-pdf-to-image'
9
-
10
- import { parseExcelAndImportTasks } from '../../controllers/parse-excel'
11
- @Resolver(Project)
12
- export class ProjectMutation {
13
- @Directive('@transaction')
14
- @Mutation(returns => Project, { description: '프로젝트 생성' })
15
- async createProject(@Arg('project') project: NewProject, @Ctx() context: ResolverContext): Promise<Project> {
16
- const { domain, user, tx } = context.state
17
- const projectRepo = getRepository(Project, tx)
18
- const buildingComplexRepo = getRepository(BuildingComplex, tx)
19
-
20
- const newBuildingComplex = await buildingComplexRepo.save({
21
- domain,
22
- creator: user,
23
- updater: user
24
- })
25
-
26
- const result = await projectRepo.save({
27
- name: project.name,
28
- buildingComplex: newBuildingComplex,
29
- domain,
30
- creator: user,
31
- updater: user
32
- })
33
-
34
- return result
35
- }
36
-
37
- @Directive('@transaction')
38
- @Mutation(returns => Project, { description: '프로젝트 업데이트' })
39
- async updateProject(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {
40
- const { user, tx } = context.state
41
- const projectRepo = getRepository(Project, tx)
42
- const buildingComplexRepo = getRepository(BuildingComplex, tx)
43
- const buildingRepo = getRepository(Building, tx)
44
- const buildingLevelRepo = getRepository(BuildingLevel, tx)
45
-
46
- const buildingComplex = project.buildingComplex
47
- const buildings = project.buildingComplex?.buildings || []
48
-
49
- // 1. 프로젝트 수정
50
- const projectState = project.totalProgress == 100 ? ProjectState.COMPLETED : ProjectState.ONGOING
51
- const projectResult = await projectRepo.save({ ...project, state: projectState, updater: user })
52
-
53
- // 2. 단지 정보 수정
54
- await buildingComplexRepo.save({ ...buildingComplex, updater: user })
55
-
56
- // 2-1. 프로젝트 메인 이미지 첨부파일 나머지 삭제 후 저장
57
- await createAttachmentAfterDelete(context, project?.mainPhotoUpload, project.id, Project.name)
58
-
59
- // 2-2. 단지 BIM 이미지 첨부파일 나머지 삭제 후 저장
60
- await createAttachmentAfterDelete(context, buildingComplex?.drawingUpload, buildingComplex.id, BuildingComplex.name + '_bim')
61
-
62
- // 3. 동의 층 정보가 바뀌었으면 층 초기화 후 다시 생성
63
- const originBuilding = await buildingRepo.findBy({ buildingComplex: { id: buildingComplex.id } }) // 이전 동 정보 가져오기
64
- const afterBuilding = buildings.reduce((acc, building) => ({ ...acc, [building.name]: building.floorCount }), {}) // 비교용으로 수정된 동 정보 데이터 파싱
65
- const isBuidlingChanged = originBuilding.some(building => afterBuilding[building.name] !== building.floorCount) // 층 개수가 달라진 동이 있는지 확인
66
-
67
- // 동의 층 개수가 달라지면 모든 층의 데이터 제거 후 생성
68
- if (isBuidlingChanged || originBuilding.length !== buildings.length) {
69
- // 3-1. 기존 동/층 첨부파일 및 데이터 제거
70
- const buildingIds = originBuilding.map((building: Building) => building.id)
71
- const buildingLevels = await buildingLevelRepo.findBy({ building: { id: In(buildingIds) } })
72
- const buildingLevelIds = buildingLevels.map((buildingLevel: BuildingLevel) => buildingLevel.id)
73
-
74
- await buildingLevelRepo.softDelete({ building: { id: In(buildingIds) } })
75
- await buildingRepo.softDelete({ id: In(buildingIds) })
76
- await deleteAttachmentsByRef(null, { refBys: [...buildingIds, ...buildingLevelIds] }, context)
77
-
78
- // 3-2. 단지 내 동 정보들 생성
79
- for (let buildingKey in buildings) {
80
- const building = buildings[buildingKey]
81
- const newBuilding = await buildingRepo.save({
82
- buildingComplex: buildingComplex,
83
- name: building.name,
84
- floorCount: building.floorCount,
85
- creator: user
86
- })
87
-
88
- // 3-3. 동별로 for문 돌면서 층 데이터 개수대로 생성
89
- for (let i = 1; i <= building.floorCount; i++) {
90
- await buildingLevelRepo.save({ building: newBuilding, floor: i, creator: user })
91
- }
92
- }
93
- }
94
-
95
- return projectResult
96
- }
97
-
98
- @Directive('@transaction')
99
- @Mutation(returns => Project, { description: '프로젝트 도면 업데이트' })
100
- async updateProjectPlan(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {
101
- const { user, tx, domain } = context.state
102
- const projectRepo = getRepository(Project, tx)
103
- const buildingComplexRepo = getRepository(BuildingComplex, tx)
104
- const buildingRepo = getRepository(Building, tx)
105
- const buildingLevelRepo = getRepository(BuildingLevel, tx)
106
- const buildingComplex = project.buildingComplex
107
- const buildings = project.buildingComplex?.buildings || []
108
-
109
- // 1. 프로젝트 수정 시간 업데이트
110
- const projectResult = await projectRepo.save({ ...project, updater: user })
111
-
112
- // 2. 단지 축척 정보 수정
113
- await buildingComplexRepo.save({ ...buildingComplex, updater: user })
114
-
115
- for (let buildingKey in buildings) {
116
- const building = buildings[buildingKey]
117
-
118
- for (let buildingLevelKey in building.buildingLevels) {
119
- const buildingLevel = building.buildingLevels[buildingLevelKey]
120
-
121
- // 3. 층별 도면 이미지 저장
122
- const mainDrawingAttatchment = await createAttachmentAfterDelete(
123
- context,
124
- buildingLevel.mainDrawingUpload,
125
- buildingLevel.id,
126
- BuildingLevel.name + '_mainDrawing'
127
- )
128
- // 첨부된 PDF가 있으면 PDF 파일대로 썸네일 생성
129
- if (mainDrawingAttatchment) {
130
- const mainDrawingUpload = await buildingLevel.mainDrawingUpload
131
- const pdfPath = `/${ATTACHMENT_PATH}/${mainDrawingAttatchment.path}` // TODO ATTACHMENT_PATH 제거, mainDrawingAttachment.fullpath 로 해도 될 것 같은데...
132
- const fileName = mainDrawingUpload.filename.replace('.pdf', '')
133
- const pngFile = await pdfToImage({ pdfPath, fileName })
134
- await createAttachmentAfterDelete(context, pngFile, buildingLevel.id, BuildingLevel.name + '_mainDrawing_image')
135
-
136
- const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })
137
- await createAttachmentAfterDelete(
138
- context,
139
- pngThumbnailFile,
140
- buildingLevel.id,
141
- BuildingLevel.name + '_mainDrawing_thumbnail'
142
- )
143
- }
144
-
145
- // 3-1. 입면도 파일 저장
146
- const elevationDrawingAttatchment = await createAttachmentAfterDelete(
147
- context,
148
- buildingLevel.elevationDrawingUpload,
149
- buildingLevel.id,
150
- BuildingLevel.name + '_elevationDrawing'
151
- )
152
- if (elevationDrawingAttatchment) {
153
- const elevationDrawingUpload = await buildingLevel.elevationDrawingUpload
154
- const pdfPath = `/${ATTACHMENT_PATH}/${elevationDrawingAttatchment.path}`
155
- const fileName = elevationDrawingUpload.filename.replace('.pdf', '')
156
- const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })
157
- await createAttachmentAfterDelete(
158
- context,
159
- pngThumbnailFile,
160
- buildingLevel.id,
161
- BuildingLevel.name + '_elevationDrawing_thumbnail'
162
- )
163
- }
164
-
165
- // 3-2. 철근배분도 파일 저장
166
- const rebarDistributionDrawingAttatchment = await createAttachmentAfterDelete(
167
- context,
168
- buildingLevel.rebarDistributionDrawingUpload,
169
- buildingLevel.id,
170
- BuildingLevel.name + '_rebarDistributionDrawing'
171
- )
172
- if (rebarDistributionDrawingAttatchment) {
173
- const rebarDistributionDrawingUpload = await buildingLevel.rebarDistributionDrawingUpload
174
- const pdfPath = `/${ATTACHMENT_PATH}/${rebarDistributionDrawingAttatchment.path}`
175
- const fileName = rebarDistributionDrawingUpload.filename.replace('.pdf', '')
176
- const pngThumbnailFile = await pdfToImage({ pdfPath, fileName, defaultViewport: { width: 300, height: 200 } })
177
- await createAttachmentAfterDelete(
178
- context,
179
- pngThumbnailFile,
180
- buildingLevel.id,
181
- BuildingLevel.name + '_rebarDistributionDrawing_thumbnail'
182
- )
183
- }
184
-
185
- // 3-3. 층 업데이트 시간 갱신
186
- await buildingLevelRepo.save({ ...buildingLevel, updater: user })
187
- }
188
-
189
- // 4. 동별 도면 이미지 저장
190
- await createAttachmentAfterDelete(context, building?.drawingUpload, building.id, Building.name)
191
-
192
- // 4-1. 동 업데이트 시간 갱신
193
- await buildingRepo.save({ ...building, updater: user })
194
- }
195
-
196
- return projectResult
197
- }
198
-
199
- @Directive('@transaction')
200
- @Mutation(returns => Boolean, { description: '프로젝트 공정표 업로드' })
201
- async uploadProjectScheduleTable(
202
- @Arg('param') param: UploadProjectScheduleTable,
203
- @Ctx() context: ResolverContext
204
- ): Promise<boolean> {
205
- const { domain, user, tx } = context.state
206
- const { projectId, scheduleTable } = param
207
-
208
- const projectRepo = getRepository(Project, tx)
209
- const project = await projectRepo.findOne({
210
- where: { domain: { id: domain.id }, id: projectId }
211
- })
212
-
213
- const { createReadStream, filename, mimetype } = await scheduleTable
214
-
215
- const stream = createReadStream()
216
-
217
- const chunks = []
218
- for await (const chunk of stream) {
219
- chunks.push(chunk)
220
- }
221
-
222
- const buffer = Buffer.concat(chunks)
223
-
224
- await parseExcelAndImportTasks(buffer, project, context)
225
- // await parseExcelAndImportTasks(attachment.fullpath, project, context)
226
-
227
- return true
228
- }
229
-
230
- @Directive('@transaction')
231
- @Mutation(returns => Boolean, { description: 'To delete Project' })
232
- async deleteProject(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
233
- const { domain, tx } = context.state
234
-
235
- await getRepository(Project, tx).delete({ domain: { id: domain.id }, id })
236
- await deleteAttachmentsByRef(null, { refBys: [id] }, context)
237
-
238
- return true
239
- }
240
- }
241
-
242
- export async function createAttachmentAfterDelete(context: ResolverContext, file: any, refBy: any, refType: any) {
243
- if (file === undefined) {
244
- return null
245
- }
246
-
247
- const { tx } = context.state
248
-
249
- // 기존 첨부 파일이 있으면 삭제
250
- await deleteAttachmentsByRef(null, { refBys: [refBy], refType }, context)
251
-
252
- let result = await createAttachment(null, { attachment: { file, refType, refBy } }, context)
253
-
254
- return await getRepository(Attachment, tx).findOne({ where: { id: result.id } })
255
- }
@@ -1,105 +0,0 @@
1
- import { Resolver, Query, FieldResolver, Root, Arg, Args, Ctx } from 'type-graphql'
2
- import { IsNull } from 'typeorm'
3
- import { Domain, getRepository, ListParam, getQueryBuilderFromListParams } from '@things-factory/shell'
4
- import { User } from '@things-factory/auth-base'
5
- import { Project } from './project'
6
- import { Task } from '../task/task'
7
- import { ProjectList } from './project-type'
8
- import { Attachment } from '@things-factory/attachment-base'
9
- import { BuildingComplex } from '@dssp/building-complex'
10
-
11
- @Resolver(Project)
12
- export class ProjectQuery {
13
- @Query(returns => Project!, { nullable: true, description: 'To fetch a Project' })
14
- async project(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Project> {
15
- const { domain } = context.state
16
-
17
- return await getRepository(Project).findOne({
18
- where: { domain: { id: domain.id }, id }
19
- })
20
- }
21
-
22
- @Query(returns => ProjectList, { description: '프로젝트 리스트' })
23
- async projects(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<ProjectList> {
24
- const { domain } = context.state
25
-
26
- const queryBuilder = getQueryBuilderFromListParams({
27
- domain,
28
- params,
29
- repository: await getRepository(Project),
30
- searchables: ['name', 'description', 'state']
31
- })
32
-
33
- const [items, total] = await queryBuilder.getManyAndCount()
34
-
35
- return { items, total }
36
- }
37
-
38
- @Query(returns => Project!, { nullable: true, description: 'To fetch a Project' })
39
- async projectByBuildingComplexId(
40
- @Arg('buildingComplexId') buildingComplexId: string,
41
- @Ctx() context: ResolverContext
42
- ): Promise<Project> {
43
- const { domain } = context.state
44
-
45
- return await getRepository(Project).findOne({
46
- where: { domain: { id: domain.id }, buildingComplex: { id: buildingComplexId } }
47
- })
48
- }
49
-
50
- @FieldResolver(type => [Task], { nullable: true })
51
- async rootTasks(@Root() project: Project): Promise<Task[]> {
52
- return await getRepository(Task).find({
53
- where: {
54
- project: { id: project.id },
55
- parent: IsNull()
56
- }
57
- })
58
- }
59
-
60
- @FieldResolver(type => Attachment)
61
- async mainPhoto(@Root() project: Project): Promise<string | Attachment> {
62
- const attachment: Attachment = await getRepository(Attachment).findOne({
63
- where: {
64
- domain: { id: project.domainId },
65
- refBy: project.id
66
- },
67
- order: { createdAt: 'ASC' }
68
- })
69
-
70
- return attachment
71
- }
72
-
73
- @FieldResolver(type => Attachment)
74
- async scheduleTable(@Root() project: Project): Promise<Attachment | undefined> {
75
- const attachment: Attachment = await getRepository(Attachment).findOne({
76
- where: {
77
- domain: { id: project.domainId },
78
- refBy: project.id,
79
- refType: Project.name + '_schedule_table'
80
- }
81
- })
82
-
83
- return attachment
84
- }
85
-
86
- @FieldResolver(type => BuildingComplex)
87
- async buildingComplex(@Root() project: Project): Promise<BuildingComplex> {
88
- return await getRepository(BuildingComplex).findOneBy({ id: project.buildingComplexId })
89
- }
90
-
91
- @FieldResolver(type => Domain)
92
- async domain(@Root() project: Project): Promise<Domain> {
93
- return await getRepository(Domain).findOneBy({ id: project.domainId })
94
- }
95
-
96
- @FieldResolver(type => User)
97
- async updater(@Root() project: Project): Promise<User> {
98
- return await getRepository(User).findOneBy({ id: project.updaterId })
99
- }
100
-
101
- @FieldResolver(type => User)
102
- async creator(@Root() project: Project): Promise<User> {
103
- return await getRepository(User).findOneBy({ id: project.creatorId })
104
- }
105
- }
@@ -1,72 +0,0 @@
1
- import { ObjectType, Field, InputType, Int, Float } from 'type-graphql'
2
- import { Project } from './project'
3
- import type { FileUpload } from 'graphql-upload/GraphQLUpload.js'
4
- import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'
5
- import { ObjectRef, ScalarObject } from '@things-factory/shell'
6
- import { BuildingComplexPatch } from '@dssp/building-complex'
7
-
8
- @InputType()
9
- export class NewProject {
10
- @Field({ nullable: false, description: '프로젝트 이름' })
11
- name: string
12
-
13
- @Field(type => ObjectRef, { nullable: true, description: '연관된 건물 복합체 정보 (선택 사항)' })
14
- buildingComplex?: ObjectRef
15
- }
16
-
17
- @InputType()
18
- export class ProjectPatch {
19
- @Field({ nullable: false, description: '수정할 프로젝트의 ID' })
20
- id: string
21
-
22
- @Field({ nullable: false, description: '프로젝트 이름' })
23
- name: string
24
-
25
- @Field({ nullable: true, description: '프로젝트 착공일정' })
26
- startDate?: string
27
-
28
- @Field({ nullable: true, description: '프로젝트 준공일정' })
29
- endDate?: string
30
-
31
- @Field(type => GraphQLUpload, { nullable: true, description: '프로젝트 대표 사진 업로드' })
32
- mainPhotoUpload?: FileUpload
33
-
34
- @Field(type => Float, { nullable: true, description: '프로젝트 전체 진행현황 (%)' })
35
- totalProgress?: number
36
-
37
- @Field(type => Float, { nullable: true, description: '프로젝트 주간 진행현황 (%)' })
38
- weeklyProgress?: number
39
-
40
- @Field(type => Float, { nullable: true, description: '프로젝트 KPI' })
41
- kpi?: number
42
-
43
- @Field(type => Float, { nullable: true, description: '검측/통과 비율 (%)' })
44
- inspPassRate?: number
45
-
46
- @Field(type => Float, { nullable: true, description: '로봇 작업 진행율 (%)' })
47
- robotProgressRate?: number
48
-
49
- @Field(type => Float, { nullable: true, description: '구조 안전도 (%)' })
50
- structuralSafetyRate?: number
51
-
52
- @Field({ nullable: true })
53
- buildingComplex?: BuildingComplexPatch
54
- }
55
-
56
- @InputType()
57
- export class UploadProjectScheduleTable {
58
- @Field({ nullable: false, description: '수정할 프로젝트의 ID' })
59
- projectId: string
60
-
61
- @Field(type => GraphQLUpload, { nullable: true, description: '프로젝트 공정표 업로드' })
62
- scheduleTable?: FileUpload
63
- }
64
-
65
- @ObjectType()
66
- export class ProjectList {
67
- @Field(type => [Project], { description: '프로젝트 리스트 항목들' })
68
- items: Project[]
69
-
70
- @Field(type => Int, { description: '전체 프로젝트 수' })
71
- total: number
72
- }
@@ -1,134 +0,0 @@
1
- import {
2
- CreateDateColumn,
3
- UpdateDateColumn,
4
- DeleteDateColumn,
5
- Entity,
6
- Index,
7
- Column,
8
- RelationId,
9
- ManyToOne,
10
- OneToOne,
11
- OneToMany,
12
- JoinColumn,
13
- PrimaryGeneratedColumn
14
- } from 'typeorm'
15
- import { ObjectType, Field, ID } from 'type-graphql'
16
-
17
- import { Domain, roundTransformer } from '@things-factory/shell'
18
- import { User } from '@things-factory/auth-base'
19
- import { Task } from '../task/task'
20
- import { BuildingComplex } from '@dssp/building-complex'
21
- import { Attachment } from '@things-factory/attachment-base'
22
-
23
- export enum ProjectState {
24
- 'ONGOING' = '10',
25
- 'COMPLETED' = '20'
26
- }
27
-
28
- @ObjectType({ description: '프로젝트' })
29
- @Entity()
30
- @Index('ix_project_building', (project: Project) => [project.buildingComplex], { unique: true, where: '"deleted_at" IS NULL' })
31
- export class Project {
32
- @PrimaryGeneratedColumn('uuid')
33
- @Field(type => ID)
34
- readonly id: string
35
-
36
- @ManyToOne(type => Domain)
37
- @Field({ nullable: true })
38
- domain?: Domain
39
-
40
- @RelationId((project: Project) => project.domain)
41
- domainId?: string
42
-
43
- @Column({ nullable: false, comment: '프로젝트 이름' })
44
- @Field({ nullable: false })
45
- name?: string
46
-
47
- @Column({ nullable: false, default: ProjectState.ONGOING, comment: '프로젝트 상태 (10: 진행중, 20: 완료)' })
48
- @Field({ nullable: false })
49
- state?: ProjectState
50
-
51
- @Column({ type: 'date', nullable: true, comment: '착공일정' })
52
- @Field({ nullable: true })
53
- startDate?: string
54
-
55
- @Column({ type: 'date', nullable: true, comment: '준공일정' })
56
- @Field({ nullable: true })
57
- endDate?: string
58
-
59
- // 대표 사진
60
- @Field(type => Attachment, { nullable: true })
61
- mainPhoto?: Attachment
62
-
63
- @Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '전체 진행현황' })
64
- @Field({ nullable: true })
65
- totalProgress?: number
66
-
67
- @Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '주간 진행현황' })
68
- @Field({ nullable: true })
69
- weeklyProgress?: number
70
-
71
- @Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: 'KPI' })
72
- @Field({ nullable: true })
73
- kpi?: number
74
-
75
- @Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '검측/통과 비율' })
76
- @Field({ nullable: true })
77
- inspPassRate?: number
78
-
79
- @Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '로봇 작업 진행율' })
80
- @Field({ nullable: true })
81
- robotProgressRate?: number
82
-
83
- @Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '구조 안전도' })
84
- @Field({ nullable: true })
85
- structuralSafetyRate?: number
86
-
87
- // 단지 정보 (1:1 테이블 참조)
88
- @OneToOne(type => BuildingComplex)
89
- @JoinColumn()
90
- @Field({ nullable: true })
91
- buildingComplex?: BuildingComplex
92
-
93
- @RelationId((project: Project) => project.buildingComplex)
94
- buildingComplexId?: string
95
-
96
- // 작업 정보 (하위 테이블 참조)
97
- @OneToMany(() => Task, task => task.project)
98
- @Field(() => [Task], { nullable: true })
99
- tasks?: Task[]
100
-
101
- // 루트 작업 정보 (부모가 없는 상위 작업)
102
- @Field(() => [Task], { nullable: true })
103
- rootTasks?: Task[]
104
-
105
- @CreateDateColumn()
106
- @Field({ nullable: true })
107
- createdAt?: Date
108
-
109
- @UpdateDateColumn()
110
- @Field({ nullable: true })
111
- updatedAt?: Date
112
-
113
- @DeleteDateColumn()
114
- @Field({ nullable: true })
115
- deletedAt?: Date
116
-
117
- @ManyToOne(type => User, { nullable: true })
118
- @Field(type => User, { nullable: true })
119
- creator?: User
120
-
121
- @RelationId((project: Project) => project.creator)
122
- creatorId?: string
123
-
124
- @ManyToOne(type => User, { nullable: true })
125
- @Field(type => User, { nullable: true })
126
- updater?: User
127
-
128
- @RelationId((project: Project) => project.updater)
129
- updaterId?: string
130
-
131
- // 공정표 파일
132
- @Field(type => Attachment, { nullable: true })
133
- scheduleTable?: Attachment
134
- }
@@ -1,7 +0,0 @@
1
- import { Resource } from './resource'
2
- import { ResourceQuery } from './resource-query'
3
- import { ResourceMutation } from './resource-mutation'
4
-
5
- export const entities = [Resource]
6
- export const resolvers = [ResourceQuery, ResourceMutation]
7
- export const subscribers = []