规划稿 v3

多用户商城前端设计方案

📅 2026-08-10 📱 三端:小程序 / H5 / APP(uni-app Vue3) 🧩 后端:本地 ThinkPHP 🔀 双系统分离

0. 本版核心决策

来自用户指令,作为后续一切设计的 spine:

① 商城前端 = 新建/重写,但只借鉴现有 uni-app 工程的写法风格,不照搬其业务实现。
② 所有请求 API 全部用新的(本地 ThinkPHP 后端),彻底弃用旧 jft.js 远程后端(test.sjslsd.com,成功码 code==0 + jwtToken + teamId 多租户)。
③ 商城接口与管理后台分离:商城只调 /api + /member,永不调 /admin、/merchant。

1. 现状盘点

层现状结论
工程根目录已是完整 uni-app(Vue3),manifest.json 配好三端复用工程,不新建
页面pages/mall 已注册约 65 个消费商城页面写法学这些页面的风格;多数仍绑旧后端
已切新后端goods/detail.vue、goods/catalog.vue 已用 API_BASE='127.0.0.1:8000' + /api/... + code!==200验证新范式可跑通,作范本
仍绑旧范式goods/cart.vue 仍用 jft.navigateTo + 远程 wlian-waterfalls + jft-mall-cart需重写为新请求层
后端-商城/api:商品/运费/下单/订单/支付;/member:登录/转账/提现公开购物闭环基本可用
后端-缺口购物车、收货地址、优惠券、收藏、钱包/积分、团队/消息后端需新补,前端才能接

1.1 后端路由实况

/api/goods/list         GET   商品目录(公开)
/api/goods/detail       GET   商品详情(公开)
/api/shipping/fee       POST  运费试算(公开)
/api/order/create       POST  下单(拆单,前端传 user_id)
/api/order/list         GET   订单列表(前端传 user_id)
/api/order/detail       GET   订单详情
/api/order/paid         POST  支付成功回调(演示)
/member/login       POST  会员登录(免密签发 token)—— 商城鉴权入口
/member/transfer/do POST  会员转账(MemberAuthMiddleware)
/member/withdraw/apply POST 会员提现申请(MemberAuthMiddleware)
⚠️ member 系统挂在 app 路由组下(无独立 member.php),商城前端统一调 /member/*。

2. 核心原则:写法学旧,API 用新

2.1 可借鉴的前端"写法"(与后端无关的纯前端约定)

Vue2 Options API(data/onLoad/methods) ColorUI:cu-btn bg-gradual-red cu-list menu / cu-item cu-tag bg-orange light cuIcon-back 等图标 jft-mall-spec 规格矩阵 jft-mall-cart 购物车行 uni-popup / uni-number-box / mp-html imgUrl() 图片拼接 uni.showToast 错误反馈

// 范本:Options API + imgUrl 助手
export default {
  data() { return { id: 0, list: [], loading: false } },
  onLoad(opts) { this.id = parseInt(opts.id || 0); this.load() },
  methods: {
    imgUrl(u) { return u && u.indexOf('http')===0 ? u : (API_BASE + u) },
    load() { /* ... */ }
  }
}

2.2 必须弃用的旧范式

旧写法问题替换
jft.request() 指向 test.sjslsd.com远程旧后端,与本系统无关common/mallRequest.js
成功码 code === 0本地后端成功是 code < 1000统一 code < 1000
jwtToken / teamId本地用 memberTokenmemberToken
每页硬编码 API_BASE散落、无法按环境切换config/env.js 集中
远程 wlian-waterfalls / jft.navigateTo绑定旧后端新列表组件 + uni.navigateTo

2.3 新的统一请求层(替换一切散落请求)

// config/env.js — 环境化基地址
let MALL_API_BASE = 'http://127.0.0.1:8000'
// #ifdef H5
MALL_API_BASE = (location.hostname==='localhost'||location.hostname==='127.0.0.1')
  ? 'http://127.0.0.1:8000' : 'https://mall.xshop.com'
// #endif
// #ifdef MP-WEIXIN / #ifdef APP-PLUS
MALL_API_BASE = 'https://mall.xshop.com'
export { MALL_API_BASE }

// common/mallRequest.js — Promise 化、统一约定
import { MALL_API_BASE } from '@/config/env.js'
export function mallRequest(url, method='GET', data={}) {
  return new Promise((resolve, reject) => {
    uni.request({
      url: MALL_API_BASE + url, method,
      data: method==='POST' ? JSON.stringify(data) : data,
      header: { 'Content-Type':'application/json',
        ...(getToken() ? { 'Authorization':'Bearer '+getToken() } : {}) },
      success: (res) => {
        const r = res.data || {}
        if (r.code < 1000) return resolve(r.data)        // 成功:直接返回 data
        if (r.code === 401) { toLogin(); return reject(r) } // 未登录跳登录
        uni.showToast({ title: r.msg||'请求失败', icon:'none' }); reject(r)
      },
      fail: () => { uni.showToast({title:'网络错误',icon:'none'}); reject({code:-1,msg:'网络错误'}) }
    })
  })
}
// common/memberAuth.js — 会员登录态(新 token 模型)
import { post } from '@/common/mallRequest.js'
export async function memberLogin(payload) {
  const data = await post('/member/login', payload) // {user_id} 或 {mobile}
  uni.setStorageSync('memberToken', data.token)
  uni.setStorageSync('userInfo', data)
  return data
}

2.4 页面改造示例(商品详情)

// 原:const API_BASE='http://127.0.0.1:8000'; uni.request({url:API_BASE+'/api/goods/detail',...})
// 新:
import { get } from '@/common/mallRequest.js'
const g = await get('/api/goods/detail', { id: this.id })
this.goods = g; this.buildAttrlist(g); this.initSkuinfo(g)
// 视觉/交互(ColorUI、jft-mall-spec、运费估算弹窗)完全保留,仅替换网络调用与去 IP 硬编码

3. 商城系统新 API 契约

3.1 已有(可直接接)

用途方法路径说明
商品目录GET/api/goods/list公开,分页/分类/关键词
商品详情GET/api/goods/detail含 SKU/店铺/供应商
运费试算POST/api/shipping/fee入参含 region_code
下单POST/api/order/create拆单;前端传 user_id
订单列表GET/api/order/list前端传 user_id
订单详情GET/api/order/detail
支付回调POST/api/order/paid演示
会员登录POST/member/login返回 token
转账/提现POST/member/transfer/do · /withdraw/apply需 memberToken

3.2 待后端新补(按优先级)

P0 购物车 /member/cart/* · 收货地址 /member/address/* · 我的订单(鉴权版)/member/order/* + 退款 /member/order/refund

P1 收藏 /member/favorite/* · 优惠券 /member/coupon/* · 钱包/积分 /member/wallet /member/points · 个人资料 /member/profile/*

P2 团队/邀请 /member/team /member/invite/qrcode · 消息 /member/message/* · 交易/分红 /member/dividend /member/transaction · 拼团 / 快捷支付 / 权益

4. 商城与后台的分离边界

维度商城系统(C 端)管理后台系统
前端uni-app(pages/mall)admin-web(Vue3+Vite)
API 网关/api + /member/admin + /merchant
鉴权memberTokenAuthMiddleware / MerchantAuthMiddleware
请求工具mallRequest.js + MALL_API_BASErequest.js + 管理网关
部署独立域名 mall.xshop.com独立域名 admin.xshop.com
跨系统一律走后端内部 service,前端不互相调
dev:mall 直连 127.0.0.1:8000;admin-web 经 vite 代理到同后端不同路由组。prod:Nginx/APISIX 按域名分流到同一 ThinkPHP 应用的不同路由组,可独立限流/灰度/扩容。

5. 分阶段落地计划

阶段 1 — MVP 购物闭环(写法学旧 + API 用新)⭐ 推荐起点

阶段 2 — 用户中心

我的、收藏、优惠券、钱包/积分、个人资料(接 P1)

阶段 3 — 高级业务

团队邀请、消息、交易/分红、拼团、快捷支付、权益(接 P2)

6. 需评审拍板的两点

已决定 会员登录方式(2026-08-10):先采用本地后端,直接使用 /member/login 免密垫片(凭 user_id/mobile 签发 memberToken),暂不接微信授权 / 远程会员网关。memberAuth.js 按免密实现,预留 code 换 token 分支供后续接入。理由:用户明确"远程后端先采用本地的"。

问题 2 订单鉴权升级:是否将 /api/order/* 从"前端传 user_id"升级为"按 memberToken 取 user_id"(更安全)?涉及后端小改。

7. 风险与对策

风险对策
旧范式残留:多数页面仍绑 jft/远程组件以 detail/catalog 为范本,全局 grep jft. 逐页改造
后端缺口阻塞前端(购物车/地址无接口)阶段 1 先约定 P0 契约并 mock,再联调
H5 跨域prod 网关转发;dev 本地代理;新接口挂 CorsMiddleware
三端差异(小程序需 https 合法域名等)env.js 条件编译 + 白名单配置