@dssp/project 0.0.24 → 0.0.26

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.
@@ -0,0 +1,159 @@
1
+ import { LitElement, html, css } from 'lit'
2
+ import { customElement, property, state } from 'lit/decorators.js'
3
+
4
+ @customElement('select2-component')
5
+ export class Select2Component extends LitElement {
6
+ static styles = css`
7
+ div[select-container] {
8
+ position: relative;
9
+ width: 300px;
10
+ border: 1px solid #000;
11
+ }
12
+
13
+ div[dropdown] {
14
+ border: 1px solid #ccc;
15
+ padding: 5px;
16
+ cursor: pointer;
17
+ }
18
+
19
+ div[options] {
20
+ position: absolute;
21
+ width: 100%;
22
+ border: 1px solid #ccc;
23
+ background-color: white;
24
+ max-height: 150px;
25
+ overflow-y: auto;
26
+ display: block;
27
+ z-index: 1;
28
+ }
29
+
30
+ div[option] {
31
+ padding: 10px;
32
+ cursor: pointer;
33
+ }
34
+
35
+ div[option]:hover {
36
+ background-color: #f0f0f0;
37
+ }
38
+
39
+ div[option][selected] {
40
+ background-color: #d3f9d8;
41
+ }
42
+
43
+ div[selected-tags] {
44
+ display: flex;
45
+ flex-wrap: wrap;
46
+ gap: 5px;
47
+ margin-top: 10px;
48
+ }
49
+
50
+ div[tag] {
51
+ background-color: #007bff;
52
+ color: white;
53
+ padding: 5px 10px;
54
+ border-radius: 20px;
55
+ display: inline-flex;
56
+ align-items: center;
57
+ cursor: pointer;
58
+ }
59
+
60
+ span[tag-close] {
61
+ margin-left: 8px;
62
+ }
63
+ `
64
+
65
+ @property({ type: String }) placeholder: string = ''
66
+ @property({ type: Array }) options: Array<{ name: string; value: string }> = []
67
+ @property({ type: Array }) selectedValues: string[] = []
68
+
69
+ @state() showOptions: boolean = false
70
+
71
+ get selectedItems() {
72
+ return this.selectedValues.map(id => this.options.find(option => option.value === id)).filter(Boolean)
73
+ }
74
+
75
+ connectedCallback() {
76
+ super.connectedCallback()
77
+ document.addEventListener('click', this._handleOutsideClick)
78
+ }
79
+
80
+ disconnectedCallback() {
81
+ super.disconnectedCallback()
82
+ document.removeEventListener('click', this._handleOutsideClick)
83
+ }
84
+
85
+ private _handleOutsideClick = (event: MouseEvent) => {
86
+ const path = event.composedPath()
87
+ if (!path.includes(this)) {
88
+ this.showOptions = false
89
+ }
90
+ }
91
+
92
+ private _toggleOptions() {
93
+ this.showOptions = !this.showOptions
94
+ }
95
+
96
+ private _handleSelect(optionValue: string) {
97
+ if (this.selectedValues.includes(optionValue)) {
98
+ // 이미 선택된 옵션을 선택한 경우 해제
99
+ this.selectedValues = this.selectedValues.filter(value => value !== optionValue)
100
+ } else {
101
+ // 선택되지 않은 옵션 추가
102
+ this.selectedValues = [...this.selectedValues, optionValue]
103
+ }
104
+
105
+ this.showOptions = false
106
+ this._dispatchEvent(this.selectedValues)
107
+ }
108
+
109
+ private _handleRemove(tagValue: string) {
110
+ this.selectedValues = this.selectedValues.filter(value => value !== tagValue)
111
+ this._dispatchEvent(this.selectedValues)
112
+ }
113
+
114
+ private _dispatchEvent(selectedValues: string[]) {
115
+ this.dispatchEvent(
116
+ new CustomEvent('selection-changed', {
117
+ detail: { selectedValues }, // ID 배열을 부모로 전달
118
+ bubbles: true,
119
+ composed: true
120
+ })
121
+ )
122
+ }
123
+
124
+ render() {
125
+ return html`
126
+ <div select-container>
127
+ <div tags @click="${this._toggleOptions}">${this.placeholder}</div>
128
+ ${this.showOptions
129
+ ? html`
130
+ <div options>
131
+ ${this.options.map(
132
+ option => html`
133
+ <div
134
+ option
135
+ ?selected=${this.selectedValues.includes(option.value)}
136
+ @click=${() => this._handleSelect(option.value)}
137
+ >
138
+ ${option.name}
139
+ </div>
140
+ `
141
+ )}
142
+ </div>
143
+ `
144
+ : ''}
145
+ </div>
146
+
147
+ <div selected-tags>
148
+ ${this.selectedItems.map(
149
+ (tag: any) => html`
150
+ <div tag @click=${() => this._handleRemove(tag.value)}>
151
+ ${tag!.name}
152
+ <span tag-close>&times;</span>
153
+ </div>
154
+ `
155
+ )}
156
+ </div>
157
+ `
158
+ }
159
+ }
@@ -15,13 +15,17 @@ export enum ProjectState {
15
15
  }
16
16
  export enum BuildingInspectionStatus {
17
17
  WAIT = 'WAIT',
18
+ OVERALL_WAIT = 'OVERALL_WAIT',
18
19
  REQUEST = 'REQUEST',
20
+ OVERALL_REQUEST = 'OVERALL_REQUEST',
19
21
  PASS = 'PASS',
20
22
  FAIL = 'FAIL'
21
23
  }
22
24
  export const BUILDING_INSPECTION_STATUS = {
23
25
  [BuildingInspectionStatus.WAIT]: '검측 대기',
26
+ [BuildingInspectionStatus.OVERALL_WAIT]: '검측 대기',
24
27
  [BuildingInspectionStatus.REQUEST]: '검측 요청',
28
+ [BuildingInspectionStatus.OVERALL_REQUEST]: '검측 요청',
25
29
  [BuildingInspectionStatus.PASS]: '합격',
26
30
  [BuildingInspectionStatus.FAIL]: '불합격'
27
31
  }
@@ -61,6 +65,10 @@ export interface BuildingComplex {
61
65
  notice?: string
62
66
  planXScale?: number
63
67
  planYScale?: number
68
+ overallConstructorEmails?: string[]
69
+ taskConstructorEmails?: string[]
70
+ overallSupervisoryEmails?: string[]
71
+ taskSupervisoryEmails?: string[]
64
72
  buildings?: Building[]
65
73
  }
66
74
  export interface Building {
@@ -9,9 +9,9 @@ import { customElement, state } from 'lit/decorators.js'
9
9
  import { ScopedElementsMixin } from '@open-wc/scoped-elements'
10
10
  import { client } from '@operato/graphql'
11
11
  import { notify } from '@operato/layout'
12
-
13
12
  import gql from 'graphql-tag'
14
13
  import { Project } from './project-list'
14
+ import '../lib/select2-component'
15
15
 
16
16
  @customElement('project-update')
17
17
  export class ProjectUpdate extends ScopedElementsMixin(PageView) {
@@ -258,6 +258,11 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
258
258
  }
259
259
  @state() projectId: string = ''
260
260
  @state() project: Project = { ...this.defaultProject }
261
+ @state() selectedValues: string[] = []
262
+ @state() overallConstructorList: Array<{ name: string; value: string }> = []
263
+ @state() taskConstructorList: Array<{ name: string; value: string }> = []
264
+ @state() taskSupervisoryList: Array<{ name: string; value: string }> = []
265
+ @state() overallSupervisoryList: Array<{ name: string; value: string }> = []
261
266
 
262
267
  render() {
263
268
  return html`
@@ -471,7 +476,56 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
471
476
  ></md-outlined-text-field>
472
477
  </span>
473
478
  </div>
479
+ <div row>
480
+ <span>총괄 시공 관리자 리스트</span>
481
+ <span>
482
+ <select2-component
483
+ placeholder="총괄 시공 관리자 리스트"
484
+ name="overallConstructorEmails"
485
+ .options=${this.overallConstructorList}
486
+ .selectedValues=${this.project?.buildingComplex?.overallConstructorEmails || []}
487
+ @selection-changed=${this._handleSelectionChange}
488
+ ></select2-component>
489
+ </span>
490
+ </div>
491
+ <div row>
492
+ <span>공종별 시공 관리자 리스트</span>
493
+ <span>
494
+ <select2-component
495
+ placeholder="공종별 시공 관리자 리스트"
496
+ name="taskConstructorEmails"
497
+ .options=${this.taskConstructorList}
498
+ .selectedValues=${this.project?.buildingComplex?.taskConstructorEmails || []}
499
+ @selection-changed=${this._handleSelectionChange}
500
+ ></select2-component>
501
+ </span>
502
+ </div>
503
+ <div row>
504
+ <span>총괄 감리 책임자 리스트</span>
505
+ <span>
506
+ <select2-component
507
+ placeholder="총괄 감리 책임자 리스트"
508
+ name="overallSupervisoryEmails"
509
+ .options=${this.overallSupervisoryList}
510
+ .selectedValues=${this.project?.buildingComplex?.overallSupervisoryEmails || []}
511
+ @selection-changed=${this._handleSelectionChange}
512
+ ></select2-component>
513
+ </span>
514
+ </div>
515
+ <div row>
516
+ <span>공종별 감리 책임자 리스트</span>
517
+ <span>
518
+ <select2-component
519
+ placeholder="공종별 감리 책임자 리스트"
520
+ name="taskSupervisoryEmails"
521
+ .options=${this.taskSupervisoryList}
522
+ .selectedValues=${this.project?.buildingComplex?.taskSupervisoryEmails || []}
523
+ @selection-changed=${this._handleSelectionChange}
524
+ ></select2-component
525
+ ></span>
526
+ </div>
474
527
  </div>
528
+
475
529
  <div detail-info>
476
530
  <div>
477
531
  <h3>건설구분 상세 정보</h3>
@@ -541,8 +595,8 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
541
595
  <div row separate-container>
542
596
  <div>
543
597
  <span>전체 진행현황</span>
544
- <span
545
- ><md-outlined-text-field
598
+ <span>
599
+ <md-outlined-text-field
546
600
  type="text"
547
601
  numeric
548
602
  project
@@ -555,8 +609,8 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
555
609
  </div>
556
610
  <div>
557
611
  <span>검측/통과비율</span>
558
- <span
559
- ><md-outlined-text-field
612
+ <span>
613
+ <md-outlined-text-field
560
614
  type="text"
561
615
  numeric
562
616
  project
@@ -571,8 +625,8 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
571
625
  <div row separate-container>
572
626
  <div>
573
627
  <span>주간 진행현황</span>
574
- <span
575
- ><md-outlined-text-field
628
+ <span>
629
+ <md-outlined-text-field
576
630
  type="text"
577
631
  numeric
578
632
  project
@@ -585,8 +639,8 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
585
639
  </div>
586
640
  <div>
587
641
  <span>로봇작업진행율</span>
588
- <span
589
- ><md-outlined-text-field
642
+ <span>
643
+ <md-outlined-text-field
590
644
  type="text"
591
645
  numeric
592
646
  project
@@ -662,7 +716,7 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
662
716
  async initProject(projectId: string = '') {
663
717
  const response = await client.query({
664
718
  query: gql`
665
- query Project($id: String!) {
719
+ query Project($id: String!, $filters: [Filter!]) {
666
720
  project(id: $id) {
667
721
  id
668
722
  name
@@ -697,6 +751,10 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
697
751
  notice
698
752
  householdCount
699
753
  buildingCount
754
+ overallConstructorEmails
755
+ taskConstructorEmails
756
+ overallSupervisoryEmails
757
+ taskSupervisoryEmails
700
758
  buildings {
701
759
  id
702
760
  name
@@ -704,15 +762,52 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
704
762
  }
705
763
  }
706
764
  }
765
+
766
+ employees(filters: $filters) {
767
+ items {
768
+ id
769
+ name
770
+ jobResponsibility
771
+ active
772
+ user {
773
+ id
774
+ name
775
+ email
776
+ }
777
+ }
778
+ }
707
779
  }
708
780
  `,
709
781
  variables: {
710
- id: projectId
782
+ id: projectId,
783
+ filters: [
784
+ {
785
+ name: 'active',
786
+ operator: 'eq',
787
+ value: true
788
+ },
789
+ {
790
+ name: 'userId',
791
+ operator: 'is_not_null',
792
+ value: ''
793
+ }
794
+ ]
711
795
  }
712
796
  })
713
797
 
714
798
  this.project = response.data?.project
715
- console.log('init project : ', this.project)
799
+
800
+ const items = response.data?.employees?.items || []
801
+ this.overallConstructorList = this._filterUserByPermission(items, 'OVERALL_CONSTRUCTOR')
802
+ this.taskConstructorList = this._filterUserByPermission(items, 'TASK_CONSTRUCTOR')
803
+ this.overallSupervisoryList = this._filterUserByPermission(items, 'OVERALL_SUPERVISORY')
804
+ this.taskSupervisoryList = this._filterUserByPermission(items, 'TASK_SUPERVISORY')
805
+ }
806
+
807
+ private _filterUserByPermission(userList, permission: string) {
808
+ return userList
809
+ .filter(v => v.jobResponsibility == permission || v.jobResponsibility == 'ADMIN')
810
+ .map(v => ({ name: v.name, value: v.user.email }))
716
811
  }
717
812
 
718
813
  private async _saveProject() {
@@ -720,8 +815,6 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
720
815
  delete this.project.mainPhoto
721
816
  delete this.project.buildingComplex.drawing
722
817
 
723
- console.log('this.project :', this.project)
724
-
725
818
  const response = await client.mutate({
726
819
  mutation: gql`
727
820
  mutation UpdateProject($project: ProjectPatch!) {
@@ -797,4 +890,11 @@ export class ProjectUpdate extends ScopedElementsMixin(PageView) {
797
890
  this.project.buildingComplex.drawingUpload = file
798
891
  }
799
892
  }
893
+
894
+ private _handleSelectionChange(e) {
895
+ const name = e.target.getAttribute('name')
896
+ const selectedValues = e.detail.selectedValues
897
+
898
+ this.project.buildingComplex[name] = selectedValues
899
+ }
800
900
  }
@@ -0,0 +1,23 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class Select2Component extends LitElement {
3
+ static styles: import("lit").CSSResult;
4
+ placeholder: string;
5
+ options: Array<{
6
+ name: string;
7
+ value: string;
8
+ }>;
9
+ selectedValues: string[];
10
+ showOptions: boolean;
11
+ get selectedItems(): ({
12
+ name: string;
13
+ value: string;
14
+ } | undefined)[];
15
+ connectedCallback(): void;
16
+ disconnectedCallback(): void;
17
+ private _handleOutsideClick;
18
+ private _toggleOptions;
19
+ private _handleSelect;
20
+ private _handleRemove;
21
+ private _dispatchEvent;
22
+ render(): import("lit-html").TemplateResult<1>;
23
+ }
@@ -0,0 +1,165 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { LitElement, html, css } from 'lit';
3
+ import { customElement, property, state } from 'lit/decorators.js';
4
+ let Select2Component = class Select2Component extends LitElement {
5
+ constructor() {
6
+ super(...arguments);
7
+ this.placeholder = '';
8
+ this.options = [];
9
+ this.selectedValues = [];
10
+ this.showOptions = false;
11
+ this._handleOutsideClick = (event) => {
12
+ const path = event.composedPath();
13
+ if (!path.includes(this)) {
14
+ this.showOptions = false;
15
+ }
16
+ };
17
+ }
18
+ get selectedItems() {
19
+ return this.selectedValues.map(id => this.options.find(option => option.value === id)).filter(Boolean);
20
+ }
21
+ connectedCallback() {
22
+ super.connectedCallback();
23
+ document.addEventListener('click', this._handleOutsideClick);
24
+ }
25
+ disconnectedCallback() {
26
+ super.disconnectedCallback();
27
+ document.removeEventListener('click', this._handleOutsideClick);
28
+ }
29
+ _toggleOptions() {
30
+ this.showOptions = !this.showOptions;
31
+ }
32
+ _handleSelect(optionValue) {
33
+ if (this.selectedValues.includes(optionValue)) {
34
+ // 이미 선택된 옵션을 선택한 경우 해제
35
+ this.selectedValues = this.selectedValues.filter(value => value !== optionValue);
36
+ }
37
+ else {
38
+ // 선택되지 않은 옵션 추가
39
+ this.selectedValues = [...this.selectedValues, optionValue];
40
+ }
41
+ this.showOptions = false;
42
+ this._dispatchEvent(this.selectedValues);
43
+ }
44
+ _handleRemove(tagValue) {
45
+ this.selectedValues = this.selectedValues.filter(value => value !== tagValue);
46
+ this._dispatchEvent(this.selectedValues);
47
+ }
48
+ _dispatchEvent(selectedValues) {
49
+ this.dispatchEvent(new CustomEvent('selection-changed', {
50
+ detail: { selectedValues },
51
+ bubbles: true,
52
+ composed: true
53
+ }));
54
+ }
55
+ render() {
56
+ return html `
57
+ <div select-container>
58
+ <div tags @click="${this._toggleOptions}">${this.placeholder}</div>
59
+ ${this.showOptions
60
+ ? html `
61
+ <div options>
62
+ ${this.options.map(option => html `
63
+ <div
64
+ option
65
+ ?selected=${this.selectedValues.includes(option.value)}
66
+ @click=${() => this._handleSelect(option.value)}
67
+ >
68
+ ${option.name}
69
+ </div>
70
+ `)}
71
+ </div>
72
+ `
73
+ : ''}
74
+ </div>
75
+
76
+ <div selected-tags>
77
+ ${this.selectedItems.map((tag) => html `
78
+ <div tag @click=${() => this._handleRemove(tag.value)}>
79
+ ${tag.name}
80
+ <span tag-close>&times;</span>
81
+ </div>
82
+ `)}
83
+ </div>
84
+ `;
85
+ }
86
+ };
87
+ Select2Component.styles = css `
88
+ div[select-container] {
89
+ position: relative;
90
+ width: 300px;
91
+ border: 1px solid #000;
92
+ }
93
+
94
+ div[dropdown] {
95
+ border: 1px solid #ccc;
96
+ padding: 5px;
97
+ cursor: pointer;
98
+ }
99
+
100
+ div[options] {
101
+ position: absolute;
102
+ width: 100%;
103
+ border: 1px solid #ccc;
104
+ background-color: white;
105
+ max-height: 150px;
106
+ overflow-y: auto;
107
+ display: block;
108
+ z-index: 1;
109
+ }
110
+
111
+ div[option] {
112
+ padding: 10px;
113
+ cursor: pointer;
114
+ }
115
+
116
+ div[option]:hover {
117
+ background-color: #f0f0f0;
118
+ }
119
+
120
+ div[option][selected] {
121
+ background-color: #d3f9d8;
122
+ }
123
+
124
+ div[selected-tags] {
125
+ display: flex;
126
+ flex-wrap: wrap;
127
+ gap: 5px;
128
+ margin-top: 10px;
129
+ }
130
+
131
+ div[tag] {
132
+ background-color: #007bff;
133
+ color: white;
134
+ padding: 5px 10px;
135
+ border-radius: 20px;
136
+ display: inline-flex;
137
+ align-items: center;
138
+ cursor: pointer;
139
+ }
140
+
141
+ span[tag-close] {
142
+ margin-left: 8px;
143
+ }
144
+ `;
145
+ __decorate([
146
+ property({ type: String }),
147
+ __metadata("design:type", String)
148
+ ], Select2Component.prototype, "placeholder", void 0);
149
+ __decorate([
150
+ property({ type: Array }),
151
+ __metadata("design:type", Array)
152
+ ], Select2Component.prototype, "options", void 0);
153
+ __decorate([
154
+ property({ type: Array }),
155
+ __metadata("design:type", Array)
156
+ ], Select2Component.prototype, "selectedValues", void 0);
157
+ __decorate([
158
+ state(),
159
+ __metadata("design:type", Boolean)
160
+ ], Select2Component.prototype, "showOptions", void 0);
161
+ Select2Component = __decorate([
162
+ customElement('select2-component')
163
+ ], Select2Component);
164
+ export { Select2Component };
165
+ //# sourceMappingURL=select2-component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select2-component.js","sourceRoot":"","sources":["../../../client/pages/lib/select2-component.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\n@customElement('select2-component')\nexport class Select2Component extends LitElement {\n static styles = css`\n div[select-container] {\n position: relative;\n width: 300px;\n border: 1px solid #000;\n }\n\n div[dropdown] {\n border: 1px solid #ccc;\n padding: 5px;\n cursor: pointer;\n }\n\n div[options] {\n position: absolute;\n width: 100%;\n border: 1px solid #ccc;\n background-color: white;\n max-height: 150px;\n overflow-y: auto;\n display: block;\n z-index: 1;\n }\n\n div[option] {\n padding: 10px;\n cursor: pointer;\n }\n\n div[option]:hover {\n background-color: #f0f0f0;\n }\n\n div[option][selected] {\n background-color: #d3f9d8;\n }\n\n div[selected-tags] {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n margin-top: 10px;\n }\n\n div[tag] {\n background-color: #007bff;\n color: white;\n padding: 5px 10px;\n border-radius: 20px;\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n }\n\n span[tag-close] {\n margin-left: 8px;\n }\n `\n\n @property({ type: String }) placeholder: string = ''\n @property({ type: Array }) options: Array<{ name: string; value: string }> = []\n @property({ type: Array }) selectedValues: string[] = []\n\n @state() showOptions: boolean = false\n\n get selectedItems() {\n return this.selectedValues.map(id => this.options.find(option => option.value === id)).filter(Boolean)\n }\n\n connectedCallback() {\n super.connectedCallback()\n document.addEventListener('click', this._handleOutsideClick)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n document.removeEventListener('click', this._handleOutsideClick)\n }\n\n private _handleOutsideClick = (event: MouseEvent) => {\n const path = event.composedPath()\n if (!path.includes(this)) {\n this.showOptions = false\n }\n }\n\n private _toggleOptions() {\n this.showOptions = !this.showOptions\n }\n\n private _handleSelect(optionValue: string) {\n if (this.selectedValues.includes(optionValue)) {\n // 이미 선택된 옵션을 선택한 경우 해제\n this.selectedValues = this.selectedValues.filter(value => value !== optionValue)\n } else {\n // 선택되지 않은 옵션 추가\n this.selectedValues = [...this.selectedValues, optionValue]\n }\n\n this.showOptions = false\n this._dispatchEvent(this.selectedValues)\n }\n\n private _handleRemove(tagValue: string) {\n this.selectedValues = this.selectedValues.filter(value => value !== tagValue)\n this._dispatchEvent(this.selectedValues)\n }\n\n private _dispatchEvent(selectedValues: string[]) {\n this.dispatchEvent(\n new CustomEvent('selection-changed', {\n detail: { selectedValues }, // ID 배열을 부모로 전달\n bubbles: true,\n composed: true\n })\n )\n }\n\n render() {\n return html`\n <div select-container>\n <div tags @click=\"${this._toggleOptions}\">${this.placeholder}</div>\n ${this.showOptions\n ? html`\n <div options>\n ${this.options.map(\n option => html`\n <div\n option\n ?selected=${this.selectedValues.includes(option.value)}\n @click=${() => this._handleSelect(option.value)}\n >\n ${option.name}\n </div>\n `\n )}\n </div>\n `\n : ''}\n </div>\n\n <div selected-tags>\n ${this.selectedItems.map(\n (tag: any) => html`\n <div tag @click=${() => this._handleRemove(tag.value)}>\n ${tag!.name}\n <span tag-close>&times;</span>\n </div>\n `\n )}\n </div>\n `\n }\n}\n"]}
@@ -8,13 +8,17 @@ export declare enum ProjectState {
8
8
  }
9
9
  export declare enum BuildingInspectionStatus {
10
10
  WAIT = "WAIT",
11
+ OVERALL_WAIT = "OVERALL_WAIT",
11
12
  REQUEST = "REQUEST",
13
+ OVERALL_REQUEST = "OVERALL_REQUEST",
12
14
  PASS = "PASS",
13
15
  FAIL = "FAIL"
14
16
  }
15
17
  export declare const BUILDING_INSPECTION_STATUS: {
16
18
  WAIT: string;
19
+ OVERALL_WAIT: string;
17
20
  REQUEST: string;
21
+ OVERALL_REQUEST: string;
18
22
  PASS: string;
19
23
  FAIL: string;
20
24
  };
@@ -53,6 +57,10 @@ export interface BuildingComplex {
53
57
  notice?: string;
54
58
  planXScale?: number;
55
59
  planYScale?: number;
60
+ overallConstructorEmails?: string[];
61
+ taskConstructorEmails?: string[];
62
+ overallSupervisoryEmails?: string[];
63
+ taskSupervisoryEmails?: string[];
56
64
  buildings?: Building[];
57
65
  }
58
66
  export interface Building {
@@ -14,13 +14,17 @@ export var ProjectState;
14
14
  export var BuildingInspectionStatus;
15
15
  (function (BuildingInspectionStatus) {
16
16
  BuildingInspectionStatus["WAIT"] = "WAIT";
17
+ BuildingInspectionStatus["OVERALL_WAIT"] = "OVERALL_WAIT";
17
18
  BuildingInspectionStatus["REQUEST"] = "REQUEST";
19
+ BuildingInspectionStatus["OVERALL_REQUEST"] = "OVERALL_REQUEST";
18
20
  BuildingInspectionStatus["PASS"] = "PASS";
19
21
  BuildingInspectionStatus["FAIL"] = "FAIL";
20
22
  })(BuildingInspectionStatus || (BuildingInspectionStatus = {}));
21
23
  export const BUILDING_INSPECTION_STATUS = {
22
24
  [BuildingInspectionStatus.WAIT]: '검측 대기',
25
+ [BuildingInspectionStatus.OVERALL_WAIT]: '검측 대기',
23
26
  [BuildingInspectionStatus.REQUEST]: '검측 요청',
27
+ [BuildingInspectionStatus.OVERALL_REQUEST]: '검측 요청',
24
28
  [BuildingInspectionStatus.PASS]: '합격',
25
29
  [BuildingInspectionStatus.FAIL]: '불합격'
26
30
  };