|
@@ -105,14 +105,12 @@ const FIELD_MAP = {
|
|
|
rebuy_rate_30d: 'rebuyRate30d',
|
|
rebuy_rate_30d: 'rebuyRate30d',
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-function trimRaw(raw) {
|
|
|
|
|
- const out = {};
|
|
|
|
|
- for (const [k, v] of Object.entries(raw || {})) {
|
|
|
|
|
- if (k === 'ds') continue;
|
|
|
|
|
- if (/_diff$|_mall_avg$|_mall_avg_rank$/.test(k)) continue;
|
|
|
|
|
- out[k] = v;
|
|
|
|
|
- }
|
|
|
|
|
- return out;
|
|
|
|
|
|
|
+// 全字段落库:原始返回一字不差保留,不做任何裁剪。
|
|
|
|
|
+// historyOverview 每行约 60+ 字段 = 基础 13 项(ds + 12 指标)+ 环比差值 _diff(12)
|
|
|
|
|
+// + 同行均值/排名 _mall_avg(_rank)(25) + 上期对比 _last_period(13)。
|
|
|
|
|
+// 后续渲染加工 / 比对分析直接从 raw 取用,无需重新取数。
|
|
|
|
|
+function captureRaw(raw) {
|
|
|
|
|
+ return { ...(raw || {}) };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function normalizeRow(rawDaily, ctx) {
|
|
function normalizeRow(rawDaily, ctx) {
|
|
@@ -127,7 +125,7 @@ function normalizeRow(rawDaily, ctx) {
|
|
|
abnormalCloseHours: null,
|
|
abnormalCloseHours: null,
|
|
|
goodsSaleAmt: null,
|
|
goodsSaleAmt: null,
|
|
|
syncedAt: new Date().toISOString(),
|
|
syncedAt: new Date().toISOString(),
|
|
|
- raw: trimRaw(rawDaily),
|
|
|
|
|
|
|
+ raw: captureRaw(rawDaily),
|
|
|
};
|
|
};
|
|
|
for (const [src, dst] of Object.entries(FIELD_MAP)) {
|
|
for (const [src, dst] of Object.entries(FIELD_MAP)) {
|
|
|
const v = rawDaily[src];
|
|
const v = rawDaily[src];
|
|
@@ -136,6 +134,16 @@ function normalizeRow(rawDaily, ctx) {
|
|
|
return row;
|
|
return row;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 范围汇总行(接口返回 ds='all'):唯一携带同行均值/排名与整段环比的行。
|
|
|
|
|
+// 以 scope='summary'、date=区间末日 入库,与公司/连锁/门店行互不干扰。
|
|
|
|
|
+function normalizeSummaryRow(allRow, ctx) {
|
|
|
|
|
+ const row = normalizeRow({ ...allRow, ds: ctx.date }, ctx);
|
|
|
|
|
+ row.scope = 'summary';
|
|
|
|
|
+ row.shopId = '';
|
|
|
|
|
+ row.shopName = '';
|
|
|
|
|
+ return row;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// ---------- 连接状态 ----------
|
|
// ---------- 连接状态 ----------
|
|
|
|
|
|
|
|
/** 按平台给出「以调试端口启动商家客户端」的可执行指引 */
|
|
/** 按平台给出「以调试端口启动商家客户端」的可执行指引 */
|
|
@@ -354,6 +362,7 @@ async function runSync({ from, to, scope = 'all', chainId, shopIds, port } = {})
|
|
|
/**
|
|
/**
|
|
|
* 调 historyOverview 取一个区间的逐日行并归一化。
|
|
* 调 historyOverview 取一个区间的逐日行并归一化。
|
|
|
* scopeKey = { chainId, shopListIn };ctx 携带行的归属信息。
|
|
* scopeKey = { chainId, shopListIn };ctx 携带行的归属信息。
|
|
|
|
|
+ * 返回:逐日行数组 + (若接口返回 ds='all' 汇总行)一条 scope='summary' 的范围汇总行。
|
|
|
*/
|
|
*/
|
|
|
async function callHistory(scopeKey, ctx, port = DEFAULT_CDP_PORT) {
|
|
async function callHistory(scopeKey, ctx, port = DEFAULT_CDP_PORT) {
|
|
|
const o = {
|
|
const o = {
|
|
@@ -370,7 +379,11 @@ async function callHistory(scopeKey, ctx, port = DEFAULT_CDP_PORT) {
|
|
|
if (r.code != null && r.code !== 0 && String(r.code) !== '0') {
|
|
if (r.code != null && r.code !== 0 && String(r.code) !== '0') {
|
|
|
throw new Error('接口返回异常 code=' + r.code + (r.msg ? ' ' + r.msg : ''));
|
|
throw new Error('接口返回异常 code=' + r.code + (r.msg ? ' ' + r.msg : ''));
|
|
|
}
|
|
}
|
|
|
- return (r.daily || []).map((d) => normalizeRow(d, ctx));
|
|
|
|
|
|
|
+ const daily = (r.daily || []).map((d) => normalizeRow(d, ctx));
|
|
|
|
|
+ if (r.all) {
|
|
|
|
|
+ daily.push(normalizeSummaryRow(r.all, { ...ctx, date: syncState.to }));
|
|
|
|
|
+ }
|
|
|
|
|
+ return daily;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function requestSyncCancel() {
|
|
function requestSyncCancel() {
|