@dssp/supervision 1.0.1 → 1.0.5
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.js +1 -1
- package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js.map +1 -1
- package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement_old_ai.js +1 -1
- package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement_old_ai.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/checklist-template-item/spec-matching-service.js +1 -1
- package/dist-server/service/checklist-template-item/spec-matching-service.js.map +1 -1
- package/dist-server/service/field-document/field-document-summary-service.js +1 -1
- package/dist-server/service/field-document/field-document-summary-service.js.map +1 -1
- package/dist-server/service/project-checklist/spec-matching-service.js +1 -1
- package/dist-server/service/project-checklist/spec-matching-service.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -18,7 +18,7 @@ import { ScrollbarStyles } from '@operato/styles';
|
|
|
18
18
|
import { client } from '@operato/graphql';
|
|
19
19
|
import { notify } from '@operato/layout';
|
|
20
20
|
import './component/building-inspection-detail-header';
|
|
21
|
-
const ENGINE_BASE_URL = 'https://hatiolab-korea-uni.
|
|
21
|
+
const ENGINE_BASE_URL = 'https://hatiolab-korea-uni.nruing.com';
|
|
22
22
|
const ENGINE_RUN_URL = `${ENGINE_BASE_URL}/api/run/inspection-ai`;
|
|
23
23
|
const ENGINE_AUTH = `Basic ${btoa('admin:admin1234')}`;
|
|
24
24
|
const MAX_IMAGES = 8;
|
package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"building-inspection-detail-ai-measurement.js","sourceRoot":"","sources":["../../../client/pages/building-inspection/building-inspection-detail-ai-measurement.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 검측 관리 상세 - AI 자동 검측\n *\n * 검측 체크리스트 항목을 AI 엔진(inspection-ai)에 보내:\n * 1) 촬영 가이드(plan-shots)를 받아 단계별 촬영 슬롯을 표시하고\n * 2) 촬영된 사진으로 자동 판정(inspect)을 실행한 뒤\n * 3) 항목별 상세 / 추가 촬영(재검사) / 종합 리포트를 거쳐\n * 4) 검사 등록 시 감리자 적합/부적합 자동 반영 + AI판단 근거를 첨부한다.\n */\nimport '@material/web/icon/icon.js'\nimport '@material/web/progress/circular-progress.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, state, query } from 'lit/decorators.js'\n\nimport { PageView, navigate } from '@operato/shell'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { PageLifecycle } from '@operato/shell/dist/src/app/pages/page-view'\nimport { client } from '@operato/graphql'\nimport { notify } from '@operato/layout'\n\nimport './component/building-inspection-detail-header'\n\nconst ENGINE_BASE_URL = 'https://hatiolab-korea-uni.ettisoft.com'\nconst ENGINE_RUN_URL = `${ENGINE_BASE_URL}/api/run/inspection-ai`\nconst ENGINE_AUTH = `Basic ${btoa('admin:admin1234')}`\nconst MAX_IMAGES = 8\n\n/* 엔진 verdict(기계값) → 화면 라벨. pass/fail만 합/불로 자동 체크, 나머지(보류/미지원/오류)는 감리자 판단 */\nconst VERDICT_LABEL = {\n pass: '적합',\n fail: '부적합',\n hold: '보류',\n pending: '미지원',\n error: '오류'\n}\n\n/* 엔진 routing(기계값) → 화면 라벨 */\nconst ROUTING_LABEL = {\n vlm: 'AI 사진판독',\n cv: '자동 측정',\n cv_missing: '자동 측정 누락'\n}\n\ntype PanelMode = 'none' | 'detail' | 'recapture' | 'report'\n\n@customElement('building-inspection-detail-ai-measurement')\nexport class BuildingInspectionAiMeasurement extends PageView {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: grid;\n grid-template-rows: 75px 1fr;\n color: #4e5055;\n width: 100%;\n height: 100%;\n background-color: #f7f7f7;\n }\n\n * {\n box-sizing: border-box;\n }\n\n div[body] {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow-y: auto;\n padding: var(--spacing-medium);\n gap: 12px;\n }\n\n .page-title {\n text-align: center;\n font-size: 16px;\n font-weight: 700;\n color: #333;\n }\n\n .page-title span[target] {\n color: #7d2f2f;\n text-decoration: underline;\n }\n\n /* ─── 1단계: 촬영 가이드 ─── */\n .guide-container {\n max-width: 560px;\n width: 100%;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .step-badge {\n align-self: flex-start;\n background: #f7e9e9;\n color: #7d2f2f;\n font-size: 12px;\n font-weight: 700;\n padding: 4px 10px;\n border-radius: 12px;\n }\n\n .guide-title {\n font-size: 26px;\n font-weight: 800;\n color: #222;\n line-height: 1.3;\n white-space: pre-line;\n }\n\n .guide-desc {\n font-size: 13px;\n color: #777;\n }\n\n .card {\n background: #fff;\n border: 1px solid #e5e5e5;\n border-radius: 10px;\n padding: 16px;\n }\n\n .card h4 {\n margin: 0 0 10px 0;\n font-size: 14px;\n color: #333;\n }\n\n .card ul {\n margin: 0;\n padding-left: 4px;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .card ul li {\n font-size: 13px;\n color: #555;\n display: flex;\n gap: 8px;\n }\n\n .card ul li::before {\n content: '';\n flex-shrink: 0;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #7d2f2f;\n margin-top: 6px;\n }\n\n .progress-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 13px;\n color: #555;\n font-weight: 600;\n }\n\n .progress-bar {\n height: 6px;\n border-radius: 3px;\n background: #eee;\n overflow: hidden;\n }\n\n .progress-bar div {\n height: 100%;\n background: #7d2f2f;\n transition: width 0.3s;\n }\n\n .next-shot {\n font-size: 13px;\n font-weight: 700;\n color: #333;\n }\n\n .slot-grid {\n display: flex;\n gap: 8px;\n }\n\n .slot {\n flex: 1;\n aspect-ratio: 1;\n border: 1px dashed #ccc;\n border-radius: 8px;\n background: #fafafa;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: #999;\n text-align: center;\n padding: 4px;\n overflow: hidden;\n cursor: pointer;\n }\n\n .slot md-icon {\n --md-icon-size: 28px;\n color: #b5b5b5;\n }\n\n .slot img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: 6px;\n }\n\n .primary-button {\n width: 100%;\n border: none;\n border-radius: 8px;\n background: #7d2f2f;\n color: #fff;\n font-size: 16px;\n font-weight: 700;\n padding: 14px;\n cursor: pointer;\n }\n\n .primary-button:disabled {\n background: #ccc;\n cursor: default;\n }\n\n .text-button {\n border: 1px solid #ddd;\n border-radius: 8px;\n background: #fff;\n color: #555;\n font-size: 13px;\n padding: 8px 14px;\n cursor: pointer;\n }\n\n input[type='file'] {\n display: none;\n }\n\n /* ─── 2단계: 판정 결과 ─── */\n .result-body {\n display: flex;\n gap: 14px;\n align-items: flex-start;\n min-height: 0;\n }\n\n .photo-pane {\n flex: 1.1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .photo-pane .caption {\n text-align: center;\n font-size: 12px;\n color: #999;\n }\n\n .photo-main {\n border-radius: 10px;\n overflow: hidden;\n background: #000;\n display: flex;\n justify-content: center;\n max-height: 480px;\n }\n\n .photo-main img {\n max-width: 100%;\n max-height: 480px;\n object-fit: contain;\n }\n\n .photo-thumbs {\n display: flex;\n gap: 8px;\n overflow-x: auto;\n padding-bottom: 4px;\n }\n\n .photo-thumbs img {\n width: 96px;\n height: 72px;\n object-fit: cover;\n border-radius: 6px;\n cursor: pointer;\n border: 2px solid transparent;\n }\n\n .photo-thumbs img[selected] {\n border-color: #7d2f2f;\n }\n\n .items-pane {\n flex: 1.4;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .summary-banner {\n background: #f7e9e9;\n border: 1px solid #eedada;\n color: #7d2f2f;\n font-size: 13px;\n font-weight: 700;\n border-radius: 8px;\n padding: 10px 14px;\n }\n\n .group-title {\n font-size: 14px;\n font-weight: 700;\n color: #333;\n margin-top: 4px;\n }\n\n .item-card {\n display: flex;\n gap: 10px;\n align-items: flex-start;\n background: #fff;\n border: 1px solid #e5e5e5;\n border-radius: 10px;\n padding: 12px;\n cursor: pointer;\n }\n\n .item-card[selected] {\n border-color: #7d2f2f;\n box-shadow: 0 0 0 1px #7d2f2f inset;\n }\n\n .item-no {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #7d2f2f;\n color: #fff;\n font-size: 12px;\n font-weight: 700;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n\n .item-main {\n flex: 1;\n min-width: 0;\n }\n\n .item-name {\n font-size: 14px;\n font-weight: 700;\n color: #222;\n margin-bottom: 4px;\n }\n\n .item-desc {\n font-size: 12px;\n color: #777;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .chip {\n display: inline-block;\n font-size: 11px;\n font-weight: 700;\n border-radius: 4px;\n padding: 2px 6px;\n margin-right: 6px;\n background: #eef2f7;\n color: #3f71a0;\n }\n\n .chip-verdict {\n font-size: 12px;\n font-weight: 700;\n color: #555;\n }\n\n .badge {\n flex-shrink: 0;\n font-size: 12px;\n font-weight: 700;\n border-radius: 14px;\n padding: 5px 12px;\n white-space: nowrap;\n }\n\n .badge[pass] {\n background: #e8f5e9;\n color: #2e7d32;\n }\n\n .badge[fail] {\n background: #fdecea;\n color: #c62828;\n }\n\n .badge[etc] {\n background: #fff8e1;\n color: #b7791f;\n }\n\n .capture-button {\n flex-shrink: 0;\n border: none;\n border-radius: 14px;\n background: #fff3e0;\n color: #b7791f;\n font-size: 12px;\n font-weight: 700;\n padding: 6px 12px;\n cursor: pointer;\n }\n\n /* ─── 우측 패널 (상세/재촬영/리포트) ─── */\n .side-pane {\n flex: 1;\n min-width: 280px;\n max-width: 360px;\n background: #fff;\n border: 1px solid #e5e5e5;\n border-radius: 10px;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .side-pane h3 {\n margin: 0;\n font-size: 16px;\n color: #222;\n }\n\n .detail-header {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .detail-header h3 {\n font-size: 18px;\n }\n\n .detail-summary {\n font-size: 12px;\n color: #555;\n line-height: 1.7;\n white-space: pre-line;\n border-bottom: 1px solid #f0f0f0;\n padding-bottom: 10px;\n }\n\n .kv-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n }\n\n .kv {\n display: flex;\n flex-direction: column;\n gap: 2px;\n border: 1px solid #eee;\n border-radius: 8px;\n padding: 10px 12px;\n background: #fff;\n }\n\n .kv label {\n font-size: 11px;\n color: #999;\n }\n\n .kv span {\n font-size: 15px;\n font-weight: 700;\n color: #333;\n }\n\n .kv .verdict-value[pass] {\n color: #2e7d32;\n }\n\n .kv .verdict-value[fail] {\n color: #c62828;\n }\n\n .reason-box {\n display: flex;\n flex-direction: column;\n gap: 10px;\n font-size: 12px;\n line-height: 1.7;\n }\n\n .reason-verdict {\n border-left: 3px solid #7d2f2f;\n background: #fdf6f6;\n color: #333;\n padding: 8px 10px;\n }\n\n .why-box {\n background: #fff8e1;\n border: 1px solid #f4e4b5;\n border-radius: 8px;\n padding: 10px;\n font-size: 12px;\n color: #7a5c14;\n line-height: 1.6;\n }\n\n .report-counts {\n display: flex;\n text-align: center;\n border: 1px solid #eee;\n border-radius: 8px;\n overflow: hidden;\n }\n\n .report-counts div {\n flex: 1;\n padding: 10px 0;\n }\n\n .report-counts b {\n display: block;\n font-size: 20px;\n }\n\n .report-counts small {\n font-size: 11px;\n color: #888;\n }\n\n .report-counts div[pass] b {\n color: #2e7d32;\n }\n\n .report-counts div[fail] b {\n color: #c62828;\n }\n\n .report-counts div[etc] b {\n color: #b7791f;\n }\n\n .report-item {\n border-bottom: 1px solid #f0f0f0;\n font-size: 13px;\n color: #333;\n }\n\n .report-head {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 10px 0;\n cursor: pointer;\n }\n\n .report-head .report-text {\n flex: 1;\n min-width: 0;\n }\n\n .report-caret {\n --md-icon-size: 20px;\n color: #999;\n transition: transform 0.2s;\n }\n\n .report-caret[open] {\n transform: rotate(180deg);\n }\n\n .report-basis {\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 12px;\n color: #555;\n background: #f7f7f7;\n border-radius: 6px;\n padding: 10px;\n margin: 0 0 10px 0;\n }\n\n .report-basis .report-ai {\n white-space: pre-line;\n color: #333;\n }\n\n .report-basis .report-used {\n color: #888;\n }\n\n .report-item .verdict {\n font-weight: 700;\n flex-shrink: 0;\n }\n\n .report-item .verdict[pass] {\n color: #2e7d32;\n }\n\n .report-item .verdict[fail] {\n color: #c62828;\n }\n\n .report-item .verdict[etc] {\n color: #b7791f;\n }\n\n /* ─── 로딩 오버레이 ─── */\n .loading-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 2000;\n }\n\n .loading-overlay .box {\n background: #fff;\n padding: 32px 48px;\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n font-size: 14px;\n color: #555;\n }\n\n .empty-state {\n text-align: center;\n color: #999;\n font-size: 14px;\n padding: 60px 0;\n }\n `\n ]\n\n @state() project: any = {}\n @state() buildingInspection: any = {}\n @state() buildingInspectionId: string = ''\n\n @state() guide: any = null // plan-shots 응답 {shots, total_shots, markdown}\n @state() photos: { file: File; url: string }[] = []\n @state() result: any = null // inspect 응답\n @state() mainPhotoIndex: number = 0\n\n @state() panel: PanelMode = 'none'\n @state() selectedItem: any = null\n @state() recaptureBase: number = 0 // 재촬영 패널 진입 시점의 사진 수\n @state() expandedReportId: string | null = null // 종합 리포트에서 펼친 항목(아코디언)\n\n @state() loading: boolean = false\n @state() loadingText: string = ''\n\n @query('#photoInput') private photoInputEl!: HTMLInputElement\n\n /* 슬롯 클릭으로 선택기를 연 경우 대상 슬롯 인덱스 (null이면 뒤에 추가) */\n private pendingSlotIndex: number | null = null\n\n get context() {\n return {\n title: '검측 관리 상세 - AI 자동 검측'\n }\n }\n\n /* 엔진에 보낼 검측요청서: 체크리스트 항목 → {item_id, category, text} */\n get engineChecklist() {\n const items = this.buildingInspection?.checklist?.checklistItems || []\n return [...items]\n .sort((a, b) => (a.sequence || 0) - (b.sequence || 0))\n .map(item => ({\n item_id: item.id,\n category: [item.mainType, item.detailType].filter(Boolean).join(' · '),\n text: item.name || ''\n }))\n }\n\n render() {\n return html`\n <building-inspection-detail-header\n .buildingInspectionId=${this.buildingInspection?.id}\n .buildingLevelId=${this.buildingInspection?.buildingLevel?.id}\n .projectName=${this.project.name}\n .buildingName=${this.buildingInspection?.buildingLevel?.building?.name}\n .buildingLevelFloor=${this.buildingInspection?.buildingLevel?.floor}\n .projectId=${this.project.id}\n ></building-inspection-detail-header>\n\n <div body>\n <div class=\"page-title\">\n AI 자동 검측 – ${this.buildingInspection?.checklist?.location || ''}\n <span target>${this.buildingInspection?.checklist?.name || ''}</span>\n </div>\n\n ${this.result ? this._renderResult() : this._renderGuide()}\n </div>\n\n <!-- 모바일에서 촬영/앨범 선택이 함께 뜨도록 capture 속성 없이 사용 -->\n <input id=\"photoInput\" type=\"file\" accept=\"image/*\" multiple @change=${this._onPhotosSelected} />\n\n ${\n this.loading\n ? html`\n <div class=\"loading-overlay\">\n <div class=\"box\">\n <md-circular-progress indeterminate></md-circular-progress>\n <span>${this.loadingText}</span>\n </div>\n </div>\n `\n : ''\n }\n `\n }\n\n /* ─── 1단계: 촬영 가이드 화면 ─── */\n private _renderGuide() {\n if (!this.guide) {\n return html`<div class=\"empty-state\">촬영 가이드를 준비 중입니다...</div>`\n }\n\n const shots = this.guide.shots || []\n const total = this.guide.total_shots || shots.length\n const taken = this.photos.length\n const current = shots[Math.min(taken, shots.length - 1)]\n const done = taken >= total\n\n return html`\n <div class=\"guide-container\">\n <div class=\"step-badge\">${Math.min(taken + 1, total)}단계 · ${current?.target || '촬영'}</div>\n <div class=\"guide-title\">${current?.target || ''}${done ? ' 촬영 완료' : ''}</div>\n <div class=\"guide-desc\">이 사진을 토대로 AI가 적용할 체크리스트를 결정하고 일부를 자동 판정합니다.</div>\n\n <div class=\"card\">\n <h4>촬영 가이드</h4>\n <ul>\n ${shots.map(s => html`<li>${s.target} — ${s.how}</li>`)}\n </ul>\n </div>\n\n <div class=\"card\" style=\"display: flex; flex-direction: column; gap: 10px;\">\n <div class=\"progress-row\">\n <span>사진 진행</span>\n <span>${taken} / ${total}</span>\n </div>\n <div class=\"progress-bar\"><div style=\"width: ${total ? (taken / total) * 100 : 0}%\"></div></div>\n ${!done ? html`<div class=\"next-shot\">다음 촬영: ${current?.how || current?.target || ''}</div>` : ''}\n <div class=\"slot-grid\">\n ${shots.map(\n (s, i) => html`\n <div class=\"slot\" @click=${() => this._openPhotoPicker(i)}>\n ${\n this.photos[i]\n ? html`<img src=${this.photos[i].url} alt=${s.target} />`\n : html`<md-icon>add_a_photo</md-icon>${s.target}`\n }\n </div>\n `\n )}\n </div>\n </div>\n\n <button class=\"primary-button\" ?disabled=${taken === 0} @click=${() => this._runInspection()}>\n 사진 선택 ${taken ? `(${taken}/${total})` : ''}\n </button>\n ${\n taken > 0\n ? html`\n <div style=\"display: flex; justify-content: flex-end;\">\n <button class=\"text-button\" @click=${this._resetPhotos}>사진 초기화</button>\n </div>\n `\n : ''\n }\n </div>\n `\n }\n\n /* ─── 2단계: 판정 결과 화면 ─── */\n private _renderResult() {\n const items = this._sortedItems()\n const autoItems = items.filter(it => it.verdict === 'pass' || it.verdict === 'fail')\n const moreItems = items.filter(it => it.verdict !== 'pass' && it.verdict !== 'fail')\n\n // 클릭한 항목의 used_images만 표시 (선택 없으면 전체 항목 합집합). used_images는 전체 사진 기준 1-based\n const focusItems = this.selectedItem ? [this.selectedItem] : items\n const usedNos = new Set<number>()\n for (const it of focusItems) for (const n of it.used_images || []) usedNos.add(n)\n const usedPhotos = this.photos.map((photo, i) => ({ photo, no: i + 1 })).filter(x => usedNos.has(x.no))\n const mainPhoto = usedPhotos[this.mainPhotoIndex]\n\n return html`\n <div class=\"result-body\">\n <div class=\"photo-pane\">\n <div class=\"caption\">판정에 사용된 사진</div>\n <div class=\"photo-main\">${mainPhoto ? html`<img src=${mainPhoto.photo.url} alt=\"현장 사진\" />` : ''}</div>\n <div class=\"photo-thumbs\">\n ${usedPhotos.map(\n (x, i) => html`\n <img\n src=${x.photo.url}\n alt=\"사진 ${x.no}\"\n ?selected=${i === this.mainPhotoIndex}\n @click=${() => (this.mainPhotoIndex = i)}\n />\n `\n )}\n </div>\n </div>\n\n <div class=\"items-pane\">\n <div class=\"summary-banner\">\n 적용 항목 ${items.length}개 · 자동 판정 ${autoItems.length}개 · 추가 촬영 ${moreItems.length}개\n </div>\n\n ${\n autoItems.length\n ? html`\n <div class=\"group-title\">자동 판정 완료 (${autoItems.length})</div>\n ${autoItems.map((it, i) => this._renderItemCard(it, i + 1))}\n `\n : ''\n }\n ${\n moreItems.length\n ? html`\n <div class=\"group-title\">추가 촬영 필요 (${moreItems.length} 남음)</div>\n ${moreItems.map((it, i) => this._renderItemCard(it, i + 1))}\n `\n : ''\n }\n\n <button class=\"primary-button\" @click=${this._openReport}>종합 검사 리포트</button>\n </div>\n\n ${this.panel !== 'none' ? this._renderSidePane() : ''}\n </div>\n `\n }\n\n private _renderItemCard(item: any, no: number) {\n const auto = item.verdict === 'pass' || item.verdict === 'fail'\n return html`\n <div class=\"item-card\" ?selected=${this.selectedItem?.item_id === item.item_id} @click=${() => this._openDetail(item)}>\n <div class=\"item-no\">${no}</div>\n <div class=\"item-main\">\n <div class=\"item-name\">${item.text}</div>\n <div>\n <span class=\"chip\">${ROUTING_LABEL[item.routing] || item.routing}</span>\n <span class=\"chip-verdict\">${VERDICT_LABEL[item.verdict] || item.verdict}</span>\n </div>\n <div class=\"item-desc\">${item.observation ? `관찰: ${item.observation}` : item.reason || ''}</div>\n </div>\n ${\n auto\n ? html`\n <div class=\"badge\" ?pass=${item.verdict === 'pass'} ?fail=${item.verdict === 'fail'}>\n ${VERDICT_LABEL[item.verdict]}\n </div>\n `\n : item.verdict === 'hold'\n ? html`\n <button\n class=\"capture-button\"\n @click=${(e: Event) => {\n e.stopPropagation()\n this._openRecapture(item)\n }}\n >\n 촬영하기\n </button>\n `\n : html`<div class=\"badge\" etc>${VERDICT_LABEL[item.verdict] || item.verdict}</div>`\n }\n </div>\n `\n }\n\n /* ─── 우측 패널: 상세 / 재촬영 / 리포트 ─── */\n private _renderSidePane() {\n if (this.panel === 'detail' && this.selectedItem) return this._renderDetailPane(this.selectedItem)\n if (this.panel === 'recapture' && this.selectedItem) return this._renderRecapturePane(this.selectedItem)\n if (this.panel === 'report') return this._renderReportPane()\n return ''\n }\n\n private _renderDetailPane(item: any) {\n const auto = item.verdict === 'pass' || item.verdict === 'fail'\n const routingLabel = ROUTING_LABEL[item.routing] || item.routing\n const verdictLabel = VERDICT_LABEL[item.verdict] || item.verdict\n\n return html`\n <div class=\"side-pane\">\n <div class=\"detail-header\">\n <span class=\"badge\" ?pass=${item.verdict === 'pass'} ?fail=${item.verdict === 'fail'} ?etc=${!auto}>\n ${routingLabel}\n </span>\n <h3>${verdictLabel}</h3>\n </div>\n <div class=\"detail-summary\">${(item.observation || item.ai_report || '').trim()}</div>\n <div class=\"kv-grid\">\n <div class=\"kv\">\n <label>판정</label>\n <span class=\"verdict-value\" ?pass=${item.verdict === 'pass'} ?fail=${item.verdict === 'fail'}>\n ${verdictLabel || '-'}\n </span>\n </div>\n ${\n item.confidence != null\n ? html`\n <div class=\"kv\">\n <label>신뢰도</label>\n <span>${Math.round(item.confidence * 100)}%</span>\n </div>\n `\n : ''\n }\n <div class=\"kv\">\n <label>처리</label>\n <span>${ROUTING_LABEL[item.routing] || item.routing || '-'}</span>\n </div>\n </div>\n\n <div class=\"reason-box\">\n <div class=\"reason-verdict\">\n <label style=\"font-size: 11px;color: #7d2f2f; display: block; font-weight: bold;\">판단 근거</label>\n ${item.reason}\n </div>\n </div>\n\n <button class=\"text-button\" @click=${this._closePanel}>닫기</button>\n </div>\n `\n }\n\n private _renderRecapturePane(item: any) {\n const shots = item.recapture_shots?.length\n ? item.recapture_shots\n : [{ target: '추가 사진', how: '항목이 잘 보이도록 촬영해주세요.' }]\n const taken = this.photos.length - this.recaptureBase\n const total = shots.length\n\n return html`\n <div class=\"side-pane\">\n <h3>${item.text}</h3>\n <div class=\"why-box\">\n <b>왜 추가 촬영이 필요한가요?</b><br />\n ${item.reason || '판정을 위해 추가 사진이 필요합니다.'}\n </div>\n <div>\n <h4 style=\"margin: 0 0 8px 0; font-size: 13px;\">촬영 가이드</h4>\n <ul\n style=\"margin: 0; padding-left: 18px; font-size: 12px; color: #555; display: flex; flex-direction: column; gap: 6px;\"\n >\n ${shots.map(s => html`<li>${s.target} — ${s.how}</li>`)}\n </ul>\n </div>\n <div class=\"progress-row\">\n <span>사진 진행</span>\n <span>${Math.min(taken, total)} / ${total}</span>\n </div>\n <div class=\"progress-bar\"><div style=\"width: ${total ? Math.min(taken / total, 1) * 100 : 0}%\"></div></div>\n <div class=\"slot-grid\">\n ${shots.map((s, i) => {\n const photo = this.photos[this.recaptureBase + i]\n return html`\n <div class=\"slot\" @click=${() => this._openPhotoPicker(this.recaptureBase + i)}>\n ${photo ? html`<img src=${photo.url} alt=${s.target} />` : html`<md-icon>add_a_photo</md-icon>${s.target}`}\n </div>\n `\n })}\n </div>\n ${\n taken > 0\n ? html`<button class=\"primary-button\" @click=${() => this._runInspection()}>재검사 실행 (${taken}장)</button>`\n : ''\n }\n <button class=\"text-button\" @click=${this._closePanel}>닫기</button>\n </div>\n `\n }\n\n private _renderReportPane() {\n const items = this._sortedItems()\n const summary = this.result?.summary || {}\n const etcCount = (summary.hold || 0) + (summary.pending || 0) + (summary.error || 0)\n\n return html`\n <div class=\"side-pane\">\n <h3>종합 검사 리포트</h3>\n <div class=\"report-counts\">\n <div pass><b>${summary.pass || 0}</b><small>적합</small></div>\n <div fail><b>${summary.fail || 0}</b><small>부적합</small></div>\n <div etc><b>${etcCount}</b><small>미검사</small></div>\n </div>\n <div style=\"overflow-y: auto; max-height: 380px;\">\n ${items.map((it, i) => {\n const expanded = this.expandedReportId === it.item_id\n return html`\n <div class=\"report-item\">\n <div class=\"report-head\" @click=${() => this._toggleReportItem(it.item_id)}>\n <span class=\"report-text\">${i + 1}. ${it.text}</span>\n <span\n class=\"verdict\"\n ?pass=${it.verdict === 'pass'}\n ?fail=${it.verdict === 'fail'}\n ?etc=${it.verdict !== 'pass' && it.verdict !== 'fail'}\n >\n ${VERDICT_LABEL[it.verdict] || it.verdict}\n </span>\n <md-icon class=\"report-caret\" ?open=${expanded}>expand_more</md-icon>\n </div>\n ${\n expanded\n ? html`\n <div class=\"report-basis\">\n ${it.ai_report ? html`<div class=\"report-ai\">${(it.ai_report || '').trim()}</div>` : ''}\n ${it.observation ? html`<div>관찰: ${it.observation}</div>` : ''}\n ${it.reason ? html`<div>판단: ${it.reason}</div>` : ''}\n ${\n it.used_images?.length\n ? html`<div class=\"report-used\">근거 사진: ${it.used_images.map(n => `#${n}`).join(', ')}</div>`\n : ''\n }\n </div>\n `\n : ''\n }\n </div>\n `\n })}\n </div>\n <button class=\"primary-button\" @click=${this._registerInspection}>검사 등록</button>\n <button class=\"text-button\" @click=${this._closePanel}>닫기</button>\n </div>\n `\n }\n\n /* ─── 라이프사이클 ─── */\n async pageUpdated(changes: any, lifecycle: PageLifecycle) {\n if (this.active) {\n this._resetAll()\n this.buildingInspectionId = lifecycle.resourceId || ''\n await this.initBuildingInspection(this.buildingInspectionId)\n await this._loadShotGuide()\n }\n }\n\n async initBuildingInspection(buildingInspectionId: string = '') {\n const response = await client.query({\n query: gql`\n query BuildingInspection($buildingInspectionId: String!) {\n buildingInspection(id: $buildingInspectionId) {\n id\n status\n checklist {\n id\n name\n location\n checklistItems {\n id\n sequence\n mainType\n detailType\n name\n }\n }\n buildingLevel {\n id\n floor\n building {\n id\n name\n buildingComplex {\n id\n }\n }\n }\n }\n }\n `,\n variables: { buildingInspectionId }\n })\n\n if (response.errors) return\n\n this.buildingInspection = response.data.buildingInspection\n\n await this._getProjectByBuildingComplexId(this.buildingInspection?.buildingLevel?.building?.buildingComplex?.id)\n }\n\n private async _getProjectByBuildingComplexId(buildingComplexId) {\n const response = await client.query({\n query: gql`\n query ProjectByBuildingComplexId($buildingComplexId: String!) {\n project: projectByBuildingComplexId(buildingComplexId: $buildingComplexId) {\n id\n name\n }\n }\n `,\n variables: { buildingComplexId }\n })\n\n if (response.errors) return\n\n this.project = response.data.project\n }\n\n /* ─── 엔진 호출 ─── */\n\n /* 엔진 실행 공통 호출: input(JSON) + 사진 파일들을 multipart로 전송 */\n private async _callEngine(input: any, files: File[] = []) {\n const form = new FormData()\n form.append('input', JSON.stringify(input))\n for (const file of files) form.append('files', file, file.name)\n\n const response = await fetch(ENGINE_RUN_URL, {\n method: 'POST',\n headers: { Authorization: ENGINE_AUTH },\n body: form\n })\n const raw = await response.json()\n const data = raw?.result || {}\n if (data?.status !== 'success') {\n throw new Error(data?.error || raw?.error || 'AI 엔진 호출에 실패했습니다.')\n }\n return data.result\n }\n\n /* [1단계] 촬영 가이드 생성 (plan-shots) */\n private async _loadShotGuide() {\n const checklist = this.engineChecklist\n if (!checklist.length) {\n notify({ message: '체크리스트 항목이 없습니다.', level: 'warn' })\n return\n }\n\n try {\n this.loading = true\n this.loadingText = 'AI 촬영 가이드 생성 중...'\n this.guide = await this._callEngine({ action: 'plan-shots', checklist })\n } catch (error) {\n console.error('촬영 가이드 생성 실패:', error)\n notify({ message: (error as Error).message, level: 'error' })\n } finally {\n this.loading = false\n }\n }\n\n /* [2단계] 자동 판정 실행 (inspect)\n * - 최초 판정: 전체 사진 + 전체 체크리스트\n * - 재검사(재촬영 패널): 이번에 새로 찍은 사진만 + 해당 항목만 재판정 후 결과 병합 */\n private async _runInspection() {\n const isRecapture = this.panel === 'recapture' && !!this.selectedItem\n // 재검사는 recaptureBase 이후에 찍은 사진만 전송\n const files = (isRecapture ? this.photos.slice(this.recaptureBase) : this.photos).map(p => p.file)\n if (!files.length) {\n notify({ message: '촬영된 사진이 없습니다.', level: 'warn' })\n return\n }\n const checklist = isRecapture\n ? this.engineChecklist.filter(c => c.item_id === this.selectedItem.item_id)\n : this.engineChecklist\n\n try {\n this.loading = true\n this.loadingText = 'AI 자동 판정 중... (최대 1~2분 소요)'\n const result = await this._callEngine({ action: 'inspect', checklist }, files)\n\n if (isRecapture) {\n this._mergeRecaptureResult(result)\n } else {\n this.result = result\n }\n this.panel = 'none'\n this.selectedItem = null\n this.mainPhotoIndex = 0\n } catch (error) {\n console.error('AI 자동 판정 실패:', error)\n notify({ message: (error as Error).message, level: 'error' })\n } finally {\n this.loading = false\n }\n }\n\n /* 재검사(부분 전송) 결과를 기존 전체 결과에 병합\n * - used_images는 전송한 부분집합 기준 1-based → 전체 사진 인덱스로 보정(recaptureBase 가산)\n * - 해당 항목만 교체 후 summary 재계산 */\n private _mergeRecaptureResult(result: any) {\n const base = this.recaptureBase\n const updated = (result?.items_sorted || result?.items || []).map((it: any) => ({\n ...it,\n used_images: (it.used_images || []).map((n: number) => n + base)\n }))\n const byId = new Map(updated.map((it: any) => [it.item_id, it]))\n const replace = (arr: any[]) => (arr || []).map(it => byId.get(it.item_id) || it)\n\n const items = replace(this.result?.items)\n const itemsSorted = this.result?.items_sorted ? replace(this.result.items_sorted) : undefined\n\n const summary: Record<string, number> = { pass: 0, fail: 0, hold: 0, pending: 0, error: 0 }\n for (const it of itemsSorted || items) summary[it.verdict] = (summary[it.verdict] || 0) + 1\n\n this.result = { ...this.result, items, ...(itemsSorted ? { items_sorted: itemsSorted } : {}), summary }\n }\n\n /* ─── 사진 선택 ─── */\n /* 슬롯 클릭 → 사진 선택기 열기 (모바일: 촬영/앨범 선택 팝업, 채워진 슬롯이면 교체) */\n private _openPhotoPicker(slotIndex: number | null = null) {\n this.pendingSlotIndex = slotIndex\n this.photoInputEl?.click()\n }\n\n private _onPhotosSelected(event: Event) {\n const input = event.target as HTMLInputElement\n const files = Array.from(input?.files || []).filter(f => f.type.startsWith('image/') || /\\.heic$/i.test(f.name))\n input.value = ''\n const slotIndex = this.pendingSlotIndex\n this.pendingSlotIndex = null\n if (!files.length) return\n\n // 채워진 슬롯을 클릭한 경우 → 해당 사진 교체 (첫 파일만 사용)\n if (slotIndex !== null && slotIndex < this.photos.length) {\n URL.revokeObjectURL(this.photos[slotIndex].url)\n const next = [...this.photos]\n next[slotIndex] = { file: files[0], url: URL.createObjectURL(files[0]) }\n this.photos = next\n return\n }\n\n // 빈 슬롯/추가 → 순서대로 뒤에 추가\n // 엔진 제한은 요청(호출)당 MAX_IMAGES장. 재검사는 새로 찍은 사진만 별도 전송되므로\n // 누적 합계가 아니라 이번 회차(최초=전체, 재검사=recaptureBase 이후) 기준으로만 제한한다.\n const batchBase = this.panel === 'recapture' ? this.recaptureBase : 0\n const cap = batchBase + MAX_IMAGES\n if (this.photos.length + files.length > cap) {\n notify({ message: `사진은 회차당 최대 ${MAX_IMAGES}장까지 사용할 수 있습니다.`, level: 'warn' })\n files.length = Math.max(0, cap - this.photos.length)\n if (!files.length) return\n }\n\n this.photos = [...this.photos, ...files.map(file => ({ file, url: URL.createObjectURL(file) }))]\n }\n\n private _resetPhotos = () => {\n this.photos.forEach(p => URL.revokeObjectURL(p.url))\n this.photos = []\n }\n\n private _resetAll() {\n this._resetPhotos()\n this.guide = null\n this.result = null\n this.panel = 'none'\n this.selectedItem = null\n this.mainPhotoIndex = 0\n this.recaptureBase = 0\n }\n\n /* ─── 패널 열기/닫기 ─── */\n private _openDetail(item: any) {\n // 보류(hold)는 추가 촬영이 필요한 케이스 → 상세 대신 추가 촬영 UI를 바로 표시\n if (item.verdict === 'hold') {\n this._openRecapture(item)\n return\n }\n this.selectedItem = item\n this.mainPhotoIndex = 0 // 선택 항목의 첫 사용 사진부터 표시\n this.panel = 'detail'\n }\n\n private _openRecapture(item: any) {\n this.selectedItem = item\n this.recaptureBase = this.photos.length\n this.panel = 'recapture'\n }\n\n private _openReport = () => {\n this.panel = 'report'\n this.selectedItem = null\n this.expandedReportId = null\n }\n\n /* 종합 리포트 항목 펼치기/접기 (한 번에 하나만 펼침) */\n private _toggleReportItem(id: string) {\n this.expandedReportId = this.expandedReportId === id ? null : id\n }\n\n private _closePanel = () => {\n this.panel = 'none'\n this.selectedItem = null\n }\n\n private _sortedItems(): any[] {\n return this.result?.items_sorted || this.result?.items || []\n }\n\n /* ─── [6단계] 검사 등록: 감리자 판정 자동 반영 + AI판단 근거 첨부 ─── */\n private async _registerInspection() {\n const items = this._sortedItems()\n if (!items.length) {\n notify({ message: '판정 결과가 없습니다.', level: 'warn' })\n return\n }\n // 적합/부적합으로 자동 판정된 항목만 반영 (보류/미지원/오류는 미검사로 건너뜀)\n const judged = items.filter(it => it.verdict === 'pass' || it.verdict === 'fail')\n\n try {\n this.loading = true\n this.loadingText = '검사 결과 등록 중...'\n\n // 1) 감리자 적합/부적합 자동 채움 (적합/부적합 판정된 항목만, 없으면 건너뜀)\n if (judged.length) {\n const response = await client.mutate({\n mutation: gql`\n mutation UpdateChecklistItemsAiJudgment($items: [ChecklistItemAiJudgment!]!) {\n updateChecklistItemsAiJudgment(items: $items)\n }\n `,\n variables: {\n items: judged.map(it => ({\n id: it.item_id,\n supervisoryConfirmStatus: it.verdict === 'pass' ? 'T' : 'F'\n }))\n }\n })\n\n if (response.errors) throw new Error(response.errors[0]?.message || '검사 등록에 실패했습니다.')\n }\n\n // 2) 항목별 첨부: 판단 근거(AI판단 텍스트) + 근거 사진 (판정 여부와 무관하게 전체 항목)\n const attachments: any[] = []\n for (const it of items) {\n if (it.ai_report) {\n attachments.push({\n file: new File([it.ai_report], `AI판단_${(it.text || it.item_id).slice(0, 30)}.txt`, { type: 'text/plain' }),\n refBy: it.item_id,\n refType: 'ChecklistItem',\n description: 'AI판단'\n })\n }\n for (const n of it.used_images || []) {\n const photo = this.photos[n - 1]\n if (photo) {\n attachments.push({ file: photo.file, refBy: it.item_id, refType: 'ChecklistItem', description: 'AI판단' })\n }\n }\n }\n\n if (attachments.length) {\n const attachResponse = await client.mutate({\n mutation: gql`\n mutation CreateAttachments($attachments: [NewAttachment!]!) {\n createAttachments(attachments: $attachments) {\n id\n }\n }\n `,\n variables: { attachments },\n context: { hasUpload: true }\n })\n\n if (attachResponse.errors) throw new Error(attachResponse.errors[0]?.message || 'AI판단 자료 첨부에 실패했습니다.')\n }\n\n notify({ message: `검사 결과를 등록하였습니다. (자동 판정 ${judged.length}건 반영)` })\n\n // 등록 후 체크리스트 화면으로 이동\n navigate(`building-inspection-detail-checklist/${this.buildingInspectionId}`)\n } catch (error) {\n console.error('검사 등록 실패:', error)\n notify({ message: (error as Error).message, level: 'error' })\n } finally {\n this.loading = false\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"building-inspection-detail-ai-measurement.js","sourceRoot":"","sources":["../../../client/pages/building-inspection/building-inspection-detail-ai-measurement.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 검측 관리 상세 - AI 자동 검측\n *\n * 검측 체크리스트 항목을 AI 엔진(inspection-ai)에 보내:\n * 1) 촬영 가이드(plan-shots)를 받아 단계별 촬영 슬롯을 표시하고\n * 2) 촬영된 사진으로 자동 판정(inspect)을 실행한 뒤\n * 3) 항목별 상세 / 추가 촬영(재검사) / 종합 리포트를 거쳐\n * 4) 검사 등록 시 감리자 적합/부적합 자동 반영 + AI판단 근거를 첨부한다.\n */\nimport '@material/web/icon/icon.js'\nimport '@material/web/progress/circular-progress.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, state, query } from 'lit/decorators.js'\n\nimport { PageView, navigate } from '@operato/shell'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { PageLifecycle } from '@operato/shell/dist/src/app/pages/page-view'\nimport { client } from '@operato/graphql'\nimport { notify } from '@operato/layout'\n\nimport './component/building-inspection-detail-header'\n\nconst ENGINE_BASE_URL = 'https://hatiolab-korea-uni.nruing.com'\nconst ENGINE_RUN_URL = `${ENGINE_BASE_URL}/api/run/inspection-ai`\nconst ENGINE_AUTH = `Basic ${btoa('admin:admin1234')}`\nconst MAX_IMAGES = 8\n\n/* 엔진 verdict(기계값) → 화면 라벨. pass/fail만 합/불로 자동 체크, 나머지(보류/미지원/오류)는 감리자 판단 */\nconst VERDICT_LABEL = {\n pass: '적합',\n fail: '부적합',\n hold: '보류',\n pending: '미지원',\n error: '오류'\n}\n\n/* 엔진 routing(기계값) → 화면 라벨 */\nconst ROUTING_LABEL = {\n vlm: 'AI 사진판독',\n cv: '자동 측정',\n cv_missing: '자동 측정 누락'\n}\n\ntype PanelMode = 'none' | 'detail' | 'recapture' | 'report'\n\n@customElement('building-inspection-detail-ai-measurement')\nexport class BuildingInspectionAiMeasurement extends PageView {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: grid;\n grid-template-rows: 75px 1fr;\n color: #4e5055;\n width: 100%;\n height: 100%;\n background-color: #f7f7f7;\n }\n\n * {\n box-sizing: border-box;\n }\n\n div[body] {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow-y: auto;\n padding: var(--spacing-medium);\n gap: 12px;\n }\n\n .page-title {\n text-align: center;\n font-size: 16px;\n font-weight: 700;\n color: #333;\n }\n\n .page-title span[target] {\n color: #7d2f2f;\n text-decoration: underline;\n }\n\n /* ─── 1단계: 촬영 가이드 ─── */\n .guide-container {\n max-width: 560px;\n width: 100%;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .step-badge {\n align-self: flex-start;\n background: #f7e9e9;\n color: #7d2f2f;\n font-size: 12px;\n font-weight: 700;\n padding: 4px 10px;\n border-radius: 12px;\n }\n\n .guide-title {\n font-size: 26px;\n font-weight: 800;\n color: #222;\n line-height: 1.3;\n white-space: pre-line;\n }\n\n .guide-desc {\n font-size: 13px;\n color: #777;\n }\n\n .card {\n background: #fff;\n border: 1px solid #e5e5e5;\n border-radius: 10px;\n padding: 16px;\n }\n\n .card h4 {\n margin: 0 0 10px 0;\n font-size: 14px;\n color: #333;\n }\n\n .card ul {\n margin: 0;\n padding-left: 4px;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .card ul li {\n font-size: 13px;\n color: #555;\n display: flex;\n gap: 8px;\n }\n\n .card ul li::before {\n content: '';\n flex-shrink: 0;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #7d2f2f;\n margin-top: 6px;\n }\n\n .progress-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 13px;\n color: #555;\n font-weight: 600;\n }\n\n .progress-bar {\n height: 6px;\n border-radius: 3px;\n background: #eee;\n overflow: hidden;\n }\n\n .progress-bar div {\n height: 100%;\n background: #7d2f2f;\n transition: width 0.3s;\n }\n\n .next-shot {\n font-size: 13px;\n font-weight: 700;\n color: #333;\n }\n\n .slot-grid {\n display: flex;\n gap: 8px;\n }\n\n .slot {\n flex: 1;\n aspect-ratio: 1;\n border: 1px dashed #ccc;\n border-radius: 8px;\n background: #fafafa;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: #999;\n text-align: center;\n padding: 4px;\n overflow: hidden;\n cursor: pointer;\n }\n\n .slot md-icon {\n --md-icon-size: 28px;\n color: #b5b5b5;\n }\n\n .slot img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: 6px;\n }\n\n .primary-button {\n width: 100%;\n border: none;\n border-radius: 8px;\n background: #7d2f2f;\n color: #fff;\n font-size: 16px;\n font-weight: 700;\n padding: 14px;\n cursor: pointer;\n }\n\n .primary-button:disabled {\n background: #ccc;\n cursor: default;\n }\n\n .text-button {\n border: 1px solid #ddd;\n border-radius: 8px;\n background: #fff;\n color: #555;\n font-size: 13px;\n padding: 8px 14px;\n cursor: pointer;\n }\n\n input[type='file'] {\n display: none;\n }\n\n /* ─── 2단계: 판정 결과 ─── */\n .result-body {\n display: flex;\n gap: 14px;\n align-items: flex-start;\n min-height: 0;\n }\n\n .photo-pane {\n flex: 1.1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .photo-pane .caption {\n text-align: center;\n font-size: 12px;\n color: #999;\n }\n\n .photo-main {\n border-radius: 10px;\n overflow: hidden;\n background: #000;\n display: flex;\n justify-content: center;\n max-height: 480px;\n }\n\n .photo-main img {\n max-width: 100%;\n max-height: 480px;\n object-fit: contain;\n }\n\n .photo-thumbs {\n display: flex;\n gap: 8px;\n overflow-x: auto;\n padding-bottom: 4px;\n }\n\n .photo-thumbs img {\n width: 96px;\n height: 72px;\n object-fit: cover;\n border-radius: 6px;\n cursor: pointer;\n border: 2px solid transparent;\n }\n\n .photo-thumbs img[selected] {\n border-color: #7d2f2f;\n }\n\n .items-pane {\n flex: 1.4;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .summary-banner {\n background: #f7e9e9;\n border: 1px solid #eedada;\n color: #7d2f2f;\n font-size: 13px;\n font-weight: 700;\n border-radius: 8px;\n padding: 10px 14px;\n }\n\n .group-title {\n font-size: 14px;\n font-weight: 700;\n color: #333;\n margin-top: 4px;\n }\n\n .item-card {\n display: flex;\n gap: 10px;\n align-items: flex-start;\n background: #fff;\n border: 1px solid #e5e5e5;\n border-radius: 10px;\n padding: 12px;\n cursor: pointer;\n }\n\n .item-card[selected] {\n border-color: #7d2f2f;\n box-shadow: 0 0 0 1px #7d2f2f inset;\n }\n\n .item-no {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #7d2f2f;\n color: #fff;\n font-size: 12px;\n font-weight: 700;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n\n .item-main {\n flex: 1;\n min-width: 0;\n }\n\n .item-name {\n font-size: 14px;\n font-weight: 700;\n color: #222;\n margin-bottom: 4px;\n }\n\n .item-desc {\n font-size: 12px;\n color: #777;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .chip {\n display: inline-block;\n font-size: 11px;\n font-weight: 700;\n border-radius: 4px;\n padding: 2px 6px;\n margin-right: 6px;\n background: #eef2f7;\n color: #3f71a0;\n }\n\n .chip-verdict {\n font-size: 12px;\n font-weight: 700;\n color: #555;\n }\n\n .badge {\n flex-shrink: 0;\n font-size: 12px;\n font-weight: 700;\n border-radius: 14px;\n padding: 5px 12px;\n white-space: nowrap;\n }\n\n .badge[pass] {\n background: #e8f5e9;\n color: #2e7d32;\n }\n\n .badge[fail] {\n background: #fdecea;\n color: #c62828;\n }\n\n .badge[etc] {\n background: #fff8e1;\n color: #b7791f;\n }\n\n .capture-button {\n flex-shrink: 0;\n border: none;\n border-radius: 14px;\n background: #fff3e0;\n color: #b7791f;\n font-size: 12px;\n font-weight: 700;\n padding: 6px 12px;\n cursor: pointer;\n }\n\n /* ─── 우측 패널 (상세/재촬영/리포트) ─── */\n .side-pane {\n flex: 1;\n min-width: 280px;\n max-width: 360px;\n background: #fff;\n border: 1px solid #e5e5e5;\n border-radius: 10px;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .side-pane h3 {\n margin: 0;\n font-size: 16px;\n color: #222;\n }\n\n .detail-header {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .detail-header h3 {\n font-size: 18px;\n }\n\n .detail-summary {\n font-size: 12px;\n color: #555;\n line-height: 1.7;\n white-space: pre-line;\n border-bottom: 1px solid #f0f0f0;\n padding-bottom: 10px;\n }\n\n .kv-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n }\n\n .kv {\n display: flex;\n flex-direction: column;\n gap: 2px;\n border: 1px solid #eee;\n border-radius: 8px;\n padding: 10px 12px;\n background: #fff;\n }\n\n .kv label {\n font-size: 11px;\n color: #999;\n }\n\n .kv span {\n font-size: 15px;\n font-weight: 700;\n color: #333;\n }\n\n .kv .verdict-value[pass] {\n color: #2e7d32;\n }\n\n .kv .verdict-value[fail] {\n color: #c62828;\n }\n\n .reason-box {\n display: flex;\n flex-direction: column;\n gap: 10px;\n font-size: 12px;\n line-height: 1.7;\n }\n\n .reason-verdict {\n border-left: 3px solid #7d2f2f;\n background: #fdf6f6;\n color: #333;\n padding: 8px 10px;\n }\n\n .why-box {\n background: #fff8e1;\n border: 1px solid #f4e4b5;\n border-radius: 8px;\n padding: 10px;\n font-size: 12px;\n color: #7a5c14;\n line-height: 1.6;\n }\n\n .report-counts {\n display: flex;\n text-align: center;\n border: 1px solid #eee;\n border-radius: 8px;\n overflow: hidden;\n }\n\n .report-counts div {\n flex: 1;\n padding: 10px 0;\n }\n\n .report-counts b {\n display: block;\n font-size: 20px;\n }\n\n .report-counts small {\n font-size: 11px;\n color: #888;\n }\n\n .report-counts div[pass] b {\n color: #2e7d32;\n }\n\n .report-counts div[fail] b {\n color: #c62828;\n }\n\n .report-counts div[etc] b {\n color: #b7791f;\n }\n\n .report-item {\n border-bottom: 1px solid #f0f0f0;\n font-size: 13px;\n color: #333;\n }\n\n .report-head {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 10px 0;\n cursor: pointer;\n }\n\n .report-head .report-text {\n flex: 1;\n min-width: 0;\n }\n\n .report-caret {\n --md-icon-size: 20px;\n color: #999;\n transition: transform 0.2s;\n }\n\n .report-caret[open] {\n transform: rotate(180deg);\n }\n\n .report-basis {\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 12px;\n color: #555;\n background: #f7f7f7;\n border-radius: 6px;\n padding: 10px;\n margin: 0 0 10px 0;\n }\n\n .report-basis .report-ai {\n white-space: pre-line;\n color: #333;\n }\n\n .report-basis .report-used {\n color: #888;\n }\n\n .report-item .verdict {\n font-weight: 700;\n flex-shrink: 0;\n }\n\n .report-item .verdict[pass] {\n color: #2e7d32;\n }\n\n .report-item .verdict[fail] {\n color: #c62828;\n }\n\n .report-item .verdict[etc] {\n color: #b7791f;\n }\n\n /* ─── 로딩 오버레이 ─── */\n .loading-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 2000;\n }\n\n .loading-overlay .box {\n background: #fff;\n padding: 32px 48px;\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n font-size: 14px;\n color: #555;\n }\n\n .empty-state {\n text-align: center;\n color: #999;\n font-size: 14px;\n padding: 60px 0;\n }\n `\n ]\n\n @state() project: any = {}\n @state() buildingInspection: any = {}\n @state() buildingInspectionId: string = ''\n\n @state() guide: any = null // plan-shots 응답 {shots, total_shots, markdown}\n @state() photos: { file: File; url: string }[] = []\n @state() result: any = null // inspect 응답\n @state() mainPhotoIndex: number = 0\n\n @state() panel: PanelMode = 'none'\n @state() selectedItem: any = null\n @state() recaptureBase: number = 0 // 재촬영 패널 진입 시점의 사진 수\n @state() expandedReportId: string | null = null // 종합 리포트에서 펼친 항목(아코디언)\n\n @state() loading: boolean = false\n @state() loadingText: string = ''\n\n @query('#photoInput') private photoInputEl!: HTMLInputElement\n\n /* 슬롯 클릭으로 선택기를 연 경우 대상 슬롯 인덱스 (null이면 뒤에 추가) */\n private pendingSlotIndex: number | null = null\n\n get context() {\n return {\n title: '검측 관리 상세 - AI 자동 검측'\n }\n }\n\n /* 엔진에 보낼 검측요청서: 체크리스트 항목 → {item_id, category, text} */\n get engineChecklist() {\n const items = this.buildingInspection?.checklist?.checklistItems || []\n return [...items]\n .sort((a, b) => (a.sequence || 0) - (b.sequence || 0))\n .map(item => ({\n item_id: item.id,\n category: [item.mainType, item.detailType].filter(Boolean).join(' · '),\n text: item.name || ''\n }))\n }\n\n render() {\n return html`\n <building-inspection-detail-header\n .buildingInspectionId=${this.buildingInspection?.id}\n .buildingLevelId=${this.buildingInspection?.buildingLevel?.id}\n .projectName=${this.project.name}\n .buildingName=${this.buildingInspection?.buildingLevel?.building?.name}\n .buildingLevelFloor=${this.buildingInspection?.buildingLevel?.floor}\n .projectId=${this.project.id}\n ></building-inspection-detail-header>\n\n <div body>\n <div class=\"page-title\">\n AI 자동 검측 – ${this.buildingInspection?.checklist?.location || ''}\n <span target>${this.buildingInspection?.checklist?.name || ''}</span>\n </div>\n\n ${this.result ? this._renderResult() : this._renderGuide()}\n </div>\n\n <!-- 모바일에서 촬영/앨범 선택이 함께 뜨도록 capture 속성 없이 사용 -->\n <input id=\"photoInput\" type=\"file\" accept=\"image/*\" multiple @change=${this._onPhotosSelected} />\n\n ${\n this.loading\n ? html`\n <div class=\"loading-overlay\">\n <div class=\"box\">\n <md-circular-progress indeterminate></md-circular-progress>\n <span>${this.loadingText}</span>\n </div>\n </div>\n `\n : ''\n }\n `\n }\n\n /* ─── 1단계: 촬영 가이드 화면 ─── */\n private _renderGuide() {\n if (!this.guide) {\n return html`<div class=\"empty-state\">촬영 가이드를 준비 중입니다...</div>`\n }\n\n const shots = this.guide.shots || []\n const total = this.guide.total_shots || shots.length\n const taken = this.photos.length\n const current = shots[Math.min(taken, shots.length - 1)]\n const done = taken >= total\n\n return html`\n <div class=\"guide-container\">\n <div class=\"step-badge\">${Math.min(taken + 1, total)}단계 · ${current?.target || '촬영'}</div>\n <div class=\"guide-title\">${current?.target || ''}${done ? ' 촬영 완료' : ''}</div>\n <div class=\"guide-desc\">이 사진을 토대로 AI가 적용할 체크리스트를 결정하고 일부를 자동 판정합니다.</div>\n\n <div class=\"card\">\n <h4>촬영 가이드</h4>\n <ul>\n ${shots.map(s => html`<li>${s.target} — ${s.how}</li>`)}\n </ul>\n </div>\n\n <div class=\"card\" style=\"display: flex; flex-direction: column; gap: 10px;\">\n <div class=\"progress-row\">\n <span>사진 진행</span>\n <span>${taken} / ${total}</span>\n </div>\n <div class=\"progress-bar\"><div style=\"width: ${total ? (taken / total) * 100 : 0}%\"></div></div>\n ${!done ? html`<div class=\"next-shot\">다음 촬영: ${current?.how || current?.target || ''}</div>` : ''}\n <div class=\"slot-grid\">\n ${shots.map(\n (s, i) => html`\n <div class=\"slot\" @click=${() => this._openPhotoPicker(i)}>\n ${\n this.photos[i]\n ? html`<img src=${this.photos[i].url} alt=${s.target} />`\n : html`<md-icon>add_a_photo</md-icon>${s.target}`\n }\n </div>\n `\n )}\n </div>\n </div>\n\n <button class=\"primary-button\" ?disabled=${taken === 0} @click=${() => this._runInspection()}>\n 사진 선택 ${taken ? `(${taken}/${total})` : ''}\n </button>\n ${\n taken > 0\n ? html`\n <div style=\"display: flex; justify-content: flex-end;\">\n <button class=\"text-button\" @click=${this._resetPhotos}>사진 초기화</button>\n </div>\n `\n : ''\n }\n </div>\n `\n }\n\n /* ─── 2단계: 판정 결과 화면 ─── */\n private _renderResult() {\n const items = this._sortedItems()\n const autoItems = items.filter(it => it.verdict === 'pass' || it.verdict === 'fail')\n const moreItems = items.filter(it => it.verdict !== 'pass' && it.verdict !== 'fail')\n\n // 클릭한 항목의 used_images만 표시 (선택 없으면 전체 항목 합집합). used_images는 전체 사진 기준 1-based\n const focusItems = this.selectedItem ? [this.selectedItem] : items\n const usedNos = new Set<number>()\n for (const it of focusItems) for (const n of it.used_images || []) usedNos.add(n)\n const usedPhotos = this.photos.map((photo, i) => ({ photo, no: i + 1 })).filter(x => usedNos.has(x.no))\n const mainPhoto = usedPhotos[this.mainPhotoIndex]\n\n return html`\n <div class=\"result-body\">\n <div class=\"photo-pane\">\n <div class=\"caption\">판정에 사용된 사진</div>\n <div class=\"photo-main\">${mainPhoto ? html`<img src=${mainPhoto.photo.url} alt=\"현장 사진\" />` : ''}</div>\n <div class=\"photo-thumbs\">\n ${usedPhotos.map(\n (x, i) => html`\n <img\n src=${x.photo.url}\n alt=\"사진 ${x.no}\"\n ?selected=${i === this.mainPhotoIndex}\n @click=${() => (this.mainPhotoIndex = i)}\n />\n `\n )}\n </div>\n </div>\n\n <div class=\"items-pane\">\n <div class=\"summary-banner\">\n 적용 항목 ${items.length}개 · 자동 판정 ${autoItems.length}개 · 추가 촬영 ${moreItems.length}개\n </div>\n\n ${\n autoItems.length\n ? html`\n <div class=\"group-title\">자동 판정 완료 (${autoItems.length})</div>\n ${autoItems.map((it, i) => this._renderItemCard(it, i + 1))}\n `\n : ''\n }\n ${\n moreItems.length\n ? html`\n <div class=\"group-title\">추가 촬영 필요 (${moreItems.length} 남음)</div>\n ${moreItems.map((it, i) => this._renderItemCard(it, i + 1))}\n `\n : ''\n }\n\n <button class=\"primary-button\" @click=${this._openReport}>종합 검사 리포트</button>\n </div>\n\n ${this.panel !== 'none' ? this._renderSidePane() : ''}\n </div>\n `\n }\n\n private _renderItemCard(item: any, no: number) {\n const auto = item.verdict === 'pass' || item.verdict === 'fail'\n return html`\n <div class=\"item-card\" ?selected=${this.selectedItem?.item_id === item.item_id} @click=${() => this._openDetail(item)}>\n <div class=\"item-no\">${no}</div>\n <div class=\"item-main\">\n <div class=\"item-name\">${item.text}</div>\n <div>\n <span class=\"chip\">${ROUTING_LABEL[item.routing] || item.routing}</span>\n <span class=\"chip-verdict\">${VERDICT_LABEL[item.verdict] || item.verdict}</span>\n </div>\n <div class=\"item-desc\">${item.observation ? `관찰: ${item.observation}` : item.reason || ''}</div>\n </div>\n ${\n auto\n ? html`\n <div class=\"badge\" ?pass=${item.verdict === 'pass'} ?fail=${item.verdict === 'fail'}>\n ${VERDICT_LABEL[item.verdict]}\n </div>\n `\n : item.verdict === 'hold'\n ? html`\n <button\n class=\"capture-button\"\n @click=${(e: Event) => {\n e.stopPropagation()\n this._openRecapture(item)\n }}\n >\n 촬영하기\n </button>\n `\n : html`<div class=\"badge\" etc>${VERDICT_LABEL[item.verdict] || item.verdict}</div>`\n }\n </div>\n `\n }\n\n /* ─── 우측 패널: 상세 / 재촬영 / 리포트 ─── */\n private _renderSidePane() {\n if (this.panel === 'detail' && this.selectedItem) return this._renderDetailPane(this.selectedItem)\n if (this.panel === 'recapture' && this.selectedItem) return this._renderRecapturePane(this.selectedItem)\n if (this.panel === 'report') return this._renderReportPane()\n return ''\n }\n\n private _renderDetailPane(item: any) {\n const auto = item.verdict === 'pass' || item.verdict === 'fail'\n const routingLabel = ROUTING_LABEL[item.routing] || item.routing\n const verdictLabel = VERDICT_LABEL[item.verdict] || item.verdict\n\n return html`\n <div class=\"side-pane\">\n <div class=\"detail-header\">\n <span class=\"badge\" ?pass=${item.verdict === 'pass'} ?fail=${item.verdict === 'fail'} ?etc=${!auto}>\n ${routingLabel}\n </span>\n <h3>${verdictLabel}</h3>\n </div>\n <div class=\"detail-summary\">${(item.observation || item.ai_report || '').trim()}</div>\n <div class=\"kv-grid\">\n <div class=\"kv\">\n <label>판정</label>\n <span class=\"verdict-value\" ?pass=${item.verdict === 'pass'} ?fail=${item.verdict === 'fail'}>\n ${verdictLabel || '-'}\n </span>\n </div>\n ${\n item.confidence != null\n ? html`\n <div class=\"kv\">\n <label>신뢰도</label>\n <span>${Math.round(item.confidence * 100)}%</span>\n </div>\n `\n : ''\n }\n <div class=\"kv\">\n <label>처리</label>\n <span>${ROUTING_LABEL[item.routing] || item.routing || '-'}</span>\n </div>\n </div>\n\n <div class=\"reason-box\">\n <div class=\"reason-verdict\">\n <label style=\"font-size: 11px;color: #7d2f2f; display: block; font-weight: bold;\">판단 근거</label>\n ${item.reason}\n </div>\n </div>\n\n <button class=\"text-button\" @click=${this._closePanel}>닫기</button>\n </div>\n `\n }\n\n private _renderRecapturePane(item: any) {\n const shots = item.recapture_shots?.length\n ? item.recapture_shots\n : [{ target: '추가 사진', how: '항목이 잘 보이도록 촬영해주세요.' }]\n const taken = this.photos.length - this.recaptureBase\n const total = shots.length\n\n return html`\n <div class=\"side-pane\">\n <h3>${item.text}</h3>\n <div class=\"why-box\">\n <b>왜 추가 촬영이 필요한가요?</b><br />\n ${item.reason || '판정을 위해 추가 사진이 필요합니다.'}\n </div>\n <div>\n <h4 style=\"margin: 0 0 8px 0; font-size: 13px;\">촬영 가이드</h4>\n <ul\n style=\"margin: 0; padding-left: 18px; font-size: 12px; color: #555; display: flex; flex-direction: column; gap: 6px;\"\n >\n ${shots.map(s => html`<li>${s.target} — ${s.how}</li>`)}\n </ul>\n </div>\n <div class=\"progress-row\">\n <span>사진 진행</span>\n <span>${Math.min(taken, total)} / ${total}</span>\n </div>\n <div class=\"progress-bar\"><div style=\"width: ${total ? Math.min(taken / total, 1) * 100 : 0}%\"></div></div>\n <div class=\"slot-grid\">\n ${shots.map((s, i) => {\n const photo = this.photos[this.recaptureBase + i]\n return html`\n <div class=\"slot\" @click=${() => this._openPhotoPicker(this.recaptureBase + i)}>\n ${photo ? html`<img src=${photo.url} alt=${s.target} />` : html`<md-icon>add_a_photo</md-icon>${s.target}`}\n </div>\n `\n })}\n </div>\n ${\n taken > 0\n ? html`<button class=\"primary-button\" @click=${() => this._runInspection()}>재검사 실행 (${taken}장)</button>`\n : ''\n }\n <button class=\"text-button\" @click=${this._closePanel}>닫기</button>\n </div>\n `\n }\n\n private _renderReportPane() {\n const items = this._sortedItems()\n const summary = this.result?.summary || {}\n const etcCount = (summary.hold || 0) + (summary.pending || 0) + (summary.error || 0)\n\n return html`\n <div class=\"side-pane\">\n <h3>종합 검사 리포트</h3>\n <div class=\"report-counts\">\n <div pass><b>${summary.pass || 0}</b><small>적합</small></div>\n <div fail><b>${summary.fail || 0}</b><small>부적합</small></div>\n <div etc><b>${etcCount}</b><small>미검사</small></div>\n </div>\n <div style=\"overflow-y: auto; max-height: 380px;\">\n ${items.map((it, i) => {\n const expanded = this.expandedReportId === it.item_id\n return html`\n <div class=\"report-item\">\n <div class=\"report-head\" @click=${() => this._toggleReportItem(it.item_id)}>\n <span class=\"report-text\">${i + 1}. ${it.text}</span>\n <span\n class=\"verdict\"\n ?pass=${it.verdict === 'pass'}\n ?fail=${it.verdict === 'fail'}\n ?etc=${it.verdict !== 'pass' && it.verdict !== 'fail'}\n >\n ${VERDICT_LABEL[it.verdict] || it.verdict}\n </span>\n <md-icon class=\"report-caret\" ?open=${expanded}>expand_more</md-icon>\n </div>\n ${\n expanded\n ? html`\n <div class=\"report-basis\">\n ${it.ai_report ? html`<div class=\"report-ai\">${(it.ai_report || '').trim()}</div>` : ''}\n ${it.observation ? html`<div>관찰: ${it.observation}</div>` : ''}\n ${it.reason ? html`<div>판단: ${it.reason}</div>` : ''}\n ${\n it.used_images?.length\n ? html`<div class=\"report-used\">근거 사진: ${it.used_images.map(n => `#${n}`).join(', ')}</div>`\n : ''\n }\n </div>\n `\n : ''\n }\n </div>\n `\n })}\n </div>\n <button class=\"primary-button\" @click=${this._registerInspection}>검사 등록</button>\n <button class=\"text-button\" @click=${this._closePanel}>닫기</button>\n </div>\n `\n }\n\n /* ─── 라이프사이클 ─── */\n async pageUpdated(changes: any, lifecycle: PageLifecycle) {\n if (this.active) {\n this._resetAll()\n this.buildingInspectionId = lifecycle.resourceId || ''\n await this.initBuildingInspection(this.buildingInspectionId)\n await this._loadShotGuide()\n }\n }\n\n async initBuildingInspection(buildingInspectionId: string = '') {\n const response = await client.query({\n query: gql`\n query BuildingInspection($buildingInspectionId: String!) {\n buildingInspection(id: $buildingInspectionId) {\n id\n status\n checklist {\n id\n name\n location\n checklistItems {\n id\n sequence\n mainType\n detailType\n name\n }\n }\n buildingLevel {\n id\n floor\n building {\n id\n name\n buildingComplex {\n id\n }\n }\n }\n }\n }\n `,\n variables: { buildingInspectionId }\n })\n\n if (response.errors) return\n\n this.buildingInspection = response.data.buildingInspection\n\n await this._getProjectByBuildingComplexId(this.buildingInspection?.buildingLevel?.building?.buildingComplex?.id)\n }\n\n private async _getProjectByBuildingComplexId(buildingComplexId) {\n const response = await client.query({\n query: gql`\n query ProjectByBuildingComplexId($buildingComplexId: String!) {\n project: projectByBuildingComplexId(buildingComplexId: $buildingComplexId) {\n id\n name\n }\n }\n `,\n variables: { buildingComplexId }\n })\n\n if (response.errors) return\n\n this.project = response.data.project\n }\n\n /* ─── 엔진 호출 ─── */\n\n /* 엔진 실행 공통 호출: input(JSON) + 사진 파일들을 multipart로 전송 */\n private async _callEngine(input: any, files: File[] = []) {\n const form = new FormData()\n form.append('input', JSON.stringify(input))\n for (const file of files) form.append('files', file, file.name)\n\n const response = await fetch(ENGINE_RUN_URL, {\n method: 'POST',\n headers: { Authorization: ENGINE_AUTH },\n body: form\n })\n const raw = await response.json()\n const data = raw?.result || {}\n if (data?.status !== 'success') {\n throw new Error(data?.error || raw?.error || 'AI 엔진 호출에 실패했습니다.')\n }\n return data.result\n }\n\n /* [1단계] 촬영 가이드 생성 (plan-shots) */\n private async _loadShotGuide() {\n const checklist = this.engineChecklist\n if (!checklist.length) {\n notify({ message: '체크리스트 항목이 없습니다.', level: 'warn' })\n return\n }\n\n try {\n this.loading = true\n this.loadingText = 'AI 촬영 가이드 생성 중...'\n this.guide = await this._callEngine({ action: 'plan-shots', checklist })\n } catch (error) {\n console.error('촬영 가이드 생성 실패:', error)\n notify({ message: (error as Error).message, level: 'error' })\n } finally {\n this.loading = false\n }\n }\n\n /* [2단계] 자동 판정 실행 (inspect)\n * - 최초 판정: 전체 사진 + 전체 체크리스트\n * - 재검사(재촬영 패널): 이번에 새로 찍은 사진만 + 해당 항목만 재판정 후 결과 병합 */\n private async _runInspection() {\n const isRecapture = this.panel === 'recapture' && !!this.selectedItem\n // 재검사는 recaptureBase 이후에 찍은 사진만 전송\n const files = (isRecapture ? this.photos.slice(this.recaptureBase) : this.photos).map(p => p.file)\n if (!files.length) {\n notify({ message: '촬영된 사진이 없습니다.', level: 'warn' })\n return\n }\n const checklist = isRecapture\n ? this.engineChecklist.filter(c => c.item_id === this.selectedItem.item_id)\n : this.engineChecklist\n\n try {\n this.loading = true\n this.loadingText = 'AI 자동 판정 중... (최대 1~2분 소요)'\n const result = await this._callEngine({ action: 'inspect', checklist }, files)\n\n if (isRecapture) {\n this._mergeRecaptureResult(result)\n } else {\n this.result = result\n }\n this.panel = 'none'\n this.selectedItem = null\n this.mainPhotoIndex = 0\n } catch (error) {\n console.error('AI 자동 판정 실패:', error)\n notify({ message: (error as Error).message, level: 'error' })\n } finally {\n this.loading = false\n }\n }\n\n /* 재검사(부분 전송) 결과를 기존 전체 결과에 병합\n * - used_images는 전송한 부분집합 기준 1-based → 전체 사진 인덱스로 보정(recaptureBase 가산)\n * - 해당 항목만 교체 후 summary 재계산 */\n private _mergeRecaptureResult(result: any) {\n const base = this.recaptureBase\n const updated = (result?.items_sorted || result?.items || []).map((it: any) => ({\n ...it,\n used_images: (it.used_images || []).map((n: number) => n + base)\n }))\n const byId = new Map(updated.map((it: any) => [it.item_id, it]))\n const replace = (arr: any[]) => (arr || []).map(it => byId.get(it.item_id) || it)\n\n const items = replace(this.result?.items)\n const itemsSorted = this.result?.items_sorted ? replace(this.result.items_sorted) : undefined\n\n const summary: Record<string, number> = { pass: 0, fail: 0, hold: 0, pending: 0, error: 0 }\n for (const it of itemsSorted || items) summary[it.verdict] = (summary[it.verdict] || 0) + 1\n\n this.result = { ...this.result, items, ...(itemsSorted ? { items_sorted: itemsSorted } : {}), summary }\n }\n\n /* ─── 사진 선택 ─── */\n /* 슬롯 클릭 → 사진 선택기 열기 (모바일: 촬영/앨범 선택 팝업, 채워진 슬롯이면 교체) */\n private _openPhotoPicker(slotIndex: number | null = null) {\n this.pendingSlotIndex = slotIndex\n this.photoInputEl?.click()\n }\n\n private _onPhotosSelected(event: Event) {\n const input = event.target as HTMLInputElement\n const files = Array.from(input?.files || []).filter(f => f.type.startsWith('image/') || /\\.heic$/i.test(f.name))\n input.value = ''\n const slotIndex = this.pendingSlotIndex\n this.pendingSlotIndex = null\n if (!files.length) return\n\n // 채워진 슬롯을 클릭한 경우 → 해당 사진 교체 (첫 파일만 사용)\n if (slotIndex !== null && slotIndex < this.photos.length) {\n URL.revokeObjectURL(this.photos[slotIndex].url)\n const next = [...this.photos]\n next[slotIndex] = { file: files[0], url: URL.createObjectURL(files[0]) }\n this.photos = next\n return\n }\n\n // 빈 슬롯/추가 → 순서대로 뒤에 추가\n // 엔진 제한은 요청(호출)당 MAX_IMAGES장. 재검사는 새로 찍은 사진만 별도 전송되므로\n // 누적 합계가 아니라 이번 회차(최초=전체, 재검사=recaptureBase 이후) 기준으로만 제한한다.\n const batchBase = this.panel === 'recapture' ? this.recaptureBase : 0\n const cap = batchBase + MAX_IMAGES\n if (this.photos.length + files.length > cap) {\n notify({ message: `사진은 회차당 최대 ${MAX_IMAGES}장까지 사용할 수 있습니다.`, level: 'warn' })\n files.length = Math.max(0, cap - this.photos.length)\n if (!files.length) return\n }\n\n this.photos = [...this.photos, ...files.map(file => ({ file, url: URL.createObjectURL(file) }))]\n }\n\n private _resetPhotos = () => {\n this.photos.forEach(p => URL.revokeObjectURL(p.url))\n this.photos = []\n }\n\n private _resetAll() {\n this._resetPhotos()\n this.guide = null\n this.result = null\n this.panel = 'none'\n this.selectedItem = null\n this.mainPhotoIndex = 0\n this.recaptureBase = 0\n }\n\n /* ─── 패널 열기/닫기 ─── */\n private _openDetail(item: any) {\n // 보류(hold)는 추가 촬영이 필요한 케이스 → 상세 대신 추가 촬영 UI를 바로 표시\n if (item.verdict === 'hold') {\n this._openRecapture(item)\n return\n }\n this.selectedItem = item\n this.mainPhotoIndex = 0 // 선택 항목의 첫 사용 사진부터 표시\n this.panel = 'detail'\n }\n\n private _openRecapture(item: any) {\n this.selectedItem = item\n this.recaptureBase = this.photos.length\n this.panel = 'recapture'\n }\n\n private _openReport = () => {\n this.panel = 'report'\n this.selectedItem = null\n this.expandedReportId = null\n }\n\n /* 종합 리포트 항목 펼치기/접기 (한 번에 하나만 펼침) */\n private _toggleReportItem(id: string) {\n this.expandedReportId = this.expandedReportId === id ? null : id\n }\n\n private _closePanel = () => {\n this.panel = 'none'\n this.selectedItem = null\n }\n\n private _sortedItems(): any[] {\n return this.result?.items_sorted || this.result?.items || []\n }\n\n /* ─── [6단계] 검사 등록: 감리자 판정 자동 반영 + AI판단 근거 첨부 ─── */\n private async _registerInspection() {\n const items = this._sortedItems()\n if (!items.length) {\n notify({ message: '판정 결과가 없습니다.', level: 'warn' })\n return\n }\n // 적합/부적합으로 자동 판정된 항목만 반영 (보류/미지원/오류는 미검사로 건너뜀)\n const judged = items.filter(it => it.verdict === 'pass' || it.verdict === 'fail')\n\n try {\n this.loading = true\n this.loadingText = '검사 결과 등록 중...'\n\n // 1) 감리자 적합/부적합 자동 채움 (적합/부적합 판정된 항목만, 없으면 건너뜀)\n if (judged.length) {\n const response = await client.mutate({\n mutation: gql`\n mutation UpdateChecklistItemsAiJudgment($items: [ChecklistItemAiJudgment!]!) {\n updateChecklistItemsAiJudgment(items: $items)\n }\n `,\n variables: {\n items: judged.map(it => ({\n id: it.item_id,\n supervisoryConfirmStatus: it.verdict === 'pass' ? 'T' : 'F'\n }))\n }\n })\n\n if (response.errors) throw new Error(response.errors[0]?.message || '검사 등록에 실패했습니다.')\n }\n\n // 2) 항목별 첨부: 판단 근거(AI판단 텍스트) + 근거 사진 (판정 여부와 무관하게 전체 항목)\n const attachments: any[] = []\n for (const it of items) {\n if (it.ai_report) {\n attachments.push({\n file: new File([it.ai_report], `AI판단_${(it.text || it.item_id).slice(0, 30)}.txt`, { type: 'text/plain' }),\n refBy: it.item_id,\n refType: 'ChecklistItem',\n description: 'AI판단'\n })\n }\n for (const n of it.used_images || []) {\n const photo = this.photos[n - 1]\n if (photo) {\n attachments.push({ file: photo.file, refBy: it.item_id, refType: 'ChecklistItem', description: 'AI판단' })\n }\n }\n }\n\n if (attachments.length) {\n const attachResponse = await client.mutate({\n mutation: gql`\n mutation CreateAttachments($attachments: [NewAttachment!]!) {\n createAttachments(attachments: $attachments) {\n id\n }\n }\n `,\n variables: { attachments },\n context: { hasUpload: true }\n })\n\n if (attachResponse.errors) throw new Error(attachResponse.errors[0]?.message || 'AI판단 자료 첨부에 실패했습니다.')\n }\n\n notify({ message: `검사 결과를 등록하였습니다. (자동 판정 ${judged.length}건 반영)` })\n\n // 등록 후 체크리스트 화면으로 이동\n navigate(`building-inspection-detail-checklist/${this.buildingInspectionId}`)\n } catch (error) {\n console.error('검사 등록 실패:', error)\n notify({ message: (error as Error).message, level: 'error' })\n } finally {\n this.loading = false\n }\n }\n}\n"]}
|
package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement_old_ai.js
CHANGED
|
@@ -15,7 +15,7 @@ import './component/building-inspection-detail-header';
|
|
|
15
15
|
let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement extends PageView {
|
|
16
16
|
constructor() {
|
|
17
17
|
super(...arguments);
|
|
18
|
-
this.KEYPOINT_RULER_API_BASE_URL = 'https://hatiolab-korea-uni.
|
|
18
|
+
this.KEYPOINT_RULER_API_BASE_URL = 'https://hatiolab-korea-uni.nruing.com';
|
|
19
19
|
this.project = {};
|
|
20
20
|
this.buildingInspection = {};
|
|
21
21
|
this.buildingInspectionId = '';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"building-inspection-detail-ai-measurement_old_ai.js","sourceRoot":"","sources":["../../../client/pages/building-inspection/building-inspection-detail-ai-measurement_old_ai.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-switch.js'\nimport '@operato/mini-map/ox-zoomable-image.js'\nimport '@material/web/progress/circular-progress.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, PropertyValues } from 'lit'\nimport { customElement, state, query } from 'lit/decorators.js'\nimport html2canvas from 'html2canvas'\n\nimport { PageView } from '@operato/shell'\nimport { CommonGristStyles, ScrollbarStyles } from '@operato/styles'\nimport { PageLifecycle } from '@operato/shell/dist/src/app/pages/page-view'\nimport { client } from '@operato/graphql'\nimport { notify } from '@operato/layout'\n\nimport './component/building-inspection-detail-header'\n\n@customElement('building-inspection-detail-ai-measurement')\nexport class BuildingInspectionAiMeasurement extends PageView {\n static styles = [\n ScrollbarStyles,\n CommonGristStyles,\n css`\n :host {\n display: grid;\n grid-template-rows: 75px 1fr;\n color: #4e5055;\n width: 100%;\n height: 100%;\n background-color: #f7f7f7;\n }\n\n div[body] {\n display: flex;\n justify-items: center;\n gap: var(--spacing-medium);\n margin: var(--spacing-medium);\n min-height: 0;\n }\n\n div[preview] {\n flex: 1;\n border: 2px solid #ddd;\n border-radius: 10px;\n\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 0;\n overflow: hidden;\n }\n\n div[preview] img {\n flex: 1;\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n }\n\n div[preview] video {\n flex: 1;\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n }\n\n div[preview] md-icon {\n --md-icon-size: 160px;\n }\n\n .loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n }\n\n .loading-text {\n font-size: 14px;\n color: #666;\n }\n\n .frame-container {\n width: 100%;\n height: 100%;\n max-height: 100%;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n }\n\n .frames-header {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n font-size: 20px;\n font-weight: 700;\n color: #333;\n text-align: center;\n padding-block: 8px;\n }\n\n .frames-count {\n font-size: 16px;\n color: #777;\n font-weight: 600;\n }\n\n .frames-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));\n gap: 12px;\n }\n\n .frame-item {\n border: 1px solid #ddd;\n border-radius: 8px;\n overflow: hidden;\n background: #fff;\n cursor: pointer;\n transition:\n box-shadow 0.2s,\n transform 0.1s;\n }\n\n .frame-item:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n }\n\n .frame-item img {\n display: block;\n width: 100%;\n height: 120px;\n object-fit: cover;\n }\n\n .image-wrapper {\n flex: 1;\n display: flex;\n position: relative;\n align-content: center;\n text-align: center;\n }\n\n .point-marker {\n position: absolute;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n border: 2px solid #fff;\n transform: translate(-50%, -50%);\n pointer-events: none;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.25);\n }\n\n .point-1 {\n background-color: #e53935;\n }\n\n .point-2 {\n background-color: #1e88e5;\n }\n\n .line-overlay {\n position: absolute;\n pointer-events: none;\n background-color: #ff9800;\n transform-origin: left center;\n }\n\n .distance-label {\n position: absolute;\n background: rgba(0, 0, 0, 0.7);\n color: #fff;\n font-size: 14px;\n padding: 2px 6px;\n border-radius: 4px;\n transform: translate(-50%, -120%);\n pointer-events: none;\n white-space: nowrap;\n }\n\n div[controls] {\n width: 240px;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n align-items: center;\n }\n\n div[action-buttons] {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n gap: 15px;\n }\n\n .switch-container {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 24px;\n font-weight: bold;\n }\n\n ox-input-switch {\n --ox-simple-switch-fullwidth: 68px;\n --ox-simple-switch-fullheight: 34px;\n --ox-simple-switch-thumbnail-size: 34px;\n }\n\n .camera-controls {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .camera-shutter {\n display: flex;\n justify-content: center;\n align-items: center;\n cursor: pointer;\n position: relative;\n }\n\n .controls-title {\n font-size: 18px;\n font-weight: 700;\n color: #333;\n margin-bottom: 8px;\n text-align: center;\n }\n\n .camera-shutter md-icon {\n --md-icon-size: 100px;\n }\n\n .camera-shutter input {\n opacity: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n left: 0;\n top: 0;\n cursor: pointer;\n }\n\n button {\n padding: 10px 20px;\n font-size: 16px;\n border-radius: 5px;\n border: none;\n cursor: pointer;\n }\n\n button.save {\n background-color: #4caf50;\n color: white;\n\n &:disabled {\n background-color: #ccc;\n cursor: default;\n }\n }\n\n button.retry {\n background-color: #f0ad4e;\n color: white;\n }\n\n button.photo {\n background-color: #1e88e5;\n color: white;\n\n &:disabled {\n background-color: #ccc;\n cursor: default;\n }\n }\n\n button.album-button {\n background-color: #9c27b0;\n color: white;\n font-size: 14px;\n padding: 8px 16px;\n border-radius: 5px;\n border: none;\n cursor: pointer;\n\n &:hover {\n background-color: #7b1fa2;\n }\n\n &:disabled {\n background-color: #ccc;\n cursor: default;\n }\n }\n\n .loading-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n z-index: 2000;\n }\n\n .loading-overlay .loading-container {\n background: white;\n padding: 32px;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n }\n `\n ]\n\n private KEYPOINT_RULER_API_BASE_URL: string = 'https://hatiolab-korea-uni.ettisoft.com'\n\n @state() project: any = {}\n @state() buildingInspection: any = {}\n @state() buildingInspectionId: string = ''\n @state() capturedVideoUrl: string | null = null\n @state() videoFile: File | null = null\n @state() frame: any | null = null\n @state() analyzing: boolean = false\n @state() selectedPoints: { x1: number | null; y1: number | null; x2: number | null; y2: number | null } = {\n x1: null,\n y1: null,\n x2: null,\n y2: null\n }\n @state() frameNaturalWidth: number = 0\n @state() frameNaturalHeight: number = 0\n @state() displayedImageRect: { width: number; height: number; left: number; top: number } | null = null\n @state() distance: number | null = null\n @state() unit: string | null = null\n @state() analyzingError: string | null = null\n\n @query('img#frameImage') private frameImageEl!: HTMLImageElement\n @query('div.image-wrapper') private imageWrapperEl!: HTMLDivElement\n @query('#cameraInput') private cameraInputEl!: HTMLInputElement\n @query('#albumInput') private albumInputEl!: HTMLInputElement\n\n get context() {\n return {\n title: '검측 관리 상세 - AI 거리 측정'\n }\n }\n\n render() {\n return html`\n <building-inspection-detail-header\n .buildingInspectionId=${this.buildingInspection?.id}\n .buildingLevelId=${this.buildingInspection?.buildingLevel?.id}\n .projectName=${this.project.name}\n .buildingName=${this.buildingInspection?.buildingLevel?.building?.name}\n .buildingLevelFloor=${this.buildingInspection?.buildingLevel?.floor}\n .projectId=${this.project.id}\n ></building-inspection-detail-header>\n\n <div body>\n <!-- Preview selected or recorded video -->\n <div preview>\n ${this.frame?.download_url\n ? html`\n <div class=\"image-wrapper\" @click=${this._onImageClick}>\n <img\n id=\"frameImage\"\n src=\"${this.KEYPOINT_RULER_API_BASE_URL + this.frame?.download_url}\"\n crossorigin=\"anonymous\"\n alt=\"frame\"\n loading=\"eager\"\n @load=${this._onImageLoad}\n />\n ${this._renderMarkers()}\n </div>\n `\n : // 동영상 선택 후 동영상 프리뷰\n this.capturedVideoUrl\n ? html`<video src=${this.capturedVideoUrl} controls playsinline></video>`\n : // 초기 상태, 동영상 선택 전\n html`<md-icon>videocam</md-icon>`}\n </div>\n\n <div controls>\n <span class=\"controls-title\">동영상 촬영</span>\n\n <!-- 가운데 버튼 -->\n ${this.frame?.download_url && this._hasTwoPoints() && this.distance && this.unit\n ? // 거리 측정 완료 시, 사진 저장 버튼 표시\n html`<button class=\"save\" ?disabled=${this.analyzing} @click=${this._savePhoto}>사진 저장</button>`\n : // 거리 측정 완료 전, 동영상 촬영 버튼 표시\n html`<div class=\"camera-controls\">\n <div class=\"camera-shutter\">\n <md-icon>camera</md-icon>\n <input id=\"cameraInput\" type=\"file\" accept=\"video/*\" capture=\"environment\" @change=\"${this._onVideoSelected}\" />\n </div>\n <button class=\"album-button\" @click=\"${this._onAlbumButtonClick}\">앨범 선택</button>\n <input id=\"albumInput\" type=\"file\" accept=\"video/*\" @change=\"${this._onVideoSelected}\" style=\"display: none;\" />\n </div>`}\n\n <!-- Action buttons -->\n <div action-buttons>\n ${this.frame\n ? html`\n <button class=\"photo\" ?disabled=${this.analyzing || !this._hasTwoPoints()} @click=${this._onAnalyzePhoto}>\n 사진 분석\n </button>\n `\n : html`\n <button class=\"save\" ?disabled=${this.analyzing || !this.capturedVideoUrl} @click=${this._onAnalyzeVideo}>\n 동영상 분석\n </button>\n `}\n <button class=\"retry\" @click=${this._onRetry}>초기화</button>\n </div>\n </div>\n </div>\n\n <!-- 전체 화면을 덮는 로딩 오버레이 -->\n ${this.analyzing\n ? html`<div class=\"loading-overlay\">\n <div class=\"loading-container\">\n <md-circular-progress indeterminate></md-circular-progress>\n <div class=\"loading-text\">분석 중...</div>\n </div>\n </div>`\n : ''}\n `\n }\n\n protected async updated(changes: PropertyValues): Promise<void> {}\n\n async pageUpdated(changes: any, lifecycle: PageLifecycle) {\n if (this.active) {\n this._onRetry()\n this.buildingInspectionId = lifecycle.resourceId || ''\n await this.initBuildingInspection(this.buildingInspectionId)\n }\n }\n\n async initBuildingInspection(buildingInspectionId: string = '') {\n const response = await client.query({\n query: gql`\n query BuildingInspection($buildingInspectionId: String!) {\n buildingInspection(id: $buildingInspectionId) {\n id\n status\n requestDate\n drawingMarker\n checklist {\n id\n location\n inspectionDrawingType\n }\n buildingLevel {\n id\n floor\n mainDrawing {\n id\n name\n fullpath\n }\n mainDrawingImage\n building {\n id\n name\n buildingComplex {\n id\n }\n }\n }\n }\n }\n `,\n variables: {\n buildingInspectionId\n }\n })\n\n if (response.errors) return\n\n this.buildingInspection = response.data.buildingInspection\n\n await this._getProjectByBuildingComplexId(this.buildingInspection?.buildingLevel?.building?.buildingComplex?.id)\n }\n\n private async _getProjectByBuildingComplexId(buildingComplexId) {\n const response = await client.query({\n query: gql`\n query ProjectByBuildingComplexId($buildingComplexId: String!) {\n project: projectByBuildingComplexId(buildingComplexId: $buildingComplexId) {\n id\n name\n }\n }\n `,\n variables: {\n buildingComplexId\n }\n })\n\n if (response.errors) return\n\n this.project = response.data.project\n }\n\n private _onVideoSelected(event: Event) {\n const input = event.target as HTMLInputElement\n const file = input?.files?.[0]\n if (!file) return\n\n // Only allow video files\n if (!file.type.startsWith('video/')) {\n console.warn('선택된 파일이 동영상이 아닙니다.')\n return\n }\n\n // Revoke old object URL if exists\n if (this.capturedVideoUrl) {\n URL.revokeObjectURL(this.capturedVideoUrl)\n }\n\n this.videoFile = file\n this.capturedVideoUrl = URL.createObjectURL(file)\n }\n\n private _onAlbumButtonClick() {\n // 앨범 선택을 위해 숨겨진 input을 클릭\n this.albumInputEl?.click()\n }\n\n private async _onAnalyzeVideo() {\n if (!this.videoFile) {\n console.warn('선택된 동영상이 없습니다.')\n return\n }\n\n try {\n this.analyzing = true\n const form = new FormData()\n form.append('files', this.videoFile, this.videoFile.name)\n const response = await fetch(`${this.KEYPOINT_RULER_API_BASE_URL}/api/run/keypoint-ruler`, {\n method: 'POST',\n headers: { Authorization: `Basic ${btoa('admin:admin1234')}` },\n body: form\n })\n\n const data = await response.json()\n\n this.frame = {\n file_id: data?.result?.output_files[0]?.file_id,\n download_url: data?.result?.output_files[0]?.download_url,\n file_path: data?.result?.frames[0]?.file_path,\n calibration: data?.result?.calibration\n }\n } catch (error) {\n console.error('동영상 업로드 실패:', error)\n } finally {\n this.analyzing = false\n }\n }\n\n private _onRetry() {\n // Clear current selection and reopen camera\n if (this.capturedVideoUrl) {\n URL.revokeObjectURL(this.capturedVideoUrl)\n }\n this.capturedVideoUrl = null\n this.videoFile = null\n this.frame = null\n this.selectedPoints = { x1: null, y1: null, x2: null, y2: null }\n this.displayedImageRect = null\n this.frameNaturalWidth = 0\n this.frameNaturalHeight = 0\n this.cameraInputEl.value = ''\n this.albumInputEl.value = ''\n this.distance = null\n this.unit = null\n this.analyzingError = null\n }\n\n private _onImageLoad = () => {\n if (!this.frameImageEl || !this.imageWrapperEl) return\n const img = this.frameImageEl\n const wrapperRect = this.imageWrapperEl.getBoundingClientRect()\n const imgRect = img.getBoundingClientRect()\n this.frameNaturalWidth = img.naturalWidth\n this.frameNaturalHeight = img.naturalHeight\n this.displayedImageRect = {\n width: imgRect.width,\n height: imgRect.height,\n left: imgRect.left - wrapperRect.left,\n top: imgRect.top - wrapperRect.top\n }\n }\n\n private _onImageClick = (event: MouseEvent) => {\n if (!this.frameImageEl || !this.imageWrapperEl) return\n const imgRect = this.frameImageEl.getBoundingClientRect()\n const wrapperRect = this.imageWrapperEl.getBoundingClientRect()\n const clientX = event.clientX\n const clientY = event.clientY\n\n // Ignore clicks outside the displayed image area\n if (clientX < imgRect.left || clientX > imgRect.right || clientY < imgRect.top || clientY > imgRect.bottom) {\n return\n }\n\n // 새로운 마크 입력 시 이전 거리/단위 결과 초기화\n this.distance = null\n this.unit = null\n this.analyzingError = null\n\n const relativeX = clientX - imgRect.left\n const relativeY = clientY - imgRect.top\n\n const xOnNatural = Math.round((relativeX * this.frameNaturalWidth) / imgRect.width)\n const yOnNatural = Math.round((relativeY * this.frameNaturalHeight) / imgRect.height)\n\n if (this.selectedPoints.x1 === null || this.selectedPoints.y1 === null) {\n this.selectedPoints = { ...this.selectedPoints, x1: xOnNatural, y1: yOnNatural }\n } else if (this.selectedPoints.x2 === null || this.selectedPoints.y2 === null) {\n this.selectedPoints = { ...this.selectedPoints, x2: xOnNatural, y2: yOnNatural }\n } else {\n // 세 번째 클릭부터는 초기화 후 첫 점으로 설정\n this.selectedPoints = { x1: xOnNatural, y1: yOnNatural, x2: null, y2: null }\n }\n\n // Update displayed rect cache (in case layout changed)\n this.displayedImageRect = {\n width: imgRect.width,\n height: imgRect.height,\n left: imgRect.left - wrapperRect.left,\n top: imgRect.top - wrapperRect.top\n }\n }\n\n private _hasTwoPoints(): boolean {\n const { x1, y1, x2, y2 } = this.selectedPoints\n return x1 !== null && y1 !== null && x2 !== null && y2 !== null\n }\n\n private _renderMarkers() {\n if (!this.displayedImageRect) return html``\n const { left, top, width, height } = this.displayedImageRect\n const { x1, y1, x2, y2 } = this.selectedPoints\n const toDisplay = (x: number, y: number) => {\n const dx = left + (x * width) / (this.frameNaturalWidth || 1)\n const dy = top + (y * height) / (this.frameNaturalHeight || 1)\n return { dx, dy }\n }\n\n return html`\n <!-- 첫 번째 점 -->\n ${x1 !== null && y1 !== null\n ? (() => {\n const p = toDisplay(x1, y1)\n return html`<div class=\"point-marker point-1\" style=\"left:${p.dx}px; top:${p.dy}px;\"></div>`\n })()\n : ''}\n <!-- 두 번째 점 -->\n ${x2 !== null && y2 !== null\n ? (() => {\n const p = toDisplay(x2, y2)\n return html`<div class=\"point-marker point-2\" style=\"left:${p.dx}px; top:${p.dy}px;\"></div>`\n })()\n : ''}\n <!-- 두점 사이 선 -->\n ${this._hasTwoPoints()\n ? (() => {\n const p1 = toDisplay(x1 as number, y1 as number)\n const p2 = toDisplay(x2 as number, y2 as number)\n const cx = (p1.dx + p2.dx) / 2\n const cy = (p1.dy + p2.dy) / 2\n\n // 선의 길이와 각도 계산\n const length = Math.sqrt(Math.pow(p2.dx - p1.dx, 2) + Math.pow(p2.dy - p1.dy, 2))\n const angle = Math.atan2(p2.dy - p1.dy, p2.dx - p1.dx) * (180 / Math.PI)\n\n return html`\n <!-- DIV로 그린 선 -->\n <div\n class=\"line-overlay\"\n style=\"\n left: ${p1.dx}px; \n top: ${p1.dy}px; \n width: ${length}px; \n height: 3px;\n transform: rotate(${angle}deg);\n \"\n ></div>\n <!-- 거리 라벨 -->\n ${this.analyzingError\n ? html`<div class=\"distance-label\" style=\"left:${cx}px; top:${cy}px;\">${this.analyzingError}</div>`\n : this.distance && this.unit\n ? html`<div class=\"distance-label\" style=\"left:${cx}px; top:${cy}px;\">${this.distance} ${this.unit}</div>`\n : ''}\n `\n })()\n : ''}\n `\n }\n\n private async _onAnalyzePhoto() {\n if (!this.frame) {\n console.warn('분석할 사진이 없습니다.')\n return\n }\n if (!this._hasTwoPoints()) {\n console.warn('두 점을 먼저 선택해 주세요.')\n return\n }\n\n try {\n this.analyzing = true\n const payload = {\n x1: this.selectedPoints.x1,\n y1: this.selectedPoints.y1,\n x2: this.selectedPoints.x2,\n y2: this.selectedPoints.y2,\n file_path: this.frame.file_path,\n calibration: this.frame.calibration\n }\n\n const form = new FormData()\n form.append('input', JSON.stringify(payload))\n const response = await fetch(`${this.KEYPOINT_RULER_API_BASE_URL}/api/run/keypoint-ruler`, {\n method: 'POST',\n headers: { Authorization: `Basic ${btoa('admin:admin1234')}` },\n body: form\n })\n\n const result = await response.json()\n const { distance, unit, error } = result.result || {}\n this.distance = distance\n this.unit = unit\n this.analyzingError = error\n } catch (error) {\n console.error('사진 분석 실패:', error)\n } finally {\n this.analyzing = false\n }\n }\n\n async _savePhoto() {\n if (!this.frame || !this._hasTwoPoints() || this.distance === null || !this.unit) {\n notify({ message: '분석 완료 후 저장할 수 있습니다.', level: 'warn' })\n return\n }\n\n const checklistId = this.buildingInspection?.checklist?.id\n let file: File\n try {\n file = await this.getCurrentImage()\n } catch (e) {\n notify({ message: '이미지 합성에 실패했습니다.', level: 'error' })\n return\n }\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($attachments: [NewAttachment!]!) {\n createAttachments(attachments: $attachments) {\n id\n }\n }\n `,\n variables: {\n attachments: [{ file, refBy: checklistId, refType: 'Checklist', description: this.buildingInspection?.status }]\n },\n context: { hasUpload: true }\n })\n\n if (!response.errors) {\n notify({ message: '사진 대지를 저장하였습니다.', level: 'info' })\n return\n }\n\n return response.data.createAttachments\n }\n\n async getCurrentImage(): Promise<File> {\n if (!this.imageWrapperEl) {\n throw new Error('이미지 영역을 찾을 수 없습니다.')\n }\n\n try {\n // html2canvas로 .image-wrapper 영역 캡처\n const canvas = await html2canvas(this.imageWrapperEl, {\n backgroundColor: null, // 투명 배경\n scale: 1, // 1:1 스케일\n useCORS: true, // CORS 이미지 허용\n allowTaint: false, // 보안상 false\n logging: false // 로그 비활성화\n })\n\n // 캔버스를 Blob으로 변환\n const blob: Blob = await new Promise(resolve => {\n canvas.toBlob(resolve as any, 'image/png', 1.0)\n })\n\n // File 객체로 변환하여 반환\n return new File([blob!], `inspection_${Date.now()}.png`, {\n type: 'image/png'\n })\n } catch (error) {\n console.error('html2canvas 캡처 실패:', error)\n throw new Error('화면 캡처에 실패했습니다.')\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"building-inspection-detail-ai-measurement_old_ai.js","sourceRoot":"","sources":["../../../client/pages/building-inspection/building-inspection-detail-ai-measurement_old_ai.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-switch.js'\nimport '@operato/mini-map/ox-zoomable-image.js'\nimport '@material/web/progress/circular-progress.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, PropertyValues } from 'lit'\nimport { customElement, state, query } from 'lit/decorators.js'\nimport html2canvas from 'html2canvas'\n\nimport { PageView } from '@operato/shell'\nimport { CommonGristStyles, ScrollbarStyles } from '@operato/styles'\nimport { PageLifecycle } from '@operato/shell/dist/src/app/pages/page-view'\nimport { client } from '@operato/graphql'\nimport { notify } from '@operato/layout'\n\nimport './component/building-inspection-detail-header'\n\n@customElement('building-inspection-detail-ai-measurement')\nexport class BuildingInspectionAiMeasurement extends PageView {\n static styles = [\n ScrollbarStyles,\n CommonGristStyles,\n css`\n :host {\n display: grid;\n grid-template-rows: 75px 1fr;\n color: #4e5055;\n width: 100%;\n height: 100%;\n background-color: #f7f7f7;\n }\n\n div[body] {\n display: flex;\n justify-items: center;\n gap: var(--spacing-medium);\n margin: var(--spacing-medium);\n min-height: 0;\n }\n\n div[preview] {\n flex: 1;\n border: 2px solid #ddd;\n border-radius: 10px;\n\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 0;\n overflow: hidden;\n }\n\n div[preview] img {\n flex: 1;\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n }\n\n div[preview] video {\n flex: 1;\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n }\n\n div[preview] md-icon {\n --md-icon-size: 160px;\n }\n\n .loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n }\n\n .loading-text {\n font-size: 14px;\n color: #666;\n }\n\n .frame-container {\n width: 100%;\n height: 100%;\n max-height: 100%;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n }\n\n .frames-header {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n font-size: 20px;\n font-weight: 700;\n color: #333;\n text-align: center;\n padding-block: 8px;\n }\n\n .frames-count {\n font-size: 16px;\n color: #777;\n font-weight: 600;\n }\n\n .frames-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));\n gap: 12px;\n }\n\n .frame-item {\n border: 1px solid #ddd;\n border-radius: 8px;\n overflow: hidden;\n background: #fff;\n cursor: pointer;\n transition:\n box-shadow 0.2s,\n transform 0.1s;\n }\n\n .frame-item:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n }\n\n .frame-item img {\n display: block;\n width: 100%;\n height: 120px;\n object-fit: cover;\n }\n\n .image-wrapper {\n flex: 1;\n display: flex;\n position: relative;\n align-content: center;\n text-align: center;\n }\n\n .point-marker {\n position: absolute;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n border: 2px solid #fff;\n transform: translate(-50%, -50%);\n pointer-events: none;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.25);\n }\n\n .point-1 {\n background-color: #e53935;\n }\n\n .point-2 {\n background-color: #1e88e5;\n }\n\n .line-overlay {\n position: absolute;\n pointer-events: none;\n background-color: #ff9800;\n transform-origin: left center;\n }\n\n .distance-label {\n position: absolute;\n background: rgba(0, 0, 0, 0.7);\n color: #fff;\n font-size: 14px;\n padding: 2px 6px;\n border-radius: 4px;\n transform: translate(-50%, -120%);\n pointer-events: none;\n white-space: nowrap;\n }\n\n div[controls] {\n width: 240px;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n align-items: center;\n }\n\n div[action-buttons] {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n gap: 15px;\n }\n\n .switch-container {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 24px;\n font-weight: bold;\n }\n\n ox-input-switch {\n --ox-simple-switch-fullwidth: 68px;\n --ox-simple-switch-fullheight: 34px;\n --ox-simple-switch-thumbnail-size: 34px;\n }\n\n .camera-controls {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .camera-shutter {\n display: flex;\n justify-content: center;\n align-items: center;\n cursor: pointer;\n position: relative;\n }\n\n .controls-title {\n font-size: 18px;\n font-weight: 700;\n color: #333;\n margin-bottom: 8px;\n text-align: center;\n }\n\n .camera-shutter md-icon {\n --md-icon-size: 100px;\n }\n\n .camera-shutter input {\n opacity: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n left: 0;\n top: 0;\n cursor: pointer;\n }\n\n button {\n padding: 10px 20px;\n font-size: 16px;\n border-radius: 5px;\n border: none;\n cursor: pointer;\n }\n\n button.save {\n background-color: #4caf50;\n color: white;\n\n &:disabled {\n background-color: #ccc;\n cursor: default;\n }\n }\n\n button.retry {\n background-color: #f0ad4e;\n color: white;\n }\n\n button.photo {\n background-color: #1e88e5;\n color: white;\n\n &:disabled {\n background-color: #ccc;\n cursor: default;\n }\n }\n\n button.album-button {\n background-color: #9c27b0;\n color: white;\n font-size: 14px;\n padding: 8px 16px;\n border-radius: 5px;\n border: none;\n cursor: pointer;\n\n &:hover {\n background-color: #7b1fa2;\n }\n\n &:disabled {\n background-color: #ccc;\n cursor: default;\n }\n }\n\n .loading-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n z-index: 2000;\n }\n\n .loading-overlay .loading-container {\n background: white;\n padding: 32px;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n }\n `\n ]\n\n private KEYPOINT_RULER_API_BASE_URL: string = 'https://hatiolab-korea-uni.nruing.com'\n\n @state() project: any = {}\n @state() buildingInspection: any = {}\n @state() buildingInspectionId: string = ''\n @state() capturedVideoUrl: string | null = null\n @state() videoFile: File | null = null\n @state() frame: any | null = null\n @state() analyzing: boolean = false\n @state() selectedPoints: { x1: number | null; y1: number | null; x2: number | null; y2: number | null } = {\n x1: null,\n y1: null,\n x2: null,\n y2: null\n }\n @state() frameNaturalWidth: number = 0\n @state() frameNaturalHeight: number = 0\n @state() displayedImageRect: { width: number; height: number; left: number; top: number } | null = null\n @state() distance: number | null = null\n @state() unit: string | null = null\n @state() analyzingError: string | null = null\n\n @query('img#frameImage') private frameImageEl!: HTMLImageElement\n @query('div.image-wrapper') private imageWrapperEl!: HTMLDivElement\n @query('#cameraInput') private cameraInputEl!: HTMLInputElement\n @query('#albumInput') private albumInputEl!: HTMLInputElement\n\n get context() {\n return {\n title: '검측 관리 상세 - AI 거리 측정'\n }\n }\n\n render() {\n return html`\n <building-inspection-detail-header\n .buildingInspectionId=${this.buildingInspection?.id}\n .buildingLevelId=${this.buildingInspection?.buildingLevel?.id}\n .projectName=${this.project.name}\n .buildingName=${this.buildingInspection?.buildingLevel?.building?.name}\n .buildingLevelFloor=${this.buildingInspection?.buildingLevel?.floor}\n .projectId=${this.project.id}\n ></building-inspection-detail-header>\n\n <div body>\n <!-- Preview selected or recorded video -->\n <div preview>\n ${this.frame?.download_url\n ? html`\n <div class=\"image-wrapper\" @click=${this._onImageClick}>\n <img\n id=\"frameImage\"\n src=\"${this.KEYPOINT_RULER_API_BASE_URL + this.frame?.download_url}\"\n crossorigin=\"anonymous\"\n alt=\"frame\"\n loading=\"eager\"\n @load=${this._onImageLoad}\n />\n ${this._renderMarkers()}\n </div>\n `\n : // 동영상 선택 후 동영상 프리뷰\n this.capturedVideoUrl\n ? html`<video src=${this.capturedVideoUrl} controls playsinline></video>`\n : // 초기 상태, 동영상 선택 전\n html`<md-icon>videocam</md-icon>`}\n </div>\n\n <div controls>\n <span class=\"controls-title\">동영상 촬영</span>\n\n <!-- 가운데 버튼 -->\n ${this.frame?.download_url && this._hasTwoPoints() && this.distance && this.unit\n ? // 거리 측정 완료 시, 사진 저장 버튼 표시\n html`<button class=\"save\" ?disabled=${this.analyzing} @click=${this._savePhoto}>사진 저장</button>`\n : // 거리 측정 완료 전, 동영상 촬영 버튼 표시\n html`<div class=\"camera-controls\">\n <div class=\"camera-shutter\">\n <md-icon>camera</md-icon>\n <input id=\"cameraInput\" type=\"file\" accept=\"video/*\" capture=\"environment\" @change=\"${this._onVideoSelected}\" />\n </div>\n <button class=\"album-button\" @click=\"${this._onAlbumButtonClick}\">앨범 선택</button>\n <input id=\"albumInput\" type=\"file\" accept=\"video/*\" @change=\"${this._onVideoSelected}\" style=\"display: none;\" />\n </div>`}\n\n <!-- Action buttons -->\n <div action-buttons>\n ${this.frame\n ? html`\n <button class=\"photo\" ?disabled=${this.analyzing || !this._hasTwoPoints()} @click=${this._onAnalyzePhoto}>\n 사진 분석\n </button>\n `\n : html`\n <button class=\"save\" ?disabled=${this.analyzing || !this.capturedVideoUrl} @click=${this._onAnalyzeVideo}>\n 동영상 분석\n </button>\n `}\n <button class=\"retry\" @click=${this._onRetry}>초기화</button>\n </div>\n </div>\n </div>\n\n <!-- 전체 화면을 덮는 로딩 오버레이 -->\n ${this.analyzing\n ? html`<div class=\"loading-overlay\">\n <div class=\"loading-container\">\n <md-circular-progress indeterminate></md-circular-progress>\n <div class=\"loading-text\">분석 중...</div>\n </div>\n </div>`\n : ''}\n `\n }\n\n protected async updated(changes: PropertyValues): Promise<void> {}\n\n async pageUpdated(changes: any, lifecycle: PageLifecycle) {\n if (this.active) {\n this._onRetry()\n this.buildingInspectionId = lifecycle.resourceId || ''\n await this.initBuildingInspection(this.buildingInspectionId)\n }\n }\n\n async initBuildingInspection(buildingInspectionId: string = '') {\n const response = await client.query({\n query: gql`\n query BuildingInspection($buildingInspectionId: String!) {\n buildingInspection(id: $buildingInspectionId) {\n id\n status\n requestDate\n drawingMarker\n checklist {\n id\n location\n inspectionDrawingType\n }\n buildingLevel {\n id\n floor\n mainDrawing {\n id\n name\n fullpath\n }\n mainDrawingImage\n building {\n id\n name\n buildingComplex {\n id\n }\n }\n }\n }\n }\n `,\n variables: {\n buildingInspectionId\n }\n })\n\n if (response.errors) return\n\n this.buildingInspection = response.data.buildingInspection\n\n await this._getProjectByBuildingComplexId(this.buildingInspection?.buildingLevel?.building?.buildingComplex?.id)\n }\n\n private async _getProjectByBuildingComplexId(buildingComplexId) {\n const response = await client.query({\n query: gql`\n query ProjectByBuildingComplexId($buildingComplexId: String!) {\n project: projectByBuildingComplexId(buildingComplexId: $buildingComplexId) {\n id\n name\n }\n }\n `,\n variables: {\n buildingComplexId\n }\n })\n\n if (response.errors) return\n\n this.project = response.data.project\n }\n\n private _onVideoSelected(event: Event) {\n const input = event.target as HTMLInputElement\n const file = input?.files?.[0]\n if (!file) return\n\n // Only allow video files\n if (!file.type.startsWith('video/')) {\n console.warn('선택된 파일이 동영상이 아닙니다.')\n return\n }\n\n // Revoke old object URL if exists\n if (this.capturedVideoUrl) {\n URL.revokeObjectURL(this.capturedVideoUrl)\n }\n\n this.videoFile = file\n this.capturedVideoUrl = URL.createObjectURL(file)\n }\n\n private _onAlbumButtonClick() {\n // 앨범 선택을 위해 숨겨진 input을 클릭\n this.albumInputEl?.click()\n }\n\n private async _onAnalyzeVideo() {\n if (!this.videoFile) {\n console.warn('선택된 동영상이 없습니다.')\n return\n }\n\n try {\n this.analyzing = true\n const form = new FormData()\n form.append('files', this.videoFile, this.videoFile.name)\n const response = await fetch(`${this.KEYPOINT_RULER_API_BASE_URL}/api/run/keypoint-ruler`, {\n method: 'POST',\n headers: { Authorization: `Basic ${btoa('admin:admin1234')}` },\n body: form\n })\n\n const data = await response.json()\n\n this.frame = {\n file_id: data?.result?.output_files[0]?.file_id,\n download_url: data?.result?.output_files[0]?.download_url,\n file_path: data?.result?.frames[0]?.file_path,\n calibration: data?.result?.calibration\n }\n } catch (error) {\n console.error('동영상 업로드 실패:', error)\n } finally {\n this.analyzing = false\n }\n }\n\n private _onRetry() {\n // Clear current selection and reopen camera\n if (this.capturedVideoUrl) {\n URL.revokeObjectURL(this.capturedVideoUrl)\n }\n this.capturedVideoUrl = null\n this.videoFile = null\n this.frame = null\n this.selectedPoints = { x1: null, y1: null, x2: null, y2: null }\n this.displayedImageRect = null\n this.frameNaturalWidth = 0\n this.frameNaturalHeight = 0\n this.cameraInputEl.value = ''\n this.albumInputEl.value = ''\n this.distance = null\n this.unit = null\n this.analyzingError = null\n }\n\n private _onImageLoad = () => {\n if (!this.frameImageEl || !this.imageWrapperEl) return\n const img = this.frameImageEl\n const wrapperRect = this.imageWrapperEl.getBoundingClientRect()\n const imgRect = img.getBoundingClientRect()\n this.frameNaturalWidth = img.naturalWidth\n this.frameNaturalHeight = img.naturalHeight\n this.displayedImageRect = {\n width: imgRect.width,\n height: imgRect.height,\n left: imgRect.left - wrapperRect.left,\n top: imgRect.top - wrapperRect.top\n }\n }\n\n private _onImageClick = (event: MouseEvent) => {\n if (!this.frameImageEl || !this.imageWrapperEl) return\n const imgRect = this.frameImageEl.getBoundingClientRect()\n const wrapperRect = this.imageWrapperEl.getBoundingClientRect()\n const clientX = event.clientX\n const clientY = event.clientY\n\n // Ignore clicks outside the displayed image area\n if (clientX < imgRect.left || clientX > imgRect.right || clientY < imgRect.top || clientY > imgRect.bottom) {\n return\n }\n\n // 새로운 마크 입력 시 이전 거리/단위 결과 초기화\n this.distance = null\n this.unit = null\n this.analyzingError = null\n\n const relativeX = clientX - imgRect.left\n const relativeY = clientY - imgRect.top\n\n const xOnNatural = Math.round((relativeX * this.frameNaturalWidth) / imgRect.width)\n const yOnNatural = Math.round((relativeY * this.frameNaturalHeight) / imgRect.height)\n\n if (this.selectedPoints.x1 === null || this.selectedPoints.y1 === null) {\n this.selectedPoints = { ...this.selectedPoints, x1: xOnNatural, y1: yOnNatural }\n } else if (this.selectedPoints.x2 === null || this.selectedPoints.y2 === null) {\n this.selectedPoints = { ...this.selectedPoints, x2: xOnNatural, y2: yOnNatural }\n } else {\n // 세 번째 클릭부터는 초기화 후 첫 점으로 설정\n this.selectedPoints = { x1: xOnNatural, y1: yOnNatural, x2: null, y2: null }\n }\n\n // Update displayed rect cache (in case layout changed)\n this.displayedImageRect = {\n width: imgRect.width,\n height: imgRect.height,\n left: imgRect.left - wrapperRect.left,\n top: imgRect.top - wrapperRect.top\n }\n }\n\n private _hasTwoPoints(): boolean {\n const { x1, y1, x2, y2 } = this.selectedPoints\n return x1 !== null && y1 !== null && x2 !== null && y2 !== null\n }\n\n private _renderMarkers() {\n if (!this.displayedImageRect) return html``\n const { left, top, width, height } = this.displayedImageRect\n const { x1, y1, x2, y2 } = this.selectedPoints\n const toDisplay = (x: number, y: number) => {\n const dx = left + (x * width) / (this.frameNaturalWidth || 1)\n const dy = top + (y * height) / (this.frameNaturalHeight || 1)\n return { dx, dy }\n }\n\n return html`\n <!-- 첫 번째 점 -->\n ${x1 !== null && y1 !== null\n ? (() => {\n const p = toDisplay(x1, y1)\n return html`<div class=\"point-marker point-1\" style=\"left:${p.dx}px; top:${p.dy}px;\"></div>`\n })()\n : ''}\n <!-- 두 번째 점 -->\n ${x2 !== null && y2 !== null\n ? (() => {\n const p = toDisplay(x2, y2)\n return html`<div class=\"point-marker point-2\" style=\"left:${p.dx}px; top:${p.dy}px;\"></div>`\n })()\n : ''}\n <!-- 두점 사이 선 -->\n ${this._hasTwoPoints()\n ? (() => {\n const p1 = toDisplay(x1 as number, y1 as number)\n const p2 = toDisplay(x2 as number, y2 as number)\n const cx = (p1.dx + p2.dx) / 2\n const cy = (p1.dy + p2.dy) / 2\n\n // 선의 길이와 각도 계산\n const length = Math.sqrt(Math.pow(p2.dx - p1.dx, 2) + Math.pow(p2.dy - p1.dy, 2))\n const angle = Math.atan2(p2.dy - p1.dy, p2.dx - p1.dx) * (180 / Math.PI)\n\n return html`\n <!-- DIV로 그린 선 -->\n <div\n class=\"line-overlay\"\n style=\"\n left: ${p1.dx}px; \n top: ${p1.dy}px; \n width: ${length}px; \n height: 3px;\n transform: rotate(${angle}deg);\n \"\n ></div>\n <!-- 거리 라벨 -->\n ${this.analyzingError\n ? html`<div class=\"distance-label\" style=\"left:${cx}px; top:${cy}px;\">${this.analyzingError}</div>`\n : this.distance && this.unit\n ? html`<div class=\"distance-label\" style=\"left:${cx}px; top:${cy}px;\">${this.distance} ${this.unit}</div>`\n : ''}\n `\n })()\n : ''}\n `\n }\n\n private async _onAnalyzePhoto() {\n if (!this.frame) {\n console.warn('분석할 사진이 없습니다.')\n return\n }\n if (!this._hasTwoPoints()) {\n console.warn('두 점을 먼저 선택해 주세요.')\n return\n }\n\n try {\n this.analyzing = true\n const payload = {\n x1: this.selectedPoints.x1,\n y1: this.selectedPoints.y1,\n x2: this.selectedPoints.x2,\n y2: this.selectedPoints.y2,\n file_path: this.frame.file_path,\n calibration: this.frame.calibration\n }\n\n const form = new FormData()\n form.append('input', JSON.stringify(payload))\n const response = await fetch(`${this.KEYPOINT_RULER_API_BASE_URL}/api/run/keypoint-ruler`, {\n method: 'POST',\n headers: { Authorization: `Basic ${btoa('admin:admin1234')}` },\n body: form\n })\n\n const result = await response.json()\n const { distance, unit, error } = result.result || {}\n this.distance = distance\n this.unit = unit\n this.analyzingError = error\n } catch (error) {\n console.error('사진 분석 실패:', error)\n } finally {\n this.analyzing = false\n }\n }\n\n async _savePhoto() {\n if (!this.frame || !this._hasTwoPoints() || this.distance === null || !this.unit) {\n notify({ message: '분석 완료 후 저장할 수 있습니다.', level: 'warn' })\n return\n }\n\n const checklistId = this.buildingInspection?.checklist?.id\n let file: File\n try {\n file = await this.getCurrentImage()\n } catch (e) {\n notify({ message: '이미지 합성에 실패했습니다.', level: 'error' })\n return\n }\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($attachments: [NewAttachment!]!) {\n createAttachments(attachments: $attachments) {\n id\n }\n }\n `,\n variables: {\n attachments: [{ file, refBy: checklistId, refType: 'Checklist', description: this.buildingInspection?.status }]\n },\n context: { hasUpload: true }\n })\n\n if (!response.errors) {\n notify({ message: '사진 대지를 저장하였습니다.', level: 'info' })\n return\n }\n\n return response.data.createAttachments\n }\n\n async getCurrentImage(): Promise<File> {\n if (!this.imageWrapperEl) {\n throw new Error('이미지 영역을 찾을 수 없습니다.')\n }\n\n try {\n // html2canvas로 .image-wrapper 영역 캡처\n const canvas = await html2canvas(this.imageWrapperEl, {\n backgroundColor: null, // 투명 배경\n scale: 1, // 1:1 스케일\n useCORS: true, // CORS 이미지 허용\n allowTaint: false, // 보안상 false\n logging: false // 로그 비활성화\n })\n\n // 캔버스를 Blob으로 변환\n const blob: Blob = await new Promise(resolve => {\n canvas.toBlob(resolve as any, 'image/png', 1.0)\n })\n\n // File 객체로 변환하여 반환\n return new File([blob!], `inspection_${Date.now()}.png`, {\n type: 'image/png'\n })\n } catch (error) {\n console.error('html2canvas 캡처 실패:', error)\n throw new Error('화면 캡처에 실패했습니다.')\n }\n }\n}\n"]}
|