Quotation SaaS (Cloudflare Workers 版)

注意: 这是 Cloudflare Workers 在线 SaaS 版(有多用户、Stripe 订阅、OAuth 登录)。本地离线单文件版见 hsdesign-quotation-tool

2026-05-24: Dashboard 改为离线版报价工具界面

架构变更

  • /dashboard 改为从 GitHub fetch HS_Design_Quotation.html + quote-app.js
  • Worker 实时补丁:移除密码门、注入 token 处理、添加 Logout
  • JS 通过独立 Worker 路由 /_app.js 加载(不内嵌,避免 HTML 解析冲突)
  • 登录后直接进入完整的报价编辑界面(可折叠侧边栏、报价编辑器、Export PDF)
  • 与离线版 GitHub 源文件解耦,互不影响

修复的 Bug

  • chkGate() 访问已移除的 #gate 元素导致 JS 崩溃 → 改为 window.load 事件直接初始化
  • printPDF() 函数内嵌的 </style></head><body> 标签被 HTML 解析器误判 → 改为外置 JS 加载

2026-05-24: Google OAuth + Dashboard 报价表单修复

Google OAuth 修复

  • 旧 Client ID 是 Desktop app 类型,不支援 Web redirect URI
  • 新建 Web application 类型 OAuth Client
  • 新 Client ID: 914687008998-1n6dr08qsi7qifs8uvcnqitgqogsqk9s
  • 新 Client Secret: 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
  • Authorized redirect URI: https://quotation.hsdesign.biz/auth/callback
  • Consent screen 已发布(Publish)
  • ⚠️ 旧 Client ID (...vkogt2m5...) 已废弃,不可再用

OAuth Cookie/SameSite 问题修复

  • 跨站 OAuth 流程中,浏览器会丢弃 SameSite=Lax 的 cookie
  • 改为:从 callback 重定向到 /dashboard?token=<JWT>(URL 传参)
  • Dashboard Worker handler 优先读取 url.searchParams.get("token")
  • Dashboard 前端 JavaScript 从 URL 读取 token 存入 localStorage
  • 双重保险:同时保留 Set-Cookie + SameSite=None; Secure

Dashboard 报价创建表单

  • 原 ”+ New Quotation” 按钮链接到 /dashboard(只是刷新页面)
  • 改为嵌入内联表单:点按钮展开 Project Name + Description 输入框
  • 通过 API POST /api/quotations 创建报价
  • 创建成功后自动刷新显示新报价

测试账号

2026-05-19: quotation-saas complete.md 进度同步

Stripe Webhook 已配置

  • Webhook ID: we_1TY5pT06BaZD1u5Pk2jQZsSs
  • Endpoint: https://quotation.hsdesign.biz/api/webhook/stripe
  • Events: checkout.session.completed + customer.subscription.deleted
  • Signing Secret: whsec_Dyw7ie99v14yiXZzvlqrzfrKoL5W714L
  • 付款闭环完成:用户订阅 → Stripe Checkout → 付款成功 → Webhook → 自动升级方案

Live API Keys(已确认)

  • Resend: re_aTz3KBN1_Axs3g6AzQ6usrRouYQnD39qF
  • Stripe Live Publishable: pk_live_51TY4cV17t9NNR8bppsjfIffp1W1orauplZT0o2KKvpoc1vlI152DJ2O4fTw3CRmlU1ZLox84c2kijEdNiLdRAumI00FXBSobcn

完整 Dashboard 上线

  • 时间问候语 + 方案徽章 + 4个统计卡 + 推荐码卡片
  • /api/referrals — 推荐统计
  • /api/email — 发送报价邮件(Resend)

调试方法改进

  • Bug 复现:清除浏览器数据(无痕),从 / 开始测试完整流程
  • 不要让用户研究 localStorage/DevTools — auth flow 本身就要正确工作

完整技术文档: [[quotation-saas-complete]](15KB,包含所有路径、API、D1 schema、部署方法)

当前 blocker: 无 — Stripe webhook 配置完成,付款闭环已打通

2026-05-22: Bug Fix — fmt() 导致 999+ 数字归零

问题: cost 和 sell 字段输入 >999 时自动归零 根因: fmt() 函数会在数字超过 999 时加逗号(如 1,000),而 type="number" 的 input 不接受逗号字符,浏览器将其视为无效值显示为 0

修复: 移除 cost/sell 字段的 fmt() 格式化,直接传入原始数字

  • f-cost: ${ct>0?ct:''}(之前是 fmt(ct)
  • f-sell: ${it.sell||it.sell===0?it.sell:''}(之前是 fmt(it.sell)

注意: fmt() 仍用于显示给小用户看的汇总数字(subtotal、total 等),只是不要再传给 type="number" input 的 value。