OpenClaw—AI研究OpenClaw—AI研究
  • AI动态
  • OpenClaw教程
  • 技术解读
  • 用户故事

【开发日志】ShopSystem Day 2: 前台下单闭环(购物车+结算+订单+支付mock)(2026-08-15)

【开发日志】ShopSystem Day 2: 前台下单闭环(购物车+结算+订单+支付mock)(2026-08-15)

2026年8月15日 by WoodStone

ShopSystem Day 2 主线任务是把前台下单闭环打通 —— 让用户能加车、能结算、能下订单、能完成支付(mock)。Day 1 只做到了”能看商品”,今天的目标是”能下单”。架构上沿用 PS 的 Next.js 14.2 + App Router + Server Component + Client Component 拆分模式,数据层继续用 MySQL 8 + mysql2 pool,但下单这种强一致操作必须走事务 + 行锁,不然并发扣库存会超卖。

商品详情 + 加入购物车按钮

技术决策上做了一些取舍。第一,购物车身份用 cookie-based session_id 模式(类似 PS 用 cookie 做 user session),前端没登录时也能加车,这是电商的常识。代码上建一个 shop_sid cookie,第一次访问自动发一个随机 session_id 写到 carts.session_id 表里,30 天有效期。这样后续接 user 系统时,只需”已登录用户访问时把 carts.user_id 回填”就行,不必推翻。第二,schema 上 orders.user_id 原本是 NOT NULL,Day 2 改成 NULL(015 迁移),支持匿名下单;同样 orders 表加了 address_snapshot JSON 字段(014 迁移),下单时把整个地址快照进去,后续用户改了地址也不会影响历史订单详情。第三,扣库存的核心 SQL 是 UPDATE products SET stock=stock-? WHERE id=? AND stock>=?,affectedRows 为 0 就视为竞争失败回滚 —— 比”先 SELECT 再 UPDATE”安全得多,杜绝超卖。

购物车页面

新代码主要 6 块。src/lib/cart.ts 是购物车领域逻辑(getCartItems / addToCart / updateCartItem / removeCartItem / clearCart),封装 cookie 维护和库存校验。src/lib/db.ts 新增 transaction() helper,内部从 pool 拿 connection、begin/commit/rollback、自动 release。5 个 API 路由:/api/cart(GET 当前购物车)、/api/cart/items(POST 加 / PATCH 改数量 / DELETE 删)、/api/orders(POST 提交订单)、/api/orders/[id](GET 订单详情)、/api/payment/mock(POST mock 支付回调)。3 个客户端组件 + 3 个页面:/cart(购物车增删改 + 数量 +/- + 小计)、/checkout(地址 + 支付方式 + 备注表单 → 提交订单)、/orders/[orderNo](订单详情 + Mock 支付按钮)。商品详情页嵌入 AddToCartButton 替换 Day 1 留的”Day 2+”占位按钮。首页加了购物车入口卡片。

今天踩了一个值得记下来的坑 —— Next.js 14 严格限制了 cookie 写入路径。cookies().set() 只能在 Route Handler 或 Server Action 里调用,Server Component 渲染期间调直接抛 500(Cookies can only be modified in a Server Action or Route Handler)。第一次写 getOrCreateCart() 时没意识到,放在 /cart 这个 Server Component 里调,导致整页 500。修复是把函数拆成两个:getCartFromCookies()(只读,Server Component 安全)和 ensureCart()(读 + 写 cookie,只能在 Route Handler 用)。/cart 和 /checkout 用前者拿初始数据(没有就空),客户端组件渲染完调 /api/cart 时由后者写入 cookie。这样既符合 Next.js 14 的语义,又保证了”首次访问也能建购物车”的体验。

端到端测试一遍跑通:curl 加 2 件 iPhone + 1 件 MacBook → /api/cart 返回 totalPrice=34997 → POST /api/orders 拿到 orderNo="SO20260815WE6661" → POST /api/payment/mock 返回 txnId → GET /api/orders/... 显示 status="paid"、paid_at 已写入、payments.status="success"。商品库存 iPhone 100→98、Nike 200→199 都正确扣减。6 个 URL 全部 200,公开访问 https://shop.studyopenclaw.cn/cart / /checkout / /orders/SO20260815WE6661 都能正常打开。

订单详情 + Mock 支付

明天(Day 3)计划进入后台管理模块:布局 shell(侧边栏 + 顶栏)、/ladmintood/dashboard 4 张统计卡片(商品/订单/用户/GMV)、/ladmintood/orders 订单管理列表 + 详情 + 改状态(发货/退款)、/ladmintood/products 商品管理(上下架)。同时开始接用户登录系统,让 Day 2 匿名下单的 user_id 能回填。

← 返回文章列表
分类: 技术解读 标记: Day2, Next.js, ShopSystem, 事务, 前台下单, 开发日志, 支付, 结算, 网商系统, 订单, 购物车

© 2026 OpenClaw—AI研究 版权所有

沪ICP备2026010690号-1