浏览代码

feat: 店铺运营字段排序 + 平台明细缓存

- 表头(金额/数量/比率)点击排序,再点切换升降序;门店在各自学校内排序,学校按小计排序
- 比率字段按曝光加权汇总后排序(不是简单平均)
- 云端库下每次请求都要拉 1.6MB 平台明细(接口 5-8 秒),改为进程内缓存 5 分钟,上传后立即失效
- 实测:字段接口 6s → 0.04s,明细接口 6.4s → 0.07s
liangzhao 1 周之前
父节点
当前提交
a84beb302d
共有 1 个文件被更改,包括 18 次插入 和 2 次删除
  1. 18 2
      server/routes/ops.js

+ 18 - 2
server/routes/ops.js

@@ -109,7 +109,7 @@ async function buildFieldCatalog(store) {
     for (const upload of uploads) {
       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) {
       for (const row of sample) for (const col of Object.keys(row.data || {})) seen.add(col);
     }
@@ -218,11 +218,25 @@ function platformRowToMatrix(row) {
 }
 
 /** 人工表 + 平台明细合并:同一天同一店,人工的 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 } = {}) {
   let platform = [];
   try {
-    platform = await store.queryPlatformRows({ from, to });
+    platform = await cachedPlatformRows(store);
   } 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 map = new Map();
@@ -1009,6 +1023,7 @@ function register(app, ctx) {
         return sendJson(res, 500, { error: '写入失败', detail: e.message || String(e) });
       }
 
+      platformRowCache.delete(store);
       return sendJson(res, 200, {
         ok: true,
         uploadId,
@@ -1079,6 +1094,7 @@ function register(app, ctx) {
       return sendJson(res, 500, { error: '写入失败', detail: e.message || String(e) });
     }
 
+    platformRowCache.delete(store);
     sendJson(res, 200, {
       ok: true,
       uploadId,