# 建行生活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商城
URL带参数: platform=ccblife&ccbParamSJ=xxx
H5->>H5: onLaunch检测环境
识别为建行环境
H5->>CCBApp: 调用JSBridge getUserInfo()
CCBApp-->>H5: 返回用户信息
{ccb_user_id, mobile, nickname, avatar}
H5->>Backend: POST /api/ccblife/autoLogin
{"ccb_user_id": "xxx", ...}
Backend->>DB: SELECT * FROM fa_user
WHERE ccb_user_id = 'xxx'
alt 用户已存在
DB-->>Backend: 返回用户记录
Backend->>DB: UPDATE fa_user
SET logintime=now()
Backend-->>H5: 返回Token + 用户信息
{is_new_user: false}
else 用户不存在 (首次登录)
Backend->>DB: INSERT INTO fa_user
(ccb_user_id, username, mobile...)
DB-->>Backend: 用户创建成功
Backend-->>H5: 返回Token + 用户信息
{is_new_user: true}
end
H5->>H5: 保存Token到localStorage
H5->>H5: 保存用户信息到Vuex/Pinia
H5-->>User: 登录成功,进入商城首页
Note over H5: 商城原有的登录注册页面
在建行环境下隐藏/禁用
```
**关键实现点:**
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