@dssp/supervision 1.0.14 → 1.0.16
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/pages/building-inspection/building-inspection-detail-ai-measurement.d.ts +7 -0
- package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js +170 -17
- package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js.map +1 -1
- package/dist-client/pages/building-inspection/building-inspection-detail-drawing.d.ts +8 -2
- package/dist-client/pages/building-inspection/building-inspection-detail-drawing.js +24 -24
- package/dist-client/pages/building-inspection/building-inspection-detail-drawing.js.map +1 -1
- package/dist-client/pages/building-inspection/inspection-create-popup.js +2 -2
- package/dist-client/pages/building-inspection/inspection-create-popup.js.map +1 -1
- package/dist-client/pages/building-inspection/inspection-with-checklist-create-popup.js +2 -2
- package/dist-client/pages/building-inspection/inspection-with-checklist-create-popup.js.map +1 -1
- package/dist-client/pages/building-inspection-grid/building-inspection-grid-detail.d.ts +1 -1
- package/dist-client/pages/checklist/checklist-view.js +3 -3
- package/dist-client/pages/checklist/checklist-view.js.map +1 -1
- package/dist-client/pages/checklist-template/checklist-template-list.js +1 -1
- package/dist-client/pages/checklist-template/checklist-template-list.js.map +1 -1
- package/dist-client/pages/project-checklist/project-checklist-management.js +14 -14
- package/dist-client/pages/project-checklist/project-checklist-management.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/checklist-item/checklist-item.js +1 -1
- package/dist-server/service/checklist-item/checklist-item.js.map +1 -1
- package/dist-server/service/checklist-item-history/checklist-item-history.js +1 -1
- package/dist-server/service/checklist-item-history/checklist-item-history.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -1
- package/dist-server/service/project-checklist/index.d.ts +1 -1
- package/dist-server/service/project-checklist/project-checklist-mutation.js +2 -2
- package/dist-server/service/project-checklist/project-checklist-mutation.js.map +1 -1
- package/dist-server/service/project-checklist/spec-matching-service.d.ts +3 -3
- package/dist-server/service/project-checklist/spec-matching-service.js +14 -14
- package/dist-server/service/project-checklist/spec-matching-service.js.map +1 -1
- package/dist-server/service/project-checklist-item/project-checklist-item.js +1 -1
- package/dist-server/service/project-checklist-item/project-checklist-item.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.d.ts
CHANGED
|
@@ -38,6 +38,9 @@ export declare class BuildingInspectionAiMeasurement extends PageView {
|
|
|
38
38
|
selectedItem: any;
|
|
39
39
|
recaptureBase: number;
|
|
40
40
|
recaptureSet: SetInfo | null;
|
|
41
|
+
setPickerFor: number | null;
|
|
42
|
+
recentSets: any[];
|
|
43
|
+
recentLoading: boolean;
|
|
41
44
|
expandedReportId: string | null;
|
|
42
45
|
measureSetIndex: number;
|
|
43
46
|
measureInputs: Record<string, string>;
|
|
@@ -93,6 +96,10 @@ export declare class BuildingInspectionAiMeasurement extends PageView {
|
|
|
93
96
|
private _callMeasure;
|
|
94
97
|
private _fetchMeasureImage;
|
|
95
98
|
private _loadShotGuide;
|
|
99
|
+
private _renderSetChooser;
|
|
100
|
+
private _loadRecentSets;
|
|
101
|
+
private _openSetChooser;
|
|
102
|
+
private _pickExistingSet;
|
|
96
103
|
private _openSetPicker;
|
|
97
104
|
private _onSetFilesSelected;
|
|
98
105
|
private _fetchVlmFrames;
|
|
@@ -32,6 +32,16 @@ const pictoRebarImg = new URL('../../assets/ai-measurement/picto-rebar-parallel.
|
|
|
32
32
|
const pictoMemberImg = new URL('../../assets/ai-measurement/picto-member-corner.svg', import.meta.url).href;
|
|
33
33
|
/* 세트 폴더 필수 파일 (LidarInspector 앱이 촬영 1회당 생성) */
|
|
34
34
|
const SET_FILES = ['video.mov', 'poses.jsonl', 'meta.json'];
|
|
35
|
+
/* 촬영 앱 실행 링크 — iPad에서 이 화면을 열었을 때 앱이 바로 촬영 화면으로 뜬다.
|
|
36
|
+
server 파라미터로 업로드 주소까지 넘겨서 앱 설정을 따로 안 만져도 되게 한다. */
|
|
37
|
+
function appCaptureLink(tech) {
|
|
38
|
+
return `gamri://${tech}?server=${encodeURIComponent(MEASURE_BASE_URL)}`;
|
|
39
|
+
}
|
|
40
|
+
/* set_id(YYYYmmdd-HHMMSS_xxxxxx) → "9/11 14:30" 표기 */
|
|
41
|
+
function _setTimeLabel(setId) {
|
|
42
|
+
const m = /^(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})/.exec(setId || '');
|
|
43
|
+
return m ? `${Number(m[2])}/${Number(m[3])} ${m[4]}:${m[5]}` : setId;
|
|
44
|
+
}
|
|
35
45
|
/* 엔진 verdict(기계값) → 화면 라벨. pass/fail만 합/불로 자동 체크, 나머지는 감리자 판단 */
|
|
36
46
|
const VERDICT_LABEL = {
|
|
37
47
|
pass: '적합',
|
|
@@ -69,6 +79,9 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
|
|
|
69
79
|
this.selectedItem = null;
|
|
70
80
|
this.recaptureBase = 0; // 재검사 진입 시점의 프레임 수 (used_images 보정용)
|
|
71
81
|
this.recaptureSet = null; // 재촬영으로 새로 올린 세트
|
|
82
|
+
this.setPickerFor = null; // 세트 고르는 중인 촬영 번호 (-1 = 재촬영)
|
|
83
|
+
this.recentSets = []; // 측정 서버에 올라온 최근 세트 (앱이 촬영 직후 자동 전송)
|
|
84
|
+
this.recentLoading = false;
|
|
72
85
|
this.expandedReportId = null; // 종합 리포트에서 펼친 항목(아코디언)
|
|
73
86
|
/* 측정 패널 상태 */
|
|
74
87
|
this.measureSetIndex = 0;
|
|
@@ -211,10 +224,6 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
|
|
|
211
224
|
<div class="card">
|
|
212
225
|
<h4>공통 촬영법 — 옆으로 이동 · 대상 정면 유지 · 대상 전체 포함</h4>
|
|
213
226
|
<img class="capture-guide-img" src=${captureGuideImg} alt="촬영 안내" />
|
|
214
|
-
<div class="picto-strip">
|
|
215
|
-
<img src=${pictoRebarImg} alt="철근: 재려는 변과 나란히" />
|
|
216
|
-
<img src=${pictoMemberImg} alt="기둥·벽: 모서리가 보이게" />
|
|
217
|
-
</div>
|
|
218
227
|
</div>
|
|
219
228
|
|
|
220
229
|
<div class="card" style="display: flex; flex-direction: column; gap: 10px;">
|
|
@@ -223,30 +232,36 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
|
|
|
223
232
|
<span>${uploaded} / ${total}</span>
|
|
224
233
|
</div>
|
|
225
234
|
<div class="progress-bar"><div style="width: ${total ? (uploaded / total) * 100 : 0}%"></div></div>
|
|
235
|
+
<div class="app-links">
|
|
236
|
+
<span>촬영 앱 열기</span>
|
|
237
|
+
<a href=${appCaptureLink('cover')}>철근 배근 길이</a>
|
|
238
|
+
<a href=${appCaptureLink('thick')}>벽·기둥 두께</a>
|
|
239
|
+
</div>
|
|
226
240
|
${shots.map((s, i) => {
|
|
227
241
|
const set = this.sets[i];
|
|
228
242
|
return html `
|
|
229
|
-
<div class="set-card" ?uploaded=${!!set} @click=${() => !set && this.
|
|
243
|
+
<div class="set-card" ?uploaded=${!!set} @click=${() => !set && this._openSetChooser(i)}>
|
|
230
244
|
<md-icon>${set ? 'check_circle' : 'video_file'}</md-icon>
|
|
231
245
|
<div class="set-main">
|
|
232
246
|
<b>촬영 ${s.shot_no || i + 1} · ${s.target}</b>
|
|
233
247
|
${set
|
|
234
248
|
? html `세트 업로드 완료${set.technique ? ` (${set.technique})` : ''}
|
|
235
249
|
${set.warnings.map(w => html `<div class="set-warn">⚠ ${w}</div>`)}`
|
|
236
|
-
: html `탭해서
|
|
250
|
+
: html `탭해서 앱으로 촬영한 세트를 선택 (또는 파일 직접 선택)`}
|
|
237
251
|
</div>
|
|
238
252
|
${set
|
|
239
253
|
? html `<button
|
|
240
254
|
class="text-button"
|
|
241
255
|
@click=${(e) => {
|
|
242
256
|
e.stopPropagation();
|
|
243
|
-
this.
|
|
257
|
+
this._openSetChooser(i);
|
|
244
258
|
}}
|
|
245
259
|
>
|
|
246
260
|
교체
|
|
247
261
|
</button>`
|
|
248
262
|
: ''}
|
|
249
263
|
</div>
|
|
264
|
+
${this.setPickerFor === i ? this._renderSetChooser(i) : ''}
|
|
250
265
|
`;
|
|
251
266
|
})}
|
|
252
267
|
</div>
|
|
@@ -488,15 +503,21 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
|
|
|
488
503
|
</div>
|
|
489
504
|
`
|
|
490
505
|
: ''}
|
|
491
|
-
<div class="
|
|
506
|
+
<div class="app-links">
|
|
507
|
+
<span>촬영 앱 열기</span>
|
|
508
|
+
<a href=${appCaptureLink('cover')}>철근 배근 길이</a>
|
|
509
|
+
<a href=${appCaptureLink('thick')}>벽·기둥 두께</a>
|
|
510
|
+
</div>
|
|
511
|
+
<div class="set-card" ?uploaded=${!!this.recaptureSet} @click=${() => this._openSetChooser(-1)}>
|
|
492
512
|
<md-icon>${this.recaptureSet ? 'check_circle' : 'video_file'}</md-icon>
|
|
493
513
|
<div class="set-main">
|
|
494
514
|
<b>재촬영 세트</b>
|
|
495
515
|
${this.recaptureSet
|
|
496
516
|
? html `세트 업로드 완료 ${this.recaptureSet.warnings.map(w => html `<div class="set-warn">⚠ ${w}</div>`)}`
|
|
497
|
-
: html `앱으로
|
|
517
|
+
: html `앱으로 재촬영한 세트를 선택 (또는 파일 직접 선택)`}
|
|
498
518
|
</div>
|
|
499
519
|
</div>
|
|
520
|
+
${this.setPickerFor === -1 ? this._renderSetChooser(-1) : ''}
|
|
500
521
|
${this.recaptureSet ? html `<button class="primary-button" @click=${() => this._runInspection()}>재검사 실행</button>` : ''}
|
|
501
522
|
<button class="text-button" @click=${this._closePanel}>닫기</button>
|
|
502
523
|
</div>
|
|
@@ -824,10 +845,74 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
|
|
|
824
845
|
this.loading = false;
|
|
825
846
|
}
|
|
826
847
|
}
|
|
827
|
-
/*
|
|
848
|
+
/* 세트 선택 목록 — 앱이 올린 최근 세트 + 파일 직접 선택 폴백 */
|
|
849
|
+
_renderSetChooser(index) {
|
|
850
|
+
return html `
|
|
851
|
+
<div class="set-chooser">
|
|
852
|
+
${this.recentLoading
|
|
853
|
+
? html `<div class="chooser-empty">불러오는 중...</div>`
|
|
854
|
+
: this.recentSets.length
|
|
855
|
+
? this.recentSets.map(s => html `
|
|
856
|
+
<button class="chooser-row" @click=${() => this._pickExistingSet(index, s)}>
|
|
857
|
+
<b>${_setTimeLabel(s.set_id)}</b>
|
|
858
|
+
<span>
|
|
859
|
+
${s.member_id ? `${s.member_id} · ` : ''}${s.technique || '기술 미상'}
|
|
860
|
+
${s.duration_sec ? ` · ${Math.round(s.duration_sec)}초` : ''}
|
|
861
|
+
</span>
|
|
862
|
+
</button>
|
|
863
|
+
`)
|
|
864
|
+
: html `<div class="chooser-empty">앱에서 올린 세트가 없습니다. 앱으로 촬영하거나 파일을 직접 선택하세요.</div>`}
|
|
865
|
+
<div class="chooser-actions">
|
|
866
|
+
<button class="text-button" @click=${() => this._loadRecentSets()}>새로고침</button>
|
|
867
|
+
<button class="text-button" @click=${() => this._openSetPicker(index)}>파일 직접 선택</button>
|
|
868
|
+
</div>
|
|
869
|
+
</div>
|
|
870
|
+
`;
|
|
871
|
+
}
|
|
872
|
+
/* ─── 세트 선택/업로드 ─── */
|
|
873
|
+
/* 촬영 앱이 측정 서버로 바로 올린 세트 목록 (앱에서 촬영 후 저장하면 자동 전송된다) */
|
|
874
|
+
async _loadRecentSets() {
|
|
875
|
+
try {
|
|
876
|
+
this.recentLoading = true;
|
|
877
|
+
const data = await this._callMeasure('/api/sets?limit=20');
|
|
878
|
+
this.recentSets = data.sets || [];
|
|
879
|
+
}
|
|
880
|
+
catch (error) {
|
|
881
|
+
console.error('세트 목록 조회 실패:', error);
|
|
882
|
+
this.recentSets = [];
|
|
883
|
+
}
|
|
884
|
+
finally {
|
|
885
|
+
this.recentLoading = false;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
/* 카드 탭 → 목록 펼치기 (이미 고른 세트는 제외하고 보여준다) */
|
|
889
|
+
_openSetChooser(index) {
|
|
890
|
+
this.setPickerFor = this.setPickerFor === index ? null : index;
|
|
891
|
+
if (this.setPickerFor !== null)
|
|
892
|
+
this._loadRecentSets();
|
|
893
|
+
}
|
|
894
|
+
/* 목록에서 세트 선택 — 이미 서버에 있으므로 업로드 없이 연결만 한다 */
|
|
895
|
+
_pickExistingSet(index, s) {
|
|
896
|
+
const set = {
|
|
897
|
+
setId: s.set_id,
|
|
898
|
+
technique: s.technique,
|
|
899
|
+
label: `세트 ${s.set_id}`,
|
|
900
|
+
warnings: []
|
|
901
|
+
};
|
|
902
|
+
if (index === -1) {
|
|
903
|
+
this.recaptureSet = set;
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
const next = [...this.sets];
|
|
907
|
+
next[index] = set;
|
|
908
|
+
this.sets = next;
|
|
909
|
+
}
|
|
910
|
+
this.setPickerFor = null;
|
|
911
|
+
}
|
|
828
912
|
_openSetPicker(index) {
|
|
829
913
|
var _a;
|
|
830
914
|
this.pendingSetIndex = index;
|
|
915
|
+
this.setPickerFor = null;
|
|
831
916
|
(_a = this.setInputEl) === null || _a === void 0 ? void 0 : _a.click();
|
|
832
917
|
}
|
|
833
918
|
async _onSetFilesSelected(event) {
|
|
@@ -1448,19 +1533,75 @@ BuildingInspectionAiMeasurement.styles = [
|
|
|
1448
1533
|
display: block;
|
|
1449
1534
|
}
|
|
1450
1535
|
|
|
1451
|
-
|
|
1536
|
+
/* 촬영 앱 실행 링크 */
|
|
1537
|
+
.app-links {
|
|
1452
1538
|
display: flex;
|
|
1539
|
+
align-items: center;
|
|
1453
1540
|
gap: 8px;
|
|
1454
|
-
|
|
1541
|
+
flex-wrap: wrap;
|
|
1542
|
+
font-size: 12px;
|
|
1543
|
+
color: #777;
|
|
1455
1544
|
}
|
|
1456
1545
|
|
|
1457
|
-
.
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1546
|
+
.app-links a {
|
|
1547
|
+
display: inline-flex;
|
|
1548
|
+
align-items: center;
|
|
1549
|
+
gap: 4px;
|
|
1550
|
+
padding: 6px 12px;
|
|
1551
|
+
border: 1px solid #7d2f2f;
|
|
1552
|
+
border-radius: 999px;
|
|
1553
|
+
color: #7d2f2f;
|
|
1554
|
+
font-size: 12px;
|
|
1555
|
+
font-weight: 600;
|
|
1556
|
+
text-decoration: none;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
/* 앱이 올린 세트 고르기 */
|
|
1560
|
+
.set-chooser {
|
|
1561
|
+
border: 1px solid #e5e5e5;
|
|
1462
1562
|
border-radius: 8px;
|
|
1563
|
+
background: #fff;
|
|
1564
|
+
margin: -4px 0 4px 38px;
|
|
1463
1565
|
padding: 6px;
|
|
1566
|
+
max-height: 220px;
|
|
1567
|
+
overflow-y: auto;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
.chooser-row {
|
|
1571
|
+
display: block;
|
|
1572
|
+
width: 100%;
|
|
1573
|
+
text-align: left;
|
|
1574
|
+
border: 0;
|
|
1575
|
+
background: transparent;
|
|
1576
|
+
border-radius: 6px;
|
|
1577
|
+
padding: 8px 10px;
|
|
1578
|
+
cursor: pointer;
|
|
1579
|
+
font-size: 12px;
|
|
1580
|
+
color: #666;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
.chooser-row:hover {
|
|
1584
|
+
background: #f5f5f5;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
.chooser-row b {
|
|
1588
|
+
display: block;
|
|
1589
|
+
font-size: 13px;
|
|
1590
|
+
color: #333;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
.chooser-empty {
|
|
1594
|
+
padding: 12px 10px;
|
|
1595
|
+
font-size: 12px;
|
|
1596
|
+
color: #999;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
.chooser-actions {
|
|
1600
|
+
display: flex;
|
|
1601
|
+
justify-content: flex-end;
|
|
1602
|
+
gap: 4px;
|
|
1603
|
+
border-top: 1px solid #f0f0f0;
|
|
1604
|
+
padding-top: 4px;
|
|
1464
1605
|
}
|
|
1465
1606
|
|
|
1466
1607
|
/* 세트 업로드 카드 */
|
|
@@ -2143,6 +2284,18 @@ __decorate([
|
|
|
2143
2284
|
state(),
|
|
2144
2285
|
__metadata("design:type", Object)
|
|
2145
2286
|
], BuildingInspectionAiMeasurement.prototype, "recaptureSet", void 0);
|
|
2287
|
+
__decorate([
|
|
2288
|
+
state(),
|
|
2289
|
+
__metadata("design:type", Object)
|
|
2290
|
+
], BuildingInspectionAiMeasurement.prototype, "setPickerFor", void 0);
|
|
2291
|
+
__decorate([
|
|
2292
|
+
state(),
|
|
2293
|
+
__metadata("design:type", Array)
|
|
2294
|
+
], BuildingInspectionAiMeasurement.prototype, "recentSets", void 0);
|
|
2295
|
+
__decorate([
|
|
2296
|
+
state(),
|
|
2297
|
+
__metadata("design:type", Boolean)
|
|
2298
|
+
], BuildingInspectionAiMeasurement.prototype, "recentLoading", void 0);
|
|
2146
2299
|
__decorate([
|
|
2147
2300
|
state(),
|
|
2148
2301
|
__metadata("design:type", Object)
|