Compare commits
9 Commits
2253ebea92
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fdd93fc4b | |||
| a79be07c52 | |||
| 7b2f3d77ca | |||
| 1324a52049 | |||
| d4a3bd5847 | |||
| 8b2de75b5f | |||
| c7244b3b87 | |||
| a7f3ee3565 | |||
| 12a263c451 |
@@ -38,7 +38,7 @@ rui-docs/
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 添加 submodule
|
# 添加 submodule
|
||||||
git submodule add ssh://git@git.dev.vifo.cc:222/rui/rui-docs.git docs
|
git submodule add ssh://git@git.vifo.cc:222/rui/rui-docs.git docs
|
||||||
|
|
||||||
# 更新到最新
|
# 更新到最新
|
||||||
git submodule update --remote
|
git submodule update --remote
|
||||||
@@ -50,7 +50,7 @@ git submodule update --init --recursive
|
|||||||
### 独立查看
|
### 独立查看
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone ssh://git@git.dev.vifo.cc:222/rui/rui-docs.git
|
git clone ssh://git@git.vifo.cc:222/rui/rui-docs.git
|
||||||
cd rui-docs
|
cd rui-docs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+27
-8
@@ -7,20 +7,39 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
ai-skills/
|
ai-skills/
|
||||||
├── README.md # 本说明
|
├── README.md # 本说明
|
||||||
├── nacos-config-rules.md # Nacos 配置与 application.yml 规范
|
├── nacos-config-rules.md # Nacos 配置与 application.yml 规范
|
||||||
├── issue-workflow.md # 工单处理流程
|
├── issue-workflow.md # 工单处理流程
|
||||||
├── gitea-api.md # Gitea API 使用指南
|
├── gitea-api.md # Gitea API 使用指南
|
||||||
├── menu-config.md # 菜单配置规范
|
├── menu-config.md # 菜单配置规范
|
||||||
├── commit-standards.md # 提交规范
|
├── commit-standards.md # 提交规范
|
||||||
└── sql-deploy.md # SQL 变更后置流程(推本地库 + 菜单 + 前端工单)
|
├── sql-deploy.md # SQL 变更后置流程(推本地库 + 菜单 + 前端工单)
|
||||||
|
└── gitnexus/ # GitNexus 代码智能技能(所有仓库通用)
|
||||||
|
├── gitnexus-cli/SKILL.md # CLI 命令(索引、状态、清理、Wiki)
|
||||||
|
├── gitnexus-debugging/SKILL.md # 调试追踪(错误定位、根因分析)
|
||||||
|
├── gitnexus-exploring/SKILL.md # 代码探索(架构理解、执行流追踪)
|
||||||
|
├── gitnexus-guide/SKILL.md # 工具参考(工具、资源、Schema)
|
||||||
|
├── gitnexus-impact-analysis/SKILL.md # 影响分析(变更安全评估)
|
||||||
|
└── gitnexus-refactoring/SKILL.md # 重构安全(重命名、提取、拆分)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## GitNexus 技能说明
|
||||||
|
|
||||||
|
GitNexus 技能是从各仓库 `.claude/skills/gitnexus/` 迁移而来的**仓库无关**通用技能。
|
||||||
|
所有仓库(rui-framework、rui-frontend、rui-cashier、rui-payment)的 GitNexus 技能完全相同,
|
||||||
|
因此统一迁移到全局文档仓库维护。
|
||||||
|
|
||||||
## 使用方式
|
## 使用方式
|
||||||
|
|
||||||
各项目通过 submodule 引用后,AI 可在以下路径读取:
|
各项目通过 submodule 引用后,AI 可在以下路径读取:
|
||||||
```
|
```
|
||||||
项目/docs/shared/ai-skills/
|
项目/rui-docs/ai-skills/
|
||||||
|
```
|
||||||
|
|
||||||
|
对于支持 `.claude/skills/` 的 Claude 项目,可以创建符号链接:
|
||||||
|
```bash
|
||||||
|
# 将全局技能链接到项目的 .claude/skills/
|
||||||
|
ln -s ../../rui-docs/ai-skills/gitnexus .claude/skills/gitnexus
|
||||||
```
|
```
|
||||||
|
|
||||||
## 更新流程
|
## 更新流程
|
||||||
|
|||||||
+79
-19
@@ -6,6 +6,47 @@
|
|||||||
~/.config/gitea/token
|
~/.config/gitea/token
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 仓库与 API 地址
|
||||||
|
|
||||||
|
| 仓库 | Git 地址 | API Issue 端点 |
|
||||||
|
|------|---------|---------------|
|
||||||
|
| rui-framework | `ssh://git@git.vifo.cc:222/rui/rui-framework.git` | `https://git.vifo.cc/api/v1/repos/rui/rui-framework/issues` |
|
||||||
|
| rui-cashier | `ssh://git@git.vifo.cc:222/rui/rui-cashier.git` | `https://git.vifo.cc/api/v1/repos/rui/rui-cashier/issues` |
|
||||||
|
| rui-payment | `ssh://git@git.vifo.cc:222/rui/rui-payment.git` | `https://git.vifo.cc/api/v1/repos/rui/rui-payment/issues` |
|
||||||
|
| rui-frontend | `ssh://git@git.vifo.cc:222/rui/rui-frontend.git` | `https://git.vifo.cc/api/v1/repos/rui/rui-frontend/issues` |
|
||||||
|
| rui-docs | `ssh://git@git.vifo.cc:222/rui/rui-docs.git` | `https://git.vifo.cc/api/v1/repos/rui/rui-docs/issues` |
|
||||||
|
|
||||||
|
## 工单路由规则
|
||||||
|
|
||||||
|
AI 必须根据**问题所属模块**向正确的仓库提交 Issue,禁止向错误仓库提交。
|
||||||
|
|
||||||
|
### 按问题类型路由
|
||||||
|
|
||||||
|
| 问题类型 | 提交到 | 示例 |
|
||||||
|
|---------|-------|------|
|
||||||
|
| 框架能力缺失(公共工具、BaseEntity、安全、Feign 等) | rui-framework | 需要新增分布式锁工具类 |
|
||||||
|
| 系统管理、用户管理接口 | rui-framework | 用户编辑接口密码字段处理 |
|
||||||
|
| 收银业务逻辑 | rui-cashier | 收银台需要新增挂单功能 |
|
||||||
|
| 支付业务逻辑 | rui-payment | 支付回调需要新增渠道 |
|
||||||
|
| 前端页面、UI 组件 | rui-frontend | 收银页面需要新增弹窗 |
|
||||||
|
| 文档、规范、技能 | rui-docs | Nacos 配置规范需要补充 |
|
||||||
|
|
||||||
|
### 按 API URL 前缀路由
|
||||||
|
|
||||||
|
| URL 前缀 | 所属仓库 | 说明 |
|
||||||
|
|---------|---------|------|
|
||||||
|
| /system/* | rui-framework | 系统管理、基础框架 |
|
||||||
|
| /user/* | rui-framework | 用户管理、权限相关 |
|
||||||
|
| /cashier/* | rui-cashier | 收银系统 |
|
||||||
|
| /pay/*, /payment/* | rui-payment | 支付系统 |
|
||||||
|
| 其他 | 按业务模块判断 | 参考项目文档或询问用户 |
|
||||||
|
|
||||||
|
### 跨仓库协作原则
|
||||||
|
|
||||||
|
1. **当前仓库能解决的问题**:直接处理,不提 Issue
|
||||||
|
2. **需要其他仓库配合**:向目标仓库提 Issue,并在当前仓库提交中注明 对应工单 {owner}/{repo}#{number}
|
||||||
|
3. **不确定归属**:先向用户确认,不要盲目提交
|
||||||
|
|
||||||
## 创建 Issue(工单)
|
## 创建 Issue(工单)
|
||||||
|
|
||||||
**步骤 1**: 准备 JSON 文件(避免转义问题)
|
**步骤 1**: 准备 JSON 文件(避免转义问题)
|
||||||
@@ -27,7 +68,7 @@ curl -s -X POST \
|
|||||||
-H "Authorization: token ${TOKEN}" \
|
-H "Authorization: token ${TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d @/tmp/issue.json \
|
-d @/tmp/issue.json \
|
||||||
"https://git.dev.vifo.cc/api/v1/repos/{owner}/{repo}/issues"
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues"
|
||||||
```
|
```
|
||||||
|
|
||||||
**示例**(提交到 rui-framework 仓库):
|
**示例**(提交到 rui-framework 仓库):
|
||||||
@@ -38,7 +79,7 @@ curl -s -X POST \
|
|||||||
-H "Authorization: token ${TOKEN}" \
|
-H "Authorization: token ${TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d @/tmp/issue.json \
|
-d @/tmp/issue.json \
|
||||||
"https://git.dev.vifo.cc/api/v1/repos/rui/rui-framework/issues"
|
"https://git.vifo.cc/api/v1/repos/rui/rui-framework/issues"
|
||||||
```
|
```
|
||||||
|
|
||||||
**返回示例**:
|
**返回示例**:
|
||||||
@@ -47,7 +88,7 @@ curl -s -X POST \
|
|||||||
"id": 7,
|
"id": 7,
|
||||||
"number": 2,
|
"number": 2,
|
||||||
"title": "[API-REQ] 用户编辑接口密码字段处理优化",
|
"title": "[API-REQ] 用户编辑接口密码字段处理优化",
|
||||||
"html_url": "https://git.dev.vifo.cc/rui/rui-framework/issues/2",
|
"html_url": "https://git.vifo.cc/rui/rui-framework/issues/2",
|
||||||
"state": "open"
|
"state": "open"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -57,7 +98,15 @@ curl -s -X POST \
|
|||||||
```bash
|
```bash
|
||||||
TOKEN=$(cat ~/.config/gitea/token)
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
curl -s -H "Authorization: token ${TOKEN}" \
|
curl -s -H "Authorization: token ${TOKEN}" \
|
||||||
"https://git.dev.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}"
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 列出仓库所有 Issue
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
|
curl -s -H "Authorization: token ${TOKEN}" \
|
||||||
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues?state=open"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 回复 Issue 评论
|
## 回复 Issue 评论
|
||||||
@@ -68,31 +117,42 @@ curl -s -X POST \
|
|||||||
-H "Authorization: token ${TOKEN}" \
|
-H "Authorization: token ${TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"body": "✅ 已完成\n\n完成内容..."}' \
|
-d '{"body": "✅ 已完成\n\n完成内容..."}' \
|
||||||
"https://git.dev.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}/comments"
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}/comments"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关闭 Issue
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
|
curl -s -X PATCH \
|
||||||
|
-H "Authorization: token ${TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"state": "closed"}' \
|
||||||
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 常用端点
|
## 常用端点
|
||||||
|
|
||||||
| 操作 | 方法 | 端点 |
|
| 操作 | 方法 | 端点 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 创建 Issue | POST | `/api/v1/repos/{owner}/{repo}/issues` |
|
| 创建 Issue | POST | /api/v1/repos/{owner}/{repo}/issues |
|
||||||
| 获取 Issue | GET | `/api/v1/repos/{owner}/{repo}/issues/{id}` |
|
| 获取 Issue | GET | /api/v1/repos/{owner}/{repo}/issues/{id} |
|
||||||
| 创建评论 | POST | `/api/v1/repos/{owner}/{repo}/issues/{id}/comments` |
|
| 列出 Issue | GET | /api/v1/repos/{owner}/{repo}/issues?state=open |
|
||||||
| 获取仓库 | GET | `/api/v1/repos/{owner}/{repo}` |
|
| 创建评论 | POST | /api/v1/repos/{owner}/{repo}/issues/{id}/comments |
|
||||||
|
| 关闭 Issue | PATCH | /api/v1/repos/{owner}/{repo}/issues/{id} |
|
||||||
|
| 获取仓库 | GET | /api/v1/repos/{owner}/{repo} |
|
||||||
|
|
||||||
## Git 远程地址
|
## Git 推送命令
|
||||||
|
|
||||||
|
所有仓库统一使用 `origin` 作为远程名称:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git push origin main
|
||||||
```
|
```
|
||||||
gitea ssh://git@git.dev.vifo.cc:222/rui/{repo}.git
|
|
||||||
```
|
|
||||||
|
|
||||||
**推送命令**: `git push gitea main`(注意不是 origin)
|
|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
|
|
||||||
1. **JSON 内容**: 建议使用文件方式(`-d @file.json`)避免转义问题
|
1. **JSON 内容**: 建议使用文件方式(-d @file.json)避免转义问题
|
||||||
2. **Labels**: 创建 Issue 时 labels 参数需要传入 ID 数组,不是字符串数组
|
2. **Labels**: 创建 Issue 时 labels 参数需要传入 ID 数组,不是字符串数组
|
||||||
3. **返回字段**: `number` 是 Issue 编号,`id` 是内部 ID
|
3. **返回字段**: number 是 Issue 编号,id 是内部 ID
|
||||||
4. **仓库映射**:
|
4. **owner 统一为 rui**: 所有仓库都在 rui 组织下
|
||||||
- rui-framework: `/system/*`, `/user/*`
|
|
||||||
- rui-cashier: `/cashier/*`
|
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
name: gitnexus-cli
|
||||||
|
description: "Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: \"Index this repo\", \"Reanalyze the codebase\", \"Generate a wiki\""
|
||||||
|
---
|
||||||
|
|
||||||
|
# GitNexus CLI Commands
|
||||||
|
|
||||||
|
All commands work via `npx` — no global install required.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### analyze — Build or refresh the index
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx gitnexus analyze
|
||||||
|
```
|
||||||
|
|
||||||
|
Run from the project root. This parses all source files, builds the knowledge graph, writes it to `.gitnexus/`, and generates CLAUDE.md / AGENTS.md context files.
|
||||||
|
|
||||||
|
| Flag | Effect |
|
||||||
|
| -------------- | ---------------------------------------------------------------- |
|
||||||
|
| `--force` | Force full re-index even if up to date |
|
||||||
|
| `--embeddings` | Enable embedding generation for semantic search (off by default) |
|
||||||
|
| `--drop-embeddings` | Drop existing embeddings on rebuild. By default, an `analyze` without `--embeddings` preserves them. |
|
||||||
|
|
||||||
|
**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook detects staleness after `git commit` and `git merge` and notifies the agent to run `analyze` — the hook does not run analyze itself, to avoid blocking the agent for up to 120s and risking KuzuDB corruption on timeout.
|
||||||
|
|
||||||
|
### status — Check index freshness
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx gitnexus status
|
||||||
|
```
|
||||||
|
|
||||||
|
Shows whether the current repo has a GitNexus index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed.
|
||||||
|
|
||||||
|
### clean — Delete the index
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx gitnexus clean
|
||||||
|
```
|
||||||
|
|
||||||
|
Deletes the `.gitnexus/` directory and unregisters the repo from the global registry. Use before re-indexing if the index is corrupt or after removing GitNexus from a project.
|
||||||
|
|
||||||
|
| Flag | Effect |
|
||||||
|
| --------- | ------------------------------------------------- |
|
||||||
|
| `--force` | Skip confirmation prompt |
|
||||||
|
| `--all` | Clean all indexed repos, not just the current one |
|
||||||
|
|
||||||
|
### wiki — Generate documentation from the graph
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx gitnexus wiki
|
||||||
|
```
|
||||||
|
|
||||||
|
Generates repository documentation from the knowledge graph using an LLM. Requires an API key (saved to `~/.gitnexus/config.json` on first use).
|
||||||
|
|
||||||
|
| Flag | Effect |
|
||||||
|
| ------------------- | ----------------------------------------- |
|
||||||
|
| `--force` | Force full regeneration |
|
||||||
|
| `--model <model>` | LLM model (default: minimax/minimax-m2.5) |
|
||||||
|
| `--base-url <url>` | LLM API base URL |
|
||||||
|
| `--api-key <key>` | LLM API key |
|
||||||
|
| `--concurrency <n>` | Parallel LLM calls (default: 3) |
|
||||||
|
| `--gist` | Publish wiki as a public GitHub Gist |
|
||||||
|
|
||||||
|
### list — Show all indexed repos
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx gitnexus list
|
||||||
|
```
|
||||||
|
|
||||||
|
Lists all repositories registered in `~/.gitnexus/registry.json`. The MCP `list_repos` tool provides the same information.
|
||||||
|
|
||||||
|
## After Indexing
|
||||||
|
|
||||||
|
1. **Read `gitnexus://repo/{name}/context`** to verify the index loaded
|
||||||
|
2. Use the other GitNexus skills (`exploring`, `debugging`, `impact-analysis`, `refactoring`) for your task
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **"Not inside a git repository"**: Run from a directory inside a git repo
|
||||||
|
- **Index is stale after re-analyzing**: Restart Claude Code to reload the MCP server
|
||||||
|
- **Embeddings slow**: Omit `--embeddings` (it's off by default) or set `OPENAI_API_KEY` for faster API-based embedding
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
name: gitnexus-debugging
|
||||||
|
description: "Use when the user is debugging a bug, tracing an error, or asking why something fails. Examples: \"Why is X failing?\", \"Where does this error come from?\", \"Trace this bug\""
|
||||||
|
---
|
||||||
|
|
||||||
|
# Debugging with GitNexus
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- "Why is this function failing?"
|
||||||
|
- "Trace where this error comes from"
|
||||||
|
- "Who calls this method?"
|
||||||
|
- "This endpoint returns 500"
|
||||||
|
- Investigating bugs, errors, or unexpected behavior
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. gitnexus_query({query: "<error or symptom>"}) → Find related execution flows
|
||||||
|
2. gitnexus_context({name: "<suspect>"}) → See callers/callees/processes
|
||||||
|
3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow
|
||||||
|
4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed
|
||||||
|
```
|
||||||
|
|
||||||
|
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] Understand the symptom (error message, unexpected behavior)
|
||||||
|
- [ ] gitnexus_query for error text or related code
|
||||||
|
- [ ] Identify the suspect function from returned processes
|
||||||
|
- [ ] gitnexus_context to see callers and callees
|
||||||
|
- [ ] Trace execution flow via process resource if applicable
|
||||||
|
- [ ] gitnexus_cypher for custom call chain traces if needed
|
||||||
|
- [ ] Read source files to confirm root cause
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging Patterns
|
||||||
|
|
||||||
|
| Symptom | GitNexus Approach |
|
||||||
|
| -------------------- | ---------------------------------------------------------- |
|
||||||
|
| Error message | `gitnexus_query` for error text → `context` on throw sites |
|
||||||
|
| Wrong return value | `context` on the function → trace callees for data flow |
|
||||||
|
| Intermittent failure | `context` → look for external calls, async deps |
|
||||||
|
| Performance issue | `context` → find symbols with many callers (hot paths) |
|
||||||
|
| Recent regression | `detect_changes` to see what your changes affect |
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
**gitnexus_query** — find code related to error:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_query({query: "payment validation error"})
|
||||||
|
→ Processes: CheckoutFlow, ErrorHandling
|
||||||
|
→ Symbols: validatePayment, handlePaymentError, PaymentException
|
||||||
|
```
|
||||||
|
|
||||||
|
**gitnexus_context** — full context for a suspect:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_context({name: "validatePayment"})
|
||||||
|
→ Incoming calls: processCheckout, webhookHandler
|
||||||
|
→ Outgoing calls: verifyCard, fetchRates (external API!)
|
||||||
|
→ Processes: CheckoutFlow (step 3/7)
|
||||||
|
```
|
||||||
|
|
||||||
|
**gitnexus_cypher** — custom call chain traces:
|
||||||
|
|
||||||
|
```cypher
|
||||||
|
MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"})
|
||||||
|
RETURN [n IN nodes(path) | n.name] AS chain
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example: "Payment endpoint returns 500 intermittently"
|
||||||
|
|
||||||
|
```
|
||||||
|
1. gitnexus_query({query: "payment error handling"})
|
||||||
|
→ Processes: CheckoutFlow, ErrorHandling
|
||||||
|
→ Symbols: validatePayment, handlePaymentError
|
||||||
|
|
||||||
|
2. gitnexus_context({name: "validatePayment"})
|
||||||
|
→ Outgoing calls: verifyCard, fetchRates (external API!)
|
||||||
|
|
||||||
|
3. READ gitnexus://repo/my-app/process/CheckoutFlow
|
||||||
|
→ Step 3: validatePayment → calls fetchRates (external)
|
||||||
|
|
||||||
|
4. Root cause: fetchRates calls external API without proper timeout
|
||||||
|
```
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
name: gitnexus-exploring
|
||||||
|
description: "Use when the user asks how code works, wants to understand architecture, trace execution flows, or explore unfamiliar parts of the codebase. Examples: \"How does X work?\", \"What calls this function?\", \"Show me the auth flow\""
|
||||||
|
---
|
||||||
|
|
||||||
|
# Exploring Codebases with GitNexus
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- "How does authentication work?"
|
||||||
|
- "What's the project structure?"
|
||||||
|
- "Show me the main components"
|
||||||
|
- "Where is the database logic?"
|
||||||
|
- Understanding code you haven't seen before
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. READ gitnexus://repos → Discover indexed repos
|
||||||
|
2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness
|
||||||
|
3. gitnexus_query({query: "<what you want to understand>"}) → Find related execution flows
|
||||||
|
4. gitnexus_context({name: "<symbol>"}) → Deep dive on specific symbol
|
||||||
|
5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow
|
||||||
|
```
|
||||||
|
|
||||||
|
> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal.
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] READ gitnexus://repo/{name}/context
|
||||||
|
- [ ] gitnexus_query for the concept you want to understand
|
||||||
|
- [ ] Review returned processes (execution flows)
|
||||||
|
- [ ] gitnexus_context on key symbols for callers/callees
|
||||||
|
- [ ] READ process resource for full execution traces
|
||||||
|
- [ ] Read source files for implementation details
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
| Resource | What you get |
|
||||||
|
| --------------------------------------- | ------------------------------------------------------- |
|
||||||
|
| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) |
|
||||||
|
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) |
|
||||||
|
| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) |
|
||||||
|
| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) |
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
**gitnexus_query** — find execution flows related to a concept:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_query({query: "payment processing"})
|
||||||
|
→ Processes: CheckoutFlow, RefundFlow, WebhookHandler
|
||||||
|
→ Symbols grouped by flow with file locations
|
||||||
|
```
|
||||||
|
|
||||||
|
**gitnexus_context** — 360-degree view of a symbol:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_context({name: "validateUser"})
|
||||||
|
→ Incoming calls: loginHandler, apiMiddleware
|
||||||
|
→ Outgoing calls: checkToken, getUserById
|
||||||
|
→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example: "How does payment processing work?"
|
||||||
|
|
||||||
|
```
|
||||||
|
1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes
|
||||||
|
2. gitnexus_query({query: "payment processing"})
|
||||||
|
→ CheckoutFlow: processPayment → validateCard → chargeStripe
|
||||||
|
→ RefundFlow: initiateRefund → calculateRefund → processRefund
|
||||||
|
3. gitnexus_context({name: "processPayment"})
|
||||||
|
→ Incoming: checkoutHandler, webhookHandler
|
||||||
|
→ Outgoing: validateCard, chargeStripe, saveTransaction
|
||||||
|
4. Read src/payments/processor.ts for implementation details
|
||||||
|
```
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
name: gitnexus-guide
|
||||||
|
description: "Use when the user asks about GitNexus itself — available tools, how to query the knowledge graph, MCP resources, graph schema, or workflow reference. Examples: \"What GitNexus tools are available?\", \"How do I use GitNexus?\""
|
||||||
|
---
|
||||||
|
|
||||||
|
# GitNexus Guide
|
||||||
|
|
||||||
|
Quick reference for all GitNexus MCP tools, resources, and the knowledge graph schema.
|
||||||
|
|
||||||
|
## Always Start Here
|
||||||
|
|
||||||
|
For any task involving code understanding, debugging, impact analysis, or refactoring:
|
||||||
|
|
||||||
|
1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness
|
||||||
|
2. **Match your task to a skill below** and **read that skill file**
|
||||||
|
3. **Follow the skill's workflow and checklist**
|
||||||
|
|
||||||
|
> If step 1 warns the index is stale, run `npx gitnexus analyze` in the terminal first.
|
||||||
|
|
||||||
|
## Skills
|
||||||
|
|
||||||
|
| Task | Skill to read |
|
||||||
|
| -------------------------------------------- | ------------------- |
|
||||||
|
| Understand architecture / "How does X work?" | `gitnexus-exploring` |
|
||||||
|
| Blast radius / "What breaks if I change X?" | `gitnexus-impact-analysis` |
|
||||||
|
| Trace bugs / "Why is X failing?" | `gitnexus-debugging` |
|
||||||
|
| Rename / extract / split / refactor | `gitnexus-refactoring` |
|
||||||
|
| Tools, resources, schema reference | `gitnexus-guide` (this file) |
|
||||||
|
| Index, status, clean, wiki CLI commands | `gitnexus-cli` |
|
||||||
|
|
||||||
|
## Tools Reference
|
||||||
|
|
||||||
|
| Tool | What it gives you |
|
||||||
|
| ---------------- | ------------------------------------------------------------------------ |
|
||||||
|
| `query` | Process-grouped code intelligence — execution flows related to a concept |
|
||||||
|
| `context` | 360-degree symbol view — categorized refs, processes it participates in |
|
||||||
|
| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |
|
||||||
|
| `detect_changes` | Git-diff impact — what do your current changes affect |
|
||||||
|
| `rename` | Multi-file coordinated rename with confidence-tagged edits |
|
||||||
|
| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) |
|
||||||
|
| `list_repos` | Discover indexed repos |
|
||||||
|
|
||||||
|
## Resources Reference
|
||||||
|
|
||||||
|
Lightweight reads (~100-500 tokens) for navigation:
|
||||||
|
|
||||||
|
| Resource | Content |
|
||||||
|
| ---------------------------------------------- | ----------------------------------------- |
|
||||||
|
| `gitnexus://repo/{name}/context` | Stats, staleness check |
|
||||||
|
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores |
|
||||||
|
| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members |
|
||||||
|
| `gitnexus://repo/{name}/processes` | All execution flows |
|
||||||
|
| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace |
|
||||||
|
| `gitnexus://repo/{name}/schema` | Graph schema for Cypher |
|
||||||
|
|
||||||
|
## Graph Schema
|
||||||
|
|
||||||
|
**Nodes:** File, Function, Class, Interface, Method, Community, Process
|
||||||
|
**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS
|
||||||
|
|
||||||
|
```cypher
|
||||||
|
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
|
||||||
|
RETURN caller.name, caller.filePath
|
||||||
|
```
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
---
|
||||||
|
name: gitnexus-impact-analysis
|
||||||
|
description: "Use when the user wants to know what will break if they change something, or needs safety analysis before editing code. Examples: \"Is it safe to change X?\", \"What depends on this?\", \"What will break?\""
|
||||||
|
---
|
||||||
|
|
||||||
|
# Impact Analysis with GitNexus
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- "Is it safe to change this function?"
|
||||||
|
- "What will break if I modify X?"
|
||||||
|
- "Show me the blast radius"
|
||||||
|
- "Who uses this code?"
|
||||||
|
- Before making non-trivial code changes
|
||||||
|
- Before committing — to understand what your changes affect
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this
|
||||||
|
2. READ gitnexus://repo/{name}/processes → Check affected execution flows
|
||||||
|
3. gitnexus_detect_changes() → Map current git changes to affected flows
|
||||||
|
4. Assess risk and report to user
|
||||||
|
```
|
||||||
|
|
||||||
|
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents
|
||||||
|
- [ ] Review d=1 items first (these WILL BREAK)
|
||||||
|
- [ ] Check high-confidence (>0.8) dependencies
|
||||||
|
- [ ] READ processes to check affected execution flows
|
||||||
|
- [ ] gitnexus_detect_changes() for pre-commit check
|
||||||
|
- [ ] Assess risk level and report to user
|
||||||
|
```
|
||||||
|
|
||||||
|
## Understanding Output
|
||||||
|
|
||||||
|
| Depth | Risk Level | Meaning |
|
||||||
|
| ----- | ---------------- | ------------------------ |
|
||||||
|
| d=1 | **WILL BREAK** | Direct callers/importers |
|
||||||
|
| d=2 | LIKELY AFFECTED | Indirect dependencies |
|
||||||
|
| d=3 | MAY NEED TESTING | Transitive effects |
|
||||||
|
|
||||||
|
## Risk Assessment
|
||||||
|
|
||||||
|
| Affected | Risk |
|
||||||
|
| ------------------------------ | -------- |
|
||||||
|
| <5 symbols, few processes | LOW |
|
||||||
|
| 5-15 symbols, 2-5 processes | MEDIUM |
|
||||||
|
| >15 symbols or many processes | HIGH |
|
||||||
|
| Critical path (auth, payments) | CRITICAL |
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
**gitnexus_impact** — the primary tool for symbol blast radius:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_impact({
|
||||||
|
target: "validateUser",
|
||||||
|
direction: "upstream",
|
||||||
|
minConfidence: 0.8,
|
||||||
|
maxDepth: 3
|
||||||
|
})
|
||||||
|
|
||||||
|
→ d=1 (WILL BREAK):
|
||||||
|
- loginHandler (src/auth/login.ts:42) [CALLS, 100%]
|
||||||
|
- apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%]
|
||||||
|
|
||||||
|
→ d=2 (LIKELY AFFECTED):
|
||||||
|
- authRouter (src/routes/auth.ts:22) [CALLS, 95%]
|
||||||
|
```
|
||||||
|
|
||||||
|
**gitnexus_detect_changes** — git-diff based impact analysis:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_detect_changes({scope: "staged"})
|
||||||
|
|
||||||
|
→ Changed: 5 symbols in 3 files
|
||||||
|
→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline
|
||||||
|
→ Risk: MEDIUM
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example: "What breaks if I change validateUser?"
|
||||||
|
|
||||||
|
```
|
||||||
|
1. gitnexus_impact({target: "validateUser", direction: "upstream"})
|
||||||
|
→ d=1: loginHandler, apiMiddleware (WILL BREAK)
|
||||||
|
→ d=2: authRouter, sessionManager (LIKELY AFFECTED)
|
||||||
|
|
||||||
|
2. READ gitnexus://repo/my-app/processes
|
||||||
|
→ LoginFlow and TokenRefresh touch validateUser
|
||||||
|
|
||||||
|
3. Risk: 2 direct callers, 2 processes = MEDIUM
|
||||||
|
```
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
---
|
||||||
|
name: gitnexus-refactoring
|
||||||
|
description: "Use when the user wants to rename, extract, split, move, or restructure code safely. Examples: \"Rename this function\", \"Extract this into a module\", \"Refactor this class\", \"Move this to a separate file\""
|
||||||
|
---
|
||||||
|
|
||||||
|
# Refactoring with GitNexus
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- "Rename this function safely"
|
||||||
|
- "Extract this into a module"
|
||||||
|
- "Split this service"
|
||||||
|
- "Move this to a new file"
|
||||||
|
- Any task involving renaming, extracting, splitting, or restructuring code
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents
|
||||||
|
2. gitnexus_query({query: "X"}) → Find execution flows involving X
|
||||||
|
3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs
|
||||||
|
4. Plan update order: interfaces → implementations → callers → tests
|
||||||
|
```
|
||||||
|
|
||||||
|
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
|
||||||
|
|
||||||
|
## Checklists
|
||||||
|
|
||||||
|
### Rename Symbol
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits
|
||||||
|
- [ ] Review graph edits (high confidence) and ast_search edits (review carefully)
|
||||||
|
- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits
|
||||||
|
- [ ] gitnexus_detect_changes() — verify only expected files changed
|
||||||
|
- [ ] Run tests for affected processes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extract Module
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs
|
||||||
|
- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers
|
||||||
|
- [ ] Define new module interface
|
||||||
|
- [ ] Extract code, update imports
|
||||||
|
- [ ] gitnexus_detect_changes() — verify affected scope
|
||||||
|
- [ ] Run tests for affected processes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Split Function/Service
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] gitnexus_context({name: target}) — understand all callees
|
||||||
|
- [ ] Group callees by responsibility
|
||||||
|
- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update
|
||||||
|
- [ ] Create new functions/services
|
||||||
|
- [ ] Update callers
|
||||||
|
- [ ] gitnexus_detect_changes() — verify affected scope
|
||||||
|
- [ ] Run tests for affected processes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
**gitnexus_rename** — automated multi-file rename:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
|
||||||
|
→ 12 edits across 8 files
|
||||||
|
→ 10 graph edits (high confidence), 2 ast_search edits (review)
|
||||||
|
→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}]
|
||||||
|
```
|
||||||
|
|
||||||
|
**gitnexus_impact** — map all dependents first:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_impact({target: "validateUser", direction: "upstream"})
|
||||||
|
→ d=1: loginHandler, apiMiddleware, testUtils
|
||||||
|
→ Affected Processes: LoginFlow, TokenRefresh
|
||||||
|
```
|
||||||
|
|
||||||
|
**gitnexus_detect_changes** — verify your changes after refactoring:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitnexus_detect_changes({scope: "all"})
|
||||||
|
→ Changed: 8 files, 12 symbols
|
||||||
|
→ Affected processes: LoginFlow, TokenRefresh
|
||||||
|
→ Risk: MEDIUM
|
||||||
|
```
|
||||||
|
|
||||||
|
**gitnexus_cypher** — custom reference queries:
|
||||||
|
|
||||||
|
```cypher
|
||||||
|
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"})
|
||||||
|
RETURN caller.name, caller.filePath ORDER BY caller.filePath
|
||||||
|
```
|
||||||
|
|
||||||
|
## Risk Rules
|
||||||
|
|
||||||
|
| Risk Factor | Mitigation |
|
||||||
|
| ------------------- | ----------------------------------------- |
|
||||||
|
| Many callers (>5) | Use gitnexus_rename for automated updates |
|
||||||
|
| Cross-area refs | Use detect_changes after to verify scope |
|
||||||
|
| String/dynamic refs | gitnexus_query to find them |
|
||||||
|
| External/public API | Version and deprecate properly |
|
||||||
|
|
||||||
|
## Example: Rename `validateUser` to `authenticateUser`
|
||||||
|
|
||||||
|
```
|
||||||
|
1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
|
||||||
|
→ 12 edits: 10 graph (safe), 2 ast_search (review)
|
||||||
|
→ Files: validator.ts, login.ts, middleware.ts, config.json...
|
||||||
|
|
||||||
|
2. Review ast_search edits (config.json: dynamic reference!)
|
||||||
|
|
||||||
|
3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false})
|
||||||
|
→ Applied 12 edits across 8 files
|
||||||
|
|
||||||
|
4. gitnexus_detect_changes({scope: "all"})
|
||||||
|
→ Affected: LoginFlow, TokenRefresh
|
||||||
|
→ Risk: MEDIUM — run tests for these flows
|
||||||
|
```
|
||||||
+70
-10
@@ -2,42 +2,102 @@
|
|||||||
|
|
||||||
## 标准流程
|
## 标准流程
|
||||||
|
|
||||||
### 1. 获取工单详情
|
### 1. 读取工单
|
||||||
|
|
||||||
使用 Gitea API 获取 Issue 内容:
|
使用 Gitea API 获取 Issue 内容:
|
||||||
```bash
|
```bash
|
||||||
curl -s -H "Authorization: token $(cat ~/.config/gitea/token)" \
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
"https://git.dev.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}"
|
curl -s -H "Authorization: token ${TOKEN}" \
|
||||||
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}"
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以列出当前仓库所有未关闭的工单:
|
||||||
|
```bash
|
||||||
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
|
curl -s -H "Authorization: token ${TOKEN}" \
|
||||||
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues?state=open"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 分析需求
|
### 2. 分析需求
|
||||||
|
|
||||||
- 阅读工单标题和描述
|
- 阅读工单标题和描述
|
||||||
- 确认需求范围
|
- 确认需求范围是否属于当前仓库
|
||||||
- 检查相关配置文件和代码
|
- 检查相关配置文件和代码
|
||||||
- 必要时向用户澄清
|
- 必要时向用户澄清
|
||||||
|
|
||||||
### 3. 实施修改
|
### 3. 判断工单归属
|
||||||
|
|
||||||
|
如果工单内容不属于当前仓库,需要路由到正确的仓库:
|
||||||
|
|
||||||
|
| 问题类型 | 正确仓库 |
|
||||||
|
|---------|---------|
|
||||||
|
| 框架能力、公共工具、安全、Feign | rui-framework |
|
||||||
|
| 系统管理、用户管理接口 | rui-framework |
|
||||||
|
| 收银业务逻辑 | rui-cashier |
|
||||||
|
| 支付业务逻辑 | rui-payment |
|
||||||
|
| 前端页面、UI 组件 | rui-frontend |
|
||||||
|
| 文档、规范、技能 | rui-docs |
|
||||||
|
|
||||||
|
**路由方式**:在当前仓库回复工单说明需转交,然后向目标仓库创建新 Issue。
|
||||||
|
|
||||||
|
### 4. 实施修改
|
||||||
|
|
||||||
按 Superpowers 工作流处理:
|
按 Superpowers 工作流处理:
|
||||||
- 简单任务:直接实施
|
- 简单任务:直接实施
|
||||||
- 复杂任务:设计 -> 计划 -> 实施
|
- 复杂任务:设计 -> 计划 -> 实施
|
||||||
|
|
||||||
### 4. 回复工单状态
|
### 5. 回复工单
|
||||||
|
|
||||||
完成后必须回复工单:
|
完成后必须回复工单:
|
||||||
```bash
|
```bash
|
||||||
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
curl -s -X POST \
|
curl -s -X POST \
|
||||||
-H "Authorization: token $(cat ~/.config/gitea/token)" \
|
-H "Authorization: token ${TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"body": "✅ 已完成\n\n完成内容..."}' \
|
-d '{"body": "✅ 已完成\n\n完成内容..."}' \
|
||||||
"https://git.dev.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}/comments"
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}/comments"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 关闭工单
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
|
curl -s -X PATCH \
|
||||||
|
-H "Authorization: token ${TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"state": "closed"}' \
|
||||||
|
"https://git.vifo.cc/api/v1/repos/{owner}/{repo}/issues/{id}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 跨仓库提工单
|
||||||
|
|
||||||
|
当当前仓库开发中需要其他仓库配合时:
|
||||||
|
|
||||||
|
1. 确认问题属于目标仓库
|
||||||
|
2. 通过 Gitea API 向目标仓库创建 Issue
|
||||||
|
3. 在当前仓库的 git commit 中注明关联工单
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 示例:payment 需要框架新增能力,向 rui-framework 提交
|
||||||
|
cat > /tmp/issue.json << 'EOF'
|
||||||
|
{
|
||||||
|
"title": "[API-REQ] 需要新增支付回调重试工具",
|
||||||
|
"body": "## 来源\n\nrui-payment 模块请求\n\n## 功能描述\n\n...\n\n## 优先级\n\n高"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
TOKEN=$(cat ~/.config/gitea/token)
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token ${TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d @/tmp/issue.json \
|
||||||
|
"https://git.vifo.cc/api/v1/repos/rui/rui-framework/issues"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 提交规范
|
## 提交规范
|
||||||
|
|
||||||
- 提交信息需关联工单编号:`对应工单 #2`
|
- 提交信息需关联工单编号:对应工单 #2
|
||||||
- 使用语义化提交前缀:`feat:`, `fix:`, `docs:`, `chore:`
|
- 使用语义化提交前缀:feat:, fix:, docs:, chore:
|
||||||
|
|
||||||
## 优先级处理
|
## 优先级处理
|
||||||
|
|
||||||
|
|||||||
@@ -64,4 +64,4 @@
|
|||||||
|
|
||||||
- 由**超级租户**读取 JSON 配置并初始化到数据库
|
- 由**超级租户**读取 JSON 配置并初始化到数据库
|
||||||
- 不需要编写 SQL 脚本或 Java 初始化代码
|
- 不需要编写 SQL 脚本或 Java 初始化代码
|
||||||
- 修改 JSON 后提交到 spring-ai 仓库即可
|
- 修改 JSON 后提交到 rui-framework 仓库即可
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
# AI 助手使用指南(开发者手册)
|
||||||
|
|
||||||
|
> 本文档面向**开发者**,帮助你高效指挥 AI 助手完成开发任务。
|
||||||
|
> 不是给 AI 读的——AI 的规则在仓库根目录的 `AGENTS.md` 中。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、开工前准备
|
||||||
|
|
||||||
|
### 1. 确认 AI 已读取规则
|
||||||
|
|
||||||
|
让 AI 读一遍 `AGENTS.md`,确认它了解自己的身份和边界:
|
||||||
|
|
||||||
|
> "读一下 AGENTS.md,确认你了解当前项目的规则"
|
||||||
|
|
||||||
|
### 2. 更新文档子模块
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule update --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
全局技能、规范、GitNexus 指南都在 `docs/` 子模块里,保持最新。
|
||||||
|
|
||||||
|
### 3. 更新 GitNexus 索引
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx gitnexus analyze
|
||||||
|
```
|
||||||
|
|
||||||
|
索引过期会导致 AI 无法准确分析代码影响,建议每次开工前跑一次。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、常用指令
|
||||||
|
|
||||||
|
以下是你可以直接发给 AI 的指令模板。
|
||||||
|
|
||||||
|
### 代码探索
|
||||||
|
|
||||||
|
| 你想做什么 | 发给 AI |
|
||||||
|
|-----------|---------|
|
||||||
|
| 理解某个功能怎么运作 | "支付订单创建流程是怎么走的?" |
|
||||||
|
| 查看某个类的所有调用者 | "PayOrderServiceImpl 被哪些地方调用了?" |
|
||||||
|
| 了解项目整体架构 | "帮我梳理下支付模块的结构" |
|
||||||
|
|
||||||
|
### 代码修改
|
||||||
|
|
||||||
|
| 你想做什么 | 发给 AI |
|
||||||
|
|-----------|---------|
|
||||||
|
| 新增功能 | "在支付渠道中新增一个 XX 渠道" |
|
||||||
|
| 修复 Bug | "支付回调偶尔会重复处理,帮我排查" |
|
||||||
|
| 重构代码 | "PayOrderService 太大了,帮我拆分" |
|
||||||
|
| 重命名 | "把 PayOrderServiceImpl 的 createOrder 方法改名为 createPayOrder" |
|
||||||
|
|
||||||
|
### 工单处理
|
||||||
|
|
||||||
|
| 你想做什么 | 发给 AI |
|
||||||
|
|-----------|---------|
|
||||||
|
| 读取工单 | "看下 #3 号工单" |
|
||||||
|
| 处理工单 | "处理一下 #3 号工单的需求" |
|
||||||
|
| 跨仓库提需求 | "支付需要框架新增一个 XX 工具,帮我提个 Issue 给 rui-framework" |
|
||||||
|
| 查看未关闭工单 | "看下当前仓库有哪些未关闭的 Issue" |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、GitNexus 速查
|
||||||
|
|
||||||
|
AI 通过 GitNexus 知识图谱理解代码。以下是你可能用到的操作:
|
||||||
|
|
||||||
|
### 常用场景
|
||||||
|
|
||||||
|
| 场景 | 你可以说 |
|
||||||
|
|------|---------|
|
||||||
|
| 修改前评估影响 | "改 PayOrderServiceImpl 会不会影响其他地方?" |
|
||||||
|
| 查看变更范围 | "帮我检查下改了哪些东西" |
|
||||||
|
| 理解执行流 | "退款流程是怎么走的,从头到尾画一下" |
|
||||||
|
| 查找代码 | "项目里哪里处理了支付回调?" |
|
||||||
|
|
||||||
|
### 索引维护
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 重新分析代码库(建议每天或大改动后执行)
|
||||||
|
npx gitnexus analyze
|
||||||
|
|
||||||
|
# 查看索引状态
|
||||||
|
npx gitnexus status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、精简 AGENTS.md
|
||||||
|
|
||||||
|
AGENTS.md 是 AI 的规则文件,应该保持精简。以下原则供你维护时参考:
|
||||||
|
|
||||||
|
### 分类原则
|
||||||
|
|
||||||
|
| 类型 | 放哪里 | 举例 |
|
||||||
|
|------|-------|------|
|
||||||
|
| AI 必须遵守的硬规则 | `AGENTS.md` | 禁止改框架、修改前必须 impact 分析 |
|
||||||
|
| AI 需要的技能/知识 | `docs/ai-skills/` | Gitea API 用法、Nacos 配置规范 |
|
||||||
|
| 通用编码规范 | `docs/standards/` | 命名规范、数据库规范 |
|
||||||
|
|
||||||
|
### 检查清单
|
||||||
|
|
||||||
|
- [ ] 同一件事有没有在多处重复?→ 只保留一处
|
||||||
|
- [ ] 有没有把代码示例写进规则?→ 代码示例是技能,不是规则
|
||||||
|
- [ ] 编码规范是否指向了全局文档?→ 不在本仓库重复
|
||||||
|
- [ ] 仓库名、路径是否正确?→ spring-ai 已改为 rui-framework
|
||||||
|
- [ ] GitNexus 段落是否精简?→ 只保留规则和资源表
|
||||||
|
|
||||||
|
### 典型精简操作
|
||||||
|
|
||||||
|
**删除技能混入规则:**
|
||||||
|
- Feign/REST 代码示例 → AI 已知,不需要教
|
||||||
|
- 工单路由表 → 已在 `docs/ai-skills/gitea-api.md`
|
||||||
|
|
||||||
|
**合并重复项:**
|
||||||
|
- "仓库职责" + "允许范围" → 合并为"项目结构"+"只允许修改"
|
||||||
|
- GitNexus Always/Never 6 条 → 合并为 4 条规则
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、目录结构速查
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/ # 全局文档(rui-docs submodule)
|
||||||
|
├── ai-skills/ # AI 技能库
|
||||||
|
│ ├── quickstart.md # 👈 你在这里
|
||||||
|
│ ├── gitea-api.md # Gitea API + 工单路由规则
|
||||||
|
│ ├── issue-workflow.md # 工单处理流程
|
||||||
|
│ ├── commit-standards.md # 提交规范
|
||||||
|
│ ├── nacos-config-rules.md # Nacos 配置规范
|
||||||
|
│ ├── menu-config.md # 菜单配置规范
|
||||||
|
│ └── gitnexus/ # GitNexus 技能(6个)
|
||||||
|
├── standards/ # 通用规范
|
||||||
|
│ ├── coding-standards.md # 编码规范
|
||||||
|
│ ├── API设计规范.md
|
||||||
|
│ └── 数据库设计规范分析.md
|
||||||
|
├── backend/ # 后端文档
|
||||||
|
│ ├── guides/ # 操作指南
|
||||||
|
│ ├── design/ # 设计文档
|
||||||
|
│ ├── specs/ # 规格说明
|
||||||
|
│ └── templates/ # 文档模板
|
||||||
|
└── frontend/ # 前端文档
|
||||||
|
```
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
# 支付模块接口设计
|
||||||
|
|
||||||
|
> **来源**: `~/rui/支付模块架构设计.md` v1.0
|
||||||
|
> **创建日期**: 2026-06-08
|
||||||
|
> **模块**: rui-payment
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、接口分层
|
||||||
|
|
||||||
|
| 层级 | 路径前缀 | 认证 | 说明 |
|
||||||
|
|------|---------|------|------|
|
||||||
|
| 对外接口 | `/payment/open/**` | 需认证 | 商户/业务系统调用 |
|
||||||
|
| 对外入口 | `/payment/entry/**` | 免认证 | 收银台、扫码支付 |
|
||||||
|
| 第三方回调 | `/payment/notify/**` | 免认证 | 支付/退款异步通知 |
|
||||||
|
| 内部接口 | `/payment/inner/**` | @Inner | 微服务间调用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、对外接口(需认证)
|
||||||
|
|
||||||
|
### 2.1 支付交易 `/payment/open/trade`
|
||||||
|
|
||||||
|
#### 统一下单 `POST /payment/open/trade/pay`
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 请求
|
||||||
|
{
|
||||||
|
"channel": "alipay", // PayChannel 枚举
|
||||||
|
"payType": "app", // PayType 枚举
|
||||||
|
"merchantOrderNo": "BIZ2026060801", // 业务订单号
|
||||||
|
"subject": "商品标题",
|
||||||
|
"body": "商品描述",
|
||||||
|
"amount": 100.00, // BigDecimal,元
|
||||||
|
"currency": "CNY",
|
||||||
|
"notifyUrl": "https://xxx/notify",
|
||||||
|
"returnUrl": "https://xxx/return",
|
||||||
|
"clientIp": "127.0.0.1",
|
||||||
|
"userId": "oXXXXXXXX" // 微信 JSAPI 需要 openid
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"success": true,
|
||||||
|
"channelOrderNo": null,
|
||||||
|
"payParams": { // 支付宝 APP
|
||||||
|
"orderInfo": "alipay_sdk=..."
|
||||||
|
},
|
||||||
|
// 或 "payUrl": "<form>...</form>", // 支付宝 H5/PC
|
||||||
|
// 或 "payQrCode": "weixin://...", // 微信 Native
|
||||||
|
// 或 "payParams": {"prepayId": "..."} // 微信 JSAPI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 统一执行入口 `POST /payment/open/trade/execute`
|
||||||
|
|
||||||
|
支持所有渠道和动作的通用入口。
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 请求
|
||||||
|
{
|
||||||
|
"channel": "alipay",
|
||||||
|
"action": "query",
|
||||||
|
"merchantOrderNo": "PAY20260608001"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应 — 查询示例
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"success": true,
|
||||||
|
"channelOrderNo": "20260608...",
|
||||||
|
"payParams": {
|
||||||
|
"tradeStatus": "TRADE_SUCCESS",
|
||||||
|
"totalAmount": "100.00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 详细的 PayRequest/PayResponse 字段说明和每个 Action 的请求/返回示例见 `rui-payment-provider/API.md`。
|
||||||
|
|
||||||
|
### 2.2 退款 `/payment/open/refund`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/open/refund/apply` | POST | 申请退款 |
|
||||||
|
| `/payment/open/refund/{refundNo}` | GET | 查询退款单 |
|
||||||
|
|
||||||
|
#### 申请退款 `POST /payment/open/refund/apply`
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 请求 PayRefundApplyRequest
|
||||||
|
{
|
||||||
|
"orderNo": "PAY20260608001",
|
||||||
|
"refundAmount": 50.00,
|
||||||
|
"refundReason": "用户申请退款",
|
||||||
|
"notifyUrl": "https://xxx/refund_notify"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应 PayRefundVO
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"refundNo": "REF20260608001",
|
||||||
|
"orderNo": "PAY20260608001",
|
||||||
|
"refundAmount": 50.00,
|
||||||
|
"refundStatus": 0, // 0:退款中 1:退款成功 2:退款失败
|
||||||
|
"channelRefundNo": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 分账 `/payment/open/split`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/open/split/create` | POST | 创建分账订单 |
|
||||||
|
| `/payment/open/split/{splitNo}` | GET | 查询分账订单 |
|
||||||
|
| `/payment/open/split/execute/{splitNo}` | POST | 执行分账(手动触发) |
|
||||||
|
| `/payment/open/split/return/{splitNo}` | POST | 回退分账 |
|
||||||
|
|
||||||
|
#### 创建分账订单 `POST /payment/open/split/create`
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 请求 SplitOrderCreateRequest
|
||||||
|
{
|
||||||
|
"orderNo": "PAY20260608001",
|
||||||
|
"splitReceivers": [
|
||||||
|
{
|
||||||
|
"receiverId": 1,
|
||||||
|
"receiverType": 1,
|
||||||
|
"receiverName": "商户A",
|
||||||
|
"amount": 30.00,
|
||||||
|
"rate": 0.30
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4 商户进件 `/payment/open/merchant`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/open/merchant/apply` | POST | 提交商户入驻申请 |
|
||||||
|
| `/payment/open/merchant/{merchantNo}` | GET | 查询商户信息 |
|
||||||
|
| `/payment/open/merchant/{merchantNo}` | PUT | 更新商户信息 |
|
||||||
|
| `/payment/open/merchant/qualification/upload` | POST | 提交资质材料 |
|
||||||
|
| `/payment/open/merchant/qualification/{merchantNo}` | GET | 查询资质列表 |
|
||||||
|
| `/payment/open/merchant/audit/{merchantNo}` | GET | 查询审核记录 |
|
||||||
|
| `/payment/open/merchant/channel/{merchantNo}` | GET | 查询渠道配置 |
|
||||||
|
| `/payment/open/merchant/channel/apply` | POST | 申请渠道开通 |
|
||||||
|
| `/payment/open/merchant/settle/{merchantNo}` | GET | 查询结算配置 |
|
||||||
|
| `/payment/open/merchant/settle/{merchantNo}` | PUT | 更新结算配置 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、对外入口(免认证)
|
||||||
|
|
||||||
|
### `/payment/entry`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/entry/cashier/{orderNo}` | GET | 收银台页面(H5) |
|
||||||
|
| `/payment/entry/scan` | POST | 扫码支付 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、第三方回调(免认证)
|
||||||
|
|
||||||
|
### `/payment/notify`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/notify/alipay` | POST | 支付宝支付回调 |
|
||||||
|
| `/payment/notify/wechat_pay` | POST | 微信支付回调(JSON body) |
|
||||||
|
| `/payment/notify/unionpay` | POST | 银联支付回调 |
|
||||||
|
| `/payment/notify/alipay/refund` | POST | 支付宝退款回调 |
|
||||||
|
| `/payment/notify/wechat_pay/refund` | POST | 微信退款回调(JSON body) |
|
||||||
|
|
||||||
|
#### 支付宝回调
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /payment/notify/alipay
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
out_trade_no=PAY20260608001&trade_no=20260608...&trade_status=TRADE_SUCCESS&total_amount=100.00&...
|
||||||
|
```
|
||||||
|
|
||||||
|
- 返回纯文本 `"success"` 表示成功,`"fail"` 表示失败
|
||||||
|
|
||||||
|
#### 微信回调
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /payment/notify/wechat_pay
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"id":"xxx","create_time":"...","resource_type":"encrypt-resource","event_type":"TRANSACTION.SUCCESS","resource":{...}}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 请求头携带 `Wechatpay-Serial`, `Wechatpay-Nonce`, `Wechatpay-Signature`, `Wechatpay-Timestamp`
|
||||||
|
- 返回 JSON `{"code":"SUCCESS","message":"成功"}`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、内部接口(@Inner)
|
||||||
|
|
||||||
|
### `/payment/inner`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/inner/order/status/{orderNo}` | GET | 查询支付状态 |
|
||||||
|
| `/payment/inner/order/biz/{bizOrderNo}` | GET | 根据业务订单号查询 |
|
||||||
|
| `/payment/inner/order/create` | POST | 创建支付订单(内部调用) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、管理后台接口
|
||||||
|
|
||||||
|
### 6.1 支付渠道管理 `/payment/admin/channel`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/admin/channel/list` | GET | 渠道列表 |
|
||||||
|
| `/payment/admin/channel/{id}` | GET | 渠道详情 |
|
||||||
|
| `/payment/admin/channel` | POST | 新增渠道 |
|
||||||
|
| `/payment/admin/channel/{id}` | PUT | 修改渠道 |
|
||||||
|
| `/payment/admin/channel/{id}/enable` | PUT | 启用渠道 |
|
||||||
|
| `/payment/admin/channel/{id}/disable` | PUT | 停用渠道 |
|
||||||
|
|
||||||
|
### 6.2 代理商管理 `/payment/admin/agent`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/admin/agent/list` | GET | 代理商列表 |
|
||||||
|
| `/payment/admin/agent/{id}` | GET | 代理商详情 |
|
||||||
|
| `/payment/admin/agent` | POST | 新增代理商 |
|
||||||
|
| `/payment/admin/agent/{id}` | PUT | 修改代理商 |
|
||||||
|
| `/payment/admin/agent/{id}/commission` | GET | 佣金记录 |
|
||||||
|
| `/payment/admin/agent/{id}/settlement` | GET | 结算记录 |
|
||||||
|
|
||||||
|
### 6.3 结算管理 `/payment/admin/settle`
|
||||||
|
|
||||||
|
| 接口 | 方法 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/payment/admin/settle/list` | GET | 结算单列表 |
|
||||||
|
| `/payment/admin/settle/{id}` | GET | 结算单详情 |
|
||||||
|
| `/payment/admin/settle/generate` | POST | 生成结算单 |
|
||||||
|
| `/payment/admin/settle/{id}/confirm` | POST | 确认结算 |
|
||||||
@@ -0,0 +1,802 @@
|
|||||||
|
# 支付模块数据库设计
|
||||||
|
|
||||||
|
> **来源**: `~/rui/支付模块架构设计.md` v1.0
|
||||||
|
> **创建日期**: 2026-06-08
|
||||||
|
> **模块**: rui-payment
|
||||||
|
> **表数量**: 21 张
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ER 关系概览
|
||||||
|
|
||||||
|
```
|
||||||
|
pay_order ──→ pay_record ──→ pay_channel_merchant
|
||||||
|
│ │
|
||||||
|
↓ ↓
|
||||||
|
pay_refund pay_channel
|
||||||
|
|
||||||
|
pay_merchant ──→ pay_merchant_qualification ──→ pay_merchant_audit
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
pay_merchant_channel ──→ pay_merchant_settle
|
||||||
|
|
||||||
|
pay_split_order ──→ pay_split_detail ──→ pay_split_receiver
|
||||||
|
|
||||||
|
pay_agent ──→ pay_agent_merchant ──→ pay_agent_commission ──→ pay_agent_settlement
|
||||||
|
|
||||||
|
pay_account ──→ pay_account_record
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
pay_account_freeze
|
||||||
|
|
||||||
|
pay_reconcile ──→ pay_reconcile_diff
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.1 支付核心表
|
||||||
|
|
||||||
|
#### 3.1.1 支付订单表 (pay_order)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_order (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
order_no VARCHAR(64) NOT NULL COMMENT '支付订单号(系统生成)',
|
||||||
|
biz_order_no VARCHAR(64) NOT NULL COMMENT '业务订单号(外部传入)',
|
||||||
|
biz_type TINYINT NOT NULL DEFAULT 1 COMMENT '业务类型 1:订单支付 2:充值 3:转账',
|
||||||
|
subject VARCHAR(256) NOT NULL COMMENT '订单标题',
|
||||||
|
body VARCHAR(500) DEFAULT NULL COMMENT '订单描述',
|
||||||
|
total_amount DECIMAL(19,4) NOT NULL COMMENT '订单总金额',
|
||||||
|
pay_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '实际支付金额',
|
||||||
|
discount_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '优惠金额',
|
||||||
|
fee_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '手续费金额',
|
||||||
|
currency VARCHAR(10) NOT NULL DEFAULT 'CNY' COMMENT '币种',
|
||||||
|
payer_id BIGINT DEFAULT NULL COMMENT '付款人ID',
|
||||||
|
payer_type TINYINT NOT NULL DEFAULT 1 COMMENT '付款人类型 1:用户 2:商户',
|
||||||
|
payer_name VARCHAR(100) DEFAULT NULL COMMENT '付款人名称',
|
||||||
|
payee_id BIGINT NOT NULL COMMENT '收款人ID(商户ID)',
|
||||||
|
payee_type TINYINT NOT NULL DEFAULT 1 COMMENT '收款人类型 1:商户 2:平台',
|
||||||
|
payee_name VARCHAR(100) DEFAULT NULL COMMENT '收款人名称',
|
||||||
|
channel_id BIGINT DEFAULT NULL COMMENT '支付渠道ID',
|
||||||
|
channel_code VARCHAR(50) DEFAULT NULL COMMENT '支付渠道编码',
|
||||||
|
pay_status TINYINT NOT NULL DEFAULT 0 COMMENT '支付状态 0:待支付 1:支付中 2:支付成功 3:支付失败 4:已关闭 5:已退款',
|
||||||
|
pay_time DATETIME(3) DEFAULT NULL COMMENT '支付成功时间',
|
||||||
|
expire_time DATETIME(3) NOT NULL COMMENT '订单过期时间',
|
||||||
|
client_ip VARCHAR(128) DEFAULT NULL COMMENT '客户端IP',
|
||||||
|
device VARCHAR(100) DEFAULT NULL COMMENT '设备信息',
|
||||||
|
notify_url VARCHAR(500) DEFAULT NULL COMMENT '异步通知地址',
|
||||||
|
return_url VARCHAR(500) DEFAULT NULL COMMENT '同步跳转地址',
|
||||||
|
extra_params JSON DEFAULT NULL COMMENT '扩展参数(渠道特定参数)',
|
||||||
|
error_code VARCHAR(100) DEFAULT NULL COMMENT '错误码',
|
||||||
|
error_msg VARCHAR(500) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:禁用 1:启用',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除 0:正常 1:删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_order_no (tenant_id, order_no),
|
||||||
|
UNIQUE KEY uk_biz_order_no (tenant_id, biz_order_no, biz_type),
|
||||||
|
INDEX idx_pay_status (pay_status),
|
||||||
|
INDEX idx_payee_id (payee_id),
|
||||||
|
INDEX idx_payer_id (payer_id),
|
||||||
|
INDEX idx_channel_id (channel_id),
|
||||||
|
INDEX idx_pay_time (pay_time),
|
||||||
|
INDEX idx_created_at (created_at),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='支付订单表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.1.2 支付流水表 (pay_record)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_record (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
record_no VARCHAR(64) NOT NULL COMMENT '流水号',
|
||||||
|
order_id BIGINT NOT NULL COMMENT '支付订单ID',
|
||||||
|
order_no VARCHAR(64) NOT NULL COMMENT '支付订单号',
|
||||||
|
channel_id BIGINT NOT NULL COMMENT '支付渠道ID',
|
||||||
|
channel_code VARCHAR(50) NOT NULL COMMENT '渠道编码',
|
||||||
|
channel_merchant_no VARCHAR(100) DEFAULT NULL COMMENT '渠道商户号',
|
||||||
|
channel_order_no VARCHAR(128) DEFAULT NULL COMMENT '渠道订单号',
|
||||||
|
pay_amount DECIMAL(19,4) NOT NULL COMMENT '支付金额',
|
||||||
|
fee_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '手续费',
|
||||||
|
currency VARCHAR(10) NOT NULL DEFAULT 'CNY' COMMENT '币种',
|
||||||
|
pay_status TINYINT NOT NULL DEFAULT 0 COMMENT '支付状态 0:待支付 1:支付中 2:支付成功 3:支付失败 4:已关闭',
|
||||||
|
pay_time DATETIME(3) DEFAULT NULL COMMENT '支付成功时间',
|
||||||
|
payer_info JSON DEFAULT NULL COMMENT '付款人信息(openid、银行卡号等)',
|
||||||
|
notify_status TINYINT NOT NULL DEFAULT 0 COMMENT '通知状态 0:未通知 1:通知成功 2:通知失败',
|
||||||
|
notify_times INT NOT NULL DEFAULT 0 COMMENT '通知次数',
|
||||||
|
notify_last_time DATETIME(3) DEFAULT NULL COMMENT '最后通知时间',
|
||||||
|
error_code VARCHAR(100) DEFAULT NULL COMMENT '错误码',
|
||||||
|
error_msg VARCHAR(500) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_record_no (tenant_id, record_no),
|
||||||
|
UNIQUE KEY uk_channel_order (tenant_id, channel_id, channel_order_no),
|
||||||
|
INDEX idx_order_id (order_id),
|
||||||
|
INDEX idx_order_no (order_no),
|
||||||
|
INDEX idx_pay_status (pay_status),
|
||||||
|
INDEX idx_pay_time (pay_time),
|
||||||
|
INDEX idx_created_at (created_at),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='支付流水表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.1.3 退款单表 (pay_refund)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_refund (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
refund_no VARCHAR(64) NOT NULL COMMENT '退款单号',
|
||||||
|
order_id BIGINT NOT NULL COMMENT '支付订单ID',
|
||||||
|
order_no VARCHAR(64) NOT NULL COMMENT '支付订单号',
|
||||||
|
record_id BIGINT NOT NULL COMMENT '支付流水ID',
|
||||||
|
record_no VARCHAR(64) NOT NULL COMMENT '支付流水号',
|
||||||
|
channel_id BIGINT NOT NULL COMMENT '支付渠道ID',
|
||||||
|
channel_refund_no VARCHAR(128) DEFAULT NULL COMMENT '渠道退款单号',
|
||||||
|
refund_amount DECIMAL(19,4) NOT NULL COMMENT '退款金额',
|
||||||
|
total_amount DECIMAL(19,4) NOT NULL COMMENT '订单总金额',
|
||||||
|
refund_status TINYINT NOT NULL DEFAULT 0 COMMENT '退款状态 0:待退款 1:退款中 2:退款成功 3:退款失败',
|
||||||
|
refund_time DATETIME(3) DEFAULT NULL COMMENT '退款成功时间',
|
||||||
|
refund_reason VARCHAR(500) DEFAULT NULL COMMENT '退款原因',
|
||||||
|
operator_id BIGINT DEFAULT NULL COMMENT '操作人ID',
|
||||||
|
operator_name VARCHAR(100) DEFAULT NULL COMMENT '操作人名称',
|
||||||
|
notify_status TINYINT NOT NULL DEFAULT 0 COMMENT '通知状态',
|
||||||
|
error_code VARCHAR(100) DEFAULT NULL COMMENT '错误码',
|
||||||
|
error_msg VARCHAR(500) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_refund_no (tenant_id, refund_no),
|
||||||
|
INDEX idx_order_id (order_id),
|
||||||
|
INDEX idx_order_no (order_no),
|
||||||
|
INDEX idx_refund_status (refund_status),
|
||||||
|
INDEX idx_created_at (created_at),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='退款单表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 支付渠道表
|
||||||
|
|
||||||
|
#### 3.2.1 支付渠道表 (pay_channel)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_channel (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
channel_code VARCHAR(50) NOT NULL COMMENT '渠道编码 如:alipay_app,wx_jsapi',
|
||||||
|
channel_name VARCHAR(100) NOT NULL COMMENT '渠道名称',
|
||||||
|
channel_type TINYINT NOT NULL DEFAULT 1 COMMENT '渠道类型 1:支付宝 2:微信支付 3:银联 4:其他',
|
||||||
|
payment_type TINYINT NOT NULL DEFAULT 1 COMMENT '支付方式 1:扫码 2:App 3:H5 4:JSAPI 5:小程序 6:刷脸',
|
||||||
|
config_json JSON NOT NULL COMMENT '渠道配置(JSON格式)',
|
||||||
|
fee_rate DECIMAL(5,4) NOT NULL DEFAULT 0.0060 COMMENT '手续费率(如0.0060=0.6%)',
|
||||||
|
fee_type TINYINT NOT NULL DEFAULT 1 COMMENT '手续费类型 1:百分比 2:固定金额',
|
||||||
|
min_amount DECIMAL(19,4) DEFAULT NULL COMMENT '单笔最小金额',
|
||||||
|
max_amount DECIMAL(19,4) DEFAULT NULL COMMENT '单笔最大金额',
|
||||||
|
day_limit_amount DECIMAL(19,4) DEFAULT NULL COMMENT '单日限额',
|
||||||
|
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序号',
|
||||||
|
is_default TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认渠道 0:否 1:是',
|
||||||
|
weight INT NOT NULL DEFAULT 100 COMMENT '权重(用于路由)',
|
||||||
|
success_rate DECIMAL(5,2) NOT NULL DEFAULT 100.00 COMMENT '成功率(%)',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:禁用 1:启用',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_channel_code (tenant_id, channel_code),
|
||||||
|
INDEX idx_channel_type (channel_type),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='支付渠道表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2.2 渠道商户配置表 (pay_channel_merchant)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_channel_merchant (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
channel_id BIGINT NOT NULL COMMENT '支付渠道ID',
|
||||||
|
merchant_id BIGINT NOT NULL COMMENT '商户ID',
|
||||||
|
merchant_no VARCHAR(100) NOT NULL COMMENT '渠道商户号',
|
||||||
|
app_id VARCHAR(100) DEFAULT NULL COMMENT '应用ID',
|
||||||
|
private_key TEXT DEFAULT NULL COMMENT '商户私钥',
|
||||||
|
public_key TEXT DEFAULT NULL COMMENT '商户公钥',
|
||||||
|
api_key VARCHAR(500) DEFAULT NULL COMMENT 'API密钥',
|
||||||
|
cert_path VARCHAR(500) DEFAULT NULL COMMENT '证书路径',
|
||||||
|
cert_password VARCHAR(100) DEFAULT NULL COMMENT '证书密码',
|
||||||
|
notify_url VARCHAR(500) DEFAULT NULL COMMENT '异步通知地址',
|
||||||
|
return_url VARCHAR(500) DEFAULT NULL COMMENT '同步跳转地址',
|
||||||
|
fee_rate DECIMAL(5,4) NOT NULL DEFAULT 0.0060 COMMENT '商户自定义费率',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_channel_merchant (tenant_id, channel_id, merchant_id),
|
||||||
|
INDEX idx_merchant_id (merchant_id),
|
||||||
|
INDEX idx_channel_id (channel_id),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='渠道商户配置表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 商户进件表
|
||||||
|
|
||||||
|
#### 3.3.1 商户表 (pay_merchant)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_merchant (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
merchant_no VARCHAR(64) NOT NULL COMMENT '商户编号',
|
||||||
|
merchant_name VARCHAR(200) NOT NULL COMMENT '商户名称',
|
||||||
|
merchant_short_name VARCHAR(100) DEFAULT NULL COMMENT '商户简称',
|
||||||
|
merchant_type TINYINT NOT NULL DEFAULT 1 COMMENT '商户类型 1:企业 2:个体户 3:个人',
|
||||||
|
agent_id BIGINT DEFAULT NULL COMMENT '所属代理ID',
|
||||||
|
contact_name VARCHAR(100) NOT NULL COMMENT '联系人姓名',
|
||||||
|
contact_phone VARCHAR(20) NOT NULL COMMENT '联系人电话',
|
||||||
|
contact_email VARCHAR(100) DEFAULT NULL COMMENT '联系人邮箱',
|
||||||
|
province_code VARCHAR(20) DEFAULT NULL COMMENT '省份编码',
|
||||||
|
city_code VARCHAR(20) DEFAULT NULL COMMENT '城市编码',
|
||||||
|
district_code VARCHAR(20) DEFAULT NULL COMMENT '区县编码',
|
||||||
|
address VARCHAR(500) DEFAULT NULL COMMENT '详细地址',
|
||||||
|
logo_url VARCHAR(500) DEFAULT NULL COMMENT '商户Logo',
|
||||||
|
website VARCHAR(500) DEFAULT NULL COMMENT '商户网站',
|
||||||
|
business_scope VARCHAR(500) DEFAULT NULL COMMENT '经营范围',
|
||||||
|
audit_status TINYINT NOT NULL DEFAULT 0 COMMENT '审核状态 0:待提交 1:待审核 2:审核中 3:审核通过 4:审核驳回',
|
||||||
|
audit_remark VARCHAR(500) DEFAULT NULL COMMENT '审核备注',
|
||||||
|
audit_time DATETIME(3) DEFAULT NULL COMMENT '审核时间',
|
||||||
|
merchant_status TINYINT NOT NULL DEFAULT 0 COMMENT '商户状态 0:未激活 1:正常 2:冻结 3:注销',
|
||||||
|
activate_time DATETIME(3) DEFAULT NULL COMMENT '激活时间',
|
||||||
|
total_transaction_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '累计交易金额',
|
||||||
|
total_transaction_count INT NOT NULL DEFAULT 0 COMMENT '累计交易笔数',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_merchant_no (tenant_id, merchant_no),
|
||||||
|
INDEX idx_agent_id (agent_id),
|
||||||
|
INDEX idx_audit_status (audit_status),
|
||||||
|
INDEX idx_merchant_status (merchant_status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='商户表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.2 商户资质表 (pay_merchant_qualification)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_merchant_qualification (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
merchant_id BIGINT NOT NULL COMMENT '商户ID',
|
||||||
|
qual_type TINYINT NOT NULL DEFAULT 1 COMMENT '资质类型 1:营业执照 2:法人身份证正面 3:法人身份证反面 4:开户许可证 5:门头照 6:店内照 7:结算银行卡 8:特殊资质',
|
||||||
|
qual_name VARCHAR(100) NOT NULL COMMENT '资质名称',
|
||||||
|
qual_no VARCHAR(100) DEFAULT NULL COMMENT '资质编号(如营业执照号)',
|
||||||
|
qual_image_url VARCHAR(500) NOT NULL COMMENT '资质图片URL',
|
||||||
|
qual_image_url2 VARCHAR(500) DEFAULT NULL COMMENT '资质图片URL2(反面)',
|
||||||
|
valid_start_date DATE DEFAULT NULL COMMENT '有效期开始',
|
||||||
|
valid_end_date DATE DEFAULT NULL COMMENT '有效期结束',
|
||||||
|
is_permanent TINYINT NOT NULL DEFAULT 0 COMMENT '是否永久有效 0:否 1:是',
|
||||||
|
verify_status TINYINT NOT NULL DEFAULT 0 COMMENT '核验状态 0:未核验 1:核验通过 2:核验失败',
|
||||||
|
verify_result VARCHAR(500) DEFAULT NULL COMMENT '核验结果',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
INDEX idx_merchant_id (merchant_id),
|
||||||
|
INDEX idx_qual_type (qual_type),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='商户资质表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.3 商户审核记录表 (pay_merchant_audit)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_merchant_audit (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
merchant_id BIGINT NOT NULL COMMENT '商户ID',
|
||||||
|
audit_type TINYINT NOT NULL DEFAULT 1 COMMENT '审核类型 1:入驻审核 2:资质变更 3:费率变更 4:结算变更',
|
||||||
|
audit_level TINYINT NOT NULL DEFAULT 1 COMMENT '审核层级 1:初审 2:复审',
|
||||||
|
audit_status TINYINT NOT NULL DEFAULT 0 COMMENT '审核状态 0:待审核 1:审核通过 2:审核驳回',
|
||||||
|
audit_remark VARCHAR(500) DEFAULT NULL COMMENT '审核意见',
|
||||||
|
auditor_id BIGINT DEFAULT NULL COMMENT '审核人ID',
|
||||||
|
auditor_name VARCHAR(100) DEFAULT NULL COMMENT '审核人姓名',
|
||||||
|
audit_time DATETIME(3) DEFAULT NULL COMMENT '审核时间',
|
||||||
|
pre_data JSON DEFAULT NULL COMMENT '变更前数据',
|
||||||
|
post_data JSON DEFAULT NULL COMMENT '变更后数据',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
INDEX idx_merchant_id (merchant_id),
|
||||||
|
INDEX idx_audit_type (audit_type),
|
||||||
|
INDEX idx_audit_status (audit_status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='商户审核记录表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.4 商户渠道配置表 (pay_merchant_channel)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_merchant_channel (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
merchant_id BIGINT NOT NULL COMMENT '商户ID',
|
||||||
|
channel_id BIGINT NOT NULL COMMENT '支付渠道ID',
|
||||||
|
channel_code VARCHAR(50) NOT NULL COMMENT '渠道编码',
|
||||||
|
channel_merchant_no VARCHAR(100) DEFAULT NULL COMMENT '渠道子商户号',
|
||||||
|
channel_app_id VARCHAR(100) DEFAULT NULL COMMENT '渠道应用ID',
|
||||||
|
channel_status TINYINT NOT NULL DEFAULT 0 COMMENT '渠道状态 0:未申请 1:申请中 2:已通过 3:已驳回 4:已停用',
|
||||||
|
apply_time DATETIME(3) DEFAULT NULL COMMENT '申请时间',
|
||||||
|
audit_time DATETIME(3) DEFAULT NULL COMMENT '渠道审核时间',
|
||||||
|
audit_remark VARCHAR(500) DEFAULT NULL COMMENT '渠道审核备注',
|
||||||
|
fee_rate DECIMAL(5,4) NOT NULL DEFAULT 0.0060 COMMENT '商户渠道费率',
|
||||||
|
day_limit_amount DECIMAL(19,4) DEFAULT NULL COMMENT '单日限额',
|
||||||
|
single_limit_amount DECIMAL(19,4) DEFAULT NULL COMMENT '单笔限额',
|
||||||
|
config_json JSON DEFAULT NULL COMMENT '渠道特定配置(JSON)',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_merchant_channel (tenant_id, merchant_id, channel_id),
|
||||||
|
INDEX idx_merchant_id (merchant_id),
|
||||||
|
INDEX idx_channel_id (channel_id),
|
||||||
|
INDEX idx_channel_status (channel_status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='商户渠道配置表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.5 商户结算配置表 (pay_merchant_settle)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_merchant_settle (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
merchant_id BIGINT NOT NULL COMMENT '商户ID',
|
||||||
|
settle_type TINYINT NOT NULL DEFAULT 1 COMMENT '结算方式 1:自动结算 2:手动结算',
|
||||||
|
settle_cycle TINYINT NOT NULL DEFAULT 1 COMMENT '结算周期 1:T+0 2:T+1 3:T+7 4:T+30',
|
||||||
|
min_settle_amount DECIMAL(19,4) NOT NULL DEFAULT 1.0000 COMMENT '最低结算金额',
|
||||||
|
settle_account_type TINYINT NOT NULL DEFAULT 1 COMMENT '结算账户类型 1:对公账户 2:对私账户 3:支付宝 4:微信',
|
||||||
|
settle_account_name VARCHAR(100) NOT NULL COMMENT '结算账户名',
|
||||||
|
settle_account_no VARCHAR(200) NOT NULL COMMENT '结算账号',
|
||||||
|
settle_bank_code VARCHAR(50) DEFAULT NULL COMMENT '结算银行编码',
|
||||||
|
settle_bank_name VARCHAR(100) DEFAULT NULL COMMENT '结算银行名称',
|
||||||
|
settle_bank_branch VARCHAR(200) DEFAULT NULL COMMENT '开户支行',
|
||||||
|
settle_bank_province VARCHAR(50) DEFAULT NULL COMMENT '开户省份',
|
||||||
|
settle_bank_city VARCHAR(50) DEFAULT NULL COMMENT '开户城市',
|
||||||
|
is_default TINYINT NOT NULL DEFAULT 1 COMMENT '是否默认结算配置',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_merchant_settle (tenant_id, merchant_id),
|
||||||
|
INDEX idx_merchant_id (merchant_id),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='商户结算配置表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 分账表
|
||||||
|
|
||||||
|
#### 3.3.1 分账订单表 (pay_split_order)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_split_order (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
split_no VARCHAR(64) NOT NULL COMMENT '分账订单号',
|
||||||
|
order_id BIGINT NOT NULL COMMENT '支付订单ID',
|
||||||
|
order_no VARCHAR(64) NOT NULL COMMENT '支付订单号',
|
||||||
|
record_id BIGINT NOT NULL COMMENT '支付流水ID',
|
||||||
|
total_amount DECIMAL(19,4) NOT NULL COMMENT '分账总金额',
|
||||||
|
split_status TINYINT NOT NULL DEFAULT 0 COMMENT '分账状态 0:待分账 1:分账中 2:分账成功 3:分账失败 4:已回退',
|
||||||
|
split_type TINYINT NOT NULL DEFAULT 1 COMMENT '分账类型 1:实时分账 2:延迟分账',
|
||||||
|
split_mode TINYINT NOT NULL DEFAULT 1 COMMENT '分账模式 1:按比例 2:按固定金额',
|
||||||
|
split_time DATETIME(3) DEFAULT NULL COMMENT '分账成功时间',
|
||||||
|
finish_time DATETIME(3) DEFAULT NULL COMMENT '分账完成时间',
|
||||||
|
return_url VARCHAR(500) DEFAULT NULL COMMENT '异步通知地址',
|
||||||
|
error_code VARCHAR(100) DEFAULT NULL COMMENT '错误码',
|
||||||
|
error_msg VARCHAR(500) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_split_no (tenant_id, split_no),
|
||||||
|
INDEX idx_order_id (order_id),
|
||||||
|
INDEX idx_order_no (order_no),
|
||||||
|
INDEX idx_split_status (split_status),
|
||||||
|
INDEX idx_created_at (created_at),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='分账订单表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.2 分账明细表 (pay_split_detail)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_split_detail (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
split_order_id BIGINT NOT NULL COMMENT '分账订单ID',
|
||||||
|
split_no VARCHAR(64) NOT NULL COMMENT '分账订单号',
|
||||||
|
receiver_id BIGINT NOT NULL COMMENT '接收方ID',
|
||||||
|
receiver_type TINYINT NOT NULL DEFAULT 1 COMMENT '接收方类型 1:商户 2:平台 3:代理商 4:个人',
|
||||||
|
receiver_name VARCHAR(100) DEFAULT NULL COMMENT '接收方名称',
|
||||||
|
split_amount DECIMAL(19,4) NOT NULL COMMENT '分账金额',
|
||||||
|
split_rate DECIMAL(5,4) DEFAULT NULL COMMENT '分账比例',
|
||||||
|
split_status TINYINT NOT NULL DEFAULT 0 COMMENT '分账状态 0:待分账 1:分账中 2:分账成功 3:分账失败',
|
||||||
|
split_time DATETIME(3) DEFAULT NULL COMMENT '分账成功时间',
|
||||||
|
channel_detail_no VARCHAR(128) DEFAULT NULL COMMENT '渠道分账明细单号',
|
||||||
|
error_code VARCHAR(100) DEFAULT NULL COMMENT '错误码',
|
||||||
|
error_msg VARCHAR(500) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
INDEX idx_split_order_id (split_order_id),
|
||||||
|
INDEX idx_split_no (split_no),
|
||||||
|
INDEX idx_receiver_id (receiver_id),
|
||||||
|
INDEX idx_split_status (split_status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='分账明细表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.3 分账接收方表 (pay_split_receiver)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_split_receiver (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
receiver_type TINYINT NOT NULL DEFAULT 1 COMMENT '接收方类型 1:商户 2:平台 3:代理商 4:个人',
|
||||||
|
receiver_id BIGINT NOT NULL COMMENT '接收方业务ID',
|
||||||
|
receiver_name VARCHAR(100) NOT NULL COMMENT '接收方名称',
|
||||||
|
channel_type TINYINT NOT NULL DEFAULT 1 COMMENT '渠道类型 1:支付宝 2:微信 3:银行卡',
|
||||||
|
account_type VARCHAR(50) DEFAULT NULL COMMENT '账户类型 如:login_name(支付宝登录号),openid(微信)',
|
||||||
|
account_no VARCHAR(200) NOT NULL COMMENT '接收账号',
|
||||||
|
account_name VARCHAR(100) DEFAULT NULL COMMENT '账号真实姓名',
|
||||||
|
relation_type TINYINT NOT NULL DEFAULT 1 COMMENT '关系类型 1:服务商 2:门店 3:员工 4:个人',
|
||||||
|
channel_relation_json JSON DEFAULT NULL COMMENT '渠道关系配置(JSON)',
|
||||||
|
is_default TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认接收方',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_receiver (tenant_id, receiver_type, receiver_id, channel_type),
|
||||||
|
INDEX idx_receiver_id (receiver_id),
|
||||||
|
INDEX idx_account_no (account_no),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='分账接收方表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.5 代理商表
|
||||||
|
|
||||||
|
#### 3.4.1 代理商表 (pay_agent)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_agent (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
agent_no VARCHAR(64) NOT NULL COMMENT '代理商编号',
|
||||||
|
agent_name VARCHAR(200) NOT NULL COMMENT '代理商名称',
|
||||||
|
agent_type TINYINT NOT NULL DEFAULT 1 COMMENT '代理商类型 1:个人 2:企业',
|
||||||
|
parent_id BIGINT DEFAULT 0 COMMENT '上级代理ID 0:顶级代理',
|
||||||
|
level TINYINT NOT NULL DEFAULT 1 COMMENT '代理层级 1:一级 2:二级 3:三级',
|
||||||
|
level_path VARCHAR(500) DEFAULT NULL COMMENT '层级路径 如: /1/5/10/',
|
||||||
|
contact_name VARCHAR(100) DEFAULT NULL COMMENT '联系人',
|
||||||
|
contact_phone VARCHAR(20) DEFAULT NULL COMMENT '联系电话',
|
||||||
|
contact_email VARCHAR(100) DEFAULT NULL COMMENT '联系邮箱',
|
||||||
|
id_card VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
|
||||||
|
business_license VARCHAR(100) DEFAULT NULL COMMENT '营业执照号',
|
||||||
|
address VARCHAR(500) DEFAULT NULL COMMENT '地址',
|
||||||
|
commission_rate DECIMAL(5,4) NOT NULL DEFAULT 0.0000 COMMENT '默认佣金比例',
|
||||||
|
min_settle_amount DECIMAL(19,4) NOT NULL DEFAULT 100.0000 COMMENT '最低结算金额',
|
||||||
|
settle_type TINYINT NOT NULL DEFAULT 1 COMMENT '结算类型 1:自动结算 2:手动结算',
|
||||||
|
settle_cycle TINYINT NOT NULL DEFAULT 1 COMMENT '结算周期 1:T+1 2:T+7 3:T+30',
|
||||||
|
settle_account_id BIGINT DEFAULT NULL COMMENT '结算账户ID',
|
||||||
|
merchant_count INT NOT NULL DEFAULT 0 COMMENT '拓展商户数',
|
||||||
|
total_transaction_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '累计交易金额',
|
||||||
|
total_commission_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '累计佣金金额',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:禁用 1:启用 2:审核中',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_agent_no (tenant_id, agent_no),
|
||||||
|
INDEX idx_parent_id (parent_id),
|
||||||
|
INDEX idx_level (level),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='代理商表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.4.2 代理商户关系表 (pay_agent_merchant)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_agent_merchant (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
agent_id BIGINT NOT NULL COMMENT '代理商ID',
|
||||||
|
merchant_id BIGINT NOT NULL COMMENT '商户ID',
|
||||||
|
merchant_name VARCHAR(200) DEFAULT NULL COMMENT '商户名称',
|
||||||
|
commission_rate DECIMAL(5,4) NOT NULL DEFAULT 0.0000 COMMENT '佣金比例(覆盖代理默认比例)',
|
||||||
|
bind_time DATETIME(3) DEFAULT NULL COMMENT '绑定时间',
|
||||||
|
unbind_time DATETIME(3) DEFAULT NULL COMMENT '解绑时间',
|
||||||
|
is_bind TINYINT NOT NULL DEFAULT 1 COMMENT '是否绑定 0:解绑 1:绑定',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_agent_merchant (tenant_id, agent_id, merchant_id),
|
||||||
|
INDEX idx_agent_id (agent_id),
|
||||||
|
INDEX idx_merchant_id (merchant_id),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='代理商户关系表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.4.3 代理佣金记录表 (pay_agent_commission)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_agent_commission (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
commission_no VARCHAR(64) NOT NULL COMMENT '佣金记录号',
|
||||||
|
agent_id BIGINT NOT NULL COMMENT '代理商ID',
|
||||||
|
merchant_id BIGINT NOT NULL COMMENT '商户ID',
|
||||||
|
order_id BIGINT NOT NULL COMMENT '支付订单ID',
|
||||||
|
order_no VARCHAR(64) NOT NULL COMMENT '支付订单号',
|
||||||
|
record_id BIGINT NOT NULL COMMENT '支付流水ID',
|
||||||
|
transaction_amount DECIMAL(19,4) NOT NULL COMMENT '交易金额',
|
||||||
|
commission_rate DECIMAL(5,4) NOT NULL COMMENT '佣金比例',
|
||||||
|
commission_amount DECIMAL(19,4) NOT NULL COMMENT '佣金金额',
|
||||||
|
commission_status TINYINT NOT NULL DEFAULT 0 COMMENT '佣金状态 0:待结算 1:已结算 2:已取消',
|
||||||
|
settle_time DATETIME(3) DEFAULT NULL COMMENT '结算时间',
|
||||||
|
settle_batch_no VARCHAR(64) DEFAULT NULL COMMENT '结算批次号',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_commission_no (tenant_id, commission_no),
|
||||||
|
INDEX idx_agent_id (agent_id),
|
||||||
|
INDEX idx_merchant_id (merchant_id),
|
||||||
|
INDEX idx_order_id (order_id),
|
||||||
|
INDEX idx_commission_status (commission_status),
|
||||||
|
INDEX idx_settle_batch_no (settle_batch_no),
|
||||||
|
INDEX idx_created_at (created_at),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='代理佣金记录表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.4.4 代理结算表 (pay_agent_settlement)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_agent_settlement (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
settlement_no VARCHAR(64) NOT NULL COMMENT '结算单号',
|
||||||
|
agent_id BIGINT NOT NULL COMMENT '代理商ID',
|
||||||
|
settlement_type TINYINT NOT NULL DEFAULT 1 COMMENT '结算类型 1:佣金结算 2:退款扣回',
|
||||||
|
start_time DATETIME(3) NOT NULL COMMENT '结算开始时间',
|
||||||
|
end_time DATETIME(3) NOT NULL COMMENT '结算结束时间',
|
||||||
|
total_count INT NOT NULL DEFAULT 0 COMMENT '结算笔数',
|
||||||
|
total_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '结算总金额',
|
||||||
|
fee_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '手续费金额',
|
||||||
|
actual_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '实际结算金额',
|
||||||
|
settlement_status TINYINT NOT NULL DEFAULT 0 COMMENT '结算状态 0:待结算 1:结算中 2:结算成功 3:结算失败',
|
||||||
|
settlement_time DATETIME(3) DEFAULT NULL COMMENT '结算成功时间',
|
||||||
|
settlement_method TINYINT NOT NULL DEFAULT 1 COMMENT '结算方式 1:转账到余额 2:银行转账 3:支付宝 4:微信',
|
||||||
|
settlement_account VARCHAR(200) DEFAULT NULL COMMENT '结算账户',
|
||||||
|
settlement_account_name VARCHAR(100) DEFAULT NULL COMMENT '结算账户名',
|
||||||
|
settlement_batch_no VARCHAR(128) DEFAULT NULL COMMENT '渠道结算批次号',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_settlement_no (tenant_id, settlement_no),
|
||||||
|
INDEX idx_agent_id (agent_id),
|
||||||
|
INDEX idx_settlement_status (settlement_status),
|
||||||
|
INDEX idx_start_time (start_time),
|
||||||
|
INDEX idx_end_time (end_time),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='代理结算表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.6 资金账户表
|
||||||
|
|
||||||
|
#### 3.5.1 资金账户表 (pay_account)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_account (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
account_no VARCHAR(64) NOT NULL COMMENT '账户号',
|
||||||
|
account_type TINYINT NOT NULL DEFAULT 1 COMMENT '账户类型 1:用户 2:商户 3:平台 4:代理',
|
||||||
|
owner_id BIGINT NOT NULL COMMENT '账户所有者ID',
|
||||||
|
owner_name VARCHAR(100) DEFAULT NULL COMMENT '账户所有者名称',
|
||||||
|
balance DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '账户余额',
|
||||||
|
available_balance DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '可用余额',
|
||||||
|
frozen_balance DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '冻结余额',
|
||||||
|
total_income DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '累计收入',
|
||||||
|
total_expenditure DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '累计支出',
|
||||||
|
currency VARCHAR(10) NOT NULL DEFAULT 'CNY' COMMENT '币种',
|
||||||
|
password_hash VARCHAR(255) DEFAULT NULL COMMENT '支付密码',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:冻结 1:正常',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_account_no (tenant_id, account_no),
|
||||||
|
UNIQUE KEY uk_owner (tenant_id, account_type, owner_id),
|
||||||
|
INDEX idx_owner_id (owner_id),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='资金账户表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.5.2 账户流水表 (pay_account_record)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_account_record (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
record_no VARCHAR(64) NOT NULL COMMENT '流水号',
|
||||||
|
account_id BIGINT NOT NULL COMMENT '账户ID',
|
||||||
|
account_no VARCHAR(64) NOT NULL COMMENT '账户号',
|
||||||
|
record_type TINYINT NOT NULL DEFAULT 1 COMMENT '流水类型 1:收入 2:支出 3:冻结 4:解冻 5:充值 6:提现',
|
||||||
|
biz_type TINYINT NOT NULL DEFAULT 1 COMMENT '业务类型 1:支付 2:退款 3:分账 4:佣金 5:结算 6:提现 7:充值',
|
||||||
|
biz_id BIGINT DEFAULT NULL COMMENT '业务ID',
|
||||||
|
biz_no VARCHAR(64) DEFAULT NULL COMMENT '业务单号',
|
||||||
|
amount DECIMAL(19,4) NOT NULL COMMENT '变动金额',
|
||||||
|
before_balance DECIMAL(19,4) NOT NULL COMMENT '变动前余额',
|
||||||
|
after_balance DECIMAL(19,4) NOT NULL COMMENT '变动后余额',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_record_no (tenant_id, record_no),
|
||||||
|
INDEX idx_account_id (account_id),
|
||||||
|
INDEX idx_biz_id (biz_id),
|
||||||
|
INDEX idx_biz_no (biz_no),
|
||||||
|
INDEX idx_record_type (record_type),
|
||||||
|
INDEX idx_created_at (created_at),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='账户流水表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.5.3 资金冻结表 (pay_account_freeze)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_account_freeze (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
freeze_no VARCHAR(64) NOT NULL COMMENT '冻结单号',
|
||||||
|
account_id BIGINT NOT NULL COMMENT '账户ID',
|
||||||
|
freeze_amount DECIMAL(19,4) NOT NULL COMMENT '冻结金额',
|
||||||
|
freeze_type TINYINT NOT NULL DEFAULT 1 COMMENT '冻结类型 1:退款保障 2:争议处理 3:合规审查',
|
||||||
|
freeze_status TINYINT NOT NULL DEFAULT 0 COMMENT '冻结状态 0:冻结中 1:已解冻 2:已扣款',
|
||||||
|
biz_type TINYINT NOT NULL DEFAULT 1 COMMENT '业务类型 1:订单 2:提现',
|
||||||
|
biz_id BIGINT NOT NULL COMMENT '业务ID',
|
||||||
|
biz_no VARCHAR(64) NOT NULL COMMENT '业务单号',
|
||||||
|
expire_time DATETIME(3) DEFAULT NULL COMMENT '过期自动解冻时间',
|
||||||
|
unfreeze_time DATETIME(3) DEFAULT NULL COMMENT '实际解冻时间',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_freeze_no (tenant_id, freeze_no),
|
||||||
|
INDEX idx_account_id (account_id),
|
||||||
|
INDEX idx_biz_id (biz_id),
|
||||||
|
INDEX idx_freeze_status (freeze_status),
|
||||||
|
INDEX idx_expire_time (expire_time),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='资金冻结表';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.7 对账结算表
|
||||||
|
|
||||||
|
#### 3.6.1 对账单表 (pay_reconcile)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_reconcile (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
reconcile_no VARCHAR(64) NOT NULL COMMENT '对账单号',
|
||||||
|
channel_id BIGINT NOT NULL COMMENT '支付渠道ID',
|
||||||
|
channel_code VARCHAR(50) NOT NULL COMMENT '渠道编码',
|
||||||
|
reconcile_date DATE NOT NULL COMMENT '对账日期',
|
||||||
|
reconcile_type TINYINT NOT NULL DEFAULT 1 COMMENT '对账类型 1:支付对账 2:退款对账',
|
||||||
|
total_count INT NOT NULL DEFAULT 0 COMMENT '总笔数',
|
||||||
|
total_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '总金额',
|
||||||
|
success_count INT NOT NULL DEFAULT 0 COMMENT '对平笔数',
|
||||||
|
success_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '对平金额',
|
||||||
|
fail_count INT NOT NULL DEFAULT 0 COMMENT '差异笔数',
|
||||||
|
fail_amount DECIMAL(19,4) NOT NULL DEFAULT 0.0000 COMMENT '差异金额',
|
||||||
|
missing_count INT NOT NULL DEFAULT 0 COMMENT '漏单笔数(平台有渠道无)',
|
||||||
|
extra_count INT NOT NULL DEFAULT 0 COMMENT '多渠道笔数(渠道有平台无)',
|
||||||
|
amount_diff_count INT NOT NULL DEFAULT 0 COMMENT '金额差异笔数',
|
||||||
|
status TINYINT NOT NULL DEFAULT 0 COMMENT '状态 0:对账中 1:对账成功 2:对账失败 3:已处理',
|
||||||
|
file_url VARCHAR(500) DEFAULT NULL COMMENT '对账文件URL',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status_record TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_reconcile (tenant_id, channel_id, reconcile_date, reconcile_type),
|
||||||
|
INDEX idx_reconcile_date (reconcile_date),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='对账单表';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.6.2 对账差异表 (pay_reconcile_diff)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE pay_reconcile_diff (
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
reconcile_id BIGINT NOT NULL COMMENT '对账单ID',
|
||||||
|
diff_type TINYINT NOT NULL DEFAULT 1 COMMENT '差异类型 1:平台漏单 2:多渠道 3:金额不符 4:状态不符',
|
||||||
|
order_id BIGINT DEFAULT NULL COMMENT '平台订单ID',
|
||||||
|
order_no VARCHAR(64) DEFAULT NULL COMMENT '平台订单号',
|
||||||
|
channel_order_no VARCHAR(128) DEFAULT NULL COMMENT '渠道订单号',
|
||||||
|
platform_amount DECIMAL(19,4) DEFAULT NULL COMMENT '平台金额',
|
||||||
|
channel_amount DECIMAL(19,4) DEFAULT NULL COMMENT '渠道金额',
|
||||||
|
platform_status TINYINT DEFAULT NULL COMMENT '平台状态',
|
||||||
|
channel_status TINYINT DEFAULT NULL COMMENT '渠道状态',
|
||||||
|
handle_status TINYINT NOT NULL DEFAULT 0 COMMENT '处理状态 0:待处理 1:已处理',
|
||||||
|
handle_result TINYINT DEFAULT NULL COMMENT '处理结果 1:补单 2:退款 3:挂账 4:忽略',
|
||||||
|
handle_remark VARCHAR(500) DEFAULT NULL COMMENT '处理备注',
|
||||||
|
handler_id BIGINT DEFAULT NULL COMMENT '处理人ID',
|
||||||
|
handler_name VARCHAR(100) DEFAULT NULL COMMENT '处理人',
|
||||||
|
handle_time DATETIME(3) DEFAULT NULL COMMENT '处理时间',
|
||||||
|
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
INDEX idx_reconcile_id (reconcile_id),
|
||||||
|
INDEX idx_order_id (order_id),
|
||||||
|
INDEX idx_handle_status (handle_status),
|
||||||
|
INDEX idx_tenant_id (tenant_id)
|
||||||
|
) COMMENT='对账差异表';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
# 支付模块架构概览
|
||||||
|
|
||||||
|
> **来源**: `~/rui/支付模块架构设计.md` v1.0
|
||||||
|
> **创建日期**: 2026-06-08
|
||||||
|
> **模块**: rui-payment
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、定位
|
||||||
|
|
||||||
|
rui-payment 是一个**聚合支付平台**,为上层业务提供统一、安全、高效的支付能力。
|
||||||
|
|
||||||
|
### 核心能力
|
||||||
|
|
||||||
|
| 能力 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 聚合支付 | 支持支付宝、微信支付、银联云闪付等多渠道 |
|
||||||
|
| 智能路由 | 根据费率、成功率、渠道状态自动选择最优通道 |
|
||||||
|
| 分账体系 | 平台、商户、代理商多级分账,支持实时/延迟/手动分账 |
|
||||||
|
| 代理商体系 | 三级代理、佣金计算、代理结算 |
|
||||||
|
| 资金账户 | 余额、冻结、可用资金管理和流水记录 |
|
||||||
|
| 商户进件 | 商户入驻、资质上传、审核管理、渠道子商户配置 |
|
||||||
|
| 对账结算 | 自动对账、差错处理、结算单生成 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、模块结构
|
||||||
|
|
||||||
|
```
|
||||||
|
rui-payment/
|
||||||
|
├── rui-payment-common/ # DTO、枚举、常量、工具
|
||||||
|
├── rui-payment-core/ # Mapper、Entity、Service(数据库层)
|
||||||
|
├── rui-payment-provider/ # 第三方支付 SDK 封装(纯网关,不碰 DB)
|
||||||
|
├── rui-payment-api/ # REST API 服务(可部署)
|
||||||
|
└── rui-payment-task/ # MQ 监听器 + 定时任务
|
||||||
|
```
|
||||||
|
|
||||||
|
### 依赖关系
|
||||||
|
|
||||||
|
```
|
||||||
|
rui-payment-common
|
||||||
|
↑
|
||||||
|
rui-payment-core ──→ rui-payment-provider
|
||||||
|
↑ ↑
|
||||||
|
rui-payment-api ←───────┘
|
||||||
|
↑
|
||||||
|
rui-payment-task
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键边界**: `rui-payment-provider` 不依赖 `rui-payment-core`,只做三方 SDK 调用。
|
||||||
|
|
||||||
|
### 各模块职责
|
||||||
|
|
||||||
|
| 模块 | 核心职责 | 典型类 |
|
||||||
|
|------|---------|--------|
|
||||||
|
| common | DTO、VO、枚举、常量 | `PayRequest`, `PayResponse`, `PayStatus` |
|
||||||
|
| core | 业务逻辑、数据访问 | `PayOrderService`, `PayOrderMapper`, `PayOrder` |
|
||||||
|
| provider | 第三方 SDK 封装 | `AlipayPayHandler`, `WechatPayJsapiHandler` |
|
||||||
|
| api | REST API、启动类 | `PaymentTradeController`, `PaymentNotifyController` |
|
||||||
|
| task | 定时任务、MQ 监听 | `ReconcileJob`, `SettlementJob`, `PayTimeoutListener` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、核心业务概念
|
||||||
|
|
||||||
|
### 3.1 支付核心
|
||||||
|
|
||||||
|
```
|
||||||
|
PayOrder (支付订单) ──→ PayRecord (支付流水) ──→ PayChannelConfig (渠道配置)
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
PayRefund (退款单)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **PayOrder**: 业务侧发起的支付请求,含金额、商品信息、买卖双方
|
||||||
|
- **PayRecord**: 单次支付尝试记录,含渠道信息、三方流水号。一个 Order 可对应多次 Record
|
||||||
|
- **PayRefund**: 对已成功支付的订单退款,支持部分退款和多次退款
|
||||||
|
|
||||||
|
### 3.2 分账
|
||||||
|
|
||||||
|
```
|
||||||
|
SplitOrder (分账订单) ──→ SplitDetail (分账明细) ──→ SplitReceiver (分账接收方)
|
||||||
|
```
|
||||||
|
|
||||||
|
分账模式:
|
||||||
|
- **实时分账**: 支付成功后立即调用渠道分账接口
|
||||||
|
- **延迟分账**: 支付成功后冻结资金,延迟期(默认 T+7)后自动分账
|
||||||
|
- **手动分账**: 运营人员在后台手动触发
|
||||||
|
|
||||||
|
### 3.3 代理商
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent (代理商) ──→ AgentRelation (代理关系) ──→ AgentMerchant (代理商户)
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
AgentCommission (代理佣金) ──→ AgentSettlement (代理结算)
|
||||||
|
```
|
||||||
|
|
||||||
|
三级代理体系,每级独立计算佣金。
|
||||||
|
|
||||||
|
### 3.4 资金账户
|
||||||
|
|
||||||
|
```
|
||||||
|
Account (资金账户) ──→ AccountLog (账户流水)
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
AccountFreeze (资金冻结)
|
||||||
|
```
|
||||||
|
|
||||||
|
为每个商户/用户/代理创建独立资金账户,支持冻结、解冻。
|
||||||
|
|
||||||
|
### 3.5 商户进件
|
||||||
|
|
||||||
|
```
|
||||||
|
Merchant (商户) ──→ MerchantQualification (资质) ──→ MerchantAuditRecord (审核)
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
MerchantChannelConfig (渠道配置) ──→ SubMerchantInfo (子商户)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、核心流程
|
||||||
|
|
||||||
|
### 4.1 支付流程
|
||||||
|
|
||||||
|
```
|
||||||
|
业务系统 → 支付API → 支付Core(保存订单) → 支付Provider(调SDK) → 第三方支付
|
||||||
|
↓
|
||||||
|
业务系统 ← 支付API(通知) ← Core(更新状态+分账+佣金) ← Provider(解析回调) ← 异步通知
|
||||||
|
```
|
||||||
|
|
||||||
|
1. 业务系统调用支付 API 创建订单
|
||||||
|
2. API 调 Core 保存订单
|
||||||
|
3. API 通过 Provider 调三方 SDK,返回支付参数
|
||||||
|
4. 用户完成支付,三方异步通知 Provider
|
||||||
|
5. Provider 验签解析,将结果通过 PayResponse 返回
|
||||||
|
6. Core 更新订单状态、记录流水、处理分账和佣金
|
||||||
|
7. API 异步通知业务系统
|
||||||
|
|
||||||
|
### 4.2 分账流程
|
||||||
|
|
||||||
|
```
|
||||||
|
支付成功 → Core(创建分账订单+明细) → Provider(调渠道分账接口) → Core(更新状态+更新账户余额)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 对账流程
|
||||||
|
|
||||||
|
```
|
||||||
|
定时任务 → 下载渠道对账文件 → 与本地订单逐笔比对 → 生成差异记录 → 人工/自动处理差异
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、关键设计决策
|
||||||
|
|
||||||
|
| 决策 | 理由 |
|
||||||
|
|------|------|
|
||||||
|
| 订单与流水分离 | 用户可能多次尝试支付(切换渠道、失败重试),每次需要独立追踪 |
|
||||||
|
| 延迟分账(默认 T+7) | 降低退款风险,符合渠道分账规则,给予平台资金沉淀期 |
|
||||||
|
| 三级代理体系 | 满足大部分场景,避免层级过多导致佣金比例过低 |
|
||||||
|
| 独立资金账户 | 清晰的资金追踪,支持冻结/解冻,便于对账审计 |
|
||||||
|
| Provider 不碰 DB | 纯网关设计,解耦三方 SDK 与业务逻辑,可独立测试和替换 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、安全设计
|
||||||
|
|
||||||
|
| 领域 | 措施 |
|
||||||
|
|------|------|
|
||||||
|
| 支付安全 | 签名验证、敏感信息加密存储、回调 IP 白名单、金额严格校验、幂等控制 |
|
||||||
|
| 资金安全 | 支付密码 BCrypt 加密、资金操作审计日志、风控拦截、退款保障期资金冻结 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、Nacos 配置
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
payment:
|
||||||
|
order-timeout: 30 # 订单超时(分钟)
|
||||||
|
split-delay-days: 7 # 分账延迟(天)
|
||||||
|
commission-settle-cycle: T+1 # 佣金结算周期
|
||||||
|
notify-max-times: 5 # 通知重试次数
|
||||||
|
notify-intervals: 15,30,60,300,900 # 通知间隔(秒)
|
||||||
|
|
||||||
|
channels:
|
||||||
|
alipay:
|
||||||
|
enabled: true
|
||||||
|
sandbox: false
|
||||||
|
app-id: ${ALIPAY_APP_ID}
|
||||||
|
private-key: ${ALIPAY_PRIVATE_KEY}
|
||||||
|
public-key: ${ALIPAY_PUBLIC_KEY}
|
||||||
|
wechatpay:
|
||||||
|
enabled: true
|
||||||
|
sandbox: false
|
||||||
|
app-id: ${WXPAY_APP_ID}
|
||||||
|
mch-id: ${WXPAY_MCH_ID}
|
||||||
|
api-v3-key: ${WXPAY_API_V3_KEY}
|
||||||
|
|
||||||
|
security:
|
||||||
|
oauth2:
|
||||||
|
ignore-urls:
|
||||||
|
- /payment/entry/**
|
||||||
|
- /payment/notify/**
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、待开发功能清单
|
||||||
|
|
||||||
|
- [ ] 支付核心流程(下单、支付、回调、查询、关闭)
|
||||||
|
- [ ] 退款功能(申请、查询、回调)
|
||||||
|
- [ ] 分账功能(创建、执行、回退、查询)
|
||||||
|
- [ ] 商户进件(入驻、资质、审核、渠道配置)
|
||||||
|
- [ ] 代理商体系(多级代理、佣金计算、结算)
|
||||||
|
- [ ] 资金账户(开户、流水、冻结)
|
||||||
|
- [ ] 对账(下载、比对、差异处理)
|
||||||
|
- [ ] 结算(商户结算、代理结算)
|
||||||
|
- [ ] 银联渠道接入
|
||||||
|
- [ ] 单元测试(核心逻辑覆盖率 ≥80%)
|
||||||
@@ -660,5 +660,5 @@ private Long id;
|
|||||||
|
|
||||||
> **文档版本**: v1.0
|
> **文档版本**: v1.0
|
||||||
> **创建日期**: 2026-05-28
|
> **创建日期**: 2026-05-28
|
||||||
> **适用范围**: spring-ai 项目数据库设计
|
> **适用范围**: rui-framework 项目数据库设计
|
||||||
> **状态**: 仅规划,未实施
|
> **状态**: 仅规划,未实施
|
||||||
|
|||||||
+19
-19
@@ -11,7 +11,7 @@
|
|||||||
│ ├── cashier-mobile/
|
│ ├── cashier-mobile/
|
||||||
│ └── customer-mobile/
|
│ └── customer-mobile/
|
||||||
│
|
│
|
||||||
├── spring-ai/ ← 后端框架 AI 工作目录
|
├── rui-framework/ ← 后端框架 AI 工作目录
|
||||||
│ ├── backend/
|
│ ├── backend/
|
||||||
│ │ ├── rui-common/
|
│ │ ├── rui-common/
|
||||||
│ │ ├── rui-gateway/
|
│ │ ├── rui-gateway/
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
│ │ └── rui-service/
|
│ │ └── rui-service/
|
||||||
│ └── docs/
|
│ └── docs/
|
||||||
│
|
│
|
||||||
├── spring-ai/app/
|
├── rui-framework/app/
|
||||||
│ ├── rui-cashier/ ← 收银 AI 工作目录
|
│ ├── rui-cashier/ ← 收银 AI 工作目录
|
||||||
│ └── rui-payment/ ← 支付 AI 工作目录
|
│ └── rui-payment/ ← 支付 AI 工作目录
|
||||||
│
|
│
|
||||||
@@ -70,12 +70,12 @@ cd ~/rhkj/rui-frontend
|
|||||||
|
|
||||||
### 后端框架 AI
|
### 后端框架 AI
|
||||||
|
|
||||||
**工作目录:** `~/rhkj/spring-ai`
|
**工作目录:** `~/rhkj/rui-framework`
|
||||||
|
|
||||||
**启动步骤:**
|
**启动步骤:**
|
||||||
```bash
|
```bash
|
||||||
# 1. 进入后端目录
|
# 1. 进入后端目录
|
||||||
cd ~/rhkj/spring-ai
|
cd ~/rhkj/rui-framework
|
||||||
|
|
||||||
# 2. 打开 OpenCode
|
# 2. 打开 OpenCode
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ cd ~/rhkj/spring-ai
|
|||||||
|
|
||||||
**AI 指令:**
|
**AI 指令:**
|
||||||
```
|
```
|
||||||
你是 Java 后端开发专家。当前项目是 spring-ai(睿核科技后端框架)。
|
你是 Java 后端开发专家。当前项目是 rui-framework(睿核科技后端框架)。
|
||||||
|
|
||||||
技术栈:Spring Boot 3.x + Spring Cloud + JDK 21 + Maven + MyBatis Plus
|
技术栈:Spring Boot 3.x + Spring Cloud + JDK 21 + Maven + MyBatis Plus
|
||||||
|
|
||||||
@@ -108,12 +108,12 @@ cd ~/rhkj/spring-ai
|
|||||||
|
|
||||||
### 收银模块 AI
|
### 收银模块 AI
|
||||||
|
|
||||||
**工作目录:** `~/rhkj/spring-ai/app/rui-cashier`
|
**工作目录:** `~/rhkj/rui-framework/app/rui-cashier`
|
||||||
|
|
||||||
**启动步骤:**
|
**启动步骤:**
|
||||||
```bash
|
```bash
|
||||||
# 1. 进入收银模块目录
|
# 1. 进入收银模块目录
|
||||||
cd ~/rhkj/spring-ai/app/rui-cashier
|
cd ~/rhkj/rui-framework/app/rui-cashier
|
||||||
|
|
||||||
# 2. 打开 OpenCode
|
# 2. 打开 OpenCode
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ cd ~/rhkj/spring-ai/app/rui-cashier
|
|||||||
|
|
||||||
约束条件:
|
约束条件:
|
||||||
- 禁止修改前端代码
|
- 禁止修改前端代码
|
||||||
- 禁止修改框架代码(在 spring-ai 仓库)
|
- 禁止修改框架代码(在 rui-framework 仓库)
|
||||||
- 禁止直接引用支付模块代码
|
- 禁止直接引用支付模块代码
|
||||||
- 通过 FeignClient 调用框架服务
|
- 通过 FeignClient 调用框架服务
|
||||||
- 通过 REST API 暴露接口供前端调用
|
- 通过 REST API 暴露接口供前端调用
|
||||||
@@ -148,12 +148,12 @@ cd ~/rhkj/spring-ai/app/rui-cashier
|
|||||||
|
|
||||||
### 支付模块 AI
|
### 支付模块 AI
|
||||||
|
|
||||||
**工作目录:** `~/rhkj/spring-ai/app/rui-payment`
|
**工作目录:** `~/rhkj/rui-framework/app/rui-payment`
|
||||||
|
|
||||||
**启动步骤:**
|
**启动步骤:**
|
||||||
```bash
|
```bash
|
||||||
# 1. 进入支付模块目录
|
# 1. 进入支付模块目录
|
||||||
cd ~/rhkj/spring-ai/app/rui-payment
|
cd ~/rhkj/rui-framework/app/rui-payment
|
||||||
|
|
||||||
# 2. 打开 OpenCode
|
# 2. 打开 OpenCode
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ cd ~/rhkj/spring-ai/app/rui-payment
|
|||||||
|
|
||||||
约束条件:
|
约束条件:
|
||||||
- 禁止修改前端代码
|
- 禁止修改前端代码
|
||||||
- 禁止修改框架代码(在 spring-ai 仓库)
|
- 禁止修改框架代码(在 rui-framework 仓库)
|
||||||
- 禁止直接引用收银模块代码
|
- 禁止直接引用收银模块代码
|
||||||
- 通过 FeignClient 调用框架服务
|
- 通过 FeignClient 调用框架服务
|
||||||
- 通过 REST API 暴露接口供收银模块调用
|
- 通过 REST API 暴露接口供收银模块调用
|
||||||
@@ -204,7 +204,7 @@ git commit -m "feat: 功能描述
|
|||||||
- 详细修改点2"
|
- 详细修改点2"
|
||||||
|
|
||||||
# 推送到 Gitea
|
# 推送到 Gitea
|
||||||
git push gitea main
|
git push origin main
|
||||||
|
|
||||||
# 查看推送结果(钉钉会收到通知)
|
# 查看推送结果(钉钉会收到通知)
|
||||||
```
|
```
|
||||||
@@ -213,7 +213,7 @@ git push gitea main
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 查看 Actions 运行状态
|
# 查看 Actions 运行状态
|
||||||
# 访问:https://git.dev.vifo.cc/rui/{仓库名}/actions
|
# 访问:https://git.vifo.cc/rui/{仓库名}/actions
|
||||||
```
|
```
|
||||||
|
|
||||||
### 模块间通信示例
|
### 模块间通信示例
|
||||||
@@ -271,9 +271,9 @@ const cashierApi = {
|
|||||||
| 文件 | 位置 | 说明 |
|
| 文件 | 位置 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| AI 边界配置 | `AGENTS.md` | 每个仓库根目录 |
|
| AI 边界配置 | `AGENTS.md` | 每个仓库根目录 |
|
||||||
| 通信规范 | `spring-ai/docs/module-communication.md` | 模块间通信规范 |
|
| 通信规范 | `rui-framework/docs/module-communication.md` | 模块间通信规范 |
|
||||||
| CI 配置 | `.gitea/workflows/*.yml` | 自动化构建 |
|
| CI 配置 | `.gitea/workflows/*.yml` | 自动化构建 |
|
||||||
| 后端 POM | `spring-ai/backend/pom.xml` | Maven 根配置 |
|
| 后端 POM | `rui-framework/backend/pom.xml` | Maven 根配置 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -294,22 +294,22 @@ const cashierApi = {
|
|||||||
git remote -v
|
git remote -v
|
||||||
|
|
||||||
# 确认是 Gitea 地址
|
# 确认是 Gitea 地址
|
||||||
gitea ssh://git@git.dev.vifo.cc:222/rui/xxx.git
|
gitea ssh://git@git.vifo.cc:222/rui/xxx.git
|
||||||
|
|
||||||
# 如果失败,检查 SSH 密钥
|
# 如果失败,检查 SSH 密钥
|
||||||
ssh -p 222 git@git.dev.vifo.cc
|
ssh -p 222 git@git.vifo.cc
|
||||||
```
|
```
|
||||||
|
|
||||||
### CI 构建失败
|
### CI 构建失败
|
||||||
```bash
|
```bash
|
||||||
# 查看构建日志
|
# 查看构建日志
|
||||||
# 访问:https://git.dev.vifo.cc/rui/{仓库}/actions
|
# 访问:https://git.vifo.cc/rui/{仓库}/actions
|
||||||
```
|
```
|
||||||
|
|
||||||
### 钉钉没收到通知
|
### 钉钉没收到通知
|
||||||
```bash
|
```bash
|
||||||
# 检查 Webhook 配置
|
# 检查 Webhook 配置
|
||||||
# 访问:https://git.dev.vifo.cc/rui/{仓库}/settings/hooks
|
# 访问:https://git.vifo.cc/rui/{仓库}/settings/hooks
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ npx gitnexus list
|
|||||||
```
|
```
|
||||||
Indexed Repositories (2)
|
Indexed Repositories (2)
|
||||||
|
|
||||||
spring-ai
|
rui-framework
|
||||||
Path: ~/work/rui-framework
|
Path: ~/work/rui-framework
|
||||||
Stats: 7504 symbols, 15350 edges
|
Stats: 7504 symbols, 15350 edges
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ AI:基于 rui-payment 索引分析...
|
|||||||
```
|
```
|
||||||
gitnexus_context({
|
gitnexus_context({
|
||||||
name: "AuthUtil",
|
name: "AuthUtil",
|
||||||
repo: "spring-ai"
|
repo: "rui-framework"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ gitnexus_context({
|
|||||||
```
|
```
|
||||||
gitnexus_query({
|
gitnexus_query({
|
||||||
query: "分布式锁 Redisson",
|
query: "分布式锁 Redisson",
|
||||||
repo: "spring-ai"
|
repo: "rui-framework"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ gitnexus_query({
|
|||||||
```
|
```
|
||||||
gitnexus_impact({
|
gitnexus_impact({
|
||||||
target: "BaseController",
|
target: "BaseController",
|
||||||
repo: "spring-ai",
|
repo: "rui-framework",
|
||||||
direction: "upstream"
|
direction: "upstream"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
@@ -245,7 +245,7 @@ gitnexus_impact({
|
|||||||
```
|
```
|
||||||
gitnexus_query({
|
gitnexus_query({
|
||||||
query: "用户登录认证流程",
|
query: "用户登录认证流程",
|
||||||
repo: "spring-ai"
|
repo: "rui-framework"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -253,9 +253,9 @@ gitnexus_query({
|
|||||||
|
|
||||||
| 我想查... | 命令 | 仓库 |
|
| 我想查... | 命令 | 仓库 |
|
||||||
|-----------|------|------|
|
|-----------|------|------|
|
||||||
| `AuthUtil.getUserId()` 怎么用 | `gitnexus_context({name:"AuthUtil", repo:"spring-ai"})` | framework |
|
| `AuthUtil.getUserId()` 怎么用 | `gitnexus_context({name:"AuthUtil", repo:"rui-framework"})` | framework |
|
||||||
| 业务异常怎么抛 | `gitnexus_query({query:"BizException", repo:"spring-ai"})` | framework |
|
| 业务异常怎么抛 | `gitnexus_query({query:"BizException", repo:"rui-framework"})` | framework |
|
||||||
| 分布式锁怎么加 | `gitnexus_query({query:"Redisson分布式锁", repo:"spring-ai"})` | framework |
|
| 分布式锁怎么加 | `gitnexus_query({query:"Redisson分布式锁", repo:"rui-framework"})` | framework |
|
||||||
| 支付订单状态流转 | `gitnexus_query({query:"订单状态", repo:"rui-payment"})` | payment |
|
| 支付订单状态流转 | `gitnexus_query({query:"订单状态", repo:"rui-payment"})` | payment |
|
||||||
| 修改订单会影响哪里 | `gitnexus_impact({target:"OrderService", direction:"upstream"})` | payment |
|
| 修改订单会影响哪里 | `gitnexus_impact({target:"OrderService", direction:"upstream"})` | payment |
|
||||||
| 收银台缓存策略 | `gitnexus_query({query:"缓存 CacheKeys", repo:"rui-cashier"})` | cashier |
|
| 收银台缓存策略 | `gitnexus_query({query:"缓存 CacheKeys", repo:"rui-cashier"})` | cashier |
|
||||||
@@ -274,11 +274,11 @@ gitnexus_query({
|
|||||||
AI:建议调用 AuthUtil.getUserId()...
|
AI:建议调用 AuthUtil.getUserId()...
|
||||||
|
|
||||||
4. 员工:AuthUtil 有哪些方法?
|
4. 员工:AuthUtil 有哪些方法?
|
||||||
【AI执行】gitnexus_context({name:"AuthUtil", repo:"spring-ai"})
|
【AI执行】gitnexus_context({name:"AuthUtil", repo:"rui-framework"})
|
||||||
AI:AuthUtil 提供 getUserId()、getTenantId()、getUser()...
|
AI:AuthUtil 提供 getUserId()、getTenantId()、getUser()...
|
||||||
|
|
||||||
5. 员工:退款金额用 BigDecimal 吗?
|
5. 员工:退款金额用 BigDecimal 吗?
|
||||||
【AI执行】gitnexus_query({query:"金额计算 BigDecimal", repo:"spring-ai"})
|
【AI执行】gitnexus_query({query:"金额计算 BigDecimal", repo:"rui-framework"})
|
||||||
AI:框架规范要求金额使用 DECIMAL(19,4),Java 对应 BigDecimal...
|
AI:框架规范要求金额使用 DECIMAL(19,4),Java 对应 BigDecimal...
|
||||||
|
|
||||||
6. AI 生成完整代码
|
6. AI 生成完整代码
|
||||||
@@ -305,7 +305,7 @@ npx gitnexus analyze
|
|||||||
# 查看所有索引
|
# 查看所有索引
|
||||||
npx gitnexus list
|
npx gitnexus list
|
||||||
|
|
||||||
# 确认 spring-ai 存在
|
# 确认 rui-framework 存在
|
||||||
# 如果不存在,重新索引框架仓库
|
# 如果不存在,重新索引框架仓库
|
||||||
cd ~/work/rui-framework
|
cd ~/work/rui-framework
|
||||||
npx gitnexus analyze
|
npx gitnexus analyze
|
||||||
@@ -353,7 +353,7 @@ npx gitnexus analyze
|
|||||||
|
|
||||||
| 仓库路径 | 索引名称 | 说明 |
|
| 仓库路径 | 索引名称 | 说明 |
|
||||||
|----------|----------|------|
|
|----------|----------|------|
|
||||||
| `~/work/rui-framework` | `spring-ai` | 基于 pom.xml artifactId |
|
| `~/work/rui-framework` | `rui-framework` | 基于 pom.xml artifactId |
|
||||||
| `~/work/rui-payment` | `rui-payment` | 基于目录名 |
|
| `~/work/rui-payment` | `rui-payment` | 基于目录名 |
|
||||||
| `~/work/rui-cashier` | `rui-cashier` | 基于目录名 |
|
| `~/work/rui-cashier` | `rui-cashier` | 基于目录名 |
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 进入后端目录
|
# 进入后端目录
|
||||||
cd ~/rhkj/spring-ai/backend
|
cd ~/rhkj/rui-framework/backend
|
||||||
|
|
||||||
# Maven 打包
|
# Maven 打包
|
||||||
mvn clean package -DskipTests
|
mvn clean package -DskipTests
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ git --version
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <repository-url>
|
git clone <repository-url>
|
||||||
cd spring-ai
|
cd rui-framework
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.2 配置本地开发环境
|
### 2.2 配置本地开发环境
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# GitNexus — Code Intelligence 使用指南
|
# GitNexus — Code Intelligence 使用指南
|
||||||
|
|
||||||
> **项目索引**: spring-ai (2690 symbols, 5387 relationships, 218 execution flows)
|
> **项目索引**: rui-framework (2690 symbols, 5387 relationships, 218 execution flows)
|
||||||
|
|
||||||
## 基本概念
|
## 基本概念
|
||||||
|
|
||||||
@@ -27,10 +27,10 @@ GitNexus 是一个代码智能工具,通过索引代码库构建知识图谱
|
|||||||
|
|
||||||
| Resource | Use for |
|
| Resource | Use for |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| `gitnexus://repo/spring-ai/context` | Codebase overview, check index freshness |
|
| `gitnexus://repo/rui-framework/context` | Codebase overview, check index freshness |
|
||||||
| `gitnexus://repo/spring-ai/clusters` | All functional areas |
|
| `gitnexus://repo/rui-framework/clusters` | All functional areas |
|
||||||
| `gitnexus://repo/spring-ai/processes` | All execution flows |
|
| `gitnexus://repo/rui-framework/processes` | All execution flows |
|
||||||
| `gitnexus://repo/spring-ai/process/{name}` | Step-by-step execution trace |
|
| `gitnexus://repo/rui-framework/process/{name}` | Step-by-step execution trace |
|
||||||
|
|
||||||
## 技能参考
|
## 技能参考
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ rui 项目采用**多仓库**架构:
|
|||||||
|
|
||||||
```
|
```
|
||||||
~/rhkj/
|
~/rhkj/
|
||||||
├── spring-ai/ # 后端仓库(Java/Spring)
|
├── rui-framework/ # 后端仓库(Java/Spring)
|
||||||
│ ├── backend/ # 基础框架
|
│ ├── backend/ # 基础框架
|
||||||
│ ├── app/ # 应用模块
|
│ ├── app/ # 应用模块
|
||||||
│ └── docs/ # 文档
|
│ └── docs/ # 文档
|
||||||
@@ -29,11 +29,11 @@ rui 项目采用**多仓库**架构:
|
|||||||
|
|
||||||
## 二、启动 OpenCode 的正确姿势
|
## 二、启动 OpenCode 的正确姿势
|
||||||
|
|
||||||
### 2.1 后端开发(spring-ai)
|
### 2.1 后端开发(rui-framework)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. 进入后端目录
|
# 1. 进入后端目录
|
||||||
cd /Users/zhangsheng/rhkj/spring-ai
|
cd /Users/zhangsheng/rhkj/rui-framework
|
||||||
|
|
||||||
# 2. 启动 OpenCode(命令行方式)
|
# 2. 启动 OpenCode(命令行方式)
|
||||||
opencode
|
opencode
|
||||||
@@ -46,7 +46,7 @@ opencode
|
|||||||
```
|
```
|
||||||
你现在进入【后端开发模式】。
|
你现在进入【后端开发模式】。
|
||||||
|
|
||||||
工作目录:/Users/zhangsheng/rhkj/spring-ai
|
工作目录:/Users/zhangsheng/rhkj/rui-framework
|
||||||
负责范围:backend/ 和 app/ 目录下的 Java 代码
|
负责范围:backend/ 和 app/ 目录下的 Java 代码
|
||||||
技术栈:Spring Boot 4.x、Spring Cloud、MyBatis Plus、JDK 21
|
技术栈:Spring Boot 4.x、Spring Cloud、MyBatis Plus、JDK 21
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ opencode
|
|||||||
|
|
||||||
规则:
|
规则:
|
||||||
1. 只能修改前端项目下的代码
|
1. 只能修改前端项目下的代码
|
||||||
2. 需要后端接口时,在 spring-ai 仓库创建 Gitee Issue
|
2. 需要后端接口时,在 rui-framework 仓库创建 Gitee Issue
|
||||||
3. 编码规范参考 AGENTS.md
|
3. 编码规范参考 AGENTS.md
|
||||||
4. 使用 pnpm workspace 管理多项目
|
4. 使用 pnpm workspace 管理多项目
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ opencode
|
|||||||
```
|
```
|
||||||
你现在进入【框架开发模式】。
|
你现在进入【框架开发模式】。
|
||||||
|
|
||||||
工作目录:/Users/zhangsheng/rhkj/spring-ai
|
工作目录:/Users/zhangsheng/rhkj/rui-framework
|
||||||
负责范围:仅 backend/ 目录
|
负责范围:仅 backend/ 目录
|
||||||
角色:基础框架维护者
|
角色:基础框架维护者
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ AI:好的,开始开发前端页面...
|
|||||||
|
|
||||||
OpenCode 应该回答:
|
OpenCode 应该回答:
|
||||||
```
|
```
|
||||||
请在 spring-ai 仓库创建 Issue,使用模板:api_request.md
|
请在 rui-framework 仓库创建 Issue,使用模板:api_request.md
|
||||||
|
|
||||||
Issue 内容:
|
Issue 内容:
|
||||||
标题:[API-REQ] 用户模块需要批量导入接口
|
标题:[API-REQ] 用户模块需要批量导入接口
|
||||||
@@ -229,11 +229,11 @@ OpenCode 应该:
|
|||||||
|
|
||||||
**答**:
|
**答**:
|
||||||
1. **方法 A(推荐)**:先在一个仓库完成,提交后切换到另一个仓库
|
1. **方法 A(推荐)**:先在一个仓库完成,提交后切换到另一个仓库
|
||||||
- 在 spring-ai 开发接口 → 提交 PR
|
- 在 rui-framework 开发接口 → 提交 PR
|
||||||
- 在 rui-frontend 开发页面 → 提交 PR
|
- 在 rui-frontend 开发页面 → 提交 PR
|
||||||
|
|
||||||
2. **方法 B(并行)**:两个 OpenCode 窗口同时工作
|
2. **方法 B(并行)**:两个 OpenCode 窗口同时工作
|
||||||
- 窗口 1:spring-ai 目录,开发后端
|
- 窗口 1:rui-framework 目录,开发后端
|
||||||
- 窗口 2:rui-frontend 目录,开发前端
|
- 窗口 2:rui-frontend 目录,开发前端
|
||||||
|
|
||||||
3. **不要**:在一个会话中同时修改两个仓库
|
3. **不要**:在一个会话中同时修改两个仓库
|
||||||
@@ -293,7 +293,7 @@ OpenCode 应该:
|
|||||||
**后端启动模板**:
|
**后端启动模板**:
|
||||||
```markdown
|
```markdown
|
||||||
你现在进入【后端开发模式】。
|
你现在进入【后端开发模式】。
|
||||||
工作目录:/Users/zhangsheng/rhkj/spring-ai
|
工作目录:/Users/zhangsheng/rhkj/rui-framework
|
||||||
技术栈:Spring Boot 4.x、JDK 21、MyBatis Plus
|
技术栈:Spring Boot 4.x、JDK 21、MyBatis Plus
|
||||||
规则:只能修改 backend/ 和 app/ 目录
|
规则:只能修改 backend/ 和 app/ 目录
|
||||||
当前任务:【填写】
|
当前任务:【填写】
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ GITEA_URL="https://git.vifo.cc"
|
|||||||
GITEA_TOKEN="your-token"
|
GITEA_TOKEN="your-token"
|
||||||
GITEA_ORG="rui"
|
GITEA_ORG="rui"
|
||||||
|
|
||||||
REPOS=("spring-ai" "rui-frontend" "rui-payment")
|
REPOS=("rui-framework" "rui-frontend" "rui-payment")
|
||||||
|
|
||||||
for repo in "${REPOS[@]}"; do
|
for repo in "${REPOS[@]}"; do
|
||||||
echo "迁移: $repo"
|
echo "迁移: $repo"
|
||||||
@@ -334,7 +334,7 @@ jobs:
|
|||||||
### 5.4 创建后端 CI/CD 工作流
|
### 5.4 创建后端 CI/CD 工作流
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# spring-ai/.gitea/workflows/build.yml
|
# rui-framework/.gitea/workflows/build.yml
|
||||||
name: Build and Test
|
name: Build and Test
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ git push -u origin master
|
|||||||
### 与框架主仓库的关系
|
### 与框架主仓库的关系
|
||||||
|
|
||||||
```
|
```
|
||||||
spring-ai/ # 框架主仓库(git)
|
rui-framework/ # 框架主仓库(git)
|
||||||
├── backend/ # 提交到框架仓库
|
├── backend/ # 提交到框架仓库
|
||||||
├── docs/ # 提交到框架仓库
|
├── docs/ # 提交到框架仓库
|
||||||
├── app/ # 不提交到框架仓库(.gitignore)
|
├── app/ # 不提交到框架仓库(.gitignore)
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
## 🔗 通信方式
|
## 🔗 通信方式
|
||||||
|
|
||||||
### 1. 模块 → 框架(spring-ai)
|
### 1. 模块 → 框架(rui-framework)
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 使用 FeignClient 调用框架服务
|
// 使用 FeignClient 调用框架服务
|
||||||
|
|||||||
+10
-10
@@ -11,7 +11,7 @@
|
|||||||
### 1.1 问题背景
|
### 1.1 问题背景
|
||||||
|
|
||||||
rui 项目采用多仓结构:
|
rui 项目采用多仓结构:
|
||||||
- **后端仓库**:`spring-ai`(backend + app/*)
|
- **后端仓库**:`rui-framework`(backend + app/*)
|
||||||
- **前端仓库**:`rui-frontend`(admin-ui + cashier-mobile + customer-mobile)
|
- **前端仓库**:`rui-frontend`(admin-ui + cashier-mobile + customer-mobile)
|
||||||
|
|
||||||
在使用 OpenCode AI 辅助开发时存在以下痛点:
|
在使用 OpenCode AI 辅助开发时存在以下痛点:
|
||||||
@@ -35,8 +35,8 @@ rui 项目采用多仓结构:
|
|||||||
### 2.1 仓库结构
|
### 2.1 仓库结构
|
||||||
|
|
||||||
```
|
```
|
||||||
# 后端仓库:spring-ai
|
# 后端仓库:rui-framework
|
||||||
spring-ai/
|
rui-framework/
|
||||||
├── backend/ # 基础框架
|
├── backend/ # 基础框架
|
||||||
├── app/ # 应用模块(支付、收银等)
|
├── app/ # 应用模块(支付、收银等)
|
||||||
├── docs/ # 后端文档
|
├── docs/ # 后端文档
|
||||||
@@ -54,8 +54,8 @@ rui-frontend/
|
|||||||
|
|
||||||
| 角色 | 所属仓库 | 负责目录 | 可修改范围 | 只读范围 | 会话配置 |
|
| 角色 | 所属仓库 | 负责目录 | 可修改范围 | 只读范围 | 会话配置 |
|
||||||
|------|---------|---------|-----------|---------|---------|
|
|------|---------|---------|-----------|---------|---------|
|
||||||
| **框架开发** | spring-ai | `backend/` | `backend/**` | `app/**` | `framework.json` |
|
| **框架开发** | rui-framework | `backend/` | `backend/**` | `app/**` | `framework.json` |
|
||||||
| **应用开发** | spring-ai | `app/{模块}/` | `app/{模块}/**` | `backend/**` | `app-module.json` |
|
| **应用开发** | rui-framework | `app/{模块}/` | `app/{模块}/**` | `backend/**` | `app-module.json` |
|
||||||
| **前端开发** | rui-frontend | `admin-ui/` | `admin-ui/**` | `cashier-mobile/`, `customer-mobile/` | `admin-ui.json` |
|
| **前端开发** | rui-frontend | `admin-ui/` | `admin-ui/**` | `cashier-mobile/`, `customer-mobile/` | `admin-ui.json` |
|
||||||
|
|
||||||
### 2.2 职责矩阵
|
### 2.2 职责矩阵
|
||||||
@@ -80,13 +80,13 @@ rui-frontend/
|
|||||||
**协作流程**(跨仓库协作):
|
**协作流程**(跨仓库协作):
|
||||||
|
|
||||||
```
|
```
|
||||||
rui-frontend/ spring-ai/
|
rui-frontend/ rui-framework/
|
||||||
┌─────────────┐ ┌─────────────┐
|
┌─────────────┐ ┌─────────────┐
|
||||||
│ 前端会话 │ │ 后端 │
|
│ 前端会话 │ │ 后端 │
|
||||||
│ (admin-ui) │ │ 会话 │
|
│ (admin-ui) │ │ 会话 │
|
||||||
└──────┬──────┘ └──────┬──────┘
|
└──────┬──────┘ └──────┬──────┘
|
||||||
│ │
|
│ │
|
||||||
│ 在 spring-ai 仓库创建 │
|
│ 在 rui-framework 仓库创建 │
|
||||||
│ Issue [API-REQ] │
|
│ Issue [API-REQ] │
|
||||||
└────────────────────────→│
|
└────────────────────────→│
|
||||||
│ │
|
│ │
|
||||||
@@ -210,9 +210,9 @@ rui-frontend/ spring-ai/
|
|||||||
|
|
||||||
启动 OpenCode 时,明确指定仓库和角色:
|
启动 OpenCode 时,明确指定仓库和角色:
|
||||||
|
|
||||||
**后端仓库(spring-ai)**:
|
**后端仓库(rui-framework)**:
|
||||||
```
|
```
|
||||||
工作目录:/Users/zhangsheng/rhkj/spring-ai
|
工作目录:/Users/zhangsheng/rhkj/rui-framework
|
||||||
角色:框架开发
|
角色:框架开发
|
||||||
限制:只能修改 backend/ 下的代码
|
限制:只能修改 backend/ 下的代码
|
||||||
```
|
```
|
||||||
@@ -367,7 +367,7 @@ rui-frontend/ spring-ai/
|
|||||||
- 需要评估影响范围
|
- 需要评估影响范围
|
||||||
- 需要同步版本更新
|
- 需要同步版本更新
|
||||||
|
|
||||||
### Q2: 前端仓库(rui-frontend)和后端仓库(spring-ai)是什么关系?
|
### Q2: 前端仓库(rui-frontend)和后端仓库(rui-framework)是什么关系?
|
||||||
|
|
||||||
**答**:
|
**答**:
|
||||||
- **独立仓库**:前端和后端是完全独立的 Git 仓库
|
- **独立仓库**:前端和后端是完全独立的 Git 仓库
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
# 睿核科技 (rui) — 项目实施规范
|
# 睿核科技 (rui) — 项目实施规范
|
||||||
|
|
||||||
> 本文档基于对当前 spring-ai 项目的全面分析,整理项目结构、业务流、现有规范、推荐修改项及缺少的专业结构,供后续项目实施参考。
|
> 本文档基于对当前 rui-framework 项目的全面分析,整理项目结构、业务流、现有规范、推荐修改项及缺少的专业结构,供后续项目实施参考。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
| 项目属性 | 值 |
|
| 项目属性 | 值 |
|
||||||
|---------|-----|
|
|---------|-----|
|
||||||
| **项目名称** | spring-ai |
|
| **项目名称** | rui-framework |
|
||||||
| **项目类型** | Spring Cloud 微服务架构(通用平台框架) |
|
| **项目类型** | Spring Cloud 微服务架构(通用平台框架) |
|
||||||
| **组织方式** | Monorepo(backend + 可扩展前端) |
|
| **组织方式** | Monorepo(backend + 可扩展前端) |
|
||||||
| **JDK** | 21 |
|
| **JDK** | 21 |
|
||||||
@@ -436,5 +436,5 @@
|
|||||||
|
|
||||||
> **文档版本**: v1.0
|
> **文档版本**: v1.0
|
||||||
> **创建日期**: 2026-05-28
|
> **创建日期**: 2026-05-28
|
||||||
> **适用范围**: spring-ai 项目及后续同类项目
|
> **适用范围**: rui-framework 项目及后续同类项目
|
||||||
> **维护方式**: 随项目实施迭代更新
|
> **维护方式**: 随项目实施迭代更新
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
|
|
||||||
| 仓库 | 地址 | 说明 |
|
| 仓库 | 地址 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 前端 | `ssh://git@git.dev.vifo.cc:222/rui/rui-frontend.git` | admin-ui + 移动端 |
|
| 前端 | `ssh://git@git.vifo.cc:222/rui/rui-frontend.git` | admin-ui + 移动端 |
|
||||||
| 后端 | `ssh://git@git.dev.vifo.cc:222/rui/rui-cashier.git` | 收银系统独立后端服务 |
|
| 后端 | `ssh://git@git.vifo.cc:222/rui/rui-cashier.git` | 收银系统独立后端服务 |
|
||||||
| 文档 | `ssh://git@git.dev.vifo.cc:222/rui/rui-docs.git` | 共享文档中心 |
|
| 文档 | `ssh://git@git.vifo.cc:222/rui/rui-docs.git` | 共享文档中心 |
|
||||||
|
|
||||||
> ⚠️ **注意**:收银系统相关 Issue 应提交到 `rui/rui-cashier` 仓库,不是 `spring-ai`
|
> ⚠️ **注意**:收银系统相关 Issue 应提交到 `rui/rui-cashier` 仓库,不是 `rui-framework`
|
||||||
|
|
||||||
### 2.2 菜单数据结构
|
### 2.2 菜单数据结构
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,642 @@
|
|||||||
|
# 支付服务(Payment)设计文档
|
||||||
|
|
||||||
|
> **设计日期**: 2026-06-08
|
||||||
|
> **版本**: v1.0
|
||||||
|
> **状态**: 设计中
|
||||||
|
> **适用前端**: admin-ui(管理后台)、管理 APP(接口一致)
|
||||||
|
> **后端服务**: rui-payment-api(端口 9401,网关路径 `/payment/**`)
|
||||||
|
> **后端状态**: ⏳ 预留,API 细节待补充
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、背景与目标
|
||||||
|
|
||||||
|
### 1.1 现状
|
||||||
|
|
||||||
|
收银系统(rui-cashier)已完成基础订单流程(开台、结账、退款),支付环节目前使用占位接口。需要建立独立的支付服务(rui-payment-api),作为聚合支付网关,统一对接多种第三方支付通道。
|
||||||
|
|
||||||
|
### 1.2 目标
|
||||||
|
|
||||||
|
1. **聚合支付网关**:统一下单,按支付方式(微信、支付宝、银行卡等)自动路由到对应通道
|
||||||
|
2. **多通道可配置**:支持同时配置多个第三方支付平台,按门店/场景灵活启用
|
||||||
|
3. **商户进件**:商户在我们平台提交进件申请 → 平台审核 → 向第三方(微信、支付宝)提交进件 → 状态跟踪
|
||||||
|
4. **多端一致**:管理后台(Web)和管理 APP 共享同一套后端接口,前端按各自框架实现
|
||||||
|
|
||||||
|
### 1.3 不在范围内
|
||||||
|
|
||||||
|
- 团购券/优惠券核销
|
||||||
|
- 会员余额/储值卡支付
|
||||||
|
- 对账、清算(后续迭代)
|
||||||
|
- 顾客端支付流程(由 cashier-customer 负责,调用本服务下单接口)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、整体架构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────────┐
|
||||||
|
│ 前端层 │
|
||||||
|
├─────────────────────┬─────────────────────────────────┤
|
||||||
|
│ 管理后台 (admin-ui)│ 管理 APP (uni-app) │
|
||||||
|
│ Vue3 + Element │ Vue3 语法 │
|
||||||
|
├─────────────────────┴─────────────────────────────────┤
|
||||||
|
│ 共享同一套后端 API │
|
||||||
|
│ /payment/admin/** │
|
||||||
|
└────────────────────────┬──────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────────────────────────────────────────────┐
|
||||||
|
│ rui-gateway (:9300) │
|
||||||
|
│ 路由:/payment/** → rui-payment-api │
|
||||||
|
└────────────────────────┬───────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────────────────────────────────────────────┐
|
||||||
|
│ rui-payment-api (:9401) │
|
||||||
|
├────────────┬──────────────┬──────────────┬─────────────┤
|
||||||
|
│ 商户管理 │ 商户进件 │ 支付通道管理 │ 交易管理 │
|
||||||
|
│ Merchant │ Onboarding │ Channel │ Transaction│
|
||||||
|
├────────────┴──────────────┴──────────────┴─────────────┤
|
||||||
|
│ 统一下单引擎 │
|
||||||
|
│ 按 payType 路由到对应第三方支付通道 │
|
||||||
|
├────────────────────────────────────────────────────────┤
|
||||||
|
│ 微信支付通道 │ 支付宝通道 │ 银行卡通道(预留) │
|
||||||
|
└────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、菜单与权限
|
||||||
|
|
||||||
|
### 3.1 菜单结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "payment",
|
||||||
|
"menus": [
|
||||||
|
{
|
||||||
|
"code": "payment",
|
||||||
|
"name": "支付管理",
|
||||||
|
"type": 1,
|
||||||
|
"icon": "tabler:credit-card",
|
||||||
|
"sortNo": 110,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "payment-merchant",
|
||||||
|
"name": "商户管理",
|
||||||
|
"type": 2,
|
||||||
|
"icon": "tabler:building-bank",
|
||||||
|
"path": "/payment/merchant",
|
||||||
|
"permission": "payment:merchant:list",
|
||||||
|
"sortNo": 1,
|
||||||
|
"buttons": [
|
||||||
|
{ "code": "btn:add", "name": "新增", "permission": "payment:merchant:add" },
|
||||||
|
{ "code": "btn:edit", "name": "编辑", "permission": "payment:merchant:edit" },
|
||||||
|
{ "code": "btn:del", "name": "删除", "permission": "payment:merchant:delete" },
|
||||||
|
{ "code": "btn:detail", "name": "详情", "permission": "payment:merchant:detail" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "payment-onboarding",
|
||||||
|
"name": "商户进件",
|
||||||
|
"type": 2,
|
||||||
|
"icon": "tabler:clipboard-check",
|
||||||
|
"path": "/payment/onboarding",
|
||||||
|
"permission": "payment:onboarding:list",
|
||||||
|
"sortNo": 2,
|
||||||
|
"buttons": [
|
||||||
|
{ "code": "btn:apply", "name": "提交进件", "permission": "payment:onboarding:apply" },
|
||||||
|
{ "code": "btn:audit", "name": "审核", "permission": "payment:onboarding:audit" },
|
||||||
|
{ "code": "btn:submit", "name": "提交第三方", "permission": "payment:onboarding:submit" },
|
||||||
|
{ "code": "btn:detail", "name": "详情", "permission": "payment:onboarding:detail" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "payment-channel",
|
||||||
|
"name": "支付通道",
|
||||||
|
"type": 2,
|
||||||
|
"icon": "tabler:route",
|
||||||
|
"path": "/payment/channel",
|
||||||
|
"permission": "payment:channel:list",
|
||||||
|
"sortNo": 3,
|
||||||
|
"buttons": [
|
||||||
|
{ "code": "btn:add", "name": "新增", "permission": "payment:channel:add" },
|
||||||
|
{ "code": "btn:edit", "name": "编辑", "permission": "payment:channel:edit" },
|
||||||
|
{ "code": "btn:status", "name": "启停", "permission": "payment:channel:status" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "payment-transaction",
|
||||||
|
"name": "交易记录",
|
||||||
|
"type": 2,
|
||||||
|
"icon": "tabler:receipt",
|
||||||
|
"path": "/payment/transaction",
|
||||||
|
"permission": "payment:transaction:list",
|
||||||
|
"sortNo": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 权限标识汇总
|
||||||
|
|
||||||
|
| 模块 | 权限标识 | 说明 |
|
||||||
|
|------|----------|------|
|
||||||
|
| 商户 | `payment:merchant:list` | 查询商户列表 |
|
||||||
|
| 商户 | `payment:merchant:add` | 新增商户 |
|
||||||
|
| 商户 | `payment:merchant:edit` | 编辑商户 |
|
||||||
|
| 商户 | `payment:merchant:delete` | 删除商户 |
|
||||||
|
| 商户 | `payment:merchant:detail` | 查看商户详情 |
|
||||||
|
| 进件 | `payment:onboarding:list` | 查询进件列表 |
|
||||||
|
| 进件 | `payment:onboarding:apply` | 提交进件申请 |
|
||||||
|
| 进件 | `payment:onboarding:audit` | 审核进件 |
|
||||||
|
| 进件 | `payment:onboarding:submit` | 提交至第三方 |
|
||||||
|
| 进件 | `payment:onboarding:detail` | 查看进件详情 |
|
||||||
|
| 通道 | `payment:channel:list` | 查询支付通道 |
|
||||||
|
| 通道 | `payment:channel:add` | 新增通道配置 |
|
||||||
|
| 通道 | `payment:channel:edit` | 编辑通道配置 |
|
||||||
|
| 通道 | `payment:channel:status` | 启用/禁用通道 |
|
||||||
|
| 交易 | `payment:transaction:list` | 查询交易记录 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、商户管理
|
||||||
|
|
||||||
|
### 4.1 页面结构
|
||||||
|
|
||||||
|
**列表页** `/payment/merchant`
|
||||||
|
|
||||||
|
| 字段 | 类型 | 宽度 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| merchantNo | string | 150 | 商户编号(系统生成) |
|
||||||
|
| merchantName | string | 150 | 商户名称 |
|
||||||
|
| contactName | string | 120 | 联系人 |
|
||||||
|
| contactPhone | string | 130 | 联系电话 |
|
||||||
|
| channelCount | number | 100 | 已开通通道数 |
|
||||||
|
| status | enum | 100 | 状态 |
|
||||||
|
| createTime | datetime | 160 | 创建时间 |
|
||||||
|
|
||||||
|
**查询条件**:商户编号、商户名称、状态
|
||||||
|
|
||||||
|
**操作按钮**:新增、编辑、详情、删除
|
||||||
|
|
||||||
|
**详情页/弹窗**:展示商户基础信息 + 已开通通道列表 + 进件记录
|
||||||
|
|
||||||
|
### 4.2 字段定义
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface MerchantDTO {
|
||||||
|
id: number
|
||||||
|
/** 商户编号(系统生成,如 M202606080001) */
|
||||||
|
merchantNo: string
|
||||||
|
/** 商户名称 */
|
||||||
|
merchantName: string
|
||||||
|
/** 商户简称 */
|
||||||
|
merchantShortName: string
|
||||||
|
/** 联系人 */
|
||||||
|
contactName: string
|
||||||
|
/** 联系电话 */
|
||||||
|
contactPhone: string
|
||||||
|
/** 联系邮箱 */
|
||||||
|
contactEmail?: string
|
||||||
|
/** 商户地址 */
|
||||||
|
address?: string
|
||||||
|
/** 备注 */
|
||||||
|
remark?: string
|
||||||
|
/** 状态:0-禁用 1-启用 */
|
||||||
|
status: number
|
||||||
|
/** 已开通通道数(只读) */
|
||||||
|
channelCount?: number
|
||||||
|
createTime: string
|
||||||
|
updateTime: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 状态枚举
|
||||||
|
|
||||||
|
| 值 | 名称 | 说明 |
|
||||||
|
|----|------|------|
|
||||||
|
| 0 | 禁用 | 商户被禁用,无法交易 |
|
||||||
|
| 1 | 启用 | 正常状态 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、商户进件
|
||||||
|
|
||||||
|
### 5.1 业务流程
|
||||||
|
|
||||||
|
```
|
||||||
|
商户提交进件申请
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
平台初审(内部审核)
|
||||||
|
│
|
||||||
|
┌───┴───┐
|
||||||
|
│ │
|
||||||
|
驳回 通过
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
退回 提交第三方
|
||||||
|
修改 │
|
||||||
|
┌───┴───┐
|
||||||
|
│ │
|
||||||
|
进件中 进件失败
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
进件成功 查看原因 → 修改后重新提交
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 页面结构
|
||||||
|
|
||||||
|
**列表页** `/payment/onboarding`
|
||||||
|
|
||||||
|
| 字段 | 类型 | 宽度 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| merchantName | string | 150 | 商户名称 |
|
||||||
|
| channelName | string | 120 | 目标通道 |
|
||||||
|
| submitterName | string | 120 | 提交人 |
|
||||||
|
| status | enum | 120 | 进件状态 |
|
||||||
|
| auditStatus | enum | 120 | 内部审核状态 |
|
||||||
|
| thirdPartyStatus | enum | 120 | 第三方状态 |
|
||||||
|
| submitTime | datetime | 160 | 提交时间 |
|
||||||
|
| updateTime | datetime | 160 | 更新时间 |
|
||||||
|
|
||||||
|
**查询条件**:商户名称、目标通道、进件状态、提交时间范围
|
||||||
|
|
||||||
|
**操作按钮**:提交进件、审核、提交第三方、查看详情
|
||||||
|
|
||||||
|
**进件申请弹窗/页面**:
|
||||||
|
|
||||||
|
分步表单,包含以下信息区域:
|
||||||
|
|
||||||
|
#### 5.2.1 基础信息
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| merchantId | select | ✅ | 关联商户(下拉选择) |
|
||||||
|
| channelType | select | ✅ | 目标通道(微信/支付宝/银行卡) |
|
||||||
|
| merchantType | select | ✅ | 商户类型(企业/个体工商户/小微商户) |
|
||||||
|
| merchantName | input | ✅ | 商户名称(营业执照上的名称) |
|
||||||
|
| merchantShortName | input | ✅ | 商户简称(对外展示) |
|
||||||
|
| licenseNo | input | ✅ | 营业执照号 |
|
||||||
|
| licenseExpireDate | date | ✅ | 营业执照有效期 |
|
||||||
|
| licensePhoto | upload | ✅ | 营业执照照片 |
|
||||||
|
|
||||||
|
#### 5.2.2 法人信息
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| legalPersonName | input | ✅ | 法人姓名 |
|
||||||
|
| legalPersonIdNo | input | ✅ | 法人身份证号 |
|
||||||
|
| legalPersonIdFront | upload | ✅ | 身份证正面 |
|
||||||
|
| legalPersonIdBack | upload | ✅ | 身份证反面 |
|
||||||
|
| legalPersonIdExpire | date | ✅ | 身份证有效期 |
|
||||||
|
|
||||||
|
#### 5.2.3 结算信息
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| settleType | select | ✅ | 结算方式(对公/对私) |
|
||||||
|
| bankName | input | ✅ | 开户银行 |
|
||||||
|
| bankBranch | input | ✅ | 开户支行 |
|
||||||
|
| bankAccountNo | input | ✅ | 银行账号 |
|
||||||
|
| bankAccountName | input | ✅ | 户名 |
|
||||||
|
| bankLicensePhoto | upload | 条件 | 开户许可证(对公必填) |
|
||||||
|
|
||||||
|
#### 5.2.4 其他材料
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| storePhotos | upload | ✅ | 门店照片(支持多张) |
|
||||||
|
| extraMaterials | upload | ❌ | 补充材料(支持多张) |
|
||||||
|
| remark | textarea | ❌ | 备注 |
|
||||||
|
|
||||||
|
### 5.3 字段定义
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface MerchantOnboardingDTO {
|
||||||
|
id: number
|
||||||
|
/** 关联商户 ID */
|
||||||
|
merchantId: number
|
||||||
|
/** 目标通道类型 */
|
||||||
|
channelType: ChannelType
|
||||||
|
/** 商户类型:1-企业 2-个体工商户 3-小微商户 */
|
||||||
|
merchantType: number
|
||||||
|
/** 商户名称(营业执照) */
|
||||||
|
merchantName: string
|
||||||
|
/** 商户简称 */
|
||||||
|
merchantShortName: string
|
||||||
|
/** 营业执照号 */
|
||||||
|
licenseNo: string
|
||||||
|
/** 营业执照有效期 */
|
||||||
|
licenseExpireDate: string
|
||||||
|
/** 营业执照照片(文件 ID) */
|
||||||
|
licensePhoto: number
|
||||||
|
/** 法人姓名 */
|
||||||
|
legalPersonName: string
|
||||||
|
/** 法人身份证号 */
|
||||||
|
legalPersonIdNo: string
|
||||||
|
/** 身份证正面(文件 ID) */
|
||||||
|
legalPersonIdFront: number
|
||||||
|
/** 身份证反面(文件 ID) */
|
||||||
|
legalPersonIdBack: number
|
||||||
|
/** 身份证有效期 */
|
||||||
|
legalPersonIdExpire: string
|
||||||
|
/** 结算方式:1-对公 2-对私 */
|
||||||
|
settleType: number
|
||||||
|
/** 开户银行 */
|
||||||
|
bankName: string
|
||||||
|
/** 开户支行 */
|
||||||
|
bankBranch: string
|
||||||
|
/** 银行账号 */
|
||||||
|
bankAccountNo: string
|
||||||
|
/** 户名 */
|
||||||
|
bankAccountName: string
|
||||||
|
/** 开户许可证(文件 ID,对公必填) */
|
||||||
|
bankLicensePhoto?: number
|
||||||
|
/** 门店照片(文件 ID 数组) */
|
||||||
|
storePhotos: number[]
|
||||||
|
/** 补充材料(文件 ID 数组) */
|
||||||
|
extraMaterials?: number[]
|
||||||
|
/** 内部审核状态 */
|
||||||
|
auditStatus: AuditStatus
|
||||||
|
/** 第三方进件状态 */
|
||||||
|
thirdPartyStatus: ThirdPartyStatus
|
||||||
|
/** 第三方返回的商户号 */
|
||||||
|
thirdPartyMerchantNo?: string
|
||||||
|
/** 第三方返回原因(失败时) */
|
||||||
|
thirdPartyRejectReason?: string
|
||||||
|
/** 审核人 */
|
||||||
|
auditorName?: string
|
||||||
|
/** 审核时间 */
|
||||||
|
auditTime?: string
|
||||||
|
/** 审核意见 */
|
||||||
|
auditRemark?: string
|
||||||
|
/** 提交人 */
|
||||||
|
submitterName?: string
|
||||||
|
/** 提交时间 */
|
||||||
|
submitTime?: string
|
||||||
|
remark?: string
|
||||||
|
createTime: string
|
||||||
|
updateTime: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4 状态枚举
|
||||||
|
|
||||||
|
**内部审核状态** `AuditStatus`
|
||||||
|
|
||||||
|
| 值 | 名称 | 说明 |
|
||||||
|
|----|------|------|
|
||||||
|
| 0 | 待提交 | 草稿,尚未提交审核 |
|
||||||
|
| 1 | 待审核 | 已提交,等待平台审核 |
|
||||||
|
| 2 | 审核通过 | 平台审核通过 |
|
||||||
|
| 3 | 审核驳回 | 平台审核驳回,可修改后重新提交 |
|
||||||
|
|
||||||
|
**第三方进件状态** `ThirdPartyStatus`
|
||||||
|
|
||||||
|
| 值 | 名称 | 说明 |
|
||||||
|
|----|------|------|
|
||||||
|
| 0 | 未提交 | 尚未提交至第三方 |
|
||||||
|
| 1 | 审核中 | 第三方审核中 |
|
||||||
|
| 2 | 进件成功 | 第三方审核通过,获得商户号 |
|
||||||
|
| 3 | 进件失败 | 第三方审核驳回 |
|
||||||
|
| 4 | 已冻结 | 第三方冻结商户 |
|
||||||
|
|
||||||
|
### 5.5 交互规则
|
||||||
|
|
||||||
|
1. **提交进件**:填写信息 → 提交内部审核(状态 → 待审核)
|
||||||
|
2. **内部审核**:审核通过 → 状态变为审核通过;驳回 → 填写原因,状态变为审核驳回
|
||||||
|
3. **提交第三方**:审核通过后,可提交至第三方(状态 → 审核中)
|
||||||
|
4. **状态同步**:第三方回调更新状态(成功/失败)
|
||||||
|
5. **重新提交**:审核驳回或第三方失败时,可修改后重新走流程
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、支付通道管理
|
||||||
|
|
||||||
|
### 6.1 页面结构
|
||||||
|
|
||||||
|
**列表页** `/payment/channel`
|
||||||
|
|
||||||
|
| 字段 | 类型 | 宽度 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| channelName | string | 150 | 通道名称 |
|
||||||
|
| channelType | enum | 120 | 通道类型 |
|
||||||
|
| channelProvider | string | 150 | 通道提供方 |
|
||||||
|
| merchantCount | number | 100 | 关联商户数 |
|
||||||
|
| status | enum | 100 | 状态 |
|
||||||
|
| createTime | datetime | 160 | 创建时间 |
|
||||||
|
|
||||||
|
**查询条件**:通道名称、通道类型、状态
|
||||||
|
|
||||||
|
**操作按钮**:新增通道、编辑、启用/禁用
|
||||||
|
|
||||||
|
**通道配置弹窗**:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| channelName | input | ✅ | 通道名称(如"微信支付-主通道") |
|
||||||
|
| channelType | select | ✅ | 通道类型(见枚举) |
|
||||||
|
| channelProvider | select | ✅ | 通道提供方(微信/支付宝/银联等) |
|
||||||
|
| appId | input | ✅ | 应用 ID(AppId/MchId) |
|
||||||
|
| merchantId | input | ✅ | 商户号 |
|
||||||
|
| apiVersion | input | ❌ | API 版本 |
|
||||||
|
| certFile | upload | 条件 | 证书文件(部分通道需要) |
|
||||||
|
| notifyUrl | input | ✅ | 回调通知地址 |
|
||||||
|
| remark | textarea | ❌ | 备注 |
|
||||||
|
| status | radio | ✅ | 状态(启用/禁用) |
|
||||||
|
|
||||||
|
### 6.2 字段定义
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PayChannelDTO {
|
||||||
|
id: number
|
||||||
|
/** 通道名称 */
|
||||||
|
channelName: string
|
||||||
|
/** 通道类型 */
|
||||||
|
channelType: ChannelType
|
||||||
|
/** 通道提供方 */
|
||||||
|
channelProvider: string
|
||||||
|
/** 应用 ID */
|
||||||
|
appId: string
|
||||||
|
/** 商户号 */
|
||||||
|
merchantId: string
|
||||||
|
/** API 版本 */
|
||||||
|
apiVersion?: string
|
||||||
|
/** 证书文件(文件 ID) */
|
||||||
|
certFile?: number
|
||||||
|
/** 回调通知地址 */
|
||||||
|
notifyUrl: string
|
||||||
|
/** 关联商户数(只读) */
|
||||||
|
merchantCount?: number
|
||||||
|
/** 状态:0-禁用 1-启用 */
|
||||||
|
status: number
|
||||||
|
remark?: string
|
||||||
|
createTime: string
|
||||||
|
updateTime: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 状态枚举
|
||||||
|
|
||||||
|
**通道类型** `ChannelType`
|
||||||
|
|
||||||
|
| 值 | 名称 | 说明 |
|
||||||
|
|----|------|------|
|
||||||
|
| WECHAT | 微信支付 | 微信 JSAPI / H5 / Native / APP |
|
||||||
|
| ALIPAY | 支付宝 | 支付宝网页/APP/扫码 |
|
||||||
|
| BANK_CARD | 银行卡 | 银行卡支付(预留) |
|
||||||
|
|
||||||
|
**通道提供方** `ChannelProvider`
|
||||||
|
|
||||||
|
| 值 | 名称 | 说明 |
|
||||||
|
|----|------|------|
|
||||||
|
| WECHAT_DIRECT | 微信直连 | 直接对接微信支付 |
|
||||||
|
| ALIPAY_DIRECT | 支付宝直连 | 直接对接支付宝 |
|
||||||
|
| LAKALA | 拉卡拉 | 聚合支付服务商 |
|
||||||
|
| SHOULIANGBA | 收钱吧 | 聚合支付服务商 |
|
||||||
|
| OTHER | 其他 | 其他聚合支付服务商 |
|
||||||
|
|
||||||
|
> 通道提供方后续可扩展,前端建议做成可配置的字典。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、交易记录
|
||||||
|
|
||||||
|
### 7.1 页面结构
|
||||||
|
|
||||||
|
**列表页** `/payment/transaction`(只读)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 宽度 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| transactionNo | string | 180 | 交易流水号 |
|
||||||
|
| merchantName | string | 150 | 商户名称 |
|
||||||
|
| channelName | string | 120 | 支付通道 |
|
||||||
|
| payType | enum | 100 | 支付方式 |
|
||||||
|
| amount | money | 120 | 交易金额 |
|
||||||
|
| fee | money | 100 | 手续费 |
|
||||||
|
| status | enum | 100 | 交易状态 |
|
||||||
|
| payTime | datetime | 160 | 支付时间 |
|
||||||
|
| createTime | datetime | 160 | 创建时间 |
|
||||||
|
|
||||||
|
**查询条件**:交易流水号、商户名称、支付方式、交易状态、时间范围
|
||||||
|
|
||||||
|
**操作**:查看详情
|
||||||
|
|
||||||
|
### 7.2 字段定义
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface TransactionDTO {
|
||||||
|
id: number
|
||||||
|
/** 交易流水号 */
|
||||||
|
transactionNo: string
|
||||||
|
/** 关联商户 ID */
|
||||||
|
merchantId: number
|
||||||
|
/** 商户名称(冗余) */
|
||||||
|
merchantName: string
|
||||||
|
/** 支付通道 ID */
|
||||||
|
channelId: number
|
||||||
|
/** 通道名称(冗余) */
|
||||||
|
channelName: string
|
||||||
|
/** 支付方式 */
|
||||||
|
payType: ChannelType
|
||||||
|
/** 交易金额(元) */
|
||||||
|
amount: number
|
||||||
|
/** 手续费(元) */
|
||||||
|
fee: number
|
||||||
|
/** 交易状态 */
|
||||||
|
status: TransactionStatus
|
||||||
|
/** 第三方交易号 */
|
||||||
|
thirdPartyTransactionNo?: string
|
||||||
|
/** 支付时间 */
|
||||||
|
payTime?: string
|
||||||
|
/** 关联的业务订单号 */
|
||||||
|
bizOrderNo?: string
|
||||||
|
/** 退款金额(元) */
|
||||||
|
refundAmount?: number
|
||||||
|
/** 备注 */
|
||||||
|
remark?: string
|
||||||
|
createTime: string
|
||||||
|
updateTime: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 状态枚举
|
||||||
|
|
||||||
|
**交易状态** `TransactionStatus`
|
||||||
|
|
||||||
|
| 值 | 名称 | 说明 |
|
||||||
|
|----|------|------|
|
||||||
|
| 0 | 待支付 | 已创建,等待支付 |
|
||||||
|
| 1 | 支付中 | 正在处理 |
|
||||||
|
| 2 | 支付成功 | 支付完成 |
|
||||||
|
| 3 | 支付失败 | 支付失败 |
|
||||||
|
| 4 | 已关闭 | 超时关闭或手动关闭 |
|
||||||
|
| 5 | 已退款 | 全额退款 |
|
||||||
|
| 6 | 部分退款 | 部分退款 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、统一下单流程(前端视角)
|
||||||
|
|
||||||
|
```
|
||||||
|
顾客端(cashier-customer) 支付服务(rui-payment-api) 第三方
|
||||||
|
│ │ │
|
||||||
|
│ 1. 发起支付 │ │
|
||||||
|
│ (payType, amount, │ │
|
||||||
|
│ merchantId, bizOrderNo) │ │
|
||||||
|
│ ──────────────────────────────► │ │
|
||||||
|
│ │ 2. 按 payType 路由通道 │
|
||||||
|
│ │ 3. 创建交易记录 │
|
||||||
|
│ │ ──────────────────────────► │
|
||||||
|
│ │ 4. 调用第三方下单 │
|
||||||
|
│ 5. 返回支付参数 │ │
|
||||||
|
│ (二维码/跳转URL/支付SDK参数) │ │
|
||||||
|
│ ◄────────────────────────────── │ │
|
||||||
|
│ │ │
|
||||||
|
│ 6. 顾客完成支付 │ │
|
||||||
|
│ │ ◄────────────────────────── │
|
||||||
|
│ │ 7. 第三方回调通知 │
|
||||||
|
│ │ 8. 更新交易状态 │
|
||||||
|
│ 9. 查询支付结果 │ │
|
||||||
|
│ ──────────────────────────────► │ │
|
||||||
|
│ 10. 返回支付结果 │ │
|
||||||
|
│ ◄────────────────────────────── │ │
|
||||||
|
```
|
||||||
|
|
||||||
|
> 统一下单和支付回调的具体 API 定义待后端整理后补充。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、前端页面清单
|
||||||
|
|
||||||
|
| 页面 | 路由 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 商户列表 | `/payment/merchant` | 商户 CRUD |
|
||||||
|
| 商户详情 | `/payment/merchant/:id` | 商户信息 + 通道 + 进件记录 |
|
||||||
|
| 进件列表 | `/payment/onboarding` | 进件记录查询 |
|
||||||
|
| 进件申请 | `/payment/onboarding/apply` | 分步表单(新开页面) |
|
||||||
|
| 进件详情 | `/payment/onboarding/:id` | 进件详情 + 状态跟踪 |
|
||||||
|
| 支付通道列表 | `/payment/channel` | 通道配置管理 |
|
||||||
|
| 通道配置 | `/payment/channel/:id?` | 新增/编辑通道 |
|
||||||
|
| 交易记录 | `/payment/transaction` | 交易查询(只读) |
|
||||||
|
| 交易详情 | `/payment/transaction/:id` | 交易详情 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、待补充项
|
||||||
|
|
||||||
|
以下内容由后端整理后补充,前端文档标记为占位:
|
||||||
|
|
||||||
|
1. **API 接口定义**:各模块的请求路径、请求参数、响应结构
|
||||||
|
2. **统一下单接口**:下单、查询、回调的完整 API 定义
|
||||||
|
3. **通道配置参数**:不同通道的特定配置字段(如微信的 v3 密钥、支付宝的私钥等)
|
||||||
|
4. **对账相关**:对账单查询、差异处理(后续迭代)
|
||||||
|
5. **文件上传**:进件材料的 bizType 定义(参考 `API设计规范.md` 第 13 节存储服务)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> **下一步**: 后端整理 API 细节后,更新本文档的待补充项,然后前端可开始实现页面。
|
||||||
@@ -252,7 +252,7 @@ Add dialog component in template:
|
|||||||
|
|
||||||
Run:
|
Run:
|
||||||
```bash
|
```bash
|
||||||
cd /Users/zhangsheng/rhkj/spring-ai/admin-ui
|
cd /Users/zhangsheng/rhkj/rui-framework/admin-ui
|
||||||
pnpm dev:cashier
|
pnpm dev:cashier
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1293,7 +1293,7 @@ git commit -m "feat(cashier): 完善订单管理开台功能"
|
|||||||
|
|
||||||
Install echarts if not already installed:
|
Install echarts if not already installed:
|
||||||
```bash
|
```bash
|
||||||
cd /Users/zhangsheng/rhkj/spring-ai/admin-ui
|
cd /Users/zhangsheng/rhkj/rui-framework/admin-ui
|
||||||
pnpm add echarts vue-echarts
|
pnpm add echarts vue-echarts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1322,7 +1322,7 @@ git commit -m "feat(cashier): 优化营业报表图表展示"
|
|||||||
|
|
||||||
Run:
|
Run:
|
||||||
```bash
|
```bash
|
||||||
cd /Users/zhangsheng/rhkj/spring-ai/admin-ui
|
cd /Users/zhangsheng/rhkj/rui-framework/admin-ui
|
||||||
pnpm build:cashier
|
pnpm build:cashier
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ services:
|
|||||||
- USER_UID=1000
|
- USER_UID=1000
|
||||||
- USER_GID=1000
|
- USER_GID=1000
|
||||||
- GITEA__database__DB_TYPE=sqlite3
|
- GITEA__database__DB_TYPE=sqlite3
|
||||||
- GITEA__server__DOMAIN=git.dev.vifo.cc
|
- GITEA__server__DOMAIN=git.vifo.cc
|
||||||
- GITEA__server__ROOT_URL=https://git.dev.vifo.cc
|
- GITEA__server__ROOT_URL=https://git.vifo.cc
|
||||||
- GITEA__server__SSH_DOMAIN=git.dev.vifo.cc
|
- GITEA__server__SSH_DOMAIN=git.vifo.cc
|
||||||
- GITEA__actions__ENABLED=true
|
- GITEA__actions__ENABLED=true
|
||||||
- GITEA__webhook__ALLOWED_HOST_LIST=*
|
- GITEA__webhook__ALLOWED_HOST_LIST=*
|
||||||
# 或者只允许特定网段:
|
# 或者只允许特定网段:
|
||||||
@@ -32,7 +32,7 @@ services:
|
|||||||
container_name: runner-default
|
container_name: runner-default
|
||||||
environment:
|
environment:
|
||||||
CONFIG_FILE: /config.yaml
|
CONFIG_FILE: /config.yaml
|
||||||
GITEA_INSTANCE_URL: "https://git.dev.vifo.cc"
|
GITEA_INSTANCE_URL: "https://git.vifo.cc"
|
||||||
GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_TOKEN}"
|
GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_TOKEN}"
|
||||||
GITEA_RUNNER_NAME: "runner-default"
|
GITEA_RUNNER_NAME: "runner-default"
|
||||||
GITEA_RUNNER_LABELS: "ubuntu-latest:docker://node:20-slim"
|
GITEA_RUNNER_LABELS: "ubuntu-latest:docker://node:20-slim"
|
||||||
@@ -54,7 +54,7 @@ services:
|
|||||||
container_name: runner-node
|
container_name: runner-node
|
||||||
environment:
|
environment:
|
||||||
CONFIG_FILE: /config.yaml
|
CONFIG_FILE: /config.yaml
|
||||||
GITEA_INSTANCE_URL: "https://git.dev.vifo.cc"
|
GITEA_INSTANCE_URL: "https://git.vifo.cc"
|
||||||
GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_TOKEN}"
|
GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_TOKEN}"
|
||||||
GITEA_RUNNER_NAME: "runner-node"
|
GITEA_RUNNER_NAME: "runner-node"
|
||||||
GITEA_RUNNER_LABELS: "node:docker://node:20-slim,ubuntu-latest:docker://node:20-slim"
|
GITEA_RUNNER_LABELS: "node:docker://node:20-slim,ubuntu-latest:docker://node:20-slim"
|
||||||
@@ -83,7 +83,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
CONFIG_FILE: /config.yaml
|
CONFIG_FILE: /config.yaml
|
||||||
GITEA_INSTANCE_URL: "https://git.dev.vifo.cc"
|
GITEA_INSTANCE_URL: "https://git.vifo.cc"
|
||||||
GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_TOKEN}"
|
GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_TOKEN}"
|
||||||
GITEA_RUNNER_NAME: "runner-java"
|
GITEA_RUNNER_NAME: "runner-java"
|
||||||
GITEA_RUNNER_LABELS: "java:docker://maven:3.9-eclipse-temurin-17,ubuntu-latest:docker://maven:3.9-eclipse-temurin-17"
|
GITEA_RUNNER_LABELS: "java:docker://maven:3.9-eclipse-temurin-17,ubuntu-latest:docker://maven:3.9-eclipse-temurin-17"
|
||||||
|
|||||||
+21
-15
@@ -116,10 +116,12 @@ GET /v1/user/users?username=admin&status=1&createdAt_start=2024-01-01&createdAt_
|
|||||||
|
|
||||||
### 4.1 统一响应格式
|
### 4.1 统一响应格式
|
||||||
|
|
||||||
|
> 详细规范见 [Result 统一响应类](Result统一响应类.md)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": 200,
|
"error": 0,
|
||||||
"msg": "操作成功",
|
"message": "操作成功",
|
||||||
"data": {}
|
"data": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -128,8 +130,8 @@ GET /v1/user/users?username=admin&status=1&createdAt_start=2024-01-01&createdAt_
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": 200,
|
"error": 0,
|
||||||
"msg": "操作成功",
|
"message": "操作成功",
|
||||||
"data": {
|
"data": {
|
||||||
"records": [],
|
"records": [],
|
||||||
"total": 100,
|
"total": 100,
|
||||||
@@ -159,19 +161,23 @@ GET /v1/user/users?username=admin&status=1&createdAt_start=2024-01-01&createdAt_
|
|||||||
|
|
||||||
| 区间 | 模块 | 示例 |
|
| 区间 | 模块 | 示例 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 1000-1999 | 通用 | 1001: 参数校验失败, 1002: 资源不存在 |
|
| 0 | 通用成功 | `0: 操作成功` |
|
||||||
| 2000-2999 | 用户模块 | 2001: 用户名已存在, 2002: 密码错误 |
|
| 1 | 通用失败 | `1: 操作失败` |
|
||||||
| 3000-3999 | 系统模块 | 3001: 字典不存在, 3002: 配置错误 |
|
| 400-499 | HTTP 标准 | `401: 未授权, 404: 资源不存在` |
|
||||||
| 4000-4999 | 认证模块 | 4001: Token 过期, 4002: 无权访问 |
|
| 4000-4099 | 认证模块 | `4001: Token 已过期, 4002: Token 无效` |
|
||||||
| 5000-5999 | 文件模块 | 5001: 上传失败, 5002: 文件过大 |
|
| 4100-4199 | 用户信息 | `4101: 用户不存在, 4102: 用户名已存在` |
|
||||||
| 6000-6999 | 消息模块 | 6001: 发送失败, 6002: 模板不存在 |
|
| 4200-4299 | 用户等级 | `4201: 等级编码已存在` |
|
||||||
|
| 5000-5999 | 文件模块(预留) | `5001: 上传失败, 5002: 文件大小超限` |
|
||||||
|
| 6000-6999 | 消息模块(预留) | `6001: 发送失败, 6002: 模板不存在` |
|
||||||
|
|
||||||
|
> 完整枚举值见 [Result 统一响应类 → ResultCode 枚举](Result统一响应类.md#四resultcode-枚举)
|
||||||
|
|
||||||
**错误响应示例**:
|
**错误响应示例**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": 2001,
|
"error": 4102,
|
||||||
"msg": "用户名已存在",
|
"message": "用户名已存在",
|
||||||
"data": null
|
"code": "USER_INFO_USERNAME_EXISTS"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -321,7 +327,7 @@ public class UserRemoteService {
|
|||||||
if (result.isSuccess()) {
|
if (result.isSuccess()) {
|
||||||
return result.getData();
|
return result.getData();
|
||||||
}
|
}
|
||||||
throw new BizException(result.getCode(), result.getMsg());
|
throw new BizException(result.getError(), result.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -464,7 +470,7 @@ http://localhost:9601/v3/api-docs # 收银服务 API 文档
|
|||||||
## 十三、文件存储服务(rui-service-storage)
|
## 十三、文件存储服务(rui-service-storage)
|
||||||
|
|
||||||
> **服务定位**:独立微服务(9400 端口 / 聚合启动器 9399),所有业务模块共用一个上传入口,通过 `bizType` 区分业务场景。
|
> **服务定位**:独立微服务(9400 端口 / 聚合启动器 9399),所有业务模块共用一个上传入口,通过 `bizType` 区分业务场景。
|
||||||
> **前端组件**:`<RuiUpload>`([rui-frontend#5](https://git.dev.vifo.cc/rui/rui-frontend/issues/5))。
|
> **前端组件**:`<RuiUpload>`([rui-frontend#5](https://git.vifo.cc/rui/rui-frontend/issues/5))。
|
||||||
|
|
||||||
### 13.1 上传文件
|
### 13.1 上传文件
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,332 @@
|
|||||||
|
# Result<T> 统一响应类规范
|
||||||
|
|
||||||
|
> RUI 框架所有 API 接口的统一返回包装
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、类信息
|
||||||
|
|
||||||
|
| 属性 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| 包路径 | `com.rui.common.core.result.Result` |
|
||||||
|
| 所在模块 | `rui-common-core` |
|
||||||
|
| 泛型参数 | `<T>` — data 字段的具体类型 |
|
||||||
|
| 序列化 | 实现 `Serializable` |
|
||||||
|
| JSON 策略 | `@JsonInclude(NON_NULL)` — 值为 `null` 的字段自动忽略 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、响应结构
|
||||||
|
|
||||||
|
### 2.1 字段定义
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 | 成功时 | 失败时 |
|
||||||
|
|------|------|------|--------|--------|
|
||||||
|
| `error` | `int` | 状态码(0 = 成功) | `0` | 非 0 |
|
||||||
|
| `message` | `String` | 提示信息 | `"操作成功"` | 具体错误描述 |
|
||||||
|
| `code` | `String` | 业务错误码 | `null`(不输出) | 如 `"AUTH_UNAUTHORIZED"` |
|
||||||
|
| `data` | `T` | 业务数据 | 实际数据 | 通常为 `null`(不输出) |
|
||||||
|
|
||||||
|
### 2.2 成功响应示例
|
||||||
|
|
||||||
|
**无数据返回:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": 0,
|
||||||
|
"message": "操作成功"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**带数据返回:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": 0,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"id": 1001,
|
||||||
|
"username": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**分页数据:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": 0,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"records": [],
|
||||||
|
"total": 100,
|
||||||
|
"size": 10,
|
||||||
|
"current": 1,
|
||||||
|
"pages": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 失败响应示例
|
||||||
|
|
||||||
|
**通用失败:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": 1,
|
||||||
|
"message": "操作失败"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**带业务错误码:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": 401,
|
||||||
|
"message": "未授权",
|
||||||
|
"code": "AUTH_UNAUTHORIZED"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**带数据(未找到场景):**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": 404,
|
||||||
|
"message": "数据不存在",
|
||||||
|
"code": "DATA_NOT_FOUND",
|
||||||
|
"data": "dictCode_001"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> `data` 字段在 `failNotFound` 场景下用于传递资源 key,便于前端做国际化模板替换。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、静态工厂方法
|
||||||
|
|
||||||
|
### 3.1 成功系列
|
||||||
|
|
||||||
|
| 方法签名 | 说明 | 使用场景 |
|
||||||
|
|----------|------|----------|
|
||||||
|
| `Result.ok()` | 无数据成功 | 删除、更新等不需要返回数据的操作 |
|
||||||
|
| `Result.ok(T data)` | 带数据成功 | 查询详情、列表、新增返回实体 |
|
||||||
|
|
||||||
|
### 3.2 失败系列
|
||||||
|
|
||||||
|
| 方法签名 | 说明 | 使用场景 |
|
||||||
|
|----------|------|----------|
|
||||||
|
| `Result.fail()` | 通用失败 | 兜底异常、未知错误 |
|
||||||
|
| `Result.fail(String message)` | 自定义提示 | 需要特定提示信息的业务异常 |
|
||||||
|
| `Result.fail(ResultCode resultCode)` | 枚举驱动 | 标准业务错误,推荐使用 |
|
||||||
|
| `Result.fail(int error, String message)` | 自定义错误码+提示 | 非标准错误场景 |
|
||||||
|
| `Result.fail(int error, String message, String code)` | 完全自定义 | 需要同时指定三个字段 |
|
||||||
|
| `Result.fail(ResultCode resultCode, T data)` | 枚举+数据 | 失败时需携带部分数据 |
|
||||||
|
| `Result.failNotFound(ResultCode resultCode, String key)` | 404 未找到 | 数据不存在,key 放入 data |
|
||||||
|
|
||||||
|
### 3.3 判断方法
|
||||||
|
|
||||||
|
| 方法 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `result.isSuccess()` | 判断是否成功(`error == 0`) |
|
||||||
|
| `result.toJsonString()` | 序列化为 JSON 字符串 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、ResultCode 枚举
|
||||||
|
|
||||||
|
### 4.1 枚举结构
|
||||||
|
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `error` | `int` | HTTP 风格状态码,0 为成功 |
|
||||||
|
| `message` | `String` | 默认提示文本 |
|
||||||
|
| `code` | `String` | 业务错误码(大写蛇形,模块前缀) |
|
||||||
|
|
||||||
|
### 4.2 枚举值一览
|
||||||
|
|
||||||
|
| 枚举值 | error | message | code | 说明 |
|
||||||
|
|--------|-------|---------|------|------|
|
||||||
|
| `SUCCESS` | 0 | 操作成功 | `null` | 成功 |
|
||||||
|
| `FAILURE` | 1 | 操作失败 | `null` | 通用失败 |
|
||||||
|
| `UNAUTHORIZED` | 401 | 未授权 | `AUTH_UNAUTHORIZED` | 未登录 |
|
||||||
|
| `FORBIDDEN` | 403 | 无权限 | `AUTH_FORBIDDEN` | 无权限 |
|
||||||
|
| `NOT_FOUND` | 404 | 资源不存在 | `COMMON_NOT_FOUND` | 资源未找到 |
|
||||||
|
| `DATA_NOT_FOUND` | 404 | 数据不存在 | `DATA_NOT_FOUND` | 数据未找到 |
|
||||||
|
| `VALIDATE_FAILED` | 400 | 参数校验失败 | `COMMON_VALIDATE_FAILED` | 参数错误 |
|
||||||
|
| `TOKEN_EXPIRED` | 4001 | Token 已过期 | `AUTH_TOKEN_EXPIRED` | Token 过期 |
|
||||||
|
| `TOKEN_INVALID` | 4002 | Token 无效 | `AUTH_TOKEN_INVALID` | Token 无效 |
|
||||||
|
| `TENANT_NOT_FOUND` | 4003 | 租户不存在 | `AUTH_TENANT_NOT_FOUND` | 租户不存在 |
|
||||||
|
| `TENANT_DISABLED` | 4004 | 租户已禁用 | `AUTH_TENANT_DISABLED` | 租户禁用 |
|
||||||
|
| `USER_NOT_FOUND` | 4101 | 用户不存在 | `USER_INFO_NOT_FOUND` | 用户不存在 |
|
||||||
|
| `USERNAME_EXISTS` | 4102 | 用户名已存在 | `USER_INFO_USERNAME_EXISTS` | 用户名重复 |
|
||||||
|
| `LEVEL_CODE_EXISTS` | 4201 | 等级编码已存在 | `USER_LEVEL_CODE_EXISTS` | 等级编码重复 |
|
||||||
|
|
||||||
|
### 4.3 错误码规划规则
|
||||||
|
|
||||||
|
| 区间 | 模块 | code 前缀 |
|
||||||
|
|------|------|-----------|
|
||||||
|
| 0 | 通用成功 | — |
|
||||||
|
| 1 | 通用失败 | — |
|
||||||
|
| 400-499 | HTTP 标准错误 | `COMMON_*` / `AUTH_*` |
|
||||||
|
| 4000-4099 | 认证错误 | `AUTH_*` |
|
||||||
|
| 4100-4199 | 用户信息错误 | `USER_INFO_*` |
|
||||||
|
| 4200-4299 | 用户等级错误 | `USER_LEVEL_*` |
|
||||||
|
| 5000-5999 | 文件模块(预留) | `FILE_*` |
|
||||||
|
| 6000-6999 | 消息模块(预留) | `MSG_*` |
|
||||||
|
|
||||||
|
**新增规则**:新模块取 100 的整数倍区间,code 格式为 `{模块}_{业务}_{具体}`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、Controller 使用示例
|
||||||
|
|
||||||
|
### 5.1 标准 CRUD
|
||||||
|
|
||||||
|
```java
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/v1/system/roles")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SysRoleController {
|
||||||
|
|
||||||
|
private final SysRoleService roleService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public Result<IPage<SysRoleVO>> list(SysRoleQuery query) {
|
||||||
|
return Result.ok(roleService.page(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<SysRoleVO> getById(@PathVariable Long id) {
|
||||||
|
SysRoleVO role = roleService.getById(id);
|
||||||
|
if (role == null) {
|
||||||
|
return Result.failNotFound(ResultCode.DATA_NOT_FOUND, String.valueOf(id));
|
||||||
|
}
|
||||||
|
return Result.ok(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<SysRoleVO> create(@RequestBody @Valid SysRoleDTO dto) {
|
||||||
|
return Result.ok(roleService.create(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public Result<SysRoleVO> update(@PathVariable Long id, @RequestBody @Valid SysRoleDTO dto) {
|
||||||
|
return Result.ok(roleService.update(id, dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<Void> delete(@PathVariable Long id) {
|
||||||
|
roleService.delete(id);
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 异常处理中返回
|
||||||
|
|
||||||
|
```java
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(BizException.class)
|
||||||
|
public Result<Void> handleBizException(BizException e) {
|
||||||
|
return Result.fail(e.getCode(), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public Result<Void> handleValidation(MethodArgumentNotValidException e) {
|
||||||
|
String message = e.getBindingResult().getFieldErrors().stream()
|
||||||
|
.map(FieldError::getDefaultMessage)
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
return Result.fail(ResultCode.VALIDATE_FAILED.getError(), message, ResultCode.VALIDATE_FAILED.getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 Feign 远程调用中处理 Result
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserRemoteService {
|
||||||
|
|
||||||
|
private final RemoteUserService remoteUserService;
|
||||||
|
|
||||||
|
public UserVO getUserById(Long userId) {
|
||||||
|
Result<UserVO> result = remoteUserService.getById(userId);
|
||||||
|
if (result.isSuccess()) {
|
||||||
|
return result.getData();
|
||||||
|
}
|
||||||
|
throw new BizException(result.getError(), result.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、前端对接指南
|
||||||
|
|
||||||
|
### 6.1 判断成功
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// response.data 为 Result<T> 结构
|
||||||
|
const isSuccess = response.data.error === 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 错误处理
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
if (result.error !== 0) {
|
||||||
|
// 优先用 code 做国际化
|
||||||
|
if (result.code) {
|
||||||
|
showI18nMessage(result.code, { key: result.data });
|
||||||
|
} else {
|
||||||
|
// 降级显示 message
|
||||||
|
showMessage(result.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 TypeScript 类型定义
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Result<T = any> {
|
||||||
|
error: number;
|
||||||
|
message: string;
|
||||||
|
code?: string; // 失败时存在
|
||||||
|
data?: T; // 成功时或 failNotFound 时存在
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、扩展指南
|
||||||
|
|
||||||
|
### 7.1 新增 ResultCode
|
||||||
|
|
||||||
|
在 `ResultCode` 枚举中添加新值,遵循以下规则:
|
||||||
|
|
||||||
|
1. **error 取值**:按模块区间分配(见 4.3 节)
|
||||||
|
2. **code 命名**:`{模块}_{业务}_{具体}`,全大写蛇形
|
||||||
|
3. **向后兼容**:禁止修改已有枚举值的 error 或 code
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 示例:文件模块新增
|
||||||
|
FILE_UPLOAD_FAILED(5001, "文件上传失败", "FILE_UPLOAD_FAILED"),
|
||||||
|
FILE_SIZE_EXCEEDED(5002, "文件大小超限", "FILE_SIZE_EXCEEDED"),
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 禁止事项
|
||||||
|
|
||||||
|
- ❌ 不要在 Controller 中直接 `new Result<>()`,必须使用静态工厂方法
|
||||||
|
- ❌ 不要修改 `Result` 类的字段名(`error`/`message`/`code`/`data`),影响序列化兼容
|
||||||
|
- ❌ 不要用 `error` 字段传递 HTTP 状态码(它只是业务状态码,HTTP 状态码由框架控制)
|
||||||
|
- ❌ 不要在 `code` 字段中使用小写或特殊字符
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> **文档版本**: v1.0
|
||||||
|
> **创建日期**: 2026-06-08
|
||||||
|
> **源码位置**: `rui-common/rui-common-core/src/main/java/com/rui/common/core/result/`
|
||||||
|
> **适用范围**: RUI 框架所有模块的 API 响应
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# 数据库设计规范分析报告
|
# 数据库设计规范分析报告
|
||||||
|
|
||||||
> 基于对当前 spring-ai 项目数据库设计的全面审查,本报告列出所有不合理之处及专业改进方案。
|
> 基于对当前 rui-framework 项目数据库设计的全面审查,本报告列出所有不合理之处及专业改进方案。
|
||||||
> **注意:本报告仅做分析,不做任何代码实施。**
|
> **注意:本报告仅做分析,不做任何代码实施。**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,644 @@
|
|||||||
|
# 门店管理新增字段 Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers-subagent-driven-development (recommended) or superpowers-executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 在 admin-ui 门店管理模块中适配后端新增的 9 个字段,修改表单弹窗和列表页,所有变更在现有 `useApiForm` + `ApiFormDialog` + `RuiTable` 框架内完成。
|
||||||
|
|
||||||
|
**Architecture:** 修改 2 个现有文件。`StoreFormDialog.vue` 新增 7 个可编辑字段(useApiForm fields 数组)、2 个只读字段(custom-fields 插槽)、数据双向转换逻辑(amenities JSON 序列化、serviceFeeRate 百分比转换)。`Index.vue` 新增 3 列(门店类型 Tag、包间信息、设施标签)、1 个筛选条件(门店类型下拉)、`parseAmenities` 工具函数。
|
||||||
|
|
||||||
|
**Tech Stack:** Vue 3 (Composition API / `<script setup>`) + TypeScript + Element Plus + Vite + pnpm
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
| # | 文件 | 操作 | 变更说明 |
|
||||||
|
|---|------|------|---------|
|
||||||
|
| 1 | `admin-ui/src/views/cashier/store/StoreFormDialog.vue` | 修改 | 扩展 `useApiForm` 的 `initial` 和 `fields`(+7 字段);修改 `onSubmit` 添加 amenities/serviceFeeRate 数据转换;修改 `watch` 添加编辑回填数据转换;模板添加 `width="720px"` 和 `#custom-fields` 插槽 |
|
||||||
|
| 2 | `admin-ui/src/views/cashier/store/Index.vue` | 修改 | `queryParams` 增加 `storeType`;`handleReset` 补充 `storeType` 重置;新增 `parseAmenities` 工具函数;`columns` 增加 3 列;模板增加门店类型筛选和 3 个列 slot |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: StoreFormDialog — 扩展 initial 默认值
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/StoreFormDialog.vue` (lines 32–40)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 在 `useApiForm` 的 `initial` 对象中追加新字段默认值**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
initial: {
|
||||||
|
storeName: '',
|
||||||
|
storeCode: '',
|
||||||
|
address: '',
|
||||||
|
contactPhone: '',
|
||||||
|
contactName: '',
|
||||||
|
businessHours: '',
|
||||||
|
status: 1,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
initial: {
|
||||||
|
storeName: '',
|
||||||
|
storeCode: '',
|
||||||
|
address: '',
|
||||||
|
contactPhone: '',
|
||||||
|
contactName: '',
|
||||||
|
businessHours: '',
|
||||||
|
status: 1,
|
||||||
|
storeType: 'STANDARD',
|
||||||
|
amenities: [],
|
||||||
|
longitude: undefined,
|
||||||
|
latitude: undefined,
|
||||||
|
serviceFeeRate: undefined,
|
||||||
|
openingDate: '',
|
||||||
|
legalPerson: '',
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/StoreFormDialog.vue
|
||||||
|
git commit -m "feat(store): 扩展 useApiForm initial 默认值,新增 7 个字段默认值"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: StoreFormDialog — 在 fields 数组中追加 7 个新字段
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/StoreFormDialog.vue` (lines 76–86, status 字段之后、fields 数组结束之前)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 在 status 字段配置之后、`],` 之前,插入 7 个新字段配置**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
label: '状态',
|
||||||
|
type: 'radio',
|
||||||
|
required: true,
|
||||||
|
options: [
|
||||||
|
{ label: '启用', value: 1 },
|
||||||
|
{ label: '禁用', value: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onSubmit: async (data) => {
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
label: '状态',
|
||||||
|
type: 'radio',
|
||||||
|
required: true,
|
||||||
|
options: [
|
||||||
|
{ label: '启用', value: 1 },
|
||||||
|
{ label: '禁用', value: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'storeType',
|
||||||
|
label: '门店类型',
|
||||||
|
type: 'select',
|
||||||
|
required: true,
|
||||||
|
options: [
|
||||||
|
{ label: '旗舰店', value: 'FLAGSHIP' },
|
||||||
|
{ label: '标准店', value: 'STANDARD' },
|
||||||
|
{ label: '社区店', value: 'COMMUNITY' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'amenities',
|
||||||
|
label: '设施标签',
|
||||||
|
type: 'checkbox',
|
||||||
|
options: [
|
||||||
|
{ label: '免费停车', value: '免费停车' },
|
||||||
|
{ label: '免费WiFi', value: '免费WiFi' },
|
||||||
|
{ label: '充电桩', value: '充电桩' },
|
||||||
|
{ label: '24小时营业', value: '24小时营业' },
|
||||||
|
{ label: '包厢', value: '包厢' },
|
||||||
|
{ label: '吸烟区', value: '吸烟区' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'longitude',
|
||||||
|
label: '经度',
|
||||||
|
type: 'number',
|
||||||
|
props: { min: -180, max: 180, precision: 6, step: 0.000001 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'latitude',
|
||||||
|
label: '纬度',
|
||||||
|
type: 'number',
|
||||||
|
props: { min: -90, max: 90, precision: 6, step: 0.000001 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'serviceFeeRate',
|
||||||
|
label: '平台服务费率(%)',
|
||||||
|
type: 'number',
|
||||||
|
props: { min: 0, max: 100, precision: 2, step: 0.01 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'openingDate',
|
||||||
|
label: '开业日期',
|
||||||
|
type: 'date',
|
||||||
|
props: { valueFormat: 'YYYY-MM-DD' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'legalPerson',
|
||||||
|
label: '法人姓名',
|
||||||
|
type: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onSubmit: async (data) => {
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/StoreFormDialog.vue
|
||||||
|
git commit -m "feat(store): 在 useApiForm fields 中新增 7 个可编辑字段配置"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: StoreFormDialog — 修改 onSubmit 添加数据转换
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/StoreFormDialog.vue` (lines 86–100, onSubmit 回调)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 替换 onSubmit 回调,添加 amenities JSON 序列化和 serviceFeeRate 百分比转小数**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
onSubmit: async (data) => {
|
||||||
|
const isEdit = !!(data as any).id
|
||||||
|
|
||||||
|
if (isEdit) {
|
||||||
|
await storeService.update(data)
|
||||||
|
ElMessage.success('修改成功')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await storeService.add(data)
|
||||||
|
ElMessage.success('新增成功')
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('success')
|
||||||
|
emit('update:visible', false)
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
onSubmit: async (rawData) => {
|
||||||
|
const data = { ...rawData } as any
|
||||||
|
|
||||||
|
// amenities: string[] → JSON 字符串
|
||||||
|
if (Array.isArray(data.amenities)) {
|
||||||
|
data.amenities = JSON.stringify(data.amenities)
|
||||||
|
}
|
||||||
|
|
||||||
|
// serviceFeeRate: 百分比 → 小数
|
||||||
|
if (data.serviceFeeRate != null && data.serviceFeeRate !== '') {
|
||||||
|
data.serviceFeeRate = Number(data.serviceFeeRate) / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
const isEdit = !!data.id
|
||||||
|
|
||||||
|
if (isEdit) {
|
||||||
|
await storeService.update(data)
|
||||||
|
ElMessage.success('修改成功')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await storeService.add(data)
|
||||||
|
ElMessage.success('新增成功')
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('success')
|
||||||
|
emit('update:visible', false)
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/StoreFormDialog.vue
|
||||||
|
git commit -m "feat(store): onSubmit 中添加 amenities JSON 序列化和 serviceFeeRate 百分比转小数"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 4: StoreFormDialog — 修改 watch 添加编辑回填数据转换
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/StoreFormDialog.vue` (lines 104–116, watch 回调)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 替换 watch 回调,添加 amenities JSON 解析和 serviceFeeRate 小数转百分比**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
// 监听编辑数据
|
||||||
|
watch(() => props.visible, (val) => {
|
||||||
|
if (val) {
|
||||||
|
if (props.row) {
|
||||||
|
// 编辑时设置表单数据
|
||||||
|
form.value = {
|
||||||
|
...props.row,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resetForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
// 监听编辑数据
|
||||||
|
watch(() => props.visible, (val) => {
|
||||||
|
if (val) {
|
||||||
|
if (props.row) {
|
||||||
|
const rowData = { ...props.row }
|
||||||
|
|
||||||
|
// amenities: JSON 字符串 → string[]
|
||||||
|
if (typeof rowData.amenities === 'string' && rowData.amenities) {
|
||||||
|
try {
|
||||||
|
rowData.amenities = JSON.parse(rowData.amenities)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
rowData.amenities = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!Array.isArray(rowData.amenities)) {
|
||||||
|
rowData.amenities = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// serviceFeeRate: 小数 → 百分比
|
||||||
|
if (rowData.serviceFeeRate != null) {
|
||||||
|
rowData.serviceFeeRate = Number(rowData.serviceFeeRate) * 100
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑时设置表单数据
|
||||||
|
form.value = rowData
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resetForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/StoreFormDialog.vue
|
||||||
|
git commit -m "feat(store): watch 中添加 amenities JSON 解析和 serviceFeeRate 小数转百分比回填"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 5: StoreFormDialog — 模板添加 width 属性和 custom-fields 插槽
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/StoreFormDialog.vue` (lines 120–128, template 中的 ApiFormDialog 标签)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 替换 ApiFormDialog 自闭合标签为开闭标签,添加 width 和 custom-fields 插槽**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```vue
|
||||||
|
<ApiFormDialog
|
||||||
|
v-model:visible="localVisible"
|
||||||
|
v-model:form="form"
|
||||||
|
:title="(form as any).id ? '编辑门店' : '新增门店'"
|
||||||
|
:fields="fields"
|
||||||
|
:rules="rules"
|
||||||
|
:loading="loading"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```vue
|
||||||
|
<ApiFormDialog
|
||||||
|
v-model:visible="localVisible"
|
||||||
|
v-model:form="form"
|
||||||
|
:title="(form as any).id ? '编辑门店' : '新增门店'"
|
||||||
|
:width="'720px'"
|
||||||
|
:fields="fields"
|
||||||
|
:rules="rules"
|
||||||
|
:loading="loading"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
>
|
||||||
|
<template #custom-fields="{ form: formData }">
|
||||||
|
<template v-if="formData.id">
|
||||||
|
<el-form-item label="包间总数">
|
||||||
|
<span>{{ formData.roomCount ?? '-' }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="空闲包间数">
|
||||||
|
<span>{{ formData.freeRoomCount ?? '-' }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</ApiFormDialog>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/StoreFormDialog.vue
|
||||||
|
git commit -m "feat(store): ApiFormDialog 增加 width=720px 和 custom-fields 插槽展示只读包间字段"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 6: Index.vue — 扩展 queryParams、handleReset、新增 parseAmenities 工具函数
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/Index.vue`
|
||||||
|
|
||||||
|
- [ ] **Step 1: 在 queryParams 中增加 storeType 字段**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
const queryParams = ref({
|
||||||
|
storeName: '',
|
||||||
|
status: undefined as number | undefined,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
const queryParams = ref({
|
||||||
|
storeName: '',
|
||||||
|
status: undefined as number | undefined,
|
||||||
|
storeType: undefined as string | undefined,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: 在 handleReset 中补充 storeType 重置**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
function handleReset() {
|
||||||
|
queryParams.value = {
|
||||||
|
storeName: '',
|
||||||
|
status: undefined,
|
||||||
|
}
|
||||||
|
tableRef.value?.reset()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
function handleReset() {
|
||||||
|
queryParams.value = {
|
||||||
|
storeName: '',
|
||||||
|
status: undefined,
|
||||||
|
storeType: undefined,
|
||||||
|
}
|
||||||
|
tableRef.value?.reset()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: 在 `handleStatusChange` 函数之后(`</script>` 标签之前),添加 `parseAmenities` 工具函数**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
async function handleStatusChange(row: any, status: number) {
|
||||||
|
if (!row?.id) return
|
||||||
|
try {
|
||||||
|
await storeService.changeStatus(row.id, status)
|
||||||
|
ElMessage.success(status === 1 ? '启用成功' : '禁用成功')
|
||||||
|
} catch {
|
||||||
|
row.status = status === 1 ? 0 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
async function handleStatusChange(row: any, status: number) {
|
||||||
|
if (!row?.id) return
|
||||||
|
try {
|
||||||
|
await storeService.changeStatus(row.id, status)
|
||||||
|
ElMessage.success(status === 1 ? '启用成功' : '禁用成功')
|
||||||
|
} catch {
|
||||||
|
row.status = status === 1 ? 0 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析设施标签(兼容 JSON 字符串和数组)
|
||||||
|
*/
|
||||||
|
function parseAmenities(val: any): string[] {
|
||||||
|
if (Array.isArray(val)) return val
|
||||||
|
if (typeof val === 'string' && val) {
|
||||||
|
try { return JSON.parse(val) } catch { return [] }
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/Index.vue
|
||||||
|
git commit -m "feat(store): queryParams 增加 storeType 筛选、handleReset 补充重置、新增 parseAmenities 工具函数"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 7: Index.vue — 在 columns 数组中追加 3 列配置
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/Index.vue` (lines 12–28, columns 数组)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 在 address 列之后追加 storeType、roomInfo、amenities 3 列**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```ts
|
||||||
|
{ prop: 'address', label: '地址', minWidth: 200, tooltip: true },
|
||||||
|
{ prop: 'businessHours', label: '营业时间', width: 120 },
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```ts
|
||||||
|
{ prop: 'address', label: '地址', minWidth: 200, tooltip: true },
|
||||||
|
{ prop: 'storeType', label: '门店类型', width: 100, align: 'center', slot: true },
|
||||||
|
{ prop: 'roomInfo', label: '包间', width: 120, align: 'center', slot: true },
|
||||||
|
{ prop: 'amenities', label: '设施标签', minWidth: 200, slot: true },
|
||||||
|
{ prop: 'businessHours', label: '营业时间', width: 120 },
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/Index.vue
|
||||||
|
git commit -m "feat(store): columns 增加 storeType/roomInfo/amenities 3 列配置"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 8: Index.vue — 模板添加门店类型筛选和 3 个列 slot
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `admin-ui/src/views/cashier/store/Index.vue` (template 部分)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 在状态筛选的 `</el-form-item>` 之后、查询按钮的 `<el-form-item>` 之前,插入门店类型筛选**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```vue
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||||
|
<el-option label="启用" :value="1" />
|
||||||
|
<el-option label="禁用" :value="0" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```vue
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||||
|
<el-option label="启用" :value="1" />
|
||||||
|
<el-option label="禁用" :value="0" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="门店类型">
|
||||||
|
<el-select v-model="queryParams.storeType" placeholder="请选择门店类型" clearable>
|
||||||
|
<el-option label="旗舰店" value="FLAGSHIP" />
|
||||||
|
<el-option label="标准店" value="STANDARD" />
|
||||||
|
<el-option label="社区店" value="COMMUNITY" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: 在状态列 slot(`#column-status`)的 `</template>` 之后、操作列 slot 之前,插入 3 个列 slot 模板**
|
||||||
|
|
||||||
|
**Old string:**
|
||||||
|
```vue
|
||||||
|
<!-- 状态列 -->
|
||||||
|
<template #column-status="{ row }">
|
||||||
|
<el-switch
|
||||||
|
v-model="row.status"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
@change="(val: any) => handleStatusChange(row, val as number)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 操作列 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
**New string:**
|
||||||
|
```vue
|
||||||
|
<!-- 状态列 -->
|
||||||
|
<template #column-status="{ row }">
|
||||||
|
<el-switch
|
||||||
|
v-model="row.status"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
@change="(val: any) => handleStatusChange(row, val as number)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 门店类型列 -->
|
||||||
|
<template #column-storeType="{ row }">
|
||||||
|
<el-tag
|
||||||
|
:type="row.storeType === 'FLAGSHIP' ? 'danger' : row.storeType === 'STANDARD' ? '' : 'info'"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{{ { FLAGSHIP: '旗舰店', STANDARD: '标准店', COMMUNITY: '社区店' }[row.storeType] || '-' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 包间信息列 -->
|
||||||
|
<template #column-roomInfo="{ row }">
|
||||||
|
<span>{{ row.freeRoomCount ?? '-' }}/{{ row.roomCount ?? '-' }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 设施标签列 -->
|
||||||
|
<template #column-amenities="{ row }">
|
||||||
|
<template v-if="parseAmenities(row.amenities).length">
|
||||||
|
<el-tag
|
||||||
|
v-for="tag in parseAmenities(row.amenities)"
|
||||||
|
:key="tag"
|
||||||
|
size="small"
|
||||||
|
type="info"
|
||||||
|
class="mr-1 mb-1"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 操作列 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add admin-ui/src/views/cashier/store/Index.vue
|
||||||
|
git commit -m "feat(store): 模板新增门店类型筛选条件和 storeType/roomInfo/amenities 列 slot"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 9: 构建验证 + 最终提交
|
||||||
|
|
||||||
|
- [ ] **Step 1: 运行 TypeScript 类型检查**
|
||||||
|
|
||||||
|
Run: `pnpm --filter admin-ui type-check`
|
||||||
|
Expected: 0 errors, 命令退出码 0
|
||||||
|
|
||||||
|
- [ ] **Step 2: 运行 ESLint 检查**
|
||||||
|
|
||||||
|
Run: `pnpm --filter admin-ui lint`
|
||||||
|
Expected: 0 errors, 0 warnings(或仅有与本次修改无关的已存在 warnings)
|
||||||
|
|
||||||
|
- [ ] **Step 3: 运行 Vite 构建**
|
||||||
|
|
||||||
|
Run: `pnpm --filter admin-ui build`
|
||||||
|
Expected: 构建成功,无编译错误,输出 dist 目录
|
||||||
|
|
||||||
|
- [ ] **Step 4: 启动开发服务器进行手动验证**
|
||||||
|
|
||||||
|
Run: `pnpm --filter admin-ui dev`
|
||||||
|
Expected: 开发服务器正常启动,浏览器打开后:
|
||||||
|
1. 门店管理列表页正确展示新增 3 列
|
||||||
|
2. 门店类型下拉筛选功能正常
|
||||||
|
3. 点击新增门店,弹窗宽度 720px,7 个新字段正确渲染
|
||||||
|
4. 新增模式下不显示包间总数/空闲包间数
|
||||||
|
5. 点击编辑门店,所有新字段正确回填,包间字段只读展示
|
||||||
|
6. 提交表单无报错
|
||||||
|
|
||||||
|
验证完毕后按 `Ctrl+C` 停止开发服务器。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Checklist
|
||||||
|
|
||||||
|
- [ ] `pnpm --filter admin-ui type-check` 通过
|
||||||
|
- [ ] `pnpm --filter admin-ui lint` 通过
|
||||||
|
- [ ] `pnpm --filter admin-ui build` 成功
|
||||||
|
- [ ] 列表新增 3 列正确展示(门店类型 Tag、包间 X/Y、设施多 Tag)
|
||||||
|
- [ ] 门店类型筛选功能正常(筛选 + 重置)
|
||||||
|
- [ ] 新增门店:7 个新字段可正常填写和提交
|
||||||
|
- [ ] 编辑门店:所有新字段正确回填,只读字段不可编辑
|
||||||
|
- [ ] amenities 数据双向转换正确(JSON 字符串 ↔ 数组)
|
||||||
|
- [ ] serviceFeeRate 数据双向转换正确(小数 ↔ 百分比)
|
||||||
|
- [ ] 新增模式下 roomCount/freeRoomCount 区域不显示
|
||||||
|
- [ ] 无数据时各列正确降级显示 `-`
|
||||||
@@ -0,0 +1,758 @@
|
|||||||
|
# API Portal — 睿核科技 API 文档门户 设计文档
|
||||||
|
|
||||||
|
> 日期:2026-06-08
|
||||||
|
> 状态:待审核
|
||||||
|
> 作者:AI + 张晟
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、项目概述
|
||||||
|
|
||||||
|
### 1.1 项目名称
|
||||||
|
|
||||||
|
- **前端项目**:`api-portal`(睿核科技 API 文档门户)
|
||||||
|
- **后端服务**:`rui-service-apidoc`(API 文档管理微服务)
|
||||||
|
|
||||||
|
### 1.2 核心目标
|
||||||
|
|
||||||
|
构建一个**精美的 API 文档门户系统**,具备以下能力:
|
||||||
|
|
||||||
|
1. **多源 API 文档聚合** — 自动同步微服务 OpenAPI JSON + 手动导入
|
||||||
|
2. **自定义多级菜单** — 3 级菜单树,自由组织,不受 Controller 结构限制
|
||||||
|
3. **文档补全增强** — 管理后台补充中文说明、示例、注意事项
|
||||||
|
4. **精美文档展示** — VitePress 风格三栏布局,代码高亮
|
||||||
|
5. **AI 结构化接口** — 提供完整 API 信息供 AI 读取、代码生成、变更感知
|
||||||
|
6. **多项目管理** — 可自由创建项目,每个项目独立菜单和文档
|
||||||
|
|
||||||
|
### 1.3 用户角色
|
||||||
|
|
||||||
|
| 角色 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 匿名访客 | 浏览公开项目的 API 文档 |
|
||||||
|
| 开发者 | 浏览 + 搜索 + 测试 API |
|
||||||
|
| 管理员 | 管理项目、菜单、同步 API、补全文档 |
|
||||||
|
| AI Agent | 通过专用接口读取结构化 API 数据 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、系统架构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 整体架构 │
|
||||||
|
├──────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ 微服务集群 │
|
||||||
|
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
|
||||||
|
│ │ rui-user │ │rui-system │ │rui-cashier│ │rui-payment│ │
|
||||||
|
│ │/v3/api- │ │/v3/api- │ │/v3/api- │ │/v3/api- │ │
|
||||||
|
│ │ docs │ │ docs │ │ docs │ │ docs │ │
|
||||||
|
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ ▼ ▼ ▼ ▼ │
|
||||||
|
│ ┌──────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ rui-service-apidoc(独立微服务) │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 同步引擎 文档管理 AI 接口 │ │
|
||||||
|
│ │ - 定时拉取 - 菜单 CRUD - 结构化查询 │ │
|
||||||
|
│ │ - 手动触发 - 文档补全 - 变更检测 │ │
|
||||||
|
│ │ - JSON 导入 - 版本管理 - 代码生成数据 │ │
|
||||||
|
│ └──────────┬───────────────────┬───────────────────────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ┌────────▼────────┐ ┌──────▼──────────┐ │
|
||||||
|
│ │ admin-ui │ │ api-portal │ │
|
||||||
|
│ │ (管理后台) │ │ (文档门户) │ │
|
||||||
|
│ │ 补全信息/管理菜单 │ │ 精美展示/公开 │ │
|
||||||
|
│ └─────────────────┘ └─────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌────────────────────────────────────────┐ │
|
||||||
|
│ │ AI Agent (Codex 等) │ │
|
||||||
|
│ │ 通过 /ai/* 接口读取结构化 API 数据 │ │
|
||||||
|
│ └────────────────────────────────────────┘ │
|
||||||
|
└──────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、后端设计 — rui-apidoc
|
||||||
|
|
||||||
|
### 3.1 技术栈
|
||||||
|
|
||||||
|
| 项目 | 选型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 语言 | Java 21 | 和框架一致 |
|
||||||
|
| 框架 | Spring Boot 3 + Spring Cloud | 和框架一致 |
|
||||||
|
| 数据库 | MySQL 8 | 和框架一致 |
|
||||||
|
| ORM | MyBatis-Plus | 继承 BaseEntity |
|
||||||
|
| API 文档 | SpringDoc (OpenAPI 3) | 和框架一致 |
|
||||||
|
| 注册中心 | Nacos | 复用现有 |
|
||||||
|
| 包管理 | Maven | parent: rui-parent |
|
||||||
|
|
||||||
|
### 3.2 模块结构
|
||||||
|
|
||||||
|
遵循 `业务应用模块创建规则`,作为 `app/` 下的独立业务模块:
|
||||||
|
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
└── rui-apidoc/
|
||||||
|
├── pom.xml # parent: rui-app
|
||||||
|
├── rui-apidoc-api/ # [可部署] REST API + 启动类
|
||||||
|
│ └── src/main/java/com/rui/apidoc/api/
|
||||||
|
│ ├── ApidocApplication.java
|
||||||
|
│ └── controller/
|
||||||
|
│ ├── PortalController.java # 文档门户 API(公开)
|
||||||
|
│ ├── ApidocController.java # 管理后台 API(需认证)
|
||||||
|
│ └── AiController.java # AI 专用 API
|
||||||
|
├── rui-apidoc-common/ # [库] DTO、VO、枚举
|
||||||
|
│ └── src/main/java/com/rui/apidoc/
|
||||||
|
│ ├── dto/
|
||||||
|
│ ├── vo/
|
||||||
|
│ └── enums/
|
||||||
|
├── rui-apidoc-core/ # [库] Entity、Mapper、Service
|
||||||
|
│ └── src/main/java/com/rui/apidoc/core/
|
||||||
|
│ ├── entity/
|
||||||
|
│ ├── mapper/
|
||||||
|
│ ├── service/
|
||||||
|
│ └── config/
|
||||||
|
└── rui-apidoc-task/ # [库] 定时同步任务
|
||||||
|
└── src/main/java/com/rui/apidoc/task/
|
||||||
|
└── SyncTask.java
|
||||||
|
```
|
||||||
|
|
||||||
|
**POM 层级**:
|
||||||
|
```
|
||||||
|
app/pom.xml (rui-app)
|
||||||
|
└── rui-apidoc/pom.xml (parent: rui-app)
|
||||||
|
├── rui-apidoc-api → parent: rui-apidoc
|
||||||
|
├── rui-apidoc-common
|
||||||
|
├── rui-apidoc-core
|
||||||
|
└── rui-apidoc-task
|
||||||
|
```
|
||||||
|
|
||||||
|
**依赖关系**:
|
||||||
|
```
|
||||||
|
common → rui-common-core
|
||||||
|
core → rui-common-mybatis, rui-common-security, common
|
||||||
|
task → core, common
|
||||||
|
api → core, task, rui-common-security, rui-common-web
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 核心数据模型
|
||||||
|
|
||||||
|
> 所有实体继承 `BaseEntity`,自动包含 id, tenant_id, deleted, created_by, created_at, updated_by, updated_at 字段。
|
||||||
|
> 建表 SQL 只写业务字段,公共字段由 BaseEntity 规范统一。
|
||||||
|
|
||||||
|
#### 3.3.1 项目表 `apidoc_project`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE apidoc_project (
|
||||||
|
-- 业务字段
|
||||||
|
project_key VARCHAR(64) NOT NULL COMMENT '项目唯一标识,如 rui-framework',
|
||||||
|
name VARCHAR(128) NOT NULL COMMENT '项目名称',
|
||||||
|
description TEXT DEFAULT NULL COMMENT '项目描述',
|
||||||
|
visibility TINYINT NOT NULL DEFAULT 0 COMMENT '可见性 0=公开 1=需登录 2=仅管理员',
|
||||||
|
logo_url VARCHAR(512) DEFAULT NULL COMMENT '项目 Logo',
|
||||||
|
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序',
|
||||||
|
-- BaseEntity 公共字段
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID(雪花算法)',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除 0=正常 1=已删',
|
||||||
|
created_by BIGINT DEFAULT NULL COMMENT '创建者ID',
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
updated_by BIGINT DEFAULT NULL COMMENT '更新者ID',
|
||||||
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_project_key (project_key)
|
||||||
|
) COMMENT='API文档项目';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.2 微服务注册表 `apidoc_service`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE apidoc_service (
|
||||||
|
-- 业务字段
|
||||||
|
project_id BIGINT NOT NULL COMMENT '所属项目ID',
|
||||||
|
service_name VARCHAR(128) NOT NULL COMMENT '服务名,如 rui-service-user',
|
||||||
|
service_url VARCHAR(512) DEFAULT NULL COMMENT '服务地址,如 http://rui-service-user:8080',
|
||||||
|
sync_mode TINYINT NOT NULL DEFAULT 0 COMMENT '同步模式 0=自动同步(URL) 1=手动导入',
|
||||||
|
sync_status TINYINT NOT NULL DEFAULT 0 COMMENT '同步状态 0=未同步 1=同步中 2=成功 3=失败',
|
||||||
|
last_sync_at DATETIME DEFAULT NULL COMMENT '最后同步时间',
|
||||||
|
openapi_json MEDIUMTEXT DEFAULT NULL COMMENT '缓存的 OpenAPI JSON',
|
||||||
|
-- BaseEntity 公共字段
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID(雪花算法)',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_by BIGINT DEFAULT NULL,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_by BIGINT DEFAULT NULL,
|
||||||
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
INDEX idx_project (project_id)
|
||||||
|
) COMMENT='API文档微服务注册';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.3 多级菜单表 `apidoc_menu`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE apidoc_menu (
|
||||||
|
-- 业务字段
|
||||||
|
project_id BIGINT NOT NULL COMMENT '所属项目ID',
|
||||||
|
parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父级菜单ID,0=顶级',
|
||||||
|
name VARCHAR(128) NOT NULL COMMENT '菜单名称',
|
||||||
|
icon VARCHAR(64) DEFAULT NULL COMMENT '图标',
|
||||||
|
menu_type TINYINT NOT NULL DEFAULT 0 COMMENT '类型 0=目录 1=自定义内容页 2=接口组',
|
||||||
|
sort_order INT NOT NULL DEFAULT 0 COMMENT '同级排序',
|
||||||
|
service_id BIGINT DEFAULT NULL COMMENT '关联的微服务(menu_type=2时)',
|
||||||
|
endpoint_paths JSON DEFAULT NULL COMMENT '关联的API路径列表',
|
||||||
|
content MEDIUMTEXT DEFAULT NULL COMMENT 'Markdown自定义内容(menu_type=1时)',
|
||||||
|
-- BaseEntity 公共字段
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID(雪花算法)',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_by BIGINT DEFAULT NULL,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_by BIGINT DEFAULT NULL,
|
||||||
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
INDEX idx_project_parent (project_id, parent_id)
|
||||||
|
) COMMENT='API文档菜单';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.4 API 端点表 `apidoc_endpoint`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE apidoc_endpoint (
|
||||||
|
-- 业务字段
|
||||||
|
service_id BIGINT NOT NULL COMMENT '所属微服务ID',
|
||||||
|
menu_id BIGINT DEFAULT NULL COMMENT '关联菜单ID',
|
||||||
|
method VARCHAR(10) NOT NULL COMMENT 'HTTP方法 GET/POST/PUT/DELETE/PATCH',
|
||||||
|
path VARCHAR(512) NOT NULL COMMENT '接口路径',
|
||||||
|
summary VARCHAR(256) DEFAULT NULL COMMENT '接口摘要(来自OpenAPI)',
|
||||||
|
description TEXT DEFAULT NULL COMMENT '接口描述(来自OpenAPI)',
|
||||||
|
deprecated TINYINT NOT NULL DEFAULT 0 COMMENT '是否废弃',
|
||||||
|
tags JSON DEFAULT NULL COMMENT 'OpenAPI tags',
|
||||||
|
request_params JSON DEFAULT NULL COMMENT '查询参数 [{name,type,required,description}]',
|
||||||
|
request_body JSON DEFAULT NULL COMMENT '请求体 JSON Schema',
|
||||||
|
request_headers JSON DEFAULT NULL COMMENT '请求头',
|
||||||
|
path_params JSON DEFAULT NULL COMMENT '路径参数',
|
||||||
|
response_200 JSON DEFAULT NULL COMMENT '200 响应 JSON Schema',
|
||||||
|
response_error JSON DEFAULT NULL COMMENT '错误响应 Schema',
|
||||||
|
raw_openapi JSON DEFAULT NULL COMMENT '原始 OpenAPI operation 对象',
|
||||||
|
content_hash VARCHAR(64) DEFAULT NULL COMMENT '内容哈希,用于变更检测',
|
||||||
|
-- BaseEntity 公共字段
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID(雪花算法)',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_by BIGINT DEFAULT NULL,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_by BIGINT DEFAULT NULL,
|
||||||
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_service_method_path (service_id, method, path),
|
||||||
|
INDEX idx_service (service_id),
|
||||||
|
INDEX idx_menu (menu_id)
|
||||||
|
) COMMENT='API端点';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.5 文档补充表 `apidoc_extra`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE apidoc_extra (
|
||||||
|
-- 业务字段
|
||||||
|
endpoint_id BIGINT NOT NULL COMMENT '关联端点ID',
|
||||||
|
custom_title VARCHAR(256) DEFAULT NULL COMMENT '自定义标题(覆盖summary)',
|
||||||
|
custom_desc TEXT DEFAULT NULL COMMENT '自定义说明(中文描述)',
|
||||||
|
use_cases TEXT DEFAULT NULL COMMENT '使用场景说明',
|
||||||
|
notes TEXT DEFAULT NULL COMMENT '注意事项',
|
||||||
|
request_example JSON DEFAULT NULL COMMENT '请求示例',
|
||||||
|
response_example JSON DEFAULT NULL COMMENT '响应示例',
|
||||||
|
error_example JSON DEFAULT NULL COMMENT '错误响应示例',
|
||||||
|
test_cases JSON DEFAULT NULL COMMENT '测试用例 [{name,params,expected}]',
|
||||||
|
-- BaseEntity 公共字段
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID(雪花算法)',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_by BIGINT DEFAULT NULL,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_by BIGINT DEFAULT NULL,
|
||||||
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY uk_endpoint (endpoint_id)
|
||||||
|
) COMMENT='API文档补充信息';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.6 版本快照表 `apidoc_version`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE apidoc_version (
|
||||||
|
-- 业务字段
|
||||||
|
service_id BIGINT NOT NULL COMMENT '所属微服务ID',
|
||||||
|
version VARCHAR(32) NOT NULL COMMENT '版本号,如 v1.2.0',
|
||||||
|
openapi_json MEDIUMTEXT DEFAULT NULL COMMENT 'OpenAPI JSON 快照',
|
||||||
|
change_log TEXT DEFAULT NULL COMMENT '变更日志(Markdown)',
|
||||||
|
-- BaseEntity 公共字段
|
||||||
|
id BIGINT NOT NULL COMMENT '主键ID(雪花算法)',
|
||||||
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
|
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
created_by BIGINT DEFAULT NULL,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_by BIGINT DEFAULT NULL,
|
||||||
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
INDEX idx_service (service_id)
|
||||||
|
) COMMENT='API文档版本快照';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 核心 API 设计
|
||||||
|
|
||||||
|
> 所有接口统一使用 `Result<T>` 返回封装(error=0 成功,code 为业务编码,message 提示,data 业务数据)。
|
||||||
|
> Controller 路径遵循 `/{模块}/{功能}/{方法}` 规范。
|
||||||
|
|
||||||
|
#### 3.4.1 文档门户 API(公开,免认证)
|
||||||
|
|
||||||
|
| 方法 | 路径 | 返回类型 | 说明 |
|
||||||
|
|------|------|---------|------|
|
||||||
|
| GET | `/apidoc/portal/project/list` | `Result<List<ProjectVO>>` | 公开项目列表 |
|
||||||
|
| GET | `/apidoc/portal/project/{key}` | `Result<ProjectVO>` | 项目详情 |
|
||||||
|
| GET | `/apidoc/portal/project/{key}/menu` | `Result<List<MenuTreeVO>>` | 项目菜单树 |
|
||||||
|
| GET | `/apidoc/portal/project/{key}/menu/{menuId}` | `Result<MenuDetailVO>` | 菜单详情 |
|
||||||
|
| GET | `/apidoc/portal/endpoint/{id}` | `Result<EndpointDetailVO>` | 端点详情(含补充信息) |
|
||||||
|
| GET | `/apidoc/portal/search` | `Result<List<EndpointVO>>` | 全文搜索 |
|
||||||
|
|
||||||
|
#### 3.4.2 管理后台 API(需认证 + 管理员权限)
|
||||||
|
|
||||||
|
遵循 Controller 分类规范,管理接口使用 `ApidocController`:
|
||||||
|
|
||||||
|
| 方法 | 路径 | 返回类型 | 说明 |
|
||||||
|
|------|------|---------|------|
|
||||||
|
| POST | `/apidoc/admin/project` | `Result<Long>` | 创建项目 |
|
||||||
|
| PUT | `/apidoc/admin/project/{id}` | `Result<Void>` | 更新项目 |
|
||||||
|
| DELETE | `/apidoc/admin/project/{id}` | `Result<Void>` | 删除项目 |
|
||||||
|
| POST | `/apidoc/admin/service` | `Result<Long>` | 注册微服务 |
|
||||||
|
| POST | `/apidoc/admin/service/{id}/sync` | `Result<Void>` | 手动触发同步 |
|
||||||
|
| POST | `/apidoc/admin/service/{id}/import` | `Result<Void>` | 手动导入 OpenAPI JSON |
|
||||||
|
| POST | `/apidoc/admin/menu` | `Result<Long>` | 创建菜单 |
|
||||||
|
| PUT | `/apidoc/admin/menu/{id}` | `Result<Void>` | 更新菜单 |
|
||||||
|
| DELETE | `/apidoc/admin/menu/{id}` | `Result<Void>` | 删除菜单 |
|
||||||
|
| PUT | `/apidoc/admin/menu/sort` | `Result<Void>` | 批量排序 |
|
||||||
|
| POST | `/apidoc/admin/menu/{id}/bind` | `Result<Void>` | 菜单绑定 API 端点 |
|
||||||
|
| PUT | `/apidoc/admin/extra/{endpointId}` | `Result<Void>` | 更新补充信息 |
|
||||||
|
| POST | `/apidoc/admin/service/{id}/snapshot` | `Result<Void>` | 创建版本快照 |
|
||||||
|
|
||||||
|
#### 3.4.3 AI 专用 API
|
||||||
|
|
||||||
|
| 方法 | 路径 | 返回类型 | 说明 |
|
||||||
|
|------|------|---------|------|
|
||||||
|
| GET | `/apidoc/ai/projects` | `Result<List<AiProjectVO>>` | 所有项目(含服务概况) |
|
||||||
|
| GET | `/apidoc/ai/project/{key}/endpoints` | `Result<List<AiEndpointVO>>` | 项目全部端点(完整结构化) |
|
||||||
|
| GET | `/apidoc/ai/endpoint/{id}` | `Result<AiEndpointDetailVO>` | 单个端点完整信息 |
|
||||||
|
| GET | `/apidoc/ai/endpoint/search` | `Result<List<AiEndpointVO>>` | 搜索端点(keyword/method/path) |
|
||||||
|
| GET | `/apidoc/ai/project/{key}/changes` | `Result<List<ApiChangeVO>>` | API 变更(增量,since参数) |
|
||||||
|
| POST | `/apidoc/ai/query` | `Result<List<AiEndpointVO>>` | AI 自然语言查询 |
|
||||||
|
|
||||||
|
**AI 接口返回示例(`GET /apidoc/ai/endpoint/{id}`)**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": 0,
|
||||||
|
"code": null,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"id": 1001,
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/v1/user/users",
|
||||||
|
"summary": "创建用户",
|
||||||
|
"description": "管理员创建新用户,需要管理员权限",
|
||||||
|
"deprecated": false,
|
||||||
|
"tags": ["用户管理"],
|
||||||
|
"auth": "需要 Bearer Token,角色:ADMIN",
|
||||||
|
"requestParams": [],
|
||||||
|
"pathParams": [],
|
||||||
|
"requestHeaders": [
|
||||||
|
{ "name": "Authorization", "required": true, "description": "Bearer Token" },
|
||||||
|
{ "name": "Content-Type", "required": true, "value": "application/json" }
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["username", "password", "phone"],
|
||||||
|
"properties": {
|
||||||
|
"username": { "type": "string", "description": "用户名,4-20位字母数字", "example": "zhangsan" },
|
||||||
|
"password": { "type": "string", "description": "密码,8-32位", "example": "Pass@123" },
|
||||||
|
"phone": { "type": "string", "description": "手机号", "example": "13800138000" },
|
||||||
|
"email": { "type": "string", "description": "邮箱(可选)", "example": "zhangsan@example.com" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response200": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"error": { "type": "integer", "description": "0=成功", "example": 0 },
|
||||||
|
"code": { "type": "string", "example": "SUCCESS" },
|
||||||
|
"message": { "type": "string", "example": "操作成功" },
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": { "type": "integer", "description": "用户ID", "example": 1001 },
|
||||||
|
"username": { "type": "string", "example": "zhangsan" },
|
||||||
|
"created_at": { "type": "string", "format": "date-time" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responseError": {
|
||||||
|
"400": { "error": 400, "code": "PARAM_INVALID", "message": "参数校验失败" },
|
||||||
|
"401": { "error": 401, "code": "UNAUTHORIZED", "message": "未登录" },
|
||||||
|
"403": { "error": 403, "code": "FORBIDDEN", "message": "无权限" }
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"customTitle": "创建新用户",
|
||||||
|
"customDesc": "管理员通过此接口创建新用户,创建后用户处于启用状态",
|
||||||
|
"useCases": "后台管理 > 用户管理 > 新增用户",
|
||||||
|
"notes": "用户名唯一,不可重复。密码需满足复杂度要求。",
|
||||||
|
"requestExample": { "username": "zhangsan", "password": "Pass@123", "phone": "13800138000" },
|
||||||
|
"responseExample": { "error": 0, "code": null, "message": "操作成功", "data": { "id": 1001, "username": "zhangsan" } },
|
||||||
|
"testCases": [
|
||||||
|
{
|
||||||
|
"name": "正常创建",
|
||||||
|
"params": { "username": "testuser01", "password": "Pass@123", "phone": "13900139001" },
|
||||||
|
"expected": { "error": 0 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "用户名重复",
|
||||||
|
"params": { "username": "admin", "password": "Pass@123", "phone": "13900139002" },
|
||||||
|
"expected": { "error": 400, "code": "USER_EXISTS" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"service": { "name": "rui-service-user", "project": "rui-framework" },
|
||||||
|
"updatedAt": "2026-06-08T10:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.5 同步引擎设计
|
||||||
|
|
||||||
|
```
|
||||||
|
自动同步流程:
|
||||||
|
1. rui-apidoc-task 中的定时任务(可配置周期) 或 手动触发
|
||||||
|
2. 遍历 apidoc_service 中 sync_mode=0 且 sync_status!=1 的服务
|
||||||
|
3. HTTP 请求 {service_url}/v3/api-docs 获取 OpenAPI JSON
|
||||||
|
4. 使用 JsonUtil 解析 JSON,提取所有 Path + Operation
|
||||||
|
5. 计算每个 Operation 的 content_hash,与 apidoc_endpoint 现有数据对比
|
||||||
|
6. 新增/更新/标记废弃 端点,记录变更
|
||||||
|
7. 更新 sync_status=2, last_sync_at, openapi_json
|
||||||
|
|
||||||
|
手动导入流程:
|
||||||
|
1. 管理员在管理后台粘贴 OpenAPI JSON 或上传文件
|
||||||
|
2. 同上解析入库逻辑,sync_mode=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.6 启动类
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.rui.apidoc.api;
|
||||||
|
|
||||||
|
import com.rui.common.security.annotation.EnableResourceServer;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableResourceServer
|
||||||
|
public class ApidocApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ApidocApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.7 Nacos 白名单配置
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
oauth2:
|
||||||
|
ignore-urls:
|
||||||
|
- /apidoc/portal/**
|
||||||
|
- /apidoc/ai/**
|
||||||
|
```
|
||||||
|
|
||||||
|
> `/apidoc/portal/**` 和 `/apidoc/ai/**` 免认证公开访问。
|
||||||
|
> `/apidoc/admin/**` 需管理员权限。
|
||||||
|
## 四、前端设计 — api-portal
|
||||||
|
|
||||||
|
### 4.1 技术栈
|
||||||
|
|
||||||
|
| 项目 | 选型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 框架 | Vue 3 + TypeScript | 组合式 API (setup),和 admin-ui 一致 |
|
||||||
|
| 构建 | Vite 6 | 和 admin-ui 一致 |
|
||||||
|
| 样式 | UnoCSS | 原子化 CSS,和 admin-ui 一致 |
|
||||||
|
| 路由 | Vue Router 4 | 侧边栏联动 |
|
||||||
|
| HTTP | Axios | 统一封装 request,复用 admin-ui 模式 |
|
||||||
|
| 代码高亮 | Shiki | 和 VitePress 同款高亮引擎 |
|
||||||
|
| Markdown 渲染 | markdown-it + 自定义插件 | 自定义内容页 |
|
||||||
|
| 图标 | @iconify-json/carbon | 专业文档风格 |
|
||||||
|
|
||||||
|
> api-portal 是独立项目(不依赖 Element Plus),UI 全部基于 UnoCSS 原子化样式构建。
|
||||||
|
|
||||||
|
### 4.2 页面结构
|
||||||
|
|
||||||
|
#### 三栏布局(接口文档页)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 🏠 Rui API Portal 🔍 搜索接口... 🌙 主题 🌐 中文 │
|
||||||
|
├────────────┬──────────────────────────────────┬─────────────────┤
|
||||||
|
│ │ │ │
|
||||||
|
│ 📖 快速开始 │ POST /v1/user/users │ 请求示例 │
|
||||||
|
│ │ ━━━━━━━━━━━━━━━━━━━━ │ │
|
||||||
|
│ ▸ 用户管理 │ 创建新用户 │ curl -X POST \ │
|
||||||
|
│ 登录 │ │ /v1/user/users \│
|
||||||
|
│ 注册 │ 管理员通过此接口创建新用户,创建 │ -H 'Auth...' \ │
|
||||||
|
│ 用户列表 │ 后用户处于启用状态。 │ -d '{...}' │
|
||||||
|
│ 用户详情 │ │ │
|
||||||
|
│ 创建用户 │ ⚡ 需要管理员权限 │─────────────────│
|
||||||
|
│ 更新用户 │ 🔒 Bearer Token │ 响应示例 │
|
||||||
|
│ ▸ 订单管理 │ │ │
|
||||||
|
│ 创建订单 │ 请求参数 │ 200 OK │
|
||||||
|
│ 查询订单 │ ┌──────┬──────┬────┬────┐ │ { │
|
||||||
|
│ 取消订单 │ │ 参数 │ 类型 │必填│说明 │ │ "error":0, │
|
||||||
|
│ ▸ 支付 │ ├──────┼──────┼────┼────┤ │ "data":{...}│
|
||||||
|
│ 发起支付 │ │username│string│ ✓ │用户名│ │ } │
|
||||||
|
│ 支付回调 │ │password│string│ ✓ │密码 │ │ │
|
||||||
|
│ 退款 │ └──────┴──────┴────┴────┘ │─────────────────│
|
||||||
|
│ │ │ 测试用例 │
|
||||||
|
│ │ 响应参数 │ ✅ 正常创建 │
|
||||||
|
│ │ ┌──────┬──────┬────┐ │ ❌ 用户名重复 │
|
||||||
|
│ │ │ 字段 │ 类型 │说明 │ │ │
|
||||||
|
│ │ ├──────┼──────┼────┤ │ │
|
||||||
|
│ │ │ id │ long │用户ID│ │ │
|
||||||
|
│ │ └──────┴──────┴────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
└────────────┴──────────────────────────────────┴─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 项目首页
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 🏠 Rui API Portal 🔍 搜索接口... 🌙 主题 🌐 中文 │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ 睿核科技 API 文档中心 │
|
||||||
|
│ 探索、测试、集成我们的 API 服务 │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────────────────────────┐ │
|
||||||
|
│ │ 🔍 搜索所有 API 接口... │ │
|
||||||
|
│ └──────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||||
|
│ │ 📦 rui-frame │ │ 📦 rui-cashier│ │ 📦 rui-payment│ │
|
||||||
|
│ │ work │ │ │ │ │ │
|
||||||
|
│ │ 基础平台框架 │ │ 收银系统 │ │ 支付系统 │ │
|
||||||
|
│ │ 128 接口 │ │ 56 接口 │ │ 32 接口 │ │
|
||||||
|
│ │ 5 模块 │ │ 3 模块 │ │ 2 模块 │ │
|
||||||
|
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 路由设计
|
||||||
|
|
||||||
|
```
|
||||||
|
/ → 项目首页(项目卡片列表)
|
||||||
|
/:projectKey → 项目页(菜单 + 欢迎页)
|
||||||
|
/:projectKey/menu/:menuId → 菜单页(自定义内容 / 接口组)
|
||||||
|
/:projectKey/endpoint/:id → 单个接口详情页
|
||||||
|
/search?keyword=&projectId= → 搜索结果页
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 核心功能
|
||||||
|
|
||||||
|
| 功能 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 多级菜单导航 | 3 级可折叠侧边栏,图标 + 名称 |
|
||||||
|
| 接口文档渲染 | 方法/路径/参数/响应/示例,结构化表格展示 |
|
||||||
|
| 代码高亮 | 请求示例(curl/JS/Java)、响应示例 JSON |
|
||||||
|
| Markdown 自定义页 | 菜单项关联自定义 Markdown 内容(快速开始、认证说明等) |
|
||||||
|
| 全文搜索 | 搜索接口名、路径、描述、参数名 |
|
||||||
|
| 深色模式 | 主题切换 |
|
||||||
|
| 响应式 | 移动端适配(侧边栏折叠) |
|
||||||
|
| "试一试" | 简易 API 测试面板(填参数发请求) |
|
||||||
|
|
||||||
|
### 4.5 项目结构
|
||||||
|
|
||||||
|
> 遵循 admin-ui 的目录约定:service 层使用 BaseService 模式,composables 存放组合式函数,views 存放页面。
|
||||||
|
|
||||||
|
```
|
||||||
|
api-portal/
|
||||||
|
├── package.json
|
||||||
|
├── vite.config.ts
|
||||||
|
├── uno.config.ts
|
||||||
|
├── tsconfig.json
|
||||||
|
├── index.html
|
||||||
|
├── public/
|
||||||
|
│ └── favicon.svg
|
||||||
|
├── src/
|
||||||
|
│ ├── main.ts
|
||||||
|
│ ├── App.vue
|
||||||
|
│ ├── service/ # API 请求封装(和 admin-ui 一致)
|
||||||
|
│ │ ├── BaseService.ts # 通用 CRUD 基类(复用 admin-ui 模式)
|
||||||
|
│ │ ├── portalService.ts # 文档门户接口
|
||||||
|
│ │ └── types.ts # TypeScript 类型定义
|
||||||
|
│ ├── composables/ # 组合式函数
|
||||||
|
│ │ ├── useTheme.ts # 主题切换
|
||||||
|
│ │ ├── useMenu.ts # 菜单状态
|
||||||
|
│ │ └── useSearch.ts # 搜索
|
||||||
|
│ ├── components/
|
||||||
|
│ │ ├── layout/
|
||||||
|
│ │ │ ├── AppHeader.vue # 顶部导航
|
||||||
|
│ │ │ ├── AppSidebar.vue # 侧边栏
|
||||||
|
│ │ │ ├── AppFooter.vue # 底部
|
||||||
|
│ │ │ └── ThreeColumn.vue # 三栏布局容器
|
||||||
|
│ │ ├── endpoint/
|
||||||
|
│ │ │ ├── EndpointHeader.vue # 方法 + 路径 + 标签
|
||||||
|
│ │ │ ├── ParamsTable.vue # 参数表格
|
||||||
|
│ │ │ ├── ResponseSchema.vue # 响应结构
|
||||||
|
│ │ │ ├── CodeBlock.vue # 代码块(Shiki 高亮)
|
||||||
|
│ │ │ └── TryIt.vue # "试一试"面板
|
||||||
|
│ │ ├── markdown/
|
||||||
|
│ │ │ └── MarkdownRenderer.vue # Markdown 渲染
|
||||||
|
│ │ └── search/
|
||||||
|
│ │ └── SearchDialog.vue # 搜索弹窗
|
||||||
|
│ ├── views/ # 页面(和 admin-ui 命名一致)
|
||||||
|
│ │ ├── HomePage.vue # 首页
|
||||||
|
│ │ ├── ProjectPage.vue # 项目页
|
||||||
|
│ │ ├── MenuPage.vue # 菜单内容页
|
||||||
|
│ │ ├── EndpointPage.vue # 接口详情页
|
||||||
|
│ │ └── SearchPage.vue # 搜索结果页
|
||||||
|
│ ├── router/
|
||||||
|
│ │ └── index.ts
|
||||||
|
│ ├── stores/ # Pinia 状态管理
|
||||||
|
│ │ └── project.ts # 项目状态
|
||||||
|
│ ├── styles/
|
||||||
|
│ │ ├── variables.css # CSS 变量(主题色)
|
||||||
|
│ │ └── prose.css # 文档内容样式
|
||||||
|
│ └── utils/
|
||||||
|
│ ├── request.ts # Axios 封装(复用 admin-ui 模式,baseURL 指向 apidoc 服务)
|
||||||
|
│ └── format.ts # 格式化工具
|
||||||
|
└── env.d.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.6 request.ts 设计
|
||||||
|
|
||||||
|
> 复用 admin-ui 的 request 封装模式,但 api-portal 是公开文档站,不需要 Token/租户拦截。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/utils/request.ts
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
const request = axios.create({
|
||||||
|
baseURL: '/api', // 通过网关转发到 rui-apidoc
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 响应拦截 — 复用 Result<T> 的 error 判断逻辑
|
||||||
|
request.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
const { data } = response
|
||||||
|
if (data.error !== 0) {
|
||||||
|
console.error(data.message || '请求失败')
|
||||||
|
return Promise.reject(data)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error('网络错误', error.message)
|
||||||
|
return Promise.reject(error)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export { request }
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.7 service 层设计
|
||||||
|
|
||||||
|
> 遵循 admin-ui 的 BaseService 模式,但 api-portal 以只读查询为主。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/service/portalService.ts
|
||||||
|
import { request } from '@/utils/request'
|
||||||
|
|
||||||
|
/** 获取公开项目列表 */
|
||||||
|
export function getProjectList() {
|
||||||
|
return request({ url: '/apidoc/portal/project/list', method: 'get' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取项目详情 */
|
||||||
|
export function getProject(key: string) {
|
||||||
|
return request({ url: `/apidoc/portal/project/${key}`, method: 'get' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取项目菜单树 */
|
||||||
|
export function getMenuTree(key: string) {
|
||||||
|
return request({ url: `/apidoc/portal/project/${key}/menu`, method: 'get' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取菜单详情 */
|
||||||
|
export function getMenuDetail(key: string, menuId: string) {
|
||||||
|
return request({ url: `/apidoc/portal/project/${key}/menu/${menuId}`, method: 'get' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取端点详情 */
|
||||||
|
export function getEndpoint(id: string) {
|
||||||
|
return request({ url: `/apidoc/portal/endpoint/${id}`, method: 'get' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索 */
|
||||||
|
export function searchEndpoints(keyword: string, projectId?: string) {
|
||||||
|
return request({ url: '/apidoc/portal/search', method: 'get', params: { keyword, projectId } })
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## 五、部署架构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────┐
|
||||||
|
│ Nginx / Gateway │
|
||||||
|
│ ├─ / → api-portal 静态资源 │
|
||||||
|
│ ├─ /admin → admin-ui 静态资源 │
|
||||||
|
│ └─ /api/apidoc/* → rui-service-apidoc │
|
||||||
|
└──────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
api-portal 构建产物部署为静态资源,通过 Nginx 或 CDN 分发。
|
||||||
|
rui-service-apidoc 注册到 Nacos,通过 Gateway 路由。
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、开发优先级
|
||||||
|
|
||||||
|
### Phase 1:MVP(最小可用)
|
||||||
|
|
||||||
|
1. 后端:项目/菜单/端点 CRUD + OpenAPI JSON 手动导入
|
||||||
|
2. 前端:三栏布局 + 菜单导航 + 接口文档渲染
|
||||||
|
|
||||||
|
### Phase 2:增强
|
||||||
|
|
||||||
|
3. 后端:自动同步引擎(定时拉取 /v3/api-docs)
|
||||||
|
4. 后端:文档补全管理
|
||||||
|
5. 前端:搜索 + 深色模式
|
||||||
|
|
||||||
|
### Phase 3:AI + 高级功能
|
||||||
|
|
||||||
|
6. 后端:AI 专用结构化接口
|
||||||
|
7. 后端:API 变更检测 + 版本管理
|
||||||
|
8. 前端:"试一试" API 测试面板
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、参考风格
|
||||||
|
|
||||||
|
| 参考站点 | 地址 | 借鉴点 |
|
||||||
|
|---------|------|--------|
|
||||||
|
| VitePress | https://vitepress.dev | 整体风格、三栏布局、深色模式 |
|
||||||
|
| Nuxt UI Pro | https://ui.nuxt.com/pro | 文档模板、导航设计 |
|
||||||
|
| Stripe API | https://stripe.com/docs/api | 代码示例、交互体验 |
|
||||||
|
| Scalar | https://scalar.com | 现代 API 文档 UI |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本文档仅涵盖设计,不涉及具体实现代码。实施前需团队审核确认。
|
||||||
@@ -0,0 +1,393 @@
|
|||||||
|
# 门店管理新增字段设计规范
|
||||||
|
|
||||||
|
**工单**: rui/rui-frontend#6 — 门店管理适配后端新增字段
|
||||||
|
**日期**: 2026-06-08
|
||||||
|
**关联 Issue**: rui/rui-cashier#6(后端门店表新增字段)
|
||||||
|
**优先级**: P2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 目标(Goal)
|
||||||
|
|
||||||
|
在 admin-ui 门店管理模块的列表页和表单弹窗中,适配后端门店表新增的 9 个字段(storeType、amenities、longitude、latitude、roomCount、freeRoomCount、serviceFeeRate、openingDate、legalPerson)。表单弹窗新增 7 个可编辑字段和 2 个只读展示字段,列表页新增 3 列(门店类型标签、包间信息、设施标签)和 1 个筛选条件(门店类型下拉)。所有变更在现有 `useApiForm` + `ApiFormDialog` + `RuiTable` 框架内完成,不引入新依赖。
|
||||||
|
|
||||||
|
## 2. 非目标(Non-Goals)
|
||||||
|
|
||||||
|
明确不在本期范围内的事项:
|
||||||
|
|
||||||
|
- **不修改后端代码或 API 接口定义**:后端已提供字段,前端仅适配展示和交互。
|
||||||
|
- **不做地图组件集成**:经纬度字段使用纯数字输入框,不嵌入高德/百度地图选点组件。
|
||||||
|
- **不修改 storeService.ts**:现有 BaseService 的 CRUD 方法已覆盖需求,无需扩展。
|
||||||
|
- **不新增独立详情页**:沿用当前「列表 + 表单弹窗」模式,只读字段在编辑弹窗中展示。
|
||||||
|
- **不做包间数量编辑**:roomCount 和 freeRoomCount 由后端计算,前端仅只读展示。
|
||||||
|
- **不引入新 npm 依赖**:所有 UI 组件使用现有 Element Plus + useApiForm 字段类型体系。
|
||||||
|
|
||||||
|
## 3. 背景与上下文(Context)
|
||||||
|
|
||||||
|
### 3.1 现有门店模块结构
|
||||||
|
|
||||||
|
- **列表页** `admin-ui/src/views/cashier/store/Index.vue`:使用 `RuiTable` 组件,现有 7 列(门店名称、门店编码、联系人、联系电话、地址、营业时间、状态),2 个筛选条件(门店名称、状态),支持增删改查和状态切换。
|
||||||
|
- **表单弹窗** `admin-ui/src/views/cashier/store/StoreFormDialog.vue`:使用 `useApiForm` composable + `ApiFormDialog` 组件,现有 7 个字段(storeName、storeCode、address、contactName、contactPhone、businessHours、status),通过 `v-model:visible` / `row` prop 控制显示和数据回填。
|
||||||
|
- **服务层** `admin-ui/src/service/cashier/storeService.ts`:继承 `BaseService('/cashier/admin/store')`,13 行代码,自动拥有 page/add/update/remove/changeStatus 能力。
|
||||||
|
|
||||||
|
### 3.2 useApiForm 字段类型支持
|
||||||
|
|
||||||
|
`useApiForm` 支持 9 种字段类型:`input`、`textarea`、`select`、`radio`、`checkbox`、`number`、`tree-select`、`date`、`datetime`。每个字段支持 `disabled` 属性(布尔值或返回布尔值的函数),可用于按编辑/新增模式动态禁用。
|
||||||
|
|
||||||
|
`ApiFormDialog` 在所有标准字段之后渲染 `<slot name="custom-fields" :form="formData" />`,用于放置无法用标准字段类型表达的 UI 内容。
|
||||||
|
|
||||||
|
### 3.3 后端新增字段一览
|
||||||
|
|
||||||
|
| 字段 | camelCase 键 | Java 类型 | 后端存储格式 |
|
||||||
|
|------|-------------|----------|-------------|
|
||||||
|
| 门店类型 | storeType | String | 纯字符串:`FLAGSHIP` / `STANDARD` / `COMMUNITY` |
|
||||||
|
| 设施标签 | amenities | String | JSON 数组字符串:`"[\"免费停车\",\"免费WiFi\"]"` |
|
||||||
|
| 经度 | longitude | BigDecimal | 小数 |
|
||||||
|
| 纬度 | latitude | BigDecimal | 小数 |
|
||||||
|
| 包间总数 | roomCount | Integer | 整数(后端计算) |
|
||||||
|
| 空闲包间数 | freeRoomCount | Integer | 整数(后端计算) |
|
||||||
|
| 平台服务费率 | serviceFeeRate | BigDecimal | 小数,如 `0.05` 表示 5% |
|
||||||
|
| 开业日期 | openingDate | LocalDate | `yyyy-MM-dd` 字符串 |
|
||||||
|
| 法人姓名 | legalPerson | String | 纯文本 |
|
||||||
|
|
||||||
|
## 4. 关键设计决策
|
||||||
|
|
||||||
|
| # | 决策项 | 选定方案 | 理由 |
|
||||||
|
|---|--------|---------|------|
|
||||||
|
| 1 | 整体方案 | 在现有 useApiForm + ApiFormDialog 框架内扩展 | 复用现有基础设施,保持与其他模块一致的开发模式 |
|
||||||
|
| 2 | amenities 表现层 | 使用 `checkbox` 字段类型,options 固定 6 项 | useApiForm 原生支持 checkbox,无需自定义渲染 |
|
||||||
|
| 3 | amenities 数据转换 | 提交时 `JSON.stringify`,编辑回填时 `JSON.parse` | 后端存 JSON 字符串,前端表单使用 `string[]` |
|
||||||
|
| 4 | serviceFeeRate 展示 | 前端用百分比数值(5 表示 5%),提交时除以 100,编辑回填时乘以 100 | 用户体验直观,避免手动输入 0.05 这样的小数 |
|
||||||
|
| 5 | roomCount / freeRoomCount | 使用 `#custom-fields` 插槽渲染只读文本 | 这两个字段仅编辑模式下只读展示,不需要 useApiForm 字段配置 |
|
||||||
|
| 6 | 门店类型枚举 | 前端硬编码 3 个选项 | 后端接口稳定,选项固定,无需动态加载 |
|
||||||
|
| 7 | 经纬度输入 | `number` 类型字段,精度限制 6 位小数 | 经纬度通常保留 6 位即可满足定位需求 |
|
||||||
|
|
||||||
|
## 5. 字段配置详情
|
||||||
|
|
||||||
|
### 5.1 useApiForm 字段新增(7 个可编辑字段)
|
||||||
|
|
||||||
|
以下字段追加到 `StoreFormDialog.vue` 中 `useApiForm` 的 `fields` 数组:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
key: 'storeType',
|
||||||
|
label: '门店类型',
|
||||||
|
type: 'select',
|
||||||
|
required: true,
|
||||||
|
options: [
|
||||||
|
{ label: '旗舰店', value: 'FLAGSHIP' },
|
||||||
|
{ label: '标准店', value: 'STANDARD' },
|
||||||
|
{ label: '社区店', value: 'COMMUNITY' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'amenities',
|
||||||
|
label: '设施标签',
|
||||||
|
type: 'checkbox',
|
||||||
|
options: [
|
||||||
|
{ label: '免费停车', value: '免费停车' },
|
||||||
|
{ label: '免费WiFi', value: '免费WiFi' },
|
||||||
|
{ label: '充电桩', value: '充电桩' },
|
||||||
|
{ label: '24小时营业', value: '24小时营业' },
|
||||||
|
{ label: '包厢', value: '包厢' },
|
||||||
|
{ label: '吸烟区', value: '吸烟区' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'longitude',
|
||||||
|
label: '经度',
|
||||||
|
type: 'number',
|
||||||
|
props: { min: -180, max: 180, precision: 6, step: 0.000001 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'latitude',
|
||||||
|
label: '纬度',
|
||||||
|
type: 'number',
|
||||||
|
props: { min: -90, max: 90, precision: 6, step: 0.000001 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'serviceFeeRate',
|
||||||
|
label: '平台服务费率(%)',
|
||||||
|
type: 'number',
|
||||||
|
props: { min: 0, max: 100, precision: 2, step: 0.01 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'openingDate',
|
||||||
|
label: '开业日期',
|
||||||
|
type: 'date',
|
||||||
|
props: { valueFormat: 'YYYY-MM-DD' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'legalPerson',
|
||||||
|
label: '法人姓名',
|
||||||
|
type: 'input',
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 弹窗宽度调整
|
||||||
|
|
||||||
|
`StoreFormDialog` 中 `ApiFormDialog` 追加 `width` prop 为 `720px`(原默认 600px),因为新增字段较多,需要更宽的弹窗空间。
|
||||||
|
|
||||||
|
### 5.3 只读展示字段(2 个,通过 custom-fields 插槽)
|
||||||
|
|
||||||
|
`roomCount` 和 `freeRoomCount` 不加入 `fields` 数组,而是在 `ApiFormDialog` 的 `#custom-fields` 插槽中以 `el-form-item` + 纯文本方式渲染。仅在编辑模式(`form.id` 存在)时显示:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template #custom-fields="{ form }">
|
||||||
|
<template v-if="form.id">
|
||||||
|
<el-form-item label="包间总数">
|
||||||
|
<span>{{ form.roomCount ?? '-' }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="空闲包间数">
|
||||||
|
<span>{{ form.freeRoomCount ?? '-' }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4 initial 默认值扩展
|
||||||
|
|
||||||
|
在 `useApiForm` 的 `initial` 对象中追加新字段默认值:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
initial: {
|
||||||
|
// ...现有字段
|
||||||
|
storeType: 'STANDARD',
|
||||||
|
amenities: [],
|
||||||
|
longitude: undefined,
|
||||||
|
latitude: undefined,
|
||||||
|
serviceFeeRate: undefined,
|
||||||
|
openingDate: '',
|
||||||
|
legalPerson: '',
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.5 数据转换逻辑
|
||||||
|
|
||||||
|
#### 提交时(`onSubmit` 回调内)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
onSubmit: async (rawData) => {
|
||||||
|
const data = { ...rawData }
|
||||||
|
|
||||||
|
// amenities: string[] → JSON 字符串
|
||||||
|
if (Array.isArray(data.amenities)) {
|
||||||
|
data.amenities = JSON.stringify(data.amenities)
|
||||||
|
}
|
||||||
|
|
||||||
|
// serviceFeeRate: 百分比 → 小数
|
||||||
|
if (data.serviceFeeRate != null && data.serviceFeeRate !== '') {
|
||||||
|
data.serviceFeeRate = Number(data.serviceFeeRate) / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...现有 add/update 逻辑
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 编辑回填时(`watch(visible)` 内)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
watch(() => props.visible, (val) => {
|
||||||
|
if (val && props.row) {
|
||||||
|
const rowData = { ...props.row }
|
||||||
|
|
||||||
|
// amenities: JSON 字符串 → string[]
|
||||||
|
if (typeof rowData.amenities === 'string' && rowData.amenities) {
|
||||||
|
try {
|
||||||
|
rowData.amenities = JSON.parse(rowData.amenities)
|
||||||
|
} catch {
|
||||||
|
rowData.amenities = []
|
||||||
|
}
|
||||||
|
} else if (!Array.isArray(rowData.amenities)) {
|
||||||
|
rowData.amenities = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// serviceFeeRate: 小数 → 百分比
|
||||||
|
if (rowData.serviceFeeRate != null) {
|
||||||
|
rowData.serviceFeeRate = Number(rowData.serviceFeeRate) * 100
|
||||||
|
}
|
||||||
|
|
||||||
|
form.value = rowData
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 列表页变更(Index.vue)
|
||||||
|
|
||||||
|
### 6.1 新增列配置
|
||||||
|
|
||||||
|
在 `columns` 数组中,`address` 列之后追加以下 3 列:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
prop: 'storeType',
|
||||||
|
label: '门店类型',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
slot: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'roomInfo',
|
||||||
|
label: '包间',
|
||||||
|
width: 120,
|
||||||
|
align: 'center',
|
||||||
|
slot: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'amenities',
|
||||||
|
label: '设施标签',
|
||||||
|
minWidth: 200,
|
||||||
|
slot: true,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 新增列 Slot 模板
|
||||||
|
|
||||||
|
#### 门店类型列(彩色 Tag)
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template #column-storeType="{ row }">
|
||||||
|
<el-tag
|
||||||
|
:type="row.storeType === 'FLAGSHIP' ? 'danger' : row.storeType === 'STANDARD' ? '' : 'info'"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{{ { FLAGSHIP: '旗舰店', STANDARD: '标准店', COMMUNITY: '社区店' }[row.storeType] || '-' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 包间信息列("空闲X/总数Y" 格式)
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template #column-roomInfo="{ row }">
|
||||||
|
<span>{{ row.freeRoomCount ?? '-' }}/{{ row.roomCount ?? '-' }}</span>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 设施标签列(多个小 Tag)
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template #column-amenities="{ row }">
|
||||||
|
<template v-if="parseAmenities(row.amenities).length">
|
||||||
|
<el-tag
|
||||||
|
v-for="tag in parseAmenities(row.amenities)"
|
||||||
|
:key="tag"
|
||||||
|
size="small"
|
||||||
|
type="info"
|
||||||
|
class="mr-1 mb-1"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
其中 `parseAmenities` 为组件内的工具函数:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function parseAmenities(val: any): string[] {
|
||||||
|
if (Array.isArray(val)) return val
|
||||||
|
if (typeof val === 'string' && val) {
|
||||||
|
try { return JSON.parse(val) } catch { return [] }
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 新增筛选条件
|
||||||
|
|
||||||
|
在 `queryParams` 中增加 `storeType` 字段,在查询区增加门店类型下拉:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const queryParams = ref({
|
||||||
|
storeName: '',
|
||||||
|
status: undefined as number | undefined,
|
||||||
|
storeType: undefined as string | undefined,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
查询区模板中,状态筛选后追加:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<el-form-item label="门店类型">
|
||||||
|
<el-select v-model="queryParams.storeType" placeholder="请选择门店类型" clearable>
|
||||||
|
<el-option label="旗舰店" value="FLAGSHIP" />
|
||||||
|
<el-option label="标准店" value="STANDARD" />
|
||||||
|
<el-option label="社区店" value="COMMUNITY" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
```
|
||||||
|
|
||||||
|
`handleReset` 方法中补充 `storeType: undefined` 重置。
|
||||||
|
|
||||||
|
## 7. 涉及文件清单(Files To Change)
|
||||||
|
|
||||||
|
| # | 文件 | 操作 | 变更说明 |
|
||||||
|
|---|------|------|---------|
|
||||||
|
| 1 | `admin-ui/src/views/cashier/store/StoreFormDialog.vue` | 修改 | 新增 7 个 useApiForm 字段、custom-fields 插槽渲染 roomCount/freeRoomCount、数据转换逻辑、弹窗宽度调整为 720px |
|
||||||
|
| 2 | `admin-ui/src/views/cashier/store/Index.vue` | 修改 | 新增 3 列配置(storeType/roomInfo/amenities)及对应 slot 模板、新增 storeType 筛选条件、queryParams 扩展、parseAmenities 工具函数、handleReset 补充 |
|
||||||
|
|
||||||
|
**变更统计**:修改 2 个文件。**不新建文件,不修改服务层和路由**。
|
||||||
|
|
||||||
|
## 8. 测试策略
|
||||||
|
|
||||||
|
### 8.1 静态检查
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm --filter admin-ui type-check # 0 errors
|
||||||
|
pnpm --filter admin-ui lint # 0 errors
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.2 功能验证(手动)
|
||||||
|
|
||||||
|
| # | 验证场景 | 预期结果 |
|
||||||
|
|---|---------|---------|
|
||||||
|
| 1 | 列表加载 | 新增 3 列正确展示:门店类型(Tag)、包间(X/Y 格式)、设施标签(多个小 Tag) |
|
||||||
|
| 2 | 门店类型筛选 | 下拉选择后点击查询,列表按类型过滤;重置后筛选条件清空 |
|
||||||
|
| 3 | 无数据的门店 | storeType 为空显示 `-`,amenities 为空显示 `-`,包间无数据显示 `-/--` |
|
||||||
|
| 4 | 新增门店 | 弹窗宽度 720px,7 个新字段正确渲染,roomCount/freeRoomCount 不显示(新增模式) |
|
||||||
|
| 5 | 新增提交 | amenities 提交为 JSON 字符串,serviceFeeRate 提交为小数(5→0.05) |
|
||||||
|
| 6 | 编辑门店 | 弹窗回填所有字段:amenities 从 JSON 字符串解析为勾选状态,serviceFeeRate 从小数转为百分比(0.05→5) |
|
||||||
|
| 7 | 编辑模式只读字段 | roomCount 和 freeRoomCount 以纯文本显示,不可编辑 |
|
||||||
|
| 8 | 新增模式无只读字段 | 新增门店时 roomCount 和 freeRoomCount 区域不显示 |
|
||||||
|
| 9 | 门店类型必填校验 | storeType 为空时提交,表单校验不通过 |
|
||||||
|
|
||||||
|
### 8.3 验证清单(提交前必过)
|
||||||
|
|
||||||
|
- [ ] `pnpm --filter admin-ui type-check` 通过
|
||||||
|
- [ ] `pnpm --filter admin-ui lint` 通过
|
||||||
|
- [ ] 列表新增 3 列正确展示
|
||||||
|
- [ ] 门店类型筛选功能正常
|
||||||
|
- [ ] 新增门店:7 个新字段可正常填写和提交
|
||||||
|
- [ ] 编辑门店:所有新字段正确回填,只读字段不可编辑
|
||||||
|
- [ ] amenities 数据双向转换正确(JSON 字符串 ↔ 数组)
|
||||||
|
- [ ] serviceFeeRate 数据双向转换正确(小数 ↔ 百分比)
|
||||||
|
|
||||||
|
## 9. 风险与缓解(Risks And Mitigations)
|
||||||
|
|
||||||
|
| # | 风险 | 缓解措施 |
|
||||||
|
|---|------|---------|
|
||||||
|
| 1 | **amenities JSON 解析失败**:后端返回格式异常或 null 时,前端 JSON.parse 抛错导致表单崩溃 | 在编辑回填时用 try-catch 包裹 JSON.parse,解析失败降级为空数组 `[]`。在列表 parseAmenities 工具函数中同样做防御性解析。 |
|
||||||
|
| 2 | **serviceFeeRate 精度问题**:BigDecimal 除以 100 或乘以 100 可能产生浮点精度误差 | 使用 `Number()` 转换后通过 `el-input-number` 的 `precision: 2` 限制小数位数,避免显示多余精度。后端使用 BigDecimal 不会丢失精度。 |
|
||||||
|
| 3 | **后端字段尚未部署**:前端先于后端部署时,新增列显示空值 | 列表和表单均对 undefined/null 做降级处理(显示 `-`),不影响现有功能。前端部署无阻断风险。 |
|
||||||
|
| 4 | **弹窗字段过多导致布局拥挤**:原有 7 个字段 + 新增 9 个字段共 16 个表单项 | 弹窗宽度从 600px 增至 720px;新增模式不显示 roomCount/freeRoomCount,实际展示 14 项。后续如仍拥挤可考虑分组或 tabs 布局。 |
|
||||||
|
|
||||||
|
## 10. 决策摘要(Decision Summary)
|
||||||
|
|
||||||
|
- **架构**:在现有 `useApiForm` + `ApiFormDialog` + `RuiTable` 框架内扩展,不新建文件、不引入新依赖。
|
||||||
|
- **amenities**:使用 `checkbox` 字段类型,options 固定 6 项。提交时 `JSON.stringify`,编辑回填时 `JSON.parse`,均做防御性处理。
|
||||||
|
- **serviceFeeRate**:前端以百分比输入/显示,提交时 `÷100`,回填时 `×100`。
|
||||||
|
- **roomCount / freeRoomCount**:通过 `#custom-fields` 插槽只读展示,仅在编辑模式显示。
|
||||||
|
- **storeType**:`select` 字段,3 个固定选项(FLAGSHIP/STANDARD/COMMUNITY),列表用彩色 Tag 展示,增加筛选条件。
|
||||||
|
- **longitude / latitude**:`number` 字段,精度 6 位小数,范围限制经度 [-180, 180]、纬度 [-90, 90]。
|
||||||
|
- **openingDate**:`date` 字段,valueFormat 为 `YYYY-MM-DD`。
|
||||||
|
- **legalPerson**:`input` 字段,无特殊处理。
|
||||||
|
- **列表新增**:3 列(门店类型 Tag、包间 X/Y、设施多 Tag)+ 1 个筛选条件。
|
||||||
|
- **弹窗宽度**:从默认 600px 增至 720px。
|
||||||
|
- **文件变更**:仅修改 2 个文件(StoreFormDialog.vue、Index.vue)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**设计评审状态**: 待评审
|
||||||
|
**下一步**: 用户评审通过后,编写实施计划(Plan)
|
||||||
Reference in New Issue
Block a user