@dssp/project 0.0.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/CHANGELOG.md +8 -0
- package/assets/images/hatiolab-logo.png +0 -0
- package/assets/images/o-mark.png +0 -0
- package/assets/images/x-mark.png +0 -0
- package/client/bootstrap.ts +0 -0
- package/client/index.ts +0 -0
- package/client/pages/checklist/checklist-importer.ts +96 -0
- package/client/pages/checklist/checklist-list-page.ts +355 -0
- package/client/pages/lib/waether.ts +159 -0
- package/client/pages/project/ox-progress-circle.ts +133 -0
- package/client/pages/project/project-create-popup.ts +148 -0
- package/client/pages/project/project-detail.ts +618 -0
- package/client/pages/project/project-list.ts +354 -0
- package/client/pages/project/project-plan-management.ts +437 -0
- package/client/pages/project/project-schedule-list.ts +280 -0
- package/client/pages/project/project-schedule.ts +248 -0
- package/client/pages/project/project-setting-list.ts +298 -0
- package/client/pages/project/project-update.ts +797 -0
- package/client/pages/resource/resource-importer.ts +96 -0
- package/client/pages/resource/resource-list-page.ts +355 -0
- package/client/pages/task/task-importer.ts +96 -0
- package/client/pages/task/task-list-page.ts +355 -0
- package/client/route.ts +39 -0
- package/client/tsconfig.json +11 -0
- package/dist-client/bootstrap.d.ts +0 -0
- package/dist-client/bootstrap.js +2 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/index.d.ts +0 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/checklist/checklist-importer.d.ts +9 -0
- package/dist-client/pages/checklist/checklist-importer.js +100 -0
- package/dist-client/pages/checklist/checklist-importer.js.map +1 -0
- package/dist-client/pages/checklist/checklist-list-page.d.ts +62 -0
- package/dist-client/pages/checklist/checklist-list-page.js +331 -0
- package/dist-client/pages/checklist/checklist-list-page.js.map +1 -0
- package/dist-client/pages/lib/waether.d.ts +6 -0
- package/dist-client/pages/lib/waether.js +152 -0
- package/dist-client/pages/lib/waether.js.map +1 -0
- package/dist-client/pages/project/ox-progress-circle.d.ts +41 -0
- package/dist-client/pages/project/ox-progress-circle.js +182 -0
- package/dist-client/pages/project/ox-progress-circle.js.map +1 -0
- package/dist-client/pages/project/project-create-popup.d.ts +14 -0
- package/dist-client/pages/project/project-create-popup.js +153 -0
- package/dist-client/pages/project/project-create-popup.js.map +1 -0
- package/dist-client/pages/project/project-detail.d.ts +35 -0
- package/dist-client/pages/project/project-detail.js +617 -0
- package/dist-client/pages/project/project-detail.js.map +1 -0
- package/dist-client/pages/project/project-list.d.ts +88 -0
- package/dist-client/pages/project/project-list.js +303 -0
- package/dist-client/pages/project/project-list.js.map +1 -0
- package/dist-client/pages/project/project-plan-management.d.ts +27 -0
- package/dist-client/pages/project/project-plan-management.js +438 -0
- package/dist-client/pages/project/project-plan-management.js.map +1 -0
- package/dist-client/pages/project/project-schedule-list.d.ts +18 -0
- package/dist-client/pages/project/project-schedule-list.js +292 -0
- package/dist-client/pages/project/project-schedule-list.js.map +1 -0
- package/dist-client/pages/project/project-schedule.d.ts +23 -0
- package/dist-client/pages/project/project-schedule.js +256 -0
- package/dist-client/pages/project/project-schedule.js.map +1 -0
- package/dist-client/pages/project/project-setting-list.d.ts +23 -0
- package/dist-client/pages/project/project-setting-list.js +307 -0
- package/dist-client/pages/project/project-setting-list.js.map +1 -0
- package/dist-client/pages/project/project-update.d.ts +24 -0
- package/dist-client/pages/project/project-update.js +797 -0
- package/dist-client/pages/project/project-update.js.map +1 -0
- package/dist-client/pages/resource/resource-importer.d.ts +9 -0
- package/dist-client/pages/resource/resource-importer.js +100 -0
- package/dist-client/pages/resource/resource-importer.js.map +1 -0
- package/dist-client/pages/resource/resource-list-page.d.ts +62 -0
- package/dist-client/pages/resource/resource-list-page.js +331 -0
- package/dist-client/pages/resource/resource-list-page.js.map +1 -0
- package/dist-client/pages/task/task-importer.d.ts +9 -0
- package/dist-client/pages/task/task-importer.js +100 -0
- package/dist-client/pages/task/task-importer.js.map +1 -0
- package/dist-client/pages/task/task-list-page.d.ts +62 -0
- package/dist-client/pages/task/task-list-page.js +331 -0
- package/dist-client/pages/task/task-list-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +32 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/controllers/index.js +1 -0
- package/dist-server/controllers/index.js.map +1 -0
- package/dist-server/controllers/project-to-excel.js +30 -0
- package/dist-server/controllers/project-to-excel.js.map +1 -0
- package/dist-server/index.js +6 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/middlewares/index.js +8 -0
- package/dist-server/middlewares/index.js.map +1 -0
- package/dist-server/routes.js +105 -0
- package/dist-server/routes.js.map +1 -0
- package/dist-server/service/check-item/check-item-mutation.js +129 -0
- package/dist-server/service/check-item/check-item-mutation.js.map +1 -0
- package/dist-server/service/check-item/check-item-query.js +86 -0
- package/dist-server/service/check-item/check-item-query.js.map +1 -0
- package/dist-server/service/check-item/check-item-type.js +69 -0
- package/dist-server/service/check-item/check-item-type.js.map +1 -0
- package/dist-server/service/check-item/check-item.js +84 -0
- package/dist-server/service/check-item/check-item.js.map +1 -0
- package/dist-server/service/check-item/index.js +9 -0
- package/dist-server/service/check-item/index.js.map +1 -0
- package/dist-server/service/checklist/checklist-mutation.js +129 -0
- package/dist-server/service/checklist/checklist-mutation.js.map +1 -0
- package/dist-server/service/checklist/checklist-query.js +86 -0
- package/dist-server/service/checklist/checklist-query.js.map +1 -0
- package/dist-server/service/checklist/checklist-type.js +69 -0
- package/dist-server/service/checklist/checklist-type.js.map +1 -0
- package/dist-server/service/checklist/checklist.js +120 -0
- package/dist-server/service/checklist/checklist.js.map +1 -0
- package/dist-server/service/checklist/index.js +9 -0
- package/dist-server/service/checklist/index.js.map +1 -0
- package/dist-server/service/index.js +36 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/project/index.js +11 -0
- package/dist-server/service/project/index.js.map +1 -0
- package/dist-server/service/project/project-mutation.js +190 -0
- package/dist-server/service/project/project-mutation.js.map +1 -0
- package/dist-server/service/project/project-query.js +143 -0
- package/dist-server/service/project/project-query.js.map +1 -0
- package/dist-server/service/project/project-type.js +106 -0
- package/dist-server/service/project/project-type.js.map +1 -0
- package/dist-server/service/project/project.js +146 -0
- package/dist-server/service/project/project.js.map +1 -0
- package/dist-server/service/resource/index.js +9 -0
- package/dist-server/service/resource/index.js.map +1 -0
- package/dist-server/service/resource/resource-mutation.js +129 -0
- package/dist-server/service/resource/resource-mutation.js.map +1 -0
- package/dist-server/service/resource/resource-query.js +86 -0
- package/dist-server/service/resource/resource-query.js.map +1 -0
- package/dist-server/service/resource/resource-type.js +69 -0
- package/dist-server/service/resource/resource-type.js.map +1 -0
- package/dist-server/service/resource/resource.js +62 -0
- package/dist-server/service/resource/resource.js.map +1 -0
- package/dist-server/service/task/index.js +9 -0
- package/dist-server/service/task/index.js.map +1 -0
- package/dist-server/service/task/task-mutation.js +129 -0
- package/dist-server/service/task/task-mutation.js.map +1 -0
- package/dist-server/service/task/task-query.js +86 -0
- package/dist-server/service/task/task-query.js.map +1 -0
- package/dist-server/service/task/task-type.js +69 -0
- package/dist-server/service/task/task-type.js.map +1 -0
- package/dist-server/service/task/task.js +106 -0
- package/dist-server/service/task/task.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/helps/management/alarm.md +160 -0
- package/helps/management/alter-video.md +160 -0
- package/helps/management/cctv.md +160 -0
- package/helps/management/device.md +160 -0
- package/helps/management/parking.md +160 -0
- package/helps/management/site.md +160 -0
- package/helps/management/sun-pnl.md +160 -0
- package/helps/project/checklist.md +160 -0
- package/helps/project/project.md +160 -0
- package/helps/project/resource.md +160 -0
- package/helps/project/task.md +160 -0
- package/package.json +38 -0
- package/server/controllers/index.ts +0 -0
- package/server/controllers/project-to-excel.ts +40 -0
- package/server/index.ts +3 -0
- package/server/middlewares/index.ts +3 -0
- package/server/routes.ts +108 -0
- package/server/service/check-item/check-item-mutation.ts +142 -0
- package/server/service/check-item/check-item-query.ts +56 -0
- package/server/service/check-item/check-item-type.ts +49 -0
- package/server/service/check-item/check-item.ts +74 -0
- package/server/service/check-item/index.ts +6 -0
- package/server/service/checklist/checklist-mutation.ts +142 -0
- package/server/service/checklist/checklist-query.ts +56 -0
- package/server/service/checklist/checklist-type.ts +49 -0
- package/server/service/checklist/checklist.ts +105 -0
- package/server/service/checklist/index.ts +6 -0
- package/server/service/index.ts +35 -0
- package/server/service/project/index.ts +8 -0
- package/server/service/project/project-mutation.ts +201 -0
- package/server/service/project/project-query.ts +103 -0
- package/server/service/project/project-type.ts +71 -0
- package/server/service/project/project.ts +131 -0
- package/server/service/resource/index.ts +6 -0
- package/server/service/resource/resource-mutation.ts +139 -0
- package/server/service/resource/resource-query.ts +56 -0
- package/server/service/resource/resource-type.ts +49 -0
- package/server/service/resource/resource.ts +56 -0
- package/server/service/task/index.ts +6 -0
- package/server/service/task/task-mutation.ts +136 -0
- package/server/service/task/task-query.ts +56 -0
- package/server/service/task/task-type.ts +49 -0
- package/server/service/task/task.ts +97 -0
- package/server/tsconfig.json +10 -0
- package/things-factory.config.js +20 -0
- package/translations/en.json +1 -0
- package/translations/ja.json +1 -0
- package/translations/ko.json +9 -0
- package/translations/ms.json +1 -0
- package/translations/zh.json +1 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* EXPORT ENTITY TYPES */
|
|
2
|
+
export * from './resource/resource'
|
|
3
|
+
export * from './check-item/check-item'
|
|
4
|
+
export * from './checklist/checklist'
|
|
5
|
+
export * from './task/task'
|
|
6
|
+
export * from './project/project'
|
|
7
|
+
|
|
8
|
+
/* IMPORT ENTITIES AND RESOLVERS */
|
|
9
|
+
import { entities as ResourceEntities, resolvers as ResourceResolvers } from './resource'
|
|
10
|
+
import { entities as CheckItemEntities, resolvers as CheckItemResolvers } from './check-item'
|
|
11
|
+
import { entities as ChecklistEntities, resolvers as ChecklistResolvers } from './checklist'
|
|
12
|
+
import { entities as TaskEntities, resolvers as TaskResolvers } from './task'
|
|
13
|
+
import { entities as ProjectEntities, resolvers as ProjectResolvers, types as ProjectTypes } from './project'
|
|
14
|
+
|
|
15
|
+
export const entities = [
|
|
16
|
+
/* ENTITIES */
|
|
17
|
+
...ResourceEntities,
|
|
18
|
+
...CheckItemEntities,
|
|
19
|
+
...ChecklistEntities,
|
|
20
|
+
...TaskEntities,
|
|
21
|
+
...ProjectEntities
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
export const schema = {
|
|
25
|
+
resolverClasses: [
|
|
26
|
+
/* RESOLVER CLASSES */
|
|
27
|
+
...ResourceResolvers,
|
|
28
|
+
...CheckItemResolvers,
|
|
29
|
+
...ChecklistResolvers,
|
|
30
|
+
...TaskResolvers,
|
|
31
|
+
...ProjectResolvers
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const types = [...ProjectTypes]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Project } from './project'
|
|
2
|
+
import { ProjectQuery } from './project-query'
|
|
3
|
+
import { ProjectMutation } from './project-mutation'
|
|
4
|
+
import { InspectionSummary } from './project-type'
|
|
5
|
+
|
|
6
|
+
export const entities = [Project]
|
|
7
|
+
export const resolvers = [ProjectQuery, ProjectMutation]
|
|
8
|
+
export const types = [InspectionSummary]
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Resolver, Mutation, Arg, Args, Ctx, Directive } from 'type-graphql'
|
|
2
|
+
import { In, Not } from 'typeorm'
|
|
3
|
+
|
|
4
|
+
import { createAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'
|
|
5
|
+
|
|
6
|
+
import { Project } from './project'
|
|
7
|
+
import { NewProject, ProjectPatch } from './project-type'
|
|
8
|
+
import { BuildingComplex, Building, BuildingLevel } from '@dssp/building-complex'
|
|
9
|
+
|
|
10
|
+
@Resolver(Project)
|
|
11
|
+
export class ProjectMutation {
|
|
12
|
+
@Directive('@transaction')
|
|
13
|
+
@Mutation(returns => Project, { description: '프로젝트 생성' })
|
|
14
|
+
async createProject(@Arg('project') project: NewProject, @Ctx() context: ResolverContext): Promise<Project> {
|
|
15
|
+
const { domain, user, tx } = context.state
|
|
16
|
+
const projectRepo = tx.getRepository(Project)
|
|
17
|
+
const buildingComplexRepo = tx.getRepository(BuildingComplex)
|
|
18
|
+
|
|
19
|
+
const newBuildingComplex = await buildingComplexRepo.save({
|
|
20
|
+
domain,
|
|
21
|
+
creator: user,
|
|
22
|
+
updater: user
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const result = await projectRepo.save({
|
|
26
|
+
name: project.name,
|
|
27
|
+
buildingComplex: newBuildingComplex,
|
|
28
|
+
domain,
|
|
29
|
+
creator: user,
|
|
30
|
+
updater: user
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
return result
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Directive('@transaction')
|
|
37
|
+
@Mutation(returns => Project, { description: '프로젝트 업데이트' })
|
|
38
|
+
async updateProject(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {
|
|
39
|
+
const { user, tx } = context.state
|
|
40
|
+
const projectRepo = tx.getRepository(Project)
|
|
41
|
+
const buildingComplexRepo = tx.getRepository(BuildingComplex)
|
|
42
|
+
const buildingRepo = tx.getRepository(Building)
|
|
43
|
+
const buildingLevelRepo = tx.getRepository(BuildingLevel)
|
|
44
|
+
|
|
45
|
+
const buildingComplex = project.buildingComplex
|
|
46
|
+
const buildings = project.buildingComplex?.buildings || []
|
|
47
|
+
|
|
48
|
+
// 1. 프로젝트 수정
|
|
49
|
+
const projectResult = await projectRepo.save({ ...project, updater: user })
|
|
50
|
+
|
|
51
|
+
// 2. 단지 정보 수정
|
|
52
|
+
await buildingComplexRepo.save({ ...buildingComplex, updater: user })
|
|
53
|
+
|
|
54
|
+
// 2-1. 프로젝트 메인 이미지 첨부파일 나머지 삭제 후 저장 (null로 오면 삭제만)
|
|
55
|
+
if (project.mainPhotoUpload !== undefined) {
|
|
56
|
+
await deleteAttachmentsByRef(null, { refBys: [project.id] }, context)
|
|
57
|
+
|
|
58
|
+
if (project.mainPhotoUpload) {
|
|
59
|
+
await createAttachment(
|
|
60
|
+
null,
|
|
61
|
+
{
|
|
62
|
+
attachment: {
|
|
63
|
+
file: project.mainPhotoUpload,
|
|
64
|
+
refType: Project.name,
|
|
65
|
+
refBy: project.id
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
context
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 2-2. 단지 BIM 이미지 첨부파일 나머지 삭제 후 저장 (null로 오면 삭제만)
|
|
74
|
+
if (buildingComplex.drawingUpload !== undefined) {
|
|
75
|
+
await deleteAttachmentsByRef(null, { refBys: [buildingComplex.id] }, context)
|
|
76
|
+
|
|
77
|
+
if (buildingComplex.drawingUpload) {
|
|
78
|
+
await createAttachment(
|
|
79
|
+
null,
|
|
80
|
+
{
|
|
81
|
+
attachment: {
|
|
82
|
+
file: buildingComplex.drawingUpload,
|
|
83
|
+
refType: BuildingComplex.name,
|
|
84
|
+
refBy: buildingComplex.id
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
context
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 3. 동의 층 정보가 바뀌었으면 층 초기화 후 다시 생성
|
|
93
|
+
const originBuilding = await buildingRepo.findBy({ buildingComplex: { id: buildingComplex.id } }) // 이전 동 정보 가져오기
|
|
94
|
+
const afterBuilding = buildings.reduce((acc, building) => ({ ...acc, [building.name]: building.floorCount }), {}) // 비교용으로 수정된 동 정보 데이터 파싱
|
|
95
|
+
const isBuidlingChanged = originBuilding.some(building => afterBuilding[building.name] !== building.floorCount) // 층 개수가 달라진 동이 있는지 확인
|
|
96
|
+
|
|
97
|
+
// 동의 층 개수가 달라지면 모든 층의 데이터 제거 후 생성
|
|
98
|
+
if (isBuidlingChanged || originBuilding.length !== buildings.length) {
|
|
99
|
+
// 3-1. 기존 동/층 첨부파일 및 데이터 제거
|
|
100
|
+
const buildingIds = originBuilding.map((building: Building) => building.id)
|
|
101
|
+
const buildingLevels = await buildingLevelRepo.findBy({ building: { id: In(buildingIds) } })
|
|
102
|
+
const buildingLevelIds = buildingLevels.map((buildingLevel: BuildingLevel) => buildingLevel.id)
|
|
103
|
+
|
|
104
|
+
await buildingLevelRepo.softDelete({ building: { id: In(buildingIds) } })
|
|
105
|
+
await buildingRepo.softDelete({ id: In(buildingIds) })
|
|
106
|
+
await deleteAttachmentsByRef(null, { refBys: [...buildingIds, ...buildingLevelIds] }, context)
|
|
107
|
+
|
|
108
|
+
buildings.forEach(async (building: Building) => {
|
|
109
|
+
// 3-2. 단지 내 동 정보들 생성
|
|
110
|
+
const newBuilding = await buildingRepo.save({
|
|
111
|
+
buildingComplex: buildingComplex,
|
|
112
|
+
name: building.name,
|
|
113
|
+
floorCount: building.floorCount,
|
|
114
|
+
creator: user
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// 3-3. 동별로 for문 돌면서 층 데이터 개수대로 생성
|
|
118
|
+
for (let i = 1; i <= building.floorCount; i++) {
|
|
119
|
+
await buildingLevelRepo.save({ building: newBuilding, floor: i, creator: user })
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return projectResult
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@Directive('@transaction')
|
|
128
|
+
@Mutation(returns => Project, { description: '프로젝트 도면 업데이트' })
|
|
129
|
+
async updateProjectPlan(@Arg('project') project: ProjectPatch, @Ctx() context: ResolverContext): Promise<Project> {
|
|
130
|
+
const { user, tx } = context.state
|
|
131
|
+
const projectRepo = tx.getRepository(Project)
|
|
132
|
+
const buildingComplexRepo = tx.getRepository(BuildingComplex)
|
|
133
|
+
const buildingComplex = project.buildingComplex
|
|
134
|
+
const buildings: Building[] = project.buildingComplex?.buildings || []
|
|
135
|
+
|
|
136
|
+
// 1. 프로젝트 수정 시간 업데이트
|
|
137
|
+
const projectResult = await projectRepo.save({ ...project, updater: user })
|
|
138
|
+
|
|
139
|
+
// 2. 단지 축척 정보 수정
|
|
140
|
+
await buildingComplexRepo.save({ ...buildingComplex, updater: user })
|
|
141
|
+
|
|
142
|
+
for (let buildingKey in buildings) {
|
|
143
|
+
const building = buildings[buildingKey]
|
|
144
|
+
|
|
145
|
+
for (let buildingLevelKey in building.buildingLevels) {
|
|
146
|
+
const buildingLevel = building.buildingLevels[buildingLevelKey]
|
|
147
|
+
|
|
148
|
+
// 3. 층별 도면 이미지 저장 (null로 오면 삭제만)
|
|
149
|
+
if (buildingLevel?.mainDrawingUpload !== undefined) {
|
|
150
|
+
await deleteAttachmentsByRef(null, { refBys: [buildingLevel.id] }, context)
|
|
151
|
+
|
|
152
|
+
if (buildingLevel?.mainDrawingUpload) {
|
|
153
|
+
await createAttachment(
|
|
154
|
+
null,
|
|
155
|
+
{
|
|
156
|
+
attachment: {
|
|
157
|
+
file: buildingLevel.mainDrawingUpload,
|
|
158
|
+
refType: BuildingLevel.name,
|
|
159
|
+
refBy: buildingLevel.id
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
context
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 4. 동별 도면 이미지 저장 (null로 오면 삭제만)
|
|
169
|
+
if (building?.drawingUpload !== undefined) {
|
|
170
|
+
await deleteAttachmentsByRef(null, { refBys: [building.id] }, context)
|
|
171
|
+
|
|
172
|
+
if (building?.drawingUpload) {
|
|
173
|
+
await createAttachment(
|
|
174
|
+
null,
|
|
175
|
+
{
|
|
176
|
+
attachment: {
|
|
177
|
+
file: building.drawingUpload,
|
|
178
|
+
refType: Building.name,
|
|
179
|
+
refBy: building.id
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
context
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return projectResult
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@Directive('@transaction')
|
|
192
|
+
@Mutation(returns => Boolean, { description: 'To delete Project' })
|
|
193
|
+
async deleteProject(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
194
|
+
const { domain, tx } = context.state
|
|
195
|
+
|
|
196
|
+
await tx.getRepository(Project).delete({ domain: { id: domain.id }, id })
|
|
197
|
+
await deleteAttachmentsByRef(null, { refBys: [id] }, context)
|
|
198
|
+
|
|
199
|
+
return true
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Resolver, Query, FieldResolver, Root, Arg, Ctx } from 'type-graphql'
|
|
2
|
+
import { Domain, getRepository } from '@things-factory/shell'
|
|
3
|
+
import { User } from '@things-factory/auth-base'
|
|
4
|
+
import { Project } from './project'
|
|
5
|
+
import { InspectionSummary, ProjectList } from './project-type'
|
|
6
|
+
import { BuildingComplex, InspectionType } from '@dssp/building-complex'
|
|
7
|
+
import { Attachment } from '@things-factory/attachment-base'
|
|
8
|
+
|
|
9
|
+
@Resolver(Project)
|
|
10
|
+
export class ProjectQuery {
|
|
11
|
+
@Query(returns => Project!, { nullable: true, description: 'To fetch a Project' })
|
|
12
|
+
async project(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Project> {
|
|
13
|
+
const { domain } = context.state
|
|
14
|
+
|
|
15
|
+
return await getRepository(Project).findOne({
|
|
16
|
+
where: { domain: { id: domain.id }, id }
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Query(returns => ProjectList, { description: '프로젝트 리스트' })
|
|
21
|
+
async projects(@Arg('projectName') projectName: string, @Ctx() context: ResolverContext): Promise<ProjectList> {
|
|
22
|
+
const { domain } = context.state
|
|
23
|
+
// const { page = 1, limit = 0 } = params.pagination || {}
|
|
24
|
+
|
|
25
|
+
const queryBuilder = await getRepository(Project)
|
|
26
|
+
.createQueryBuilder('p')
|
|
27
|
+
.innerJoinAndSelect('p.buildingComplex', 'bc')
|
|
28
|
+
.where('p.domain = :domain', { domain: domain.id })
|
|
29
|
+
.orderBy('p.created_at', 'DESC')
|
|
30
|
+
// .offset((page - 1) * limit)
|
|
31
|
+
// .limit(limit)
|
|
32
|
+
|
|
33
|
+
if (projectName) {
|
|
34
|
+
projectName = `%${projectName}%`
|
|
35
|
+
queryBuilder.andWhere('p.name LIKE :projectName', { projectName })
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [items, total] = await queryBuilder.getManyAndCount()
|
|
39
|
+
|
|
40
|
+
return { items, total }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Query(returns => InspectionSummary, { description: '프로젝트의 검측상태 별 카운트' })
|
|
44
|
+
async inspectionSummary(
|
|
45
|
+
@Arg('projectId') projectId: string,
|
|
46
|
+
@Ctx() context: ResolverContext
|
|
47
|
+
): Promise<InspectionSummary> {
|
|
48
|
+
const { domain } = context.state
|
|
49
|
+
|
|
50
|
+
const queryBuilder = getRepository(Project)
|
|
51
|
+
.createQueryBuilder('p')
|
|
52
|
+
.select(`COUNT(CASE WHEN bi.type="${InspectionType.REQUEST}" THEN 1 ELSE NULL END) AS request`)
|
|
53
|
+
.addSelect(`COUNT(CASE WHEN bi.type="${InspectionType.PASS}" THEN 1 ELSE NULL END) AS pass`)
|
|
54
|
+
.addSelect(`COUNT(CASE WHEN bi.type="${InspectionType.FAIL}" THEN 1 ELSE NULL END) AS fail`)
|
|
55
|
+
.innerJoin('p.buildingComplex', 'bc')
|
|
56
|
+
.innerJoin('bc.buildings', 'b')
|
|
57
|
+
.innerJoin('b.buildingLevels', 'bl')
|
|
58
|
+
.innerJoin('bl.buildingInspections', 'bi')
|
|
59
|
+
.where('p.domain = :domain', { domain: domain.id })
|
|
60
|
+
.andWhere('p.id = :projectId', { projectId })
|
|
61
|
+
.groupBy('p.id')
|
|
62
|
+
|
|
63
|
+
const result = (await queryBuilder.getRawOne()) || {}
|
|
64
|
+
return {
|
|
65
|
+
request: result.request || 0,
|
|
66
|
+
pass: result.pass || 0,
|
|
67
|
+
fail: result.fail || 0
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@FieldResolver(type => Attachment)
|
|
72
|
+
async mainPhoto(@Root() project: Project): Promise<string | Attachment> {
|
|
73
|
+
const attachment: Attachment = await getRepository(Attachment).findOne({
|
|
74
|
+
where: {
|
|
75
|
+
domain: { id: project.domainId },
|
|
76
|
+
refBy: project.id
|
|
77
|
+
},
|
|
78
|
+
order: { createdAt: 'ASC' }
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
return attachment
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@FieldResolver(type => BuildingComplex)
|
|
85
|
+
async buildingComplex(@Root() project: Project): Promise<BuildingComplex> {
|
|
86
|
+
return await getRepository(BuildingComplex).findOneBy({ id: project.buildingComplexId })
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@FieldResolver(type => Domain)
|
|
90
|
+
async domain(@Root() project: Project): Promise<Domain> {
|
|
91
|
+
return await getRepository(Domain).findOneBy({ id: project.domainId })
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@FieldResolver(type => User)
|
|
95
|
+
async updater(@Root() project: Project): Promise<User> {
|
|
96
|
+
return await getRepository(User).findOneBy({ id: project.updaterId })
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@FieldResolver(type => User)
|
|
100
|
+
async creator(@Root() project: Project): Promise<User> {
|
|
101
|
+
return await getRepository(User).findOneBy({ id: project.creatorId })
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ObjectType, Field, InputType, Int, Float } from 'type-graphql'
|
|
2
|
+
import { Project } from './project'
|
|
3
|
+
import { BuildingComplexPatch } from '@dssp/building-complex'
|
|
4
|
+
import type { FileUpload } from 'graphql-upload/GraphQLUpload.js'
|
|
5
|
+
import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'
|
|
6
|
+
|
|
7
|
+
@InputType()
|
|
8
|
+
export class NewProject {
|
|
9
|
+
@Field({ nullable: false })
|
|
10
|
+
name: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@InputType()
|
|
14
|
+
export class ProjectPatch {
|
|
15
|
+
@Field({ nullable: false })
|
|
16
|
+
id: string
|
|
17
|
+
|
|
18
|
+
@Field({ nullable: false })
|
|
19
|
+
name: string
|
|
20
|
+
|
|
21
|
+
@Field({ nullable: true })
|
|
22
|
+
startDate?: string
|
|
23
|
+
|
|
24
|
+
@Field({ nullable: true })
|
|
25
|
+
endDate?: string
|
|
26
|
+
|
|
27
|
+
@Field(type => GraphQLUpload, { nullable: true })
|
|
28
|
+
mainPhotoUpload?: FileUpload
|
|
29
|
+
|
|
30
|
+
@Field(type => Float, { nullable: true })
|
|
31
|
+
totalProgress?: number
|
|
32
|
+
|
|
33
|
+
@Field(type => Float, { nullable: true })
|
|
34
|
+
weeklyProgress?: number
|
|
35
|
+
|
|
36
|
+
@Field(type => Float, { nullable: true })
|
|
37
|
+
kpi?: number
|
|
38
|
+
|
|
39
|
+
@Field(type => Float, { nullable: true })
|
|
40
|
+
inspPassRate?: number
|
|
41
|
+
|
|
42
|
+
@Field(type => Float, { nullable: true })
|
|
43
|
+
robotProgressRate?: number
|
|
44
|
+
|
|
45
|
+
@Field(type => Float, { nullable: true })
|
|
46
|
+
structuralSafetyRate?: number
|
|
47
|
+
|
|
48
|
+
@Field({ nullable: true })
|
|
49
|
+
buildingComplex?: BuildingComplexPatch
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@ObjectType()
|
|
53
|
+
export class ProjectList {
|
|
54
|
+
@Field(type => [Project])
|
|
55
|
+
items: Project[]
|
|
56
|
+
|
|
57
|
+
@Field(type => Int)
|
|
58
|
+
total: number
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@ObjectType()
|
|
62
|
+
export class InspectionSummary {
|
|
63
|
+
@Field(type => Int)
|
|
64
|
+
request: number
|
|
65
|
+
|
|
66
|
+
@Field(type => Int)
|
|
67
|
+
pass: number
|
|
68
|
+
|
|
69
|
+
@Field(type => Int)
|
|
70
|
+
fail: number
|
|
71
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
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, registerEnumType } 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 ProjectStatus {
|
|
24
|
+
'PROCEEDING' = '10',
|
|
25
|
+
'COMPLICATED' = '20'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
registerEnumType(ProjectStatus, {
|
|
29
|
+
name: 'ProjectStatus',
|
|
30
|
+
description: '프로젝트 상태'
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
@Entity()
|
|
34
|
+
@Index('ix_project_0', (project: Project) => [project.buildingComplex], { unique: true, where: '"deleted_at" IS NULL' })
|
|
35
|
+
@ObjectType({ description: '프로젝트' })
|
|
36
|
+
export class Project {
|
|
37
|
+
@PrimaryGeneratedColumn('uuid')
|
|
38
|
+
@Field(type => ID)
|
|
39
|
+
readonly id: string
|
|
40
|
+
|
|
41
|
+
@ManyToOne(type => Domain)
|
|
42
|
+
@Field({ nullable: true })
|
|
43
|
+
domain?: Domain
|
|
44
|
+
|
|
45
|
+
@RelationId((project: Project) => project.domain)
|
|
46
|
+
domainId?: string
|
|
47
|
+
|
|
48
|
+
@Column({ nullable: false, comment: '프로젝트 이름' })
|
|
49
|
+
@Field({ nullable: false })
|
|
50
|
+
name?: string
|
|
51
|
+
|
|
52
|
+
@Column({ nullable: false, default: ProjectStatus.PROCEEDING, comment: '프로젝트 상태 (10: 진행중, 20: 완료)' })
|
|
53
|
+
@Field({ nullable: false })
|
|
54
|
+
state?: ProjectStatus
|
|
55
|
+
|
|
56
|
+
@Column({ type: 'date', nullable: true, comment: '착공일정' })
|
|
57
|
+
@Field({ nullable: true })
|
|
58
|
+
startDate?: string
|
|
59
|
+
|
|
60
|
+
@Column({ type: 'date', nullable: true, comment: '준공일정' })
|
|
61
|
+
@Field({ nullable: true })
|
|
62
|
+
endDate?: string
|
|
63
|
+
|
|
64
|
+
// 대표 사진
|
|
65
|
+
@Field(type => Attachment, { nullable: true })
|
|
66
|
+
mainPhoto?: Attachment
|
|
67
|
+
|
|
68
|
+
@Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '전체 진행현황' })
|
|
69
|
+
@Field({ nullable: true })
|
|
70
|
+
totalProgress?: number
|
|
71
|
+
|
|
72
|
+
@Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '주간 진행현황' })
|
|
73
|
+
@Field({ nullable: true })
|
|
74
|
+
weeklyProgress?: number
|
|
75
|
+
|
|
76
|
+
@Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: 'KPI' })
|
|
77
|
+
@Field({ nullable: true })
|
|
78
|
+
kpi?: number
|
|
79
|
+
|
|
80
|
+
@Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '검측/통과 비율' })
|
|
81
|
+
@Field({ nullable: true })
|
|
82
|
+
inspPassRate?: number
|
|
83
|
+
|
|
84
|
+
@Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '로봇 작업 진행율' })
|
|
85
|
+
@Field({ nullable: true })
|
|
86
|
+
robotProgressRate?: number
|
|
87
|
+
|
|
88
|
+
@Column({ type: 'float', nullable: true, default: 0, transformer: roundTransformer, comment: '구조 안전도' })
|
|
89
|
+
@Field({ nullable: true })
|
|
90
|
+
structuralSafetyRate?: number
|
|
91
|
+
|
|
92
|
+
// 단지 정보 (1:1 테이블 참조)
|
|
93
|
+
@OneToOne(type => BuildingComplex)
|
|
94
|
+
@JoinColumn()
|
|
95
|
+
@Field({ nullable: true })
|
|
96
|
+
buildingComplex?: BuildingComplex
|
|
97
|
+
|
|
98
|
+
@RelationId((project: Project) => project.buildingComplex)
|
|
99
|
+
buildingComplexId?: string
|
|
100
|
+
|
|
101
|
+
// 작업 정보 (하위 테이블 참조)
|
|
102
|
+
@Field(() => [Task], { nullable: true })
|
|
103
|
+
@OneToMany(() => Task, task => task.project)
|
|
104
|
+
tasks?: Task[]
|
|
105
|
+
|
|
106
|
+
@CreateDateColumn()
|
|
107
|
+
@Field({ nullable: true })
|
|
108
|
+
createdAt?: Date
|
|
109
|
+
|
|
110
|
+
@UpdateDateColumn()
|
|
111
|
+
@Field({ nullable: true })
|
|
112
|
+
updatedAt?: Date
|
|
113
|
+
|
|
114
|
+
@DeleteDateColumn()
|
|
115
|
+
@Field({ nullable: true })
|
|
116
|
+
deletedAt?: Date
|
|
117
|
+
|
|
118
|
+
@ManyToOne(type => User, { nullable: true })
|
|
119
|
+
@Field(type => User, { nullable: true })
|
|
120
|
+
creator?: User
|
|
121
|
+
|
|
122
|
+
@RelationId((project: Project) => project.creator)
|
|
123
|
+
creatorId?: string
|
|
124
|
+
|
|
125
|
+
@ManyToOne(type => User, { nullable: true })
|
|
126
|
+
@Field(type => User, { nullable: true })
|
|
127
|
+
updater?: User
|
|
128
|
+
|
|
129
|
+
@RelationId((project: Project) => project.updater)
|
|
130
|
+
updaterId?: string
|
|
131
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
|
|
2
|
+
import { In } from 'typeorm'
|
|
3
|
+
|
|
4
|
+
import { createAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'
|
|
5
|
+
|
|
6
|
+
import { Resource } from './resource'
|
|
7
|
+
import { NewResource, ResourcePatch } from './resource-type'
|
|
8
|
+
|
|
9
|
+
@Resolver(Resource)
|
|
10
|
+
export class ResourceMutation {
|
|
11
|
+
@Directive('@transaction')
|
|
12
|
+
@Mutation(returns => Resource, { description: 'To create new Resource' })
|
|
13
|
+
async createResource(@Arg('resource') resource: NewResource, @Ctx() context: ResolverContext): Promise<Resource> {
|
|
14
|
+
const { domain, user, tx } = context.state
|
|
15
|
+
|
|
16
|
+
const result = await tx.getRepository(Resource).save({
|
|
17
|
+
...resource,
|
|
18
|
+
domain,
|
|
19
|
+
creator: user,
|
|
20
|
+
updater: user
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return result
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Directive('@transaction')
|
|
27
|
+
@Mutation(returns => Resource, { description: 'To modify Resource information' })
|
|
28
|
+
async updateResource(
|
|
29
|
+
@Arg('id') id: string,
|
|
30
|
+
@Arg('patch') patch: ResourcePatch,
|
|
31
|
+
@Ctx() context: ResolverContext
|
|
32
|
+
): Promise<Resource> {
|
|
33
|
+
const { domain, user, tx } = context.state
|
|
34
|
+
|
|
35
|
+
const repository = tx.getRepository(Resource)
|
|
36
|
+
const resource = await repository.findOne({
|
|
37
|
+
where: { id }
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const result = await repository.save({
|
|
41
|
+
...resource,
|
|
42
|
+
...patch,
|
|
43
|
+
updater: user
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return result
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Directive('@transaction')
|
|
50
|
+
@Mutation(returns => [Resource], { description: "To modify multiple Resources' information" })
|
|
51
|
+
async updateMultipleResource(
|
|
52
|
+
@Arg('patches', type => [ResourcePatch]) patches: ResourcePatch[],
|
|
53
|
+
@Ctx() context: ResolverContext
|
|
54
|
+
): Promise<Resource[]> {
|
|
55
|
+
const { domain, user, tx } = context.state
|
|
56
|
+
|
|
57
|
+
let results = []
|
|
58
|
+
const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
|
|
59
|
+
const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
|
|
60
|
+
const resourceRepo = tx.getRepository(Resource)
|
|
61
|
+
|
|
62
|
+
if (_createRecords.length > 0) {
|
|
63
|
+
for (let i = 0; i < _createRecords.length; i++) {
|
|
64
|
+
const newRecord = _createRecords[i]
|
|
65
|
+
|
|
66
|
+
const result = await resourceRepo.save({
|
|
67
|
+
...newRecord,
|
|
68
|
+
domain,
|
|
69
|
+
creator: user,
|
|
70
|
+
updater: user
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
results.push({ ...result, cuFlag: '+' })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (_updateRecords.length > 0) {
|
|
78
|
+
for (let i = 0; i < _updateRecords.length; i++) {
|
|
79
|
+
const updateRecord = _updateRecords[i]
|
|
80
|
+
const resource = await resourceRepo.findOneBy({ id: updateRecord.id })
|
|
81
|
+
|
|
82
|
+
const result = await resourceRepo.save({
|
|
83
|
+
...resource,
|
|
84
|
+
...updateRecord,
|
|
85
|
+
updater: user
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
results.push({ ...result, cuFlag: 'M' })
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return results
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@Directive('@transaction')
|
|
96
|
+
@Mutation(returns => Boolean, { description: 'To delete Resource' })
|
|
97
|
+
async deleteResource(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
98
|
+
const { domain, tx } = context.state
|
|
99
|
+
|
|
100
|
+
await tx.getRepository(Resource).delete({ id })
|
|
101
|
+
await deleteAttachmentsByRef(null, { refBys: [id] }, context)
|
|
102
|
+
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@Directive('@transaction')
|
|
107
|
+
@Mutation(returns => Boolean, { description: 'To delete multiple Resources' })
|
|
108
|
+
async deleteResources(
|
|
109
|
+
@Arg('ids', type => [String]) ids: string[],
|
|
110
|
+
@Ctx() context: ResolverContext
|
|
111
|
+
): Promise<boolean> {
|
|
112
|
+
const { domain, tx } = context.state
|
|
113
|
+
|
|
114
|
+
await tx.getRepository(Resource).delete({
|
|
115
|
+
id: In(ids)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
await deleteAttachmentsByRef(null, { refBys: ids }, context)
|
|
119
|
+
|
|
120
|
+
return true
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@Directive('@transaction')
|
|
124
|
+
@Mutation(returns => Boolean, { description: 'To import multiple Resources' })
|
|
125
|
+
async importResources(
|
|
126
|
+
@Arg('resources', type => [ResourcePatch]) resources: ResourcePatch[],
|
|
127
|
+
@Ctx() context: ResolverContext
|
|
128
|
+
): Promise<boolean> {
|
|
129
|
+
const { domain, tx } = context.state
|
|
130
|
+
|
|
131
|
+
await Promise.all(
|
|
132
|
+
resources.map(async (resource: ResourcePatch) => {
|
|
133
|
+
const createdResource: Resource = await tx.getRepository(Resource).save({ domain, ...resource })
|
|
134
|
+
})
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return true
|
|
138
|
+
}
|
|
139
|
+
}
|