# Pay 模块前端对接文档

## 1. 说明

- 模块路径：`/pay/open`（前台充值支付）
- 本文重点：前端发起钱包充值、拉起支付、轮询支付状态
- 统一响应结构：`R<T>`

```json
{
  "code": 200,
  "msg": "操作成功",
  "data": {}
}
```

- `code = 200` 表示成功，非 `200` 视为失败

## 2. 鉴权要求

- `POST /pay/open/recharge/unified-order`
- `GET /pay/open/recharge/status/{rechargeOrderNo}`

以上两个接口都需要登录态（与系统统一鉴权方式一致，前端按当前项目 token 方案携带请求头即可）。

第三方支付回调接口由支付平台调用，前端不用调用：

- `POST /pay/open/notify/alipay/{channelId}`
- `POST /pay/open/notify/wechat/{channelId}`

## 3. 枚举约定

### _3.1 下单参数枚举_

- `provider`：`WECHAT` / `ALIPAY`
- `scene`：`QR` / `H5` / `APP`
- `walletType`：`1` 个人钱包，`2` 企业钱包（默认 `2`）

支持的有效组合：

- `WECHAT + QR` -> `WECHAT_QR`
- `WECHAT + H5` -> `WECHAT_H5`
- `WECHAT + APP` -> `WECHAT_APP`
- `ALIPAY + QR` -> `ALIPAY_QR`
- `ALIPAY + H5` -> `ALIPAY_H5`
- `ALIPAY + APP` -> `ALIPAY_APP`

### 3.2 支付状态

- `1` 待支付（WAITING）
- `2` 支付中（PAYING）
- `3` 支付成功（SUCCESS）
- `4` 支付失败（FAILED）
- `5` 已关闭（CLOSED）

### 3.3 展示模式（下单响应）

- `QR_CODE`：展示二维码（用 `codeUrl`）
- `REDIRECT`：跳转支付链接（用 `payUrl`）
- `APP`：APP 拉起支付（`orderString` 或 `appPayParams`）

## 4. 接口一：统一下单

- 地址：`POST /pay/open/recharge/unified-order`
- Content-Type：`application/json`

### 4.1 请求参数

```json
{
  "amount": 100.00,
  "provider": "WECHAT",
  "scene": "H5",
  "walletType": 2,
  "returnUrl": "https://your-frontend.com/pay-return"
}
```

字段说明：

- `amount`：充值金额，必须大于 `0.01`
- `provider`：支付渠道类型（`WECHAT` / `ALIPAY`）
- `scene`：支付场景（`QR` / `H5` / `APP`）
- `walletType`：钱包类型（可不传，默认企业钱包 `2`）
- `returnUrl`：支付宝 H5 跳转地址建议传；微信场景可按需传

防重说明：

- 同一用户同一钱包在存在“待支付/支付中且未过期”的充值订单时，后端会拒绝重复下单。
- 返回错误示例：`存在待支付充值订单，请先完成支付（订单号：RC...）`

### 4.2 响应示例

```json
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "rechargeOrderNo": "RC20260509143000XXXXXXXXXX",
    "payOrderNo": "PO20260509143000XXXXXXXXXX",
    "channelCode": "WECHAT_H5",
    "displayMode": "REDIRECT",
    "codeUrl": null,
    "payUrl": "https://wx.tenpay.com/...",
    "orderString": null,
    "appPayParams": null,
    "expireTime": "2026-05-09T14:33:00.000+08:00"
  }
}
```

`APP` 场景返回示例（微信）：

```json
{
  "displayMode": "APP",
  "appPayParams": {
    "appid": "wx...",
    "partnerid": "19...",
    "prepayid": "wx2014...",
    "package": "Sign=WXPay",
    "noncestr": "xxx",
    "timestamp": "1715239200",
    "sign": "xxx"
  }
}
```

`APP` 场景返回示例（支付宝）：

```json
{
  "displayMode": "APP",
  "orderString": "app_id=...&method=alipay.trade.app.pay&..."
}
```

## 5. 接口二：查询充值状态

- 地址：`GET /pay/open/recharge/status/{rechargeOrderNo}`

### 5.1 响应示例

```json
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "rechargeOrderNo": "RC20260509143000XXXXXXXXXX",
    "payOrderNo": "PO20260509143000XXXXXXXXXX",
    "payStatus": 2,
    "amount": 100.00,
    "thirdTradeNo": null,
    "paidTime": null
  }
}
```

## 6. 接口三：查询可用支付方式

- 地址：`GET /pay/open/recharge/channels`

### 6.1 响应示例

```json
{
  "code": 200,
  "msg": "操作成功",
  "data": [
    {
      "provider": "ALIPAY",
      "scene": "H5",
      "channelCode": "ALIPAY_H5",
      "payMethod": 2,
      "payScene": 1,
      "displayName": "支付宝H5"
    },
    {
      "provider": "ALIPAY",
      "scene": "APP",
      "channelCode": "ALIPAY_APP",
      "payMethod": 2,
      "payScene": 3,
      "displayName": "支付宝APP"
    }
  ]
}
```

## 7. 钱包充值流程图（前端调用顺序）

```mermaid
sequenceDiagram
    autonumber
    participant FE as 前端
    participant BE as 后端(/pay/open)
    participant ALI as 支付宝/微信

    FE->>BE: POST /recharge/unified-order
    BE-->>FE: R<UnifiedOrderRespVO>\n(displayMode + payUrl/codeUrl/orderString/appPayParams + rechargeOrderNo)

    alt displayMode = QR_CODE
        FE->>FE: 渲染二维码(codeUrl)\n用户扫码支付
    else displayMode = REDIRECT
        FE->>ALI: 浏览器跳转 payUrl
    else displayMode = APP
        FE->>ALI: APP 拉起支付\n(支付宝 orderString / 微信 appPayParams)
    end

    ALI-->>BE: 异步回调 notify\n(前端不调用)
    loop 每2秒轮询一次(最多90秒)
        FE->>BE: GET /recharge/status/{rechargeOrderNo}
        BE-->>FE: R<PayRechargeStatusRespVO>(payStatus)
    end

    alt payStatus = 3
        FE->>FE: 展示支付成功
    else payStatus = 4 or 5
        FE->>FE: 展示支付失败/已关闭
    end
```

## 8. 前端依次调用哪些接口

1. 可先查余额：`GET /pay/open/wallet/balance?walletType=2`（不传默认企业钱包）。
2. 再调方式接口：`GET /pay/open/recharge/channels`，渲染可选支付方式。
3. 用户选中支付方式后，再调下单：`POST /pay/open/recharge/unified-order`（传 `provider+scene`）。
4. 根据返回字段拉起支付：
    - `displayMode=QR_CODE` -> 使用 `codeUrl`
    - `displayMode=REDIRECT` -> 跳转 `payUrl`
    - `displayMode=APP` -> 支付宝用 `orderString`，微信用 `appPayParams`
5. 保存 `rechargeOrderNo`，开始轮询：`GET /pay/open/recharge/status/{rechargeOrderNo}`
6. 轮询终止条件：
    - `payStatus=3`：成功，停止轮询
    - `payStatus=4/5`：失败或关闭，停止轮询
    - 超时（建议 90 秒）：停止轮询并提示用户手动刷新

说明：`/pay/open/notify/alipay/{channelId}` 与 `/pay/open/notify/wechat/{channelId}` 是三方回调接口，由支付宝/微信调用，前端无需调用。

## 9. 前端最小调用示例（Axios）

```ts
import axios from "axios";

export async function createRechargeOrder(payload: {
    amount: number;
    provider: "WECHAT" | "ALIPAY";
    scene: "QR" | "H5" | "APP";
    walletType?: 1 | 2;
    returnUrl?: string;
}) {
    const res = await axios.post("/pay/open/recharge/unified-order", payload);
    if (res.data?.code !== 200) throw new Error(res.data?.msg || "下单失败");
    return res.data.data;
}

export async function listRechargeChannels() {
    const res = await axios.get("/pay/open/recharge/channels");
    if (res.data?.code !== 200) throw new Error(res.data?.msg || "获取支付方式失败");
    return res.data.data;
}

export async function queryWalletBalance(walletType = 2) {
    const res = await axios.get("/pay/open/wallet/balance", {params: {walletType}});
    if (res.data?.code !== 200) throw new Error(res.data?.msg || "查询余额失败");
    return res.data.data;
}

export async function queryRechargeStatus(rechargeOrderNo: string) {
    const res = await axios.get(`/pay/open/recharge/status/${rechargeOrderNo}`);
    if (res.data?.code !== 200) throw new Error(res.data?.msg || "查询失败");
    return res.data.data;
}
```

## 10. 总部批量充值企业钱包

- 地址：`POST /platform/wallet/batchRechargeCompany`
- 权限：`platform:wallet:recharge`
- 说明：按企业ID列表批量给企业钱包加余额；若企业钱包不存在则自动创建；每个企业写一条钱包流水（含备注）

请求示例：

```json
{
  "companyIds": "1,2,3",
  "amount": 100.00,
  "remark": "总部活动补贴"
}
```

返回示例（`data` 为成功充值企业数量）：

```json
{
  "code": 200,
  "msg": "操作成功",
  "data": 3
}
```

## 11. 钱包冻结/解冻

- 地址：`POST /platform/wallet/freeze`
- 权限：`platform:wallet:edit`
- 说明：总部端可冻结或解冻指定钱包；冻结后，钱包不能充值和使用

请求示例：

```json
{
  "walletId": 1,
  "freezeStatus": 1
}
```

字段说明：

- `walletId`：钱包ID
- `freezeStatus`：冻结状态，`0=正常`，`1=冻结`

返回示例：

```json
{
  "code": 200,
  "msg": "操作成功",
  "data": null
}
```

## 12. 后台管理接口（可选）

以下是 `pay` 模块后台管理接口前缀（用于运营后台，不是 C 端支付主流程）：

- `/platform/app`：支付应用管理
- `/platform/channel`：支付渠道管理
- `/platform/order`：支付订单管理
- `/platform/orderExtension`：支付订单拓展单管理
- `/platform/wallet`：钱包管理
- `/platform/walletTransaction`：钱包流水管理

钱包管理补充接口：

- `GET /platform/wallet/companyBalanceList`：分页返回企业名称、企业负责人、手机号、账户余额（支持 `keyword` 搜索企业名/负责人/手机号）
- `GET /platform/wallet/headquarters/balance?walletId=xxx`：总部端按钱包ID查询钱包余额
- `POST /platform/wallet/batchRechargeCompany`：总部批量充值企业钱包
- `POST /platform/wallet/freeze`：总部端冻结/解冻钱包；冻结后钱包不能充值和使用
- `GET /platform/walletTransaction/headquarters/list?walletId=xxx`：总部端按钱包ID分页查询钱包流水

权限点均为 `platform:*` 形式（如 `platform:wallet:list`）。

## 13. Pay 表查询接口对照

说明：

- 下表包含 `pay` 模块涉及的主要表及其“查询接口”。
- `开放接口` 主要给前端 C 端使用；`后台接口` 主要给运营后台使用（需 `platform:*` 权限）。

| 表名                       | 用途            | 查询接口                                                                                                                                                                                                                                                                                                                                           |
|--------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pay_app`                | 支付应用配置        | `GET /platform/app/list`（分页），`GET /platform/app/{id}`（详情）                                                                                                                                                                                                                                                                                      |
| `pay_channel`            | 支付渠道配置        | `GET /platform/channel/list`（分页），`GET /platform/channel/{id}`（详情），`GET /pay/open/recharge/channels`（开放：可用支付方式）                                                                                                                                                                                                                                 |
| `pay_order`              | 支付主订单         | `GET /platform/order/list`（分页），`GET /platform/order/{id}`（详情）                                                                                                                                                                                                                                                                                  |
| `pay_order_extension`    | 支付拓展单（三方侧单号等） | `GET /platform/orderExtension/list`（分页），`GET /platform/orderExtension/{id}`（详情）                                                                                                                                                                                                                                                                |
| `pay_recharge_order`     | 充值业务单         | 当前无独立后台 Controller；开放侧可用 `GET /pay/open/recharge/status/{rechargeOrderNo}` 按充值单号查询状态                                                                                                                                                                                                                                                           |
| `pay_wallet`             | 钱包主表（个人/企业）   | `GET /platform/wallet/list`（分页），`GET /platform/wallet/{id}`（详情），`GET /platform/wallet/companyBalanceList`（企业余额分页），`GET /platform/wallet/headquarters/balance?walletId=xxx`（总部端：按钱包ID查余额），`GET /pay/open/wallet/balance?walletType=1/2`（开放：余额），`POST /platform/wallet/batchRechargeCompany`（总部批量充值企业钱包），`POST /platform/wallet/freeze`（冻结/解冻钱包） |
| `pay_wallet_transaction` | 钱包流水          | `GET /platform/walletTransaction/list`（分页），`GET /platform/walletTransaction/{id}`（详情），`GET /platform/walletTransaction/company/current/list`（企业端：当前企业流水分页），`GET /platform/walletTransaction/company/list?companyId=xxx`（总部端：指定企业流水分页），`GET /platform/walletTransaction/headquarters/list?walletId=xxx`（总部端：按钱包ID分页查流水）                         |

## 14. Pay 表字段总览

说明：

- 以下字段按当前 `pay` 模块实体与现有建表脚本整理。
- 通用审计字段统一为：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、
  `update_time`、`is_deleted`。

### 14.1 pay_app

- 业务字段：`id`、`app_key`、`name`、`status`、`remark`、`order_notify_url`
- 通用字段：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、`update_time`、
  `is_deleted`

### 14.2 pay_channel

- 业务字段：`id`、`code`、`status`、`remark`、`app_id`、`config`
- 通用字段：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、`update_time`、
  `is_deleted`

### 14.3 pay_order

- 业务字段：`id`、`app_id`、`merchant_order_no`、`biz_order_type`、`biz_order_id`、`subject`、`body`、`channel_id`、
  `channel_code`、`notify_url`、`return_url`、`price`、`status`、`user_ip`、`expire_time`、`success_time`、`extension_id`、`no`、
  `channel_user_id`、`channel_order_no`
- 通用字段：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、`update_time`、
  `is_deleted`

### 14.4 pay_order_extension

- 业务字段：`id`、`no`、`order_id`、`channel_id`、`channel_code`、`user_ip`、`status`、`channel_extras`、`channel_error_code`、
  `channel_error_msg`、`channel_notify_data`
- 通用字段：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、`update_time`、
  `is_deleted`

### 14.5 pay_recharge_order

- 业务字段：`id`、`company_id`、`account_id`、`user_id`、`recharge_order_no`、`recharge_amount`、`pay_method`、`pay_scene`、
  `pay_status`、`third_trade_no`、`paid_time`、`fail_reason`、`remark`
- 通用字段：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、`update_time`、
  `is_deleted`

### 14.6 pay_wallet

- 业务字段：`id`、`user_id`、`balance`、`total_expense`、`total_recharge`、`freeze_price`、`wallet_type`、`freeze_status`
- 通用字段：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、`update_time`、
  `is_deleted`

### 14.7 pay_wallet_transaction

- 业务字段：`id`、`wallet_id`、`biz_type`、`biz_id`、`no`、`title`、`price`、`balance`
- 通用字段：`create_dept`、`create_by`、`create_by_name`、`create_time`、`update_by`、`update_by_name`、`update_time`、
  `is_deleted`
