|
@@ -109,7 +109,7 @@ async function buildFieldCatalog(store) {
|
|
|
for (const upload of uploads) {
|
|
for (const upload of uploads) {
|
|
|
for (const col of ((upload.report && upload.report.columns) || [])) seen.add(col);
|
|
for (const col of ((upload.report && upload.report.columns) || [])) seen.add(col);
|
|
|
}
|
|
}
|
|
|
- sample = (await store.queryPlatformRows({})).slice(0, 300);
|
|
|
|
|
|
|
+ sample = (await cachedPlatformRows(store)).slice(0, 300);
|
|
|
if (!seen.size) {
|
|
if (!seen.size) {
|
|
|
for (const row of sample) for (const col of Object.keys(row.data || {})) seen.add(col);
|
|
for (const row of sample) for (const col of Object.keys(row.data || {})) seen.add(col);
|
|
|
}
|
|
}
|
|
@@ -218,11 +218,25 @@ function platformRowToMatrix(row) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 人工表 + 平台明细合并:同一天同一店,人工的 4 个指标覆盖平台,其余平台字段保留 */
|
|
/** 人工表 + 平台明细合并:同一天同一店,人工的 4 个指标覆盖平台,其余平台字段保留 */
|
|
|
|
|
+const PLATFORM_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
|
|
|
+const platformRowCache = new WeakMap(); // store -> { at, rows }
|
|
|
|
|
+
|
|
|
|
|
+/** 平台明细整表缓存:云端库单次拉取约 1.6MB,避免每个请求重复传输 */
|
|
|
|
|
+async function cachedPlatformRows(store) {
|
|
|
|
|
+ const hit = platformRowCache.get(store);
|
|
|
|
|
+ if (hit && Date.now() - hit.at < PLATFORM_CACHE_TTL_MS) return hit.rows;
|
|
|
|
|
+ const rows = await store.queryPlatformRows({});
|
|
|
|
|
+ platformRowCache.set(store, { at: Date.now(), rows });
|
|
|
|
|
+ return rows;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
async function loadMergedRows(store, { from, to, schools, shops } = {}) {
|
|
async function loadMergedRows(store, { from, to, schools, shops } = {}) {
|
|
|
let platform = [];
|
|
let platform = [];
|
|
|
try {
|
|
try {
|
|
|
- platform = await store.queryPlatformRows({ from, to });
|
|
|
|
|
|
|
+ platform = await cachedPlatformRows(store);
|
|
|
} catch { /* 平台表不可用不影响人工数据 */ }
|
|
} catch { /* 平台表不可用不影响人工数据 */ }
|
|
|
|
|
+ if (from) platform = platform.filter((row) => row.date >= from);
|
|
|
|
|
+ if (to) platform = platform.filter((row) => row.date <= to);
|
|
|
const manual = await store.queryRows({ from, to, schools, shops });
|
|
const manual = await store.queryRows({ from, to, schools, shops });
|
|
|
|
|
|
|
|
const map = new Map();
|
|
const map = new Map();
|
|
@@ -1009,6 +1023,7 @@ function register(app, ctx) {
|
|
|
return sendJson(res, 500, { error: '写入失败', detail: e.message || String(e) });
|
|
return sendJson(res, 500, { error: '写入失败', detail: e.message || String(e) });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ platformRowCache.delete(store);
|
|
|
return sendJson(res, 200, {
|
|
return sendJson(res, 200, {
|
|
|
ok: true,
|
|
ok: true,
|
|
|
uploadId,
|
|
uploadId,
|
|
@@ -1079,6 +1094,7 @@ function register(app, ctx) {
|
|
|
return sendJson(res, 500, { error: '写入失败', detail: e.message || String(e) });
|
|
return sendJson(res, 500, { error: '写入失败', detail: e.message || String(e) });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ platformRowCache.delete(store);
|
|
|
sendJson(res, 200, {
|
|
sendJson(res, 200, {
|
|
|
ok: true,
|
|
ok: true,
|
|
|
uploadId,
|
|
uploadId,
|