Procházet zdrojové kódy

fix: PostgreSQL 驱动兼容问题(首次实跑暴露)

- summary() 两处子查询缺别名,PG 报 "subquery in FROM must have an alias"
- queryPlatformRows 的日期占位符漏了 $,生成 date >= 1 导致区间查询返回空
- db-export/db-import 增加经营报告历史的导出与导入
- 已用云端 PG 15 实测:驾驶舱/学校/报告/上传记录/保存报告全部正常
liangzhao před 1 týdnem
rodič
revize
07fdb32a2d
3 změnil soubory, kde provedl 29 přidání a 5 odebrání
  1. 8 1
      scripts/db-export.js
  2. 17 0
      scripts/db-import.js
  3. 4 4
      server/stores/ops-pg.js

+ 8 - 1
scripts/db-export.js

@@ -37,6 +37,12 @@ const { createOpsStore } = require('../ops-store.js');
   const rows = await store.queryRows({});
   const platformRows = await store.queryPlatformRows({});
   const summary = await store.summary();
+  // 经营报告历史(完整快照),迁移后仍可回看/下载
+  const reports = [];
+  for (const item of await store.listReports()) {
+    const full = await store.getReport(item.id);
+    if (full) reports.push({ ...item, report: full });
+  }
 
   const payload = {
     version: 1,
@@ -46,6 +52,7 @@ const { createOpsStore } = require('../ops-store.js');
     uploads,
     shops: summary.shops,
     platformRows,
+    reports,
     rows: rows.map((r) => ({
       date: r.date,
       shopKey: r.shopKey,
@@ -64,6 +71,6 @@ const { createOpsStore } = require('../ops-store.js');
   };
 
   fs.writeFileSync(outPath, JSON.stringify(payload, null, 2));
-  console.log(`已导出 ${uploads.length} 次上传、${rows.length} 行人工数据、${platformRows.length} 行平台明细 → ${outPath}${withFiles ? '(含原件)' : '(不含原件)'}`);
+  console.log(`已导出 ${uploads.length} 次上传、${rows.length} 行人工数据、${platformRows.length} 行平台明细、${reports.length} 份报告 → ${outPath}${withFiles ? '(含原件)' : '(不含原件)'}`);
   await store.close();
 })();

+ 17 - 0
scripts/db-import.js

@@ -92,6 +92,23 @@ const { createOpsStore } = require('../ops-store.js');
     process.exit(1);
   }
 
+  if (Array.isArray(payload.reports) && payload.reports.length) {
+    for (const item of payload.reports) {
+      await store.insertReport({
+        id: item.id,
+        createdAt: item.createdAt,
+        periodFrom: item.from,
+        periodTo: item.to,
+        schools: item.schools || [],
+        shops: item.shops || [],
+        source: item.source || 'rules',
+        model: item.model || '',
+        title: item.title || '经营分析报告',
+        report: item.report,
+      }).catch((err) => console.error('报告导入失败:' + item.id + ' ' + (err.message || err)));
+    }
+  }
+
   const summary = await store.summary();
   console.log(`导入完成:上传 ${summary.uploadCount} 次 · ${summary.rowCount} 行 · ${summary.schools.length} 个学校`);
   await store.close();

+ 4 - 4
server/stores/ops-pg.js

@@ -318,8 +318,8 @@ function createPgStore({ connectionString, ssl = true, max = 5, schema = 'public
   async function queryPlatformRows({ from, to } = {}) {
     const where = [];
     const params = [];
-    if (from) { params.push(String(from)); where.push(`date >= ${params.length}`); }
-    if (to) { params.push(String(to)); where.push(`date <= ${params.length}`); }
+    if (from) { params.push(String(from)); where.push(`date >= $${params.length}`); }
+    if (to) { params.push(String(to)); where.push(`date <= $${params.length}`); }
     const sql = `SELECT * FROM ops_platform_row ${where.length ? 'WHERE ' + where.join(' AND ') : ''} ORDER BY date ASC, shop_id ASC`;
     const r = await getPool().query(sql, params);
     return r.rows.map((row) => ({
@@ -340,9 +340,9 @@ function createPgStore({ connectionString, ssl = true, max = 5, schema = 'public
       poolRef.query('SELECT COUNT(*)::int AS c FROM ops_row'),
       poolRef.query('SELECT COUNT(*)::int AS c FROM ops_platform_row'),
       poolRef.query(`SELECT MIN(d) AS f, MAX(d) AS t FROM (
-        SELECT date AS d FROM ops_row UNION SELECT date AS d FROM ops_platform_row)`),
+        SELECT date AS d FROM ops_row UNION SELECT date AS d FROM ops_platform_row) AS t`),
       poolRef.query(`SELECT COUNT(*)::int AS c FROM (
-        SELECT date, shop_key FROM ops_row UNION SELECT date, shop_id FROM ops_platform_row)`),
+        SELECT date, shop_key FROM ops_row UNION SELECT date, shop_id FROM ops_platform_row) AS t`),
       poolRef.query(`SELECT school, COUNT(DISTINCT shop)::int AS c FROM (
         SELECT school, shop_id AS shop FROM ops_platform_row WHERE school <> ''
         UNION SELECT school, shop_key AS shop FROM ops_row WHERE school <> ''