卷
VAN-CONVERSION-ESTIMATOR 2026

FEEL豊橋(爱知县丰桥市)

商用车改装经销商官网重构与在线报价器

为 FEEL豊橋 重做官网:SolidStart 访客端、Nuxt CMS、抓取用 cron 三个 Worker 共享一个 D1。61,386 行代码、1,033 个测试,报价器覆盖 114 个价格点。

商用车改装经销商官网重构与在线报价器

概要

FEEL豊橋 是爱知县丰桥市的丰田 HIACE / 日产 CARAVAN 改装专门店。旧站建在 Wix 上,首屏三秒以上,且没有任何在线报价能力。新站从设计到上线由我一人完成,首屏压到一秒以内。

选型分两端:访客端用 SolidStart 做服务端渲染,运营端用 Nuxt 做 CMS,两者都跑在 Cloudflare Workers 上,共享同一个 D1。整体是 Turborepo 单仓,报价逻辑抽成独立包给两端复用。

代码规模 61,386 行 TS/TSX/Vue(生产 48,110、测试 13,276)
自动化测试 1,033 个用例 / 109 个测试文件
首屏加载 3 秒以上 → 1 秒以内(对比旧 Wix 站)

核心功能:新车改装报价模拟器

报价器覆盖 13 种官方车体规格与 23 个改装 plan,交叉出 114 个可报价价格点,每个价格点挂载各自适用的选装。49 个选装分 8 组,单选组与多选组语义不同,全部组合约 8.6×10¹⁰ 种。

配置全部存在 D1,由 CMS 表单维护。运营能改车型、价格、选装和适用范围,但看不到 JSON,也写不了规则表达式。需要新的关系类型时,由我在引擎里加一种,再配一套业务语言的表单。

可报价价格点 114 个(13 车体规格 × 23 改装 plan 交叉)
选装适用关系 2,837 条(49 个选装分 8 组)
LIVE 可以直接操作
报价器交互演示:选车体规格,选驱动方式与燃料,选改装 plan,勾选选装,总额实时更新;条件不满足的选装保持可见并禁用,附上日文理由。

架构设计

三个 Worker 共享同一个 D1。访客站以只读为主,写路径只有问询提交和「気になる」计数两条;CMS 全量读写;抓取 YouTube 与 Instagram 的 cron Worker 每六小时跑一次。

cron Worker 是唯一接触第三方 API 的进程,第三方凭据也只配在它身上,访客站和 CMS 都拿不到。抓取结果写成 D1 快照,失败时只记错误不覆盖旧数据,首页继续显示上一次成功的内容。

三个 Worker 共享同一个 D1 的部署结构与数据流向
三个 Worker 共享同一个 D1 的部署结构与数据流向

技术难点

级联失效与定点迭代

取消一个选装,会让依赖它的选装失效,而这些失效又可能带走下一层。规则引擎用 while-changed 循环反复扫描选中集合,直到一轮扫描不再产生变化才停下,单趟遍历会留下悬空的选中项。

引擎是零运行时依赖的纯函数包,不认识 DOM、框架和数据库,所以访客端和 CMS 预览共用同一份判断,也能直接单元测试。金额相关的逻辑一律照这个方式抽离。

传输层的字典化压缩

嵌套结构会把选装目录在每个价格点里各嵌一份,114 个价格点合计 2,837 条适用关系,同一份选项定义被反复序列化。服务端改发顶层字典加 id 引用,客户端一次性还原,引擎和界面都不用改。

保存时拦截依赖环

运营若配出 A 需要 B、B 又需要 A,两个选装在前台会永远选不上。CMS 在写库前用三色标记做深度优先搜索,发现环就拒绝保存,并把 id 路径翻译成选装名称提示运营。

同一道检查还拦另外两种死配置:依赖目标落在同一个单选组里,以及依赖目标不在该价格点的适用选装内。两种情况都会让选装在前台显示却永远点不动。

其他判断

  • 报价结果不落库。分享链接只带价格点 id 和选装 id,服务端从 D1 重算并重新过一遍规则引擎,手改 URL 凑不出非法组合来抬高总额
  • 条件不满足的选装保持可见并禁用,标注「要◯◯」「◯◯と併用不可」,让客户看得到车型之间的差异
  • 见积书 PDF 在浏览器端生成,jsPDF 只在点击时动态引入,不进 SSR 产物和主 bundle
  • 报价配置读多写少,服务端结果走边缘缓存,TTL 五分钟
  • 涉及 D1 的测试跑在真实 workerd 里,对真实 migration 建库,不 mock 数据库
访客端报价模拟器:分步收敛的选择流程与实时更新的金额面板
访客端报价模拟器:分步收敛的选择流程与实时更新的金额面板
CMS 选装配置界面:依赖关系以业务文案呈现,运营接触不到 JSON 与规则表达式
CMS 选装配置界面:依赖关系以业务文案呈现,运营接触不到 JSON 与规则表达式
上线站点