mirror of
https://gitee.com/liuxioabin/fengketrade.git
synced 2026-04-17 12:57:32 +08:00
1814 lines
54 KiB
Markdown
1814 lines
54 KiB
Markdown
# 建行生活H5商城完整技术实现方案
|
|
|
|
> 基于 FastAdmin + ThinkPHP 5.x + UniApp Vue3 + 建行生活开放平台
|
|
> 方案版本: v1.0
|
|
> 编制日期: 2025-01-16
|
|
|
|
## 📋 目录
|
|
|
|
- [1. 项目概述](#1-项目概述)
|
|
- [2. 技术架构设计](#2-技术架构设计)
|
|
- [3. 核心功能模块](#3-核心功能模块)
|
|
- [4. 数据库设计](#4-数据库设计)
|
|
- [5. 接口规范](#5-接口规范)
|
|
- [6. 安全机制](#6-安全机制)
|
|
- [7. 开发实施计划](#7-开发实施计划)
|
|
- [8. 测试方案](#8-测试方案)
|
|
- [9. 部署方案](#9-部署方案)
|
|
- [10. 风险评估与应对](#10-风险评估与应对)
|
|
|
|
---
|
|
|
|
## 1. 项目概述
|
|
|
|
### 1.1 项目背景
|
|
|
|
将现有的 FastAdmin + Shopro 商城系统对接到建行生活开放平台,实现:
|
|
- H5商城在建行生活APP内运行
|
|
- 使用建行支付完成交易
|
|
- 订单数据实时同步到建行平台
|
|
- 用户可在建行生活APP中查看订单
|
|
|
|
### 1.2 技术栈
|
|
|
|
| 层级 | 技术选型 | 版本要求 |
|
|
|------|---------|---------|
|
|
| 前端框架 | UniApp (Vue3) | 3.0+ |
|
|
| 后端框架 | FastAdmin (ThinkPHP 5.x) | 5.1+ |
|
|
| 数据库 | MySQL | 5.7+ |
|
|
| PHP版本 | PHP | 7.4+ |
|
|
| Node.js | Node.js | 14+ |
|
|
| 加密库 | OpenSSL | - |
|
|
|
|
### 1.3 已确认的建行参数
|
|
|
|
```yaml
|
|
服务方编号: YS44000098000600
|
|
商户代码: 105910100194086
|
|
商户柜台代码: 313368474
|
|
分行代码: 441000000
|
|
|
|
UAT测试环境: http://128.192.179.60/uat_new/tp_service/txCtrl/server
|
|
生产环境: https://yunbusiness.ccb.com/tp_service/txCtrl/server
|
|
|
|
核心接口:
|
|
- A3341TP01: 订单推送
|
|
- A3341TP02: 订单更新
|
|
- A3341TP03: 订单查询
|
|
- A3341TP04: 订单退款
|
|
```
|
|
|
|
### 1.4 关键文档依据
|
|
|
|
- ✅ `建行生活输入通讯报文v1.1.6【最新】.xlsx` - 接口参数规范
|
|
- ✅ `建行相关App服务方接入文档v2.20_20250725.html` - 接入流程
|
|
- ✅ `建行生活原生与h5交互规范接口1.3(新).html` - JSBridge规范
|
|
- ✅ `支付下单串示例.xlsx` - 支付签名验证
|
|
- ✅ `建行接口地址(真实版).md` - 接口地址确认
|
|
|
|
---
|
|
|
|
## 2. 技术架构设计
|
|
|
|
### 2.1 整体架构图
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ 建行生活APP │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ WebView容器 + JSBridge │ │
|
|
│ │ ┌────────────────────────────────────────────────┐ │ │
|
|
│ │ │ UniApp H5 商城前端 │ │ │
|
|
│ │ │ ┌──────────────────────────────────────────┐ │ │ │
|
|
│ │ │ │ pages/ │ sheep/ │ uni_modules│ │ │ │
|
|
│ │ │ │ - 商品页 │ - API封装 │ - JSBridge │ │ │ │
|
|
│ │ │ │ - 订单页 │ - 状态管理 │ 封装 │ │ │ │
|
|
│ │ │ │ - 支付页 │ - 工具函数 │ │ │ │ │
|
|
│ │ │ └──────────────────────────────────────────┘ │ │ │
|
|
│ │ └────────────────────────────────────────────────┘ │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
│
|
|
│ HTTPS API
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ FastAdmin + Shopro商城 (ThinkPHP 5.x) │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ addons/shopro/controller/ │ │
|
|
│ │ ├─ Ccblife.php (建行用户自动登录控制器) │ │
|
|
│ │ └─ Ccbpayment.php (建行支付控制器) │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ addons/shopro/library/ccblife/ │ │
|
|
│ │ ├─ CcbEncryption.php (加密解密核心类) │ │
|
|
│ │ ├─ CcbHttpClient.php (HTTP客户端类) │ │
|
|
│ │ ├─ CcbOrderService.php (订单服务类) │ │
|
|
│ │ └─ CcbPaymentService.php (支付服务类) │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ 数据库 │ │
|
|
│ │ ├─ fa_shopro_order (订单表-已有) │ │
|
|
│ │ ├─ fa_ccb_payment_log (建行支付日志-新增) │ │
|
|
│ │ └─ fa_ccb_sync_log (建行同步日志-新增) │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
│
|
|
│ HTTPS (加密报文)
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ 建行服务器 │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ 后台交易接口 │ │
|
|
│ │ ├─ A3341TP01 订单推送接口 │ │
|
|
│ │ ├─ A3341TP02 订单更新接口 │ │
|
|
│ │ ├─ A3341TP03 订单查询接口 │ │
|
|
│ │ └─ A3341TP04 订单退款接口 │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ 收银台 │ │
|
|
│ │ - 支付页面 │ │
|
|
│ │ - 支付结果回调 │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.2 数据流转图
|
|
|
|
```
|
|
[用户] → [建行APP] → [H5商城] → [FastAdmin] → [建行服务器]
|
|
↑ ↓ ↓ ↓
|
|
└─────[支付回调]────────┴───[订单推送]────[支付验证]
|
|
```
|
|
|
|
### 2.3 用户认证流程 (建行统一登录)
|
|
|
|
**重要说明:** 弃用商城原有的登录注册功能,完全使用建行的用户体系
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant User as 用户
|
|
participant CCBApp as 建行生活App
|
|
participant H5 as H5商城
|
|
participant Backend as FastAdmin后端
|
|
participant DB as 数据库
|
|
|
|
User->>CCBApp: 打开建行生活App
|
|
CCBApp->>H5: 跳转H5商城<br/>URL带参数: platform=ccblife&ccbParamSJ=xxx
|
|
H5->>H5: onLaunch检测环境<br/>识别为建行环境
|
|
H5->>CCBApp: 调用JSBridge getUserInfo()
|
|
CCBApp-->>H5: 返回用户信息<br/>{ccb_user_id, mobile, nickname, avatar}
|
|
H5->>Backend: POST /api/ccblife/autoLogin<br/>{"ccb_user_id": "xxx", ...}
|
|
Backend->>DB: SELECT * FROM fa_user<br/>WHERE ccb_user_id = 'xxx'
|
|
|
|
alt 用户已存在
|
|
DB-->>Backend: 返回用户记录
|
|
Backend->>DB: UPDATE fa_user<br/>SET logintime=now()
|
|
Backend-->>H5: 返回Token + 用户信息<br/>{is_new_user: false}
|
|
else 用户不存在 (首次登录)
|
|
Backend->>DB: INSERT INTO fa_user<br/>(ccb_user_id, username, mobile...)
|
|
DB-->>Backend: 用户创建成功
|
|
Backend-->>H5: 返回Token + 用户信息<br/>{is_new_user: true}
|
|
end
|
|
|
|
H5->>H5: 保存Token到localStorage
|
|
H5->>H5: 保存用户信息到Vuex/Pinia
|
|
H5-->>User: 登录成功,进入商城首页
|
|
|
|
Note over H5: 商城原有的登录注册页面<br/>在建行环境下隐藏/禁用
|
|
```
|
|
|
|
**关键实现点:**
|
|
|
|
1. **环境识别 (App.vue onLaunch):**
|
|
```javascript
|
|
// 检测是否在建行App中
|
|
const isInCCBApp = location.search.includes('platform=ccblife') ||
|
|
location.search.includes('platform=ccb');
|
|
|
|
if (isInCCBApp) {
|
|
// 自动调用建行登录
|
|
await this.ccbAutoLogin();
|
|
} else {
|
|
// 非建行环境,提示需要在建行App中打开
|
|
uni.showModal({
|
|
title: '提示',
|
|
content: '请在建行生活APP中打开',
|
|
showCancel: false
|
|
});
|
|
}
|
|
```
|
|
|
|
2. **自动登录方法:**
|
|
```javascript
|
|
async ccbAutoLogin() {
|
|
try {
|
|
// 1. 解析URL参数
|
|
const urlParams = new URLSearchParams(location.search);
|
|
const ccbParamSJ = urlParams.get('ccbParamSJ');
|
|
|
|
// 2. 调用JSBridge获取用户信息
|
|
const userInfo = await ccbBridge.getUserInfo();
|
|
|
|
// 3. 调用后端自动登录接口
|
|
const res = await uni.$u.http.post('/addons/shopro/ccblife/autoLogin', {
|
|
ccb_user_id: userInfo.userId, // 建行用户ID (必需)
|
|
ccb_param_sj: ccbParamSJ, // URL加密参数 (可选)
|
|
mobile: userInfo.mobile, // 手机号 (可选)
|
|
nickname: userInfo.nickname, // 昵称 (可选)
|
|
avatar: userInfo.avatar // 头像 (可选)
|
|
});
|
|
|
|
// 4. 保存Token
|
|
uni.setStorageSync('token', res.data.token);
|
|
|
|
// 5. 保存用户信息到Vuex
|
|
this.$store.commit('user/setUserInfo', res.data.userInfo);
|
|
|
|
// 6. 如果是新用户,可以引导
|
|
if (res.data.is_new_user) {
|
|
uni.showToast({ title: '欢迎来到商城', icon: 'success' });
|
|
}
|
|
} catch (error) {
|
|
console.error('建行自动登录失败:', error);
|
|
uni.showToast({ title: '登录失败', icon: 'none' });
|
|
}
|
|
}
|
|
```
|
|
|
|
3. **数据库用户表改造:**
|
|
```sql
|
|
ALTER TABLE `fa_user`
|
|
ADD COLUMN `ccb_user_id` varchar(50) DEFAULT NULL COMMENT '建行用户ID' AFTER `id`,
|
|
ADD UNIQUE KEY `uk_ccb_user_id` (`ccb_user_id`);
|
|
```
|
|
|
|
4. **商城原有登录注册页面处理:**
|
|
```javascript
|
|
// pages/user/login.vue
|
|
onLoad() {
|
|
// 检测是否在建行环境
|
|
if (this.$ccb.isInCCBApp()) {
|
|
uni.showModal({
|
|
title: '提示',
|
|
content: '您已通过建行账号登录,无需再次登录',
|
|
showCancel: false,
|
|
success: () => {
|
|
uni.reLaunch({ url: '/pages/index/index' });
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 非建行环境,显示原有登录页面 (如果需要支持)
|
|
// 或者直接提示用户在建行App中打开
|
|
}
|
|
```
|
|
|
|
### 2.4 关键技术点
|
|
|
|
#### 2.4.1 加密通讯机制
|
|
|
|
**请求加密流程:**
|
|
```
|
|
1. 构造原始JSON报文 (CLD_HEADER + CLD_BODY)
|
|
2. 使用建行平台公钥进行RSA加密
|
|
3. 对密文进行BASE64编码并去除换行符
|
|
4. 使用原始报文+服务方私钥生成MD5签名
|
|
5. 组装最终报文: {cnt: 密文, mac: 签名, svcid: 服务方编号}
|
|
```
|
|
|
|
**响应解密流程:**
|
|
```
|
|
1. 验证响应报文的MAC签名
|
|
2. 使用服务方私钥对cnt字段RSA解密
|
|
3. 解析JSON获取业务数据
|
|
4. 检查RET_CODE判断成功失败
|
|
```
|
|
|
|
#### 2.3.2 支付串生成机制
|
|
|
|
**支付串构造流程:**
|
|
```
|
|
1. 构造支付参数 (MERCHANTID, POSID, ORDERID, PAYMENT...)
|
|
2. 按参数名ASCII排序并拼接: key1=value1&key2=value2&...
|
|
3. 追加平台公钥: 参数串 + &PLATFORMPUB=xxx
|
|
4. 生成MD5签名: md5(参数串+平台公钥+服务方私钥)
|
|
5. RSA加密商户公钥并BASE64: ENCPUB
|
|
6. 组装最终支付串: 参数串 + &MAC=xxx + &PLATFORMID=xxx + &ENCPUB=xxx
|
|
```
|
|
|
|
**验证机制:**
|
|
根据 `支付下单串示例.xlsx`,已提供测试数据可验证签名算法正确性:
|
|
- 测试签名: `f07ef63236e3bbbc1dc221b06e631f3d`
|
|
|
|
#### 2.3.3 JSBridge交互机制
|
|
|
|
**调用格式:**
|
|
```javascript
|
|
window.CCBMofeBridge.exec(
|
|
"api分类", // baseAPI/userAPI/payAPI
|
|
"api名称", // getUserInfo/startPayment
|
|
JSON.stringify(params), // 参数JSON字符串
|
|
'callbackName' // 全局回调函数名
|
|
);
|
|
```
|
|
|
|
**响应格式:**
|
|
```javascript
|
|
{
|
|
"status": "0", // 0-成功, 1-失败, -1-取消, -2-未开通
|
|
"data": {
|
|
// 业务数据
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. 核心功能模块
|
|
|
|
### 3.1 模块划分
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 模块1: 用户认证模块 (使用建行统一登录) │
|
|
│ - 环境检测 (识别建行App环境) │
|
|
│ - 解析ccbParamSJ参数获取建行用户ID │
|
|
│ - JSBridge调用getUserInfo获取用户详细信息 │
|
|
│ - 建行用户与商城用户自动绑定/创建 │
|
|
│ - 弃用现有商城的登录注册功能 │
|
|
└─────────────────────────────────────────────────────────┘
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 模块2: 订单管理模块 │
|
|
│ - 订单创建 │
|
|
│ - 订单推送到建行 (A3341TP01) │
|
|
│ - 订单状态更新 (A3341TP02) │
|
|
│ - 订单查询 (A3341TP03) │
|
|
└─────────────────────────────────────────────────────────┘
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 模块3: 支付模块 │
|
|
│ - 支付串生成 │
|
|
│ - JSBridge调起支付 │
|
|
│ - 支付回调处理 │
|
|
│ - 支付结果验证 │
|
|
└─────────────────────────────────────────────────────────┘
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 模块4: 退款模块 │
|
|
│ - 退款申请 │
|
|
│ - 退款推送到建行 (A3341TP04) │
|
|
│ - 退款状态同步 │
|
|
└─────────────────────────────────────────────────────────┘
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 模块5: 加密通讯模块 │
|
|
│ - RSA加密/解密 │
|
|
│ - MD5签名/验签 │
|
|
│ - BASE64编码 │
|
|
│ - 报文构造与解析 │
|
|
└─────────────────────────────────────────────────────────┘
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 模块6: 日志与监控模块 │
|
|
│ - 支付日志记录 │
|
|
│ - 同步日志记录 │
|
|
│ - 异常监控与告警 │
|
|
│ - 数据对账 │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.2 核心类设计
|
|
|
|
#### 3.2.1 CcbEncryption 加密类
|
|
|
|
**文件路径:** `addons/shopro/library/ccblife/CcbEncryption.php`
|
|
|
|
**职责:**
|
|
- RSA加密与解密
|
|
- MD5签名生成与验证
|
|
- 报文构造与解析
|
|
- 交易流水号生成
|
|
|
|
**核心方法:**
|
|
|
|
| 方法名 | 参数 | 返回值 | 说明 |
|
|
|--------|------|--------|------|
|
|
| `rsaEncrypt($data)` | string $data | string | 使用建行平台公钥加密 |
|
|
| `rsaDecrypt($data)` | string $data | string | 使用服务方私钥解密 |
|
|
| `generateSign($data)` | string $data | string | 生成MD5签名 |
|
|
| `verifySign($data, $sign)` | string $data, string $sign | bool | 验证签名 |
|
|
| `buildEncryptedMessage($txCode, $bodyData)` | string $txCode, array $bodyData | array | 构造完整加密报文 |
|
|
| `parseResponse($response)` | string $response | array | 解析响应报文 |
|
|
| `generateTransSeq()` | - | string | 生成唯一交易流水号 |
|
|
|
|
**依赖:**
|
|
- PHP OpenSSL扩展
|
|
- 配置文件中的密钥信息
|
|
|
|
#### 3.2.2 CcbHttpClient HTTP客户端类
|
|
|
|
**文件路径:** `addons/shopro/library/ccblife/CcbHttpClient.php`
|
|
|
|
**职责:**
|
|
- 发送HTTP请求到建行
|
|
- 处理HTTP响应
|
|
- 失败重试机制
|
|
- 超时控制
|
|
|
|
**核心方法:**
|
|
|
|
| 方法名 | 参数 | 返回值 | 说明 |
|
|
|--------|------|--------|------|
|
|
| `request($txCode, $bodyData)` | string $txCode, array $bodyData | array | 发送请求并返回结果 |
|
|
| `post($url, $data, $headers)` | string $url, array $data, array $headers | string | 发送POST请求 |
|
|
| `parseResponse($response)` | string $response | array | 解析响应 |
|
|
| `retry($callable, $maxRetries)` | callable $callable, int $maxRetries | mixed | 重试机制 |
|
|
|
|
**关键配置:**
|
|
- 超时时间: 30秒
|
|
- 重试次数: 3次
|
|
- 重试间隔: 1秒、2秒、5秒
|
|
|
|
#### 3.2.3 CcbOrderService 订单服务类
|
|
|
|
**文件路径:** `addons/shopro/library/ccblife/CcbOrderService.php`
|
|
|
|
**职责:**
|
|
- 订单推送到建行
|
|
- 订单状态更新
|
|
- 订单查询
|
|
- 订单退款
|
|
|
|
**核心方法:**
|
|
|
|
| 方法名 | 参数 | 返回值 | 说明 |
|
|
|--------|------|--------|------|
|
|
| `pushOrder($orderData)` | array $orderData | array | 推送订单 (A3341TP01) |
|
|
| `updateOrder($orderId, $status)` | string $orderId, string $status | array | 更新订单状态 (A3341TP02) |
|
|
| `queryOrder($orderId)` | string $orderId | array | 查询订单 (A3341TP03) |
|
|
| `refundOrder($orderId, $amount, $reason)` | string $orderId, float $amount, string $reason | array | 订单退款 (A3341TP04) |
|
|
|
|
**订单推送必需字段 (根据通讯报文Excel):**
|
|
```php
|
|
[
|
|
'USER_ID' => '建行用户ID',
|
|
'ORDER_ID' => '订单号',
|
|
'ORDER_DT' => 'YmdHis格式时间',
|
|
'TOTAL_AMT' => '订单原金额',
|
|
'PAY_AMT' => '实际支付金额',
|
|
'DISCOUNT_AMT' => '优惠金额',
|
|
'ORDER_STATUS' => '0-待支付 1-已支付 2-已过期 3-失败 4-取消',
|
|
'REFUND_STATUS' => '0-无退款 1-申请 2-已退款 3-部分退款',
|
|
'MCT_NM' => '商户名称',
|
|
'CUS_ORDER_URL' => '订单详情URL',
|
|
'OCC_MCT_LOGO_URL' => '商户Logo URL',
|
|
'PAY_FLOW_ID' => '支付流水号 (对应ORDERID)',
|
|
'PAY_MRCH_ID' => '支付商户号',
|
|
'SKU_LIST' => '商品信息JSON',
|
|
// ... 其他字段
|
|
]
|
|
```
|
|
|
|
#### 3.2.4 CcbPaymentService 支付服务类
|
|
|
|
**文件路径:** `addons/shopro/library/ccblife/CcbPaymentService.php`
|
|
|
|
**职责:**
|
|
- 生成建行支付串
|
|
- 处理支付回调
|
|
- 验证支付结果
|
|
|
|
**核心方法:**
|
|
|
|
| 方法名 | 参数 | 返回值 | 说明 |
|
|
|--------|------|--------|------|
|
|
| `generatePaymentString($order)` | array $order | string | 生成支付串 |
|
|
| `handleCallback($callbackData)` | array $callbackData | array | 处理支付回调 |
|
|
| `verifyPayment($orderId)` | string $orderId | bool | 验证支付结果 |
|
|
|
|
**支付串必需参数 (根据支付下单串示例):**
|
|
```php
|
|
[
|
|
'MERCHANTID' => '商户代码',
|
|
'POSID' => '柜台代码',
|
|
'BRANCHID' => '分行代码',
|
|
'ORDERID' => '支付流水号 (唯一)',
|
|
'USER_ORDERID' => '用户订单号',
|
|
'PAYMENT' => '支付金额',
|
|
'CURCODE' => '01 (人民币)',
|
|
'TXCODE' => '520100',
|
|
'REMARK1' => '',
|
|
'REMARK2' => '服务方编号 (重要!)',
|
|
'TYPE' => '1',
|
|
'GATEWAY' => '0',
|
|
'CLIENTIP' => '客户端IP',
|
|
'THIRDAPPINFO' => 'comccbpay1234567890cloudmerchant',
|
|
'TIMEOUT' => 'YmdHis格式超时时间',
|
|
]
|
|
```
|
|
|
|
#### 3.2.5 ccb-bridge.js JSBridge封装
|
|
|
|
**文件路径:** `frontend/uni_modules/ccb-jsbridge/js_sdk/ccb-bridge.js`
|
|
|
|
**职责:**
|
|
- 封装JSBridge调用
|
|
- 环境检测
|
|
- Promise化异步调用
|
|
- 错误处理
|
|
|
|
**核心方法:**
|
|
|
|
| 方法名 | 参数 | 返回值 | 说明 |
|
|
|--------|------|--------|------|
|
|
| `checkEnvironment()` | - | boolean | 检测是否在建行APP中 |
|
|
| `exec(api, method, params)` | string api, string method, object params | Promise | 统一JSBridge调用 |
|
|
| `getUserInfo()` | - | Promise<object> | 获取用户信息 |
|
|
| `startPayment(paymentString, orderId)` | string paymentString, string orderId | Promise<object> | 调起支付 |
|
|
| `getLocation()` | - | Promise<object> | 获取地理位置 |
|
|
| `callCamera(options)` | object options | Promise<array> | 调用相机 |
|
|
|
|
**使用示例:**
|
|
```javascript
|
|
import ccbBridge from '@/uni_modules/ccb-jsbridge/js_sdk/ccb-bridge.js';
|
|
|
|
// 获取用户信息
|
|
const userInfo = await ccbBridge.getUserInfo();
|
|
|
|
// 调起支付
|
|
const result = await ccbBridge.startPayment(paymentString, orderId);
|
|
if (result.status === '0') {
|
|
// 支付成功
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 数据库设计
|
|
|
|
### 4.1 新增表结构
|
|
|
|
#### 4.1.1 建行支付日志表
|
|
|
|
```sql
|
|
CREATE TABLE `fa_ccb_payment_log` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
`order_id` varchar(50) NOT NULL COMMENT '商城订单ID',
|
|
`order_sn` varchar(50) NOT NULL COMMENT '商城订单号',
|
|
`pay_flow_id` varchar(50) NOT NULL COMMENT '支付流水号(对应建行ORDERID)',
|
|
`payment_string` text COMMENT '支付串',
|
|
`trans_id` varchar(100) DEFAULT NULL COMMENT '建行交易ID',
|
|
`user_id` int(11) DEFAULT NULL COMMENT '用户ID',
|
|
`ccb_user_id` varchar(30) DEFAULT NULL COMMENT '建行用户ID',
|
|
`amount` decimal(10,2) NOT NULL COMMENT '支付金额',
|
|
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-待支付 1-支付成功 2-支付失败 3-已取消',
|
|
`create_time` int(11) NOT NULL COMMENT '创建时间',
|
|
`pay_time` int(11) DEFAULT NULL COMMENT '支付时间',
|
|
`callback_data` text COMMENT '回调数据',
|
|
`error_msg` varchar(500) DEFAULT NULL COMMENT '错误信息',
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `pay_flow_id` (`pay_flow_id`),
|
|
KEY `order_id` (`order_id`),
|
|
KEY `order_sn` (`order_sn`),
|
|
KEY `trans_id` (`trans_id`),
|
|
KEY `status` (`status`),
|
|
KEY `create_time` (`create_time`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='建行支付日志表';
|
|
```
|
|
|
|
#### 4.1.2 建行订单同步日志表
|
|
|
|
```sql
|
|
CREATE TABLE `fa_ccb_sync_log` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
`order_id` varchar(50) NOT NULL COMMENT '商城订单ID',
|
|
`order_sn` varchar(50) NOT NULL COMMENT '商城订单号',
|
|
`tx_code` varchar(20) NOT NULL COMMENT '交易代码 A3341TP01/02/03/04',
|
|
`tx_seq` varchar(50) DEFAULT NULL COMMENT '交易流水号',
|
|
`request_data` text COMMENT '请求数据(加密前)',
|
|
`encrypted_data` text COMMENT '加密后数据',
|
|
`response_data` text COMMENT '响应数据',
|
|
`sync_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-失败 1-成功',
|
|
`sync_time` int(11) NOT NULL COMMENT '同步时间',
|
|
`retry_times` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
|
|
`error_msg` varchar(500) DEFAULT NULL COMMENT '错误信息',
|
|
`cost_time` int(11) DEFAULT NULL COMMENT '耗时(毫秒)',
|
|
PRIMARY KEY (`id`),
|
|
KEY `order_id` (`order_id`),
|
|
KEY `order_sn` (`order_sn`),
|
|
KEY `tx_code` (`tx_code`),
|
|
KEY `tx_seq` (`tx_seq`),
|
|
KEY `sync_status` (`sync_status`),
|
|
KEY `sync_time` (`sync_time`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='建行订单同步日志表';
|
|
```
|
|
|
|
### 4.2 已有表改造
|
|
|
|
#### 4.2.1 订单表字段新增
|
|
|
|
```sql
|
|
ALTER TABLE `fa_shopro_order`
|
|
ADD COLUMN `ccb_user_id` varchar(30) DEFAULT NULL COMMENT '建行用户ID' AFTER `user_id`,
|
|
ADD COLUMN `ccb_pay_flow_id` varchar(50) DEFAULT NULL COMMENT '建行支付流水号' AFTER `order_sn`,
|
|
ADD COLUMN `ccb_sync_status` tinyint(1) DEFAULT '0' COMMENT '建行同步状态 0-未同步 1-已同步 2-同步失败' AFTER `pay_status`,
|
|
ADD COLUMN `ccb_sync_time` int(11) DEFAULT NULL COMMENT '建行同步时间' AFTER `ccb_sync_status`,
|
|
ADD INDEX `idx_ccb_user_id` (`ccb_user_id`),
|
|
ADD INDEX `idx_ccb_pay_flow_id` (`ccb_pay_flow_id`),
|
|
ADD INDEX `idx_ccb_sync_status` (`ccb_sync_status`);
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 接口规范
|
|
|
|
### 5.1 前端调用后端接口
|
|
|
|
#### 5.1.1 建行用户自动登录接口 (替代原有登录注册)
|
|
|
|
**说明:**
|
|
- 弃用商城原有的登录注册功能
|
|
- H5在建行App内打开时,自动通过JSBridge获取建行用户信息
|
|
- 如果建行用户ID已存在则登录,不存在则自动创建商城用户并绑定
|
|
- 返回商城Token用于后续API调用
|
|
|
|
**请求:**
|
|
```http
|
|
POST /addons/shopro/ccblife/autoLogin
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"ccb_user_id": "建行用户ID (必需)",
|
|
"ccb_param_sj": "建行加密参数 (可选,来自URL参数)",
|
|
"mobile": "手机号 (可选,来自getUserInfo)",
|
|
"nickname": "昵称 (可选,来自getUserInfo)",
|
|
"avatar": "头像URL (可选,来自getUserInfo)"
|
|
}
|
|
```
|
|
|
|
**响应:**
|
|
```json
|
|
{
|
|
"code": 1,
|
|
"msg": "登录成功",
|
|
"data": {
|
|
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
|
|
"user_id": 123,
|
|
"is_new_user": false,
|
|
"userInfo": {
|
|
"id": 123,
|
|
"username": "user_ccb_xxx",
|
|
"nickname": "建行用户昵称",
|
|
"mobile": "138****0000",
|
|
"avatar": "https://...",
|
|
"ccb_user_id": "建行用户ID",
|
|
"create_time": "2025-01-16 12:00:00"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**业务逻辑:**
|
|
```
|
|
1. 接收ccb_user_id(必需)
|
|
2. 查询fa_user表中是否存在该ccb_user_id
|
|
3. 如果存在:
|
|
- 更新最后登录时间
|
|
- 生成新的Token
|
|
- 返回用户信息 (is_new_user=false)
|
|
4. 如果不存在:
|
|
- 创建新用户记录
|
|
- username: "user_ccb_" + ccb_user_id
|
|
- ccb_user_id: 建行用户ID
|
|
- mobile/nickname/avatar: 来自请求参数
|
|
- 生成Token
|
|
- 返回用户信息 (is_new_user=true)
|
|
```
|
|
|
|
#### 5.1.2 创建订单接口
|
|
|
|
**请求:**
|
|
```http
|
|
POST /addons/shopro/order/create
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"goods_list": [
|
|
{
|
|
"goods_id": 1,
|
|
"sku_id": 1,
|
|
"quantity": 2
|
|
}
|
|
],
|
|
"address_id": 1,
|
|
"remark": "备注"
|
|
}
|
|
```
|
|
|
|
**响应:**
|
|
```json
|
|
{
|
|
"code": 1,
|
|
"msg": "订单创建成功",
|
|
"data": {
|
|
"order_id": 123,
|
|
"order_sn": "ORD202501160001",
|
|
"pay_flow_id": "PAY20250116000112345678",
|
|
"total_amount": 100.00,
|
|
"pay_amount": 99.00
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 5.1.3 生成支付串接口
|
|
|
|
**请求:**
|
|
```http
|
|
POST /addons/shopro/ccbpayment/createPayment
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"order_id": 123
|
|
}
|
|
```
|
|
|
|
**响应:**
|
|
```json
|
|
{
|
|
"code": 1,
|
|
"msg": "支付串生成成功",
|
|
"data": {
|
|
"payment_string": "MERCHANTID=105910100194086&POSID=313368474&...",
|
|
"order_id": 123,
|
|
"pay_flow_id": "PAY20250116000112345678",
|
|
"amount": 99.00
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 5.1.4 支付回调接口
|
|
|
|
**请求:**
|
|
```http
|
|
POST /addons/shopro/ccbpayment/callback
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"order_id": 123,
|
|
"trans_id": "建行交易ID",
|
|
"pay_time": "20250116120000"
|
|
}
|
|
```
|
|
|
|
**响应:**
|
|
```json
|
|
{
|
|
"code": 1,
|
|
"msg": "支付成功",
|
|
"data": {
|
|
"order_id": 123,
|
|
"order_sn": "ORD202501160001",
|
|
"pay_status": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5.2 后端调用建行接口
|
|
|
|
#### 5.2.1 订单推送接口 (A3341TP01)
|
|
|
|
**请求URL:**
|
|
```
|
|
POST https://yunbusiness.ccb.com/tp_service/txCtrl/server?txcode=A3341TP01
|
|
Content-Type: application/json
|
|
```
|
|
|
|
**请求体 (加密前):**
|
|
```json
|
|
{
|
|
"CLD_HEADER": {
|
|
"CLD_TX_CHNL": "YS44000098000600",
|
|
"CLD_TX_TIME": "20250116120000",
|
|
"CLD_TX_CODE": "A3341TP01",
|
|
"CLD_TX_SEQ": "202501161200001234567890"
|
|
},
|
|
"CLD_BODY": {
|
|
"USER_ID": "建行用户ID",
|
|
"ORDER_ID": "ORD202501160001",
|
|
"ORDER_DT": "20250116120000",
|
|
"TOTAL_AMT": "100.00",
|
|
"PAY_AMT": "99.00",
|
|
"DISCOUNT_AMT": "1.00",
|
|
"ORDER_STATUS": "1",
|
|
"REFUND_STATUS": "0",
|
|
"MCT_NM": "商户名称",
|
|
"CUS_ORDER_URL": "https://your-domain.com/order/detail/123",
|
|
"OCC_MCT_LOGO_URL": "https://your-domain.com/logo.png",
|
|
"PAY_FLOW_ID": "PAY20250116000112345678",
|
|
"PAY_MRCH_ID": "105910100194086",
|
|
"SKU_LIST": "[{\"SKU_NAME\":\"商品名\",\"SKU_REF_PRICE\":100.00,\"SKU_NUM\":1,\"SKU_SELL_PRICE\":99.00}]"
|
|
}
|
|
}
|
|
```
|
|
|
|
**请求体 (加密后):**
|
|
```json
|
|
{
|
|
"cnt": "RSA加密后的BASE64字符串...",
|
|
"mac": "MD5签名32位小写",
|
|
"svcid": "YS44000098000600"
|
|
}
|
|
```
|
|
|
|
**响应体 (解密后):**
|
|
```json
|
|
{
|
|
"CLD_HEADER": {
|
|
"RET_CODE": "000000",
|
|
"RET_MSG": "成功"
|
|
},
|
|
"CLD_BODY": {
|
|
"CCB_DISCOUNT_AMT": "0.00",
|
|
"CCB_DISCOUNT_AMT_DESC": ""
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 5.2.2 订单更新接口 (A3341TP02)
|
|
|
|
**请求结构同A3341TP01,只是交易代码不同**
|
|
|
|
**CLD_BODY字段:**
|
|
```json
|
|
{
|
|
"USER_ID": "建行用户ID",
|
|
"ORDER_ID": "ORD202501160001",
|
|
"ORDER_STATUS": "1", // 更新后的状态
|
|
"REFUND_STATUS": "0",
|
|
"PAY_AMT": "99.00", // 如果状态变更涉及金额变化
|
|
// ... 其他需要更新的字段
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. 安全机制
|
|
|
|
### 6.1 加密安全
|
|
|
|
#### 6.1.1 密钥管理
|
|
|
|
**原则:**
|
|
- ✅ 私钥存储在环境变量 `.env` 中,不提交到代码仓库
|
|
- ✅ 生产环境使用密钥管理服务 (如 Vault)
|
|
- ✅ 定期轮换密钥 (建议每年一次)
|
|
- ✅ 密钥访问权限严格控制
|
|
|
|
**配置示例:**
|
|
```bash
|
|
# .env
|
|
CCB_PRIVATE_KEY="MIICdQIBADANBgkqhkiG9w0BAQ..."
|
|
CCB_PUBLIC_KEY="MIGfMA0GCSqGSIb3DQEBAQUAA4G..."
|
|
CCB_PLATFORM_PUBLIC_KEY="MIGfMA0GCSqGSIb3DQEBAQUAA4G..."
|
|
```
|
|
|
|
**读取方式:**
|
|
```php
|
|
$config = [
|
|
'private_key' => env('CCB_PRIVATE_KEY'),
|
|
'public_key' => env('CCB_PUBLIC_KEY'),
|
|
'platform_public_key' => env('CCB_PLATFORM_PUBLIC_KEY'),
|
|
];
|
|
```
|
|
|
|
#### 6.1.2 加密强度
|
|
|
|
- RSA密钥长度: 1024位 (建行要求)
|
|
- 签名算法: MD5 (建行要求)
|
|
- BASE64编码: 标准BASE64,去除换行符
|
|
|
|
#### 6.1.3 防重放攻击
|
|
|
|
**措施:**
|
|
- 交易流水号唯一性: `YmdHis + 微秒 + 随机数`
|
|
- 交易时间戳: 精确到秒
|
|
- 服务端验证流水号唯一性
|
|
- 请求有效期: 5分钟
|
|
|
|
### 6.2 接口安全
|
|
|
|
#### 6.2.1 HTTPS强制
|
|
|
|
- ✅ 生产环境强制HTTPS
|
|
- ✅ 证书有效期监控
|
|
- ✅ TLS 1.2+
|
|
|
|
#### 6.2.2 请求头验证
|
|
|
|
**必需请求头:**
|
|
```http
|
|
Accept: application/json
|
|
Content-Type: application/json
|
|
```
|
|
|
|
**缺少将导致404错误!**
|
|
|
|
#### 6.2.3 签名验证
|
|
|
|
**请求签名:**
|
|
```
|
|
MD5(原始报文JSON + 服务方私钥)
|
|
```
|
|
|
|
**响应验签:**
|
|
```
|
|
MD5(解密后JSON + 服务方私钥) === 响应中的mac
|
|
```
|
|
|
|
### 6.3 数据安全
|
|
|
|
#### 6.3.1 敏感信息脱敏
|
|
|
|
**日志记录规则:**
|
|
- ❌ 禁止记录完整密钥
|
|
- ❌ 禁止记录完整支付串
|
|
- ✅ 记录加密后的报文 (可用于排查)
|
|
- ✅ 手机号脱敏: 138****0000
|
|
- ✅ 身份证脱敏: 440***********1234
|
|
|
|
#### 6.3.2 SQL注入防护
|
|
|
|
**使用参数绑定:**
|
|
```php
|
|
// ❌ 错误示例
|
|
$sql = "SELECT * FROM order WHERE order_id = '{$orderId}'";
|
|
|
|
// ✅ 正确示例
|
|
$order = Db::name('order')->where('order_id', $orderId)->find();
|
|
```
|
|
|
|
#### 6.3.3 XSS防护
|
|
|
|
**前端输出转义:**
|
|
```javascript
|
|
// 使用Vue的自动转义
|
|
<div>{{ userInput }}</div>
|
|
|
|
// 不要使用v-html除非必要
|
|
```
|
|
|
|
---
|
|
|
|
## 7. 开发实施计划
|
|
|
|
### 7.1 总体时间规划
|
|
|
|
```
|
|
总工期: 18-23个工作日 (约4周)
|
|
|
|
第一周: 基础框架搭建 (5天)
|
|
第二周: 核心功能开发 (5天)
|
|
第三周: 业务集成与前端 (5天)
|
|
第四周: 测试与上线 (3-8天)
|
|
```
|
|
|
|
### 7.2 详细任务分解
|
|
|
|
#### Phase 1: 环境准备与基础框架 (Day 1-2)
|
|
|
|
**Day 1: 环境配置**
|
|
- [ ] 配置 `.env` 环境变量
|
|
- [ ] 创建数据库表 (fa_ccb_payment_log, fa_ccb_sync_log)
|
|
- [ ] 改造用户表和订单表 (新增建行相关字段)
|
|
- [ ] 创建Shopro插件目录结构
|
|
- `addons/shopro/library/ccblife/` - 核心类库
|
|
- `addons/shopro/controller/Ccblife.php` - 用户登录控制器
|
|
- `addons/shopro/controller/Ccbpayment.php` - 支付控制器
|
|
- [ ] 配置文件编写 (addons/shopro/config/ccblife.php)
|
|
|
|
**验收标准:**
|
|
- 数据库表创建成功
|
|
- 配置文件正确读取环境变量
|
|
- 目录结构符合规范
|
|
|
|
**Day 2: 核心加密模块**
|
|
- [ ] 实现 CcbEncryption.php (加密解密类)
|
|
- [ ] 单元测试: RSA加密解密
|
|
- [ ] 单元测试: MD5签名验证
|
|
- [ ] 单元测试: 报文构造
|
|
- [ ] 对比支付下单串示例验证签名正确性
|
|
|
|
**验收标准:**
|
|
- 生成的MD5签名与示例一致: `f07ef63236e3bbbc1dc221b06e631f3d`
|
|
- RSA加密解密往返成功
|
|
- 报文格式符合建行规范
|
|
|
|
#### Phase 2: HTTP通讯与接口封装 (Day 3-4)
|
|
|
|
**Day 3: HTTP客户端**
|
|
- [ ] 实现 CcbHttpClient.php
|
|
- [ ] 实现请求重试机制
|
|
- [ ] 实现超时控制
|
|
- [ ] 实现响应解析
|
|
- [ ] 单元测试: Mock建行接口测试
|
|
|
|
**验收标准:**
|
|
- 能够正确发送加密请求
|
|
- 能够正确解析响应
|
|
- 重试机制生效
|
|
- 超时正常工作
|
|
|
|
**Day 4: 订单与支付服务**
|
|
- [ ] 实现 CcbOrderService.php
|
|
- [ ] 实现 CcbPaymentService.php
|
|
- [ ] 实现订单推送方法 (A3341TP01)
|
|
- [ ] 实现订单更新方法 (A3341TP02)
|
|
- [ ] 实现支付串生成方法
|
|
- [ ] 单元测试: 各服务方法
|
|
|
|
**验收标准:**
|
|
- 订单推送报文格式正确
|
|
- 支付串生成符合规范
|
|
- 所有必需字段完整
|
|
|
|
#### Phase 3: 控制器与业务逻辑 (Day 5-7)
|
|
|
|
**Day 5: 后端控制器**
|
|
- [ ] 实现 addons/shopro/controller/Ccblife.php
|
|
- autoLogin() - 建行用户自动登录
|
|
- [ ] 实现 addons/shopro/controller/Ccbpayment.php
|
|
- createPayment() - 生成支付串
|
|
- callback() - 支付回调处理
|
|
- [ ] 实现用户自动登录接口 (替代原有登录注册)
|
|
- [ ] 实现生成支付串接口
|
|
- [ ] 实现支付回调接口
|
|
- [ ] 集成日志记录
|
|
|
|
**验收标准:**
|
|
- 所有接口响应格式统一
|
|
- 错误处理完善
|
|
- 日志记录完整
|
|
|
|
**Day 6-7: 订单流程集成**
|
|
- [ ] 订单创建后自动推送到建行
|
|
- [ ] 支付成功后更新订单状态并同步
|
|
- [ ] 退款流程对接
|
|
- [ ] 定时任务: 失败订单重试
|
|
- [ ] 定时任务: 订单状态对账
|
|
|
|
**验收标准:**
|
|
- 订单创建→推送→支付→同步 全流程打通
|
|
- 异常订单有重试机制
|
|
- 对账功能正常
|
|
|
|
#### Phase 4: 前端开发 (Day 8-10)
|
|
|
|
**Day 8: JSBridge封装**
|
|
- [ ] 实现 ccb-bridge.js
|
|
- [ ] 实现环境检测
|
|
- [ ] 实现getUserInfo方法
|
|
- [ ] 实现startPayment方法
|
|
- [ ] 实现getLocation方法
|
|
- [ ] 本地Mock测试
|
|
|
|
**验收标准:**
|
|
- JSBridge调用正常
|
|
- Promise化完成
|
|
- 错误处理完善
|
|
|
|
**Day 9: 支付页面开发**
|
|
- [ ] 实现 pages/payment/ccb-pay.vue
|
|
- [ ] 页面布局
|
|
- [ ] 支付逻辑实现
|
|
- [ ] 支付结果处理
|
|
- [ ] Loading状态
|
|
- [ ] 错误提示
|
|
|
|
**验收标准:**
|
|
- 页面UI符合设计
|
|
- 支付流程完整
|
|
- 异常处理完善
|
|
|
|
**Day 10: 订单页面适配**
|
|
- [ ] 订单列表适配建行环境
|
|
- [ ] 订单详情页适配
|
|
- [ ] 支付按钮跳转
|
|
- [ ] 订单状态展示
|
|
- [ ] App.vue初始化逻辑
|
|
|
|
**验收标准:**
|
|
- 建行环境下订单功能正常
|
|
- 非建行环境降级处理
|
|
- 用户体验流畅
|
|
|
|
#### Phase 5: 测试与修复 (Day 11-15)
|
|
|
|
**Day 11-12: 单元测试**
|
|
- [ ] 后端单元测试覆盖率>80%
|
|
- [ ] 加密模块测试
|
|
- [ ] 接口调用测试
|
|
- [ ] 边界条件测试
|
|
|
|
**Day 13-14: UAT环境联调**
|
|
- [ ] 订单推送接口联调
|
|
- [ ] 支付流程联调
|
|
- [ ] 订单更新接口联调
|
|
- [ ] 退款接口联调
|
|
- [ ] 异常场景测试
|
|
|
|
**Day 15: 性能与安全测试**
|
|
- [ ] 并发测试 (100笔/分钟)
|
|
- [ ] 压力测试
|
|
- [ ] 安全扫描
|
|
- [ ] 渗透测试
|
|
- [ ] 代码审查
|
|
|
|
**验收标准:**
|
|
- 所有接口联调成功
|
|
- 性能指标达标
|
|
- 无高危漏洞
|
|
- 代码质量合格
|
|
|
|
#### Phase 6: 上线部署 (Day 16-18)
|
|
|
|
**Day 16: 生产环境准备**
|
|
- [ ] 配置生产环境变量
|
|
- [ ] 配置正式接口地址
|
|
- [ ] 配置正式密钥
|
|
- [ ] 配置监控告警
|
|
- [ ] 准备应急预案
|
|
- [ ] 编写运维文档
|
|
|
|
**Day 17: 灰度发布**
|
|
- [ ] 1%用户灰度测试
|
|
- [ ] 监控支付成功率
|
|
- [ ] 监控订单同步率
|
|
- [ ] 监控接口响应时间
|
|
- [ ] 分析错误日志
|
|
|
|
**Day 18: 全量上线**
|
|
- [ ] 扩大到10%用户
|
|
- [ ] 扩大到50%用户
|
|
- [ ] 全量发布
|
|
- [ ] 持续监控
|
|
- [ ] 总结复盘
|
|
|
|
### 7.3 人力安排
|
|
|
|
| 角色 | 人数 | 职责 |
|
|
|------|------|------|
|
|
| 后端开发 | 1人 | PHP后端开发、接口对接 |
|
|
| 前端开发 | 1人 | UniApp前端开发、JSBridge封装 |
|
|
| 测试工程师 | 1人 | 测试用例编写、功能测试、接口测试 |
|
|
| 项目经理 | 1人 | 进度把控、风险管理、对外协调 |
|
|
|
|
---
|
|
|
|
## 8. 测试方案
|
|
|
|
### 8.1 测试环境
|
|
|
|
```
|
|
UAT环境:
|
|
- 接口地址: http://128.192.179.60/uat_new/tp_service/txCtrl/server
|
|
- 服务方编号: YS44000098000600
|
|
- 测试数据: 使用测试商户号和密钥
|
|
|
|
生产环境:
|
|
- 接口地址: https://yunbusiness.ccb.com/tp_service/txCtrl/server
|
|
- 服务方编号: YS44000098000600
|
|
- 真实交易: 小额测试后全量
|
|
```
|
|
|
|
### 8.2 测试用例
|
|
|
|
#### 8.2.1 功能测试用例
|
|
|
|
**用例1: 建行用户自动登录 (替代原有登录注册)**
|
|
```
|
|
前置条件: 在建行生活APP中打开H5
|
|
测试步骤:
|
|
1. H5加载完成,App.vue的onLaunch执行
|
|
2. 检测运行环境 (location.search是否包含platform=ccblife)
|
|
3. 解析URL参数获取ccbParamSJ
|
|
4. 调用JSBridge的getUserInfo()获取用户详细信息
|
|
5. 发送ccb_user_id等信息到后端 /addons/shopro/ccblife/autoLogin
|
|
6. 后端检查建行用户是否已存在:
|
|
- 存在: 更新登录时间,返回Token
|
|
- 不存在: 创建新用户,绑定ccb_user_id,返回Token
|
|
7. 前端保存Token到storage
|
|
8. 前端保存用户信息到Vuex/Pinia
|
|
|
|
预期结果:
|
|
- 环境检测正确 (isInCCBApp=true)
|
|
- 获取到ccb_user_id, mobile, nickname等信息
|
|
- 后端返回token
|
|
- 用户自动登录成功,无需注册
|
|
- 商城原有的登录注册页面被禁用
|
|
```
|
|
|
|
**用例2: 订单创建与推送**
|
|
```
|
|
前置条件: 用户已登录
|
|
测试步骤:
|
|
1. 选择商品加入购物车
|
|
2. 提交订单
|
|
3. 后端创建订单
|
|
4. 推送订单到建行 (A3341TP01)
|
|
|
|
预期结果:
|
|
- 订单创建成功
|
|
- 订单推送成功 (RET_CODE=000000)
|
|
- 数据库记录完整
|
|
- 同步日志记录
|
|
```
|
|
|
|
**用例3: 支付流程**
|
|
```
|
|
前置条件: 订单已创建并推送成功
|
|
测试步骤:
|
|
1. 点击支付按钮
|
|
2. 后端生成支付串
|
|
3. 前端调用startPayment
|
|
4. 建行收银台展示
|
|
5. 用户确认支付
|
|
6. 支付成功回调
|
|
|
|
预期结果:
|
|
- 支付串签名正确
|
|
- 收银台正常调起
|
|
- 支付成功
|
|
- 订单状态更新
|
|
- 推送订单状态到建行 (A3341TP02)
|
|
```
|
|
|
|
**用例4: 订单查询**
|
|
```
|
|
前置条件: 订单已支付
|
|
测试步骤:
|
|
1. 进入订单列表
|
|
2. 点击订单详情
|
|
3. 后端查询订单 (A3341TP03)
|
|
|
|
预期结果:
|
|
- 订单信息正确
|
|
- 建行侧数据一致
|
|
```
|
|
|
|
**用例5: 订单退款**
|
|
```
|
|
前置条件: 订单已支付
|
|
测试步骤:
|
|
1. 申请退款
|
|
2. 后端处理退款
|
|
3. 推送退款到建行 (A3341TP04)
|
|
4. 更新订单状态
|
|
|
|
预期结果:
|
|
- 退款成功
|
|
- 订单状态更新
|
|
- 建行侧数据同步
|
|
```
|
|
|
|
#### 8.2.2 异常场景测试
|
|
|
|
| 场景 | 测试方法 | 预期结果 |
|
|
|------|---------|---------|
|
|
| 网络超时 | 断网或延迟注入 | 触发重试机制,记录日志 |
|
|
| 签名错误 | 篡改签名 | 返回签名验证失败 |
|
|
| 订单重复推送 | 多次调用推送接口 | 检测重复,不重复推送 |
|
|
| 支付超时 | 用户长时间未支付 | 订单过期,状态正确 |
|
|
| 用户取消支付 | 在收银台取消 | 订单状态为待支付 |
|
|
| 建行接口异常 | Mock 500错误 | 重试机制生效,记录日志 |
|
|
| 金额不一致 | 前后端金额不同 | 校验失败,拒绝支付 |
|
|
|
|
#### 8.2.3 性能测试
|
|
|
|
**测试指标:**
|
|
```
|
|
支付并发: 100笔/分钟
|
|
订单推送: 200笔/分钟
|
|
接口响应: <3秒
|
|
成功率: >99%
|
|
```
|
|
|
|
**压测工具:**
|
|
- JMeter
|
|
- Locust
|
|
|
|
**压测场景:**
|
|
```
|
|
场景1: 100个用户同时下单支付
|
|
场景2: 1000笔订单批量推送
|
|
场景3: 持续压力测试30分钟
|
|
```
|
|
|
|
#### 8.2.4 安全测试
|
|
|
|
**测试项:**
|
|
- [ ] SQL注入测试
|
|
- [ ] XSS攻击测试
|
|
- [ ] CSRF防护测试
|
|
- [ ] 密钥泄露检测
|
|
- [ ] 接口鉴权测试
|
|
- [ ] 越权访问测试
|
|
- [ ] 重放攻击测试
|
|
|
|
**工具:**
|
|
- OWASP ZAP
|
|
- Burp Suite
|
|
- 代码扫描工具
|
|
|
|
---
|
|
|
|
## 9. 部署方案
|
|
|
|
### 9.1 服务器要求
|
|
|
|
**生产环境配置:**
|
|
```yaml
|
|
Web服务器:
|
|
- 类型: Nginx 1.18+
|
|
- 数量: 2台 (主备)
|
|
- CPU: 4核
|
|
- 内存: 8GB
|
|
- 硬盘: 100GB SSD
|
|
|
|
应用服务器:
|
|
- 类型: PHP-FPM 7.4+
|
|
- 进程数: 根据并发动态调整
|
|
- 超时: 60秒
|
|
|
|
数据库服务器:
|
|
- 类型: MySQL 5.7+
|
|
- CPU: 8核
|
|
- 内存: 16GB
|
|
- 硬盘: 500GB SSD
|
|
- 备份: 每日全量+实时binlog
|
|
```
|
|
|
|
### 9.2 部署步骤
|
|
|
|
#### 9.2.1 代码部署
|
|
|
|
```bash
|
|
# 1. 拉取代码
|
|
cd /www/wwwroot/fengketrade.com
|
|
git pull origin main
|
|
|
|
# 2. 安装依赖
|
|
composer install --no-dev --optimize-autoloader
|
|
|
|
# 前端构建 (如需)
|
|
cd frontend
|
|
npm run build:h5
|
|
|
|
# 3. 配置环境变量
|
|
cp .env.example .env
|
|
vi .env # 配置生产环境参数
|
|
|
|
# 4. 目录权限
|
|
chown -R www:www /www/wwwroot/fengketrade.com
|
|
chmod -R 755 runtime/ public/uploads/
|
|
|
|
# 5. 数据库迁移
|
|
php think migrate:run # 如有迁移脚本
|
|
|
|
# 6. 清除缓存
|
|
php think clear
|
|
php think optimize:config
|
|
|
|
# 7. 重启服务
|
|
systemctl reload php-fpm
|
|
systemctl reload nginx
|
|
```
|
|
|
|
#### 9.2.2 Nginx配置
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
listen 443 ssl http2;
|
|
server_name fengketrade.com;
|
|
|
|
ssl_certificate /path/to/cert.pem;
|
|
ssl_certificate_key /path/to/key.pem;
|
|
|
|
# HTTPS强制跳转
|
|
if ($scheme = http) {
|
|
return 301 https://$server_name$request_uri;
|
|
}
|
|
|
|
root /www/wwwroot/fengketrade.com/public;
|
|
index index.php index.html;
|
|
|
|
# FastAdmin路由
|
|
location / {
|
|
if (!-e $request_filename) {
|
|
rewrite ^(.*)$ /index.php?s=$1 last;
|
|
break;
|
|
}
|
|
}
|
|
|
|
# PHP处理
|
|
location ~ \.php$ {
|
|
fastcgi_pass unix:/var/run/php-fpm.sock;
|
|
fastcgi_index index.php;
|
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
include fastcgi_params;
|
|
|
|
# 增加超时时间
|
|
fastcgi_read_timeout 60s;
|
|
}
|
|
|
|
# 静态资源缓存
|
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
|
|
expires 30d;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
|
|
# 安全配置
|
|
location ~ /\.git {
|
|
deny all;
|
|
}
|
|
|
|
location ~ /\.env {
|
|
deny all;
|
|
}
|
|
|
|
# 日志
|
|
access_log /www/logs/fengketrade_access.log;
|
|
error_log /www/logs/fengketrade_error.log;
|
|
}
|
|
```
|
|
|
|
### 9.3 监控配置
|
|
|
|
#### 9.3.1 应用监控
|
|
|
|
**监控指标:**
|
|
```yaml
|
|
业务指标:
|
|
- 支付成功率
|
|
- 订单推送成功率
|
|
- 接口响应时间
|
|
- 错误率
|
|
|
|
系统指标:
|
|
- CPU使用率
|
|
- 内存使用率
|
|
- 磁盘IO
|
|
- 网络流量
|
|
```
|
|
|
|
**告警规则:**
|
|
```yaml
|
|
严重告警 (立即处理):
|
|
- 支付成功率 < 95%
|
|
- 订单推送失败 > 10笔/小时
|
|
- 系统错误率 > 5%
|
|
- 数据库连接失败
|
|
|
|
警告告警 (关注处理):
|
|
- 支付成功率 < 98%
|
|
- 接口响应时间 > 3秒
|
|
- CPU使用率 > 80%
|
|
- 磁盘使用率 > 80%
|
|
```
|
|
|
|
#### 9.3.2 日志收集
|
|
|
|
**日志级别:**
|
|
```
|
|
ERROR: 错误日志 (必须处理)
|
|
WARNING: 警告日志 (需要关注)
|
|
INFO: 信息日志 (常规记录)
|
|
DEBUG: 调试日志 (开发环境)
|
|
```
|
|
|
|
**日志内容:**
|
|
```php
|
|
// 订单推送日志
|
|
[2025-01-16 12:00:00] INFO 订单推送开始 order_id=123 tx_code=A3341TP01
|
|
[2025-01-16 12:00:01] DEBUG 请求数据 request={"USER_ID":"xxx"...}
|
|
[2025-01-16 12:00:02] INFO 订单推送成功 order_id=123 cost_time=1.2s
|
|
|
|
// 支付日志
|
|
[2025-01-16 12:05:00] INFO 支付串生成 order_id=123 amount=99.00
|
|
[2025-01-16 12:05:01] INFO 支付调起成功 pay_flow_id=PAYxxx
|
|
[2025-01-16 12:05:30] INFO 支付回调 status=success trans_id=xxx
|
|
```
|
|
|
|
### 9.4 备份方案
|
|
|
|
#### 9.4.1 数据库备份
|
|
|
|
```bash
|
|
# 每日全量备份 (凌晨2点)
|
|
0 2 * * * /usr/local/bin/mysql_backup.sh
|
|
|
|
# 备份脚本
|
|
#!/bin/bash
|
|
DATE=$(date +%Y%m%d)
|
|
BACKUP_DIR=/backup/mysql
|
|
mkdir -p $BACKUP_DIR
|
|
|
|
mysqldump -u root -p'password' \
|
|
--single-transaction \
|
|
--quick \
|
|
--lock-tables=false \
|
|
fengketrade > $BACKUP_DIR/fengketrade_$DATE.sql
|
|
|
|
# 压缩
|
|
gzip $BACKUP_DIR/fengketrade_$DATE.sql
|
|
|
|
# 删除7天前的备份
|
|
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
|
|
```
|
|
|
|
#### 9.4.2 代码备份
|
|
|
|
```bash
|
|
# 每次发布前打tag
|
|
git tag -a v1.0.0 -m "Release version 1.0.0"
|
|
git push origin v1.0.0
|
|
```
|
|
|
|
---
|
|
|
|
## 10. 风险评估与应对
|
|
|
|
### 10.1 技术风险
|
|
|
|
#### 风险1: 加密算法实现错误
|
|
|
|
**风险等级:** 高
|
|
**影响:** 无法与建行通讯,业务完全中断
|
|
**概率:** 中
|
|
|
|
**应对措施:**
|
|
- ✅ 使用支付下单串示例验证签名正确性
|
|
- ✅ 单元测试覆盖所有加密方法
|
|
- ✅ UAT环境充分测试
|
|
- ✅ 保留Java示例代码作为参考
|
|
|
|
**验证方式:**
|
|
```php
|
|
// 生成的签名必须与示例一致
|
|
$testSign = 'f07ef63236e3bbbc1dc221b06e631f3d';
|
|
$generatedSign = CcbEncryption::generateSign($testData);
|
|
assert($testSign === $generatedSign);
|
|
```
|
|
|
|
#### 风险2: 接口调用失败率高
|
|
|
|
**风险等级:** 高
|
|
**影响:** 订单推送失败,支付异常
|
|
**概率:** 中
|
|
|
|
**应对措施:**
|
|
- ✅ 实现失败重试机制 (最多3次)
|
|
- ✅ 实现异步队列,失败订单重推
|
|
- ✅ 实现定时对账功能
|
|
- ✅ 监控告警,及时发现问题
|
|
|
|
**重试策略:**
|
|
```
|
|
第1次失败: 立即重试
|
|
第2次失败: 1秒后重试
|
|
第3次失败: 5秒后重试
|
|
超过3次: 进入异常队列,人工处理
|
|
```
|
|
|
|
#### 风险3: JSBridge兼容性问题
|
|
|
|
**风险等级:** 中
|
|
**影响:** 部分功能无法使用
|
|
**概率:** 低
|
|
|
|
**应对措施:**
|
|
- ✅ 实现环境检测,非建行环境降级处理
|
|
- ✅ 充分测试iOS和Android
|
|
- ✅ 提供Mock方案用于本地调试
|
|
- ✅ 错误提示友好
|
|
|
|
**降级方案:**
|
|
```javascript
|
|
if (!ccbBridge.isInCcbLife) {
|
|
uni.showModal({
|
|
title: '提示',
|
|
content: '请在建行生活APP中打开',
|
|
confirmText: '前往下载',
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
// 跳转到建行生活下载页
|
|
}
|
|
}
|
|
});
|
|
}
|
|
```
|
|
|
|
### 10.2 业务风险
|
|
|
|
#### 风险4: 订单金额不一致
|
|
|
|
**风险等级:** 高
|
|
**影响:** 资金风险,财务对账异常
|
|
**概率:** 低
|
|
|
|
**应对措施:**
|
|
- ✅ 前后端双重金额校验
|
|
- ✅ 支付前再次校验订单金额
|
|
- ✅ 建行侧金额校验
|
|
- ✅ 定时对账发现差异
|
|
|
|
**校验逻辑:**
|
|
```php
|
|
// 后端生成支付串前校验
|
|
$orderAmount = $order['total_amount'];
|
|
$requestAmount = $request->post('amount');
|
|
if (bccomp($orderAmount, $requestAmount, 2) !== 0) {
|
|
throw new Exception('金额不一致');
|
|
}
|
|
|
|
// 支付回调后校验
|
|
$paidAmount = $callbackData['amount'];
|
|
if (bccomp($orderAmount, $paidAmount, 2) !== 0) {
|
|
// 异常告警
|
|
Log::error('支付金额不一致', [
|
|
'order_id' => $orderId,
|
|
'order_amount' => $orderAmount,
|
|
'paid_amount' => $paidAmount
|
|
]);
|
|
}
|
|
```
|
|
|
|
#### 风险5: 订单状态不同步
|
|
|
|
**风险等级:** 中
|
|
**影响:** 用户体验差,客诉增加
|
|
**概率:** 中
|
|
|
|
**应对措施:**
|
|
- ✅ 关键节点立即同步 (支付成功、退款)
|
|
- ✅ 定时任务兜底同步
|
|
- ✅ 提供手动同步功能
|
|
- ✅ 监控同步成功率
|
|
|
|
**同步策略:**
|
|
```
|
|
实时同步: 订单创建、支付成功、发货、完成、退款
|
|
定时同步: 每小时同步一次所有未同步订单
|
|
对账同步: 每日凌晨对账,发现差异立即同步
|
|
```
|
|
|
|
### 10.3 安全风险
|
|
|
|
#### 风险6: 密钥泄露
|
|
|
|
**风险等级:** 严重
|
|
**影响:** 系统安全完全失效
|
|
**概率:** 低
|
|
|
|
**应对措施:**
|
|
- ✅ 密钥存储在环境变量,不提交代码
|
|
- ✅ 生产环境使用密钥管理服务
|
|
- ✅ 定期轮换密钥
|
|
- ✅ 访问权限严格控制
|
|
- ✅ 代码审查检查密钥泄露
|
|
|
|
**检查方式:**
|
|
```bash
|
|
# 检查是否有密钥硬编码
|
|
grep -r "MIICdQIBADANBgkqhkiG9w0BAQ" application/
|
|
grep -r "private_key.*=" application/
|
|
```
|
|
|
|
#### 风险7: 接口被恶意调用
|
|
|
|
**风险等级:** 高
|
|
**影响:** 资源浪费,系统不稳定
|
|
**概率:** 中
|
|
|
|
**应对措施:**
|
|
- ✅ 接口鉴权 (Token验证)
|
|
- ✅ 频率限制 (同一用户1分钟最多10次)
|
|
- ✅ IP白名单 (建行回调接口)
|
|
- ✅ 异常流量告警
|
|
|
|
**限流实现:**
|
|
```php
|
|
// 使用Redis实现限流
|
|
$key = "rate_limit:user:{$userId}:payment";
|
|
$count = Redis::incr($key);
|
|
if ($count == 1) {
|
|
Redis::expire($key, 60); // 1分钟过期
|
|
}
|
|
if ($count > 10) {
|
|
throw new Exception('操作过于频繁,请稍后再试');
|
|
}
|
|
```
|
|
|
|
### 10.4 运维风险
|
|
|
|
#### 风险8: 服务器宕机
|
|
|
|
**风险等级:** 高
|
|
**影响:** 业务中断
|
|
**概率:** 低
|
|
|
|
**应对措施:**
|
|
- ✅ 双机热备
|
|
- ✅ 负载均衡
|
|
- ✅ 自动故障切换
|
|
- ✅ 监控告警
|
|
- ✅ 应急预案
|
|
|
|
**应急预案:**
|
|
```
|
|
1. 监控发现主服务器异常
|
|
2. 自动切换到备服务器 (30秒内)
|
|
3. 告警通知运维人员
|
|
4. 运维人员排查主服务器问题
|
|
5. 修复后切回主服务器
|
|
```
|
|
|
|
#### 风险9: 数据库异常
|
|
|
|
**风险等级:** 严重
|
|
**影响:** 数据丢失,业务中断
|
|
**概率:** 低
|
|
|
|
**应对措施:**
|
|
- ✅ 主从复制
|
|
- ✅ 每日全量备份
|
|
- ✅ 实时binlog备份
|
|
- ✅ 定期演练恢复
|
|
- ✅ 监控数据库状态
|
|
|
|
**恢复演练:**
|
|
```bash
|
|
# 1. 停止应用
|
|
systemctl stop php-fpm
|
|
|
|
# 2. 恢复数据库
|
|
mysql -u root -p fengketrade < /backup/mysql/fengketrade_20250116.sql
|
|
|
|
# 3. 恢复binlog (从备份时间点到当前)
|
|
mysqlbinlog --start-datetime="2025-01-16 02:00:00" \
|
|
/var/lib/mysql/mysql-bin.000001 | mysql -u root -p fengketrade
|
|
|
|
# 4. 验证数据
|
|
# 5. 启动应用
|
|
systemctl start php-fpm
|
|
```
|
|
|
|
---
|
|
|
|
## 11. 附录
|
|
|
|
### 11.1 名词解释
|
|
|
|
| 术语 | 解释 |
|
|
|------|------|
|
|
| FastAdmin | 基于ThinkPHP的后台管理系统框架 |
|
|
| UniApp | 跨平台应用开发框架 |
|
|
| JSBridge | H5与原生APP通讯的桥接技术 |
|
|
| RSA | 非对称加密算法 |
|
|
| MD5 | 消息摘要算法 |
|
|
| BASE64 | 编码方式 |
|
|
| txcode | 交易代码,标识不同的接口 |
|
|
| 服务方编号 | 建行分配的唯一标识,格式YS开头 |
|
|
| 支付流水号 | 支付请求的唯一标识 |
|
|
| 交易流水号 | 后台接口调用的唯一标识 |
|
|
|
|
### 11.2 参考文档
|
|
|
|
- [建行生活输入通讯报文v1.1.6【最新】.xlsx](doc/建行生活输入通讯报文v1.1.6【最新】.xlsx)
|
|
- [建行相关App服务方接入文档v2.20_20250725.html](doc/建行相关App服务方接入文档v2.20_20250725.html)
|
|
- [建行生活原生与h5交互规范接口1.3(新).html](doc/建行生活原生与h5交互规范接口1.3(新).html)
|
|
- [支付下单串示例.xlsx](doc/支付下单串示例.xlsx)
|
|
- [建行接口地址(真实版).md](doc/建行接口地址(真实版).md)
|
|
|
|
### 11.3 联系方式
|
|
|
|
**技术支持:**
|
|
- 建行技术热线: 95533
|
|
- 工作时间: 工作日 9:00-18:00
|
|
|
|
**紧急联系:**
|
|
- 项目经理: [联系方式]
|
|
- 技术负责人: [联系方式]
|
|
|
|
---
|
|
|
|
## 文档变更记录
|
|
|
|
| 版本 | 日期 | 修改人 | 修改内容 |
|
|
|------|------|--------|---------|
|
|
| v1.0 | 2025-01-16 | Claude | 初版,完整技术实现方案 |
|
|
|
|
---
|
|
|
|
**文档结束**
|