Refactor data loading and query projections
This commit is contained in:
+177
-10
@@ -3666,20 +3666,23 @@
|
||||
const serverFocusCode = {{ project_focus_code | tojson }};
|
||||
const projectEditCache = new Map();
|
||||
let modalOriginalEdit = null;
|
||||
const revenueMix = {{ project_revenue_mix | tojson }};
|
||||
let revenueMix = [];
|
||||
const revenueMixMode = {{ ("monthly" if selected_year else "yearly") | tojson }};
|
||||
const projectCostRows = {{ project_cost_by_year | tojson }};
|
||||
let projectCostRows = [];
|
||||
const projectMonthlyCostRows = {{ project_monthly_cost_rows | tojson }};
|
||||
const projectStatusRows = {{ project_status_rows | tojson }};
|
||||
let projectStatusRows = [];
|
||||
const projectComparisonNotes = {{ project_comparison_notes | tojson }};
|
||||
const projectAnalysisSettings = {{ project_analysis_settings | tojson }};
|
||||
const persistedProjectPageState = {{ project_page_state | tojson }};
|
||||
const persistedProjectRelatedLinks = {{ project_related_links | tojson }};
|
||||
const persistedUncontractedCategoryOverrides = {{ project_uncontracted_classifications | tojson }};
|
||||
const projectPageSessionId = window.clientSessionId || "";
|
||||
const projectStatusMap = Object.fromEntries(projectStatusRows.map((item) => [item.support_dept_code, item]));
|
||||
const projectAccountBreakdowns = {{ project_account_breakdowns | tojson }};
|
||||
const projectCostMap = Object.fromEntries(projectCostRows.map((item) => [item.support_dept_code, item]));
|
||||
let projectStatusMap = {};
|
||||
let projectAccountBreakdowns = {};
|
||||
let projectAccountBreakdownsLoaded = false;
|
||||
let projectAccountBreakdownsLoadedCodes = new Set();
|
||||
let projectAccountBreakdownsPromise = null;
|
||||
let projectCostMap = {};
|
||||
const currencyFormatter = new Intl.NumberFormat("ko-KR", { maximumFractionDigits: 0 });
|
||||
window.__projectRelatedSelections = new Map();
|
||||
const persistedUncontractedFilterState = {
|
||||
@@ -4586,6 +4589,7 @@
|
||||
} else {
|
||||
projectStatusRows.push(projectRow);
|
||||
}
|
||||
refreshProjectDerivedCaches();
|
||||
}
|
||||
|
||||
function createCollectionRow(row = {}) {
|
||||
@@ -6126,6 +6130,126 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
function buildProjectBreakdownRequestCodes(baseCode = "") {
|
||||
const normalizedBaseCode = String(baseCode || selectedCode || "").trim();
|
||||
if (!normalizedBaseCode) {
|
||||
return [];
|
||||
}
|
||||
const codeSet = new Set([normalizedBaseCode]);
|
||||
getRelatedCodes(normalizedBaseCode).forEach((code) => {
|
||||
const normalizedCode = String(code || "").trim();
|
||||
if (normalizedCode) {
|
||||
codeSet.add(normalizedCode);
|
||||
}
|
||||
});
|
||||
return [...codeSet];
|
||||
}
|
||||
|
||||
function hasProjectBreakdownDataForCodes(codes = []) {
|
||||
const requestedCodes = Array.isArray(codes)
|
||||
? codes.map((code) => String(code || "").trim()).filter(Boolean)
|
||||
: [];
|
||||
if (!requestedCodes.length) {
|
||||
return projectAccountBreakdownsLoaded;
|
||||
}
|
||||
return requestedCodes.every((code) => projectAccountBreakdownsLoadedCodes.has(code));
|
||||
}
|
||||
|
||||
async function loadProjectAccountBreakdowns(force = false, codes = []) {
|
||||
const requestedCodes = Array.isArray(codes)
|
||||
? codes.map((code) => String(code || "").trim()).filter(Boolean)
|
||||
: [];
|
||||
const needsFullLoad = !requestedCodes.length;
|
||||
if (!force) {
|
||||
if (needsFullLoad && projectAccountBreakdownsLoaded) {
|
||||
return projectAccountBreakdowns;
|
||||
}
|
||||
if (!needsFullLoad && requestedCodes.every((code) => projectAccountBreakdownsLoadedCodes.has(code))) {
|
||||
return projectAccountBreakdowns;
|
||||
}
|
||||
if (projectAccountBreakdownsPromise) {
|
||||
await projectAccountBreakdownsPromise;
|
||||
if (needsFullLoad && projectAccountBreakdownsLoaded) {
|
||||
return projectAccountBreakdowns;
|
||||
}
|
||||
if (!needsFullLoad && requestedCodes.every((code) => projectAccountBreakdownsLoadedCodes.has(code))) {
|
||||
return projectAccountBreakdowns;
|
||||
}
|
||||
}
|
||||
}
|
||||
const codesToLoad = force || needsFullLoad
|
||||
? requestedCodes
|
||||
: requestedCodes.filter((code) => !projectAccountBreakdownsLoadedCodes.has(code));
|
||||
const queryParams = new URLSearchParams();
|
||||
if (selectedYear) {
|
||||
queryParams.set("year", String(selectedYear));
|
||||
}
|
||||
if (codesToLoad.length) {
|
||||
queryParams.set("codes", codesToLoad.join(","));
|
||||
}
|
||||
const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
|
||||
projectAccountBreakdownsPromise = fetch(`/projects/account-breakdowns${query}`, {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
},
|
||||
}).then(async (response) => {
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
if (!response.ok || payload?.error) {
|
||||
throw new Error(payload?.error || `HTTP ${response.status}`);
|
||||
}
|
||||
const nextPayload = payload || {};
|
||||
if (needsFullLoad) {
|
||||
projectAccountBreakdowns = nextPayload;
|
||||
projectAccountBreakdownsLoaded = true;
|
||||
projectAccountBreakdownsLoadedCodes = new Set(Object.keys(nextPayload || {}));
|
||||
} else {
|
||||
projectAccountBreakdowns = {
|
||||
...projectAccountBreakdowns,
|
||||
...nextPayload,
|
||||
};
|
||||
codesToLoad.forEach((code) => {
|
||||
projectAccountBreakdownsLoadedCodes.add(code);
|
||||
});
|
||||
}
|
||||
return projectAccountBreakdowns;
|
||||
}).catch((error) => {
|
||||
console.error("프로젝트 계정 분해 조회 에러", error);
|
||||
if (needsFullLoad) {
|
||||
projectAccountBreakdowns = {};
|
||||
projectAccountBreakdownsLoaded = false;
|
||||
projectAccountBreakdownsLoadedCodes = new Set();
|
||||
}
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
projectAccountBreakdownsPromise = null;
|
||||
});
|
||||
return projectAccountBreakdownsPromise;
|
||||
}
|
||||
|
||||
async function loadProjectBootstrapData(force = false) {
|
||||
if (!force && projectStatusRows.length && projectCostRows.length) {
|
||||
return;
|
||||
}
|
||||
const query = selectedYear ? `?year=${encodeURIComponent(String(selectedYear))}` : "";
|
||||
const response = await fetch(`/projects/bootstrap-data${query}`, {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
},
|
||||
});
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
if (!response.ok || payload?.error) {
|
||||
throw new Error(payload?.error || `HTTP ${response.status}`);
|
||||
}
|
||||
revenueMix = Array.isArray(payload?.revenue_mix) ? payload.revenue_mix : [];
|
||||
projectCostRows = Array.isArray(payload?.project_cost_by_year) ? payload.project_cost_by_year : [];
|
||||
projectStatusRows = Array.isArray(payload?.project_status_rows) ? payload.project_status_rows : [];
|
||||
refreshProjectDerivedCaches();
|
||||
}
|
||||
|
||||
function getBreakdownList(code, kind) {
|
||||
const item = projectAccountBreakdowns?.[code] || {};
|
||||
return Array.isArray(item?.[kind]) ? item[kind] : [];
|
||||
@@ -7934,10 +8058,18 @@
|
||||
}
|
||||
|
||||
const aggregatedProjectCostDatasetCache = new Map();
|
||||
const aggregatedAllProjectCostRows = mergeProjectExplorerRows(projectCostRows, projectStatusRows);
|
||||
const aggregatedAllProjectCostMap = new Map(
|
||||
aggregatedAllProjectCostRows.map((item) => [item.support_dept_code, item]),
|
||||
);
|
||||
let aggregatedAllProjectCostRows = [];
|
||||
let aggregatedAllProjectCostMap = new Map();
|
||||
|
||||
function refreshProjectDerivedCaches() {
|
||||
projectStatusMap = Object.fromEntries(projectStatusRows.map((item) => [item.support_dept_code, item]));
|
||||
projectCostMap = Object.fromEntries(projectCostRows.map((item) => [item.support_dept_code, item]));
|
||||
aggregatedProjectCostDatasetCache.clear();
|
||||
aggregatedAllProjectCostRows = mergeProjectExplorerRows(projectCostRows, projectStatusRows);
|
||||
aggregatedAllProjectCostMap = new Map(
|
||||
aggregatedAllProjectCostRows.map((item) => [item.support_dept_code, item]),
|
||||
);
|
||||
}
|
||||
|
||||
function getAggregatedProjectCostDataset(yearFilterValue) {
|
||||
const cacheKey = String(yearFilterValue || "");
|
||||
@@ -8950,6 +9082,36 @@
|
||||
scheduleStandaloneUncontractedDashboardRender();
|
||||
return;
|
||||
}
|
||||
const requestedBreakdownCodes = buildProjectBreakdownRequestCodes(item.support_dept_code);
|
||||
if (!hasProjectBreakdownDataForCodes(requestedBreakdownCodes)) {
|
||||
relatedBarBox.innerHTML = "";
|
||||
heroBox.innerHTML = renderAnalysisHero(item);
|
||||
metricsBox.innerHTML = renderAnalysisMetrics(item);
|
||||
comparisonBox.innerHTML = `
|
||||
<div class="detail-block">
|
||||
<p class="stacked-note">프로젝트 세부 집계 데이터를 불러오는 중입니다...</p>
|
||||
</div>
|
||||
`;
|
||||
notesBox.innerHTML = `
|
||||
<div class="detail-block">
|
||||
<p class="stacked-note">프로젝트 세부 집계 데이터를 준비한 뒤 표시합니다.</p>
|
||||
</div>
|
||||
`;
|
||||
loadProjectAccountBreakdowns(false, requestedBreakdownCodes).then(() => {
|
||||
const latestItem = getAnalysisItem(item.support_dept_code);
|
||||
if (latestItem && String(currentSelectedProjectCode || "") === String(item.support_dept_code || "")) {
|
||||
renderAnalysis(latestItem);
|
||||
}
|
||||
}).catch(() => {
|
||||
comparisonBox.innerHTML = `
|
||||
<div class="detail-block">
|
||||
<p class="stacked-note">프로젝트 세부 집계 데이터를 불러오지 못했습니다. 잠시 후 다시 시도해 주세요.</p>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
scheduleStandaloneUncontractedDashboardRender();
|
||||
return;
|
||||
}
|
||||
const baseCode = String(item.support_dept_code || "").trim();
|
||||
const allRelatedItems = getRelatedItems(item.support_dept_code, { includeInactive: true });
|
||||
const relatedItems = getRelatedItems(item.support_dept_code);
|
||||
@@ -9502,6 +9664,11 @@
|
||||
(async () => {
|
||||
await loadProjectPageStateFromServer();
|
||||
await loadProjectQuickLinksFromServer();
|
||||
try {
|
||||
await loadProjectBootstrapData();
|
||||
} catch (error) {
|
||||
console.error("프로젝트 부트스트랩 데이터 조회 에러", error);
|
||||
}
|
||||
if (serverEditCode) {
|
||||
selectedCode = serverEditCode;
|
||||
currentSelectedProjectCode = serverEditCode;
|
||||
|
||||
Reference in New Issue
Block a user