@dssp/supervision 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist-client/pages/action-plan/action-plan-list-page.d.ts +6 -3
  2. package/dist-client/pages/action-plan/action-plan-list-page.js +26 -16
  3. package/dist-client/pages/action-plan/action-plan-list-page.js.map +1 -1
  4. package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.d.ts +3 -0
  5. package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js +16 -4
  6. package/dist-client/pages/building-inspection/building-inspection-detail-ai-measurement.js.map +1 -1
  7. package/dist-client/pages/building-inspection/building-inspection-detail-camera.d.ts +3 -0
  8. package/dist-client/pages/building-inspection/building-inspection-detail-camera.js +17 -1
  9. package/dist-client/pages/building-inspection/building-inspection-detail-camera.js.map +1 -1
  10. package/dist-client/pages/building-inspection/building-inspection-detail-checklist.d.ts +3 -0
  11. package/dist-client/pages/building-inspection/building-inspection-detail-checklist.js +22 -6
  12. package/dist-client/pages/building-inspection/building-inspection-detail-checklist.js.map +1 -1
  13. package/dist-client/pages/building-inspection/building-inspection-list.d.ts +3 -0
  14. package/dist-client/pages/building-inspection/building-inspection-list.js +27 -11
  15. package/dist-client/pages/building-inspection/building-inspection-list.js.map +1 -1
  16. package/dist-client/pages/building-inspection/building-inspection-management.d.ts +3 -0
  17. package/dist-client/pages/building-inspection/building-inspection-management.js +19 -5
  18. package/dist-client/pages/building-inspection/building-inspection-management.js.map +1 -1
  19. package/dist-client/pages/building-inspection/component/field-document/field-document-popup.d.ts +3 -0
  20. package/dist-client/pages/building-inspection/component/field-document/field-document-popup.js +24 -5
  21. package/dist-client/pages/building-inspection/component/field-document/field-document-popup.js.map +1 -1
  22. package/dist-client/pages/building-inspection-grid/building-inspection-grid-detail.d.ts +3 -0
  23. package/dist-client/pages/building-inspection-grid/building-inspection-grid-detail.js +27 -11
  24. package/dist-client/pages/building-inspection-grid/building-inspection-grid-detail.js.map +1 -1
  25. package/dist-client/pages/building-inspection-grid/component/notice-comment-popup.js +17 -2
  26. package/dist-client/pages/building-inspection-grid/component/notice-comment-popup.js.map +1 -1
  27. package/dist-client/pages/checklist/attachment-list-popup.js +22 -8
  28. package/dist-client/pages/checklist/attachment-list-popup.js.map +1 -1
  29. package/dist-client/pages/checklist/comment-list-popup.js +22 -8
  30. package/dist-client/pages/checklist/comment-list-popup.js.map +1 -1
  31. package/dist-client/pages/checklist/inspection-info-popup.d.ts +3 -0
  32. package/dist-client/pages/checklist/inspection-info-popup.js +12 -1
  33. package/dist-client/pages/checklist/inspection-info-popup.js.map +1 -1
  34. package/dist-client/pages/checklist-template/checklist-template-item.js +23 -3
  35. package/dist-client/pages/checklist-template/checklist-template-item.js.map +1 -1
  36. package/dist-client/pages/checklist-template/checklist-template-list.d.ts +3 -0
  37. package/dist-client/pages/checklist-template/checklist-template-list.js +21 -4
  38. package/dist-client/pages/checklist-template/checklist-template-list.js.map +1 -1
  39. package/dist-client/pages/checklist-template/checklist-type-management.d.ts +3 -0
  40. package/dist-client/pages/checklist-template/checklist-type-management.js +21 -4
  41. package/dist-client/pages/checklist-template/checklist-type-management.js.map +1 -1
  42. package/dist-client/pages/checklist-template/construction-checklist-template-item-popup.js +21 -3
  43. package/dist-client/pages/checklist-template/construction-checklist-template-item-popup.js.map +1 -1
  44. package/dist-client/pages/checklist-template/construction-checklist-template-list.d.ts +3 -0
  45. package/dist-client/pages/checklist-template/construction-checklist-template-list.js +18 -4
  46. package/dist-client/pages/checklist-template/construction-checklist-template-list.js.map +1 -1
  47. package/dist-client/pages/issue/issue-list-page.d.ts +6 -3
  48. package/dist-client/pages/issue/issue-list-page.js +26 -16
  49. package/dist-client/pages/issue/issue-list-page.js.map +1 -1
  50. package/dist-client/pages/project-checklist/project-checklist-management.d.ts +3 -0
  51. package/dist-client/pages/project-checklist/project-checklist-management.js +31 -9
  52. package/dist-client/pages/project-checklist/project-checklist-management.js.map +1 -1
  53. package/dist-client/pages/project-report/project-report-list-page.d.ts +6 -3
  54. package/dist-client/pages/project-report/project-report-list-page.js +26 -16
  55. package/dist-client/pages/project-report/project-report-list-page.js.map +1 -1
  56. package/dist-client/pages/supervisor/supervisor-list-page.d.ts +6 -3
  57. package/dist-client/pages/supervisor/supervisor-list-page.js +26 -16
  58. package/dist-client/pages/supervisor/supervisor-list-page.js.map +1 -1
  59. package/dist-client/route.d.ts +1 -1
  60. package/dist-client/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +3 -3
@@ -16,9 +16,15 @@ export declare class ActionPlanListPage extends ActionPlanListPage_base {
16
16
  };
17
17
  private gristConfig;
18
18
  private mode;
19
+ /** 뮤테이션 가능 여부('dcsp guest' 권한 보유 시 false) — 게스트에게는 생성/수정/삭제 버튼을 숨긴다 */
20
+ private canMutate;
19
21
  private grist;
20
22
  private sortersControl;
23
+ connectedCallback(): Promise<void>;
21
24
  get context(): {
25
+ importable?: {
26
+ handler: (records: any) => Promise<void>;
27
+ } | undefined;
22
28
  title: string;
23
29
  search: {
24
30
  handler: (search: string) => void;
@@ -43,9 +49,6 @@ export declare class ActionPlanListPage extends ActionPlanListPage_base {
43
49
  name: string;
44
50
  data: () => Promise<{}[]>;
45
51
  };
46
- importable: {
47
- handler: (records: any) => Promise<void>;
48
- };
49
52
  };
50
53
  render(): import("lit-html").TemplateResult<1>;
51
54
  pageInitialized(lifecycle: any): Promise<void>;
@@ -12,45 +12,51 @@ import { i18next, localize } from '@operato/i18n';
12
12
  import { notify, openPopup } from '@operato/layout';
13
13
  import { OxPopup, OxPrompt } from '@operato/popup';
14
14
  import { isMobileDevice } from '@operato/utils';
15
+ import { canDcspMutate } from '@dssp/building-complex/dist-client/utils/privilege';
15
16
  import gql from 'graphql-tag';
16
17
  import { ActionPlanImporter } from './action-plan-importer';
17
18
  let ActionPlanListPage = class ActionPlanListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
18
19
  constructor() {
19
20
  super(...arguments);
20
21
  this.mode = isMobileDevice() ? 'CARD' : 'GRID';
22
+ /** 뮤테이션 가능 여부('dcsp guest' 권한 보유 시 false) — 게스트에게는 생성/수정/삭제 버튼을 숨긴다 */
23
+ this.canMutate = false;
21
24
  }
22
25
  static get scopedElements() {
23
26
  return {
24
27
  'action-plan-importer': ActionPlanImporter
25
28
  };
26
29
  }
30
+ async connectedCallback() {
31
+ super.connectedCallback();
32
+ this.canMutate = await canDcspMutate();
33
+ this.updateContext();
34
+ }
27
35
  get context() {
28
- return {
29
- title: i18next.t('title.action-plan list'),
30
- search: {
36
+ return Object.assign({ title: i18next.t('title.action-plan list'), search: {
31
37
  handler: (search) => {
32
38
  this.grist.searchText = search;
33
39
  },
34
40
  value: this.grist.searchText
35
- },
36
- filter: {
41
+ }, filter: {
37
42
  handler: () => {
38
43
  this.grist.toggleHeadroom();
39
44
  }
40
- },
41
- help: 'supervision/action-plan',
42
- actions: [
43
- Object.assign({ title: i18next.t('button.save'), action: this.updateActionPlan.bind(this) }, CommonButtonStyles.save),
44
- Object.assign({ title: i18next.t('button.delete'), action: this.deleteActionPlan.bind(this) }, CommonButtonStyles.delete)
45
- ],
46
- exportable: {
45
+ }, help: 'supervision/action-plan', actions: this.canMutate
46
+ ? [
47
+ Object.assign({ title: i18next.t('button.save'), action: this.updateActionPlan.bind(this) }, CommonButtonStyles.save),
48
+ Object.assign({ title: i18next.t('button.delete'), action: this.deleteActionPlan.bind(this) }, CommonButtonStyles.delete)
49
+ ]
50
+ : [], exportable: {
47
51
  name: i18next.t('title.action-plan list'),
48
52
  data: this.exportHandler.bind(this)
49
- },
50
- importable: {
51
- handler: this.importHandler.bind(this)
53
+ } }, (this.canMutate
54
+ ? {
55
+ importable: {
56
+ handler: this.importHandler.bind(this)
57
+ }
52
58
  }
53
- };
59
+ : {}));
54
60
  }
55
61
  render() {
56
62
  const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID');
@@ -307,6 +313,10 @@ __decorate([
307
313
  state(),
308
314
  __metadata("design:type", String)
309
315
  ], ActionPlanListPage.prototype, "mode", void 0);
316
+ __decorate([
317
+ state(),
318
+ __metadata("design:type", Object)
319
+ ], ActionPlanListPage.prototype, "canMutate", void 0);
310
320
  __decorate([
311
321
  query('ox-grist'),
312
322
  __metadata("design:type", DataGrist)
@@ -1 +1 @@
1
- {"version":3,"file":"action-plan-list-page.js","sourceRoot":"","sources":["../../../client/pages/action-plan/action-plan-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\n\nimport { CommonButtonStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'\nimport { PageView, store, connect } from '@operato/shell'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ColumnConfig, DataGrist, FetchOption, SortersControl } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { OxPopup, OxPrompt } from '@operato/popup'\nimport { isMobileDevice } from '@operato/utils'\n\nimport gql from 'graphql-tag'\n\nimport { ActionPlanImporter } from './action-plan-importer'\n\n@customElement('action-plan-list-page')\nexport class ActionPlanListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {\n static styles = [\n ScrollbarStyles,\n CommonGristStyles,\n css`\n :host {\n display: flex;\n\n width: 100%;\n\n --grid-record-emphasized-background-color: red;\n --grid-record-emphasized-color: yellow;\n }\n `\n ]\n\n static get scopedElements() {\n return {\n 'action-plan-importer': ActionPlanImporter\n }\n }\n\n @state() private gristConfig: any\n @state() private mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @query('ox-grist') private grist!: DataGrist\n @query('#sorter-control') private sortersControl!: OxPopup\n\n get context() {\n return {\n title: i18next.t('title.action-plan list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist.searchText\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n help: 'supervision/action-plan',\n actions: [\n {\n title: i18next.t('button.save'),\n action: this.updateActionPlan.bind(this),\n ...CommonButtonStyles.save\n },\n {\n title: i18next.t('button.delete'),\n action: this.deleteActionPlan.bind(this),\n ...CommonButtonStyles.delete\n }\n ],\n exportable: {\n name: i18next.t('title.action-plan list'),\n data: this.exportHandler.bind(this)\n },\n importable: {\n handler: this.importHandler.bind(this)\n }\n }\n }\n\n render() {\n const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>\n <div slot=\"headroom\">\n <div id=\"filters\">\n <ox-filters-form autofocus></ox-filters-form>\n </div>\n\n <div id=\"sorters\">\n Sort\n <md-icon\n @click=${e => {\n const target = e.currentTarget\n this.sortersControl.open({\n right: 0,\n top: target.offsetTop + target.offsetHeight\n })\n }}\n >expand_more</md-icon\n >\n <ox-popup id=\"sorter-control\">\n <ox-sorters-control> </ox-sorters-control>\n </ox-popup>\n </div>\n\n <div id=\"modes\">\n <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</md-icon>\n <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</md-icon>\n <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>\n </div>\n </div>\n </ox-grist>\n `\n }\n\n async pageInitialized(lifecycle: any) {\n this.gristConfig = {\n list: {\n fields: ['name', 'description'],\n details: ['active', 'updatedAt']\n },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: true },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n editable: true\n },\n filter: 'search',\n sortable: true,\n width: 150\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n editable: true\n },\n filter: 'search',\n width: 200\n },\n {\n type: 'checkbox',\n name: 'active',\n label: true,\n header: i18next.t('field.active'),\n record: {\n editable: true\n },\n filter: true,\n sortable: true,\n width: 60\n },\n {\n type: 'resource-object',\n name: 'updater',\n header: i18next.t('field.updater'),\n record: {\n editable: false\n },\n sortable: true,\n width: 120\n },\n {\n type: 'datetime',\n name: 'updatedAt',\n header: i18next.t('field.updated_at'),\n record: {\n editable: false\n },\n sortable: true,\n width: 180\n }\n ],\n rows: {\n selectable: {\n multiple: true\n }\n },\n sorters: [\n {\n name: 'name'\n }\n ]\n }\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (this.active) {\n // do something here when this page just became as active\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: actionPlans(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n name\n description\n active\n updater {\n id\n name\n }\n updatedAt\n }\n total\n }\n }\n `,\n variables: {\n filters,\n pagination: { page, limit },\n sortings\n }\n })\n\n return {\n total: response.data.responses.total || 0,\n records: response.data.responses.items || []\n }\n }\n\n private async deleteActionPlan() {\n if (\n await OxPrompt.open({\n title: i18next.t('text.are_you_sure'),\n text: i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }),\n confirmButton: { text: i18next.t('button.confirm') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n ) {\n const ids = this.grist.selected.map(record => record.id)\n if (ids && ids.length > 0) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($ids: [String!]!) {\n deleteActionPlans(ids: $ids)\n }\n `,\n variables: {\n ids\n }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n notify({\n message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })\n })\n }\n }\n }\n }\n\n private async updateActionPlan() {\n let patches = this.grist.dirtyRecords\n if (patches && patches.length) {\n patches = patches.map(patch => {\n let patchField: any = patch.id ? { id: patch.id } : {}\n const dirtyFields = patch.__dirtyfields__\n for (let key in dirtyFields) {\n patchField[key] = dirtyFields[key].after\n }\n patchField.cuFlag = patch.__dirty__\n\n return patchField\n })\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [ActionPlanPatch!]!) {\n updateMultipleActionPlan(patches: $patches) {\n name\n }\n }\n `,\n variables: {\n patches\n }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n }\n }\n }\n\n private async exportHandler() {\n const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records\n const targetFieldSet = new Set(['id', 'name', 'description', 'active'])\n\n return exportTargets.map(actionPlan => {\n let tempObj = {}\n for (const field of targetFieldSet) {\n tempObj[field] = actionPlan[field]\n }\n\n return tempObj\n })\n }\n\n private async importHandler(records) {\n const popup = openPopup(\n html`\n <action-plan-importer\n .actionPlans=${records}\n @imported=${() => {\n history.back()\n this.grist.fetch()\n }}\n ></action-plan-importer>\n `,\n {\n backdrop: true,\n size: 'large',\n title: i18next.t('title.import action-plan')\n }\n )\n\n popup.onclosed = () => {\n this.grist.fetch()\n }\n }\n}\n"]}
1
+ {"version":3,"file":"action-plan-list-page.js","sourceRoot":"","sources":["../../../client/pages/action-plan/action-plan-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\n\nimport { CommonButtonStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'\nimport { PageView, store, connect } from '@operato/shell'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ColumnConfig, DataGrist, FetchOption, SortersControl } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { OxPopup, OxPrompt } from '@operato/popup'\nimport { isMobileDevice } from '@operato/utils'\nimport { canDcspMutate } from '@dssp/building-complex/dist-client/utils/privilege'\n\nimport gql from 'graphql-tag'\n\nimport { ActionPlanImporter } from './action-plan-importer'\n\n@customElement('action-plan-list-page')\nexport class ActionPlanListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {\n static styles = [\n ScrollbarStyles,\n CommonGristStyles,\n css`\n :host {\n display: flex;\n\n width: 100%;\n\n --grid-record-emphasized-background-color: red;\n --grid-record-emphasized-color: yellow;\n }\n `\n ]\n\n static get scopedElements() {\n return {\n 'action-plan-importer': ActionPlanImporter\n }\n }\n\n @state() private gristConfig: any\n @state() private mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'\n /** 뮤테이션 가능 여부('dcsp guest' 권한 보유 시 false) — 게스트에게는 생성/수정/삭제 버튼을 숨긴다 */\n @state() private canMutate = false\n\n @query('ox-grist') private grist!: DataGrist\n @query('#sorter-control') private sortersControl!: OxPopup\n\n async connectedCallback() {\n super.connectedCallback()\n this.canMutate = await canDcspMutate()\n this.updateContext()\n }\n\n get context() {\n return {\n title: i18next.t('title.action-plan list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist.searchText\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n help: 'supervision/action-plan',\n actions: this.canMutate\n ? [\n {\n title: i18next.t('button.save'),\n action: this.updateActionPlan.bind(this),\n ...CommonButtonStyles.save\n },\n {\n title: i18next.t('button.delete'),\n action: this.deleteActionPlan.bind(this),\n ...CommonButtonStyles.delete\n }\n ]\n : [],\n exportable: {\n name: i18next.t('title.action-plan list'),\n data: this.exportHandler.bind(this)\n },\n ...(this.canMutate\n ? {\n importable: {\n handler: this.importHandler.bind(this)\n }\n }\n : {})\n }\n }\n\n render() {\n const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>\n <div slot=\"headroom\">\n <div id=\"filters\">\n <ox-filters-form autofocus></ox-filters-form>\n </div>\n\n <div id=\"sorters\">\n Sort\n <md-icon\n @click=${e => {\n const target = e.currentTarget\n this.sortersControl.open({\n right: 0,\n top: target.offsetTop + target.offsetHeight\n })\n }}\n >expand_more</md-icon\n >\n <ox-popup id=\"sorter-control\">\n <ox-sorters-control> </ox-sorters-control>\n </ox-popup>\n </div>\n\n <div id=\"modes\">\n <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</md-icon>\n <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</md-icon>\n <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>\n </div>\n </div>\n </ox-grist>\n `\n }\n\n async pageInitialized(lifecycle: any) {\n this.gristConfig = {\n list: {\n fields: ['name', 'description'],\n details: ['active', 'updatedAt']\n },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: true },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n editable: true\n },\n filter: 'search',\n sortable: true,\n width: 150\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n editable: true\n },\n filter: 'search',\n width: 200\n },\n {\n type: 'checkbox',\n name: 'active',\n label: true,\n header: i18next.t('field.active'),\n record: {\n editable: true\n },\n filter: true,\n sortable: true,\n width: 60\n },\n {\n type: 'resource-object',\n name: 'updater',\n header: i18next.t('field.updater'),\n record: {\n editable: false\n },\n sortable: true,\n width: 120\n },\n {\n type: 'datetime',\n name: 'updatedAt',\n header: i18next.t('field.updated_at'),\n record: {\n editable: false\n },\n sortable: true,\n width: 180\n }\n ],\n rows: {\n selectable: {\n multiple: true\n }\n },\n sorters: [\n {\n name: 'name'\n }\n ]\n }\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (this.active) {\n // do something here when this page just became as active\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: actionPlans(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n name\n description\n active\n updater {\n id\n name\n }\n updatedAt\n }\n total\n }\n }\n `,\n variables: {\n filters,\n pagination: { page, limit },\n sortings\n }\n })\n\n return {\n total: response.data.responses.total || 0,\n records: response.data.responses.items || []\n }\n }\n\n private async deleteActionPlan() {\n if (\n await OxPrompt.open({\n title: i18next.t('text.are_you_sure'),\n text: i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }),\n confirmButton: { text: i18next.t('button.confirm') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n ) {\n const ids = this.grist.selected.map(record => record.id)\n if (ids && ids.length > 0) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($ids: [String!]!) {\n deleteActionPlans(ids: $ids)\n }\n `,\n variables: {\n ids\n }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n notify({\n message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })\n })\n }\n }\n }\n }\n\n private async updateActionPlan() {\n let patches = this.grist.dirtyRecords\n if (patches && patches.length) {\n patches = patches.map(patch => {\n let patchField: any = patch.id ? { id: patch.id } : {}\n const dirtyFields = patch.__dirtyfields__\n for (let key in dirtyFields) {\n patchField[key] = dirtyFields[key].after\n }\n patchField.cuFlag = patch.__dirty__\n\n return patchField\n })\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [ActionPlanPatch!]!) {\n updateMultipleActionPlan(patches: $patches) {\n name\n }\n }\n `,\n variables: {\n patches\n }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n }\n }\n }\n\n private async exportHandler() {\n const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records\n const targetFieldSet = new Set(['id', 'name', 'description', 'active'])\n\n return exportTargets.map(actionPlan => {\n let tempObj = {}\n for (const field of targetFieldSet) {\n tempObj[field] = actionPlan[field]\n }\n\n return tempObj\n })\n }\n\n private async importHandler(records) {\n const popup = openPopup(\n html`\n <action-plan-importer\n .actionPlans=${records}\n @imported=${() => {\n history.back()\n this.grist.fetch()\n }}\n ></action-plan-importer>\n `,\n {\n backdrop: true,\n size: 'large',\n title: i18next.t('title.import action-plan')\n }\n )\n\n popup.onclosed = () => {\n this.grist.fetch()\n }\n }\n}\n"]}
@@ -31,7 +31,10 @@ export declare class BuildingInspectionAiMeasurement extends PageView {
31
31
  expandedReportId: string | null;
32
32
  loading: boolean;
33
33
  loadingText: string;
34
+ /** 뮤테이션 가능 여부('dcsp guest' 권한 보유 시 false) — 게스트에게는 생성/수정/삭제 버튼을 숨긴다 */
35
+ private canMutate;
34
36
  private photoInputEl;
37
+ connectedCallback(): Promise<void>;
35
38
  private pendingSlotIndex;
36
39
  get context(): {
37
40
  title: string;
@@ -17,6 +17,7 @@ import { PageView, navigate } from '@operato/shell';
17
17
  import { ScrollbarStyles } from '@operato/styles';
18
18
  import { client } from '@operato/graphql';
19
19
  import { notify } from '@operato/layout';
20
+ import { canDcspMutate } from '@dssp/building-complex/dist-client/utils/privilege';
20
21
  import './component/building-inspection-detail-header';
21
22
  const ENGINE_BASE_URL = 'https://hatiolab-korea-uni.nruing.com';
22
23
  const ENGINE_RUN_URL = `${ENGINE_BASE_URL}/api/run/inspection-ai`;
@@ -52,6 +53,8 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
52
53
  this.expandedReportId = null; // 종합 리포트에서 펼친 항목(아코디언)
53
54
  this.loading = false;
54
55
  this.loadingText = '';
56
+ /** 뮤테이션 가능 여부('dcsp guest' 권한 보유 시 false) — 게스트에게는 생성/수정/삭제 버튼을 숨긴다 */
57
+ this.canMutate = false;
55
58
  /* 슬롯 클릭으로 선택기를 연 경우 대상 슬롯 인덱스 (null이면 뒤에 추가) */
56
59
  this.pendingSlotIndex = null;
57
60
  this._resetPhotos = () => {
@@ -68,6 +71,11 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
68
71
  this.selectedItem = null;
69
72
  };
70
73
  }
74
+ async connectedCallback() {
75
+ super.connectedCallback();
76
+ this.canMutate = await canDcspMutate();
77
+ this.updateContext();
78
+ }
71
79
  get context() {
72
80
  return {
73
81
  title: '검측 관리 상세 - AI 자동 검측'
@@ -412,7 +420,9 @@ let BuildingInspectionAiMeasurement = class BuildingInspectionAiMeasurement exte
412
420
  `;
413
421
  })}
414
422
  </div>
415
- <button class="primary-button" @click=${this._registerInspection}>검사 등록</button>
423
+ ${this.canMutate
424
+ ? html `<button class="primary-button" @click=${this._registerInspection}>검사 등록</button>`
425
+ : ''}
416
426
  <button class="text-button" @click=${this._closePanel}>닫기</button>
417
427
  </div>
418
428
  `;
@@ -1394,11 +1404,13 @@ __decorate([
1394
1404
  state(),
1395
1405
  __metadata("design:type", String)
1396
1406
  ], BuildingInspectionAiMeasurement.prototype, "loadingText", void 0);
1407
+ __decorate([
1408
+ state(),
1409
+ __metadata("design:type", Object)
1410
+ ], BuildingInspectionAiMeasurement.prototype, "canMutate", void 0);
1397
1411
  __decorate([
1398
1412
  query('#photoInput'),
1399
- __metadata("design:type", HTMLInputElement
1400
- /* 슬롯 클릭으로 선택기를 연 경우 대상 슬롯 인덱스 (null이면 뒤에 추가) */
1401
- )
1413
+ __metadata("design:type", HTMLInputElement)
1402
1414
  ], BuildingInspectionAiMeasurement.prototype, "photoInputEl", void 0);
1403
1415
  BuildingInspectionAiMeasurement = __decorate([
1404
1416
  customElement('building-inspection-detail-ai-measurement')
@@ -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.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"]}
1
+ {"version":3,"file":"building-inspection-detail-ai-measurement.js","sourceRoot":"","sources":["../../../client/pages/building-inspection/building-inspection-detail-ai-measurement.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AACH,OAAO,4BAA4B,CAAA;AACnC,OAAO,6CAA6C,CAAA;AAEpD,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE/D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,oDAAoD,CAAA;AAElF,OAAO,+CAA+C,CAAA;AAEtD,MAAM,eAAe,GAAG,uCAAuC,CAAA;AAC/D,MAAM,cAAc,GAAG,GAAG,eAAe,wBAAwB,CAAA;AACjE,MAAM,WAAW,GAAG,SAAS,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAA;AACtD,MAAM,UAAU,GAAG,CAAC,CAAA;AAEpB,4EAA4E;AAC5E,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,IAAI;CACZ,CAAA;AAED,6BAA6B;AAC7B,MAAM,aAAa,GAAG;IACpB,GAAG,EAAE,SAAS;IACd,EAAE,EAAE,OAAO;IACX,UAAU,EAAE,UAAU;CACvB,CAAA;AAKM,IAAM,+BAA+B,GAArC,MAAM,+BAAgC,SAAQ,QAAQ;IAAtD;;QAgnBI,YAAO,GAAQ,EAAE,CAAA;QACjB,uBAAkB,GAAQ,EAAE,CAAA;QAC5B,yBAAoB,GAAW,EAAE,CAAA;QAEjC,UAAK,GAAQ,IAAI,CAAA,CAAC,+CAA+C;QACjE,WAAM,GAAkC,EAAE,CAAA;QAC1C,WAAM,GAAQ,IAAI,CAAA,CAAC,aAAa;QAChC,mBAAc,GAAW,CAAC,CAAA;QAE1B,UAAK,GAAc,MAAM,CAAA;QACzB,iBAAY,GAAQ,IAAI,CAAA;QACxB,kBAAa,GAAW,CAAC,CAAA,CAAC,qBAAqB;QAC/C,qBAAgB,GAAkB,IAAI,CAAA,CAAC,uBAAuB;QAE9D,YAAO,GAAY,KAAK,CAAA;QACxB,gBAAW,GAAW,EAAE,CAAA;QACjC,uEAAuE;QACtD,cAAS,GAAG,KAAK,CAAA;QAUlC,gDAAgD;QACxC,qBAAgB,GAAkB,IAAI,CAAA;QA8kBtC,iBAAY,GAAG,GAAG,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACpD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;QAClB,CAAC,CAAA;QA8BO,gBAAW,GAAG,GAAG,EAAE;YACzB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAA;YACrB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;YACxB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAA;QAC9B,CAAC,CAAA;QAOO,gBAAW,GAAG,GAAG,EAAE;YACzB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAA;YACnB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;QAC1B,CAAC,CAAA;IAqFH,CAAC;IAztBC,KAAK,CAAC,iBAAiB;QACrB,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,IAAI,CAAC,SAAS,GAAG,MAAM,aAAa,EAAE,CAAA;QACtC,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAKD,IAAI,OAAO;QACT,OAAO;YACL,KAAK,EAAE,qBAAqB;SAC7B,CAAA;IACH,CAAC;IAED,wDAAwD;IACxD,IAAI,eAAe;;QACjB,MAAM,KAAK,GAAG,CAAA,MAAA,MAAA,IAAI,CAAC,kBAAkB,0CAAE,SAAS,0CAAE,cAAc,KAAI,EAAE,CAAA;QACtE,OAAO,CAAC,GAAG,KAAK,CAAC;aACd,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;aACrD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACZ,OAAO,EAAE,IAAI,CAAC,EAAE;YAChB,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;YACtE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;SACtB,CAAC,CAAC,CAAA;IACP,CAAC;IAED,MAAM;;QACJ,OAAO,IAAI,CAAA;;gCAEiB,MAAA,IAAI,CAAC,kBAAkB,0CAAE,EAAE;2BAChC,MAAA,MAAA,IAAI,CAAC,kBAAkB,0CAAE,aAAa,0CAAE,EAAE;uBAC9C,IAAI,CAAC,OAAO,CAAC,IAAI;wBAChB,MAAA,MAAA,MAAA,IAAI,CAAC,kBAAkB,0CAAE,aAAa,0CAAE,QAAQ,0CAAE,IAAI;8BAChD,MAAA,MAAA,IAAI,CAAC,kBAAkB,0CAAE,aAAa,0CAAE,KAAK;qBACtD,IAAI,CAAC,OAAO,CAAC,EAAE;;;;;uBAKb,CAAA,MAAA,MAAA,IAAI,CAAC,kBAAkB,0CAAE,SAAS,0CAAE,QAAQ,KAAI,EAAE;yBAChD,CAAA,MAAA,MAAA,IAAI,CAAC,kBAAkB,0CAAE,SAAS,0CAAE,IAAI,KAAI,EAAE;;;UAG7D,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE;;;;6EAIW,IAAI,CAAC,iBAAiB;;QAG3F,IAAI,CAAC,OAAO;YACV,CAAC,CAAC,IAAI,CAAA;;;;0BAIU,IAAI,CAAC,WAAW;;;aAG7B;YACH,CAAC,CAAC,EACN;KACD,CAAA;IACH,CAAC;IAED,4BAA4B;IACpB,YAAY;QAClB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO,IAAI,CAAA,mDAAmD,CAAA;QAChE,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAA;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,MAAM,CAAA;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAA;QAChC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;QACxD,MAAM,IAAI,GAAG,KAAK,IAAI,KAAK,CAAA;QAE3B,OAAO,IAAI,CAAA;;kCAEmB,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,KAAI,IAAI;mCACxD,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,KAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;;;;;;cAMjE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAA,OAAO,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC;;;;;;;oBAO/C,KAAK,MAAM,KAAK;;yDAEqB,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9E,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA,iCAAiC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,MAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,CAAA,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE;;cAE7F,KAAK,CAAC,GAAG,CACT,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;2CACe,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;oBAErD,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACZ,CAAC,CAAC,IAAI,CAAA,YAAY,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,KAAK;YACzD,CAAC,CAAC,IAAI,CAAA,iCAAiC,CAAC,CAAC,MAAM,EACnD;;eAEH,CACF;;;;mDAIsC,KAAK,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE;kBAClF,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE;;UAG1C,KAAK,GAAG,CAAC;YACP,CAAC,CAAC,IAAI,CAAA;;uDAEqC,IAAI,CAAC,YAAY;;eAEzD;YACH,CAAC,CAAC,EACN;;KAEH,CAAA;IACH,CAAC;IAED,2BAA2B;IACnB,aAAa;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAA;QACjC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,KAAK,MAAM,IAAI,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC,CAAA;QACpF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,KAAK,MAAM,IAAI,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC,CAAA;QAEpF,4EAA4E;QAC5E,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QAClE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;QACjC,KAAK,MAAM,EAAE,IAAI,UAAU;YAAE,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACjF,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACvG,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAEjD,OAAO,IAAI,CAAA;;;;oCAIqB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA,YAAY,SAAS,CAAC,KAAK,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE;;cAE3F,UAAU,CAAC,GAAG,CACd,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;;wBAEJ,CAAC,CAAC,KAAK,CAAC,GAAG;4BACP,CAAC,CAAC,EAAE;8BACF,CAAC,KAAK,IAAI,CAAC,cAAc;2BAC5B,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;;eAE3C,CACF;;;;;;oBAMO,KAAK,CAAC,MAAM,aAAa,SAAS,CAAC,MAAM,aAAa,SAAS,CAAC,MAAM;;;YAI9E,SAAS,CAAC,MAAM;YACd,CAAC,CAAC,IAAI,CAAA;uDACmC,SAAS,CAAC,MAAM;oBACnD,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;iBAC5D;YACH,CAAC,CAAC,EACN;YAEE,SAAS,CAAC,MAAM;YACd,CAAC,CAAC,IAAI,CAAA;uDACmC,SAAS,CAAC,MAAM;oBACnD,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;iBAC5D;YACH,CAAC,CAAC,EACN;;kDAEwC,IAAI,CAAC,WAAW;;;UAGxD,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE;;KAExD,CAAA;IACH,CAAC;IAEO,eAAe,CAAC,IAAS,EAAE,EAAU;;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,CAAA;QAC/D,OAAO,IAAI,CAAA;yCAC0B,CAAA,MAAA,IAAI,CAAC,YAAY,0CAAE,OAAO,MAAK,IAAI,CAAC,OAAO,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;+BAC5F,EAAE;;mCAEE,IAAI,CAAC,IAAI;;iCAEX,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO;yCACnC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO;;mCAEjD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE;;UAGzF,IAAI;YACF,CAAC,CAAC,IAAI,CAAA;2CACyB,IAAI,CAAC,OAAO,KAAK,MAAM,UAAU,IAAI,CAAC,OAAO,KAAK,MAAM;oBAC/E,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;;eAEhC;YACH,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,MAAM;gBACvB,CAAC,CAAC,IAAI,CAAA;;;6BAGS,CAAC,CAAQ,EAAE,EAAE;oBACpB,CAAC,CAAC,eAAe,EAAE,CAAA;oBACnB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;gBAC3B,CAAC;;;;iBAIJ;gBACH,CAAC,CAAC,IAAI,CAAA,0BAA0B,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,QACjF;;KAEH,CAAA;IACH,CAAC;IAED,mCAAmC;IAC3B,eAAe;QACrB,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAClG,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACxG,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,iBAAiB,EAAE,CAAA;QAC5D,OAAO,EAAE,CAAA;IACX,CAAC;IAEO,iBAAiB,CAAC,IAAS;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,CAAA;QAC/D,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAA;QAChE,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAA;QAEhE,OAAO,IAAI,CAAA;;;sCAGuB,IAAI,CAAC,OAAO,KAAK,MAAM,UAAU,IAAI,CAAC,OAAO,KAAK,MAAM,SAAS,CAAC,IAAI;cAC9F,YAAY;;gBAEV,YAAY;;sCAEU,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;;;;gDAIvC,IAAI,CAAC,OAAO,KAAK,MAAM,UAAU,IAAI,CAAC,OAAO,KAAK,MAAM;gBACxF,YAAY,IAAI,GAAG;;;YAIvB,IAAI,CAAC,UAAU,IAAI,IAAI;YACrB,CAAC,CAAC,IAAI,CAAA;;;4BAGQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;;iBAE5C;YACH,CAAC,CAAC,EACN;;;oBAGU,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,GAAG;;;;;;;cAOxD,IAAI,CAAC,MAAM;;;;6CAIoB,IAAI,CAAC,WAAW;;KAExD,CAAA;IACH,CAAC;IAEO,oBAAoB,CAAC,IAAS;;QACpC,MAAM,KAAK,GAAG,CAAA,MAAA,IAAI,CAAC,eAAe,0CAAE,MAAM;YACxC,CAAC,CAAC,IAAI,CAAC,eAAe;YACtB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,oBAAoB,EAAE,CAAC,CAAA;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAA;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAA;QAE1B,OAAO,IAAI,CAAA;;cAED,IAAI,CAAC,IAAI;;;YAGX,IAAI,CAAC,MAAM,IAAI,sBAAsB;;;;;;;cAOnC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAA,OAAO,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC;;;;;kBAKjD,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,KAAK;;uDAEI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;;YAEvF,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACnB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAA;YACjD,OAAO,IAAI,CAAA;yCACkB,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;kBAC1E,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,YAAY,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,iCAAiC,CAAC,CAAC,MAAM,EAAE;;aAE7G,CAAA;QACH,CAAC,CAAC;;UAGF,KAAK,GAAG,CAAC;YACP,CAAC,CAAC,IAAI,CAAA,yCAAyC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,KAAK,aAAa;YACxG,CAAC,CAAC,EACN;6CACqC,IAAI,CAAC,WAAW;;KAExD,CAAA;IACH,CAAC;IAEO,iBAAiB;;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAA;QACjC,MAAM,OAAO,GAAG,CAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,OAAO,KAAI,EAAE,CAAA;QAC1C,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAA;QAEpF,OAAO,IAAI,CAAA;;;;yBAIU,OAAO,CAAC,IAAI,IAAI,CAAC;yBACjB,OAAO,CAAC,IAAI,IAAI,CAAC;wBAClB,QAAQ;;;YAGpB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;;YACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,KAAK,EAAE,CAAC,OAAO,CAAA;YACrD,OAAO,IAAI,CAAA;;kDAE2B,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,OAAO,CAAC;8CAC5C,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI;;;4BAGnC,EAAE,CAAC,OAAO,KAAK,MAAM;4BACrB,EAAE,CAAC,OAAO,KAAK,MAAM;2BACtB,EAAE,CAAC,OAAO,KAAK,MAAM,IAAI,EAAE,CAAC,OAAO,KAAK,MAAM;;sBAEnD,aAAa,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO;;wDAEL,QAAQ;;kBAG9C,QAAQ;gBACN,CAAC,CAAC,IAAI,CAAA;;4BAEE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA,0BAA0B,CAAC,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE;4BACrF,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA,YAAY,EAAE,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,EAAE;4BAC5D,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA,YAAY,EAAE,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE;4BAElD,CAAA,MAAA,EAAE,CAAC,WAAW,0CAAE,MAAM;oBACpB,CAAC,CAAC,IAAI,CAAA,mCAAmC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;oBAC5F,CAAC,CAAC,EACN;;uBAEH;gBACH,CAAC,CAAC,EACN;;aAEH,CAAA;QACH,CAAC,CAAC;;UAEF,IAAI,CAAC,SAAS;YACd,CAAC,CAAC,IAAI,CAAA,yCAAyC,IAAI,CAAC,mBAAmB,iBAAiB;YACxF,CAAC,CAAC,EAAE;6CAC+B,IAAI,CAAC,WAAW;;KAExD,CAAA;IACH,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,WAAW,CAAC,OAAY,EAAE,SAAwB;QACtD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,EAAE,CAAA;YAChB,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC,UAAU,IAAI,EAAE,CAAA;YACtD,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;YAC5D,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;QAC7B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,uBAA+B,EAAE;;QAC5D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BT;YACD,SAAS,EAAE,EAAE,oBAAoB,EAAE;SACpC,CAAC,CAAA;QAEF,IAAI,QAAQ,CAAC,MAAM;YAAE,OAAM;QAE3B,IAAI,CAAC,kBAAkB,GAAG,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAA;QAE1D,MAAM,IAAI,CAAC,8BAA8B,CAAC,MAAA,MAAA,MAAA,MAAA,IAAI,CAAC,kBAAkB,0CAAE,aAAa,0CAAE,QAAQ,0CAAE,eAAe,0CAAE,EAAE,CAAC,CAAA;IAClH,CAAC;IAEO,KAAK,CAAC,8BAA8B,CAAC,iBAAiB;QAC5D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,GAAG,CAAA;;;;;;;OAOT;YACD,SAAS,EAAE,EAAE,iBAAiB,EAAE;SACjC,CAAC,CAAA;QAEF,IAAI,QAAQ,CAAC,MAAM;YAAE,OAAM;QAE3B,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAA;IACtC,CAAC;IAED,mBAAmB;IAEnB,sDAAsD;IAC9C,KAAK,CAAC,WAAW,CAAC,KAAU,EAAE,QAAgB,EAAE;QACtD,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAA;QAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3C,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAE/D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE;YAC3C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,WAAW,EAAE;YACvC,IAAI,EAAE,IAAI;SACX,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QACjC,MAAM,IAAI,GAAG,CAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,MAAM,KAAI,EAAE,CAAA;QAC9B,IAAI,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,MAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,KAAK,MAAI,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,KAAK,CAAA,IAAI,mBAAmB,CAAC,CAAA;QACnE,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,kCAAkC;IAC1B,KAAK,CAAC,cAAc;QAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAA;QACtC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACtB,MAAM,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;YACrD,OAAM;QACR,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;YACnB,IAAI,CAAC,WAAW,GAAG,mBAAmB,CAAA;YACtC,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAA;QAC1E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;YACrC,MAAM,CAAC,EAAE,OAAO,EAAG,KAAe,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QAC/D,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACtB,CAAC;IACH,CAAC;IAED;;2DAEuD;IAC/C,KAAK,CAAC,cAAc;QAC1B,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAA;QACrE,mCAAmC;QACnC,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAClG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;YACnD,OAAM;QACR,CAAC;QACD,MAAM,SAAS,GAAG,WAAW;YAC3B,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YAC3E,CAAC,CAAC,IAAI,CAAC,eAAe,CAAA;QAExB,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;YACnB,IAAI,CAAC,WAAW,GAAG,4BAA4B,CAAA;YAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,CAAA;YAE9E,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAA;YACpC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;YACtB,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAA;YACnB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;YACxB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAA;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;YACpC,MAAM,CAAC,EAAE,OAAO,EAAG,KAAe,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QAC/D,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACtB,CAAC;IACH,CAAC;IAED;;mCAE+B;IACvB,qBAAqB,CAAC,MAAW;;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAA;QAC/B,MAAM,OAAO,GAAG,CAAC,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,YAAY,MAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAA,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAO,EAAE,EAAE,CAAC,iCAC1E,EAAE,KACL,WAAW,EAAE,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,IAChE,CAAC,CAAA;QACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAO,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;QAChE,MAAM,OAAO,GAAG,CAAC,GAAU,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;QAEjF,MAAM,KAAK,GAAG,OAAO,CAAC,MAAA,IAAI,CAAC,MAAM,0CAAE,KAAK,CAAC,CAAA;QACzC,MAAM,WAAW,GAAG,CAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,YAAY,EAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAE7F,MAAM,OAAO,GAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;QAC3F,KAAK,MAAM,EAAE,IAAI,WAAW,IAAI,KAAK;YAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;QAE3F,IAAI,CAAC,MAAM,+DAAQ,IAAI,CAAC,MAAM,KAAE,KAAK,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAE,OAAO,GAAE,CAAA;IACzG,CAAC;IAED,mBAAmB;IACnB,uDAAuD;IAC/C,gBAAgB,CAAC,YAA2B,IAAI;;QACtD,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAA;QACjC,MAAA,IAAI,CAAC,YAAY,0CAAE,KAAK,EAAE,CAAA;IAC5B,CAAC;IAEO,iBAAiB,CAAC,KAAY;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B,CAAA;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,KAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAChH,KAAK,CAAC,KAAK,GAAG,EAAE,CAAA;QAChB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAA;QACvC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAA;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAM;QAEzB,uCAAuC;QACvC,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACzD,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAA;YAC/C,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;YAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;YACxE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;YAClB,OAAM;QACR,CAAC;QAED,uBAAuB;QACvB,sDAAsD;QACtD,4DAA4D;QAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;QACrE,MAAM,GAAG,GAAG,SAAS,GAAG,UAAU,CAAA;QAClC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC5C,MAAM,CAAC,EAAE,OAAO,EAAE,cAAc,UAAU,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;YAC7E,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACpD,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,OAAM;QAC3B,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAClG,CAAC;IAOO,SAAS;QACf,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAClB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAA;QACnB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;QACxB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAA;QACvB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;IACxB,CAAC;IAED,sBAAsB;IACd,WAAW,CAAC,IAAS;QAC3B,mDAAmD;QACnD,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;YACzB,OAAM;QACR,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;QACxB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAA,CAAC,sBAAsB;QAC9C,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAA;IACvB,CAAC;IAEO,cAAc,CAAC,IAAS;QAC9B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;QACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAA;QACvC,IAAI,CAAC,KAAK,GAAG,WAAW,CAAA;IAC1B,CAAC;IAQD,oCAAoC;IAC5B,iBAAiB,CAAC,EAAU;QAClC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;IAClE,CAAC;IAOO,YAAY;;QAClB,OAAO,CAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,YAAY,MAAI,MAAA,IAAI,CAAC,MAAM,0CAAE,KAAK,CAAA,IAAI,EAAE,CAAA;IAC9D,CAAC;IAED,oDAAoD;IAC5C,KAAK,CAAC,mBAAmB;;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAA;QACjC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;YAClD,OAAM;QACR,CAAC;QACD,+CAA+C;QAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,KAAK,MAAM,IAAI,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC,CAAA;QAEjF,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;YACnB,IAAI,CAAC,WAAW,GAAG,eAAe,CAAA;YAElC,gDAAgD;YAChD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;oBACnC,QAAQ,EAAE,GAAG,CAAA;;;;WAIZ;oBACD,SAAS,EAAE;wBACT,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;4BACvB,EAAE,EAAE,EAAE,CAAC,OAAO;4BACd,wBAAwB,EAAE,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;yBAC5D,CAAC,CAAC;qBACJ;iBACF,CAAC,CAAA;gBAEF,IAAI,QAAQ,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,CAAA,MAAA,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,0CAAE,OAAO,KAAI,gBAAgB,CAAC,CAAA;YACvF,CAAC;YAED,yDAAyD;YACzD,MAAM,WAAW,GAAU,EAAE,CAAA;YAC7B,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;oBACjB,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;wBAC1G,KAAK,EAAE,EAAE,CAAC,OAAO;wBACjB,OAAO,EAAE,eAAe;wBACxB,WAAW,EAAE,MAAM;qBACpB,CAAC,CAAA;gBACJ,CAAC;gBACD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;oBACrC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;oBAChC,IAAI,KAAK,EAAE,CAAC;wBACV,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAA;oBAC1G,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;gBACvB,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;oBACzC,QAAQ,EAAE,GAAG,CAAA;;;;;;WAMZ;oBACD,SAAS,EAAE,EAAE,WAAW,EAAE;oBAC1B,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;iBAC7B,CAAC,CAAA;gBAEF,IAAI,cAAc,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,CAAA,MAAA,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,0CAAE,OAAO,KAAI,qBAAqB,CAAC,CAAA;YACxG,CAAC;YAED,MAAM,CAAC,EAAE,OAAO,EAAE,0BAA0B,MAAM,CAAC,MAAM,OAAO,EAAE,CAAC,CAAA;YAEnE,qBAAqB;YACrB,QAAQ,CAAC,wCAAwC,IAAI,CAAC,oBAAoB,EAAE,CAAC,CAAA;QAC/E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAA;YACjC,MAAM,CAAC,EAAE,OAAO,EAAG,KAAe,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QAC/D,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACtB,CAAC;IACH,CAAC;;AA51CM,sCAAM,GAAG;IACd,eAAe;IACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0mBF;CACF,AA7mBY,CA6mBZ;AAEQ;IAAR,KAAK,EAAE;;gEAAkB;AACjB;IAAR,KAAK,EAAE;;2EAA6B;AAC5B;IAAR,KAAK,EAAE;;6EAAkC;AAEjC;IAAR,KAAK,EAAE;;8DAAkB;AACjB;IAAR,KAAK,EAAE;;+DAA2C;AAC1C;IAAR,KAAK,EAAE;;+DAAmB;AAClB;IAAR,KAAK,EAAE;;uEAA2B;AAE1B;IAAR,KAAK,EAAE;;8DAA0B;AACzB;IAAR,KAAK,EAAE;;qEAAyB;AACxB;IAAR,KAAK,EAAE;;sEAA0B;AACzB;IAAR,KAAK,EAAE;;yEAAuC;AAEtC;IAAR,KAAK,EAAE;;gEAAyB;AACxB;IAAR,KAAK,EAAE;;oEAAyB;AAEhB;IAAhB,KAAK,EAAE;;kEAA0B;AAEJ;IAA7B,KAAK,CAAC,aAAa,CAAC;8BAAwB,gBAAgB;qEAAA;AAnoBlD,+BAA+B;IAD3C,aAAa,CAAC,2CAA2C,CAAC;GAC9C,+BAA+B,CA81C3C","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'\nimport { canDcspMutate } from '@dssp/building-complex/dist-client/utils/privilege'\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 /** 뮤테이션 가능 여부('dcsp guest' 권한 보유 시 false) — 게스트에게는 생성/수정/삭제 버튼을 숨긴다 */\n @state() private canMutate = false\n\n @query('#photoInput') private photoInputEl!: HTMLInputElement\n\n async connectedCallback() {\n super.connectedCallback()\n this.canMutate = await canDcspMutate()\n this.updateContext()\n }\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 ${this.canMutate\n ? html`<button class=\"primary-button\" @click=${this._registerInspection}>검사 등록</button>`\n : ''}\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"]}
@@ -12,7 +12,10 @@ export declare class BuildingInspectionCamera extends PageView {
12
12
  capturedImageUrl: string | null;
13
13
  imageFile: File | null;
14
14
  isSaved: boolean;
15
+ /** 뮤테이션 가능 여부('dcsp guest' 권한 보유 시 false) — 게스트에게는 생성/수정/삭제 버튼을 숨긴다 */
16
+ private canMutate;
15
17
  private imageInputEl;
18
+ connectedCallback(): Promise<void>;
16
19
  get context(): {
17
20
  title: string;
18
21
  };