@dssp/supervision 1.0.16 → 1.0.18

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.
Files changed (31) hide show
  1. package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.d.ts +6 -0
  2. package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js +86 -13
  3. package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js.map +1 -1
  4. package/dist-client/pages/building-inspection/inspection-create-popup.d.ts +1 -0
  5. package/dist-client/pages/building-inspection/inspection-create-popup.js +35 -8
  6. package/dist-client/pages/building-inspection/inspection-create-popup.js.map +1 -1
  7. package/dist-client/pages/building-inspection/inspection-part-picker.d.ts +31 -0
  8. package/dist-client/pages/building-inspection/inspection-part-picker.js +228 -0
  9. package/dist-client/pages/building-inspection/inspection-part-picker.js.map +1 -0
  10. package/dist-client/pages/building-inspection/inspection-with-checklist-create-popup.d.ts +1 -0
  11. package/dist-client/pages/building-inspection/inspection-with-checklist-create-popup.js +40 -1
  12. package/dist-client/pages/building-inspection/inspection-with-checklist-create-popup.js.map +1 -1
  13. package/dist-client/pages/project-checklist/project-checklist-management.d.ts +15 -6
  14. package/dist-client/pages/project-checklist/project-checklist-management.js +243 -103
  15. package/dist-client/pages/project-checklist/project-checklist-management.js.map +1 -1
  16. package/dist-client/route.d.ts +1 -1
  17. package/dist-client/tsconfig.tsbuildinfo +1 -1
  18. package/dist-server/service/building-inspection/building-inspection-mutation.js +5 -1
  19. package/dist-server/service/building-inspection/building-inspection-mutation.js.map +1 -1
  20. package/dist-server/service/index.d.ts +1 -1
  21. package/dist-server/service/project-checklist/project-checklist-mutation.d.ts +4 -3
  22. package/dist-server/service/project-checklist/project-checklist-mutation.js +21 -10
  23. package/dist-server/service/project-checklist/project-checklist-mutation.js.map +1 -1
  24. package/dist-server/service/project-checklist/project-checklist-type.d.ts +4 -0
  25. package/dist-server/service/project-checklist/project-checklist-type.js +16 -1
  26. package/dist-server/service/project-checklist/project-checklist-type.js.map +1 -1
  27. package/dist-server/service/project-checklist/spec-matching-service.d.ts +14 -6
  28. package/dist-server/service/project-checklist/spec-matching-service.js +101 -46
  29. package/dist-server/service/project-checklist/spec-matching-service.js.map +1 -1
  30. package/dist-server/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +3 -3
@@ -66,7 +66,9 @@ export declare class BuildingInspectionAiMeasurement extends PageView {
66
66
  private setInputEl;
67
67
  private pendingSetIndex;
68
68
  private objectUrls;
69
+ private _onVisible;
69
70
  connectedCallback(): Promise<void>;
71
+ disconnectedCallback(): void;
70
72
  get context(): {
71
73
  title: string;
72
74
  };
@@ -96,6 +98,10 @@ export declare class BuildingInspectionAiMeasurement extends PageView {
96
98
  private _callMeasure;
97
99
  private _fetchMeasureImage;
98
100
  private _loadShotGuide;
101
+ private _shotTag;
102
+ private _shotTechnique;
103
+ private _shotAppLink;
104
+ private _autoAttachTaggedSets;
99
105
  private _renderSetChooser;
100
106
  private _loadRecentSets;
101
107
  private _openSetChooser;
@@ -101,6 +101,11 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
101
101
  /* 세트 업로드 대상: 촬영 건 인덱스(가이드 화면) 또는 -1(재촬영 패널) */
102
102
  this.pendingSetIndex = null;
103
103
  this.objectUrls = []; // 페이지 이탈 시 정리할 blob URL들
104
+ /* 촬영 앱에 다녀온 뒤 화면이 다시 보이면 올라온 세트를 찾아 자동 등록한다 */
105
+ this._onVisible = () => {
106
+ if (document.visibilityState === 'visible' && this.guide && !this.result)
107
+ this._autoAttachTaggedSets();
108
+ };
104
109
  this._openReport = () => {
105
110
  this.panel = 'report';
106
111
  this.selectedItem = null;
@@ -129,9 +134,14 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
129
134
  }
130
135
  async connectedCallback() {
131
136
  super.connectedCallback();
137
+ document.addEventListener('visibilitychange', this._onVisible);
132
138
  this.canMutate = await canDcspMutate();
133
139
  this.updateContext();
134
140
  }
141
+ disconnectedCallback() {
142
+ document.removeEventListener('visibilitychange', this._onVisible);
143
+ super.disconnectedCallback();
144
+ }
135
145
  get context() {
136
146
  return {
137
147
  title: '검측 관리 상세 - AI 자동 검측'
@@ -232,11 +242,6 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
232
242
  <span>${uploaded} / ${total}</span>
233
243
  </div>
234
244
  <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>
240
245
  ${shots.map((s, i) => {
241
246
  const set = this.sets[i];
242
247
  return html `
@@ -245,9 +250,8 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
245
250
  <div class="set-main">
246
251
  <b>촬영 ${s.shot_no || i + 1} · ${s.target}</b>
247
252
  ${set
248
- ? html `세트 업로드 완료${set.technique ? ` (${set.technique})` : ''}
249
- ${set.warnings.map(w => html `<div class="set-warn">⚠ ${w}</div>`)}`
250
- : html `탭해서 앱으로 촬영한 세트를 선택 (또는 파일 직접 선택)`}
253
+ ? html `세트 연결 완료 (${set.setId}) ${set.warnings.map(w => html `<div class="set-warn">⚠ ${w}</div>`)}`
254
+ : html `「앱으로 촬영」을 누르면 촬영 후 이 칸에 자동 등록됩니다 · 탭하면 직접 선택`}
251
255
  </div>
252
256
  ${set
253
257
  ? html `<button
@@ -259,7 +263,9 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
259
263
  >
260
264
  교체
261
265
  </button>`
262
- : ''}
266
+ : html `<a class="shoot-link" href=${this._shotAppLink(s, i)} @click=${(e) => e.stopPropagation()}>
267
+ <md-icon>photo_camera</md-icon>앱으로 촬영
268
+ </a>`}
263
269
  </div>
264
270
  ${this.setPickerFor === i ? this._renderSetChooser(i) : ''}
265
271
  `;
@@ -504,9 +510,8 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
504
510
  `
505
511
  : ''}
506
512
  <div class="app-links">
507
- <span>촬영 앱 열기</span>
508
- <a href=${appCaptureLink('cover')}>철근 배근 길이</a>
509
- <a href=${appCaptureLink('thick')}>벽·기둥 두께</a>
513
+ <span>앱으로 재촬영</span>
514
+ <a href=${`${appCaptureLink(this._shotTechnique(shot))}&set=${encodeURIComponent(this._shotTag(0))}`}> 촬영 시작 </a>
510
515
  </div>
511
516
  <div class="set-card" ?uploaded=${!!this.recaptureSet} @click=${() => this._openSetChooser(-1)}>
512
517
  <md-icon>${this.recaptureSet ? 'check_circle' : 'video_file'}</md-icon>
@@ -845,6 +850,47 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
845
850
  this.loading = false;
846
851
  }
847
852
  }
853
+ /* 촬영 칸마다 고유 태그 — 앱에 부재 ID로 넘겨 두면, 올라온 세트의 member_id로
854
+ "어느 촬영 칸의 것인지" 되찾을 수 있다 (앱↔플랫폼 왕복에 식별자가 없어서 쓰는 방법) */
855
+ _shotTag(shotNo) {
856
+ return `${(this.buildingInspectionId || 'ins').replace(/-/g, '').slice(0, 6)}-${shotNo}`;
857
+ }
858
+ /* 촬영 지시문에서 기술 추론 — 앱의 촬영 안내만 달라진다(측정은 meta.technique를 안 봄) */
859
+ _shotTechnique(shot) {
860
+ const text = `${(shot === null || shot === void 0 ? void 0 : shot.target) || ''} ${(shot === null || shot === void 0 ? void 0 : shot.how) || ''}`;
861
+ if (/두께|콘크리트\s*면|거푸집|탈형|벽체\s*면/.test(text))
862
+ return 'thick';
863
+ return 'cover';
864
+ }
865
+ _shotAppLink(shot, index) {
866
+ const tag = this._shotTag((shot === null || shot === void 0 ? void 0 : shot.shot_no) || index + 1);
867
+ return `${appCaptureLink(this._shotTechnique(shot))}&set=${encodeURIComponent(tag)}`;
868
+ }
869
+ /* 앱에서 촬영하고 돌아오면 태그로 찾아 해당 촬영 칸에 자동 등록 */
870
+ async _autoAttachTaggedSets() {
871
+ var _a, _b;
872
+ if (!((_b = (_a = this.guide) === null || _a === void 0 ? void 0 : _a.shots) === null || _b === void 0 ? void 0 : _b.length))
873
+ return;
874
+ await this._loadRecentSets();
875
+ const used = new Set(this.uploadedSets.map(s => s.setId));
876
+ let changed = false;
877
+ const next = [...this.sets];
878
+ this.guide.shots.forEach((shot, i) => {
879
+ if (next[i])
880
+ return;
881
+ const tag = this._shotTag((shot === null || shot === void 0 ? void 0 : shot.shot_no) || i + 1);
882
+ const hit = this.recentSets.find(s => s.member_id === tag && !used.has(s.set_id));
883
+ if (!hit)
884
+ return;
885
+ used.add(hit.set_id);
886
+ next[i] = { setId: hit.set_id, technique: hit.technique, label: `세트 ${hit.set_id}`, warnings: [] };
887
+ changed = true;
888
+ });
889
+ if (changed) {
890
+ this.sets = next;
891
+ notify({ message: '촬영한 세트를 자동으로 등록했습니다.' });
892
+ }
893
+ }
848
894
  /* 세트 선택 목록 — 앱이 올린 최근 세트 + 파일 직접 선택 폴백 */
849
895
  _renderSetChooser(index) {
850
896
  return html `
@@ -861,7 +907,9 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
861
907
  </span>
862
908
  </button>
863
909
  `)
864
- : html `<div class="chooser-empty">앱에서 올린 세트가 없습니다. 앱으로 촬영하거나 파일을 직접 선택하세요.</div>`}
910
+ : html `<div class="chooser-empty">
911
+ 올라온 세트가 없습니다. 카드의 「앱으로 촬영」으로 찍으면 여기에 나타납니다.
912
+ </div>`}
865
913
  <div class="chooser-actions">
866
914
  <button class="text-button" @click=${() => this._loadRecentSets()}>새로고침</button>
867
915
  <button class="text-button" @click=${() => this._openSetPicker(index)}>파일 직접 선택</button>
@@ -1543,6 +1591,26 @@ BuildingInspectionAiMeasurement.styles = [
1543
1591
  color: #777;
1544
1592
  }
1545
1593
 
1594
+ /* 촬영 칸의 「앱으로 촬영」 */
1595
+ .shoot-link {
1596
+ display: inline-flex;
1597
+ align-items: center;
1598
+ gap: 4px;
1599
+ flex-shrink: 0;
1600
+ padding: 7px 12px;
1601
+ border-radius: 999px;
1602
+ background: #7d2f2f;
1603
+ color: #fff;
1604
+ font-size: 12px;
1605
+ font-weight: 600;
1606
+ text-decoration: none;
1607
+ }
1608
+
1609
+ .shoot-link md-icon {
1610
+ --md-icon-size: 16px;
1611
+ color: #fff;
1612
+ }
1613
+
1546
1614
  .app-links a {
1547
1615
  display: inline-flex;
1548
1616
  align-items: center;
@@ -1604,6 +1672,11 @@ BuildingInspectionAiMeasurement.styles = [
1604
1672
  padding-top: 4px;
1605
1673
  }
1606
1674
 
1675
+ .set-chooser .app-links {
1676
+ border-top: 1px solid #f0f0f0;
1677
+ padding: 8px 4px 6px;
1678
+ }
1679
+
1607
1680
  /* 세트 업로드 카드 */
1608
1681
  .set-card {
1609
1682
  display: flex;