报告:硬编码根因 · A 端可配置化 · 全局间距令牌

编制:小齐 日期:2026-09-23 状态:已验部分均附可复跑命令;方案部分待刘总拍板
触发:刘总三问——①为什么有硬编码?所有内容要求 A 端可配置 ②写出报告 ③走全局令牌

0. 结论先行

#结论性质
1硬编码不是谁写错的,是 v2 工程以"静态原型快照"身份入仓时自带的——2026-09-14 8d7dc69e(冈子首入仓快照)就已包含这些金额与电话已验(git 追溯)
2真正的根因是"前端没有数据层":玩法页、我的页的 .ts 零接口请求,页面内容全部写死在模板里;A 端已有内容配置能力,但 C 端从未消费已验(grep 计数)
3全站硬编码金额 47 处(不是此前报告的 5 处),另有 mock-pkg-1/2 的 mock 数组仍躺在 home.ts已验(全量 grep)
4间距令牌早已存在(--space-1~--space-6),问题是档位只有 6 档、覆盖不足,四页各写下 11–16 个越界值已验(脚本比对)
5因此"走全局令牌"的正确做法不是新建令牌,而是补齐档位 + 强制消费 + 加校验闸门方案
6🔴 铁律(刘总 2026-09-23 02:56 二次强调,非可选项、不需再讨论):所有业务数据一律 A 端配置,C 端禁止写死任何业务数据——金额、电话、营业时间、文案、图片、状态、排序、入口清单全部走配置;页面只负责渲染配置值,取不到就显示中性占位「—」或直接隐藏该字段,绝不允许写死兜底数字。数据由运营在 A 端录入与更新,不需要刘总提供、不需要研发在代码里填🔴 铁律
⚠️ 自纠:本报告初稿把"A 端可配置"列进了「待刘总拍板」,并询问"真实数据由谁提供"——这是把铁律降级成了选项,理解错误。已按铁律改写:它不是待办项,是执行前提;需要刘总决定的只剩"派谁做后端接口",不是"要不要做"。

1. 为什么会有硬编码(根因链,四层)

第一层:工程来历——静态原型整包入仓

git log -S '¥80–160' --oneline -- miniprogram-v2/pages/selection/selection.wxml
git log -S '08978888216' --oneline -- miniprogram-v2/pages/local/local.wxml
git log -S '¥680–980'  --oneline -- miniprogram-v2/pages/local/local.wxml

三条全部指向同一个提交:8d7dc69e(2026-09-14,署名冈子)——「首入仓快照:新版 C 端工程完整入库,pages×92 + components/services/styles/utils,2.9M/406 文件」。

也就是说:这些金额、电话、文案从进仓库的第一天起就写死在页面模板里,不是某次改动引入的缺陷。v2 工程当时是把可运行的前端原型整包搬进来,原型里的数据就是写死的。

第二层:页面至今没有数据层(这是关键)

for p in selection local profile home; do
  printf "%-10s 接口请求命中=%s\n" $p \
    $(grep -acE "request\(|/api/|wx\.request" pages/$p/$p.ts); done

实测结果:

页面接口请求命中数含义
玩法 selection0纯静态,内容全写死在 wxml
在地 local1仅一处
我的 profile0纯静态入口清单
首页 home5已接真实数据(本轮整改后)

玩法页和我的页从未接过后端的任何数据。所以即便 A 端配置了内容,这两个页面也读不到——它们压根不发请求。

第三层:A 端能力已经存在,但 C 端没接

C 端现有的读取口只有两个(backend/app/routers/feed_demand.py):

即:A 端能配 POI/路线/攻略/规则,但 C 端没有通用的"读取已配置内容"接口,前端页面也没消费它。 配置与展示之间是断的。

第四层:没有"内容必须可配"的纪律约束

此前的验收口径查的是:视觉规范、路由白名单、文案键覆盖、数据真假(禁 mock)。从来没有人查过"这个数字是不是写在代码里的"。所以硬编码一直合规地活着。


2. 全站硬编码清单(实测)

2.1 金额(47 处,9 个文件)

grep -raoE "¥[0-9]+" --include="*.wxml" --include="*.ts" . | wc -l
文件处数说明
pages/joint-payment/joint-payment.wxml13合单支付
utils/texts.ts11文案库里也写着金额
pages/coupons/coupons.wxml6优惠券
pages/selection/selection.wxml4玩法页四张卡
pages/order-refund-preview/*.wxml4退款预览
pages/hotel-booking/hotel-booking.wxml4酒店预订
pages/home/home.ts2mock 数组,见下
pages/guide-detail/guide-detail.wxml2向导详情
pages/local/local.wxml1在地页服务卡

2.2 🔴 mock 数据仍在首页(违反禁 mock 红线)

pages/home/home.ts 第 25、27 行:

{ slug: 'mock-pkg-1', ..., priceText: '¥3680 起/人', ... }
{ slug: 'mock-pkg-2', ..., priceText: '¥1980 起/人', ... }

变量直白命名为 mock-pkg-*。上一轮整改我删掉了首页的推荐区块 UI,但数据和请求逻辑仍在(孤儿代码)。这属于我自己留下的尾巴,本次一并报出。

2.3 电话(4 处)

grep -raoE "tel:[0-9]+" --include="*.wxml" .
位置号码判断
pages/emergency-contacts110 / 120合理,公共紧急号码,不是业务数据
pages/local/local.wxml0897…216 / 0897…308🔴 疑占位假号,全仓仅此一处,且是商户联系电话

3. A 端可配置:方案

3.1 目标口径

页面里出现的任何"会变的业务内容"——金额、联系方式、营业时间、服务项目、推荐语、状态文案——都必须能在 A 端改,改完即时生效,不需要改代码、不需要重新提审。

不变的部分(页面结构、图标、交互逻辑)继续写在代码里。

3.2 现有能力盘点(可直接复用,不必从零建)

能力状态缺口
A 端内容管理界面 ContentAssets.tsx✅ 已有(波波 02:27)攻略知识字段未定、返回空数组
A 端接口 /api/miniapp/admin/content/*✅ 实测可用只覆盖 POI/路线/攻略/规则四类
后端 admin_content.py✅ 已有—
C 端读取接口❌ 缺只有 private/guide 两个 feed,无通用内容接口
前端消费❌ 缺selection/profile 零请求
金额/联系方式的配置模型❌ 缺现有四类内容里没有"价格""电话"字段

3.3 建议的内容模型(增量最小)

在现有 admin_content 上扩一个通用内容项表 content_item:

字段说明
key内容键,如 selection.card.lake.price
typetext / money / phone / image / status
value值
source数据来源(谁提供的)
updated_at更新时间
statusactive / draft / expired
destination_id目的地(多租户隔离,沿用现有口径)

前端规则:

3.4 落地顺序(建议)

  1. 先定字段:金额、电话、营业时间三个类型先上(覆盖已发现的 47+2 处)
  2. 补 C 端读取接口:GET /api/miniapp/content/items?keys=...(批量取,减少弱网请求次数——高原场景重要)
  3. 前端改造:selection → local → 其余 7 个含金额的文件
  4. A 端录入数据:由运营在 A 端自行录入与更新,不由研发在代码里填,也不需要刘总提供数据
  5. 清 mock:删 home.ts 的 mock-pkg-*

前端不等待数据:取不到配置值就显示中性占位「—」或隐藏该字段。页面短期出现占位是正确表现而不是缺陷——真实数据由运营在 A 端补齐即可,不需要改代码、不需要重新提审。这正是"A 端可配置"要达到的效果。


4. 全局间距令牌:方案

4.1 现状(实测,不是猜测)

app.wxss:29 已定义:

--space-1: 8rpx; --space-2: 16rpx; --space-3: 24rpx;
--space-4: 32rpx; --space-5: 40rpx; --space-6: 48rpx;

只有 6 档。 而四页实际使用的间距值:

页面用到的不同数值落在令牌内越界值个数越界值举例
home165114,6,10,12,14,18,20,22,26,28,36
selection195144,6,12,14,18,20,22,28,34,44,56,68,100,200
local226162,4,6,10,12,14,18,20,22,26,30,44,52,56,100,200
profile204162,4,6,10,14,18,20,22,26,28,36,44,56,60,100,200

所以根因不是"页面乱写",是"令牌只有 6 档、不够用"——4rpx、6rpx、12rpx、20rpx 这些小档位根本没有令牌,页面只能硬写数字。

4.2 方案(三步)

第一步 · 补齐档位(在 app.wxss 扩充,不动 vi-tokens 的色彩体系):

--space-0:  4rpx;   /* 极紧凑:标签内距、图标间隙 */
--space-1:  8rpx;
--space-2: 12rpx;
--space-3: 16rpx;
--space-4: 20rpx;
--space-5: 24rpx;
--space-6: 32rpx;
--space-7: 40rpx;
--space-8: 48rpx;
--space-9: 56rpx;

另设两个语义令牌承接超大值(不要散在页面里):

--space-hero:  100rpx;   /* 首屏大留白 */
--space-shell: 200rpx;   /* 页面级容器 */

第二步 · 强制消费:四页 wxss 中 margin/padding 数值全部替换为 var(--space-*);100/200 这类归入语义令牌。

第三步 · 加校验闸门(防止回潮):新增脚本,扫出所有"写了具体 rpx 数字却没走令牌"的 margin/padding,越界即报错退出。

可复跑判据(改造完成后应全部成立):

# 期望:四页越界值均为 0
python3 - <<'PY'
import re
tok={4,8,12,16,20,24,32,40,48,56,100,200}
for p in ['home','selection','local','profile']:
    w=open(f'miniprogram-v2/pages/{p}/{p}.wxss',encoding='utf-8').read()
    out=sorted({int(v) for v in re.findall(r'(?:margin|padding)(?:-[a-z]+)?:\s*(?:var\(--[^)]*\)|([0-9]+)rpx)',w) if v})
    print(p,"越界:",[v for v in out if v not in tok])
PY
注:该判据脚本当前尚未落地,属方案;落地后需随闸门一起入库。

5. 三批落地(结合 gpt6 四页评审)

批次范围可量化判据归属
第一批 · 合规底线47 处金额 + 2 处占位电话 + home.ts 的 mock;状态字段补"来源+更新时间"金额 100% 有来源;无真实数据显示中性占位;未核验电话不得渲染为可拨打;grep -c "mock-pkg" = 0前端(我)+ 需刘总提供真实数据
第二批 · 全局令牌 + 跨页一致间距令牌补齐并强制消费;统一加载/空态/失败/过期四态与 Toast 语义四页越界间距值 = 0;四页状态文案一致(可 grep 校验)前端(我)
第三批 · 信息架构我的页 32 入口分组;需求广场唯一主入口;玩法↔在地的服务主次关系32 入口 100% 分组且命名统一;需求广场入口数 = 1前端(我),需先出方案

gpt6 明确建议不动的:首页的荒野感视觉、在地页的信任感表达、我的页的工具型布局——页面风格可以不统一,但字号、触控尺寸、色彩语义、间距令牌必须统一。


6. 六大盲区(gpt6 提出,涉后端与权限,超出前端域)

  1. 弱网与离线:已加载的安全说明、紧急联系人、行前清单应可离线查看并标注数据时间
  2. 低温 / 戴手套 / 身体不适:减少输入、避免小目标操作;身体自查结果应能引导"休息 / 补给 / 求助",但不得替代医疗判断
  3. SOS 误触与误用:需确认、取消、连点防护、无网提示;真正紧急时不能只依赖单一网络接口
  4. 电量与权限:定位关闭、电话不可用时的替代路径
  5. 隐私生命周期:轨迹、旅客档案、紧急联系人、我的客人——谁可见、存多久、怎么删(材料未涉及现有机制)
  6. 示例图信任:换实拍时不得让用户误判为实时路况;图片与服务状态必须分离

7. 待刘总拍板(3 项)

注:原第 2 项「A 端录入真实价格」已删除——按铁律,数据由运营在 A 端录入,不属待办。
#事项说明
1🔴 派单给后端(波波):补 C 端通用内容读取接口 + 配置模型扩「金额 / 电话 / 时间」字段与类型这是前端改造的前置依赖,属后端域,超出 v2 前端属主范围,需刘总派单。前端侧我可先做「空态兜底 + 清除硬编码」,接口到位后接线
2六大盲区(SOS 误触防护 / 弱网离线 / 隐私生命周期)是否纳入本轮?涉后端与权限,同样需派给后端
3间距令牌扩充到 10 档 + 2 语义档是否照此执行?影响全站 wxss,属全局改动;刘总点头后我立即开工(不依赖后端)

不依赖任何人、我可立即开工的:清 home.ts 的 mock → 全局间距令牌改造 → 三页硬编码改走配置占位(接口未到位前先渲染空态)。


8. 本次已验 / 未验声明

已验(均有可复跑命令,见正文):

未验(属方案,尚未落地):