@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.
- package/client/pages/lib/select2-component.ts +159 -0
- package/client/pages/project/project-list.ts +8 -0
- package/client/pages/project/project-update.ts +114 -14
- package/dist-client/pages/lib/select2-component.d.ts +23 -0
- package/dist-client/pages/lib/select2-component.js +165 -0
- package/dist-client/pages/lib/select2-component.js.map +1 -0
- package/dist-client/pages/project/project-list.d.ts +8 -0
- package/dist-client/pages/project/project-list.js +4 -0
- package/dist-client/pages/project/project-list.js.map +1 -1
- package/dist-client/pages/project/project-update.d.ts +20 -0
- package/dist-client/pages/project/project-update.js +142 -24
- package/dist-client/pages/project/project-update.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/migrations/1723861466414-seed-codes.js +26 -8
- package/dist-server/migrations/1723861466414-seed-codes.js.map +1 -1
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/service/project/project-type.js +1 -4
- package/dist-server/service/project/project-type.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/server/migrations/1723861466414-seed-codes.ts +26 -8
- package/server/service/project/project-type.ts +0 -3
|
@@ -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>×</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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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>×</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>×</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
|
};
|