@dssp/dkpi 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/bootstrap.d.ts +9 -0
- package/dist-client/bootstrap.js +272 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/components/kpi-2d-lookup-chart.d.ts +50 -0
- package/dist-client/components/kpi-2d-lookup-chart.js +263 -0
- package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
- package/dist-client/components/kpi-boxplot-chart.d.ts +31 -0
- package/dist-client/components/kpi-boxplot-chart.js +306 -0
- package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
- package/dist-client/components/kpi-lookup-chart.d.ts +58 -0
- package/dist-client/components/kpi-lookup-chart.js +464 -0
- package/dist-client/components/kpi-lookup-chart.js.map +1 -0
- package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
- package/dist-client/components/kpi-mini-trend-chart.js +180 -0
- package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
- package/dist-client/components/kpi-radar-chart.d.ts +17 -0
- package/dist-client/components/kpi-radar-chart.js +259 -0
- package/dist-client/components/kpi-radar-chart.js.map +1 -0
- package/dist-client/components/kpi-single-boxplot-chart.d.ts +36 -0
- package/dist-client/components/kpi-single-boxplot-chart.js +417 -0
- package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
- package/dist-client/components/kpi-step-lookup-chart.d.ts +33 -0
- package/dist-client/components/kpi-step-lookup-chart.js +181 -0
- package/dist-client/components/kpi-step-lookup-chart.js.map +1 -0
- package/dist-client/components/kpi-trend-chart.d.ts +25 -0
- package/dist-client/components/kpi-trend-chart.js +241 -0
- package/dist-client/components/kpi-trend-chart.js.map +1 -0
- package/dist-client/components/sv-pagenation-control.d.ts +18 -0
- package/dist-client/components/sv-pagenation-control.js +142 -0
- package/dist-client/components/sv-pagenation-control.js.map +1 -0
- package/dist-client/entries/auth/checkin.d.ts +38 -0
- package/dist-client/entries/auth/checkin.js +551 -0
- package/dist-client/entries/auth/checkin.js.map +1 -0
- package/dist-client/entries/public/home.d.ts +8 -0
- package/dist-client/entries/public/home.js +97 -0
- package/dist-client/entries/public/home.js.map +1 -0
- package/dist-client/google-map/common-google-map.d.ts +35 -0
- package/dist-client/google-map/common-google-map.js +349 -0
- package/dist-client/google-map/common-google-map.js.map +1 -0
- package/dist-client/google-map/google-map-loader.d.ts +6 -0
- package/dist-client/google-map/google-map-loader.js +23 -0
- package/dist-client/google-map/google-map-loader.js.map +1 -0
- package/dist-client/icons/menu-icons.d.ts +11 -0
- package/dist-client/icons/menu-icons.js +126 -0
- package/dist-client/icons/menu-icons.js.map +1 -0
- package/dist-client/index.d.ts +0 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/menu.d.ts +23 -0
- package/dist-client/menu.js +59 -0
- package/dist-client/menu.js.map +1 -0
- package/dist-client/pages/component/project-update-header.d.ts +1 -0
- package/dist-client/pages/component/project-update-header.js +127 -0
- package/dist-client/pages/component/project-update-header.js.map +1 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +47 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +393 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +1 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
- package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +18 -0
- package/dist-client/pages/kpi-admin/kpi-system-guide.js +696 -0
- package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +18 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +259 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +22 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +346 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +26 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +433 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +46 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +945 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +34 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +238 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +37 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +689 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +131 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +57 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +866 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +63 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +1097 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +147 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +57 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +719 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +68 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +394 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +40 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +190 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +71 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +454 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +69 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +790 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +22 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +344 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +21 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +335 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +51 -0
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +693 -0
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -0
- package/dist-client/pages/sv-project-complete.d.ts +31 -0
- package/dist-client/pages/sv-project-complete.js +359 -0
- package/dist-client/pages/sv-project-complete.js.map +1 -0
- package/dist-client/pages/sv-project-completed-list.d.ts +27 -0
- package/dist-client/pages/sv-project-completed-list.js +416 -0
- package/dist-client/pages/sv-project-completed-list.js.map +1 -0
- package/dist-client/pages/sv-project-detail.d.ts +73 -0
- package/dist-client/pages/sv-project-detail.js +1501 -0
- package/dist-client/pages/sv-project-detail.js.map +1 -0
- package/dist-client/pages/sv-project-list.d.ts +175 -0
- package/dist-client/pages/sv-project-list.js +581 -0
- package/dist-client/pages/sv-project-list.js.map +1 -0
- package/dist-client/pages/sv-project-update.d.ts +91 -0
- package/dist-client/pages/sv-project-update.js +1150 -0
- package/dist-client/pages/sv-project-update.js.map +1 -0
- package/dist-client/pages/sv-user-management.d.ts +6 -0
- package/dist-client/pages/sv-user-management.js +224 -0
- package/dist-client/pages/sv-user-management.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +58 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/shared/complete-api.d.ts +45 -0
- package/dist-client/shared/complete-api.js +274 -0
- package/dist-client/shared/complete-api.js.map +1 -0
- package/dist-client/shared/func.d.ts +2 -0
- package/dist-client/shared/func.js +22 -0
- package/dist-client/shared/func.js.map +1 -0
- package/dist-client/shared/geo-group-mapping.d.ts +25 -0
- package/dist-client/shared/geo-group-mapping.js +189 -0
- package/dist-client/shared/geo-group-mapping.js.map +1 -0
- package/dist-client/shared/integration-fetch.d.ts +35 -0
- package/dist-client/shared/integration-fetch.js +53 -0
- package/dist-client/shared/integration-fetch.js.map +1 -0
- package/dist-client/shared/kpi-project-sync.d.ts +16 -0
- package/dist-client/shared/kpi-project-sync.js +129 -0
- package/dist-client/shared/kpi-project-sync.js.map +1 -0
- package/dist-client/themes/dark.css +51 -0
- package/dist-client/themes/light.css +51 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/viewparts/menu-tools.d.ts +62 -0
- package/dist-client/viewparts/menu-tools.js +554 -0
- package/dist-client/viewparts/menu-tools.js.map +1 -0
- package/dist-client/viewparts/user-circle.d.ts +5 -0
- package/dist-client/viewparts/user-circle.js +26 -0
- package/dist-client/viewparts/user-circle.js.map +1 -0
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +6 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/migrations/index.d.ts +1 -0
- package/dist-server/migrations/index.js +12 -0
- package/dist-server/migrations/index.js.map +1 -0
- package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
- package/dist-server/scripts/calculate-kpi-scores.js +333 -0
- package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
- package/dist-server/scripts/load-grade-data-migration.d.ts +14 -0
- package/dist-server/scripts/load-grade-data-migration.js +279 -0
- package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
- package/dist-server/scripts/propagate-parent-kpi-values.d.ts +14 -0
- package/dist-server/scripts/propagate-parent-kpi-values.js +786 -0
- package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
- package/dist-server/scripts/recalculate-by-project-name.d.ts +2 -0
- package/dist-server/scripts/recalculate-by-project-name.js +72 -0
- package/dist-server/scripts/recalculate-by-project-name.js.map +1 -0
- package/dist-server/service/index.d.ts +4 -0
- package/dist-server/service/index.js +20 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
- package/dist-server/service/kpi-metric-value/index.js +8 -0
- package/dist-server/service/kpi-metric-value/index.js.map +1 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +198 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +1067 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +15 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +72 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
- package/dist-server/service/kpi-stat/index.d.ts +4 -0
- package/dist-server/service/kpi-stat/index.js +8 -0
- package/dist-server/service/kpi-stat/index.js.map +1 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +13 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.js +751 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +32 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js +180 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -0
- package/dist-server/service/kpi-value/index.d.ts +3 -0
- package/dist-server/service/kpi-value/index.js +7 -0
- package/dist-server/service/kpi-value/index.js.map +1 -0
- package/dist-server/service/kpi-value/kpi-value-query.d.ts +8 -0
- package/dist-server/service/kpi-value/kpi-value-query.js +90 -0
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { gql } from '@apollo/client';
|
|
2
|
+
import { client } from '@operato/graphql';
|
|
3
|
+
import { tenantHeaders } from '@dssp/project/dist-client/shared/domain-context';
|
|
4
|
+
export const getProject = async (projectId, projectCode) => {
|
|
5
|
+
const response = await client.query({
|
|
6
|
+
query: gql `
|
|
7
|
+
query Project($id: String!) {
|
|
8
|
+
project(id: $id) {
|
|
9
|
+
id
|
|
10
|
+
code
|
|
11
|
+
name
|
|
12
|
+
startDate
|
|
13
|
+
endDate
|
|
14
|
+
state
|
|
15
|
+
|
|
16
|
+
completeReport {
|
|
17
|
+
id
|
|
18
|
+
name
|
|
19
|
+
fullpath
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
buildingComplex {
|
|
23
|
+
id
|
|
24
|
+
coverageRatio
|
|
25
|
+
floorAreaRatio
|
|
26
|
+
workerCount
|
|
27
|
+
designChangeCount
|
|
28
|
+
constructionCost
|
|
29
|
+
area
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`,
|
|
34
|
+
variables: { id: projectId },
|
|
35
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
36
|
+
});
|
|
37
|
+
if (response.errors) {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
return response.data.project;
|
|
41
|
+
};
|
|
42
|
+
export const getKpiMetrics = async (projectCode) => {
|
|
43
|
+
const response = await client.query({
|
|
44
|
+
query: gql `
|
|
45
|
+
query KpiMetrics {
|
|
46
|
+
kpiMetrics {
|
|
47
|
+
items {
|
|
48
|
+
id
|
|
49
|
+
name
|
|
50
|
+
unit
|
|
51
|
+
periodType
|
|
52
|
+
description
|
|
53
|
+
active
|
|
54
|
+
rank
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`,
|
|
59
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
60
|
+
});
|
|
61
|
+
if (response.errors) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
// KpiMetric 자체의 active 만 통과 — admin 에서 active=false 로 비활성화한 metric 은 자동 제외.
|
|
65
|
+
// rank 오름차순 정렬 (미지정=null 은 뒤로). rank 가 같으면 기존(서버) 순서 유지.
|
|
66
|
+
const items = (response.data.kpiMetrics.items || []).filter((m) => m.active !== false);
|
|
67
|
+
return items
|
|
68
|
+
.map((m, i) => ({ m, i }))
|
|
69
|
+
.sort((a, b) => {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const ra = (_a = a.m.rank) !== null && _a !== void 0 ? _a : Number.POSITIVE_INFINITY;
|
|
72
|
+
const rb = (_b = b.m.rank) !== null && _b !== void 0 ? _b : Number.POSITIVE_INFINITY;
|
|
73
|
+
return ra !== rb ? ra - rb : a.i - b.i;
|
|
74
|
+
})
|
|
75
|
+
.map((x) => x.m);
|
|
76
|
+
};
|
|
77
|
+
export const getKpiMetricValues = async (projectId, projectCode) => {
|
|
78
|
+
const filters = [{ name: 'org', operator: 'eq', value: projectId }];
|
|
79
|
+
const response = await client.query({
|
|
80
|
+
query: gql `
|
|
81
|
+
query KpiMetricValues($filters: [Filter!], $projectId: String) {
|
|
82
|
+
kpiMetricValues(filters: $filters, projectId: $projectId) {
|
|
83
|
+
items {
|
|
84
|
+
id
|
|
85
|
+
value
|
|
86
|
+
unit
|
|
87
|
+
periodType
|
|
88
|
+
valueDate
|
|
89
|
+
metricId
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
`,
|
|
94
|
+
variables: {
|
|
95
|
+
filters,
|
|
96
|
+
// projectId 전달 → 서버가 그 프로젝트 도메인으로 스코프 → cross-domain 중복 row 방지.
|
|
97
|
+
projectId
|
|
98
|
+
},
|
|
99
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
100
|
+
});
|
|
101
|
+
if (response.errors) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
return response.data.kpiMetricValues.items;
|
|
105
|
+
};
|
|
106
|
+
export const getKpiCategories = async (projectCode) => {
|
|
107
|
+
const response = await client.query({
|
|
108
|
+
query: gql `
|
|
109
|
+
query {
|
|
110
|
+
kpiCategories: kpisLevel1 {
|
|
111
|
+
id
|
|
112
|
+
name
|
|
113
|
+
description
|
|
114
|
+
active
|
|
115
|
+
kpis: children {
|
|
116
|
+
id
|
|
117
|
+
name
|
|
118
|
+
description
|
|
119
|
+
formula
|
|
120
|
+
active
|
|
121
|
+
grades
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
`,
|
|
126
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
127
|
+
});
|
|
128
|
+
if (response.errors) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
return response.data.kpiCategories;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* BuildingComplex 컬럼 부분 업데이트. updateBuildingComplex 는 기존 row 를 load 후
|
|
135
|
+
* patch 를 merge 저장하므로 (building-complex-mutation.ts) 지정 컬럼만 안전하게 갱신
|
|
136
|
+
* — updateProject 처럼 buildings 재생성 side-effect 가 없다.
|
|
137
|
+
*/
|
|
138
|
+
export const updateBuildingComplexFields = async (id, patch, projectCode) => {
|
|
139
|
+
return await client.mutate({
|
|
140
|
+
mutation: gql `
|
|
141
|
+
mutation UpdateBuildingComplex($id: String!, $patch: BuildingComplexPatch!) {
|
|
142
|
+
updateBuildingComplex(id: $id, patch: $patch) {
|
|
143
|
+
id
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
`,
|
|
147
|
+
variables: { id, patch },
|
|
148
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
export const updateProjectCompleteStep1 = async (patches, projectCode) => {
|
|
152
|
+
const response = await client.mutate({
|
|
153
|
+
mutation: gql `
|
|
154
|
+
mutation UpdateKpiMetricValuesCumulative($patches: [KpiMetricValuePatch!]!) {
|
|
155
|
+
updateKpiMetricValuesCumulative(patches: $patches) {
|
|
156
|
+
id
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
`,
|
|
160
|
+
variables: {
|
|
161
|
+
patches
|
|
162
|
+
},
|
|
163
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
164
|
+
});
|
|
165
|
+
return response;
|
|
166
|
+
};
|
|
167
|
+
export const updateProjectCompleteStep2 = async (patches, projectCode) => {
|
|
168
|
+
const response = await client.mutate({
|
|
169
|
+
mutation: gql `
|
|
170
|
+
mutation UpdateKpiMetricValuesAssessment($patches: [KpiMetricValuePatch!]!) {
|
|
171
|
+
updateKpiMetricValuesAssessment(patches: $patches) {
|
|
172
|
+
id
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
`,
|
|
176
|
+
variables: {
|
|
177
|
+
patches
|
|
178
|
+
},
|
|
179
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
180
|
+
});
|
|
181
|
+
return response;
|
|
182
|
+
};
|
|
183
|
+
export const updateProjectCompleteStep3 = async (file, projectId, projectCode) => {
|
|
184
|
+
const response = await client.mutate({
|
|
185
|
+
mutation: gql `
|
|
186
|
+
mutation UpdateKpiMetricValuesSentiment($attachment: NewAttachment!) {
|
|
187
|
+
updateKpiMetricValuesSentiment(attachment: $attachment) {
|
|
188
|
+
id
|
|
189
|
+
name
|
|
190
|
+
fullpath
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
`,
|
|
194
|
+
variables: {
|
|
195
|
+
attachment: {
|
|
196
|
+
file,
|
|
197
|
+
refBy: projectId,
|
|
198
|
+
refType: 'ProjectCompleteReport'
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
context: {
|
|
202
|
+
hasUpload: true,
|
|
203
|
+
headers: tenantHeaders(projectCode)
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
return response;
|
|
207
|
+
};
|
|
208
|
+
export const collectProjectExternalData = async (projectId, projectCode) => {
|
|
209
|
+
const response = await client.mutate({
|
|
210
|
+
mutation: gql `
|
|
211
|
+
mutation CollectProjectExternalData($projectId: String!) {
|
|
212
|
+
collectProjectExternalData(projectId: $projectId) {
|
|
213
|
+
source
|
|
214
|
+
label
|
|
215
|
+
ok
|
|
216
|
+
message
|
|
217
|
+
data
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
`,
|
|
221
|
+
variables: { projectId },
|
|
222
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
223
|
+
});
|
|
224
|
+
if (response.errors) {
|
|
225
|
+
// 전체 mutation 자체 실패 — UI 가 시스템별 fallback 결과 구성
|
|
226
|
+
throw new Error(response.errors.map((e) => e.message).join('\n'));
|
|
227
|
+
}
|
|
228
|
+
return response.data.collectProjectExternalData;
|
|
229
|
+
};
|
|
230
|
+
export const updateProjectCompleteFinalize = async (projectId, projectCode) => {
|
|
231
|
+
const response = await client.mutate({
|
|
232
|
+
mutation: gql `
|
|
233
|
+
mutation FinalizeProjectWithKpiRecalculation($projectId: String!) {
|
|
234
|
+
finalizeProjectWithKpiRecalculation(projectId: $projectId)
|
|
235
|
+
}
|
|
236
|
+
`,
|
|
237
|
+
variables: {
|
|
238
|
+
projectId
|
|
239
|
+
},
|
|
240
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
241
|
+
});
|
|
242
|
+
return response;
|
|
243
|
+
};
|
|
244
|
+
/** 완료(COMPLETED) 프로젝트를 진행중(ONGOING) 으로 되돌림 (완료처리 토글의 해제). */
|
|
245
|
+
export const updateProjectCompleteUnfinalize = async (projectId, projectCode) => {
|
|
246
|
+
const response = await client.mutate({
|
|
247
|
+
mutation: gql `
|
|
248
|
+
mutation UpdateProject($project: ProjectPatch!) {
|
|
249
|
+
updateProject(project: $project) {
|
|
250
|
+
id
|
|
251
|
+
state
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
`,
|
|
255
|
+
variables: { project: { id: projectId, state: 'ONGOING' } },
|
|
256
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
257
|
+
});
|
|
258
|
+
return response;
|
|
259
|
+
};
|
|
260
|
+
export const recalculateProjectKpi = async (projectId, projectCode) => {
|
|
261
|
+
const response = await client.mutate({
|
|
262
|
+
mutation: gql `
|
|
263
|
+
mutation RecalculateProjectKpi($projectId: String!) {
|
|
264
|
+
recalculateProjectKpi(projectId: $projectId)
|
|
265
|
+
}
|
|
266
|
+
`,
|
|
267
|
+
variables: {
|
|
268
|
+
projectId
|
|
269
|
+
},
|
|
270
|
+
context: { headers: tenantHeaders(projectCode) }
|
|
271
|
+
});
|
|
272
|
+
return response;
|
|
273
|
+
};
|
|
274
|
+
//# sourceMappingURL=complete-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complete-api.js","sourceRoot":"","sources":["../../client/shared/complete-api.ts"],"names":[],"mappings":"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","sourcesContent":["import { gql } from '@apollo/client'\nimport { client } from '@operato/graphql'\nimport { tenantHeaders } from '@dssp/project/dist-client/shared/domain-context'\n\nexport const getProject = async (projectId: string, projectCode?: string) => {\n const response = await client.query({\n query: gql`\n query Project($id: String!) {\n project(id: $id) {\n id\n code\n name\n startDate\n endDate\n state\n\n completeReport {\n id\n name\n fullpath\n }\n\n buildingComplex {\n id\n coverageRatio\n floorAreaRatio\n workerCount\n designChangeCount\n constructionCost\n area\n }\n }\n }\n `,\n variables: { id: projectId },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n if (response.errors) {\n return {}\n }\n\n return response.data.project\n}\n\nexport const getKpiMetrics = async (projectCode?: string) => {\n const response = await client.query({\n query: gql`\n query KpiMetrics {\n kpiMetrics {\n items {\n id\n name\n unit\n periodType\n description\n active\n rank\n }\n }\n }\n `,\n context: { headers: tenantHeaders(projectCode) }\n })\n\n if (response.errors) {\n return []\n }\n\n // KpiMetric 자체의 active 만 통과 — admin 에서 active=false 로 비활성화한 metric 은 자동 제외.\n // rank 오름차순 정렬 (미지정=null 은 뒤로). rank 가 같으면 기존(서버) 순서 유지.\n const items = (response.data.kpiMetrics.items || []).filter((m: any) => m.active !== false)\n return items\n .map((m: any, i: number) => ({ m, i }))\n .sort((a: any, b: any) => {\n const ra = a.m.rank ?? Number.POSITIVE_INFINITY\n const rb = b.m.rank ?? Number.POSITIVE_INFINITY\n return ra !== rb ? ra - rb : a.i - b.i\n })\n .map((x: any) => x.m)\n}\n\nexport const getKpiMetricValues = async (projectId: string, projectCode?: string) => {\n const filters = [{ name: 'org', operator: 'eq', value: projectId }]\n\n const response = await client.query({\n query: gql`\n query KpiMetricValues($filters: [Filter!], $projectId: String) {\n kpiMetricValues(filters: $filters, projectId: $projectId) {\n items {\n id\n value\n unit\n periodType\n valueDate\n metricId\n }\n }\n }\n `,\n variables: {\n filters,\n // projectId 전달 → 서버가 그 프로젝트 도메인으로 스코프 → cross-domain 중복 row 방지.\n projectId\n },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n if (response.errors) {\n return []\n }\n\n return response.data.kpiMetricValues.items\n}\n\nexport const getKpiCategories = async (projectCode?: string) => {\n const response = await client.query({\n query: gql`\n query {\n kpiCategories: kpisLevel1 {\n id\n name\n description\n active\n kpis: children {\n id\n name\n description\n formula\n active\n grades\n }\n }\n }\n `,\n context: { headers: tenantHeaders(projectCode) }\n })\n\n if (response.errors) {\n return []\n }\n\n return response.data.kpiCategories\n}\n\n/**\n * BuildingComplex 컬럼 부분 업데이트. updateBuildingComplex 는 기존 row 를 load 후\n * patch 를 merge 저장하므로 (building-complex-mutation.ts) 지정 컬럼만 안전하게 갱신\n * — updateProject 처럼 buildings 재생성 side-effect 가 없다.\n */\nexport const updateBuildingComplexFields = async (id: string, patch: any, projectCode?: string) => {\n return await client.mutate({\n mutation: gql`\n mutation UpdateBuildingComplex($id: String!, $patch: BuildingComplexPatch!) {\n updateBuildingComplex(id: $id, patch: $patch) {\n id\n }\n }\n `,\n variables: { id, patch },\n context: { headers: tenantHeaders(projectCode) }\n })\n}\n\nexport const updateProjectCompleteStep1 = async (patches: any, projectCode?: string) => {\n const response = await client.mutate({\n mutation: gql`\n mutation UpdateKpiMetricValuesCumulative($patches: [KpiMetricValuePatch!]!) {\n updateKpiMetricValuesCumulative(patches: $patches) {\n id\n }\n }\n `,\n variables: {\n patches\n },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n return response\n}\n\nexport const updateProjectCompleteStep2 = async (patches: any, projectCode?: string) => {\n const response = await client.mutate({\n mutation: gql`\n mutation UpdateKpiMetricValuesAssessment($patches: [KpiMetricValuePatch!]!) {\n updateKpiMetricValuesAssessment(patches: $patches) {\n id\n }\n }\n `,\n variables: {\n patches\n },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n return response\n}\n\nexport const updateProjectCompleteStep3 = async (file: any, projectId: string, projectCode?: string) => {\n const response = await client.mutate({\n mutation: gql`\n mutation UpdateKpiMetricValuesSentiment($attachment: NewAttachment!) {\n updateKpiMetricValuesSentiment(attachment: $attachment) {\n id\n name\n fullpath\n }\n }\n `,\n variables: {\n attachment: {\n file,\n refBy: projectId,\n refType: 'ProjectCompleteReport'\n }\n },\n context: {\n hasUpload: true,\n headers: tenantHeaders(projectCode)\n }\n })\n\n return response\n}\n\n/**\n * UI \"자동 수집\" 버튼 전용 — 세움터/올바로/키스콘 시나리오를 순차 호출 후\n * 시스템별 성공/실패 결과를 반환. 시나리오는 도메인 EnvVar 만으로 동작하므로\n * 파라미터 없음. 시나리오 내부 step 이 KPI Value 를 DB 에 적재하므로 호출 후\n * KPI Metric Values 를 다시 조회해 form 을 갱신하는 것이 정상 흐름.\n */\nexport interface ExternalDataCollectionResult {\n source: string // 'saeumteo' | 'allbaro' | 'kiscon'\n label: string // '세움터' | '올바로' | '키스콘'\n ok: boolean\n message: string\n /**\n * 시나리오 result 객체. projectKey: value 맵.\n * - 세움터: { area, floorAreaRatio, upperFloorCount, lowerFloorCount,\n * structureType, siteType }\n * - 올바로: { totalConstructionWasteAmount }\n * - 키스콘: { constructionPeriod, constructionCost }\n *\n * siteType (건물 용도, SiteType enum 값 — 예: APARTMENT_COMPLEX) 와\n * structureType (구조형태) 는 KPI metric 이 아니라 BuildingComplex 의 기본\n * 속성으로 사용. KISCON 의 \"공사유형(신설/증축)\" 은 SiteType 도메인과 다르므로\n * 매핑 대상 아님.\n *\n * 없는 키는 omit. 시나리오 실패 시 null/undefined.\n */\n data?: Record<string, number | string | null>\n}\n\nexport const collectProjectExternalData = async (\n projectId: string,\n projectCode?: string\n): Promise<ExternalDataCollectionResult[]> => {\n const response = await client.mutate({\n mutation: gql`\n mutation CollectProjectExternalData($projectId: String!) {\n collectProjectExternalData(projectId: $projectId) {\n source\n label\n ok\n message\n data\n }\n }\n `,\n variables: { projectId },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n if (response.errors) {\n // 전체 mutation 자체 실패 — UI 가 시스템별 fallback 결과 구성\n throw new Error(response.errors.map((e: any) => e.message).join('\\n'))\n }\n\n return response.data.collectProjectExternalData\n}\n\nexport const updateProjectCompleteFinalize = async (projectId: string, projectCode?: string) => {\n const response = await client.mutate({\n mutation: gql`\n mutation FinalizeProjectWithKpiRecalculation($projectId: String!) {\n finalizeProjectWithKpiRecalculation(projectId: $projectId)\n }\n `,\n variables: {\n projectId\n },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n return response\n}\n\n/** 완료(COMPLETED) 프로젝트를 진행중(ONGOING) 으로 되돌림 (완료처리 토글의 해제). */\nexport const updateProjectCompleteUnfinalize = async (projectId: string, projectCode?: string) => {\n const response = await client.mutate({\n mutation: gql`\n mutation UpdateProject($project: ProjectPatch!) {\n updateProject(project: $project) {\n id\n state\n }\n }\n `,\n variables: { project: { id: projectId, state: 'ONGOING' } },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n return response\n}\n\nexport const recalculateProjectKpi = async (projectId: string, projectCode?: string) => {\n const response = await client.mutate({\n mutation: gql`\n mutation RecalculateProjectKpi($projectId: String!) {\n recalculateProjectKpi(projectId: $projectId)\n }\n `,\n variables: {\n projectId\n },\n context: { headers: tenantHeaders(projectCode) }\n })\n\n return response\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import moment from 'moment';
|
|
2
|
+
// a와 b의 차이를 계산하여 값과 클래스를 반환
|
|
3
|
+
export const calcDiff = (a, b) => {
|
|
4
|
+
const origin = Number(a || '0');
|
|
5
|
+
const complete = Number(b || '0');
|
|
6
|
+
const diff = complete - origin;
|
|
7
|
+
if (!isFinite(diff))
|
|
8
|
+
return 0;
|
|
9
|
+
return diff;
|
|
10
|
+
};
|
|
11
|
+
// a와 b의 날짜 차이를 계산하여 값과 클래스를 반환
|
|
12
|
+
export const calcDateDiff = (a, b) => {
|
|
13
|
+
const origin = moment(a, 'YYYY-MM-DD', true);
|
|
14
|
+
const complete = moment(b, 'YYYY-MM-DD', true);
|
|
15
|
+
if (!origin.isValid() || !complete.isValid())
|
|
16
|
+
return 0;
|
|
17
|
+
const diffDays = complete.diff(origin, 'days');
|
|
18
|
+
if (diffDays === 0)
|
|
19
|
+
return 0;
|
|
20
|
+
return diffDays;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=func.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"func.js","sourceRoot":"","sources":["../../client/shared/func.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,4BAA4B;AAC5B,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAkB,EAAE,CAAkB,EAAU,EAAE;IACzE,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;IAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;IACjC,MAAM,IAAI,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED,+BAA+B;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE;IAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAA;IAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAA;IAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;QAAE,OAAO,CAAC,CAAA;IAEtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9C,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IAE5B,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA","sourcesContent":["import moment from 'moment'\n\n// a와 b의 차이를 계산하여 값과 클래스를 반환\nexport const calcDiff = (a: string | number, b: string | number): number => {\n const origin = Number(a || '0')\n const complete = Number(b || '0')\n const diff = complete - origin\n if (!isFinite(diff)) return 0\n return diff\n}\n\n// a와 b의 날짜 차이를 계산하여 값과 클래스를 반환\nexport const calcDateDiff = (a: string, b: string): number => {\n const origin = moment(a, 'YYYY-MM-DD', true)\n const complete = moment(b, 'YYYY-MM-DD', true)\n if (!origin.isValid() || !complete.isValid()) return 0\n\n const diffDays = complete.diff(origin, 'days')\n if (diffDays === 0) return 0\n\n return diffDays\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* geo_group 2자리 코드 ↔ 시도/시군구 매핑.
|
|
3
|
+
* convert-augmented-xlsx-to-csv.py 의 GEO_GROUPS dict 를 TypeScript 로 이식.
|
|
4
|
+
*
|
|
5
|
+
* 운영자가 프로젝트 주소를 입력하면 그 안에서 시도+시군구 표준명을 부분 매칭하여
|
|
6
|
+
* 2자리 코드를 추정. 자동 채움 후에도 운영자가 수동 정정 가능.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 우편번호 prefix (2자리) → geo_group 2자리 코드 best-guess 매핑.
|
|
10
|
+
* convert-augmented-xlsx-to-csv.py 의 GEO_GROUPS 세 번째 값 (postal_prefix) 기준,
|
|
11
|
+
* 1:N 케이스는 첫 매칭 사용. 정확한 시군구 분리에는 한국 행정안전부 5자리 우편번호
|
|
12
|
+
* 룩업 필요하지만 client embed 불가능 — best-guess 로 시도 단위 통계만 신뢰 가능.
|
|
13
|
+
*/
|
|
14
|
+
export declare const POSTAL_PREFIX_TO_GEO_GROUP: Record<string, string>;
|
|
15
|
+
export declare function inferGeoGroupFromPostalCode(postalCode: string | null | undefined): string | null;
|
|
16
|
+
/** "시도+시군구 표준명" → "2자리 geo_group 코드" */
|
|
17
|
+
export declare const ADDRESS_TO_GEO_GROUP: Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* 주소 문자열에서 2자리 geo_group 코드 추정. 매칭 안 되면 null.
|
|
20
|
+
* 매칭 우선:
|
|
21
|
+
* 1) 정식 시도명 + 시군구명 (예: '서울특별시 종로구')
|
|
22
|
+
* 2) 약칭 시도 + 시군구 (예: '서울 종로구' → '서울특별시 종로구')
|
|
23
|
+
* 3) 시군구명 단독 매칭 (예: '종로구') — 유니크한 경우
|
|
24
|
+
*/
|
|
25
|
+
export declare function inferGeoGroupFromAddress(address: string | null | undefined): string | null;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* geo_group 2자리 코드 ↔ 시도/시군구 매핑.
|
|
3
|
+
* convert-augmented-xlsx-to-csv.py 의 GEO_GROUPS dict 를 TypeScript 로 이식.
|
|
4
|
+
*
|
|
5
|
+
* 운영자가 프로젝트 주소를 입력하면 그 안에서 시도+시군구 표준명을 부분 매칭하여
|
|
6
|
+
* 2자리 코드를 추정. 자동 채움 후에도 운영자가 수동 정정 가능.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 우편번호 prefix (2자리) → geo_group 2자리 코드 best-guess 매핑.
|
|
10
|
+
* convert-augmented-xlsx-to-csv.py 의 GEO_GROUPS 세 번째 값 (postal_prefix) 기준,
|
|
11
|
+
* 1:N 케이스는 첫 매칭 사용. 정확한 시군구 분리에는 한국 행정안전부 5자리 우편번호
|
|
12
|
+
* 룩업 필요하지만 client embed 불가능 — best-guess 로 시도 단위 통계만 신뢰 가능.
|
|
13
|
+
*/
|
|
14
|
+
export const POSTAL_PREFIX_TO_GEO_GROUP = {
|
|
15
|
+
'03': '01', // 서울 종로구
|
|
16
|
+
'04': '02', // 서울 중구
|
|
17
|
+
'05': '05', // 서울 광진구
|
|
18
|
+
'06': '06', // 서울 강남구
|
|
19
|
+
'07': '08', // 서울 강서구
|
|
20
|
+
'10': '12', // 경기 고양시 / 파주시
|
|
21
|
+
'11': '11', // 경기 성남시
|
|
22
|
+
'12': '11', // 경기 성남시
|
|
23
|
+
'13': '11', // 경기 성남시
|
|
24
|
+
'14': '14', // 경기 부천시
|
|
25
|
+
'15': '15', // 경기 안산시
|
|
26
|
+
'16': '10', // 경기 수원시
|
|
27
|
+
'17': '13', // 경기 용인시 / 평택시
|
|
28
|
+
'18': '16', // 경기 화성시
|
|
29
|
+
'21': '21', // 인천 남동구 / 부평구
|
|
30
|
+
'22': '23', // 인천 서구
|
|
31
|
+
'24': '24', // 강원 춘천시
|
|
32
|
+
'25': '26', // 강원 강릉시
|
|
33
|
+
'26': '25', // 강원 원주시
|
|
34
|
+
'27': '28', // 충북 충주시 / 제천시
|
|
35
|
+
'28': '27', // 충북 청주시
|
|
36
|
+
'30': '30', // 세종
|
|
37
|
+
'31': '31', // 충남 천안시 / 아산시
|
|
38
|
+
'34': '35', // 대전 유성구
|
|
39
|
+
'35': '34', // 대전 서구
|
|
40
|
+
'36': '39', // 경북 안동시
|
|
41
|
+
'37': '36', // 경북 포항시
|
|
42
|
+
'38': '37', // 경북 경주시
|
|
43
|
+
'39': '38', // 경북 구미시 / 김천시
|
|
44
|
+
'41': '41', // 대구 중구
|
|
45
|
+
'42': '42', // 대구 수성구 / 달서구
|
|
46
|
+
'44': '44', // 울산 남구 / 중구
|
|
47
|
+
'46': '49', // 부산 금정구
|
|
48
|
+
'48': '46', // 부산 중구 / 해운대구
|
|
49
|
+
'49': '48', // 부산 사하구
|
|
50
|
+
'50': '51', // 경남 김해시 / 양산시
|
|
51
|
+
'51': '50', // 경남 창원시
|
|
52
|
+
'52': '52', // 경남 진주시
|
|
53
|
+
'54': '54', // 전북 전주시 / 익산시 / 군산시
|
|
54
|
+
'57': '59', // 전남 순천시
|
|
55
|
+
'58': '57', // 전남 목포시
|
|
56
|
+
'59': '58', // 전남 여수시
|
|
57
|
+
'61': '61', // 광주 서구 / 북구
|
|
58
|
+
'63': '63' // 제주
|
|
59
|
+
};
|
|
60
|
+
export function inferGeoGroupFromPostalCode(postalCode) {
|
|
61
|
+
if (!postalCode)
|
|
62
|
+
return null;
|
|
63
|
+
const prefix = postalCode.trim().slice(0, 2);
|
|
64
|
+
return POSTAL_PREFIX_TO_GEO_GROUP[prefix] || null;
|
|
65
|
+
}
|
|
66
|
+
/** "시도+시군구 표준명" → "2자리 geo_group 코드" */
|
|
67
|
+
export const ADDRESS_TO_GEO_GROUP = {
|
|
68
|
+
'서울특별시 종로구': '01',
|
|
69
|
+
'서울특별시 중구': '02',
|
|
70
|
+
'서울특별시 용산구': '03',
|
|
71
|
+
'서울특별시 성동구': '04',
|
|
72
|
+
'서울특별시 광진구': '05',
|
|
73
|
+
'서울특별시 강남구': '06',
|
|
74
|
+
'서울특별시 송파구': '07',
|
|
75
|
+
'서울특별시 강서구': '08',
|
|
76
|
+
'경기도 수원시': '10',
|
|
77
|
+
'경기도 성남시': '11',
|
|
78
|
+
'경기도 고양시': '12',
|
|
79
|
+
'경기도 용인시': '13',
|
|
80
|
+
'경기도 부천시': '14',
|
|
81
|
+
'경기도 안산시': '15',
|
|
82
|
+
'경기도 화성시': '16',
|
|
83
|
+
'경기도 평택시': '17',
|
|
84
|
+
'경기도 파주시': '18',
|
|
85
|
+
'인천광역시 남동구': '21',
|
|
86
|
+
'인천광역시 부평구': '22',
|
|
87
|
+
'인천광역시 서구': '23',
|
|
88
|
+
'강원도 춘천시': '24',
|
|
89
|
+
'강원도 원주시': '25',
|
|
90
|
+
'강원도 강릉시': '26',
|
|
91
|
+
'충청북도 청주시': '27',
|
|
92
|
+
'충청북도 충주시': '28',
|
|
93
|
+
'충청북도 제천시': '29',
|
|
94
|
+
'세종특별자치시': '30',
|
|
95
|
+
'충청남도 천안시': '31',
|
|
96
|
+
'충청남도 아산시': '32',
|
|
97
|
+
'강원도 속초시': '33',
|
|
98
|
+
'대전광역시 서구': '34',
|
|
99
|
+
'대전광역시 유성구': '35',
|
|
100
|
+
'경상북도 포항시': '36',
|
|
101
|
+
'경상북도 경주시': '37',
|
|
102
|
+
'경상북도 구미시': '38',
|
|
103
|
+
'경상북도 안동시': '39',
|
|
104
|
+
'경상북도 김천시': '40',
|
|
105
|
+
'대구광역시 중구': '41',
|
|
106
|
+
'대구광역시 수성구': '42',
|
|
107
|
+
'대구광역시 달서구': '43',
|
|
108
|
+
'울산광역시 남구': '44',
|
|
109
|
+
'울산광역시 중구': '45',
|
|
110
|
+
'부산광역시 중구': '46',
|
|
111
|
+
'부산광역시 해운대구': '47',
|
|
112
|
+
'부산광역시 사하구': '48',
|
|
113
|
+
'부산광역시 금정구': '49',
|
|
114
|
+
'경상남도 창원시': '50',
|
|
115
|
+
'경상남도 김해시': '51',
|
|
116
|
+
'경상남도 진주시': '52',
|
|
117
|
+
'경상남도 양산시': '53',
|
|
118
|
+
'전라북도 전주시': '54',
|
|
119
|
+
'전라북도 익산시': '55',
|
|
120
|
+
'전라북도 군산시': '56',
|
|
121
|
+
'전라남도 목포시': '57',
|
|
122
|
+
'전라남도 여수시': '58',
|
|
123
|
+
'전라남도 순천시': '59',
|
|
124
|
+
'광주광역시 서구': '61',
|
|
125
|
+
'광주광역시 북구': '62',
|
|
126
|
+
'제주특별자치도 제주시': '63'
|
|
127
|
+
};
|
|
128
|
+
/** 시도 약칭 → 정식 명 (부분 매칭용). */
|
|
129
|
+
const PROVINCE_ALIASES = {
|
|
130
|
+
서울: '서울특별시',
|
|
131
|
+
경기: '경기도',
|
|
132
|
+
인천: '인천광역시',
|
|
133
|
+
강원: '강원도',
|
|
134
|
+
충북: '충청북도',
|
|
135
|
+
충남: '충청남도',
|
|
136
|
+
세종: '세종특별자치시',
|
|
137
|
+
대전: '대전광역시',
|
|
138
|
+
경북: '경상북도',
|
|
139
|
+
경남: '경상남도',
|
|
140
|
+
대구: '대구광역시',
|
|
141
|
+
울산: '울산광역시',
|
|
142
|
+
부산: '부산광역시',
|
|
143
|
+
전북: '전라북도',
|
|
144
|
+
전남: '전라남도',
|
|
145
|
+
광주: '광주광역시',
|
|
146
|
+
제주: '제주특별자치도'
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* 주소 문자열에서 2자리 geo_group 코드 추정. 매칭 안 되면 null.
|
|
150
|
+
* 매칭 우선:
|
|
151
|
+
* 1) 정식 시도명 + 시군구명 (예: '서울특별시 종로구')
|
|
152
|
+
* 2) 약칭 시도 + 시군구 (예: '서울 종로구' → '서울특별시 종로구')
|
|
153
|
+
* 3) 시군구명 단독 매칭 (예: '종로구') — 유니크한 경우
|
|
154
|
+
*/
|
|
155
|
+
export function inferGeoGroupFromAddress(address) {
|
|
156
|
+
if (!address)
|
|
157
|
+
return null;
|
|
158
|
+
const trimmed = address.trim();
|
|
159
|
+
if (!trimmed)
|
|
160
|
+
return null;
|
|
161
|
+
// 1) 정식 매칭
|
|
162
|
+
for (const key of Object.keys(ADDRESS_TO_GEO_GROUP)) {
|
|
163
|
+
if (trimmed.includes(key))
|
|
164
|
+
return ADDRESS_TO_GEO_GROUP[key];
|
|
165
|
+
}
|
|
166
|
+
// 2) 약칭 시도 → 정식 시도로 expand 후 다시 매칭
|
|
167
|
+
for (const [short, full] of Object.entries(PROVINCE_ALIASES)) {
|
|
168
|
+
if (trimmed.startsWith(short) && !trimmed.startsWith(full)) {
|
|
169
|
+
const expanded = trimmed.replace(short, full);
|
|
170
|
+
for (const key of Object.keys(ADDRESS_TO_GEO_GROUP)) {
|
|
171
|
+
if (expanded.includes(key))
|
|
172
|
+
return ADDRESS_TO_GEO_GROUP[key];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 3) 시군구명 단독 매칭 (시도 prefix 없는 경우). 유니크한 시군구만 통과.
|
|
177
|
+
const districtMatches = Object.entries(ADDRESS_TO_GEO_GROUP)
|
|
178
|
+
.filter(([key]) => {
|
|
179
|
+
const parts = key.split(' ');
|
|
180
|
+
const district = parts[parts.length - 1];
|
|
181
|
+
return trimmed.includes(district);
|
|
182
|
+
})
|
|
183
|
+
.map(([, code]) => code);
|
|
184
|
+
const uniqueDistrictCodes = Array.from(new Set(districtMatches));
|
|
185
|
+
if (uniqueDistrictCodes.length === 1)
|
|
186
|
+
return uniqueDistrictCodes[0];
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=geo-group-mapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo-group-mapping.js","sourceRoot":"","sources":["../../client/shared/geo-group-mapping.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * geo_group 2자리 코드 ↔ 시도/시군구 매핑.\n * convert-augmented-xlsx-to-csv.py 의 GEO_GROUPS dict 를 TypeScript 로 이식.\n *\n * 운영자가 프로젝트 주소를 입력하면 그 안에서 시도+시군구 표준명을 부분 매칭하여\n * 2자리 코드를 추정. 자동 채움 후에도 운영자가 수동 정정 가능.\n */\n\n/**\n * 우편번호 prefix (2자리) → geo_group 2자리 코드 best-guess 매핑.\n * convert-augmented-xlsx-to-csv.py 의 GEO_GROUPS 세 번째 값 (postal_prefix) 기준,\n * 1:N 케이스는 첫 매칭 사용. 정확한 시군구 분리에는 한국 행정안전부 5자리 우편번호\n * 룩업 필요하지만 client embed 불가능 — best-guess 로 시도 단위 통계만 신뢰 가능.\n */\nexport const POSTAL_PREFIX_TO_GEO_GROUP: Record<string, string> = {\n '03': '01', // 서울 종로구\n '04': '02', // 서울 중구\n '05': '05', // 서울 광진구\n '06': '06', // 서울 강남구\n '07': '08', // 서울 강서구\n '10': '12', // 경기 고양시 / 파주시\n '11': '11', // 경기 성남시\n '12': '11', // 경기 성남시\n '13': '11', // 경기 성남시\n '14': '14', // 경기 부천시\n '15': '15', // 경기 안산시\n '16': '10', // 경기 수원시\n '17': '13', // 경기 용인시 / 평택시\n '18': '16', // 경기 화성시\n '21': '21', // 인천 남동구 / 부평구\n '22': '23', // 인천 서구\n '24': '24', // 강원 춘천시\n '25': '26', // 강원 강릉시\n '26': '25', // 강원 원주시\n '27': '28', // 충북 충주시 / 제천시\n '28': '27', // 충북 청주시\n '30': '30', // 세종\n '31': '31', // 충남 천안시 / 아산시\n '34': '35', // 대전 유성구\n '35': '34', // 대전 서구\n '36': '39', // 경북 안동시\n '37': '36', // 경북 포항시\n '38': '37', // 경북 경주시\n '39': '38', // 경북 구미시 / 김천시\n '41': '41', // 대구 중구\n '42': '42', // 대구 수성구 / 달서구\n '44': '44', // 울산 남구 / 중구\n '46': '49', // 부산 금정구\n '48': '46', // 부산 중구 / 해운대구\n '49': '48', // 부산 사하구\n '50': '51', // 경남 김해시 / 양산시\n '51': '50', // 경남 창원시\n '52': '52', // 경남 진주시\n '54': '54', // 전북 전주시 / 익산시 / 군산시\n '57': '59', // 전남 순천시\n '58': '57', // 전남 목포시\n '59': '58', // 전남 여수시\n '61': '61', // 광주 서구 / 북구\n '63': '63' // 제주\n}\n\nexport function inferGeoGroupFromPostalCode(postalCode: string | null | undefined): string | null {\n if (!postalCode) return null\n const prefix = postalCode.trim().slice(0, 2)\n return POSTAL_PREFIX_TO_GEO_GROUP[prefix] || null\n}\n\n/** \"시도+시군구 표준명\" → \"2자리 geo_group 코드\" */\nexport const ADDRESS_TO_GEO_GROUP: Record<string, string> = {\n '서울특별시 종로구': '01',\n '서울특별시 중구': '02',\n '서울특별시 용산구': '03',\n '서울특별시 성동구': '04',\n '서울특별시 광진구': '05',\n '서울특별시 강남구': '06',\n '서울특별시 송파구': '07',\n '서울특별시 강서구': '08',\n '경기도 수원시': '10',\n '경기도 성남시': '11',\n '경기도 고양시': '12',\n '경기도 용인시': '13',\n '경기도 부천시': '14',\n '경기도 안산시': '15',\n '경기도 화성시': '16',\n '경기도 평택시': '17',\n '경기도 파주시': '18',\n '인천광역시 남동구': '21',\n '인천광역시 부평구': '22',\n '인천광역시 서구': '23',\n '강원도 춘천시': '24',\n '강원도 원주시': '25',\n '강원도 강릉시': '26',\n '충청북도 청주시': '27',\n '충청북도 충주시': '28',\n '충청북도 제천시': '29',\n '세종특별자치시': '30',\n '충청남도 천안시': '31',\n '충청남도 아산시': '32',\n '강원도 속초시': '33',\n '대전광역시 서구': '34',\n '대전광역시 유성구': '35',\n '경상북도 포항시': '36',\n '경상북도 경주시': '37',\n '경상북도 구미시': '38',\n '경상북도 안동시': '39',\n '경상북도 김천시': '40',\n '대구광역시 중구': '41',\n '대구광역시 수성구': '42',\n '대구광역시 달서구': '43',\n '울산광역시 남구': '44',\n '울산광역시 중구': '45',\n '부산광역시 중구': '46',\n '부산광역시 해운대구': '47',\n '부산광역시 사하구': '48',\n '부산광역시 금정구': '49',\n '경상남도 창원시': '50',\n '경상남도 김해시': '51',\n '경상남도 진주시': '52',\n '경상남도 양산시': '53',\n '전라북도 전주시': '54',\n '전라북도 익산시': '55',\n '전라북도 군산시': '56',\n '전라남도 목포시': '57',\n '전라남도 여수시': '58',\n '전라남도 순천시': '59',\n '광주광역시 서구': '61',\n '광주광역시 북구': '62',\n '제주특별자치도 제주시': '63'\n}\n\n/** 시도 약칭 → 정식 명 (부분 매칭용). */\nconst PROVINCE_ALIASES: Record<string, string> = {\n 서울: '서울특별시',\n 경기: '경기도',\n 인천: '인천광역시',\n 강원: '강원도',\n 충북: '충청북도',\n 충남: '충청남도',\n 세종: '세종특별자치시',\n 대전: '대전광역시',\n 경북: '경상북도',\n 경남: '경상남도',\n 대구: '대구광역시',\n 울산: '울산광역시',\n 부산: '부산광역시',\n 전북: '전라북도',\n 전남: '전라남도',\n 광주: '광주광역시',\n 제주: '제주특별자치도'\n}\n\n/**\n * 주소 문자열에서 2자리 geo_group 코드 추정. 매칭 안 되면 null.\n * 매칭 우선:\n * 1) 정식 시도명 + 시군구명 (예: '서울특별시 종로구')\n * 2) 약칭 시도 + 시군구 (예: '서울 종로구' → '서울특별시 종로구')\n * 3) 시군구명 단독 매칭 (예: '종로구') — 유니크한 경우\n */\nexport function inferGeoGroupFromAddress(address: string | null | undefined): string | null {\n if (!address) return null\n const trimmed = address.trim()\n if (!trimmed) return null\n\n // 1) 정식 매칭\n for (const key of Object.keys(ADDRESS_TO_GEO_GROUP)) {\n if (trimmed.includes(key)) return ADDRESS_TO_GEO_GROUP[key]\n }\n\n // 2) 약칭 시도 → 정식 시도로 expand 후 다시 매칭\n for (const [short, full] of Object.entries(PROVINCE_ALIASES)) {\n if (trimmed.startsWith(short) && !trimmed.startsWith(full)) {\n const expanded = trimmed.replace(short, full)\n for (const key of Object.keys(ADDRESS_TO_GEO_GROUP)) {\n if (expanded.includes(key)) return ADDRESS_TO_GEO_GROUP[key]\n }\n }\n }\n\n // 3) 시군구명 단독 매칭 (시도 prefix 없는 경우). 유니크한 시군구만 통과.\n const districtMatches = Object.entries(ADDRESS_TO_GEO_GROUP)\n .filter(([key]) => {\n const parts = key.split(' ')\n const district = parts[parts.length - 1]\n return trimmed.includes(district)\n })\n .map(([, code]) => code)\n const uniqueDistrictCodes = Array.from(new Set(districtMatches))\n if (uniqueDistrictCodes.length === 1) return uniqueDistrictCodes[0]\n\n return null\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 완공 입력 화면의 "자동 수집" 워크플로용 외부 시스템 연동 수집 함수.
|
|
3
|
+
*
|
|
4
|
+
* 데모 목적: 키스콘·세움터·올바로에서 "연동을 통해 값을 가져온다"는 워크플로를
|
|
5
|
+
* 보여주기 위한 것. 실제 스크래핑/API 연동의 깊이는 이 함수 내부에 캡슐화되어
|
|
6
|
+
* 있으므로, 추후 실연동(integration-kiscon / data-go-kr / integration-allbaro)
|
|
7
|
+
* 으로 교체할 때 이 본문만 바꾸면 화면/저장 흐름은 그대로 유지된다.
|
|
8
|
+
*/
|
|
9
|
+
export type IntegrationSource = 'kiscon' | 'saeumteo' | 'allbaro';
|
|
10
|
+
export interface IntegrationSourceMeta {
|
|
11
|
+
source: IntegrationSource;
|
|
12
|
+
label: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
desc: string;
|
|
15
|
+
}
|
|
16
|
+
/** 화면에 표시할 연동 소스 목록 (수집 순서대로) */
|
|
17
|
+
export declare const INTEGRATION_SOURCES: IntegrationSourceMeta[];
|
|
18
|
+
export interface CollectedField {
|
|
19
|
+
/** 폼의 projectKey (KPI_METRIC_KEY_MAPPING 의 projectKey 와 일치) */
|
|
20
|
+
projectKey: string;
|
|
21
|
+
label: string;
|
|
22
|
+
value: number | string;
|
|
23
|
+
unit?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface CollectionResult {
|
|
26
|
+
source: IntegrationSource;
|
|
27
|
+
label: string;
|
|
28
|
+
fields: CollectedField[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 한 외부 시스템에서 연동으로 값을 수집한다.
|
|
32
|
+
* 데모에서는 연동 수집을 흉내내기 위해 짧은 지연 후 대표값을 반환한다
|
|
33
|
+
* (프로젝트에 이미 있는 값이 있으면 우선 사용).
|
|
34
|
+
*/
|
|
35
|
+
export declare function collectFromSource(source: IntegrationSource, project: any): Promise<CollectionResult>;
|