@dssp/project 1.0.0-alpha.0 → 1.0.0-alpha.2
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.
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/client/bootstrap.ts +0 -0
- package/client/index.ts +0 -0
- package/client/pages/lib/select2-component.ts +0 -175
- package/client/pages/lib/waether.ts +0 -159
- package/client/pages/project/component/project-update-header.ts +0 -88
- package/client/pages/project/popup/popup-plan-upload.ts +0 -138
- package/client/pages/project/popup/popup-project-create.ts +0 -147
- package/client/pages/project/popup/popup-schedule-upload.ts +0 -102
- package/client/pages/project/project-completed-list.ts +0 -281
- package/client/pages/project/project-detail.ts +0 -738
- package/client/pages/project/project-list.ts +0 -418
- package/client/pages/project/project-plan-management.ts +0 -476
- package/client/pages/project/project-schedule-list.ts +0 -294
- package/client/pages/project/project-schedule.ts +0 -393
- package/client/pages/project/project-setting-list.ts +0 -393
- package/client/pages/project/project-update.ts +0 -876
- package/client/pages/resource/construction-detail-type-popup.ts +0 -201
- package/client/pages/resource/construction-type-management.ts +0 -212
- package/client/pages/resource/inspection-drawing-type-management.ts +0 -245
- package/client/pages/resource/inspection-part-popup.ts +0 -201
- package/client/pages/resource/resource-importer.ts +0 -97
- package/client/pages/resource/resource-list-page.ts +0 -356
- package/client/pages/resource/worker-type-management.ts +0 -192
- package/client/pages/task/task-importer.ts +0 -94
- package/client/pages/task/task-list-page.ts +0 -340
- package/client/pages/task-resource/task-resource-importer.ts +0 -97
- package/client/pages/task-resource/task-resource-list-page.ts +0 -356
- package/client/route.ts +0 -55
- package/client/tsconfig.json +0 -11
- package/server/controllers/export-tasks.ts +0 -40
- package/server/controllers/import-task.ts +0 -134
- package/server/controllers/index.ts +0 -0
- package/server/controllers/parse-excel.ts +0 -86
- package/server/controllers/types.ts +0 -20
- package/server/index.ts +0 -4
- package/server/middlewares/index.ts +0 -3
- package/server/migrations/1723861466413-seed-roles.ts +0 -128
- package/server/migrations/1723861466414-seed-codes.ts +0 -157
- package/server/migrations/1723861476419-seed-resources.ts +0 -62
- package/server/migrations/1723861478420-seed-/bsample-project.ts +0 -87
- package/server/migrations/1723861478421-seed-/bsample-tasks.ts +0 -194
- package/server/migrations/index.ts +0 -9
- package/server/routes.ts +0 -108
- package/server/service/construction-detail-type/construction-detail-type-mutation.ts +0 -57
- package/server/service/construction-detail-type/construction-detail-type-query.ts +0 -31
- package/server/service/construction-detail-type/construction-detail-type-type.ts +0 -26
- package/server/service/construction-detail-type/construction-detail-type.ts +0 -52
- package/server/service/construction-detail-type/index.ts +0 -6
- package/server/service/construction-type/construction-type-mutation.ts +0 -66
- package/server/service/construction-type/construction-type-query.ts +0 -56
- package/server/service/construction-type/construction-type-type.ts +0 -26
- package/server/service/construction-type/construction-type.ts +0 -74
- package/server/service/construction-type/index.ts +0 -6
- package/server/service/index.ts +0 -56
- package/server/service/inspection-drawing-type/index.ts +0 -6
- package/server/service/inspection-drawing-type/inspection-drawing-type-mutation.ts +0 -69
- package/server/service/inspection-drawing-type/inspection-drawing-type-query.ts +0 -55
- package/server/service/inspection-drawing-type/inspection-drawing-type-type.ts +0 -23
- package/server/service/inspection-drawing-type/inspection-drawing-type.ts +0 -68
- package/server/service/inspection-part/index.ts +0 -6
- package/server/service/inspection-part/inspection-part-mutation.ts +0 -52
- package/server/service/inspection-part/inspection-part-query.ts +0 -41
- package/server/service/inspection-part/inspection-part-type.ts +0 -26
- package/server/service/inspection-part/inspection-part.ts +0 -51
- package/server/service/manager/index.ts +0 -6
- package/server/service/manager/manager-mutation.ts +0 -42
- package/server/service/manager/manager-query.ts +0 -28
- package/server/service/manager/manager-type.ts +0 -40
- package/server/service/manager/manager.ts +0 -29
- package/server/service/project/index.ts +0 -6
- package/server/service/project/project-mutation.ts +0 -255
- package/server/service/project/project-query.ts +0 -105
- package/server/service/project/project-type.ts +0 -72
- package/server/service/project/project.ts +0 -134
- package/server/service/resource/index.ts +0 -7
- package/server/service/resource/resource-mutation.ts +0 -137
- package/server/service/resource/resource-query.ts +0 -50
- package/server/service/resource/resource-type.ts +0 -41
- package/server/service/resource/resource.ts +0 -82
- package/server/service/task/index.ts +0 -6
- package/server/service/task/task-mutation.ts +0 -135
- package/server/service/task/task-query.ts +0 -169
- package/server/service/task/task-type.ts +0 -75
- package/server/service/task/task.ts +0 -130
- package/server/service/task-resource/index.ts +0 -7
- package/server/service/task-resource/task-resource-mutation.ts +0 -140
- package/server/service/task-resource/task-resource-query.ts +0 -36
- package/server/service/task-resource/task-resource-type.ts +0 -41
- package/server/service/task-resource/task-resource.ts +0 -51
- package/server/service/worker-type/index.ts +0 -6
- package/server/service/worker-type/worker-type-mutation.ts +0 -66
- package/server/service/worker-type/worker-type-query.ts +0 -47
- package/server/service/worker-type/worker-type-type.ts +0 -26
- package/server/service/worker-type/worker-type.ts +0 -68
- 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 = []
|