mirror of
https://gitee.com/liuxioabin/fengketrade.git
synced 2026-04-22 05:57:33 +08:00
代码优化
This commit is contained in:
parent
eee44f2816
commit
1b8d4538ae
@ -88,29 +88,18 @@ class Ccbpayment extends Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. 生成支付串
|
// 4. 生成支付串
|
||||||
|
// ⚠️ 注意: generatePaymentString()内部已经完成了以下操作:
|
||||||
|
// - 更新订单的ccb_pay_flow_id字段
|
||||||
|
// - 记录支付日志到ccb_payment_log表
|
||||||
|
// 控制器不应该重复操作,否则会导致数据重复写入!
|
||||||
$result = $this->paymentService->generatePaymentString($orderId);
|
$result = $this->paymentService->generatePaymentString($orderId);
|
||||||
|
|
||||||
if (!$result['status']) {
|
if (!$result['status']) {
|
||||||
$this->error('支付串生成失败: ' . $result['message']);
|
$this->error('支付串生成失败: ' . $result['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 保存支付流水号到订单
|
// 5. 直接返回支付串(不再重复保存数据库!)
|
||||||
$order->ccb_pay_flow_id = $result['data']['pay_flow_id']; // ✅ 使用真实的支付流水号
|
$this->success('支付串生成成功', $result['data']);
|
||||||
$order->save();
|
|
||||||
|
|
||||||
// 6. 记录支付日志
|
|
||||||
$this->savePaymentLog($order, $result['data']['payment_string'], $result['data']['pay_flow_id']);
|
|
||||||
|
|
||||||
// 7. 返回支付串
|
|
||||||
$this->success('支付串生成成功', [
|
|
||||||
'payment_string' => $result['data']['payment_string'],
|
|
||||||
'payment_url' => $result['data']['payment_url'],
|
|
||||||
'mac' => $result['data']['mac'],
|
|
||||||
'order_id' => $order->id,
|
|
||||||
'order_sn' => $order->order_sn,
|
|
||||||
'pay_flow_id' => $result['data']['pay_flow_id'], // ✅ 返回真实的支付流水号
|
|
||||||
'amount' => $result['data']['amount'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error('[建行支付] 生成支付串失败 order_id:' . ($orderId ?? 0) . ' error:' . $e->getMessage());
|
Log::error('[建行支付] 生成支付串失败 order_id:' . ($orderId ?? 0) . ' error:' . $e->getMessage());
|
||||||
|
|||||||
@ -70,7 +70,6 @@ class CcbEncryption
|
|||||||
{
|
{
|
||||||
$this->privateKey = $this->config['private_key'] ?? '';
|
$this->privateKey = $this->config['private_key'] ?? '';
|
||||||
$this->publicKey = $this->config['public_key'] ?? '';
|
$this->publicKey = $this->config['public_key'] ?? '';
|
||||||
$this->platformPublicKey = $this->config['platform_public_key'] ?? '';
|
|
||||||
|
|
||||||
if (empty($this->privateKey)) {
|
if (empty($this->privateKey)) {
|
||||||
throw new Exception('服务方私钥未配置');
|
throw new Exception('服务方私钥未配置');
|
||||||
|
|||||||
@ -96,6 +96,9 @@ class CcbPaymentService
|
|||||||
*/
|
*/
|
||||||
public function generatePaymentString($orderId)
|
public function generatePaymentString($orderId)
|
||||||
{
|
{
|
||||||
|
// ⚠️ 开启事务保护,确保数据一致性
|
||||||
|
Db::startTrans();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取订单信息
|
// 获取订单信息
|
||||||
$order = Order::find($orderId);
|
$order = Order::find($orderId);
|
||||||
@ -176,6 +179,9 @@ class CcbPaymentService
|
|||||||
'pay_flow_id' => $payFlowId
|
'pay_flow_id' => $payFlowId
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// ✅ 提交事务
|
||||||
|
Db::commit();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'status' => true,
|
'status' => true,
|
||||||
'message' => '支付串生成成功',
|
'message' => '支付串生成成功',
|
||||||
@ -185,11 +191,15 @@ class CcbPaymentService
|
|||||||
'payment_url' => $paymentUrl,
|
'payment_url' => $paymentUrl,
|
||||||
'order_sn' => $order['order_sn'],
|
'order_sn' => $order['order_sn'],
|
||||||
'pay_flow_id' => $payFlowId,
|
'pay_flow_id' => $payFlowId,
|
||||||
'amount' => number_format($order['pay_fee'], 2, '.', '')
|
'amount' => number_format($order['pay_fee'], 2, '.', ''),
|
||||||
|
'order_id' => $orderId // 补充order_id字段
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
// ❌ 回滚事务
|
||||||
|
Db::rollback();
|
||||||
|
|
||||||
Log::error('建行支付串生成失败: ' . $e->getMessage());
|
Log::error('建行支付串生成失败: ' . $e->getMessage());
|
||||||
return [
|
return [
|
||||||
'status' => false,
|
'status' => false,
|
||||||
|
|||||||
@ -1,500 +0,0 @@
|
|||||||
# 建行生活前端测试指南
|
|
||||||
|
|
||||||
## 测试环境准备
|
|
||||||
|
|
||||||
### 1. 前端项目结构确认
|
|
||||||
|
|
||||||
确认以下文件已正确创建:
|
|
||||||
|
|
||||||
```
|
|
||||||
frontend/
|
|
||||||
├── sheep/platform/
|
|
||||||
│ ├── provider/ccblife/
|
|
||||||
│ │ ├── index.js ✅ 已创建
|
|
||||||
│ │ └── api.js ✅ 已创建
|
|
||||||
│ ├── index.js ✅ 已修改(添加建行支持)
|
|
||||||
│ └── pay.js ✅ 已修改(添加建行支付)
|
|
||||||
├── pages/ccblife/
|
|
||||||
│ └── index.vue ✅ 已创建
|
|
||||||
├── static/
|
|
||||||
│ └── ccb-test.html ✅ 已创建(测试页面)
|
|
||||||
└── pages.json ✅ 已修改(添加路由配置)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 检查文件完整性
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /Users/billy/Code/fengketrade.com/frontend
|
|
||||||
|
|
||||||
# 检查建行模块文件
|
|
||||||
ls -l sheep/platform/provider/ccblife/
|
|
||||||
|
|
||||||
# 检查建行页面
|
|
||||||
ls -l pages/ccblife/
|
|
||||||
|
|
||||||
# 检查测试页面
|
|
||||||
ls -l static/ccb-test.html
|
|
||||||
```
|
|
||||||
|
|
||||||
## 测试方法
|
|
||||||
|
|
||||||
### 方法一:使用 HBuilderX(推荐)
|
|
||||||
|
|
||||||
这是 uni-app 项目的标准开发方式。
|
|
||||||
|
|
||||||
#### 步骤 1: 打开项目
|
|
||||||
|
|
||||||
1. 启动 HBuilderX
|
|
||||||
2. 文件 → 打开目录 → 选择 `frontend` 目录
|
|
||||||
3. 等待项目加载完成
|
|
||||||
|
|
||||||
#### 步骤 2: 运行到浏览器
|
|
||||||
|
|
||||||
1. 点击工具栏的"运行"按钮
|
|
||||||
2. 选择"运行到浏览器" → "Chrome"(或其他浏览器)
|
|
||||||
3. 等待编译完成,会自动打开浏览器
|
|
||||||
|
|
||||||
#### 步骤 3: 访问测试页面
|
|
||||||
|
|
||||||
在浏览器中访问:
|
|
||||||
```
|
|
||||||
http://localhost:8080/static/ccb-test.html
|
|
||||||
```
|
|
||||||
|
|
||||||
或访问建行专属页面:
|
|
||||||
```
|
|
||||||
http://localhost:8080/#/pages/ccblife/index
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 步骤 4: 模拟建行环境
|
|
||||||
|
|
||||||
在 URL 后添加参数模拟建行环境:
|
|
||||||
```
|
|
||||||
http://localhost:8080/#/pages/index/index?from=ccblife&ccbParamSJ=test123
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法二:使用 Vite 开发服务器
|
|
||||||
|
|
||||||
如果项目配置了 Vite,可以使用命令行运行。
|
|
||||||
|
|
||||||
#### 步骤 1: 安装依赖
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd frontend
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 步骤 2: 启动开发服务器
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 如果有 dev:h5 脚本
|
|
||||||
npm run dev:h5
|
|
||||||
|
|
||||||
# 或者直接使用 vite
|
|
||||||
npx vite
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 步骤 3: 访问测试页面
|
|
||||||
|
|
||||||
默认地址:`http://localhost:3000`(端口以实际为准)
|
|
||||||
|
|
||||||
### 方法三:使用测试服务器
|
|
||||||
|
|
||||||
将前端代码部署到测试服务器。
|
|
||||||
|
|
||||||
#### 步骤 1: 访问后端静态测试页面
|
|
||||||
|
|
||||||
```
|
|
||||||
http://fengketrade.test/ccblife-demo.html
|
|
||||||
```
|
|
||||||
|
|
||||||
这个页面已经在后端 public 目录创建,可以直接访问。
|
|
||||||
|
|
||||||
#### 步骤 2: 访问测试接口
|
|
||||||
|
|
||||||
```
|
|
||||||
http://fengketrade.test/addons/shopro/ccbtest
|
|
||||||
```
|
|
||||||
|
|
||||||
## 测试项目清单
|
|
||||||
|
|
||||||
### 1. 模块加载测试
|
|
||||||
|
|
||||||
#### 测试目标
|
|
||||||
验证建行模块是否正确导入和初始化。
|
|
||||||
|
|
||||||
#### 测试步骤
|
|
||||||
1. 打开浏览器开发者工具(F12)
|
|
||||||
2. 访问测试页面
|
|
||||||
3. 在 Console 中输入:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 检查 sheep 对象
|
|
||||||
console.log(window.$shop || window.sheep);
|
|
||||||
|
|
||||||
// 检查平台对象
|
|
||||||
console.log(sheep.$platform);
|
|
||||||
|
|
||||||
// 检查平台名称
|
|
||||||
console.log(sheep.$platform.name);
|
|
||||||
|
|
||||||
// 检查提供商
|
|
||||||
console.log(sheep.$platform.provider);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 预期结果
|
|
||||||
- 在非建行环境:`name` 应该是 `H5` 或 `WechatOfficialAccount`
|
|
||||||
- 在建行环境:`name` 应该是 `CcbLife`,`provider` 应该是 `ccb`
|
|
||||||
|
|
||||||
### 2. 环境检测测试
|
|
||||||
|
|
||||||
#### 测试目标
|
|
||||||
验证系统能否正确识别建行生活 App 环境。
|
|
||||||
|
|
||||||
#### 测试步骤
|
|
||||||
|
|
||||||
**情况 1:普通浏览器**
|
|
||||||
```
|
|
||||||
访问: http://localhost:3000/
|
|
||||||
预期: 识别为 H5 或 WechatOfficialAccount 环境
|
|
||||||
```
|
|
||||||
|
|
||||||
**情况 2:模拟建行环境(URL 参数)**
|
|
||||||
```
|
|
||||||
访问: http://localhost:3000/?from=ccblife
|
|
||||||
预期: 识别为 CcbLife 环境
|
|
||||||
```
|
|
||||||
|
|
||||||
**情况 3:模拟建行参数**
|
|
||||||
```
|
|
||||||
访问: http://localhost:3000/?ccbParamSJ=test123
|
|
||||||
预期: 识别为 CcbLife 环境
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 验证方法
|
|
||||||
|
|
||||||
在 Console 中执行:
|
|
||||||
```javascript
|
|
||||||
// 方法1:通过平台对象
|
|
||||||
console.log(sheep.$platform.provider === 'ccb' ? '建行环境' : '非建行环境');
|
|
||||||
|
|
||||||
// 方法2:直接导入模块(在实际项目中)
|
|
||||||
// import CcbLifePlatform from '@/sheep/platform/provider/ccblife/index';
|
|
||||||
// console.log(CcbLifePlatform.isInCcbApp);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 页面路由测试
|
|
||||||
|
|
||||||
#### 测试目标
|
|
||||||
验证建行专属页面是否可以正常访问。
|
|
||||||
|
|
||||||
#### 测试步骤
|
|
||||||
|
|
||||||
1. **访问首页**
|
|
||||||
```
|
|
||||||
http://localhost:3000/#/pages/index/index
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **访问建行专属页面**
|
|
||||||
```
|
|
||||||
http://localhost:3000/#/pages/ccblife/index
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **使用路由跳转**
|
|
||||||
|
|
||||||
在任意页面的 Console 中执行:
|
|
||||||
```javascript
|
|
||||||
uni.navigateTo({
|
|
||||||
url: '/pages/ccblife/index'
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 预期结果
|
|
||||||
- 页面能正常加载
|
|
||||||
- 显示"建行生活"标题
|
|
||||||
- 导航栏背景色为建行红(#F51C13)
|
|
||||||
|
|
||||||
### 4. API 接口测试
|
|
||||||
|
|
||||||
#### 测试目标
|
|
||||||
验证前端能否正确调用后端建行接口。
|
|
||||||
|
|
||||||
#### 测试步骤
|
|
||||||
|
|
||||||
在 Console 中执行:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 测试1:URL跳转登录接口
|
|
||||||
fetch('/addons/shopro/ccblife/login?ccbParamSJ=test')
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => console.log('登录接口:', data))
|
|
||||||
.catch(err => console.error('登录接口错误:', err));
|
|
||||||
|
|
||||||
// 测试2:环境检查
|
|
||||||
fetch('/addons/shopro/ccbtest/checkConfig')
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => console.log('配置检查:', data))
|
|
||||||
.catch(err => console.error('配置检查错误:', err));
|
|
||||||
|
|
||||||
// 测试3:数据库检查
|
|
||||||
fetch('/addons/shopro/ccbtest/checkDatabase')
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => console.log('数据库检查:', data))
|
|
||||||
.catch(err => console.error('数据库检查错误:', err));
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 预期结果
|
|
||||||
- 接口返回 JSON 格式数据
|
|
||||||
- 不应该出现 404 或 500 错误
|
|
||||||
|
|
||||||
### 5. 支付功能测试
|
|
||||||
|
|
||||||
#### 测试目标
|
|
||||||
验证建行支付流程是否正常。
|
|
||||||
|
|
||||||
#### 前置条件
|
|
||||||
- 已登录用户
|
|
||||||
- 有可支付的订单
|
|
||||||
|
|
||||||
#### 测试步骤
|
|
||||||
|
|
||||||
1. **创建测试订单**(可选)
|
|
||||||
```
|
|
||||||
访问: http://fengketrade.test/#/pages/goods/index?id=1
|
|
||||||
添加商品到购物车 → 去结算 → 提交订单
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **选择建行支付**
|
|
||||||
|
|
||||||
在支付页面,如果在建行环境中,应该看到"建行支付"选项。
|
|
||||||
|
|
||||||
3. **模拟支付调用**
|
|
||||||
|
|
||||||
在 Console 中执行:
|
|
||||||
```javascript
|
|
||||||
// 注意:这需要有实际的订单
|
|
||||||
sheep.$platform.pay('ccb', 'goods', 'ORDER202501170001');
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 预期结果
|
|
||||||
- 非建行环境:提示"请在建行生活App内使用建行支付"
|
|
||||||
- 建行环境(模拟):尝试调用 JSBridge
|
|
||||||
|
|
||||||
### 6. 日志和错误测试
|
|
||||||
|
|
||||||
#### 测试目标
|
|
||||||
验证错误处理和日志记录是否正常。
|
|
||||||
|
|
||||||
#### 测试步骤
|
|
||||||
|
|
||||||
1. **查看 Console 日志**
|
|
||||||
|
|
||||||
启动应用后,在 Console 中应该看到:
|
|
||||||
```
|
|
||||||
[CcbLife] 初始化完成, 是否在建行App内: false
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **触发错误**
|
|
||||||
|
|
||||||
在非建行环境调用建行功能:
|
|
||||||
```javascript
|
|
||||||
// 应该输出友好的错误提示
|
|
||||||
sheep.$platform.useProvider('ccb').getUserInfo()
|
|
||||||
.catch(err => console.log('预期的错误:', err));
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 预期结果
|
|
||||||
- 有清晰的日志输出
|
|
||||||
- 错误信息友好可读
|
|
||||||
|
|
||||||
## 使用静态测试页面
|
|
||||||
|
|
||||||
访问 `http://fengketrade.test/static/ccb-test.html`(或前端开发服务器对应地址)
|
|
||||||
|
|
||||||
### 测试页面功能
|
|
||||||
|
|
||||||
1. **环境信息显示**
|
|
||||||
- 自动检测当前平台
|
|
||||||
- 显示是否在建行App内
|
|
||||||
- 显示 User-Agent 和 URL 参数
|
|
||||||
|
|
||||||
2. **模块加载测试**
|
|
||||||
- 点击"测试模块导入"按钮
|
|
||||||
- 检查建行模块文件是否存在
|
|
||||||
|
|
||||||
3. **环境检测测试**
|
|
||||||
- 点击"测试环境检测"按钮
|
|
||||||
- 查看多种检测方式的结果
|
|
||||||
|
|
||||||
4. **URL参数测试**
|
|
||||||
- 点击"测试URL参数解析"按钮
|
|
||||||
- 验证参数解析功能
|
|
||||||
|
|
||||||
### 模拟建行环境
|
|
||||||
|
|
||||||
在测试页面 URL 后添加参数:
|
|
||||||
```
|
|
||||||
?from=ccblife&ccbParamSJ=testdata123
|
|
||||||
```
|
|
||||||
|
|
||||||
完整示例:
|
|
||||||
```
|
|
||||||
http://localhost:3000/static/ccb-test.html?from=ccblife&ccbParamSJ=testdata123
|
|
||||||
```
|
|
||||||
|
|
||||||
## 常见问题排查
|
|
||||||
|
|
||||||
### 问题1:页面打不开
|
|
||||||
|
|
||||||
**症状**:访问建行页面显示 404
|
|
||||||
|
|
||||||
**排查步骤**:
|
|
||||||
1. 检查 `pages.json` 是否正确配置
|
|
||||||
```bash
|
|
||||||
grep -A 10 "ccblife" pages.json
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 检查页面文件是否存在
|
|
||||||
```bash
|
|
||||||
ls -l pages/ccblife/index.vue
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 重新编译项目(在 HBuilderX 中点击"停止" → "运行")
|
|
||||||
|
|
||||||
### 问题2:模块导入失败
|
|
||||||
|
|
||||||
**症状**:Console 显示 "Cannot find module" 错误
|
|
||||||
|
|
||||||
**排查步骤**:
|
|
||||||
1. 检查文件路径
|
|
||||||
```bash
|
|
||||||
ls -l sheep/platform/provider/ccblife/
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 检查文件内容是否有语法错误
|
|
||||||
```bash
|
|
||||||
node --check sheep/platform/provider/ccblife/index.js
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 清除缓存重新编译
|
|
||||||
|
|
||||||
### 问题3:平台识别错误
|
|
||||||
|
|
||||||
**症状**:在建行环境中仍识别为 H5
|
|
||||||
|
|
||||||
**排查步骤**:
|
|
||||||
1. 检查 URL 参数
|
|
||||||
```javascript
|
|
||||||
console.log(window.location.search);
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 检查 User-Agent
|
|
||||||
```javascript
|
|
||||||
console.log(navigator.userAgent);
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 手动测试检测函数
|
|
||||||
```javascript
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
console.log('from参数:', urlParams.get('from'));
|
|
||||||
console.log('ccbParamSJ参数:', urlParams.get('ccbParamSJ'));
|
|
||||||
```
|
|
||||||
|
|
||||||
### 问题4:API 请求失败
|
|
||||||
|
|
||||||
**症状**:接口返回 404 或跨域错误
|
|
||||||
|
|
||||||
**排查步骤**:
|
|
||||||
1. 检查后端服务是否运行
|
|
||||||
```bash
|
|
||||||
curl http://fengketrade.test/addons/shopro/ccbtest
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 检查 `.env` 配置
|
|
||||||
```bash
|
|
||||||
cat .env | grep SHOPRO_BASE_URL
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 检查跨域配置(如果前后端分离)
|
|
||||||
|
|
||||||
## 真机测试
|
|
||||||
|
|
||||||
### iOS 设备测试
|
|
||||||
|
|
||||||
1. **使用 Safari 调试**
|
|
||||||
- Mac 上打开 Safari → 开发 → [设备名] → [页面]
|
|
||||||
- 可以查看 Console 和调试
|
|
||||||
|
|
||||||
2. **HBuilderX 真机运行**
|
|
||||||
- 连接 iOS 设备
|
|
||||||
- 运行 → 运行到手机或模拟器 → iOS
|
|
||||||
|
|
||||||
### Android 设备测试
|
|
||||||
|
|
||||||
1. **使用 Chrome 调试**
|
|
||||||
- 电脑 Chrome 访问 `chrome://inspect`
|
|
||||||
- 查看设备上的页面
|
|
||||||
|
|
||||||
2. **HBuilderX 真机运行**
|
|
||||||
- 连接 Android 设备(开启 USB 调试)
|
|
||||||
- 运行 → 运行到手机或模拟器 → Android
|
|
||||||
|
|
||||||
## 性能测试
|
|
||||||
|
|
||||||
### 加载时间
|
|
||||||
|
|
||||||
在 Console 中查看:
|
|
||||||
```javascript
|
|
||||||
// 查看性能数据
|
|
||||||
console.log(performance.timing);
|
|
||||||
|
|
||||||
// 计算加载时间
|
|
||||||
const loadTime = performance.timing.loadEventEnd - performance.timing.navigationStart;
|
|
||||||
console.log('页面加载时间:', loadTime + 'ms');
|
|
||||||
```
|
|
||||||
|
|
||||||
### 内存使用
|
|
||||||
|
|
||||||
使用 Chrome DevTools:
|
|
||||||
1. Performance → 录制
|
|
||||||
2. 操作页面
|
|
||||||
3. 停止录制
|
|
||||||
4. 查看内存使用情况
|
|
||||||
|
|
||||||
## 测试报告模板
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## 建行生活前端测试报告
|
|
||||||
|
|
||||||
**测试日期**: 2025-01-17
|
|
||||||
**测试环境**: [开发环境/测试环境]
|
|
||||||
**测试人员**: [姓名]
|
|
||||||
|
|
||||||
### 测试结果
|
|
||||||
|
|
||||||
| 测试项 | 状态 | 备注 |
|
|
||||||
|-------|------|------|
|
|
||||||
| 模块加载 | ✅ 通过 | 所有模块正常加载 |
|
|
||||||
| 环境检测 | ✅ 通过 | 正确识别建行环境 |
|
|
||||||
| 页面路由 | ✅ 通过 | 页面可以正常访问 |
|
|
||||||
| API接口 | ✅ 通过 | 接口返回正常 |
|
|
||||||
| 支付功能 | ⏳ 待测试 | 需要建行真机环境 |
|
|
||||||
|
|
||||||
### 发现的问题
|
|
||||||
|
|
||||||
1. [问题描述]
|
|
||||||
- **严重程度**: 高/中/低
|
|
||||||
- **复现步骤**: ...
|
|
||||||
- **预期行为**: ...
|
|
||||||
- **实际行为**: ...
|
|
||||||
|
|
||||||
### 建议
|
|
||||||
|
|
||||||
1. [建议内容]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*文档版本:1.0.0*
|
|
||||||
*最后更新:2025-01-17*
|
|
||||||
*作者:Billy*
|
|
||||||
@ -1,252 +0,0 @@
|
|||||||
# 建行生活 H5 商城对接实施指南
|
|
||||||
|
|
||||||
## 项目概述
|
|
||||||
|
|
||||||
本文档描述了 Shopro 商城系统与建行生活 App 的完整对接方案实现。所有代码已根据您的实际数据库结构进行调整,确保与现有系统完美兼容。
|
|
||||||
|
|
||||||
## 已实现功能清单
|
|
||||||
|
|
||||||
### 1. 核心加密模块
|
|
||||||
- ✅ **RSA 加密解密** (`CcbRSA.php`):支持 1024 位 RSA,117/128 字节分段处理
|
|
||||||
- ✅ **MD5 签名** (`CcbMD5.php`):API 消息签名和支付串签名
|
|
||||||
- ✅ **URL 参数解密** (`CcbUrlDecrypt.php`):双层 BASE64 + DES 解密
|
|
||||||
|
|
||||||
### 2. 业务服务类
|
|
||||||
- ✅ **HTTP 客户端** (`CcbHttpClient.php`):处理与建行 API 的通信
|
|
||||||
- ✅ **订单服务** (`CcbOrderService.php`):订单推送、查询、状态更新、退款
|
|
||||||
- ✅ **支付服务** (`CcbPaymentService.php`):支付串生成、回调处理、支付验证
|
|
||||||
|
|
||||||
### 3. 控制器接口
|
|
||||||
- ✅ **用户登录** (`Ccblife.php`):建行用户登录、自动登录、用户绑定
|
|
||||||
- ✅ **支付处理** (`Ccbpayment.php`):生成支付串、处理回调、推送订单
|
|
||||||
- ✅ **测试接口** (`Ccbtest.php`):全面的功能测试接口
|
|
||||||
|
|
||||||
### 4. 前端集成
|
|
||||||
- ✅ **JSBridge 库** (`ccblife-bridge.js`):封装建行原生交互功能
|
|
||||||
- ✅ **示例页面** (`ccblife-demo.html`):演示如何使用 JSBridge
|
|
||||||
|
|
||||||
## 数据库结构(已执行)
|
|
||||||
|
|
||||||
### 用户表改造
|
|
||||||
```sql
|
|
||||||
ALTER TABLE `fa_user`
|
|
||||||
ADD COLUMN `ccb_user_id` varchar(50) DEFAULT NULL COMMENT '建行用户ID';
|
|
||||||
```
|
|
||||||
|
|
||||||
### 订单表改造
|
|
||||||
```sql
|
|
||||||
ALTER TABLE `fa_shopro_order`
|
|
||||||
ADD COLUMN `ccb_user_id` varchar(30) DEFAULT NULL COMMENT '建行用户ID',
|
|
||||||
ADD COLUMN `ccb_pay_flow_id` varchar(50) DEFAULT NULL COMMENT '建行支付流水号',
|
|
||||||
ADD COLUMN `ccb_sync_status` tinyint(1) DEFAULT '0' COMMENT '建行同步状态',
|
|
||||||
ADD COLUMN `ccb_sync_time` int(11) DEFAULT NULL COMMENT '建行同步时间';
|
|
||||||
```
|
|
||||||
|
|
||||||
### 支付日志表
|
|
||||||
```sql
|
|
||||||
-- fa_ccb_payment_log 表用于记录支付流水
|
|
||||||
```
|
|
||||||
|
|
||||||
### 同步日志表
|
|
||||||
```sql
|
|
||||||
-- fa_ccb_sync_log 表用于记录与建行的同步日志
|
|
||||||
```
|
|
||||||
|
|
||||||
## 配置说明
|
|
||||||
|
|
||||||
配置文件位置:`/addons/shopro/config/ccblife.php`
|
|
||||||
|
|
||||||
关键配置项(从 .env 读取):
|
|
||||||
- `CCB_SERVICE_ID`: 服务方编号(生产:YS44000009001853)
|
|
||||||
- `CCB_MERCHANT_ID`: 商户号
|
|
||||||
- `CCB_POS_ID`: POS 号
|
|
||||||
- `CCB_BRANCH_ID`: 分行号
|
|
||||||
- `CCB_PRIVATE_KEY`: RSA 私钥(BASE64 格式)
|
|
||||||
- `CCB_PUBLIC_KEY`: RSA 公钥(BASE64 格式)
|
|
||||||
|
|
||||||
## 接口调用流程
|
|
||||||
|
|
||||||
### 1. 用户登录流程
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
sequenceDiagram
|
|
||||||
participant U as 用户
|
|
||||||
participant CCB as 建行App
|
|
||||||
participant H5 as H5商城
|
|
||||||
participant API as 后端API
|
|
||||||
participant DB as 数据库
|
|
||||||
|
|
||||||
U->>CCB: 点击进入商城
|
|
||||||
CCB->>H5: 跳转URL(携带ccbParamSJ)
|
|
||||||
H5->>API: 调用 /ccblife/login
|
|
||||||
API->>API: 解密ccbParamSJ参数
|
|
||||||
API->>DB: 查询/创建用户
|
|
||||||
DB-->>API: 返回用户信息
|
|
||||||
API->>API: 生成Token
|
|
||||||
API-->>H5: 返回Token和用户信息
|
|
||||||
H5-->>U: 显示商城首页
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 支付流程
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
sequenceDiagram
|
|
||||||
participant U as 用户
|
|
||||||
participant H5 as H5商城
|
|
||||||
participant API as 后端API
|
|
||||||
participant CCB as 建行App
|
|
||||||
participant CCBAPI as 建行API
|
|
||||||
|
|
||||||
U->>H5: 提交订单
|
|
||||||
H5->>API: 创建订单
|
|
||||||
API-->>H5: 返回订单信息
|
|
||||||
H5->>API: 请求支付串 /ccbpayment/createPayment
|
|
||||||
API->>API: 生成支付串和MAC签名
|
|
||||||
API-->>H5: 返回支付串
|
|
||||||
H5->>CCB: 调用JSBridge发起支付
|
|
||||||
CCB->>U: 显示收银台
|
|
||||||
U->>CCB: 确认支付
|
|
||||||
CCB->>CCBAPI: 处理支付
|
|
||||||
CCBAPI-->>CCB: 支付结果
|
|
||||||
CCB->>H5: 返回支付结果
|
|
||||||
H5->>API: 回调 /ccbpayment/callback
|
|
||||||
API->>CCBAPI: 验证支付结果
|
|
||||||
API->>API: 更新订单状态
|
|
||||||
API->>CCBAPI: 推送订单信息
|
|
||||||
API-->>H5: 返回最终结果
|
|
||||||
```
|
|
||||||
|
|
||||||
## 测试步骤
|
|
||||||
|
|
||||||
### 1. 环境检查
|
|
||||||
访问:`http://fengketrade.test/addons/shopro/ccbtest`
|
|
||||||
|
|
||||||
检查项:
|
|
||||||
- 配置检查:`/ccbtest/checkConfig`
|
|
||||||
- 数据库检查:`/ccbtest/checkDatabase`
|
|
||||||
|
|
||||||
### 2. 功能测试
|
|
||||||
|
|
||||||
#### 基础功能
|
|
||||||
- RSA 测试:`/ccbtest/testRsa`
|
|
||||||
- MD5 测试:`/ccbtest/testMd5`
|
|
||||||
- URL 解密:`/ccbtest/testUrlDecrypt`
|
|
||||||
|
|
||||||
#### 业务功能
|
|
||||||
- 用户登录:`POST /ccbtest/testUserLogin`
|
|
||||||
- 订单推送:`/ccbtest/testOrderPush?order_id=1`
|
|
||||||
- 支付串生成:`/ccbtest/testPaymentString?order_id=1`
|
|
||||||
|
|
||||||
### 3. 前端测试
|
|
||||||
1. 访问示例页面:`http://fengketrade.test/ccblife-demo.html`
|
|
||||||
2. 测试各项功能:
|
|
||||||
- 检测运行环境
|
|
||||||
- 获取用户信息
|
|
||||||
- 自动登录
|
|
||||||
- 模拟支付
|
|
||||||
|
|
||||||
## 前端集成示例
|
|
||||||
|
|
||||||
### 初始化 JSBridge
|
|
||||||
```javascript
|
|
||||||
// 在页面加载时初始化
|
|
||||||
CcbLifeBridge.init({
|
|
||||||
debug: true,
|
|
||||||
apiBaseUrl: '/addons/shopro'
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 获取用户信息
|
|
||||||
```javascript
|
|
||||||
CcbLifeBridge.getUserInfo(function(result) {
|
|
||||||
if (result.success) {
|
|
||||||
console.log('用户信息:', result.data);
|
|
||||||
// result.data 包含: ccb_user_id, mobile, nickname, avatar
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 调起支付
|
|
||||||
```javascript
|
|
||||||
// 先调用后端生成支付串
|
|
||||||
fetch('/addons/shopro/ccbpayment/createPayment', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'token': localStorage.getItem('ccb_token')
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ order_id: orderId })
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.code === 1) {
|
|
||||||
// 调起建行支付
|
|
||||||
CcbLifeBridge.payment({
|
|
||||||
payment_string: data.data.payment_string
|
|
||||||
}, function(result) {
|
|
||||||
if (result.success) {
|
|
||||||
// 支付成功,通知后端
|
|
||||||
notifyPaymentSuccess(orderId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
### 1. 安全要求
|
|
||||||
- 所有敏感配置必须存储在 `.env` 文件中
|
|
||||||
- RSA 密钥必须是 BASE64 格式(不含 PEM 头尾)
|
|
||||||
- 生产环境必须启用 HTTPS
|
|
||||||
|
|
||||||
### 2. 数据同步
|
|
||||||
- 订单状态变更必须同步到建行
|
|
||||||
- 使用 `fa_ccb_sync_log` 表记录所有同步操作
|
|
||||||
- 支持批量同步未同步的订单
|
|
||||||
|
|
||||||
### 3. 错误处理
|
|
||||||
- 所有 API 调用都有重试机制(默认 3 次)
|
|
||||||
- 失败的同步任务会记录到日志表
|
|
||||||
- 支付失败需要明确提示用户
|
|
||||||
|
|
||||||
### 4. 兼容性
|
|
||||||
- iOS:通过 URL Scheme 调起支付(comccbpay://)
|
|
||||||
- Android:通过 window.mbspay 对象调用
|
|
||||||
- H5:在非建行环境降级处理
|
|
||||||
|
|
||||||
## 部署检查清单
|
|
||||||
|
|
||||||
- [ ] 确认 `.env` 配置正确
|
|
||||||
- [ ] 数据库表结构已更新
|
|
||||||
- [ ] RSA 密钥已配置
|
|
||||||
- [ ] HTTPS 证书已安装
|
|
||||||
- [ ] 前端 JS 文件已部署
|
|
||||||
- [ ] 测试接口访问正常
|
|
||||||
- [ ] 日志目录可写
|
|
||||||
|
|
||||||
## 常见问题
|
|
||||||
|
|
||||||
### Q: RSA 加密失败
|
|
||||||
A: 检查密钥格式是否为 BASE64,不要包含 PEM 头尾标记
|
|
||||||
|
|
||||||
### Q: 用户登录失败
|
|
||||||
A: 确认 ccbParamSJ 参数正确,服务方编号与配置一致
|
|
||||||
|
|
||||||
### Q: 订单推送失败
|
|
||||||
A: 检查必需的 34 个字段是否都已填充,特别注意日期格式
|
|
||||||
|
|
||||||
### Q: 支付无响应
|
|
||||||
A: 确认在建行 App 内访问,检查 JSBridge 是否就绪
|
|
||||||
|
|
||||||
## 技术支持
|
|
||||||
|
|
||||||
如有问题,请检查:
|
|
||||||
1. 系统日志:`runtime/log/ccblife/`
|
|
||||||
2. 同步日志:`fa_ccb_sync_log` 表
|
|
||||||
3. 支付日志:`fa_ccb_payment_log` 表
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*最后更新:2025-01-17*
|
|
||||||
*作者:Billy*
|
|
||||||
@ -1,321 +0,0 @@
|
|||||||
# 建行生活前端测试摘要
|
|
||||||
|
|
||||||
## 📋 测试环境配置完成
|
|
||||||
|
|
||||||
**日期**: 2025-01-17
|
|
||||||
**状态**: ✅ 就绪
|
|
||||||
|
|
||||||
## 📁 已创建/修改的文件
|
|
||||||
|
|
||||||
### 新建文件 (6个)
|
|
||||||
|
|
||||||
1. `/frontend/sheep/platform/provider/ccblife/index.js` (347行)
|
|
||||||
- 建行生活平台核心模块
|
|
||||||
- 环境检测、JSBridge、用户信息、支付功能
|
|
||||||
|
|
||||||
2. `/frontend/sheep/platform/provider/ccblife/api.js` (69行)
|
|
||||||
- 建行 API 接口封装
|
|
||||||
- 登录、支付相关接口
|
|
||||||
|
|
||||||
3. `/frontend/pages/ccblife/index.vue` (373行)
|
|
||||||
- 建行生活专属页面
|
|
||||||
- 用户信息、专属活动、专享商品展示
|
|
||||||
|
|
||||||
4. `/frontend/static/ccb-test.html` (620行)
|
|
||||||
- 前端集成测试页面
|
|
||||||
- 环境检测、模块加载、功能测试
|
|
||||||
|
|
||||||
5. `/doc/ccblife-uniapp-integration.md`
|
|
||||||
- uni-app 集成指南文档
|
|
||||||
|
|
||||||
6. `/doc/ccblife-frontend-testing-guide.md`
|
|
||||||
- 完整的测试指南文档
|
|
||||||
|
|
||||||
### 修改文件 (3个)
|
|
||||||
|
|
||||||
1. `/frontend/sheep/platform/index.js`
|
|
||||||
- ✅ 添加 ccblife 模块导入
|
|
||||||
- ✅ 添加建行环境检测
|
|
||||||
- ✅ 添加 ccb provider 支持
|
|
||||||
|
|
||||||
2. `/frontend/sheep/platform/pay.js`
|
|
||||||
- ✅ 添加建行支付方式
|
|
||||||
- ✅ 实现 ccbPay() 方法
|
|
||||||
- ✅ 集成支付流程
|
|
||||||
|
|
||||||
3. `/frontend/pages.json`
|
|
||||||
- ✅ 添加建行页面路由配置
|
|
||||||
|
|
||||||
## ✅ 文件验证结果
|
|
||||||
|
|
||||||
| 检查项 | 状态 | 说明 |
|
|
||||||
|--------|------|------|
|
|
||||||
| JavaScript 语法 | ✅ 通过 | 所有 JS 文件语法正确 |
|
|
||||||
| JSON 格式 | ✅ 通过 | pages.json 格式正确 |
|
|
||||||
| 文件完整性 | ✅ 通过 | 所有文件已创建 |
|
|
||||||
| 代码行数 | ✅ 正常 | 共 516 行核心代码 |
|
|
||||||
|
|
||||||
## 🚀 快速开始测试
|
|
||||||
|
|
||||||
### 方式 1: 使用测试页面(最简单)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. 访问后端测试页面
|
|
||||||
http://fengketrade.test/ccblife-demo.html
|
|
||||||
|
|
||||||
# 2. 或访问前端测试页面(需启动前端服务)
|
|
||||||
http://localhost:3000/static/ccb-test.html
|
|
||||||
|
|
||||||
# 3. 模拟建行环境
|
|
||||||
添加 URL 参数: ?from=ccblife&ccbParamSJ=test
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方式 2: 使用 HBuilderX(推荐)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. 打开 HBuilderX
|
|
||||||
# 2. 文件 → 打开目录 → 选择 frontend
|
|
||||||
# 3. 运行 → 运行到浏览器 → Chrome
|
|
||||||
# 4. 访问: http://localhost:8080/#/pages/ccblife/index
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方式 3: 使用命令行(开发者)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd frontend
|
|
||||||
|
|
||||||
# 安装依赖(如果还没安装)
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# 启动开发服务器(如果项目支持)
|
|
||||||
npm run dev:h5
|
|
||||||
# 或
|
|
||||||
npx vite
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 核心测试点
|
|
||||||
|
|
||||||
### 1. 环境检测测试 ⏳
|
|
||||||
|
|
||||||
**测试目标**: 验证系统能否正确识别建行生活 App
|
|
||||||
|
|
||||||
**测试方法**:
|
|
||||||
```javascript
|
|
||||||
// 在浏览器 Console 中执行
|
|
||||||
console.log(sheep.$platform);
|
|
||||||
// 预期输出: { name: 'CcbLife', provider: 'ccb', ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
**测试场景**:
|
|
||||||
- ✅ 普通浏览器 → 应识别为 H5
|
|
||||||
- ✅ 带 from=ccblife 参数 → 应识别为 CcbLife
|
|
||||||
- ✅ 带 ccbParamSJ 参数 → 应识别为 CcbLife
|
|
||||||
|
|
||||||
### 2. 页面路由测试 ⏳
|
|
||||||
|
|
||||||
**测试目标**: 验证建行专属页面可以正常访问
|
|
||||||
|
|
||||||
**测试方法**:
|
|
||||||
```
|
|
||||||
访问: http://localhost:3000/#/pages/ccblife/index
|
|
||||||
```
|
|
||||||
|
|
||||||
**预期结果**:
|
|
||||||
- ✅ 页面正常加载
|
|
||||||
- ✅ 显示"建行生活"标题
|
|
||||||
- ✅ 导航栏背景色为建行红 (#F51C13)
|
|
||||||
|
|
||||||
### 3. 模块导入测试 ⏳
|
|
||||||
|
|
||||||
**测试目标**: 验证建行模块正确导入
|
|
||||||
|
|
||||||
**测试方法**:
|
|
||||||
```javascript
|
|
||||||
// 检查文件是否可访问
|
|
||||||
fetch('/sheep/platform/provider/ccblife/index.js')
|
|
||||||
.then(res => console.log('建行模块:', res.ok ? '✓ 存在' : '✗ 不存在'));
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. API 接口测试 ⏳
|
|
||||||
|
|
||||||
**测试目标**: 验证前端能调用后端建行接口
|
|
||||||
|
|
||||||
**测试方法**:
|
|
||||||
```bash
|
|
||||||
# 方法1: 使用 curl
|
|
||||||
curl http://fengketrade.test/addons/shopro/ccbtest
|
|
||||||
|
|
||||||
# 方法2: 浏览器访问
|
|
||||||
http://fengketrade.test/addons/shopro/ccbtest/checkConfig
|
|
||||||
```
|
|
||||||
|
|
||||||
**预期结果**:
|
|
||||||
- ✅ 返回 JSON 数据
|
|
||||||
- ✅ code 字段为 1(成功)
|
|
||||||
|
|
||||||
### 5. 支付流程测试 ⏳
|
|
||||||
|
|
||||||
**测试目标**: 验证建行支付调用流程
|
|
||||||
|
|
||||||
**前置条件**: 在建行环境中
|
|
||||||
|
|
||||||
**测试方法**:
|
|
||||||
```javascript
|
|
||||||
// 模拟支付调用
|
|
||||||
sheep.$platform.pay('ccb', 'goods', 'ORDER_TEST_001');
|
|
||||||
```
|
|
||||||
|
|
||||||
**预期结果**:
|
|
||||||
- ✅ 非建行环境: 提示"请在建行生活App内使用"
|
|
||||||
- ✅ 建行环境: 尝试调用 JSBridge
|
|
||||||
|
|
||||||
## 📊 测试覆盖范围
|
|
||||||
|
|
||||||
```
|
|
||||||
核心功能模块
|
|
||||||
├── 环境检测 ✅ 已实现 ⏳ 待测试
|
|
||||||
├── 用户信息获取 ✅ 已实现 ⏳ 待测试
|
|
||||||
├── 自动登录 ✅ 已实现 ⏳ 待测试
|
|
||||||
├── 支付集成 ✅ 已实现 ⏳ 待测试
|
|
||||||
├── JSBridge 调用 ✅ 已实现 ⏳ 待测试
|
|
||||||
└── 专属页面 ✅ 已实现 ⏳ 待测试
|
|
||||||
|
|
||||||
平台兼容
|
|
||||||
├── H5 环境 ✅ 已实现 ⏳ 待测试
|
|
||||||
├── iOS JSBridge ✅ 已实现 ⏳ 需真机
|
|
||||||
├── Android 集成 ✅ 已实现 ⏳ 需真机
|
|
||||||
└── 小程序 ⚠️ 不支持(符合预期)
|
|
||||||
|
|
||||||
API 接口
|
|
||||||
├── 用户登录 ✅ 已实现 ⏳ 待测试
|
|
||||||
├── 自动登录 ✅ 已实现 ⏳ 待测试
|
|
||||||
├── 支付串生成 ✅ 已实现 ⏳ 待测试
|
|
||||||
└── 支付回调 ✅ 已实现 ⏳ 待测试
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔍 已知限制
|
|
||||||
|
|
||||||
1. **真机测试依赖**
|
|
||||||
- JSBridge 功能需要在真实建行 App 中测试
|
|
||||||
- 支付功能需要建行生产环境
|
|
||||||
|
|
||||||
2. **小程序限制**
|
|
||||||
- 微信小程序不支持建行支付
|
|
||||||
- 系统会自动降级处理
|
|
||||||
|
|
||||||
3. **开发环境限制**
|
|
||||||
- 本地无法完整模拟建行 JSBridge
|
|
||||||
- 可以通过 URL 参数模拟环境判断
|
|
||||||
|
|
||||||
## 📝 下一步行动
|
|
||||||
|
|
||||||
### 立即可以测试(本地)
|
|
||||||
|
|
||||||
- [x] 文件语法检查
|
|
||||||
- [x] JSON 格式验证
|
|
||||||
- [ ] 启动开发服务器
|
|
||||||
- [ ] 访问测试页面
|
|
||||||
- [ ] 验证环境检测
|
|
||||||
- [ ] 验证页面路由
|
|
||||||
- [ ] 测试 API 接口调用
|
|
||||||
|
|
||||||
### 需要建行环境(真机)
|
|
||||||
|
|
||||||
- [ ] JSBridge 功能测试
|
|
||||||
- [ ] 获取建行用户信息
|
|
||||||
- [ ] 自动登录流程
|
|
||||||
- [ ] 支付功能完整流程
|
|
||||||
- [ ] URL 参数解密
|
|
||||||
|
|
||||||
### 建议测试顺序
|
|
||||||
|
|
||||||
1. **第一阶段: 本地基础测试**
|
|
||||||
```bash
|
|
||||||
# 1. 访问测试页面
|
|
||||||
http://localhost:3000/static/ccb-test.html
|
|
||||||
|
|
||||||
# 2. 点击"测试模块导入"
|
|
||||||
# 3. 点击"测试环境检测"
|
|
||||||
# 4. 点击"测试URL参数解析"
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **第二阶段: 接口联调测试**
|
|
||||||
```bash
|
|
||||||
# 1. 测试配置检查
|
|
||||||
curl http://fengketrade.test/addons/shopro/ccbtest/checkConfig
|
|
||||||
|
|
||||||
# 2. 测试数据库检查
|
|
||||||
curl http://fengketrade.test/addons/shopro/ccbtest/checkDatabase
|
|
||||||
|
|
||||||
# 3. 测试 RSA 加密
|
|
||||||
curl http://fengketrade.test/addons/shopro/ccbtest/testRsa
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **第三阶段: 真机环境测试**
|
|
||||||
- 在建行生活 App 内打开测试链接
|
|
||||||
- 验证 JSBridge 功能
|
|
||||||
- 测试完整的支付流程
|
|
||||||
|
|
||||||
## 📚 相关文档
|
|
||||||
|
|
||||||
- **集成指南**: `/doc/ccblife-uniapp-integration.md`
|
|
||||||
- **测试指南**: `/doc/ccblife-frontend-testing-guide.md`
|
|
||||||
- **实施指南**: `/doc/ccblife-implementation-guide.md`
|
|
||||||
- **技术方案**: `/fangan.md`
|
|
||||||
|
|
||||||
## 💡 测试技巧
|
|
||||||
|
|
||||||
### 快速验证模块加载
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 在浏览器 Console 中粘贴执行
|
|
||||||
(() => {
|
|
||||||
console.group('🏦 建行生活模块验证');
|
|
||||||
|
|
||||||
// 1. 平台对象
|
|
||||||
console.log('平台对象:', window.sheep?.$platform || '未找到');
|
|
||||||
|
|
||||||
// 2. 平台名称
|
|
||||||
console.log('平台名称:', window.sheep?.$platform?.name || '未知');
|
|
||||||
|
|
||||||
// 3. 提供商
|
|
||||||
console.log('提供商:', window.sheep?.$platform?.provider || '未知');
|
|
||||||
|
|
||||||
// 4. 是否建行环境
|
|
||||||
const isCcb = window.sheep?.$platform?.provider === 'ccb';
|
|
||||||
console.log('建行环境:', isCcb ? '✓ 是' : '✗ 否');
|
|
||||||
|
|
||||||
console.groupEnd();
|
|
||||||
})();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 模拟建行参数
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 方式1: 修改 URL(刷新后生效)
|
|
||||||
const url = new URL(window.location);
|
|
||||||
url.searchParams.set('from', 'ccblife');
|
|
||||||
url.searchParams.set('ccbParamSJ', 'test123');
|
|
||||||
window.location.href = url.toString();
|
|
||||||
|
|
||||||
// 方式2: 直接访问
|
|
||||||
window.location.href = '?from=ccblife&ccbParamSJ=test123';
|
|
||||||
```
|
|
||||||
|
|
||||||
## ❓ 问题排查
|
|
||||||
|
|
||||||
遇到问题?查看**测试指南**的"常见问题排查"部分:
|
|
||||||
```
|
|
||||||
/doc/ccblife-frontend-testing-guide.md#常见问题排查
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**测试状态图例**:
|
|
||||||
- ✅ 已完成
|
|
||||||
- ⏳ 待测试
|
|
||||||
- ❌ 失败
|
|
||||||
- ⚠️ 有限制
|
|
||||||
|
|
||||||
*摘要生成时间: 2025-01-17*
|
|
||||||
*作者: Billy*
|
|
||||||
@ -1,363 +0,0 @@
|
|||||||
# 建行生活 uni-app 前端集成指南
|
|
||||||
|
|
||||||
## 概述
|
|
||||||
|
|
||||||
本文档介绍了如何在 Shopro uni-app 前端项目中集成建行生活功能,包括用户登录、支付、专属页面等功能。
|
|
||||||
|
|
||||||
## 已实现的前端功能
|
|
||||||
|
|
||||||
### 1. 平台集成模块
|
|
||||||
|
|
||||||
**位置**: `/frontend/sheep/platform/provider/ccblife/`
|
|
||||||
|
|
||||||
- `index.js` - 建行生活平台核心模块
|
|
||||||
- 环境检测(检测是否在建行App内)
|
|
||||||
- JSBridge 初始化和管理
|
|
||||||
- 用户信息获取
|
|
||||||
- 自动登录
|
|
||||||
- 支付调起
|
|
||||||
- 原生方法调用
|
|
||||||
|
|
||||||
- `api.js` - API 接口封装
|
|
||||||
- URL 跳转登录
|
|
||||||
- 自动登录
|
|
||||||
- 支付串生成
|
|
||||||
- 支付回调
|
|
||||||
|
|
||||||
### 2. 支付集成
|
|
||||||
|
|
||||||
**位置**: `/frontend/sheep/platform/pay.js`
|
|
||||||
|
|
||||||
已在现有支付系统中添加了建行支付(ccb)支持:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 支付方式现在支持
|
|
||||||
payment = ['wechat','alipay','ccb','money','offline']
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 平台识别
|
|
||||||
|
|
||||||
**位置**: `/frontend/sheep/platform/index.js`
|
|
||||||
|
|
||||||
系统会自动识别建行生活环境:
|
|
||||||
- 平台名称:`CcbLife`
|
|
||||||
- 提供商:`ccb`
|
|
||||||
- 平台标识:`ccblife`
|
|
||||||
|
|
||||||
### 4. 建行专属页面
|
|
||||||
|
|
||||||
**位置**: `/frontend/pages/ccblife/index.vue`
|
|
||||||
|
|
||||||
建行生活专属页面,展示:
|
|
||||||
- 建行用户信息
|
|
||||||
- 专属优惠活动
|
|
||||||
- 专享商品
|
|
||||||
- 建行特色功能
|
|
||||||
|
|
||||||
## 使用指南
|
|
||||||
|
|
||||||
### 1. 检测建行环境
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import sheep from '@/sheep';
|
|
||||||
|
|
||||||
// 检查是否在建行App内
|
|
||||||
if (sheep.$platform.provider === 'ccb') {
|
|
||||||
console.log('在建行生活App内');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 或直接使用平台对象
|
|
||||||
import CcbLifePlatform from '@/sheep/platform/provider/ccblife/index';
|
|
||||||
|
|
||||||
if (CcbLifePlatform.isInCcbApp) {
|
|
||||||
console.log('在建行生活App内');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 获取建行用户信息
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import CcbLifePlatform from '@/sheep/platform/provider/ccblife/index';
|
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
CcbLifePlatform.getUserInfo().then(result => {
|
|
||||||
if (result.code === 0) {
|
|
||||||
console.log('用户信息:', result.data);
|
|
||||||
// data包含: ccb_user_id, mobile, nickname, avatar
|
|
||||||
}
|
|
||||||
}).catch(error => {
|
|
||||||
console.error('获取用户信息失败:', error);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 自动登录流程
|
|
||||||
|
|
||||||
平台会自动处理登录流程,无需手动调用:
|
|
||||||
|
|
||||||
1. 用户从建行App进入H5页面
|
|
||||||
2. 系统自动检测建行环境
|
|
||||||
3. 自动获取用户信息并登录
|
|
||||||
4. 保存Token到本地存储
|
|
||||||
|
|
||||||
手动触发登录:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import CcbLifePlatform from '@/sheep/platform/provider/ccblife/index';
|
|
||||||
|
|
||||||
// 手动触发自动登录
|
|
||||||
CcbLifePlatform.autoLogin();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 建行支付集成
|
|
||||||
|
|
||||||
#### 在订单支付页面
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 支付方式选择
|
|
||||||
const payMethods = [
|
|
||||||
{
|
|
||||||
value: 'wechat',
|
|
||||||
name: '微信支付',
|
|
||||||
icon: 'wechat'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'alipay',
|
|
||||||
name: '支付宝',
|
|
||||||
icon: 'alipay'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'ccb',
|
|
||||||
name: '建行支付',
|
|
||||||
icon: 'ccb',
|
|
||||||
// 只在建行App内显示
|
|
||||||
show: sheep.$platform.provider === 'ccb'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 发起支付
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import sheep from '@/sheep';
|
|
||||||
|
|
||||||
// 调起支付
|
|
||||||
sheep.$platform.pay('ccb', 'goods', orderSN);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 监听事件
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 监听登录成功事件
|
|
||||||
uni.$on('ccb:login:success', (data) => {
|
|
||||||
console.log('建行用户登录成功', data);
|
|
||||||
// 更新UI或执行其他操作
|
|
||||||
});
|
|
||||||
|
|
||||||
// 在页面销毁时移除监听
|
|
||||||
onUnmounted(() => {
|
|
||||||
uni.$off('ccb:login:success');
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 条件编译
|
|
||||||
|
|
||||||
在需要区分平台的代码中使用条件编译:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// #ifdef H5
|
|
||||||
import CcbLifePlatform from '@/sheep/platform/provider/ccblife/index';
|
|
||||||
|
|
||||||
if (CcbLifePlatform.isInCcbApp) {
|
|
||||||
// 建行App内的特殊处理
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
```
|
|
||||||
|
|
||||||
## 页面路由配置
|
|
||||||
|
|
||||||
在 `pages.json` 中添加建行相关页面:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"pages": [
|
|
||||||
{
|
|
||||||
"path": "pages/ccblife/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "建行生活",
|
|
||||||
"navigationBarBackgroundColor": "#F51C13",
|
|
||||||
"navigationBarTextStyle": "white"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 测试流程
|
|
||||||
|
|
||||||
### 1. 本地测试
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 进入前端目录
|
|
||||||
cd frontend
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# 运行H5
|
|
||||||
npm run dev:h5
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 模拟建行环境
|
|
||||||
|
|
||||||
在浏览器中添加URL参数模拟建行环境:
|
|
||||||
```
|
|
||||||
http://localhost:3000/#/pages/index/index?from=ccblife&ccbParamSJ=xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 真机测试
|
|
||||||
|
|
||||||
1. 使用 HBuilderX 打包H5应用
|
|
||||||
2. 部署到测试服务器
|
|
||||||
3. 在建行生活App内访问测试地址
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
### 1. 平台判断优先级
|
|
||||||
|
|
||||||
系统按以下优先级判断平台:
|
|
||||||
1. 建行生活 (`CcbLife`)
|
|
||||||
2. 微信公众号 (`WechatOfficialAccount`)
|
|
||||||
3. 普通H5 (`H5`)
|
|
||||||
|
|
||||||
### 2. JSBridge 兼容性
|
|
||||||
|
|
||||||
- iOS:使用 WebViewJavascriptBridge
|
|
||||||
- Android:使用 window.mbspay 对象
|
|
||||||
|
|
||||||
### 3. 支付流程
|
|
||||||
|
|
||||||
1. 用户选择建行支付
|
|
||||||
2. 调用后端生成支付串
|
|
||||||
3. 通过JSBridge调起建行收银台
|
|
||||||
4. 支付完成后回调通知后端
|
|
||||||
5. 更新订单状态
|
|
||||||
|
|
||||||
### 4. 错误处理
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
try {
|
|
||||||
const result = await CcbLifePlatform.payment(options);
|
|
||||||
// 处理成功
|
|
||||||
} catch (error) {
|
|
||||||
if (error.code === -1) {
|
|
||||||
// 不在建行App内
|
|
||||||
uni.showToast({
|
|
||||||
title: '请在建行生活App内使用',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 其他错误
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 常见问题
|
|
||||||
|
|
||||||
### Q: 如何判断是否在建行App内?
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import sheep from '@/sheep';
|
|
||||||
|
|
||||||
// 方式1:通过平台对象
|
|
||||||
if (sheep.$platform.provider === 'ccb') {
|
|
||||||
// 在建行App内
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方式2:直接使用建行平台模块
|
|
||||||
import CcbLifePlatform from '@/sheep/platform/provider/ccblife/index';
|
|
||||||
if (CcbLifePlatform.isInCcbApp) {
|
|
||||||
// 在建行App内
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Q: 自动登录失败怎么办?
|
|
||||||
|
|
||||||
1. 检查是否在建行App内
|
|
||||||
2. 确认后端接口正常
|
|
||||||
3. 查看控制台错误信息
|
|
||||||
4. 清除本地缓存重试
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 清除缓存
|
|
||||||
uni.removeStorageSync('token');
|
|
||||||
uni.removeStorageSync('userInfo');
|
|
||||||
|
|
||||||
// 重新触发登录
|
|
||||||
CcbLifePlatform.autoLogin();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Q: 支付无响应?
|
|
||||||
|
|
||||||
1. 确认在建行App内
|
|
||||||
2. 检查JSBridge是否就绪
|
|
||||||
3. 验证支付串格式
|
|
||||||
4. 查看原生日志
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 检查JSBridge状态
|
|
||||||
CcbLifePlatform.ready(() => {
|
|
||||||
console.log('JSBridge已就绪');
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Q: 如何调试?
|
|
||||||
|
|
||||||
在建行平台模块中开启调试模式:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// frontend/sheep/platform/provider/ccblife/index.js
|
|
||||||
const config = {
|
|
||||||
debug: true // 开启调试
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## 扩展开发
|
|
||||||
|
|
||||||
### 添加新的原生方法调用
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 在 CcbLifePlatform 中添加新方法
|
|
||||||
async customMethod() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.callNative('customMethod', {
|
|
||||||
// 参数
|
|
||||||
}, (result) => {
|
|
||||||
if (result.success) {
|
|
||||||
resolve(result);
|
|
||||||
} else {
|
|
||||||
reject(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 添加新的API接口
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 在 api.js 中添加
|
|
||||||
newApi: (data) => {
|
|
||||||
return request({
|
|
||||||
url: '/ccblife/newApi',
|
|
||||||
method: 'POST',
|
|
||||||
data: data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*文档版本:1.0.0*
|
|
||||||
*最后更新:2025-01-17*
|
|
||||||
*作者:Billy*
|
|
||||||
@ -1,539 +0,0 @@
|
|||||||
# 建行生活H5商城对接 - Bug修复总结
|
|
||||||
|
|
||||||
> 修复时间: 2025-01-18
|
|
||||||
> 审查人员: Billy (Claude Code)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Bug统计
|
|
||||||
|
|
||||||
| 级别 | 数量 | 说明 |
|
|
||||||
|------|------|------|
|
|
||||||
| P0 - 致命 | 7 | 导致功能完全无法使用 |
|
|
||||||
| P1 - 严重 | 0 | 影响核心功能但有workaround |
|
|
||||||
| P2 - 一般 | 0 | 影响次要功能 |
|
|
||||||
| **总计** | **7** | - |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔴 P0级Bug清单
|
|
||||||
|
|
||||||
### Bug #1: MD5签名大小写混用
|
|
||||||
**文件**: `CcbMD5.php`
|
|
||||||
**行号**: 未区分
|
|
||||||
**发现时间**: 初次代码审查
|
|
||||||
|
|
||||||
**问题描述**:
|
|
||||||
代码未区分API接口签名和支付串签名的MD5大小写要求,全部使用大写。
|
|
||||||
|
|
||||||
**错误代码**:
|
|
||||||
```php
|
|
||||||
// 错误:API和支付串都用大写
|
|
||||||
public static function sign($message, $privateKey)
|
|
||||||
{
|
|
||||||
return strtoupper(md5($message . $privateKey));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**根本原因**:
|
|
||||||
根据建行文档:
|
|
||||||
- **API接口签名**: MD5签名后转大写
|
|
||||||
- **支付串签名**: MD5签名后保持小写
|
|
||||||
|
|
||||||
**修复方案**:
|
|
||||||
```php
|
|
||||||
/**
|
|
||||||
* API接口签名(使用大写MD5)
|
|
||||||
*/
|
|
||||||
public static function signApiMessage($message, $privateKey)
|
|
||||||
{
|
|
||||||
return strtoupper(md5($message . $privateKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付串签名(使用小写MD5)
|
|
||||||
*/
|
|
||||||
public static function signPaymentString($params, $privateKey)
|
|
||||||
{
|
|
||||||
return md5($paymentString); // 保持小写
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围**:
|
|
||||||
- ❌ 支付串签名验证失败
|
|
||||||
- ❌ 建行收银台无法打开
|
|
||||||
- ❌ 支付回调签名验证失败
|
|
||||||
|
|
||||||
**验证方法**:
|
|
||||||
```bash
|
|
||||||
# 测试支付串生成
|
|
||||||
php addons/shopro/test/ccblife_test.php
|
|
||||||
# 检查输出的MAC签名是否为小写32位字符串
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Bug #2: 支付串缺少必需参数
|
|
||||||
**文件**: `CcbPaymentService.php`
|
|
||||||
**行号**: 原66-86(已修复)
|
|
||||||
**发现时间**: 初次代码审查
|
|
||||||
|
|
||||||
**问题描述**:
|
|
||||||
支付串只包含10个参数,缺少建行要求的必需参数。
|
|
||||||
|
|
||||||
**错误代码**:
|
|
||||||
```php
|
|
||||||
// 原代码只有10个参数
|
|
||||||
$paymentParams = [
|
|
||||||
'MERCHANTID' => $this->config['merchant_id'],
|
|
||||||
'POSID' => $this->config['pos_id'],
|
|
||||||
'ORDERID' => $payFlowId,
|
|
||||||
'PAYMENT' => $order['total_fee'],
|
|
||||||
// ... 只有10个参数
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
**根本原因**:
|
|
||||||
未按照建行支付串规范包含所有必需字段,特别是:
|
|
||||||
- CLIENTIP(客户端IP)
|
|
||||||
- PROINFO(商品信息)
|
|
||||||
- THIRDAPPINFO(第三方应用信息)
|
|
||||||
- USER_ORDERID(商户订单号)
|
|
||||||
- TIMEOUT(超时时间)
|
|
||||||
|
|
||||||
**修复方案**:
|
|
||||||
```php
|
|
||||||
// 修复后包含18个核心参数
|
|
||||||
$paymentParams = [
|
|
||||||
'MERCHANTID' => $this->config['merchant_id'],
|
|
||||||
'POSID' => $this->config['pos_id'],
|
|
||||||
'BRANCHID' => $this->config['branch_id'],
|
|
||||||
'ORDERID' => $payFlowId, // 支付流水号
|
|
||||||
'PAYMENT' => number_format($order['total_fee'], 2, '.', ''),
|
|
||||||
'CURCODE' => '01',
|
|
||||||
'TXCODE' => '520100',
|
|
||||||
'REMARK1' => '',
|
|
||||||
'REMARK2' => $this->config['service_id'],
|
|
||||||
'TYPE' => '1',
|
|
||||||
'GATEWAY' => '0',
|
|
||||||
'CLIENTIP' => request()->ip(),
|
|
||||||
'REGINFO' => '',
|
|
||||||
'PROINFO' => $this->buildProductInfo($order),
|
|
||||||
'REFERER' => '',
|
|
||||||
'THIRDAPPINFO' => 'comccbpay1234567890cloudmerchant',
|
|
||||||
'USER_ORDERID' => $order['order_sn'], // 商户订单号
|
|
||||||
'TIMEOUT' => date('YmdHis', strtotime('+30 minutes'))
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围**:
|
|
||||||
- ❌ 支付串验证失败
|
|
||||||
- ❌ 建行收银台拒绝请求
|
|
||||||
- ❌ 无法完成支付
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Bug #3: 支付回调notify()方法空实现
|
|
||||||
**文件**: `Ccbpayment.php`
|
|
||||||
**行号**: 原217-230(已修复)
|
|
||||||
**发现时间**: 初次代码审查
|
|
||||||
|
|
||||||
**问题描述**:
|
|
||||||
异步通知方法只有TODO注释,没有实际业务逻辑。
|
|
||||||
|
|
||||||
**错误代码**:
|
|
||||||
```php
|
|
||||||
public function notify()
|
|
||||||
{
|
|
||||||
// TODO: 处理建行异步通知
|
|
||||||
echo 'FAIL';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**根本原因**:
|
|
||||||
开发时未实现异步通知处理逻辑。
|
|
||||||
|
|
||||||
**修复方案**:
|
|
||||||
```php
|
|
||||||
public function notify()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
// 1. 获取原始请求数据
|
|
||||||
$rawData = file_get_contents('php://input');
|
|
||||||
Log::info('[建行通知] 收到异步通知: ' . $rawData);
|
|
||||||
|
|
||||||
// 2. 解析POST参数
|
|
||||||
$params = $this->request->post();
|
|
||||||
if (empty($params) && $rawData) {
|
|
||||||
parse_str($rawData, $params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 验证必需参数
|
|
||||||
if (empty($params['ORDERID'])) {
|
|
||||||
echo 'FAIL';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 调用支付服务处理通知
|
|
||||||
$result = $this->paymentService->handleNotify($params);
|
|
||||||
|
|
||||||
// 5. 返回结果
|
|
||||||
echo $result; // 'SUCCESS' 或 'FAIL'
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::error('[建行通知] 处理失败 error:' . $e->getMessage());
|
|
||||||
echo 'FAIL';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围**:
|
|
||||||
- ❌ 异步通知处理失败
|
|
||||||
- ❌ 订单状态无法自动更新
|
|
||||||
- ❌ 建行会持续重发通知
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Bug #4: 支付流水号与订单号混淆
|
|
||||||
**文件**:
|
|
||||||
- `CcbPaymentService.php` (多处)
|
|
||||||
- `Ccbpayment.php` (多处)
|
|
||||||
|
|
||||||
**行号**: 409, 98, 111, 187-212, 272-283
|
|
||||||
**发现时间**: 深度代码审查
|
|
||||||
|
|
||||||
**问题描述**:
|
|
||||||
代码将支付流水号(pay_flow_id)和订单号(order_sn)混用,特别是在:
|
|
||||||
1. 日志记录时用了 `order_sn` 代替 `pay_flow_id`
|
|
||||||
2. 返回数据时用了 `order_sn` 代替 `pay_flow_id`
|
|
||||||
3. 回调处理时用 `ORDERID` 查询 `order_sn` 字段
|
|
||||||
|
|
||||||
**错误代码**:
|
|
||||||
```php
|
|
||||||
// 错误1: 日志记录
|
|
||||||
Db::name('ccb_payment_log')->insert([
|
|
||||||
'pay_flow_id' => $order['order_sn'], // ❌ 应该用真实的pay_flow_id
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 错误2: 返回数据
|
|
||||||
$this->success('支付串生成成功', [
|
|
||||||
'pay_flow_id' => $result['data']['order_sn'], // ❌ 应该用真实的pay_flow_id
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 错误3: 回调处理
|
|
||||||
$orderSn = $params['ORDERID'] ?? ''; // ❌ ORDERID是支付流水号,不是订单号!
|
|
||||||
$order = Order::where('order_sn', $orderSn)->find(); // ❌ 永远查不到订单
|
|
||||||
```
|
|
||||||
|
|
||||||
**核心概念区分**:
|
|
||||||
```
|
|
||||||
支付流水号 (pay_flow_id):
|
|
||||||
- 格式: PAY + YmdHis + 6位随机数
|
|
||||||
- 示例: PAY20250118143000123456
|
|
||||||
- 用途: 建行支付唯一标识
|
|
||||||
- 对应建行字段: ORDERID
|
|
||||||
|
|
||||||
订单号 (order_sn):
|
|
||||||
- 格式: Shopro系统生成
|
|
||||||
- 示例: SO20250118001
|
|
||||||
- 用途: 商城内部订单标识
|
|
||||||
- 对应建行字段: USER_ORDERID
|
|
||||||
```
|
|
||||||
|
|
||||||
**修复方案**:
|
|
||||||
```php
|
|
||||||
// 修复1: 日志记录
|
|
||||||
'pay_flow_id' => $paymentData['pay_flow_id'] ?? '', // ✅ 使用真实的支付流水号
|
|
||||||
|
|
||||||
// 修复2: 返回数据
|
|
||||||
'pay_flow_id' => $result['data']['pay_flow_id'], // ✅ 返回真实的支付流水号
|
|
||||||
|
|
||||||
// 修复3: 回调处理
|
|
||||||
$payFlowId = $params['ORDERID'] ?? ''; // 支付流水号
|
|
||||||
$userOrderId = $params['USER_ORDERID'] ?? ''; // 商户订单号
|
|
||||||
|
|
||||||
// 优先使用USER_ORDERID查询
|
|
||||||
if (!empty($userOrderId)) {
|
|
||||||
$order = Order::where('order_sn', $userOrderId)->find();
|
|
||||||
} else {
|
|
||||||
$order = Order::where('ccb_pay_flow_id', $payFlowId)->find();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围**:
|
|
||||||
- ❌ 支付日志记录错误
|
|
||||||
- ❌ 前端无法获取正确的支付流水号
|
|
||||||
- ❌ **支付回调100%失败**(订单永远查不到)
|
|
||||||
- ❌ 异步通知100%失败
|
|
||||||
- ❌ 对账数据不准确
|
|
||||||
|
|
||||||
**严重程度**: 🔥🔥🔥 致命(会导致所有支付失败)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Bug #5: 平台公钥字段不存在
|
|
||||||
**文件**: `CcbPaymentService.php`
|
|
||||||
**行号**: 原94-97(已修复)
|
|
||||||
**发现时间**: 用户反馈
|
|
||||||
|
|
||||||
**问题描述**:
|
|
||||||
代码尝试在支付串签名中追加 `PLATFORMPUB` 字段,但建行文档中没有这个参数。
|
|
||||||
|
|
||||||
**错误代码**:
|
|
||||||
```php
|
|
||||||
// 追加平台公钥(如果有)
|
|
||||||
if (!empty($this->config['platform_public_key'])) {
|
|
||||||
$signString .= '&PLATFORMPUB=' . $this->config['platform_public_key'];
|
|
||||||
}
|
|
||||||
$mac = md5($signString . $this->config['private_key']);
|
|
||||||
```
|
|
||||||
|
|
||||||
**根本原因**:
|
|
||||||
对建行签名规则理解错误,误以为需要平台公钥参与签名。
|
|
||||||
|
|
||||||
**正确规则**:
|
|
||||||
```
|
|
||||||
支付串签名 = MD5(参数字符串 + 服务方私钥)
|
|
||||||
不需要平台公钥!
|
|
||||||
```
|
|
||||||
|
|
||||||
**修复方案**:
|
|
||||||
```php
|
|
||||||
// ⚠️ 注意:建行支付串签名规则
|
|
||||||
// 签名 = MD5(参数字符串 + 服务方私钥)
|
|
||||||
// 不需要PLATFORMPUB字段,直接使用私钥签名
|
|
||||||
$mac = md5($signString . $this->config['private_key']);
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围**:
|
|
||||||
- ⚠️ 签名算法错误(如果配置了platform_public_key)
|
|
||||||
- ⚠️ 可能导致签名验证失败
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Bug #6: 订单状态更新字段错误
|
|
||||||
**文件**: `CcbPaymentService.php`
|
|
||||||
**行号**: 原363-374(已修复)
|
|
||||||
**发现时间**: 数据库Schema审查
|
|
||||||
|
|
||||||
**问题描述**:
|
|
||||||
更新订单支付状态时使用了错误的字段名和数据类型。
|
|
||||||
|
|
||||||
**错误代码**:
|
|
||||||
```php
|
|
||||||
Order::where('id', $order['id'])->update([
|
|
||||||
'status' => 'paid',
|
|
||||||
'pay_type' => 'ccb', // ❌ 枚举中没有'ccb'
|
|
||||||
'paytime' => time(), // ❌ 字段名错误,应为paid_time
|
|
||||||
'transaction_id' => $params['ORDERID'] ?? '',
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
**根本原因**:
|
|
||||||
1. Shopro订单表使用 `paid_time` 字段,不是 `paytime`
|
|
||||||
2. `paid_time` 是bigint(16)毫秒时间戳,不是秒级
|
|
||||||
3. `pay_type` 枚举值中没有 `'ccb'` 选项
|
|
||||||
|
|
||||||
**数据库Schema**:
|
|
||||||
```sql
|
|
||||||
-- Shopro订单表字段
|
|
||||||
`paid_time` bigint(16) NULL DEFAULT NULL COMMENT '支付成功时间', -- 毫秒时间戳
|
|
||||||
|
|
||||||
`pay_type` enum('wechat','alipay','money','score','offline') NULL DEFAULT NULL
|
|
||||||
```
|
|
||||||
|
|
||||||
**修复方案**:
|
|
||||||
```php
|
|
||||||
Order::where('id', $order['id'])->update([
|
|
||||||
'status' => 'paid',
|
|
||||||
'pay_type' => 'offline', // ✅ 建行支付归类为线下银行支付
|
|
||||||
'paid_time' => time() * 1000, // ✅ 毫秒时间戳
|
|
||||||
'transaction_id' => $params['ORDERID'] ?? '',
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围**:
|
|
||||||
- ❌ 订单状态更新SQL执行失败
|
|
||||||
- ❌ 支付时间无法记录
|
|
||||||
- ❌ 订单列表显示异常
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Bug #7: 订单字段映射错误
|
|
||||||
**文件**: `CcbOrderService.php`
|
|
||||||
**行号**: 原276-331(已在之前修复)
|
|
||||||
**发现时间**: 初次代码审查
|
|
||||||
|
|
||||||
**问题描述**:
|
|
||||||
订单同步到建行时,使用了错误的Shopro字段名。
|
|
||||||
|
|
||||||
**错误代码**:
|
|
||||||
```php
|
|
||||||
return [
|
|
||||||
'PAY_AMT' => $order['pay_amount'], // ❌ Shopro没有这个字段
|
|
||||||
'PAY_TIME' => date('YmdHis', $order['paytime']), // ❌ 字段名错误
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
**正确字段映射**:
|
|
||||||
| Shopro字段 | 建行字段 | 说明 |
|
|
||||||
|------------|----------|------|
|
|
||||||
| total_fee | PAY_AMT | 实际支付金额 |
|
|
||||||
| paid_time | PAY_TIME | 支付时间(需除以1000) |
|
|
||||||
| discount_fee | - | 优惠金额 |
|
|
||||||
| aftersale_status | REFUND_STATUS | 退款状态 |
|
|
||||||
|
|
||||||
**修复方案**:
|
|
||||||
```php
|
|
||||||
// 计算金额(Shopro使用total_fee作为实际支付)
|
|
||||||
$payAmount = number_format($order['total_fee'] ?? 0, 2, '.', '');
|
|
||||||
|
|
||||||
// 处理支付时间(Shopro paid_time是毫秒时间戳)
|
|
||||||
$payTime = '';
|
|
||||||
if (!empty($order['paid_time'])) {
|
|
||||||
$payTime = date('YmdHis', intval($order['paid_time'] / 1000)); // ✅ 除以1000转为秒
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'PAY_AMT' => $payAmount,
|
|
||||||
'PAY_TIME' => $payTime,
|
|
||||||
'REFUND_STATUS' => $this->mapRefundStatus($order['aftersale_status'] ?? 0),
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
**影响范围**:
|
|
||||||
- ❌ 订单同步到建行失败
|
|
||||||
- ❌ 建行后台订单数据错误
|
|
||||||
- ❌ 对账金额不一致
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📈 修复效果
|
|
||||||
|
|
||||||
### 修复前
|
|
||||||
- ❌ 支付串签名错误
|
|
||||||
- ❌ 支付回调100%失败
|
|
||||||
- ❌ 异步通知无法处理
|
|
||||||
- ❌ 订单状态无法更新
|
|
||||||
- ❌ 订单同步失败
|
|
||||||
|
|
||||||
### 修复后
|
|
||||||
- ✅ 支付串生成正确
|
|
||||||
- ✅ 支付回调正确处理
|
|
||||||
- ✅ 异步通知正确处理
|
|
||||||
- ✅ 订单状态正确更新
|
|
||||||
- ✅ 订单同步正确执行
|
|
||||||
- ✅ 所有自动化测试通过
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 验证方法
|
|
||||||
|
|
||||||
### 1. 运行自动化测试
|
|
||||||
```bash
|
|
||||||
cd /Users/billy/Code/fengketrade.com
|
|
||||||
php addons/shopro/test/ccblife_test.php
|
|
||||||
```
|
|
||||||
|
|
||||||
**预期结果**:
|
|
||||||
```
|
|
||||||
========================================
|
|
||||||
总计: 10 项测试
|
|
||||||
通过: 10 项
|
|
||||||
失败: 0 项
|
|
||||||
========================================
|
|
||||||
🎉 所有测试通过!系统运行正常。
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 手动验证关键点
|
|
||||||
|
|
||||||
**验证支付流水号格式**:
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
order_sn,
|
|
||||||
ccb_pay_flow_id,
|
|
||||||
LENGTH(ccb_pay_flow_id) as length,
|
|
||||||
SUBSTRING(ccb_pay_flow_id, 1, 3) as prefix
|
|
||||||
FROM fa_shopro_order
|
|
||||||
WHERE ccb_pay_flow_id IS NOT NULL;
|
|
||||||
|
|
||||||
-- 预期:
|
|
||||||
-- length = 23
|
|
||||||
-- prefix = 'PAY'
|
|
||||||
```
|
|
||||||
|
|
||||||
**验证订单状态更新**:
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
order_sn,
|
|
||||||
status,
|
|
||||||
pay_type,
|
|
||||||
paid_time,
|
|
||||||
FROM_UNIXTIME(paid_time/1000) as paid_datetime,
|
|
||||||
transaction_id
|
|
||||||
FROM fa_shopro_order
|
|
||||||
WHERE status = 'paid' AND pay_type = 'offline';
|
|
||||||
|
|
||||||
-- 预期:
|
|
||||||
-- status = 'paid'
|
|
||||||
-- pay_type = 'offline'
|
|
||||||
-- paid_time > 0 (毫秒时间戳)
|
|
||||||
-- transaction_id = ccb_pay_flow_id
|
|
||||||
```
|
|
||||||
|
|
||||||
**验证支付日志**:
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
order_sn,
|
|
||||||
pay_flow_id,
|
|
||||||
LENGTH(pay_flow_id) as length,
|
|
||||||
status,
|
|
||||||
amount
|
|
||||||
FROM fa_ccb_payment_log
|
|
||||||
ORDER BY id DESC
|
|
||||||
LIMIT 10;
|
|
||||||
|
|
||||||
-- 预期:
|
|
||||||
-- pay_flow_id 不等于 order_sn
|
|
||||||
-- length = 23
|
|
||||||
-- pay_flow_id 格式: PAY开头
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 总结
|
|
||||||
|
|
||||||
本次代码审查发现并修复了**7个P0级致命bug**,这些bug会导致:
|
|
||||||
|
|
||||||
1. **支付功能完全无法使用**(Bug #2, #4)
|
|
||||||
2. **订单状态无法更新**(Bug #6, #7)
|
|
||||||
3. **回调和通知100%失败**(Bug #3, #4)
|
|
||||||
4. **签名验证失败**(Bug #1, #5)
|
|
||||||
|
|
||||||
修复后,系统核心逻辑已完全正确,可以进行模拟测试。
|
|
||||||
|
|
||||||
**下一步**:
|
|
||||||
1. ✅ 运行自动化测试脚本验证修复
|
|
||||||
2. ⏸️ 等待建行提供测试环境配置
|
|
||||||
3. 🔄 进行真实环境联调测试
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 附录:修改文件清单
|
|
||||||
|
|
||||||
| 文件 | 修改行数 | 修改类型 | 影响 |
|
|
||||||
|------|----------|----------|------|
|
|
||||||
| CcbMD5.php | ~50 | 重构 | 区分API和支付串签名 |
|
|
||||||
| CcbPaymentService.php | ~200 | 重大修复 | 修复支付串生成、回调处理、状态更新 |
|
|
||||||
| CcbOrderService.php | ~50 | 修复 | 修复字段映射 |
|
|
||||||
| Ccbpayment.php | ~100 | 补充实现 | 实现notify()方法 |
|
|
||||||
| CcbPaymentLog.php | +150 | 新建 | 创建支付日志模型 |
|
|
||||||
| CcbSyncLog.php | +150 | 新建 | 创建同步日志模型 |
|
|
||||||
| ccblife_test.php | +600 | 新建 | 创建自动化测试脚本 |
|
|
||||||
| ccblife_test_guide.md | +800 | 新建 | 创建测试指南文档 |
|
|
||||||
|
|
||||||
**总修改**: ~2100行代码
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**文档结束**
|
|
||||||
@ -1,744 +0,0 @@
|
|||||||
# 建行生活H5商城对接 - 测试指南
|
|
||||||
|
|
||||||
> 文档版本: v1.0
|
|
||||||
> 更新时间: 2025-01-18
|
|
||||||
> 作者: Billy
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 目录
|
|
||||||
|
|
||||||
1. [测试概述](#测试概述)
|
|
||||||
2. [测试环境准备](#测试环境准备)
|
|
||||||
3. [自动化测试流程](#自动化测试流程)
|
|
||||||
4. [手动测试流程](#手动测试流程)
|
|
||||||
5. [常见问题排查](#常见问题排查)
|
|
||||||
6. [测试检查清单](#测试检查清单)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 测试概述
|
|
||||||
|
|
||||||
本测试方案分为两个阶段:
|
|
||||||
|
|
||||||
### 🤖 阶段一:模拟测试(当前可用)
|
|
||||||
**目的**: 在没有建行加密数据的情况下,验证系统核心逻辑是否正确
|
|
||||||
|
|
||||||
**范围**:
|
|
||||||
- ✅ 环境配置检查
|
|
||||||
- ✅ 数据库表结构验证
|
|
||||||
- ✅ 用户和订单创建
|
|
||||||
- ✅ 支付串生成逻辑
|
|
||||||
- ✅ 支付流水号规则
|
|
||||||
- ✅ 订单状态更新逻辑
|
|
||||||
- ✅ 字段映射正确性
|
|
||||||
|
|
||||||
**不包含**:
|
|
||||||
- ❌ 真实RSA加密/解密
|
|
||||||
- ❌ 真实建行API调用
|
|
||||||
- ❌ 建行回调签名验证
|
|
||||||
- ❌ JSBridge通信
|
|
||||||
|
|
||||||
### 🌐 阶段二:真实环境测试(需建行配置)
|
|
||||||
**前提**: 已获得建行提供的测试/生产环境配置
|
|
||||||
|
|
||||||
**范围**:
|
|
||||||
- ✅ 完整RSA加密流程
|
|
||||||
- ✅ 建行API接口调用
|
|
||||||
- ✅ 订单同步到建行
|
|
||||||
- ✅ 建行收银台支付
|
|
||||||
- ✅ 支付回调验证
|
|
||||||
- ✅ 异步通知验证
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 测试环境准备
|
|
||||||
|
|
||||||
### 1. 系统要求
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 检查PHP版本(需要 >= 7.0)
|
|
||||||
php -v
|
|
||||||
|
|
||||||
# 检查必需扩展
|
|
||||||
php -m | grep -E 'openssl|pdo|json|mbstring'
|
|
||||||
|
|
||||||
# 检查数据库连接
|
|
||||||
mysql -h <host> -u <user> -p<password> -e "SELECT VERSION();"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 配置文件检查
|
|
||||||
|
|
||||||
确保已创建配置文件:`/application/extra/ccblife.php`
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
return [
|
|
||||||
// 基础配置
|
|
||||||
'merchant_id' => '***', // 商户代码
|
|
||||||
'pos_id' => '***', // 柜台代码
|
|
||||||
'branch_id' => '***', // 分行代码
|
|
||||||
'service_id' => '***', // 服务方编号
|
|
||||||
|
|
||||||
// 密钥配置
|
|
||||||
'private_key' => '***', // 服务方私钥(1024位)
|
|
||||||
'merchant_public_key' => '***', // 商户公钥(1024位)
|
|
||||||
|
|
||||||
// API地址(测试环境)
|
|
||||||
'api_url' => 'http://test.ccb.com/api',
|
|
||||||
'cashier_url' => 'comccbpay://pay',
|
|
||||||
|
|
||||||
// 回调地址
|
|
||||||
'callback_url' => 'https://your-domain.com/addons/shopro/ccbpayment/callback',
|
|
||||||
'notify_url' => 'https://your-domain.com/addons/shopro/ccbpayment/notify',
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 数据库表检查
|
|
||||||
|
|
||||||
确保已执行以下SQL(如未执行):
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- 订单表添加建行支付流水号字段
|
|
||||||
ALTER TABLE `fa_shopro_order`
|
|
||||||
ADD COLUMN `ccb_pay_flow_id` VARCHAR(50) NULL DEFAULT NULL COMMENT '建行支付流水号'
|
|
||||||
AFTER `order_sn`;
|
|
||||||
|
|
||||||
-- 用户表添加建行用户ID字段
|
|
||||||
ALTER TABLE `fa_user`
|
|
||||||
ADD COLUMN `ccb_user_id` VARCHAR(50) NULL DEFAULT NULL COMMENT '建行用户ID'
|
|
||||||
AFTER `mobile`;
|
|
||||||
|
|
||||||
-- 支付日志表(已在install.sql中)
|
|
||||||
-- fa_ccb_payment_log
|
|
||||||
|
|
||||||
-- 同步日志表(已在install.sql中)
|
|
||||||
-- fa_ccb_sync_log
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 自动化测试流程
|
|
||||||
|
|
||||||
### 运行自动化测试脚本
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /Users/billy/Code/fengketrade.com
|
|
||||||
|
|
||||||
# 运行完整测试套件
|
|
||||||
php addons/shopro/test/ccblife_test.php
|
|
||||||
```
|
|
||||||
|
|
||||||
### 预期输出示例
|
|
||||||
|
|
||||||
```
|
|
||||||
========================================
|
|
||||||
建行生活H5商城对接 - 自动化测试
|
|
||||||
========================================
|
|
||||||
测试时间: 2025-01-18 14:30:00
|
|
||||||
========================================
|
|
||||||
|
|
||||||
【环境检查】
|
|
||||||
✓ PHP版本检查 (7.4.33 >= 7.0)
|
|
||||||
✓ 检查OpenSSL扩展
|
|
||||||
✓ 检查PDO扩展
|
|
||||||
✓ 检查JSON扩展
|
|
||||||
✓ 检查文件: CcbPaymentService.php
|
|
||||||
✓ 检查文件: CcbOrderService.php
|
|
||||||
✓ 检查文件: CcbRSA.php
|
|
||||||
✓ 检查文件: CcbMD5.php
|
|
||||||
✓ 检查文件: CcbEncryption.php
|
|
||||||
|
|
||||||
【配置文件检查】
|
|
||||||
✓ 配置文件存在
|
|
||||||
✓ 商户ID配置
|
|
||||||
✓ POS ID配置
|
|
||||||
✓ 分行代码配置
|
|
||||||
✓ 服务方编号配置
|
|
||||||
✓ 服务方私钥配置
|
|
||||||
✓ 商户公钥配置
|
|
||||||
|
|
||||||
【数据库表检查】
|
|
||||||
✓ 检查表: fa_ccb_payment_log
|
|
||||||
✓ 检查表: fa_ccb_sync_log
|
|
||||||
✓ 检查表: fa_shopro_order
|
|
||||||
✓ 检查表: fa_user
|
|
||||||
✓ 检查订单表ccb_pay_flow_id字段
|
|
||||||
|
|
||||||
【创建测试用户】
|
|
||||||
✓ 用户创建成功 (ID: 123)
|
|
||||||
|
|
||||||
【创建测试订单】
|
|
||||||
✓ 订单创建成功 (ID: 456, SN: SO20250118143000001)
|
|
||||||
|
|
||||||
【支付串生成测试】
|
|
||||||
✓ 支付串生成状态
|
|
||||||
✓ 支付串不为空
|
|
||||||
✓ 支付流水号不为空
|
|
||||||
✓ MAC签名不为空
|
|
||||||
✓ 支付流水号长度正确 (23位)
|
|
||||||
✓ 支付流水号前缀正确 (PAY)
|
|
||||||
✓ 订单表支付流水号已更新
|
|
||||||
✓ 支付日志已记录
|
|
||||||
支付串长度: 512 字节
|
|
||||||
支付流水号: PAY20250118143000123456
|
|
||||||
MAC签名: a1b2c3d4e5f6...
|
|
||||||
|
|
||||||
【支付回调测试】
|
|
||||||
✓ 回调处理成功
|
|
||||||
✓ 回调消息正确
|
|
||||||
✓ 订单状态已更新为已支付
|
|
||||||
✓ 支付方式正确 (offline代表建行)
|
|
||||||
✓ 支付时间已记录
|
|
||||||
✓ 交易单号正确
|
|
||||||
订单状态: paid
|
|
||||||
支付时间: 2025-01-18 14:30:05
|
|
||||||
|
|
||||||
【异步通知测试】
|
|
||||||
通知处理结果: fail
|
|
||||||
✓ 通知处理逻辑测试完成
|
|
||||||
|
|
||||||
【订单同步测试】
|
|
||||||
✓ 订单字段 ORD_NUM 存在
|
|
||||||
✓ 订单字段 PAY_AMT 存在
|
|
||||||
✓ 订单字段 ORD_TIME 存在
|
|
||||||
✓ 订单字段 PAY_TIME 存在
|
|
||||||
✓ 订单字段 ORD_STATUS 存在
|
|
||||||
✓ 订单字段 REFUND_STATUS 存在
|
|
||||||
✓ 订单号正确
|
|
||||||
✓ 支付金额正确
|
|
||||||
订单号: SO20250118143000001
|
|
||||||
支付金额: 100.00
|
|
||||||
订单状态: 02
|
|
||||||
|
|
||||||
【清理测试数据】
|
|
||||||
✓ 删除测试订单 (ID: 456)
|
|
||||||
✓ 删除支付日志
|
|
||||||
✓ 删除测试用户 (ID: 123)
|
|
||||||
|
|
||||||
========================================
|
|
||||||
测试报告
|
|
||||||
========================================
|
|
||||||
✓ 通过 环境检查
|
|
||||||
所有环境检查通过
|
|
||||||
✓ 通过 配置文件检查
|
|
||||||
所有配置项完整
|
|
||||||
✓ 通过 数据库表检查
|
|
||||||
所有表结构完整
|
|
||||||
✓ 通过 创建测试用户
|
|
||||||
用户ID: 123
|
|
||||||
✓ 通过 创建测试订单
|
|
||||||
订单ID: 456
|
|
||||||
✓ 通过 支付串生成测试
|
|
||||||
支付流水号: PAY20250118143000123456
|
|
||||||
✓ 通过 支付回调测试
|
|
||||||
支付回调处理成功
|
|
||||||
✓ 通过 异步通知测试
|
|
||||||
通知处理逻辑测试完成
|
|
||||||
✓ 通过 订单同步测试
|
|
||||||
订单数据构建正确
|
|
||||||
✓ 通过 清理测试数据
|
|
||||||
所有测试数据已清理
|
|
||||||
|
|
||||||
========================================
|
|
||||||
总计: 10 项测试
|
|
||||||
通过: 10 项
|
|
||||||
失败: 0 项
|
|
||||||
耗时: 1.23 秒
|
|
||||||
========================================
|
|
||||||
|
|
||||||
🎉 所有测试通过!系统运行正常。
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 手动测试流程
|
|
||||||
|
|
||||||
### 测试1: 前端环境检测
|
|
||||||
|
|
||||||
**目的**: 验证建行生活APP环境识别
|
|
||||||
|
|
||||||
**步骤**:
|
|
||||||
1. 在建行生活APP内打开H5商城链接(待建行提供测试链接)
|
|
||||||
2. 打开浏览器控制台
|
|
||||||
3. 查看输出:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 预期输出
|
|
||||||
[CcbLife] 初始化完成, 是否在建行App内: true
|
|
||||||
[CcbLife] JSBridge 已就绪
|
|
||||||
```
|
|
||||||
|
|
||||||
**验证点**:
|
|
||||||
- `isInCcbApp` 应为 `true`
|
|
||||||
- `isReady` 应为 `true`
|
|
||||||
- User-Agent 包含 'ccblife' 或 'ccb'
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 测试2: 用户自动登录
|
|
||||||
|
|
||||||
**目的**: 验证建行用户自动登录流程
|
|
||||||
|
|
||||||
**前提**:
|
|
||||||
- 测试1通过
|
|
||||||
- 已在建行APP内打开H5商城
|
|
||||||
|
|
||||||
**步骤**:
|
|
||||||
1. 清除商城登录态:`localStorage.clear()`
|
|
||||||
2. 刷新页面
|
|
||||||
3. 观察控制台输出
|
|
||||||
|
|
||||||
**预期输出**:
|
|
||||||
```
|
|
||||||
[CcbLife] 自动登录成功
|
|
||||||
```
|
|
||||||
|
|
||||||
**验证点**:
|
|
||||||
- `localStorage.getItem('token')` 不为空
|
|
||||||
- `localStorage.getItem('userInfo')` 包含用户信息
|
|
||||||
- 数据库 `fa_user` 表中 `ccb_user_id` 已绑定
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 测试3: 创建订单
|
|
||||||
|
|
||||||
**目的**: 验证订单创建流程
|
|
||||||
|
|
||||||
**步骤**:
|
|
||||||
1. 选择商品加入购物车
|
|
||||||
2. 进入结算页
|
|
||||||
3. 填写收货地址
|
|
||||||
4. 提交订单
|
|
||||||
|
|
||||||
**验证点**:
|
|
||||||
- 订单创建成功,返回订单ID和订单号
|
|
||||||
- 数据库 `fa_shopro_order` 表中订单状态为 `unpaid`
|
|
||||||
- `ccb_pay_flow_id` 字段为空
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 测试4: 生成支付串
|
|
||||||
|
|
||||||
**目的**: 验证支付串生成逻辑
|
|
||||||
|
|
||||||
**接口**: `POST /addons/shopro/ccbpayment/pay`
|
|
||||||
|
|
||||||
**请求参数**:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"order_id": 123
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**预期响应**:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 1,
|
|
||||||
"msg": "支付串生成成功",
|
|
||||||
"data": {
|
|
||||||
"payment_string": "MERCHANTID=...&POSID=...&MAC=...",
|
|
||||||
"payment_url": "comccbpay://pay?MERCHANTID=...&MAC=...",
|
|
||||||
"mac": "a1b2c3d4e5f6...",
|
|
||||||
"order_id": 123,
|
|
||||||
"order_sn": "SO20250118001",
|
|
||||||
"pay_flow_id": "PAY20250118143000123456",
|
|
||||||
"amount": "100.00"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**验证点**:
|
|
||||||
1. `payment_string` 包含所有必需参数
|
|
||||||
2. `pay_flow_id` 格式正确(PAY + 14位时间戳 + 6位随机数)
|
|
||||||
3. `mac` 签名不为空
|
|
||||||
4. 数据库订单表 `ccb_pay_flow_id` 已更新
|
|
||||||
5. `fa_ccb_payment_log` 表中已记录支付请求
|
|
||||||
|
|
||||||
**关键参数检查**:
|
|
||||||
```javascript
|
|
||||||
// 从 payment_string 中提取参数
|
|
||||||
const params = new URLSearchParams(payment_string);
|
|
||||||
|
|
||||||
console.log('ORDERID:', params.get('ORDERID')); // 应等于 pay_flow_id
|
|
||||||
console.log('USER_ORDERID:', params.get('USER_ORDERID')); // 应等于 order_sn
|
|
||||||
console.log('PAYMENT:', params.get('PAYMENT')); // 应等于订单实际支付金额
|
|
||||||
console.log('MAC:', params.get('MAC')); // MD5签名
|
|
||||||
console.log('PLATFORMID:', params.get('PLATFORMID')); // 服务方编号
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 测试5: 调起支付(需建行环境)
|
|
||||||
|
|
||||||
**目的**: 验证JSBridge调起建行收银台
|
|
||||||
|
|
||||||
**前提**:
|
|
||||||
- 测试1-4全部通过
|
|
||||||
- 已在建行APP内
|
|
||||||
|
|
||||||
**步骤**:
|
|
||||||
1. 点击"去支付"按钮
|
|
||||||
2. 前端调用 `CcbLifePlatform.payment()`
|
|
||||||
|
|
||||||
**前端代码示例**:
|
|
||||||
```javascript
|
|
||||||
// sheep/platform/provider/ccblife/index.js
|
|
||||||
|
|
||||||
const paymentResult = await CcbLifePlatform.payment({
|
|
||||||
payment_string: '支付串内容'
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('支付结果:', paymentResult);
|
|
||||||
```
|
|
||||||
|
|
||||||
**iOS预期行为**:
|
|
||||||
- 跳转到 `comccbpay://pay?支付参数`
|
|
||||||
- 打开建行收银台
|
|
||||||
|
|
||||||
**Android预期行为**:
|
|
||||||
- 调用 `window.mbspay.payment()`
|
|
||||||
- 打开建行收银台
|
|
||||||
|
|
||||||
**验证点**:
|
|
||||||
- 收银台显示正确的订单金额
|
|
||||||
- 收银台显示正确的商品信息
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 测试6: 支付回调(需建行环境)
|
|
||||||
|
|
||||||
**目的**: 验证支付完成后的同步回调
|
|
||||||
|
|
||||||
**触发方式**:
|
|
||||||
- 在建行收银台完成支付(或取消支付)
|
|
||||||
- 建行会重定向到 `callback_url`
|
|
||||||
|
|
||||||
**回调URL示例**:
|
|
||||||
```
|
|
||||||
https://your-domain.com/addons/shopro/ccbpayment/callback?ccbParamSJ=加密参数
|
|
||||||
```
|
|
||||||
|
|
||||||
**预期流程**:
|
|
||||||
1. 解密 `ccbParamSJ` 参数
|
|
||||||
2. 获取支付结果参数
|
|
||||||
3. 根据 `SUCCESS=Y/N` 判断支付成功或失败
|
|
||||||
4. 更新订单状态
|
|
||||||
|
|
||||||
**支付成功验证点**:
|
|
||||||
- 订单状态 → `paid`
|
|
||||||
- 支付时间 `paid_time` 已记录(毫秒时间戳)
|
|
||||||
- 支付方式 `pay_type` → `offline`
|
|
||||||
- 交易单号 `transaction_id` → 支付流水号
|
|
||||||
- 页面跳转到订单详情或支付成功页
|
|
||||||
|
|
||||||
**支付失败验证点**:
|
|
||||||
- 订单状态保持 `unpaid`
|
|
||||||
- 页面显示失败原因
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 测试7: 异步通知(需建行环境)
|
|
||||||
|
|
||||||
**目的**: 验证建行异步通知处理
|
|
||||||
|
|
||||||
**触发方式**:
|
|
||||||
- 支付成功后,建行会POST请求到 `notify_url`
|
|
||||||
|
|
||||||
**接口**: `POST /addons/shopro/ccbpayment/notify`
|
|
||||||
|
|
||||||
**建行会发送的参数**(示例):
|
|
||||||
```
|
|
||||||
POST数据:
|
|
||||||
ORDERID=PAY20250118143000123456
|
|
||||||
&USER_ORDERID=SO20250118001
|
|
||||||
&POSID=100001
|
|
||||||
&PAYMENT=100.00
|
|
||||||
&SUCCESS=Y
|
|
||||||
&SIGN=签名值
|
|
||||||
```
|
|
||||||
|
|
||||||
**预期处理逻辑**:
|
|
||||||
1. 验证签名 `SIGN`
|
|
||||||
2. 验证 `POSID` 是否匹配
|
|
||||||
3. 根据 `USER_ORDERID` 或 `ccb_pay_flow_id` 查询订单
|
|
||||||
4. 更新订单状态
|
|
||||||
5. 返回 `SUCCESS` 或 `FAIL`
|
|
||||||
|
|
||||||
**验证点**:
|
|
||||||
- 响应体必须返回字符串 `SUCCESS` 或 `FAIL`
|
|
||||||
- 订单状态正确更新
|
|
||||||
- 日志 `runtime/log/` 中记录通知详情
|
|
||||||
|
|
||||||
**测试异步通知的方法**(模拟建行POST请求):
|
|
||||||
```bash
|
|
||||||
curl -X POST 'https://your-domain.com/addons/shopro/ccbpayment/notify' \
|
|
||||||
-H 'Content-Type: application/x-www-form-urlencoded' \
|
|
||||||
-d 'ORDERID=PAY20250118143000123456&USER_ORDERID=SO20250118001&POSID=100001&PAYMENT=100.00&SUCCESS=Y&SIGN=mock_sign'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 测试8: 订单同步到建行(需建行环境)
|
|
||||||
|
|
||||||
**目的**: 验证支付成功后订单推送到建行
|
|
||||||
|
|
||||||
**触发时机**:
|
|
||||||
- 支付回调成功后自动触发
|
|
||||||
- 或手动调用同步接口
|
|
||||||
|
|
||||||
**手动触发方式**:
|
|
||||||
```php
|
|
||||||
$orderService = new \addons\shopro\library\ccblife\CcbOrderService();
|
|
||||||
$result = $orderService->pushOrder($orderId);
|
|
||||||
|
|
||||||
var_dump($result);
|
|
||||||
```
|
|
||||||
|
|
||||||
**验证点**:
|
|
||||||
1. API请求成功(HTTP 200)
|
|
||||||
2. 返回 `CLD_HEAD.ERR_CODE === '0'`
|
|
||||||
3. `fa_ccb_sync_log` 表中记录同步成功
|
|
||||||
4. 订单同步状态更新
|
|
||||||
|
|
||||||
**失败处理**:
|
|
||||||
- 如果同步失败,日志中记录错误原因
|
|
||||||
- 支持重试机制(通过定时任务)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 常见问题排查
|
|
||||||
|
|
||||||
### 问题1: 支付串生成失败
|
|
||||||
|
|
||||||
**错误信息**: "订单状态不正确"
|
|
||||||
|
|
||||||
**原因**: 订单已支付或已关闭
|
|
||||||
|
|
||||||
**解决**:
|
|
||||||
```sql
|
|
||||||
-- 检查订单状态
|
|
||||||
SELECT id, order_sn, status, pay_status FROM fa_shopro_order WHERE id = <order_id>;
|
|
||||||
|
|
||||||
-- 如需重测,重置订单状态
|
|
||||||
UPDATE fa_shopro_order SET status = 'unpaid', pay_status = 'unpaid' WHERE id = <order_id>;
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 问题2: 支付串签名错误
|
|
||||||
|
|
||||||
**错误信息**: "签名验证失败"
|
|
||||||
|
|
||||||
**排查步骤**:
|
|
||||||
1. 检查配置文件中私钥是否正确
|
|
||||||
2. 检查参数是否按ASCII排序
|
|
||||||
3. 检查MD5签名是否为小写
|
|
||||||
|
|
||||||
**验证签名算法**:
|
|
||||||
```php
|
|
||||||
// 测试代码
|
|
||||||
$params = [/* 支付参数 */];
|
|
||||||
ksort($params);
|
|
||||||
$signString = http_build_query($params);
|
|
||||||
$mac = md5($signString . config('ccblife.private_key'));
|
|
||||||
|
|
||||||
echo "签名字符串: {$signString}\n";
|
|
||||||
echo "MAC签名: {$mac}\n";
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 问题3: 订单查询失败
|
|
||||||
|
|
||||||
**错误信息**: "订单不存在"
|
|
||||||
|
|
||||||
**原因**:
|
|
||||||
- 使用了错误的订单号字段
|
|
||||||
- ORDERID(支付流水号)和 USER_ORDERID(商户订单号)混淆
|
|
||||||
|
|
||||||
**排查**:
|
|
||||||
```sql
|
|
||||||
-- 检查订单数据
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
order_sn, -- 商户订单号
|
|
||||||
ccb_pay_flow_id, -- 建行支付流水号
|
|
||||||
status
|
|
||||||
FROM fa_shopro_order
|
|
||||||
WHERE order_sn = 'SO20250118001' -- 使用商户订单号查询
|
|
||||||
OR ccb_pay_flow_id = 'PAY20250118143000123456'; -- 使用支付流水号查询
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 问题4: 订单状态未更新
|
|
||||||
|
|
||||||
**可能原因**:
|
|
||||||
1. 字段名错误(`paytime` vs `paid_time`)
|
|
||||||
2. 时间戳单位错误(秒 vs 毫秒)
|
|
||||||
3. `pay_type` 枚举值不存在
|
|
||||||
|
|
||||||
**验证**:
|
|
||||||
```sql
|
|
||||||
-- 检查订单表字段
|
|
||||||
SHOW COLUMNS FROM fa_shopro_order LIKE 'paid_time';
|
|
||||||
|
|
||||||
-- 检查pay_type枚举值
|
|
||||||
SHOW COLUMNS FROM fa_shopro_order LIKE 'pay_type';
|
|
||||||
|
|
||||||
-- 查看订单更新时间
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
paid_time, -- 应为毫秒时间戳
|
|
||||||
FROM_UNIXTIME(paid_time/1000) as paid_datetime,
|
|
||||||
pay_type, -- 应为 'offline'
|
|
||||||
status
|
|
||||||
FROM fa_shopro_order
|
|
||||||
WHERE id = <order_id>;
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 问题5: RSA加密失败
|
|
||||||
|
|
||||||
**错误信息**: "RSA加密失败" 或 "key size too small"
|
|
||||||
|
|
||||||
**原因**:
|
|
||||||
- 密钥格式不正确
|
|
||||||
- 密钥长度不是1024位
|
|
||||||
- 数据块大小超过117字节
|
|
||||||
|
|
||||||
**验证密钥**:
|
|
||||||
```bash
|
|
||||||
# 检查私钥
|
|
||||||
echo "<私钥内容>" | openssl rsa -text -noout
|
|
||||||
|
|
||||||
# 检查公钥
|
|
||||||
echo "<公钥内容>" | openssl rsa -pubin -text -noout
|
|
||||||
|
|
||||||
# 查看密钥长度
|
|
||||||
# 应显示: Private-Key: (1024 bit)
|
|
||||||
```
|
|
||||||
|
|
||||||
**修复**:
|
|
||||||
1. 确保密钥包含完整的 `-----BEGIN` 和 `-----END` 标记
|
|
||||||
2. 数据分块处理,每块不超过117字节
|
|
||||||
3. 使用正确的填充模式 `OPENSSL_PKCS1_PADDING`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 测试检查清单
|
|
||||||
|
|
||||||
### ✅ 阶段一:模拟测试(可立即执行)
|
|
||||||
|
|
||||||
- [ ] 运行自动化测试脚本,所有测试通过
|
|
||||||
- [ ] 配置文件已正确配置
|
|
||||||
- [ ] 数据库表结构完整
|
|
||||||
- [ ] 订单表 `ccb_pay_flow_id` 字段存在
|
|
||||||
- [ ] 用户表 `ccb_user_id` 字段存在
|
|
||||||
- [ ] 支付日志表 `fa_ccb_payment_log` 存在
|
|
||||||
- [ ] 同步日志表 `fa_ccb_sync_log` 存在
|
|
||||||
- [ ] 支付串生成逻辑正确
|
|
||||||
- [ ] 支付流水号格式正确(PAY+14位+6位)
|
|
||||||
- [ ] 订单字段映射正确(paid_time、total_fee等)
|
|
||||||
|
|
||||||
### ✅ 阶段二:真实环境测试(需建行配置)
|
|
||||||
|
|
||||||
- [ ] 已获得建行测试环境配置
|
|
||||||
- [ ] RSA密钥对配置正确(1024位)
|
|
||||||
- [ ] API地址配置正确
|
|
||||||
- [ ] 回调地址已配置且可访问
|
|
||||||
- [ ] 在建行APP内能正确识别环境
|
|
||||||
- [ ] JSBridge初始化成功
|
|
||||||
- [ ] 用户自动登录成功
|
|
||||||
- [ ] ccb_user_id正确绑定
|
|
||||||
- [ ] 支付串加密正确(ENCPUB字段)
|
|
||||||
- [ ] 建行收银台能正确打开
|
|
||||||
- [ ] 支付回调能正确接收和处理
|
|
||||||
- [ ] 异步通知能正确接收和处理
|
|
||||||
- [ ] 签名验证通过
|
|
||||||
- [ ] 订单状态正确更新
|
|
||||||
- [ ] 订单同步到建行成功
|
|
||||||
- [ ] 重复通知幂等性处理正确
|
|
||||||
- [ ] 小额支付测试通过(0.01元)
|
|
||||||
- [ ] 正常金额支付测试通过
|
|
||||||
- [ ] 支付取消测试通过
|
|
||||||
- [ ] 支付超时测试通过
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 附录
|
|
||||||
|
|
||||||
### A. 支付流水号规则
|
|
||||||
|
|
||||||
```
|
|
||||||
格式: PAY + YmdHis(14位) + 随机数(6位)
|
|
||||||
示例: PAY20250118143000123456
|
|
||||||
长度: 23位固定长度
|
|
||||||
|
|
||||||
组成:
|
|
||||||
- PAY: 固定前缀(3位)
|
|
||||||
- 20250118143000: 时间戳 yyMMddHHmmss (14位)
|
|
||||||
- 123456: 随机数 (6位)
|
|
||||||
```
|
|
||||||
|
|
||||||
### B. 重要字段映射表
|
|
||||||
|
|
||||||
| Shopro字段 | 建行字段 | 说明 | 示例 |
|
|
||||||
|------------|----------|------|------|
|
|
||||||
| order_sn | USER_ORDERID | 商户订单号 | SO20250118001 |
|
|
||||||
| ccb_pay_flow_id | ORDERID | 建行支付流水号 | PAY20250118143000123456 |
|
|
||||||
| total_fee | PAYMENT / PAY_AMT | 实际支付金额 | 100.00 |
|
|
||||||
| discount_fee | - | 优惠金额 | 5.00 |
|
|
||||||
| paid_time | PAY_TIME | 支付时间(毫秒) | 1737183000000 |
|
|
||||||
| createtime | ORD_TIME | 订单创建时间(秒) | 20250118143000 |
|
|
||||||
| status | ORD_STATUS | 订单状态 | paid → 02 |
|
|
||||||
| pay_type | - | 支付方式 | offline(代表建行) |
|
|
||||||
| transaction_id | ORDERID | 交易单号 | PAY20250118143000123456 |
|
|
||||||
|
|
||||||
### C. 订单状态映射
|
|
||||||
|
|
||||||
| Shopro状态 | 建行状态码 | 说明 |
|
|
||||||
|-----------|-----------|------|
|
|
||||||
| unpaid | 01 | 未支付 |
|
|
||||||
| paid | 02 | 已支付 |
|
|
||||||
| closed | 03 | 已关闭 |
|
|
||||||
| cancelled | 04 | 已取消 |
|
|
||||||
|
|
||||||
### D. 日志文件位置
|
|
||||||
|
|
||||||
```
|
|
||||||
建行支付日志:
|
|
||||||
- runtime/log/202501/18.log
|
|
||||||
|
|
||||||
关键日志标识:
|
|
||||||
- [建行支付] 支付串生成
|
|
||||||
- [建行支付] 生成支付串失败
|
|
||||||
- [建行回调] 收到同步回调
|
|
||||||
- [建行通知] 收到异步通知
|
|
||||||
- [建行订单同步] 推送订单
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 总结
|
|
||||||
|
|
||||||
本测试指南提供了完整的测试方案,分为两个阶段:
|
|
||||||
|
|
||||||
1. **模拟测试阶段**(当前可用)
|
|
||||||
- 运行自动化测试脚本即可验证核心逻辑
|
|
||||||
- 无需建行真实配置
|
|
||||||
- 适合开发阶段自测
|
|
||||||
|
|
||||||
2. **真实环境测试阶段**(需建行配置)
|
|
||||||
- 需要建行提供测试环境
|
|
||||||
- 包含完整的支付流程
|
|
||||||
- 适合联调和上线前测试
|
|
||||||
|
|
||||||
**下一步行动**:
|
|
||||||
1. ✅ 立即运行自动化测试脚本
|
|
||||||
2. ⏸️ 等待建行提供测试环境配置
|
|
||||||
3. 🔄 获得配置后执行阶段二测试
|
|
||||||
|
|
||||||
**如有问题,请查看"常见问题排查"章节或联系开发人员。**
|
|
||||||
@ -1,579 +0,0 @@
|
|||||||
# Shopro 前端项目部署指南
|
|
||||||
|
|
||||||
## 概述
|
|
||||||
|
|
||||||
本文档描述如何将 Shopro uni-app 前端项目打包并部署到生产环境 `https://app.fengketrade.com`。
|
|
||||||
|
|
||||||
## 环境配置
|
|
||||||
|
|
||||||
### 生产环境配置已完成 ✅
|
|
||||||
|
|
||||||
`.env` 文件已配置:
|
|
||||||
```env
|
|
||||||
# 正式环境接口域名
|
|
||||||
SHOPRO_BASE_URL = https://app.fengketrade.com
|
|
||||||
|
|
||||||
# 开发环境接口域名
|
|
||||||
SHOPRO_DEV_BASE_URL = https://app.fengketrade.com
|
|
||||||
|
|
||||||
# 开发环境运行端口
|
|
||||||
SHOPRO_DEV_PORT = 3000
|
|
||||||
|
|
||||||
# 接口地址前缀
|
|
||||||
SHOPRO_API_PATH = /addons/shopro/
|
|
||||||
```
|
|
||||||
|
|
||||||
## 打包方法
|
|
||||||
|
|
||||||
### 方法一:使用 HBuilderX 打包(推荐)
|
|
||||||
|
|
||||||
这是 uni-app 官方推荐的打包方式,最稳定可靠。
|
|
||||||
|
|
||||||
#### 步骤 1: 准备 HBuilderX
|
|
||||||
|
|
||||||
1. **下载 HBuilderX**
|
|
||||||
- 官网:https://www.dcloud.io/hbuilderx.html
|
|
||||||
- 选择"正式版" → "标准版"即可
|
|
||||||
|
|
||||||
2. **安装必要插件**
|
|
||||||
- 启动 HBuilderX
|
|
||||||
- 工具 → 插件安装 → 搜索"uni-app编译"
|
|
||||||
- 安装"uni-app (Vue3)"编译器
|
|
||||||
|
|
||||||
#### 步骤 2: 打开项目
|
|
||||||
|
|
||||||
1. 文件 → 打开目录
|
|
||||||
2. 选择:`/Users/billy/Code/fengketrade.com/frontend`
|
|
||||||
3. 等待项目加载完成
|
|
||||||
|
|
||||||
#### 步骤 3: H5 打包
|
|
||||||
|
|
||||||
1. **发行到 H5**
|
|
||||||
- 发行 → 网站-H5手机版
|
|
||||||
- 或者点击菜单:发行 → 网站-PC Web或App(适用于宽屏应用)
|
|
||||||
|
|
||||||
2. **配置打包选项**
|
|
||||||
```
|
|
||||||
网站标题:风刻商城
|
|
||||||
网站域名:https://app.fengketrade.com
|
|
||||||
路由模式:hash(推荐)或 history
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **点击"发行"**
|
|
||||||
- 等待编译完成
|
|
||||||
- 控制台会显示编译进度
|
|
||||||
|
|
||||||
4. **查看打包结果**
|
|
||||||
```
|
|
||||||
打包目录:/Users/billy/Code/fengketrade.com/frontend/unpackage/dist/build/h5
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 步骤 4: 部署到服务器
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /Users/billy/Code/fengketrade.com/frontend
|
|
||||||
|
|
||||||
# 压缩打包文件(排除 macOS 元数据)
|
|
||||||
tar --no-mac-metadata --no-xattrs --exclude='.DS_Store' \
|
|
||||||
-czf h5-dist.tar.gz -C unpackage/dist/build/h5 .
|
|
||||||
|
|
||||||
# 上传到服务器
|
|
||||||
scp h5-dist.tar.gz user@app.fengketrade.com:/tmp/
|
|
||||||
|
|
||||||
# 登录服务器
|
|
||||||
ssh user@app.fengketrade.com
|
|
||||||
|
|
||||||
# 解压到 Web 目录
|
|
||||||
cd /path/to/web/root
|
|
||||||
mkdir -p h5
|
|
||||||
tar -xzf /tmp/h5-dist.tar.gz -C h5/
|
|
||||||
|
|
||||||
# 设置权限
|
|
||||||
chown -R www-data:www-data h5/
|
|
||||||
chmod -R 755 h5/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法二:使用命令行打包
|
|
||||||
|
|
||||||
如果已安装 uni-app CLI 工具,可以使用命令行打包。
|
|
||||||
|
|
||||||
#### 步骤 1: 安装 uni-app CLI
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /Users/billy/Code/fengketrade.com/frontend
|
|
||||||
|
|
||||||
# 安装 uni-app 编译器(如果还没安装)
|
|
||||||
npm install -g @dcloudio/uvm
|
|
||||||
uvm
|
|
||||||
|
|
||||||
# 或直接安装依赖
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 步骤 2: 添加构建脚本
|
|
||||||
|
|
||||||
编辑 `package.json`,添加以下脚本:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"dev:h5": "uni -p h5",
|
|
||||||
"build:h5": "uni build -p h5",
|
|
||||||
"build:h5:prod": "cross-env NODE_ENV=production uni build -p h5",
|
|
||||||
"prettier": "prettier --write \"{pages,sheep}/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 步骤 3: 执行打包
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 开发环境打包
|
|
||||||
npm run build:h5
|
|
||||||
|
|
||||||
# 生产环境打包(压缩优化)
|
|
||||||
npm run build:h5:prod
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 步骤 4: 查看打包结果
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ls -lh unpackage/dist/build/h5/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法三:快速部署脚本(自动化)
|
|
||||||
|
|
||||||
创建自动化部署脚本。
|
|
||||||
|
|
||||||
#### 创建部署脚本
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat > deploy-frontend.sh << 'EOF'
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 前端自动化部署脚本
|
|
||||||
# 作者: Billy
|
|
||||||
# 日期: 2025-01-17
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "=== 前端部署脚本 ==="
|
|
||||||
|
|
||||||
# 配置
|
|
||||||
PROJECT_DIR="/Users/billy/Code/fengketrade.com/frontend"
|
|
||||||
BUILD_DIR="$PROJECT_DIR/unpackage/dist/build/h5"
|
|
||||||
SERVER_USER="your_user"
|
|
||||||
SERVER_HOST="app.fengketrade.com"
|
|
||||||
SERVER_PATH="/var/www/html/h5"
|
|
||||||
BACKUP_DIR="/var/www/backup"
|
|
||||||
|
|
||||||
# 颜色输出
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
RED='\033[0;31m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
echo -e "${YELLOW}步骤 1: 检查环境...${NC}"
|
|
||||||
cd "$PROJECT_DIR"
|
|
||||||
|
|
||||||
if [ ! -d "node_modules" ]; then
|
|
||||||
echo -e "${YELLOW}安装依赖...${NC}"
|
|
||||||
npm install
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✓ 环境检查完成${NC}"
|
|
||||||
|
|
||||||
echo -e "${YELLOW}步骤 2: 清理旧文件...${NC}"
|
|
||||||
rm -rf unpackage/dist/build/h5
|
|
||||||
|
|
||||||
echo -e "${YELLOW}步骤 3: 开始打包...${NC}"
|
|
||||||
# 如果有 HBuilderX CLI
|
|
||||||
if command -v cli &> /dev/null; then
|
|
||||||
cli publish --platform h5 --project "$PROJECT_DIR"
|
|
||||||
# 或使用 npm
|
|
||||||
elif [ -f "package.json" ]; then
|
|
||||||
npm run build:h5:prod || npm run build:h5
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ 找不到构建工具,请使用 HBuilderX 手动打包${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✓ 打包完成${NC}"
|
|
||||||
|
|
||||||
echo -e "${YELLOW}步骤 4: 压缩文件...${NC}"
|
|
||||||
cd "$PROJECT_DIR"
|
|
||||||
tar --no-mac-metadata --no-xattrs --exclude='.DS_Store' \
|
|
||||||
-czf h5-dist-$(date +%Y%m%d-%H%M%S).tar.gz -C "$BUILD_DIR" .
|
|
||||||
|
|
||||||
ARCHIVE_NAME=$(ls -t h5-dist-*.tar.gz | head -1)
|
|
||||||
echo -e "${GREEN}✓ 压缩完成: $ARCHIVE_NAME${NC}"
|
|
||||||
|
|
||||||
echo -e "${YELLOW}步骤 5: 上传到服务器...${NC}"
|
|
||||||
scp "$ARCHIVE_NAME" "$SERVER_USER@$SERVER_HOST:/tmp/"
|
|
||||||
|
|
||||||
echo -e "${YELLOW}步骤 6: 部署到服务器...${NC}"
|
|
||||||
ssh "$SERVER_USER@$SERVER_HOST" << ENDSSH
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# 创建备份
|
|
||||||
if [ -d "$SERVER_PATH" ]; then
|
|
||||||
echo "备份当前版本..."
|
|
||||||
sudo mkdir -p "$BACKUP_DIR"
|
|
||||||
sudo tar -czf "$BACKUP_DIR/h5-backup-\$(date +%Y%m%d-%H%M%S).tar.gz" \
|
|
||||||
-C "$SERVER_PATH" . || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 解压新版本
|
|
||||||
echo "部署新版本..."
|
|
||||||
sudo mkdir -p "$SERVER_PATH"
|
|
||||||
sudo tar -xzf "/tmp/$ARCHIVE_NAME" -C "$SERVER_PATH"
|
|
||||||
|
|
||||||
# 设置权限
|
|
||||||
sudo chown -R www-data:www-data "$SERVER_PATH"
|
|
||||||
sudo chmod -R 755 "$SERVER_PATH"
|
|
||||||
|
|
||||||
# 清理临时文件
|
|
||||||
rm -f "/tmp/$ARCHIVE_NAME"
|
|
||||||
|
|
||||||
echo "部署完成!"
|
|
||||||
ENDSSH
|
|
||||||
|
|
||||||
echo -e "${GREEN}=== 部署成功!===${NC}"
|
|
||||||
echo -e "${GREEN}访问地址: https://app.fengketrade.com/h5${NC}"
|
|
||||||
|
|
||||||
# 清理本地临时文件
|
|
||||||
rm -f "$ARCHIVE_NAME"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod +x deploy-frontend.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用部署脚本
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 修改脚本中的服务器配置
|
|
||||||
vim deploy-frontend.sh
|
|
||||||
|
|
||||||
# 执行部署
|
|
||||||
./deploy-frontend.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## 部署后配置
|
|
||||||
|
|
||||||
### Nginx 配置
|
|
||||||
|
|
||||||
#### H5 项目配置
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
# /etc/nginx/sites-available/app.fengketrade.com
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
listen 443 ssl http2;
|
|
||||||
server_name app.fengketrade.com;
|
|
||||||
|
|
||||||
# SSL 证书配置
|
|
||||||
ssl_certificate /path/to/ssl/cert.pem;
|
|
||||||
ssl_certificate_key /path/to/ssl/key.pem;
|
|
||||||
|
|
||||||
# 强制 HTTPS
|
|
||||||
if ($scheme != "https") {
|
|
||||||
return 301 https://$server_name$request_uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
# H5 前端
|
|
||||||
location /h5 {
|
|
||||||
alias /var/www/html/h5;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# 解决 Vue Router history 模式 404
|
|
||||||
try_files $uri $uri/ /h5/index.html;
|
|
||||||
|
|
||||||
# 静态资源缓存
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
||||||
expires 30d;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTML 不缓存
|
|
||||||
location ~* \.html$ {
|
|
||||||
expires -1;
|
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# API 代理到 PHP 后端
|
|
||||||
location /addons/shopro {
|
|
||||||
proxy_pass http://127.0.0.1:8080;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 建行测试页面
|
|
||||||
location /ccblife-demo.html {
|
|
||||||
alias /var/www/html/public/ccblife-demo.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 静态资源
|
|
||||||
location /static {
|
|
||||||
alias /var/www/html/public;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 重启 Nginx
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 测试配置
|
|
||||||
sudo nginx -t
|
|
||||||
|
|
||||||
# 重启服务
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
### Apache 配置(如果使用 Apache)
|
|
||||||
|
|
||||||
```apache
|
|
||||||
<VirtualHost *:443>
|
|
||||||
ServerName app.fengketrade.com
|
|
||||||
DocumentRoot /var/www/html
|
|
||||||
|
|
||||||
# SSL 配置
|
|
||||||
SSLEngine on
|
|
||||||
SSLCertificateFile /path/to/ssl/cert.pem
|
|
||||||
SSLCertificateKeyFile /path/to/ssl/key.pem
|
|
||||||
|
|
||||||
# H5 前端
|
|
||||||
Alias /h5 /var/www/html/h5
|
|
||||||
<Directory /var/www/html/h5>
|
|
||||||
Options -Indexes +FollowSymLinks
|
|
||||||
AllowOverride All
|
|
||||||
Require all granted
|
|
||||||
|
|
||||||
# Vue Router history 模式
|
|
||||||
RewriteEngine On
|
|
||||||
RewriteBase /h5
|
|
||||||
RewriteRule ^index\.html$ - [L]
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
RewriteRule . /h5/index.html [L]
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
# 静态资源缓存
|
|
||||||
<FilesMatch "\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$">
|
|
||||||
Header set Cache-Control "max-age=2592000, public"
|
|
||||||
</FilesMatch>
|
|
||||||
|
|
||||||
# HTML 不缓存
|
|
||||||
<FilesMatch "\.html$">
|
|
||||||
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
|
||||||
</FilesMatch>
|
|
||||||
</VirtualHost>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 部署检查清单
|
|
||||||
|
|
||||||
### 打包前检查
|
|
||||||
|
|
||||||
- [ ] ✅ `.env` 文件配置正确(生产环境域名)
|
|
||||||
- [ ] 检查 `manifest.json` 配置
|
|
||||||
- [ ] 移除开发环境的 console.log
|
|
||||||
- [ ] 移除调试工具(如 vconsole)
|
|
||||||
- [ ] 检查建行生活模块是否正确集成
|
|
||||||
|
|
||||||
### 打包检查
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 检查打包文件大小
|
|
||||||
du -sh unpackage/dist/build/h5
|
|
||||||
|
|
||||||
# 检查关键文件是否存在
|
|
||||||
ls -lh unpackage/dist/build/h5/index.html
|
|
||||||
ls -lh unpackage/dist/build/h5/static/
|
|
||||||
|
|
||||||
# 检查是否有 source map(生产环境应该移除)
|
|
||||||
find unpackage/dist/build/h5 -name "*.map"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 部署后检查
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. 检查文件是否上传成功
|
|
||||||
ssh user@app.fengketrade.com "ls -lh /var/www/html/h5"
|
|
||||||
|
|
||||||
# 2. 检查权限
|
|
||||||
ssh user@app.fengketrade.com "ls -ld /var/www/html/h5"
|
|
||||||
|
|
||||||
# 3. 测试访问
|
|
||||||
curl -I https://app.fengketrade.com/h5/
|
|
||||||
|
|
||||||
# 4. 检查 API 接口
|
|
||||||
curl https://app.fengketrade.com/addons/shopro/ccbtest
|
|
||||||
```
|
|
||||||
|
|
||||||
### 功能测试
|
|
||||||
|
|
||||||
- [ ] 访问首页是否正常
|
|
||||||
- [ ] API 接口是否可以调用
|
|
||||||
- [ ] 建行生活模块是否正常
|
|
||||||
- [ ] 支付功能是否正常
|
|
||||||
- [ ] 图片资源是否加载
|
|
||||||
- [ ] 移动端适配是否正常
|
|
||||||
|
|
||||||
## 快速部署命令
|
|
||||||
|
|
||||||
### 本地到服务器一键部署
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /Users/billy/Code/fengketrade.com/frontend
|
|
||||||
|
|
||||||
# 1. 打包(使用 HBuilderX 或命令行)
|
|
||||||
# HBuilderX: 发行 → 网站-H5手机版
|
|
||||||
|
|
||||||
# 2. 压缩
|
|
||||||
tar --no-mac-metadata --no-xattrs --exclude='.DS_Store' \
|
|
||||||
-czf h5-$(date +%Y%m%d-%H%M%S).tar.gz \
|
|
||||||
-C unpackage/dist/build/h5 .
|
|
||||||
|
|
||||||
# 3. 上传
|
|
||||||
ARCHIVE=$(ls -t h5-*.tar.gz | head -1)
|
|
||||||
scp $ARCHIVE user@app.fengketrade.com:/tmp/
|
|
||||||
|
|
||||||
# 4. 部署(在服务器上执行)
|
|
||||||
ssh user@app.fengketrade.com << 'EOF'
|
|
||||||
ARCHIVE=$(ls -t /tmp/h5-*.tar.gz | head -1)
|
|
||||||
sudo mkdir -p /var/www/html/h5
|
|
||||||
sudo tar -xzf $ARCHIVE -C /var/www/html/h5
|
|
||||||
sudo chown -R www-data:www-data /var/www/html/h5
|
|
||||||
sudo chmod -R 755 /var/www/html/h5
|
|
||||||
rm -f $ARCHIVE
|
|
||||||
echo "部署完成!"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 5. 测试
|
|
||||||
curl -I https://app.fengketrade.com/h5/
|
|
||||||
```
|
|
||||||
|
|
||||||
## 回滚方案
|
|
||||||
|
|
||||||
### 快速回滚
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 在服务器上执行
|
|
||||||
cd /var/www/backup
|
|
||||||
|
|
||||||
# 查看备份
|
|
||||||
ls -lht h5-backup-*.tar.gz | head -5
|
|
||||||
|
|
||||||
# 回滚到指定版本
|
|
||||||
BACKUP_FILE="h5-backup-20250117-143000.tar.gz"
|
|
||||||
sudo rm -rf /var/www/html/h5/*
|
|
||||||
sudo tar -xzf $BACKUP_FILE -C /var/www/html/h5
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
|
|
||||||
echo "已回滚到: $BACKUP_FILE"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 性能优化
|
|
||||||
|
|
||||||
### 打包优化
|
|
||||||
|
|
||||||
1. **启用 Gzip 压缩**(在 `vite.config.js`)
|
|
||||||
```javascript
|
|
||||||
import viteCompression from 'vite-plugin-compression';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
plugins: [
|
|
||||||
viteCompression({
|
|
||||||
verbose: true,
|
|
||||||
disable: false,
|
|
||||||
threshold: 10240,
|
|
||||||
algorithm: 'gzip',
|
|
||||||
ext: '.gz'
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **代码分割**
|
|
||||||
- uni-app 会自动进行代码分割
|
|
||||||
- 按页面分包加载
|
|
||||||
|
|
||||||
3. **图片优化**
|
|
||||||
- 压缩图片资源
|
|
||||||
- 使用 WebP 格式
|
|
||||||
- 启用懒加载
|
|
||||||
|
|
||||||
### CDN 配置
|
|
||||||
|
|
||||||
修改 `.env`:
|
|
||||||
```env
|
|
||||||
# 使用 CDN 加速静态资源
|
|
||||||
SHOPRO_STATIC_URL = https://cdn.fengketrade.com
|
|
||||||
```
|
|
||||||
|
|
||||||
## 常见问题
|
|
||||||
|
|
||||||
### Q: 打包后页面空白?
|
|
||||||
|
|
||||||
**原因**: 路径配置错误
|
|
||||||
|
|
||||||
**解决**:
|
|
||||||
```javascript
|
|
||||||
// manifest.json 中检查
|
|
||||||
{
|
|
||||||
"h5": {
|
|
||||||
"router": {
|
|
||||||
"mode": "hash", // 推荐使用 hash 模式
|
|
||||||
"base": "/h5/" // 根据实际部署路径调整
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Q: API 请求 404?
|
|
||||||
|
|
||||||
**原因**: 接口地址配置错误
|
|
||||||
|
|
||||||
**解决**: 检查 `.env` 中的 `SHOPRO_BASE_URL`
|
|
||||||
|
|
||||||
### Q: 静态资源 404?
|
|
||||||
|
|
||||||
**原因**: Nginx 配置问题
|
|
||||||
|
|
||||||
**解决**: 确保 Nginx 配置正确映射静态资源路径
|
|
||||||
|
|
||||||
### Q: 打包文件太大?
|
|
||||||
|
|
||||||
**解决**:
|
|
||||||
1. 移除无用的依赖
|
|
||||||
2. 启用代码压缩
|
|
||||||
3. 使用 CDN 加载大文件
|
|
||||||
4. 按需引入组件
|
|
||||||
|
|
||||||
## 监控和维护
|
|
||||||
|
|
||||||
### 访问日志
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Nginx 访问日志
|
|
||||||
sudo tail -f /var/log/nginx/access.log | grep "GET /h5"
|
|
||||||
|
|
||||||
# 错误日志
|
|
||||||
sudo tail -f /var/log/nginx/error.log
|
|
||||||
```
|
|
||||||
|
|
||||||
### 性能监控
|
|
||||||
|
|
||||||
使用浏览器开发者工具:
|
|
||||||
1. Network - 查看资源加载时间
|
|
||||||
2. Performance - 分析页面性能
|
|
||||||
3. Lighthouse - 综合评分
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*文档版本: 1.0.0*
|
|
||||||
*最后更新: 2025-01-17*
|
|
||||||
*作者: Billy*
|
|
||||||
Loading…
x
Reference in New Issue
Block a user