# 资金概览 — 技术方案

> **依据：** 《资金概览功能需求.md》v1.0  
> **关联：** 平台《账务管理.md》v1.0、《提现审核功能需求》v1.0、《提现审核技术方案》v1.0；商家《资金概览功能需求》v1.0、《资金概览技术方案》v1.0、《提现管理技术方案》v1.0、《账户管理技术方案》v1.0；《关联需求分析.md》v1.6  
> **范围：** 平台端 **财务管理 · 资金概览** — **全平台总览**、**店铺余额排行**、**资金变动明细**（只读）；**不含** 提现审核、手工调账、商家账户维护。  
> **原则：** **全平台** 可见；**纯查询**；单店指标与商家端 **同名同口径**；流水 **只读**。

---

## 1. 技术架构

| 项 | 选型 |
|----|------|
| 基础框架 | RuoYi **v3.9.2**（`springboot2` 分支） |
| 数据库 | **MySQL 5.7.39**；读 **`biz_shop_wallet`**、**`biz_shop_fund_log`**、**`biz_order`**、**`biz_shop`** |
| ORM / 权限 / 响应 | MyBatis；`@PreAuthorize`；`AjaxResult` / `TableDataInfo` |
| 店铺上下文 | **无** `X-Shop-Id`（平台端全平台） |
| 金额 | `BigDecimal`；两位小数 |

### 1.1 与兄弟模块边界

| 维度 | **本模块 · 平台资金概览** | 平台 · 提现审核 | 商家 · 资金概览 | 订单链 |
|------|--------------------------|-----------------|-----------------|--------|
| 路径 | `/agri/finance/fundOverview` | `/withdrawAudit` | `/agri/seller/finance/overview` | C 端 confirmReceive |
| 写操作 | **无** | approve/reject | **无** | settleOrder |
| 数据范围 | **全平台** | 全平台提现单 | **单店** `shop_id` | 按订单 `shop_id` |
| 总览 | Σ 各店 wallet + order | — | 单店 wallet + order | 写 wallet（结算） |
| 流水 | 跨店只读 | 写 3/4 类 | 单店只读 | 写 1 类 |
| 店铺信息 | 读 `biz_shop` | 快照于 withdraw | — | — |

### 1.2 数据流（只读展示）

```text
【上游写入 · 非本模块】
    订单 confirmReceive → settleOrder
        → fund_log（1 订单收支）；wallet.available ↑
    商家提现 submit → fund_log（2 余额提现）；wallet 余额↓ 冻结↑
    平台审核 → fund_log（3 提现驳回 / 4 提现完成）；wallet 调整

【待结算 · 不落库】
    单店：SUM(biz_order.pay_amount) WHERE 已支付 AND 待发货/已发货
    全平台：对各店待结算 **求和**（或直接全表 SUM，口径等价）

【本模块 · 只读】
    GET /summary  → 全平台三块总览
    GET /shops    → 店铺排行（关联 biz_shop + wallet + 待结算子查询）
    GET /logs     → fund_log 分页；可选 shopId / shopName / 时间
```

> 协作链详见平台《账务管理.md》：订单与提现 **无表级绑定**；流水 `biz_no` = 订单号/提现编号。

### 1.3 模块落位

**文档目录：** `doc/平台后台/财务管理/资金概览/`  
**菜单：** 财务管理 → 资金概览（建议 `menu_id=7620`，`parent_id=7600`）  
**后端包：** `com.ruoyi.web.modules.finance`

```text
finance/
├── controller/PlatformFundOverviewController.java   # 本模块入口
├── service/IShopFundService.java                    # 扩展平台概览方法（与提现审核同 Service）
├── service/impl/ShopFundServiceImpl.java
├── dto/PlatformShopFundRankQuery.java
├── dto/PlatformFundLogQuery.java
├── vo/PlatformFundOverviewSummaryVO.java
├── vo/PlatformShopFundRankRowVO.java
├── vo/FundLogListRowVO.java                         # 复用商家端
├── mapper/BizShopWalletMapper.java                  # 扩展 sumPlatform / 排行 SQL
├── mapper/BizShopFundLogMapper.java                 # 扩展 selectPlatformList
├── mapper/BizOrderMapper.java                       # sumPendingSettleByShopId / sumPlatformPendingSettle
├── mapper/BizShopMapper.java                        # 店铺名称/LOGO/状态/开店时间
├── support/FinanceSupport.java                      # changeReason、shopStatus 文案
resources/mapper/finance/*.xml
resources/mapper/order/BizOrderMapper.xml
resources/mapper/store/BizShopMapper.xml

sql/biz_shop_finance.sql                             # 已有，本模块不增表
sql/biz_shop_finance_menu.sql                        # 追加 7620 菜单与权限
```

**前端（建议）：**

| 项 | 值 |
|----|-----|
| 页面 | `ruoyi-ui/src/views/agri/finance/fundOverview/index.vue` |
| API | `ruoyi-ui/src/api/agri/finance/fundOverview.js` |
| 日志弹窗 | 排行行「查看资金日志」→ 抽屉/弹窗调 `/logs` |
| 展示格式 | §3.4「变更值+变更后」由 **前端** 格式化（与商家端一致） |

---

## 2. 数据库设计

**权威 DDL：** [`sql/biz_shop_finance.sql`](../../../../sql/biz_shop_finance.sql)

本模块 **不建表**；**只读** 下列表。表结构由 **提现审核技术方案** 统一维护，本模块 **复用**。

### 2.1 店铺钱包 `biz_shop_wallet`（总览 · 余额/冻结）

| 字段 | 平台用途 |
|------|----------|
| shop_id | 排行关联键 |
| available_balance | 单店 **店铺余额**；无记录 → `0.00` |
| frozen_amount | 单店 **冻结**；无记录 → `0.00` |

**全平台汇总：**

```sql
SELECT IFNULL(SUM(available_balance), 0) AS totalBalance,
       IFNULL(SUM(frozen_amount), 0)     AS frozenTotal
FROM biz_shop_wallet
```

### 2.2 订单 `biz_order`（总览 · 待结算）

**单店待结算（与商家端一致）：**

```sql
SELECT IFNULL(SUM(pay_amount), 0)
FROM biz_order
WHERE shop_id = #{shopId}
  AND pay_status = '1'
  AND order_status IN ('1', '2')   -- 待发货、已发货
  AND del_flag = '0'
```

**全平台待结算总额：**

```sql
SELECT IFNULL(SUM(pay_amount), 0)
FROM biz_order
WHERE pay_status = '1'
  AND order_status IN ('1', '2')
  AND del_flag = '0'
```

| 口径 | 需求规则 |
|------|----------|
| 计入 | 已支付 + 待发货/已发货 |
| 不计入 | 待支付、已完成、已关闭 |
| 与流水 | **无** 待结算流水；确认收货后写 **订单收支** |

### 2.3 资金流水 `biz_shop_fund_log`（变动明细）

| 字段 | 列表用途 |
|------|----------|
| shop_id | 单店入口默认过滤 |
| shop_name | 明细列；**模糊检索** 条件 |
| biz_no | 业务编号（订单号/提现编号） |
| change_reason | `1`～`4` → 文案 |
| balance_change / balance_after | 变动余额 |
| frozen_change / frozen_after | 变动冻结 |
| create_time | 变动时间；**倒序** |

**变动原因枚举（与商家端一致）：**

| change_reason | 文案 | 写入方 |
|---------------|------|--------|
| `1` | 订单收支 | `settleOrder` |
| `2` | 余额提现 | 提现 submit |
| `3` | 提现驳回 | 平台 reject |
| `4` | 提现完成 | 平台 approve |

**索引（已有）：** `idx_shop_time (shop_id, create_time)`、`idx_ref (ref_type, ref_id)`。

**可选优化（非必须）：** 跨店按时间检索量大时，可追加 `idx_create_time (create_time)`。

### 2.4 店铺 `biz_shop`（排行 · 展示信息）

| 字段 | 排行用途 |
|------|----------|
| shop_id | 主键 |
| shop_name | 店铺名称 |
| shop_avatar | 店铺 LOGO |
| shop_status | `0` 开业 / `1` 停业 |
| del_flag | `0` 正常；`2` 逻辑删除 → **另标识** |
| create_time | **开店时间** |

**排行数据范围（实现口径）：**

```sql
-- 纳入：未删店（开业/停业）
-- 追加：已逻辑删除 且（有钱包行 或 存在流水）
WHERE s.del_flag = '0'
   OR w.wallet_id IS NOT NULL
   OR EXISTS (SELECT 1 FROM biz_shop_fund_log l WHERE l.shop_id = s.shop_id LIMIT 1)
```

### 2.5 排行 SQL 骨架（单页）

```sql
SELECT s.shop_id,
       s.shop_name,
       s.shop_avatar,
       s.shop_status,
       s.del_flag,
       s.create_time AS openTime,
       IFNULL(w.available_balance, 0) AS availableBalance,
       IFNULL(w.frozen_amount, 0)     AS frozenAmount,
       IFNULL(ps.pending_settle, 0)   AS pendingSettleAmount
FROM biz_shop s
LEFT JOIN biz_shop_wallet w ON w.shop_id = s.shop_id
LEFT JOIN (
    SELECT shop_id, IFNULL(SUM(pay_amount), 0) AS pending_settle
    FROM biz_order
    WHERE pay_status = '1' AND order_status IN ('1','2') AND del_flag = '0'
    GROUP BY shop_id
) ps ON ps.shop_id = s.shop_id
WHERE /* §2.4 数据范围 */
ORDER BY /* 动态：availableBalance / pendingSettleAmount / frozenAmount */
```

> **恒等式（验收）：** 全平台 `totalBalance` = Σ 排行 `availableBalance`；`pendingSettleTotal`、`frozenTotal` 同理（PF-A3、PF-A4）。

---

## 3. 接口设计

**基路径：** `/agri/finance/fundOverview`  
**上下文：** **无** 店铺请求头  
**写接口：** **无**

### 3.1 接口一览

| 方法 | 路径 | 权限 | 说明 |
|------|------|------|------|
| GET | `/summary` | `agri:finance:fundOverview:summary` | 全平台三块总览 |
| GET | `/shops` | `agri:finance:fundOverview:ranking` | 店铺余额排行（分页+排序） |
| GET | `/logs` | `agri:finance:fundOverview:log` | 资金变动明细分页 |

> v1 可合并为单一权限 `agri:finance:fundOverview:query`；需求允许 **分权**，上表为 **推荐粒度**。

### 3.2 全平台总览 `GET /summary`

**响应 data（PlatformFundOverviewSummaryVO）：**

| 字段 | 来源 | 说明 |
|------|------|------|
| totalBalance | `SUM(biz_shop_wallet.available_balance)` | 总余额 |
| pendingSettleTotal | `biz_order` 全平台 SUM（§2.2） | 待结算总额 |
| frozenTotal | `SUM(biz_shop_wallet.frozen_amount)` | 冻结总额 |

**无 wallet 行时：** 对应 SUM 为 `0.00`（不影响待结算）。

### 3.3 店铺余额排行 `GET /shops`

**Query（PlatformShopFundRankQuery）：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| pageNum | int | 是 | 页码 |
| pageSize | int | 是 | 每页条数 |
| orderByColumn | string | 否 | `availableBalance` / `pendingSettleAmount` / `frozenAmount` |
| isAsc | string | 否 | `asc` / `desc` |

**定稿默认：** `orderByColumn=availableBalance`，`isAsc=desc`（店铺余额降序）。

**行 VO（PlatformShopFundRankRowVO）：**

| 字段 | 说明 |
|------|------|
| shopId | 店铺 ID |
| shopName | 店铺名称 |
| shopAvatar | 店铺 LOGO |
| shopStatus | `0`/`1` |
| shopStatusText | 开业/停业 |
| deleted | 是否逻辑删除（`del_flag='2'`） |
| availableBalance | 店铺余额（可用） |
| pendingSettleAmount | 待结算金额 |
| frozenAmount | 冻结金额 |
| openTime | 开店时间（`biz_shop.create_time`） |

**排序规则：** 同时仅 **一列** 生效；点击列头切换升/降序（RuoYi `orderByColumn` + `isAsc`）。

**非本期 Query：** 店铺名称关键词检索（需求 §5.3）。

### 3.4 资金变动明细 `GET /logs`

**Query（PlatformFundLogQuery）：**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| pageNum | int | 是 | 页码 |
| pageSize | int | 是 | 每页条数 |
| shopId | long | 否 | 排行「查看资金日志」传入；**默认仅该店** |
| shopName | string | 否 | 店铺名称 **模糊**；**有值时覆盖 shopId 范围** |
| beginChangeTime | date | 否 | 变动时间起（含 `00:00:00`） |
| endChangeTime | date | 否 | 变动时间止（含 `23:59:59`） |

**过滤逻辑（定稿）：**

| 条件 | SQL |
|------|-----|
| 仅 `shopId` | `shop_id = #{shopId}` |
| `shopName` 有值 | `shop_name LIKE %shopName%`（**忽略 shopId**） |
| 皆空 | **全平台** 流水 |
| 时间区间 | `create_time BETWEEN ...` |

**固定排序：** `ORDER BY create_time DESC, log_id DESC`。

**行 VO：** 复用 **`FundLogListRowVO`**（与商家 `/overview/logs` **字段一致**）；`changeReasonText` 由 `FinanceSupport.toChangeReasonText` 填充。

**前端约定：**

- 从排行进入：带 `shopId`；**重置** 恢复 **仅该 shopId**；
- 运营对账：店名、时间留空 → 查全平台。

**非本期 Query：** 变动原因、业务编号筛选。

### 3.5 与商家端接口对照

| 能力 | 平台 `/agri/finance/fundOverview` | 商家 `/agri/seller/finance/overview` |
|------|-----------------------------------|--------------------------------------|
| 总览 | `/summary` 三块（无账户信息） | `/summary` 含 username、bankAccountCount |
| 排行 | `/shops` | **无** |
| 流水 | `/logs` 可跨店 | `/logs` 固定本店 |
| 隔离 | 全平台 | `X-Shop-Id` |

单店对账：平台排行/日志中 **同一 shopId** 的余额、待结算、冻结、流水 **须与** 商家端 **一致**（需求 §7.3）。

---

## 4. 业务规则（实现）

| 编号 | 需求规则 | 实现要点 |
|------|----------|----------|
| PF-A1 | 只读 | Controller **仅 GET** |
| PF-A2 | 全平台 | **无** shop_id 强制过滤（logs 可选） |
| PF-A3 | 总览 = 各店之和 | summary 与 shops 聚合 **口径一致** |
| PF-A4 | 单店口径同商家端 | 复用 `sumPendingSettleByShopId`、wallet 读法 |
| PF-A5 | 四类变动原因 | `FinanceSupport.toChangeReasonText` |
| PF-A6 | 排行三列可排序 | 白名单列名 + SQL `ORDER BY` |
| PF-A7 | 明细字段与草稿一致 | 复用 `FundLogListRowVO` |
| PF-A8 | 检索：店名 + 时间 | `PlatformFundLogQuery` |
| PF-A9 | 不写提现审核 | **无** approve/reject |
| PF-A10 | 店名/LOGO/状态/开店时间 | 读 `biz_shop`；`shopStatusText` / `deleted` |
| PF-A11 | 虚拟账分层 | 文档/前端文案；**不** 读微信商户号 |

**店铺状态文案：**

| shop_status | del_flag | 展示 |
|-------------|----------|------|
| `0` | `0` | 开业 |
| `1` | `0` | 停业 |
| * | `2` | 已删除（另标识） |

---

## 5. 权限与菜单

| 权限 | 说明 |
|------|------|
| `agri:finance:fundOverview:summary` | 全平台总览 |
| `agri:finance:fundOverview:ranking` | 店铺排行 |
| `agri:finance:fundOverview:log` | 资金日志 |

| 菜单 | menu_id | path | 父菜单 |
|------|---------|------|--------|
| 财务管理（平台） | 7600 | finance | — |
| 提现审核 | 7610 | withdrawAudit | 7600 |
| **资金概览** | **7620** | **fundOverview** | **7600** |

脚本：在 [`sql/biz_shop_finance_menu.sql`](../../../../sql/biz_shop_finance_menu.sql) **追加** 7620 及按钮权限。

---

## 6. 测试要点

| 编号 | 场景 | 预期 |
|------|------|------|
| T1 | summary 三块 | 与 Σ 各店 wallet/order **一致** |
| T2 | 无 wallet 的店 | 排行余额/冻结为 0；待结算仍可按订单汇总 |
| T3 | 待发货订单 | 该店 pendingSettleAmount 含 pay_amount |
| T4 | 确认收货后 | 订单收支 log；总余额↑、待结算↓ |
| T5 | 提现 submit / 审核 | 2/3/4 类 log；总览冻结联动 |
| T6 | shops 默认排序 | 店铺余额 **降序** |
| T7 | shops 列排序 | 三列升/降序切换 |
| T8 | logs shopId | 仅该店流水 |
| T9 | logs shopName | 模糊跨店；**覆盖** shopId |
| T10 | logs 皆空 | 全平台流水 |
| T11 | 与商家端对账 | 同 shopId 指标与流水 **一致** |
| T12 | 已删店有流水 | 排行 **仍展示** 且 deleted=true |

**建议测试类：** `ShopFundServiceImplTest`（扩展 platform 方法）、`PlatformFundOverviewControllerTest`（MockMvc）。

---

## 7. 实现状态

| 项 | 状态 |
|----|------|
| DDL（wallet / fund_log / order / shop） | **已有** |
| 商家 `SellerFundOverviewController` | **已实现**（单店参照） |
| `PlatformFundOverviewController` | **待建** |
| `IShopFundService` 平台概览方法 | **待扩展** |
| Mapper：平台汇总 / 排行 / 跨店流水 | **待扩展** |
| 菜单 SQL 7620 | **待追加** |
| ruoyi-ui 平台资金概览页 | **待建** |
| 排行店名检索 / 导出 / 跳转审核 | **非本期** |

---

## 8. 版本记录

| 版本 | 说明 |
|------|------|
| **v1.0** | 首版：对齐《资金概览功能需求》v1.0；关联账务/提现审核/商家财务；简练 DB/接口设计；RuoYi v3.9.2 + MySQL 5.7.39 |

---

*文档版本：v1.0 · 依据《资金概览功能需求.md》v1.0*
