15 KiB
Design Document
Overview
本设计文档描述前端 API 接口调用重构的技术方案。核心目标是将分散在页面和组件中的接口调用统一收敛到 common/server/ 模块,实现接口集中管理、统一错误处理,并在改造过程中生成完整的 API 清单用于核对 C# 后端迁移完整性。
Architecture
整体架构
┌─────────────────────────────────────────────────────────────┐
│ Pages / Components │
│ (pages/shouye/*.vue, pages/user/*.vue, components/*.vue) │
└─────────────────────────────┬───────────────────────────────┘
│ import { funcName } from '@/common/server/xxx.js'
▼
┌─────────────────────────────────────────────────────────────┐
│ Server Modules │
│ common/server/ │
│ ├── auth.js (登录、注册、绑定) │
│ ├── user.js (用户信息、VIP) │
│ ├── goods.js (商品列表、详情、奖品) │
│ ├── order.js (订单、抽奖) │
│ ├── warehouse.js (仓库、回收、发货) │
│ ├── coupon.js (优惠券) │
│ ├── welfare.js (福利屋、签到、任务) │
│ ├── collection.js(收藏) │
│ ├── address.js (收货地址) - 已有 userAddress.js │
│ ├── config.js (系统配置) - 已有 │
│ ├── rank.js (排行榜) │
│ ├── invitation.js(邀请) │
│ ├── redeem.js (兑换码) │
│ └── pay.js (支付) │
└─────────────────────────────┬───────────────────────────────┘
│ RequestManager.get/post()
▼
┌─────────────────────────────────────────────────────────────┐
│ RequestManager │
│ common/request.js │
│ - 统一请求封装 │
│ - 签名机制 │
│ - 错误处理 │
│ - Content-Type: application/json │
└─────────────────────────────┬───────────────────────────────┘
│ HTTP Request
▼
┌─────────────────────────────────────────────────────────────┐
│ C# Backend API │
│ http://localhost:5238/api/* │
└─────────────────────────────────────────────────────────────┘
调用流程
sequenceDiagram
participant P as Page/Component
participant S as Server Module
participant R as RequestManager
participant B as Backend API
P->>S: import { getGoodsList } from '@/common/server/goods.js'
P->>S: await getGoodsList({ page: 1, type: 0 })
S->>R: RequestManager.post('/goods_list', data)
R->>R: 添加签名参数 (timestamp, nonce, sign)
R->>B: POST /api/goods_list (JSON)
B-->>R: { status: 1, data: {...} }
R-->>S: response
S->>S: 统一错误处理
S-->>P: 标准格式结果
Components and Interfaces
1. RequestManager (已有,需修改)
文件: honey_box/common/request.js
修改内容: POST 请求 Content-Type 改为 application/json
// 修改前
if (method.toUpperCase() == 'POST') {
header = {
'content-type': 'application/x-www-form-urlencoded',
// ...
}
}
// 修改后
if (method.toUpperCase() == 'POST') {
header = {
'content-type': 'application/json',
// ...
}
}
接口保持不变:
static get(url, data, showLoading)- GET 请求static post(url, data, showLoading)- POST 请求static getCache(url, data, showLoading)- 带缓存的 GET 请求
2. Server Module 标准结构
每个 Server Module 遵循统一的结构:
// common/server/xxx.js
import RequestManager from '../request';
/**
* 函数名使用语义化命名
* @param {Object} params 请求参数
* @returns {Promise<Object>} 标准响应格式
*/
export const getFunctionName = async (params = {}) => {
const res = await RequestManager.post('/api_endpoint', params);
return res;
};
// 如需数据处理
export const getProcessedData = async (params = {}) => {
const res = await RequestManager.post('/api_endpoint', params);
if (res.status === 1 && res.data) {
// 数据处理逻辑
return res.data;
}
return null;
};
3. Server Modules 详细设计
3.1 auth.js (认证模块)
// 微信登录
export const wxLogin = async (code, userInfo) => {...}
// 手机号登录
export const mobileLogin = async (mobile, code) => {...}
// 微信绑定手机号
export const bindMobileByWx = async (encryptedData, iv) => {...}
// 验证码绑定手机号
export const bindMobileByCode = async (mobile, code) => {...}
// 记录登录
export const recordLogin = async () => {...}
// 账号注销
export const logOff = async () => {...}
3.2 user.js (用户模块 - 扩展已有)
// 已有
export const getUserInfo = async () => {...}
// 新增
export const updateUserInfo = async (data) => {...}
export const getVipList = async () => {...}
export const getProfitMoney = async (page) => {...}
export const getProfitIntegral = async (page) => {...}
export const getProfitScore = async (page) => {...}
export const getProfitPay = async (page) => {...}
3.3 goods.js (商品模块)
// 商品列表
export const getGoodsList = async (params) => {...}
// 商品详情
export const getGoodsDetail = async (goodsId) => {...}
// 子奖品列表
export const getGoodsChildren = async (goodsId) => {...}
// 商品扩展配置
export const getGoodsExtend = async (goodsId) => {...}
// 箱号列表
export const getGoodsNumList = async (goodsId) => {...}
// 箱号详情
export const getGoodsNumDetail = async (goodsId, goodsNum) => {...}
// 奖品数量统计
export const getGoodsPrizeCount = async (goodsId) => {...}
// 奖品内容
export const getGoodsPrizeContent = async (goodsId, shangId) => {...}
// 中奖记录
export const getGoodsPrizeLogs = async (params) => {...}
3.4 order.js (订单模块 - 扩展已有)
// 一番赏金额计算
export const calcOrderMoney = async (params) => {...}
// 一番赏下单
export const createOrder = async (params) => {...}
// 无限赏金额计算
export const calcInfiniteOrderMoney = async (params) => {...}
// 无限赏下单
export const createInfiniteOrder = async (params) => {...}
// 商城金额计算
export const calcMallOrderMoney = async (params) => {...}
// 订单列表
export const getOrderList = async (page, pageSize) => {...}
// 订单详情
export const getOrderDetail = async (orderId) => {...}
// 抽奖结果
export const getPrizeOrderLog = async (orderId) => {...}
// 无限赏抽奖结果
export const getInfinitePrizeOrderLog = async (orderId) => {...}
// 道具卡抽奖
export const useItemCard = async (params) => {...}
3.5 warehouse.js (仓库模块)
// 仓库首页
export const getWarehouseIndex = async (params) => {...}
// 回收奖品
export const recoveryPrize = async (ids) => {...}
// 发货奖品
export const sendPrize = async (params) => {...}
// 确认发货
export const confirmSend = async (params) => {...}
// 发货记录
export const getSendRecord = async (page) => {...}
// 发货详情
export const getSendRecordDetail = async (id) => {...}
// 回收记录
export const getRecoveryRecord = async (page) => {...}
// 物流信息
export const getLogistics = async (orderId) => {...}
3.6 coupon.js (优惠券模块)
// 优惠券列表
export const getCouponList = async (params) => {...}
// 优惠券详情
export const getCouponDetail = async (couponId) => {...}
// 领取优惠券
export const receiveCoupon = async (couponId) => {...}
// 分享优惠券
export const shareCoupon = async (couponId) => {...}
// 合成优惠券
export const synthesisCoupon = async (ids) => {...}
// 计算合成
export const calcSynthesis = async (ids) => {...}
3.7 welfare.js (福利模块)
// 福利屋列表
export const getWelfareHouseList = async () => {...}
// 福利屋详情
export const getWelfareHouseDetail = async (goodsId) => {...}
// 福利屋下单
export const buyWelfareHouse = async (params) => {...}
// 签到信息
export const getSignInfo = async () => {...}
// 执行签到
export const doSign = async () => {...}
// 任务列表
export const getTaskList = async () => {...}
// 领取任务奖励
export const receiveTaskReward = async (taskId) => {...}
3.8 collection.js (收藏模块)
// 收藏列表
export const getCollectionList = async (page) => {...}
// 添加收藏
export const addCollection = async (goodsId) => {...}
// 取消收藏
export const cancelCollection = async (goodsId) => {...}
// 收藏状态
export const getCollectionStatus = async (goodsId) => {...}
3.9 rank.js (排行榜模块)
// 排行榜列表
export const getRankList = async (type, page) => {...}
3.10 invitation.js (邀请模块)
// 邀请信息
export const getInvitationInfo = async () => {...}
// 邀请记录
export const getInvitationRecord = async (page) => {...}
3.11 redeem.js (兑换码模块)
// 使用兑换码
export const useRedeemCode = async (code) => {...}
3.12 pay.js (支付模块)
// 微信支付
export const wxPay = async (orderId) => {...}
// 余额支付
export const balancePay = async (orderId) => {...}
// 充值
export const recharge = async (amount) => {...}
Data Models
标准响应格式
interface ApiResponse<T> {
status: number; // 1=成功, 0=失败, -1=未登录, -9=需绑定手机号
msg: string; // 提示信息
data: T; // 业务数据
}
interface PaginatedResponse<T> {
status: number;
msg: string;
data: {
data: T[]; // 列表数据
total: number; // 总数
currentPage: number;
lastPage: number;
};
}
状态码定义
| 状态码 | 含义 | 处理方式 |
|---|---|---|
| 1 | 成功 | 返回数据 |
| 0 | 业务失败 | 显示 msg 提示 |
| -1 | 未登录 | 跳转登录页 |
| -9 | 需绑定手机号 | 跳转绑定页 |
| 2222 | 特殊状态 | 返回数据 |
Correctness Properties
A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.
Property 1: POST 请求使用 JSON 格式
For any POST 请求通过 RequestManager 发送, 请求头的 Content-Type 应为 application/json
Validates: Requirements 1.1
Property 2: 签名机制一致性
For any 请求数据对象, 生成的签名应与原有算法保持一致:参数按键名排序 → 拼接为 key=value& 格式 → 添加密钥(host+timestamp) → MD5 加密
Validates: Requirements 1.2
Property 3: 响应格式一致性
For any API 响应, 返回格式应包含 status、msg、data 三个字段,且 status 为数字类型
Validates: Requirements 1.3
Property 4: 错误处理统一性
For any 接口调用返回 status !== 1 的响应, Server Module 应返回包含 status 和 msg 的标准格式对象
Validates: Requirements 2.3, 6.2
Error Handling
RequestManager 层错误处理
RequestManager 已实现以下错误处理逻辑(保持不变):
- 网络异常: 显示 "网络连接异常,请检查网络"
- status = 0: 显示 msg 提示
- status = -1: 清除 token,跳转登录页
- status = -9: 显示 msg,跳转绑定手机号页面
- 请求失败: 显示错误信息
Server Module 层错误处理
Server Module 不额外处理错误,直接返回 RequestManager 的响应:
export const getGoodsList = async (params) => {
// 直接返回,错误由 RequestManager 统一处理
return await RequestManager.post('/goods_list', params);
};
如需数据转换,在成功时处理:
export const getUserInfo = async () => {
const res = await RequestManager.post('/user');
if (res.status === 1 && res.data) {
// 数据处理
res.data.money = common.removeTrailingZeros(res.data.money);
return res.data;
}
return null;
};
Testing Strategy
单元测试
由于前端 UniApp 项目的特殊性,主要通过以下方式验证:
- 手动测试: 在开发环境使用 eruda 调试工具检查请求
- 接口测试: 使用 Postman/curl 验证接口响应格式
测试用例
| 测试项 | 预期结果 |
|---|---|
| POST 请求 Content-Type | application/json |
| 签名参数存在 | timestamp, nonce, sign |
| 成功响应格式 | { status: 1, msg: "...", data: {...} } |
| 错误响应处理 | 显示 msg 提示 |
| 未登录处理 | 跳转登录页 |
| 需绑定手机号处理 | 跳转绑定页 |
集成测试清单
按模块逐一测试:
- 认证模块: 登录、绑定手机号
- 用户模块: 获取用户信息、VIP 信息
- 商品模块: 商品列表、详情、奖品
- 订单模块: 下单、支付、抽奖结果
- 仓库模块: 回收、发货
- 优惠券模块: 列表、领取、合成
- 福利模块: 签到、任务
- 其他模块: 收藏、排行榜、邀请、兑换码