siluzan-tso-cli 1.1.44-beta.2 → 1.1.44-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +3 -4
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/report-templates/google-ads-diagnosis.md +6 -6
- package/dist/skill/report-templates/GoogleAdsDiagnosisReport.html +291 -230
- package/dist/skill/report-templates/google-ads-diagnosis.md +6 -6
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.44-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.44-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -128632,7 +128632,6 @@ function createDefaultDiagnosisReportData() {
|
|
|
128632
128632
|
keywordCount: 0,
|
|
128633
128633
|
adCount: 0,
|
|
128634
128634
|
extensionCount: 0,
|
|
128635
|
-
negativeKeywordCount: 0,
|
|
128636
128635
|
countriesWithConversionsCount: 0
|
|
128637
128636
|
},
|
|
128638
128637
|
conversionGoals: { items: [] },
|
|
@@ -128965,7 +128964,7 @@ function buildStructureCounts(resourceRecord, campaignRows2, keywordRows, search
|
|
|
128965
128964
|
keywordCount,
|
|
128966
128965
|
adCount: num(resourceRecord?.adCount),
|
|
128967
128966
|
extensionCount: num(resourceRecord?.extensionCount),
|
|
128968
|
-
negativeKeywordCount
|
|
128967
|
+
// collect 未拉取否词明细,不输出 negativeKeywordCount(避免报告展示 0 误导)
|
|
128969
128968
|
countriesWithConversionsCount: num(resourceRecord?.countriesWithConversionsCount),
|
|
128970
128969
|
searchTermCount: searchRows.length
|
|
128971
128970
|
};
|
|
@@ -129126,6 +129125,7 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
129126
129125
|
loadSectionSnapshot(snapDir, "resource-counts", accountId, start, end)
|
|
129127
129126
|
);
|
|
129128
129127
|
const goldRecord = sectionRecord(loadSectionSnapshot(snapDir, "gold-account", accountId, start, end)) ?? {};
|
|
129128
|
+
delete goldRecord.adsNegativeQualified;
|
|
129129
129129
|
const campaignCurrent = sectionItems(
|
|
129130
129130
|
loadSectionSnapshot(snapDir, "campaigns", accountId, start, end)
|
|
129131
129131
|
);
|
|
@@ -129195,7 +129195,6 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
129195
129195
|
keywordCount: structureCounts.keywordCount,
|
|
129196
129196
|
adCount: structureCounts.adCount,
|
|
129197
129197
|
extensionCount: structureCounts.extensionCount,
|
|
129198
|
-
negativeKeywordCount: structureCounts.negativeKeywordCount,
|
|
129199
129198
|
countriesWithConversionsCount: structureCounts.countriesWithConversionsCount
|
|
129200
129199
|
};
|
|
129201
129200
|
data.conversionGoals = {
|
|
@@ -129930,7 +129929,7 @@ var NARRATIVE_CONSISTENCY_RULES = [
|
|
|
129930
129929
|
id: "negative-keyword-zero-as-core-issue",
|
|
129931
129930
|
textPattern: /否定(关键)?词.{0,40}(为\s*0|数量为\s*0|为0|缺少|没有)/,
|
|
129932
129931
|
isContradicted: () => true,
|
|
129933
|
-
hint: "\u7981\u6B62\u5C06\u300C\u5426\u5B9A\u5173\u952E\u8BCD\u6570\u91CF\u4E3A 0 / \u7F3A\u5C11\u5426\u8BCD\u300D\u5199\u5165 summary.keyIssues \u6216 diagnosisOverview.disadvantages\
|
|
129932
|
+
hint: "\u672C\u62A5\u544A collect \u672A\u62C9\u53D6\u5426\u8BCD\u6570\u636E\uFF0C\u7981\u6B62\u5C06\u300C\u5426\u5B9A\u5173\u952E\u8BCD\u6570\u91CF\u4E3A 0 / \u7F3A\u5C11\u5426\u8BCD\u300D\u5199\u5165 summary.keyIssues \u6216 diagnosisOverview.disadvantages\u3002\u6709\u641C\u7D22\u8BCD\u6D6A\u8D39\u65F6\u4EC5\u5728 \xA708 \u6309\u5177\u4F53\u641C\u7D22\u8BCD\u5199\u4F18\u5316\u5EFA\u8BAE\uFF0C\u52FF\u4EE5\u5426\u8BCD\u8BA1\u6570\u4E0B\u7ED3\u8BBA\u3002"
|
|
129934
129933
|
},
|
|
129935
129934
|
{
|
|
129936
129935
|
id: "landing-page-missing-as-core-issue",
|
package/dist/skill/_meta.json
CHANGED
|
@@ -68,7 +68,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
68
68
|
- 若环比列全为 `null`,检查落盘目录是否存在上一周期文件(如 `campaigns-<id>_20260503-20260602.json`);不存在则**重新执行 collect**(勿用手动拼装或 Python 脚本绕过 CLI)。
|
|
69
69
|
|
|
70
70
|
- **render 自动合并(默认开启)**:若同目录存在 `google-ads-diagnosis-collect.json`,且 Agent 改坏了 `campaigns` / `geographic` / `keywords` 的 `items`(缺 `title`/`currentCost` 或环比写成字符串)或整体覆盖丢弃了 `landingPageAnalysis.desktop`/`mobile`,CLI **自动从 collect.reportData 恢复**,保留 Agent 的 `analysis`/`suggestions`。可用 `--no-merge-collect` 关闭;`--collect <file>` 指定 collect 路径。
|
|
71
|
-
- **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages`
|
|
71
|
+
- **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages` 与事实字段矛盾,或出现「否词相关 / 着陆页测速缺失」禁写项、预算/创意建议千篇一律、§07 写成关键词洞察时同样 **exit 1**。
|
|
72
72
|
|
|
73
73
|
- **禁止**在 `collect` 阶段生成或写入 `analysis` / `suggestions` / `diagnosisOverview` / `summary` 等建议性文案。
|
|
74
74
|
- **禁止**跳过 Agent 直接 `render` collect 产物(`render` 会校验全部叙事 / 建议字段;调试可加 `--lenient`)。
|
|
@@ -144,7 +144,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
144
144
|
- 结论涉及「转化跟踪/GA 关联」→ 核对 `goldAccount.gaConfigured` / `goldAccount.conversionTrackingQualified`(按第 4 条 `true`=已达标)。
|
|
145
145
|
- 结论涉及「着陆页测速/性能」→ 先看 `landingPageAnalysis.source`:`api` 才可用 desktop/mobile 的 score/FCP;`simple` 只能写简易诊断信号(`simpleDiagnosis`),**禁止**把 fetchMs 当 FCP 或编造性能指数;`none` 写「数据未获取」。
|
|
146
146
|
- **禁止写入 keyIssues / disadvantages(render 硬拦截)**:
|
|
147
|
-
- 「否定关键词数量为 0 /
|
|
147
|
+
- 「否定关键词数量为 0 / 缺少否词过滤」——本报告 **collect 未拉取否词数据**,结构表与黄金账户**不展示否词项**;禁止据此下结论。有搜索词浪费时仅在 §08 按具体搜索词写。
|
|
148
148
|
- 「着陆页性能数据缺失 / 无法评估加载速度」——测速未获取是采集降级,**不是**投放核心问题;只在 §07 `analysis` 说明即可。
|
|
149
149
|
- `render` 会对已知矛盾与上述禁写模式做**硬校验**,命中直接 `exit 1`——须按提示改写,**禁止**删字段绕过。
|
|
150
150
|
|
|
@@ -243,10 +243,9 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
243
243
|
| 有效关键字 (Effective Keywords) | |
|
|
244
244
|
| 有效广告 (Effective Ads) | |
|
|
245
245
|
| 附加链接 (Sitelinks) | |
|
|
246
|
-
| 否定关键字 (Negative Keywords) | |
|
|
247
246
|
| 有效国家 (Effective Countries) | |
|
|
248
247
|
|
|
249
|
-
**对应字段**:`structure.campaignCount`、`adGroupCount`、`keywordCount`、`adCount`、`extensionCount`、`
|
|
248
|
+
**对应字段**:`structure.campaignCount`、`adGroupCount`、`keywordCount`、`adCount`、`extensionCount`、`countriesWithConversionsCount`(**不含**否词计数;collect 未拉否词)
|
|
250
249
|
|
|
251
250
|
### 3.3 指标检测
|
|
252
251
|
|
|
@@ -329,10 +328,11 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
329
328
|
| 附加链接 | | |
|
|
330
329
|
| 附加宣传信息 | | |
|
|
331
330
|
| 附加电话信息 | | |
|
|
332
|
-
| 否定词添加 | | |
|
|
333
331
|
| 受众群体设置 | | |
|
|
334
332
|
| 出价策略 | | |
|
|
335
333
|
|
|
334
|
+
> 黄金账户表**不含**「否定词添加」(`adsNegativeQualified`):collect 未拉取否词数据,render 会剥离该字段。
|
|
335
|
+
|
|
336
336
|
**得分**:`goldAccountScore`;**未达标项数**:若有 `goldAccountUnqualifiedCount` 可注明。
|
|
337
337
|
|
|
338
338
|
---
|
|
@@ -498,7 +498,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
498
498
|
### 12.1 核心问题总结
|
|
499
499
|
|
|
500
500
|
- `summary.keyIssues`:逐条列出(或写「暂无核心问题」)
|
|
501
|
-
-
|
|
501
|
+
- **不要写**:否词数量/缺少否词(本报告无否词数据);着陆页测速数据缺失(见撰写硬约束第 5 条)
|
|
502
502
|
|
|
503
503
|
### 12.2 优先级优化路线图
|
|
504
504
|
|
|
@@ -2110,7 +2110,7 @@
|
|
|
2110
2110
|
{ key: "adsSitelinkExtensionQualified", name: "附加链接" },
|
|
2111
2111
|
{ key: "adsCalloutExtensionQualified", name: "附加宣传信息" },
|
|
2112
2112
|
{ key: "adsCallExtensionQualified", name: "附加电话信息" },
|
|
2113
|
-
|
|
2113
|
+
// collect 未拉取否词数据,不展示「否定词添加」
|
|
2114
2114
|
{ key: "audienceQualified", name: "受众群体设置" },
|
|
2115
2115
|
{ key: "biddingPolicyQualified", name: "出价策略" },
|
|
2116
2116
|
];
|
|
@@ -2130,7 +2130,6 @@
|
|
|
2130
2130
|
附加链接: "请添加附加链接,为用户提供更多访问路径",
|
|
2131
2131
|
附加宣传信息: "请添加宣传信息,突出产品优势",
|
|
2132
2132
|
附加电话信息: "请添加电话信息,方便用户直接联系",
|
|
2133
|
-
否定词添加: "请添加否定关键词,排除不相关流量",
|
|
2134
2133
|
受众群体设置: "请设置受众群体,提高广告精准度",
|
|
2135
2134
|
出价策略: "请使用智能出价策略,让Google AI优化出价",
|
|
2136
2135
|
};
|
|
@@ -2933,31 +2932,83 @@
|
|
|
2933
2932
|
return suggestions;
|
|
2934
2933
|
};
|
|
2935
2934
|
|
|
2935
|
+
/**
|
|
2936
|
+
* 统一图例布局:卡片已有 HTML chart-title 时不再画 ECharts title,避免与 legend 重叠。
|
|
2937
|
+
* 无 HTML 标题时把 ECharts title 置顶、legend 放底部。
|
|
2938
|
+
*/
|
|
2939
|
+
const applyChartChrome = (option, opts = {}) => {
|
|
2940
|
+
const { chartTitle, hasHtmlTitle = false, legendPlacement = "top" } = opts;
|
|
2941
|
+
const next = { ...option };
|
|
2942
|
+
const baseLegend =
|
|
2943
|
+
typeof next.legend === "object" && next.legend ? { ...next.legend } : {};
|
|
2944
|
+
|
|
2945
|
+
if (hasHtmlTitle || !chartTitle) {
|
|
2946
|
+
delete next.title;
|
|
2947
|
+
if (baseLegend.orient === "vertical") {
|
|
2948
|
+
next.legend = {
|
|
2949
|
+
...baseLegend,
|
|
2950
|
+
orient: "vertical",
|
|
2951
|
+
right: 10,
|
|
2952
|
+
top: "middle",
|
|
2953
|
+
left: undefined,
|
|
2954
|
+
bottom: undefined,
|
|
2955
|
+
};
|
|
2956
|
+
} else if (legendPlacement === "bottom") {
|
|
2957
|
+
next.legend = { ...baseLegend, bottom: 0, top: undefined, left: "center" };
|
|
2958
|
+
if (next.grid) {
|
|
2959
|
+
next.grid = {
|
|
2960
|
+
...next.grid,
|
|
2961
|
+
bottom: Math.max(Number(next.grid.bottom) || 0, 48),
|
|
2962
|
+
};
|
|
2963
|
+
}
|
|
2964
|
+
} else {
|
|
2965
|
+
next.legend = { ...baseLegend, top: 4, left: "center", bottom: undefined };
|
|
2966
|
+
if (next.grid) {
|
|
2967
|
+
next.grid = { ...next.grid, top: 48 };
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
} else {
|
|
2971
|
+
next.title = {
|
|
2972
|
+
text: chartTitle,
|
|
2973
|
+
left: "center",
|
|
2974
|
+
top: 0,
|
|
2975
|
+
textStyle: { fontSize: 14, fontWeight: "bold" },
|
|
2976
|
+
};
|
|
2977
|
+
next.legend = { ...baseLegend, bottom: 0, top: undefined, left: "center" };
|
|
2978
|
+
if (next.grid) {
|
|
2979
|
+
next.grid = {
|
|
2980
|
+
...next.grid,
|
|
2981
|
+
top: 40,
|
|
2982
|
+
bottom: Math.max(Number(next.grid.bottom) || 0, 48),
|
|
2983
|
+
};
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
return next;
|
|
2987
|
+
};
|
|
2988
|
+
|
|
2936
2989
|
const buildGeographicChartConfig = (items) => {
|
|
2937
2990
|
if (!Array.isArray(items) || !items.length) return null;
|
|
2938
2991
|
const labels = items.map((item) => getItemLabel(item, "geographic"));
|
|
2939
2992
|
const dataPoints = items.map((item) => Number(item?.cost) || 0);
|
|
2940
2993
|
if (!dataPoints.some((value) => value > 0)) return null;
|
|
2941
|
-
return
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2994
|
+
return applyChartChrome(
|
|
2995
|
+
{
|
|
2996
|
+
color: ["#3b68f9", "#5b8fff", "#7ba7ff", "#9db9ff", "#bfcbff", "#dce5ff"],
|
|
2997
|
+
tooltip: { trigger: "item" },
|
|
2998
|
+
legend: { type: "scroll" },
|
|
2999
|
+
series: [
|
|
3000
|
+
{
|
|
3001
|
+
type: "pie",
|
|
3002
|
+
radius: ["40%", "65%"],
|
|
3003
|
+
center: ["50%", "46%"],
|
|
3004
|
+
itemStyle: { borderColor: "#ffffff", borderWidth: 2 },
|
|
3005
|
+
label: { show: false },
|
|
3006
|
+
data: labels.map((name, index) => ({ name, value: dataPoints[index] })),
|
|
3007
|
+
},
|
|
3008
|
+
],
|
|
2947
3009
|
},
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
series: [
|
|
2951
|
-
{
|
|
2952
|
-
type: "pie",
|
|
2953
|
-
radius: ["40%", "70%"],
|
|
2954
|
-
center: ["50%", "48%"],
|
|
2955
|
-
itemStyle: { borderColor: "#ffffff", borderWidth: 2 },
|
|
2956
|
-
label: { show: false },
|
|
2957
|
-
data: labels.map((name, index) => ({ name, value: dataPoints[index] })),
|
|
2958
|
-
},
|
|
2959
|
-
],
|
|
2960
|
-
};
|
|
3010
|
+
{ hasHtmlTitle: true, legendPlacement: "bottom" },
|
|
3011
|
+
);
|
|
2961
3012
|
};
|
|
2962
3013
|
|
|
2963
3014
|
const buildDeviceChartConfig = (items) => {
|
|
@@ -2966,22 +3017,20 @@
|
|
|
2966
3017
|
const costData = items.map((item) => Number(item?.cost) || 0);
|
|
2967
3018
|
const conversionData = items.map((item) => Number(item?.conversions) || 0);
|
|
2968
3019
|
if (!costData.some((v) => v > 0) && !conversionData.some((v) => v > 0)) return null;
|
|
2969
|
-
return
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
3020
|
+
return applyChartChrome(
|
|
3021
|
+
{
|
|
3022
|
+
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
|
|
3023
|
+
legend: {},
|
|
3024
|
+
grid: { left: "8%", right: "5%", bottom: 30, containLabel: true },
|
|
3025
|
+
xAxis: { type: "category", data: labels, axisLine: { show: false }, axisTick: { show: false } },
|
|
3026
|
+
yAxis: { type: "value", splitLine: { lineStyle: { color: "#f0f0f0" } } },
|
|
3027
|
+
series: [
|
|
3028
|
+
{ name: "消费", type: "bar", data: costData, itemStyle: { color: "#3b68f9" } },
|
|
3029
|
+
{ name: "转化次数", type: "bar", data: conversionData, itemStyle: { color: "#5b8fff" } },
|
|
3030
|
+
],
|
|
2974
3031
|
},
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
grid: { left: "8%", right: "5%", top: 70, bottom: 30, containLabel: true },
|
|
2978
|
-
xAxis: { type: "category", data: labels, axisLine: { show: false }, axisTick: { show: false } },
|
|
2979
|
-
yAxis: { type: "value", splitLine: { lineStyle: { color: "#f0f0f0" } } },
|
|
2980
|
-
series: [
|
|
2981
|
-
{ name: "消费", type: "bar", data: costData, itemStyle: { color: "#3b68f9" } },
|
|
2982
|
-
{ name: "转化次数", type: "bar", data: conversionData, itemStyle: { color: "#5b8fff" } },
|
|
2983
|
-
],
|
|
2984
|
-
};
|
|
3032
|
+
{ hasHtmlTitle: true },
|
|
3033
|
+
);
|
|
2985
3034
|
};
|
|
2986
3035
|
|
|
2987
3036
|
const buildAudienceChartConfig = (items) => {
|
|
@@ -2989,25 +3038,23 @@
|
|
|
2989
3038
|
const labels = items.map((item) => getItemLabel(item, "audience"));
|
|
2990
3039
|
const dataPoints = items.map((item) => Number(item?.cost) || 0);
|
|
2991
3040
|
if (!dataPoints.some((value) => value > 0)) return null;
|
|
2992
|
-
return
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
3041
|
+
return applyChartChrome(
|
|
3042
|
+
{
|
|
3043
|
+
color: ["#ff6b6b", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3"],
|
|
3044
|
+
tooltip: { trigger: "item" },
|
|
3045
|
+
legend: { orient: "vertical", type: "scroll" },
|
|
3046
|
+
series: [
|
|
3047
|
+
{
|
|
3048
|
+
type: "pie",
|
|
3049
|
+
radius: "65%",
|
|
3050
|
+
center: ["40%", "55%"],
|
|
3051
|
+
itemStyle: { borderColor: "#ffffff", borderWidth: 2 },
|
|
3052
|
+
data: labels.map((name, index) => ({ name, value: dataPoints[index] })),
|
|
3053
|
+
},
|
|
3054
|
+
],
|
|
2998
3055
|
},
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
series: [
|
|
3002
|
-
{
|
|
3003
|
-
type: "pie",
|
|
3004
|
-
radius: "65%",
|
|
3005
|
-
center: ["40%", "55%"],
|
|
3006
|
-
itemStyle: { borderColor: "#ffffff", borderWidth: 2 },
|
|
3007
|
-
data: labels.map((name, index) => ({ name, value: dataPoints[index] })),
|
|
3008
|
-
},
|
|
3009
|
-
],
|
|
3010
|
-
};
|
|
3056
|
+
{ hasHtmlTitle: true },
|
|
3057
|
+
);
|
|
3011
3058
|
};
|
|
3012
3059
|
|
|
3013
3060
|
const buildCustomAudienceChartConfig = (items) => {
|
|
@@ -3029,31 +3076,29 @@
|
|
|
3029
3076
|
if (totalConversions === 0) return 0;
|
|
3030
3077
|
return Number(((conversions / totalConversions) * 100).toFixed(2));
|
|
3031
3078
|
});
|
|
3032
|
-
return
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3079
|
+
return applyChartChrome(
|
|
3080
|
+
{
|
|
3081
|
+
tooltip: {
|
|
3082
|
+
trigger: "axis",
|
|
3083
|
+
axisPointer: { type: "shadow" },
|
|
3084
|
+
formatter: (params) =>
|
|
3085
|
+
params.map((p) => `${p.marker}${p.seriesName}: ${p.value}%`).join("<br/>"),
|
|
3086
|
+
},
|
|
3087
|
+
legend: {},
|
|
3088
|
+
grid: { left: "8%", right: "5%", bottom: 30, containLabel: true },
|
|
3089
|
+
xAxis: { type: "category", data: labels, axisLine: { show: false }, axisTick: { show: false } },
|
|
3090
|
+
yAxis: {
|
|
3091
|
+
type: "value",
|
|
3092
|
+
axisLabel: { formatter: "{value}%" },
|
|
3093
|
+
splitLine: { lineStyle: { color: "#f0f0f0" } },
|
|
3094
|
+
},
|
|
3095
|
+
series: [
|
|
3096
|
+
{ name: "花费占比 (%)", type: "bar", data: costPercent, itemStyle: { color: "#3b68f9" } },
|
|
3097
|
+
{ name: "转化占比 (%)", type: "bar", data: conversionPercent, itemStyle: { color: "#5b8fff" } },
|
|
3098
|
+
],
|
|
3051
3099
|
},
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
{ name: "转化占比 (%)", type: "bar", data: conversionPercent, itemStyle: { color: "#5b8fff" } },
|
|
3055
|
-
],
|
|
3056
|
-
};
|
|
3100
|
+
{ hasHtmlTitle: true },
|
|
3101
|
+
);
|
|
3057
3102
|
};
|
|
3058
3103
|
|
|
3059
3104
|
const buildTargetingTableRow = (item, labelKey) => {
|
|
@@ -3387,22 +3432,28 @@
|
|
|
3387
3432
|
|
|
3388
3433
|
const buildKeywordChartConfig = (items) => {
|
|
3389
3434
|
if (!Array.isArray(items) || !items.length) {
|
|
3390
|
-
return
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
yAxis: { type: "value", axisLabel: { formatter: "{value}%" } },
|
|
3397
|
-
series: [
|
|
3398
|
-
{
|
|
3399
|
-
name: "花费占比 (%)",
|
|
3400
|
-
type: "bar",
|
|
3401
|
-
data: [0],
|
|
3402
|
-
itemStyle: { color: "rgba(59, 104, 249, 0.6)", borderRadius: 6 },
|
|
3435
|
+
return applyChartChrome(
|
|
3436
|
+
{
|
|
3437
|
+
tooltip: {
|
|
3438
|
+
trigger: "axis",
|
|
3439
|
+
axisPointer: { type: "shadow" },
|
|
3440
|
+
valueFormatter: (v) => `${v}%`,
|
|
3403
3441
|
},
|
|
3404
|
-
|
|
3405
|
-
|
|
3442
|
+
legend: {},
|
|
3443
|
+
grid: { left: "8%", right: "5%", containLabel: true },
|
|
3444
|
+
xAxis: { type: "category", data: ["暂无数据"] },
|
|
3445
|
+
yAxis: { type: "value", axisLabel: { formatter: "{value}%" } },
|
|
3446
|
+
series: [
|
|
3447
|
+
{
|
|
3448
|
+
name: "花费占比 (%)",
|
|
3449
|
+
type: "bar",
|
|
3450
|
+
data: [0],
|
|
3451
|
+
itemStyle: { color: "rgba(59, 104, 249, 0.6)", borderRadius: 6 },
|
|
3452
|
+
},
|
|
3453
|
+
],
|
|
3454
|
+
},
|
|
3455
|
+
{ chartTitle: "关键词表现趋势" },
|
|
3456
|
+
);
|
|
3406
3457
|
}
|
|
3407
3458
|
|
|
3408
3459
|
const topItems = items.slice(0, 20);
|
|
@@ -3416,52 +3467,60 @@
|
|
|
3416
3467
|
return Number.isFinite(value) ? Number(value.toFixed(2)) : 0;
|
|
3417
3468
|
});
|
|
3418
3469
|
|
|
3419
|
-
return
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
type: "category",
|
|
3426
|
-
data: labels,
|
|
3427
|
-
axisLabel: { rotate: 45 },
|
|
3428
|
-
},
|
|
3429
|
-
yAxis: { type: "value", axisLabel: { formatter: "{value}%" } },
|
|
3430
|
-
series: [
|
|
3431
|
-
{
|
|
3432
|
-
name: "花费占比 (%)",
|
|
3433
|
-
type: "bar",
|
|
3434
|
-
data: costShareValues,
|
|
3435
|
-
itemStyle: { color: "rgba(59, 104, 249, 0.7)", borderRadius: 6 },
|
|
3470
|
+
return applyChartChrome(
|
|
3471
|
+
{
|
|
3472
|
+
tooltip: {
|
|
3473
|
+
trigger: "axis",
|
|
3474
|
+
axisPointer: { type: "shadow" },
|
|
3475
|
+
valueFormatter: (v) => `${v}%`,
|
|
3436
3476
|
},
|
|
3437
|
-
{
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3477
|
+
legend: {},
|
|
3478
|
+
grid: { left: "8%", right: "5%", bottom: 60, containLabel: true },
|
|
3479
|
+
xAxis: {
|
|
3480
|
+
type: "category",
|
|
3481
|
+
data: labels,
|
|
3482
|
+
axisLabel: { rotate: 45 },
|
|
3442
3483
|
},
|
|
3443
|
-
|
|
3444
|
-
};
|
|
3445
|
-
};
|
|
3446
|
-
|
|
3447
|
-
const buildSearchTermsChartConfig = (items) => {
|
|
3448
|
-
if (!Array.isArray(items) || !items.length) {
|
|
3449
|
-
return {
|
|
3450
|
-
title: { text: "搜索词表现趋势", left: "center" },
|
|
3451
|
-
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
|
|
3452
|
-
legend: { top: 28 },
|
|
3453
|
-
grid: { left: "8%", right: "5%", top: 60, bottom: 30, containLabel: true },
|
|
3454
|
-
xAxis: { type: "category", data: ["暂无数据"] },
|
|
3455
|
-
yAxis: { type: "value" },
|
|
3484
|
+
yAxis: { type: "value", axisLabel: { formatter: "{value}%" } },
|
|
3456
3485
|
series: [
|
|
3457
3486
|
{
|
|
3458
|
-
name: "
|
|
3487
|
+
name: "花费占比 (%)",
|
|
3488
|
+
type: "bar",
|
|
3489
|
+
data: costShareValues,
|
|
3490
|
+
itemStyle: { color: "rgba(59, 104, 249, 0.7)", borderRadius: 6 },
|
|
3491
|
+
},
|
|
3492
|
+
{
|
|
3493
|
+
name: "转化占比 (%)",
|
|
3459
3494
|
type: "bar",
|
|
3460
|
-
data:
|
|
3461
|
-
itemStyle: { color: "rgba(
|
|
3495
|
+
data: conversionShareValues,
|
|
3496
|
+
itemStyle: { color: "rgba(16, 185, 129, 0.7)", borderRadius: 6 },
|
|
3462
3497
|
},
|
|
3463
3498
|
],
|
|
3464
|
-
}
|
|
3499
|
+
},
|
|
3500
|
+
{ chartTitle: "关键词表现趋势" },
|
|
3501
|
+
);
|
|
3502
|
+
};
|
|
3503
|
+
|
|
3504
|
+
const buildSearchTermsChartConfig = (items) => {
|
|
3505
|
+
if (!Array.isArray(items) || !items.length) {
|
|
3506
|
+
return applyChartChrome(
|
|
3507
|
+
{
|
|
3508
|
+
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
|
|
3509
|
+
legend: {},
|
|
3510
|
+
grid: { left: "8%", right: "5%", containLabel: true },
|
|
3511
|
+
xAxis: { type: "category", data: ["暂无数据"] },
|
|
3512
|
+
yAxis: { type: "value" },
|
|
3513
|
+
series: [
|
|
3514
|
+
{
|
|
3515
|
+
name: "展示次数",
|
|
3516
|
+
type: "bar",
|
|
3517
|
+
data: [0],
|
|
3518
|
+
itemStyle: { color: "rgba(245, 158, 11, 0.7)", borderRadius: 6 },
|
|
3519
|
+
},
|
|
3520
|
+
],
|
|
3521
|
+
},
|
|
3522
|
+
{ chartTitle: "搜索词表现趋势" },
|
|
3523
|
+
);
|
|
3465
3524
|
}
|
|
3466
3525
|
|
|
3467
3526
|
const topItems = items.slice(0, 10);
|
|
@@ -3469,32 +3528,34 @@
|
|
|
3469
3528
|
const impressionsData = topItems.map((item) => Number(item?.impressions) || 0);
|
|
3470
3529
|
const clicksData = topItems.map((item) => Number(item?.clicks) || 0);
|
|
3471
3530
|
|
|
3472
|
-
return
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
},
|
|
3482
|
-
yAxis: { type: "value" },
|
|
3483
|
-
series: [
|
|
3484
|
-
{
|
|
3485
|
-
name: "展示次数",
|
|
3486
|
-
type: "bar",
|
|
3487
|
-
data: impressionsData,
|
|
3488
|
-
itemStyle: { color: "rgba(245, 158, 11, 0.75)", borderRadius: 6 },
|
|
3489
|
-
},
|
|
3490
|
-
{
|
|
3491
|
-
name: "点击次数",
|
|
3492
|
-
type: "bar",
|
|
3493
|
-
data: clicksData,
|
|
3494
|
-
itemStyle: { color: "rgba(16, 185, 129, 0.75)", borderRadius: 6 },
|
|
3531
|
+
return applyChartChrome(
|
|
3532
|
+
{
|
|
3533
|
+
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
|
|
3534
|
+
legend: {},
|
|
3535
|
+
grid: { left: "8%", right: "5%", bottom: 60, containLabel: true },
|
|
3536
|
+
xAxis: {
|
|
3537
|
+
type: "category",
|
|
3538
|
+
data: labels,
|
|
3539
|
+
axisLabel: { rotate: 45 },
|
|
3495
3540
|
},
|
|
3496
|
-
|
|
3497
|
-
|
|
3541
|
+
yAxis: { type: "value" },
|
|
3542
|
+
series: [
|
|
3543
|
+
{
|
|
3544
|
+
name: "展示次数",
|
|
3545
|
+
type: "bar",
|
|
3546
|
+
data: impressionsData,
|
|
3547
|
+
itemStyle: { color: "rgba(245, 158, 11, 0.75)", borderRadius: 6 },
|
|
3548
|
+
},
|
|
3549
|
+
{
|
|
3550
|
+
name: "点击次数",
|
|
3551
|
+
type: "bar",
|
|
3552
|
+
data: clicksData,
|
|
3553
|
+
itemStyle: { color: "rgba(16, 185, 129, 0.75)", borderRadius: 6 },
|
|
3554
|
+
},
|
|
3555
|
+
],
|
|
3556
|
+
},
|
|
3557
|
+
{ chartTitle: "搜索词表现趋势" },
|
|
3558
|
+
);
|
|
3498
3559
|
};
|
|
3499
3560
|
|
|
3500
3561
|
const STRATEGY_NAME_MAP = {
|
|
@@ -4101,22 +4162,78 @@
|
|
|
4101
4162
|
if (useCostClickTrend) {
|
|
4102
4163
|
const costData = items.map((item) => Number(item?.cost) || 0);
|
|
4103
4164
|
const clicksData = items.map((item) => Number(item?.clicks) || 0);
|
|
4104
|
-
return
|
|
4165
|
+
return applyChartChrome(
|
|
4166
|
+
{
|
|
4167
|
+
tooltip: { trigger: "axis" },
|
|
4168
|
+
legend: { textStyle: { fontSize: 12 } },
|
|
4169
|
+
grid: { left: "8%", right: "8%", bottom: 30, containLabel: true },
|
|
4170
|
+
xAxis: { type: "category", data: labels, axisLabel: { fontSize: 11 } },
|
|
4171
|
+
yAxis: [
|
|
4172
|
+
{
|
|
4173
|
+
type: "value",
|
|
4174
|
+
name: "消耗",
|
|
4175
|
+
position: "left",
|
|
4176
|
+
axisLabel: { fontSize: 11 },
|
|
4177
|
+
nameTextStyle: { fontSize: 12 },
|
|
4178
|
+
},
|
|
4179
|
+
{
|
|
4180
|
+
type: "value",
|
|
4181
|
+
name: "点击次数",
|
|
4182
|
+
position: "right",
|
|
4183
|
+
splitLine: { show: false },
|
|
4184
|
+
axisLabel: { fontSize: 11 },
|
|
4185
|
+
nameTextStyle: { fontSize: 12 },
|
|
4186
|
+
},
|
|
4187
|
+
],
|
|
4188
|
+
series: [
|
|
4189
|
+
{
|
|
4190
|
+
name: "消耗",
|
|
4191
|
+
type: "line",
|
|
4192
|
+
data: costData,
|
|
4193
|
+
smooth: 0.3,
|
|
4194
|
+
symbolSize: 6,
|
|
4195
|
+
yAxisIndex: 0,
|
|
4196
|
+
lineStyle: { color: "#3b82f6" },
|
|
4197
|
+
itemStyle: { color: "#3b82f6" },
|
|
4198
|
+
areaStyle: { color: "rgba(59, 130, 246, 0.12)" },
|
|
4199
|
+
},
|
|
4200
|
+
{
|
|
4201
|
+
name: "点击次数",
|
|
4202
|
+
type: "line",
|
|
4203
|
+
data: clicksData,
|
|
4204
|
+
smooth: 0.3,
|
|
4205
|
+
symbolSize: 6,
|
|
4206
|
+
yAxisIndex: 1,
|
|
4207
|
+
lineStyle: { color: "#10b981" },
|
|
4208
|
+
itemStyle: { color: "#10b981" },
|
|
4209
|
+
areaStyle: { color: "rgba(16, 185, 129, 0.12)" },
|
|
4210
|
+
},
|
|
4211
|
+
],
|
|
4212
|
+
},
|
|
4213
|
+
{ hasHtmlTitle: true },
|
|
4214
|
+
);
|
|
4215
|
+
}
|
|
4216
|
+
|
|
4217
|
+
const cpaData = items.map((item) => Number(item?.cpa) || 0);
|
|
4218
|
+
const conversionsData = items.map((item) => Number(item?.conversions ?? 0));
|
|
4219
|
+
|
|
4220
|
+
return applyChartChrome(
|
|
4221
|
+
{
|
|
4105
4222
|
tooltip: { trigger: "axis" },
|
|
4106
|
-
legend: {
|
|
4107
|
-
grid: { left: "8%", right: "8%",
|
|
4223
|
+
legend: { textStyle: { fontSize: 12 } },
|
|
4224
|
+
grid: { left: "8%", right: "8%", bottom: 30, containLabel: true },
|
|
4108
4225
|
xAxis: { type: "category", data: labels, axisLabel: { fontSize: 11 } },
|
|
4109
4226
|
yAxis: [
|
|
4110
4227
|
{
|
|
4111
4228
|
type: "value",
|
|
4112
|
-
name: "
|
|
4229
|
+
name: "CPA",
|
|
4113
4230
|
position: "left",
|
|
4114
4231
|
axisLabel: { fontSize: 11 },
|
|
4115
4232
|
nameTextStyle: { fontSize: 12 },
|
|
4116
4233
|
},
|
|
4117
4234
|
{
|
|
4118
4235
|
type: "value",
|
|
4119
|
-
name: "
|
|
4236
|
+
name: "转化次数",
|
|
4120
4237
|
position: "right",
|
|
4121
4238
|
splitLine: { show: false },
|
|
4122
4239
|
axisLabel: { fontSize: 11 },
|
|
@@ -4125,9 +4242,9 @@
|
|
|
4125
4242
|
],
|
|
4126
4243
|
series: [
|
|
4127
4244
|
{
|
|
4128
|
-
name: "
|
|
4245
|
+
name: "CPA",
|
|
4129
4246
|
type: "line",
|
|
4130
|
-
data:
|
|
4247
|
+
data: cpaData,
|
|
4131
4248
|
smooth: 0.3,
|
|
4132
4249
|
symbolSize: 6,
|
|
4133
4250
|
yAxisIndex: 0,
|
|
@@ -4136,70 +4253,20 @@
|
|
|
4136
4253
|
areaStyle: { color: "rgba(59, 130, 246, 0.12)" },
|
|
4137
4254
|
},
|
|
4138
4255
|
{
|
|
4139
|
-
name: "
|
|
4256
|
+
name: "转化次数",
|
|
4140
4257
|
type: "line",
|
|
4141
|
-
data:
|
|
4258
|
+
data: conversionsData,
|
|
4142
4259
|
smooth: 0.3,
|
|
4143
4260
|
symbolSize: 6,
|
|
4144
4261
|
yAxisIndex: 1,
|
|
4145
|
-
lineStyle: { color: "#
|
|
4146
|
-
itemStyle: { color: "#
|
|
4147
|
-
areaStyle: { color: "rgba(
|
|
4262
|
+
lineStyle: { color: "#f97316" },
|
|
4263
|
+
itemStyle: { color: "#f97316" },
|
|
4264
|
+
areaStyle: { color: "rgba(249, 115, 22, 0.12)" },
|
|
4148
4265
|
},
|
|
4149
4266
|
],
|
|
4150
|
-
}
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
const cpaData = items.map((item) => Number(item?.cpa) || 0);
|
|
4154
|
-
const conversionsData = items.map((item) => Number(item?.conversions ?? 0));
|
|
4155
|
-
|
|
4156
|
-
return {
|
|
4157
|
-
tooltip: { trigger: "axis" },
|
|
4158
|
-
legend: { top: 0, textStyle: { fontSize: 12 } },
|
|
4159
|
-
grid: { left: "8%", right: "8%", top: 40, bottom: 30, containLabel: true },
|
|
4160
|
-
xAxis: { type: "category", data: labels, axisLabel: { fontSize: 11 } },
|
|
4161
|
-
yAxis: [
|
|
4162
|
-
{
|
|
4163
|
-
type: "value",
|
|
4164
|
-
name: "CPA",
|
|
4165
|
-
position: "left",
|
|
4166
|
-
axisLabel: { fontSize: 11 },
|
|
4167
|
-
nameTextStyle: { fontSize: 12 },
|
|
4168
|
-
},
|
|
4169
|
-
{
|
|
4170
|
-
type: "value",
|
|
4171
|
-
name: "转化次数",
|
|
4172
|
-
position: "right",
|
|
4173
|
-
splitLine: { show: false },
|
|
4174
|
-
axisLabel: { fontSize: 11 },
|
|
4175
|
-
nameTextStyle: { fontSize: 12 },
|
|
4176
|
-
},
|
|
4177
|
-
],
|
|
4178
|
-
series: [
|
|
4179
|
-
{
|
|
4180
|
-
name: "CPA",
|
|
4181
|
-
type: "line",
|
|
4182
|
-
data: cpaData,
|
|
4183
|
-
smooth: 0.3,
|
|
4184
|
-
symbolSize: 6,
|
|
4185
|
-
yAxisIndex: 0,
|
|
4186
|
-
lineStyle: { color: "#3b82f6" },
|
|
4187
|
-
itemStyle: { color: "#3b82f6" },
|
|
4188
|
-
areaStyle: { color: "rgba(59, 130, 246, 0.12)" },
|
|
4189
|
-
},
|
|
4190
|
-
{
|
|
4191
|
-
name: "转化次数",
|
|
4192
|
-
type: "line",
|
|
4193
|
-
data: conversionsData,
|
|
4194
|
-
smooth: 0.3,
|
|
4195
|
-
symbolSize: 6,
|
|
4196
|
-
yAxisIndex: 1,
|
|
4197
|
-
lineStyle: { color: "#f97316" },
|
|
4198
|
-
itemStyle: { color: "#f97316" },
|
|
4199
|
-
areaStyle: { color: "rgba(249, 115, 22, 0.12)" },
|
|
4200
|
-
},
|
|
4201
|
-
],
|
|
4202
|
-
};
|
|
4267
|
+
},
|
|
4268
|
+
{ hasHtmlTitle: true },
|
|
4269
|
+
);
|
|
4203
4270
|
}
|
|
4204
4271
|
|
|
4205
4272
|
const labels = ["消耗", "点击", "转化"];
|
|
@@ -4485,10 +4552,6 @@
|
|
|
4485
4552
|
label: "附加链接 (Sitelinks)",
|
|
4486
4553
|
value: structure.extensionCount ?? 0,
|
|
4487
4554
|
},
|
|
4488
|
-
{
|
|
4489
|
-
label: "否定关键字 (Negative Keywords)",
|
|
4490
|
-
value: structure.negativeKeywordCount ?? 0,
|
|
4491
|
-
},
|
|
4492
4555
|
{
|
|
4493
4556
|
label: "有效国家 (Effective Countries)",
|
|
4494
4557
|
value: structure.countriesWithConversionsCount ?? 0,
|
|
@@ -4921,10 +4984,8 @@
|
|
|
4921
4984
|
(count, item) => count + (goldAccount[item.key] ? 1 : 0),
|
|
4922
4985
|
0,
|
|
4923
4986
|
);
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
? goldAccount.goldAccountUnqualifiedCount
|
|
4927
|
-
: totalItems - qualifiedCount;
|
|
4987
|
+
// 按当前展示项重算(已排除否词项),勿用可能含 adsNegativeQualified 的接口计数
|
|
4988
|
+
const unqualifiedCount = totalItems - qualifiedCount;
|
|
4928
4989
|
const scoreValue =
|
|
4929
4990
|
goldAccount.goldAccountScore !== undefined && goldAccount.goldAccountScore !== null
|
|
4930
4991
|
? String(goldAccount.goldAccountScore)
|
|
@@ -68,7 +68,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
68
68
|
- 若环比列全为 `null`,检查落盘目录是否存在上一周期文件(如 `campaigns-<id>_20260503-20260602.json`);不存在则**重新执行 collect**(勿用手动拼装或 Python 脚本绕过 CLI)。
|
|
69
69
|
|
|
70
70
|
- **render 自动合并(默认开启)**:若同目录存在 `google-ads-diagnosis-collect.json`,且 Agent 改坏了 `campaigns` / `geographic` / `keywords` 的 `items`(缺 `title`/`currentCost` 或环比写成字符串)或整体覆盖丢弃了 `landingPageAnalysis.desktop`/`mobile`,CLI **自动从 collect.reportData 恢复**,保留 Agent 的 `analysis`/`suggestions`。可用 `--no-merge-collect` 关闭;`--collect <file>` 指定 collect 路径。
|
|
71
|
-
- **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages`
|
|
71
|
+
- **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages` 与事实字段矛盾,或出现「否词相关 / 着陆页测速缺失」禁写项、预算/创意建议千篇一律、§07 写成关键词洞察时同样 **exit 1**。
|
|
72
72
|
|
|
73
73
|
- **禁止**在 `collect` 阶段生成或写入 `analysis` / `suggestions` / `diagnosisOverview` / `summary` 等建议性文案。
|
|
74
74
|
- **禁止**跳过 Agent 直接 `render` collect 产物(`render` 会校验全部叙事 / 建议字段;调试可加 `--lenient`)。
|
|
@@ -144,7 +144,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
144
144
|
- 结论涉及「转化跟踪/GA 关联」→ 核对 `goldAccount.gaConfigured` / `goldAccount.conversionTrackingQualified`(按第 4 条 `true`=已达标)。
|
|
145
145
|
- 结论涉及「着陆页测速/性能」→ 先看 `landingPageAnalysis.source`:`api` 才可用 desktop/mobile 的 score/FCP;`simple` 只能写简易诊断信号(`simpleDiagnosis`),**禁止**把 fetchMs 当 FCP 或编造性能指数;`none` 写「数据未获取」。
|
|
146
146
|
- **禁止写入 keyIssues / disadvantages(render 硬拦截)**:
|
|
147
|
-
- 「否定关键词数量为 0 /
|
|
147
|
+
- 「否定关键词数量为 0 / 缺少否词过滤」——本报告 **collect 未拉取否词数据**,结构表与黄金账户**不展示否词项**;禁止据此下结论。有搜索词浪费时仅在 §08 按具体搜索词写。
|
|
148
148
|
- 「着陆页性能数据缺失 / 无法评估加载速度」——测速未获取是采集降级,**不是**投放核心问题;只在 §07 `analysis` 说明即可。
|
|
149
149
|
- `render` 会对已知矛盾与上述禁写模式做**硬校验**,命中直接 `exit 1`——须按提示改写,**禁止**删字段绕过。
|
|
150
150
|
|
|
@@ -243,10 +243,9 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
243
243
|
| 有效关键字 (Effective Keywords) | |
|
|
244
244
|
| 有效广告 (Effective Ads) | |
|
|
245
245
|
| 附加链接 (Sitelinks) | |
|
|
246
|
-
| 否定关键字 (Negative Keywords) | |
|
|
247
246
|
| 有效国家 (Effective Countries) | |
|
|
248
247
|
|
|
249
|
-
**对应字段**:`structure.campaignCount`、`adGroupCount`、`keywordCount`、`adCount`、`extensionCount`、`
|
|
248
|
+
**对应字段**:`structure.campaignCount`、`adGroupCount`、`keywordCount`、`adCount`、`extensionCount`、`countriesWithConversionsCount`(**不含**否词计数;collect 未拉否词)
|
|
250
249
|
|
|
251
250
|
### 3.3 指标检测
|
|
252
251
|
|
|
@@ -329,10 +328,11 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
329
328
|
| 附加链接 | | |
|
|
330
329
|
| 附加宣传信息 | | |
|
|
331
330
|
| 附加电话信息 | | |
|
|
332
|
-
| 否定词添加 | | |
|
|
333
331
|
| 受众群体设置 | | |
|
|
334
332
|
| 出价策略 | | |
|
|
335
333
|
|
|
334
|
+
> 黄金账户表**不含**「否定词添加」(`adsNegativeQualified`):collect 未拉取否词数据,render 会剥离该字段。
|
|
335
|
+
|
|
336
336
|
**得分**:`goldAccountScore`;**未达标项数**:若有 `goldAccountUnqualifiedCount` 可注明。
|
|
337
337
|
|
|
338
338
|
---
|
|
@@ -498,7 +498,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
498
498
|
### 12.1 核心问题总结
|
|
499
499
|
|
|
500
500
|
- `summary.keyIssues`:逐条列出(或写「暂无核心问题」)
|
|
501
|
-
-
|
|
501
|
+
- **不要写**:否词数量/缺少否词(本报告无否词数据);着陆页测速数据缺失(见撰写硬约束第 5 条)
|
|
502
502
|
|
|
503
503
|
### 12.2 优先级优化路线图
|
|
504
504
|
|
|
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
$PKG_NAME = 'siluzan-tso-cli'
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
$PKG_VERSION = '1.1.44-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.44-beta.3'
|
|
13
13
|
$CLI_BIN = 'siluzan-tso'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan TSO'
|
|
15
15
|
$INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
readonly PKG_NAME="siluzan-tso-cli"
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
readonly PKG_VERSION="1.1.44-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.44-beta.3"
|
|
13
13
|
readonly CLI_BIN="siluzan-tso"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan TSO"
|
|
15
15
|
readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
|