Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
221454081c |
@@ -1,16 +0,0 @@
|
|||||||
.git
|
|
||||||
.gitea
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
**/.DS_Store
|
|
||||||
web/node_modules
|
|
||||||
web/dist
|
|
||||||
server/temp
|
|
||||||
server/logs
|
|
||||||
server/storage/cache
|
|
||||||
server/storage/diskqueue
|
|
||||||
server/resource/public/admin
|
|
||||||
docs
|
|
||||||
tools
|
|
||||||
*.docx
|
|
||||||
*.pdf
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
name: Deploy olons-admin production
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- pro
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: production-olons-admin
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: git.olns.shop
|
|
||||||
IMAGE: git.olns.shop/pro/olons_admin
|
|
||||||
SERVICE: olons-admin
|
|
||||||
DEPLOY_HOST: 145.223.69.9
|
|
||||||
DEPLOY_USER: olns-deploy
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: deploy-host
|
|
||||||
timeout-minutes: 60
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Log in to Gitea Container Registry
|
|
||||||
env:
|
|
||||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY" -u admin --password-stdin
|
|
||||||
|
|
||||||
- name: Build and push image
|
|
||||||
env:
|
|
||||||
GITHUB_SHA: ${{ github.sha }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
SHORT_SHA="$(printf '%.12s' "$GITHUB_SHA")"
|
|
||||||
docker build -t "${IMAGE}:pro" -t "${IMAGE}:${SHORT_SHA}" .
|
|
||||||
docker push "$IMAGE:pro"
|
|
||||||
docker push "$IMAGE:$SHORT_SHA"
|
|
||||||
|
|
||||||
- name: Deploy Compose service
|
|
||||||
env:
|
|
||||||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
|
||||||
DEPLOY_KNOWN_HOSTS: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
|
|
||||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
install -d -m 700 "$HOME/.ssh"
|
|
||||||
KEY_FILE="$(mktemp "$HOME/.ssh/olns-deploy.XXXXXX")"
|
|
||||||
cleanup() {
|
|
||||||
shred -u "$KEY_FILE" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
printf '%s\n' "$DEPLOY_SSH_KEY" > "$KEY_FILE"
|
|
||||||
chmod 600 "$KEY_FILE"
|
|
||||||
printf '%s\n' "$DEPLOY_KNOWN_HOSTS" > "$HOME/.ssh/known_hosts"
|
|
||||||
chmod 600 "$HOME/.ssh/known_hosts"
|
|
||||||
SSH_ARGS=(-i "$KEY_FILE" -o BatchMode=yes -o StrictHostKeyChecking=yes)
|
|
||||||
for attempt in 1 2 3; do
|
|
||||||
if printf '%s' "$REGISTRY_TOKEN" | ssh "${SSH_ARGS[@]}" "$DEPLOY_USER@$DEPLOY_HOST" \
|
|
||||||
"docker login git.olns.shop -u admin --password-stdin"; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if [[ "$attempt" -eq 3 ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
sleep "$((attempt * 5))"
|
|
||||||
done
|
|
||||||
ssh "${SSH_ARGS[@]}" "$DEPLOY_USER@$DEPLOY_HOST" \
|
|
||||||
'cd /opt/olns && for attempt in 1 2 3; do
|
|
||||||
if timeout 180 docker compose pull olons-admin; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if [ "$attempt" -eq 3 ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
sleep $((attempt * 5))
|
|
||||||
done && docker compose up -d --no-deps --wait olons-admin'
|
|
||||||
@@ -1,76 +1,165 @@
|
|||||||
# Go binaries and test/build artifacts
|
# ---> Go
|
||||||
|
# If you prefer the allow list template instead of the deny list, see community template:
|
||||||
|
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||||
|
#
|
||||||
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
*.exe~
|
*.exe~
|
||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
go.work
|
go.work
|
||||||
go.work.sum
|
go.work.sum
|
||||||
|
|
||||||
# Node dependencies, logs, caches, and build output
|
# env file
|
||||||
node_modules/
|
.env
|
||||||
jspm_packages/
|
|
||||||
web_modules/
|
# ---> Node
|
||||||
logs/
|
# Logs
|
||||||
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
coverage/
|
|
||||||
*.lcov
|
|
||||||
.nyc_output/
|
|
||||||
.grunt/
|
|
||||||
bower_components/
|
|
||||||
.lock-wscript
|
|
||||||
build/Release/
|
|
||||||
*.tsbuildinfo
|
|
||||||
.npm/
|
|
||||||
.eslintcache
|
|
||||||
.stylelintcache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rpt2_cache_cjs/
|
|
||||||
.rpt2_cache_es/
|
|
||||||
.rpt2_cache_umd/
|
|
||||||
.node_repl_history
|
|
||||||
*.tgz
|
|
||||||
.yarn-integrity
|
|
||||||
.cache/
|
|
||||||
.parcel-cache/
|
|
||||||
.next/
|
|
||||||
out/
|
|
||||||
.nuxt/
|
|
||||||
dist/
|
|
||||||
.temp/
|
|
||||||
**/.vitepress/dist/
|
|
||||||
**/.vitepress/cache/
|
|
||||||
.docusaurus/
|
|
||||||
.serverless/
|
|
||||||
.fusebox/
|
|
||||||
.dynamodb/
|
|
||||||
.tern-port
|
|
||||||
.vscode-test/
|
|
||||||
.yarn/cache/
|
|
||||||
.yarn/unplugged/
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|
||||||
# Local environment files
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
.env
|
.env
|
||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
.env.local
|
.env.local
|
||||||
|
|
||||||
# Local OS and editor metadata
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.DS_Store
|
.cache
|
||||||
.idea/
|
.parcel-cache
|
||||||
.vscode/
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# vuepress v2.x temp and cache directory
|
||||||
|
.temp
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# vitepress build output
|
||||||
|
**/.vitepress/dist
|
||||||
|
|
||||||
|
# vitepress cache directory
|
||||||
|
**/.vitepress/cache
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
# Python bytecode
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
|
|||||||
@@ -1,960 +0,0 @@
|
|||||||
# HotGo 项目开发规范
|
|
||||||
|
|
||||||
**生成或修改任何代码前,必须完整阅读本文档。**
|
|
||||||
本规范是项目唯一事实来源,所有新增代码必须严格对齐现有模块风格,不得自创新的代码模式。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 技术栈
|
|
||||||
|
|
||||||
| 层 | 技术 |
|
|
||||||
|----|----------------------------------------------------------------|
|
|
||||||
| 后端语言 | Go,module 名 `hotgo` |
|
|
||||||
| 后端框架 | GoFrame v2(gdb、ghttp、gcron、gerror、gctx、gerror、gjson、gvar) |
|
|
||||||
| 前端框架 | Vue 3 + Vite + TypeScript |
|
|
||||||
| UI 组件库 | **Naive UI**(优先使用,未经允许不得引入其他 UI 库) |
|
|
||||||
| 状态管理 | Pinia |
|
|
||||||
| HTTP 客户端 | 项目封装 `@/utils/http/axios`(`http.request`),禁止直接使用 axios |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 后端目录结构
|
|
||||||
|
|
||||||
```
|
|
||||||
server/
|
|
||||||
├── addons/ # 插件模块(每个插件独立微架构,见"插件开发"章节)
|
|
||||||
│ ├── modules/ # 隐式注册文件(每个插件一个 .go,仅含 import)
|
|
||||||
│ └── <addonName>/ # 插件目录,与主模块结构镜像
|
|
||||||
├── api/admin/<module>/ # 主模块 HTTP 契约:Req/Res + g.Meta 路由声明
|
|
||||||
├── internal/
|
|
||||||
│ ├── consts/ # 全局常量与字典选项(枚举在此定义并注册)
|
|
||||||
│ ├── global/ # 全局公用变量(谨慎添加,尽量少用)
|
|
||||||
│ ├── controller/admin/sys/ # 薄控制器,只做参数透传,不含业务逻辑
|
|
||||||
│ ├── crons/ # 主模块定时任务注册与处理
|
|
||||||
│ ├── queues/ # 主模块消息队列消费者注册与处理
|
|
||||||
│ ├── logic/sys/ # 业务实现(sSysXxx),init() 注册到 service
|
|
||||||
│ ├── library/ # 内部基础库(addons、dict、hgorm、cache、queue、cron 等)
|
|
||||||
│ ├── service/ # 接口声明(ISysXxx)+ 注册函数
|
|
||||||
│ ├── dao/ # 对外 DAO;internal/dao/internal/ 为 CLI 生成,禁止手改
|
|
||||||
│ ├── model/
|
|
||||||
│ │ ├── entity/ # 表结构体(CLI 生成,禁止手改)
|
|
||||||
│ │ ├── do/ # ORM 写入结构(CLI 生成,禁止手改)
|
|
||||||
│ │ └── input/sysin/ # 业务入参、出参、过滤结构
|
|
||||||
│ └── router/
|
|
||||||
│ ├── admin.go # 主路由,末尾调用 genrouter.Register()
|
|
||||||
│ └── genrouter/ # 每个生成模块一个文件,init() 追加到 LoginRequiredRouter
|
|
||||||
├── resource/
|
|
||||||
│ ├── generate/default/curd/ # 主模块 CRUD 代码生成模板(参考,禁止直接修改)
|
|
||||||
│ └── generate/default/addon/ # 插件脚手架代码生成模板(参考,禁止直接修改)
|
|
||||||
└── utility/ # 通用工具:convert、excel、validate 等
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 后端分层约定
|
|
||||||
|
|
||||||
### 分层职责(禁止跨层调用)
|
|
||||||
|
|
||||||
```
|
|
||||||
api(HTTP契约) → controller(参数透传) → service(接口) → logic(业务实现) → dao(数据访问)
|
|
||||||
```
|
|
||||||
|
|
||||||
- **controller 层**:不写任何业务逻辑,只转调 service
|
|
||||||
- **logic 层**:不出现 HTTP 相关代码,所有校验通过 `Filter()` 或 `g.Validator()` 完成
|
|
||||||
- **dao 层**:`internal/dao/internal/` 由 CLI 自动生成,禁止手改
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 1. API 层 `api/admin/<module>/<module>.go`
|
|
||||||
|
|
||||||
- 每个接口一对 `XxxReq` / `XxxRes`,`g.Meta` 声明路由
|
|
||||||
- GET 接口用 `method:"get"`,写操作用 `method:"post"`
|
|
||||||
- 请求体嵌入 `sysin.XxxInp`,响应体嵌入对应 Model 或空 `struct{}`
|
|
||||||
|
|
||||||
```go
|
|
||||||
type ListReq struct {
|
|
||||||
g.Meta `path:"/xxxModule/list" method:"get" tags:"XXX模块" summary:"获取XXX列表"`
|
|
||||||
sysin.XxxListInp
|
|
||||||
}
|
|
||||||
type ListRes struct {
|
|
||||||
form.PageRes
|
|
||||||
List []*sysin.XxxListModel `json:"list" dc:"数据列表"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Controller 层 `internal/controller/admin/sys/<module>.go`
|
|
||||||
|
|
||||||
- 变量:`var XxxModule = cXxxModule{}`,类型:`type cXxxModule struct{}`
|
|
||||||
- 只做参数转发和结果组装,禁止直接操作 dao 或写业务逻辑
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (c *cXxxModule) List(ctx context.Context, req *xxxmodule.ListReq) (res *xxxmodule.ListRes, err error) {
|
|
||||||
list, totalCount, err := service.SysXxxModule().List(ctx, &req.XxxListInp)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if list == nil {
|
|
||||||
list = []*sysin.XxxListModel{}
|
|
||||||
}
|
|
||||||
res = new(xxxmodule.ListRes)
|
|
||||||
res.List = list
|
|
||||||
res.PageRes.Pack(req, totalCount)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Service 层 `internal/service/sys.go`
|
|
||||||
|
|
||||||
- 在已有文件中**追加**接口声明和注册函数,禁止新建文件
|
|
||||||
- 声明 `ISysXxxModule` 接口,提供 `SysXxxModule()` 获取函数和 `RegisterSysXxxModule()` 注册函数
|
|
||||||
|
|
||||||
### 4. Logic 层 `internal/logic/sys/<module>.go`
|
|
||||||
|
|
||||||
- 结构体:`type sSysXxxModule struct{}`
|
|
||||||
- `init()` 里调用 `service.RegisterSysXxxModule(NewSysXxxModule())`
|
|
||||||
- `Model()` 方法:`return handler.Model(dao.XxxTable.Ctx(ctx), option...)`
|
|
||||||
- 列名引用必须用 `dao.XxxTable.Columns().FieldName`,禁止硬编码字符串字段名
|
|
||||||
- `Edit` 方法以 `in.Id > 0` 区分更新/新增,更新用 `XxxUpdateFields`,新增用 `XxxInsertFields`
|
|
||||||
- 字段校验在 `sysin` 的 `Filter(ctx)` 方法完成,logic 层不重复校验
|
|
||||||
|
|
||||||
### 5. Model 层 `internal/model/input/sysin/<module>.go`
|
|
||||||
|
|
||||||
| 类型 | 用途 |
|
|
||||||
|------|------|
|
|
||||||
| `XxxUpdateFields` | 更新时字段白名单 |
|
|
||||||
| `XxxInsertFields` | 新增时字段白名单 |
|
|
||||||
| `XxxEditInp` | 嵌入 `entity.XxxTable`,含 `Filter()` 校验方法 |
|
|
||||||
| `XxxListInp` | 列表查询入参,嵌入 `form.PageInp` |
|
|
||||||
| `XxxListModel` | 列表返回字段 |
|
|
||||||
| `XxxViewInp` / `XxxViewModel` | 详情入参/出参 |
|
|
||||||
| `XxxDeleteInp` | 删除入参(通常含 `Ids []int64`) |
|
|
||||||
| `XxxStatusInp`、`XxxMaxSortInp` 等 | 其他操作 |
|
|
||||||
|
|
||||||
### 6. 路由注册 `internal/router/genrouter/<module>.go`
|
|
||||||
|
|
||||||
```go
|
|
||||||
package genrouter
|
|
||||||
|
|
||||||
import "hotgo/internal/controller/admin/sys"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
LoginRequiredRouter = append(LoginRequiredRouter, sys.XxxModule) // XXX模块
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
新建此文件即可,`genrouter/init.go` 通过 `init()` 链自动加载,无需修改 `admin.go`。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 字典与枚举规范
|
|
||||||
|
|
||||||
**字典由后端统一维护**,前端通过固定接口拉取,禁止在前端硬编码枚举值。
|
|
||||||
|
|
||||||
### 后端:定义与注册(`internal/consts/` 下对应文件)
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 1. 定义常量
|
|
||||||
const (
|
|
||||||
XxxStatusEnabled = 1 // 启用
|
|
||||||
XxxStatusDisable = 2 // 禁用
|
|
||||||
)
|
|
||||||
|
|
||||||
// 2. 定义选项(选择合适的样式函数)
|
|
||||||
var XxxStatusOptions = []*model.Option{
|
|
||||||
dict.GenSuccessOption(XxxStatusEnabled, "启用"),
|
|
||||||
dict.GenWarningOption(XxxStatusDisable, "禁用"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 在 init() 中注册(同文件)
|
|
||||||
func init() {
|
|
||||||
dict.RegisterEnums("XxxStatusOptions", "XXX状态选项", XxxStatusOptions)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**样式函数选择规则:**
|
|
||||||
|
|
||||||
| 函数 | 适用场景 |
|
|
||||||
|------|---------|
|
|
||||||
| `dict.GenSuccessOption` | 正常、启用、成功 |
|
|
||||||
| `dict.GenWarningOption` | 待处理、禁用、警告 |
|
|
||||||
| `dict.GenErrorOption` | 失败、封禁、危险 |
|
|
||||||
| `dict.GenInfoOption` | 信息类、中性状态 |
|
|
||||||
| `dict.GenPrimaryOption` | 主要操作、强调 |
|
|
||||||
| `dict.GenDefaultOption` | 默认、无特殊含义 |
|
|
||||||
| `dict.GenHashOption` | 不确定数量的动态枚举 |
|
|
||||||
|
|
||||||
### 后端:Logic 层中使用字典
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 获取标签文本
|
|
||||||
label := dict.GetOptionLabel(consts.XxxStatusOptions, in.Status)
|
|
||||||
|
|
||||||
// 校验是否为合法值
|
|
||||||
if !dict.HasOptionKey(consts.XxxStatusOptions, in.Status) {
|
|
||||||
return gerror.New("状态值不合法")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 前端:加载与使用字典
|
|
||||||
|
|
||||||
**加载**(在 `model.ts` 的 `loadOptions()` 中):
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export function loadOptions() {
|
|
||||||
dict.loadOptions(['XxxStatusOptions', 'sys_normal_disable']);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**在 `model.ts` 的 columns 中渲染字典标签:**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { useDictStore } from '@/store/modules/dict';
|
|
||||||
const dict = useDictStore();
|
|
||||||
|
|
||||||
// columns 中
|
|
||||||
{
|
|
||||||
title: '状态',
|
|
||||||
key: 'status',
|
|
||||||
render(row) {
|
|
||||||
return dict.getLabel('XxxStatusOptions', row.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**在搜索表单 schemas 中使用字典下拉:**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
{
|
|
||||||
field: 'status',
|
|
||||||
component: 'NSelect',
|
|
||||||
label: '状态',
|
|
||||||
componentProps: {
|
|
||||||
options: computed(() => dict.getOptions('XxxStatusOptions')),
|
|
||||||
placeholder: '请选择状态',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 插件(Addon)开发规范
|
|
||||||
|
|
||||||
> 定位:独立、临时性、工具类型的功能推荐插件化开发,例如小游戏、广告管理、文章管理、小程序、微商城等。插件之间完全隔离,方便多项目复用。
|
|
||||||
|
|
||||||
### 插件目录结构
|
|
||||||
|
|
||||||
每个插件拥有完整的独立微架构,与主模块结构镜像,但 **包路径前缀为 `hotgo/addons/<addonName>/`**:
|
|
||||||
|
|
||||||
```
|
|
||||||
server/addons/<addonName>/
|
|
||||||
├── main.go # 插件入口:定义 module 结构体,实现 Module 接口,init() 注册
|
|
||||||
├── global/
|
|
||||||
│ ├── global.go # 插件级全局变量
|
|
||||||
│ └── init.go # Init(ctx, skeleton),GetSkeleton() 方法
|
|
||||||
├── api/
|
|
||||||
│ ├── admin/ # 后台接口契约(同主模块 api 写法)
|
|
||||||
│ ├── api/ # 前台 API 接口契约
|
|
||||||
│ └── home/ # 首页接口契约(如有)
|
|
||||||
├── controller/
|
|
||||||
│ ├── admin/sys/ # 后台薄控制器
|
|
||||||
│ ├── api/ # 前台控制器
|
|
||||||
│ └── home/ # 首页控制器(如有)
|
|
||||||
├── logic/
|
|
||||||
│ ├── logic.go # 匿名导入各 logic 子包触发 init()
|
|
||||||
│ └── sys/ # 业务实现(同主模块 logic 写法)
|
|
||||||
├── service/ # 插件内接口声明与注册(独立,不与主模块 service 混用)
|
|
||||||
├── model/
|
|
||||||
│ └── input/sysin/ # 插件内入参/出参(调用主模块服务时继承主模块 input 结构)
|
|
||||||
├── router/
|
|
||||||
│ ├── admin.go # 注册后台路由,使用 addons.RouterPrefix() 获取路由前缀
|
|
||||||
│ ├── api.go # 注册前台路由
|
|
||||||
│ ├── home.go # 注册首页路由(如有)
|
|
||||||
│ ├── websocket.go # 注册 WebSocket 路由(如有)
|
|
||||||
│ └── genrouter/
|
|
||||||
│ ├── init.go # 插件版 genrouter:Register() 使用插件前缀
|
|
||||||
│ └── *.go # 每个生成模块一个文件,追加到插件 LoginRequiredRouter
|
|
||||||
├── consts/ # 插件内常量与字典(同主模块 consts 写法)
|
|
||||||
├── crons/ # 插件定时任务(可选)
|
|
||||||
├── queues/ # 插件消息队列消费者(可选)
|
|
||||||
└── resource/ # 插件静态资源与模板(可选)
|
|
||||||
```
|
|
||||||
|
|
||||||
**对应前端目录:**
|
|
||||||
|
|
||||||
```
|
|
||||||
web/src/
|
|
||||||
├── api/addons/<addonName>/ # 插件前端 API 封装
|
|
||||||
└── views/addons/<addonName>/ # 插件前端页面
|
|
||||||
```
|
|
||||||
|
|
||||||
### 插件入口 `main.go`
|
|
||||||
|
|
||||||
```go
|
|
||||||
package <addonName>
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/gogf/gf/v2/net/ghttp"
|
|
||||||
_ "hotgo/addons/<addonName>/crons"
|
|
||||||
"hotgo/addons/<addonName>/global"
|
|
||||||
_ "hotgo/addons/<addonName>/logic"
|
|
||||||
_ "hotgo/addons/<addonName>/queues"
|
|
||||||
"hotgo/addons/<addonName>/router"
|
|
||||||
"hotgo/internal/library/addons"
|
|
||||||
"hotgo/internal/service"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type module struct {
|
|
||||||
skeleton *addons.Skeleton
|
|
||||||
ctx context.Context
|
|
||||||
sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { newModule() }
|
|
||||||
|
|
||||||
func newModule() {
|
|
||||||
m := &module{
|
|
||||||
skeleton: &addons.Skeleton{
|
|
||||||
Label: "插件显示名",
|
|
||||||
Name: "<addonName>", // 与目录名一致
|
|
||||||
Group: 1,
|
|
||||||
Brief: "简介",
|
|
||||||
Description: "详细描述",
|
|
||||||
Author: "作者",
|
|
||||||
Version: "v1.0.0",
|
|
||||||
},
|
|
||||||
ctx: gctx.New(),
|
|
||||||
}
|
|
||||||
addons.RegisterModule(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *module) Start(option *addons.Option) (err error) {
|
|
||||||
global.Init(m.ctx, m.skeleton)
|
|
||||||
option.Server.Group("/", func(group *ghttp.RouterGroup) {
|
|
||||||
group.Middleware(service.Middleware().Addon)
|
|
||||||
router.Admin(m.ctx, group)
|
|
||||||
router.Api(m.ctx, group)
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 其余方法:Stop、Ctx、GetSkeleton、Install、Upgrade、UnInstall(默认留空)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 插件路由前缀规则
|
|
||||||
|
|
||||||
```
|
|
||||||
后台:/admin/<addonName>/接口路径 → 对应 controller/admin/sys/
|
|
||||||
前台:/api/<addonName>/接口路径 → 对应 controller/api/
|
|
||||||
首页:/home/<addonName>/接口路径 → 对应 controller/home/
|
|
||||||
WebSocket:/socket/<addonName>/接口路径
|
|
||||||
```
|
|
||||||
|
|
||||||
路由前缀通过 `addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)` 自动生成,**禁止在路由文件里硬编码路径前缀**。
|
|
||||||
|
|
||||||
### 插件 genrouter 与主模块的区别
|
|
||||||
|
|
||||||
插件 `genrouter/init.go` 的 `Register()` 函数需要传入 `ctx` 和 `group`,并使用插件路由前缀:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 插件 genrouter/init.go
|
|
||||||
func Register(ctx context.Context, group *ghttp.RouterGroup) {
|
|
||||||
prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)
|
|
||||||
group.Group(prefix, func(group *ghttp.RouterGroup) {
|
|
||||||
group.Middleware(service.Middleware().AdminAuth)
|
|
||||||
if len(LoginRequiredRouter) > 0 {
|
|
||||||
group.Bind(LoginRequiredRouter...)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插件 genrouter/<module>.go
|
|
||||||
func init() {
|
|
||||||
LoginRequiredRouter = append(LoginRequiredRouter, sys.XxxModule)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
参考实现:`server/addons/hgexample/router/genrouter/`
|
|
||||||
|
|
||||||
### 插件调用主模块服务
|
|
||||||
|
|
||||||
**在插件 input 层继承主模块 input 结构,解耦参数依赖**,避免 import cycle:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 插件 model/input/sysin/config.go
|
|
||||||
package sysin
|
|
||||||
|
|
||||||
import "hotgo/internal/model/input/sysin"
|
|
||||||
|
|
||||||
type UpdateConfigInp struct {
|
|
||||||
sysin.UpdateAddonsConfigInp
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 插件 logic 中调用主模块服务
|
|
||||||
import isc "hotgo/internal/service"
|
|
||||||
|
|
||||||
func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error {
|
|
||||||
in.UpdateAddonsConfigInp.AddonName = global.GetSkeleton().Name
|
|
||||||
return isc.SysAddonsConfig().UpdateConfigByGroup(ctx, in.UpdateAddonsConfigInp)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 插件获取自身信息
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 插件内部
|
|
||||||
global.GetSkeleton()
|
|
||||||
|
|
||||||
// 任意位置判断当前请求是否为插件请求
|
|
||||||
contexts.IsAddonRequest(ctx)
|
|
||||||
contexts.GetAddonName(ctx)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 插件隐式注册
|
|
||||||
|
|
||||||
在 `server/addons/modules/` 下新建 `<addonName>.go`,内容仅含一行匿名导入:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package modules
|
|
||||||
|
|
||||||
import _ "hotgo/addons/<addonName>"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 新增插件检查清单
|
|
||||||
|
|
||||||
**后端:**
|
|
||||||
- [ ] `addons/<addonName>/main.go` — 插件入口,实现 Module 接口
|
|
||||||
- [ ] `addons/<addonName>/global/` — global.go + init.go
|
|
||||||
- [ ] `addons/modules/<addonName>.go` — 隐式注册
|
|
||||||
- [ ] `addons/<addonName>/service/` — 插件内接口声明(独立包)
|
|
||||||
- [ ] `addons/<addonName>/logic/logic.go` — 匿名导入触发 init()
|
|
||||||
- [ ] `addons/<addonName>/logic/sys/<module>.go` — 业务实现
|
|
||||||
- [ ] `addons/<addonName>/model/input/sysin/<module>.go` — 入参/出参
|
|
||||||
- [ ] `addons/<addonName>/api/admin/<module>/<module>.go` — API 契约
|
|
||||||
- [ ] `addons/<addonName>/controller/admin/sys/<module>.go` — 薄控制器
|
|
||||||
- [ ] `addons/<addonName>/router/admin.go` — 路由注册
|
|
||||||
- [ ] `addons/<addonName>/router/genrouter/init.go` — 插件 genrouter
|
|
||||||
- [ ] `addons/<addonName>/router/genrouter/<module>.go` — 模块路由追加
|
|
||||||
|
|
||||||
**前端:**
|
|
||||||
- [ ] `web/src/api/addons/<addonName>/index.ts` — API 封装
|
|
||||||
- [ ] `web/src/views/addons/<addonName>/model.ts` — State、schemas、columns
|
|
||||||
- [ ] `web/src/views/addons/<addonName>/index.vue` — 列表页
|
|
||||||
- [ ] `web/src/views/addons/<addonName>/edit.vue` — 编辑页
|
|
||||||
|
|
||||||
参考实现:`server/addons/hgexample/`(完整插件示例)、`server/resource/generate/default/addon/`(生成模板)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 标准 CRUD 接口清单
|
|
||||||
|
|
||||||
| 接口 | method | 说明 |
|
|
||||||
|------|--------|------|
|
|
||||||
| `/xxx/list` | GET | 分页列表 |
|
|
||||||
| `/xxx/view` | GET | 详情 |
|
|
||||||
| `/xxx/edit` | POST | 新增/编辑(id>0 为编辑) |
|
|
||||||
| `/xxx/delete` | POST | 删除(支持批量,传 ids) |
|
|
||||||
| `/xxx/status` | POST | 启用/禁用状态切换 |
|
|
||||||
| `/xxx/switch` | POST | 开关字段切换 |
|
|
||||||
| `/xxx/maxSort` | GET | 获取最大排序值 |
|
|
||||||
| `/xxx/export` | GET | 导出列表 |
|
|
||||||
|
|
||||||
按实际需求裁剪,不强制全部实现。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 前端目录结构
|
|
||||||
|
|
||||||
```
|
|
||||||
web/src/
|
|
||||||
├── api/<module>/index.ts # HTTP 请求封装
|
|
||||||
├── views/<module>/
|
|
||||||
│ ├── index.vue # 列表页
|
|
||||||
│ ├── edit.vue # 新增/编辑弹窗
|
|
||||||
│ └── model.ts # State 类、rules、schemas、columns、loadOptions
|
|
||||||
├── components/ # 通用组件(BasicTable、BasicForm、BasicModal 等)
|
|
||||||
├── store/modules/dict.ts # 字典 store(loadOptions、getLabel、getOptions)
|
|
||||||
└── utils/
|
|
||||||
├── http/axios.ts # HTTP 封装(http.request / jumpExport)
|
|
||||||
└── dateUtil.ts # 日期工具(defRangeShortcuts 等)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 前端编码约定
|
|
||||||
|
|
||||||
### API 文件 `api/<module>/index.ts`
|
|
||||||
|
|
||||||
- 使用 `http.request`,禁止直接使用 axios
|
|
||||||
- 函数名与接口语义一致:`List`、`Edit`、`Delete`、`View`、`Status`、`Switch`、`Export`、`MaxSort`
|
|
||||||
- 导出接口用 `jumpExport('/xxx/export', params)`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { http, jumpExport } from '@/utils/http/axios';
|
|
||||||
|
|
||||||
export function List(params) {
|
|
||||||
return http.request({ url: '/xxxModule/list', method: 'get', params });
|
|
||||||
}
|
|
||||||
export function Edit(params) {
|
|
||||||
return http.request({ url: '/xxxModule/edit', method: 'POST', params });
|
|
||||||
}
|
|
||||||
export function Export(params) {
|
|
||||||
jumpExport('/xxxModule/export', params);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### model.ts 结构
|
|
||||||
|
|
||||||
- `class State`:属性与后端 entity 字段对应,提供合理默认值
|
|
||||||
- `newState()`:工厂函数,支持深拷贝(`cloneDeep`)
|
|
||||||
- `rules`:Naive UI 表单校验规则
|
|
||||||
- `schemas`:搜索栏 `FormSchema[]`(`ref` 包装)
|
|
||||||
- `columns`:表格列定义,含权限守卫的操作用 `hasPermission(['/xxx/edit'])`
|
|
||||||
- `loadOptions()`:调用 `dict.loadOptions([...])`,预加载字典数据
|
|
||||||
|
|
||||||
### 组件使用规范
|
|
||||||
|
|
||||||
**必须优先使用 Naive UI 原生组件**,能用 Naive UI 实现的禁止自行封装替代组件:
|
|
||||||
|
|
||||||
| 场景 | 必须使用的组件 |
|
|
||||||
|------|--------------|
|
|
||||||
| 表格 | 项目封装 `BasicTable`(基于 Naive UI) |
|
|
||||||
| 表单 | 项目封装 `BasicForm`(基于 Naive UI) |
|
|
||||||
| 弹窗 | `n-modal` 或项目封装 `BasicModal` |
|
|
||||||
| 按钮 | `n-button`,类型用 `primary`/`default`/`error` 等语义值 |
|
|
||||||
| 选择器 | `n-select`(字典下拉)、`n-tree-select`(树形) |
|
|
||||||
| 开关 | `n-switch`,配合 Switch 接口 |
|
|
||||||
| 输入框 | `n-input` |
|
|
||||||
| 日期选择 | `n-date-picker`,范围选择配合 `defRangeShortcuts()` |
|
|
||||||
| 图片渲染 | `renderImage(url)` |
|
|
||||||
| 文件渲染 | `renderFile(url)` |
|
|
||||||
| 成员信息 | `renderPopoverMemberSumma(summa)` |
|
|
||||||
|
|
||||||
**禁止行为:**
|
|
||||||
- 禁止引入 Element Plus、Ant Design Vue 等其他 UI 库
|
|
||||||
- 禁止使用内联 style(使用 Naive UI 的 props 或 class)
|
|
||||||
- 禁止在模板里硬编码字典值文本,必须通过 `dict.getLabel()` 渲染
|
|
||||||
|
|
||||||
### 权限控制
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { usePermission } from '@/hooks/web/usePermission';
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
// 模板中
|
|
||||||
v-if="hasPermission(['/xxxModule/edit'])"
|
|
||||||
|
|
||||||
// columns 中开关操作
|
|
||||||
disabled: !hasPermission(['/xxxModule/switch'])
|
|
||||||
```
|
|
||||||
|
|
||||||
权限标识与后端路由路径保持一致,**路由由后端菜单数据驱动,禁止在源码里硬编码路由路径**。
|
|
||||||
|
|
||||||
### Vue 3 代码规范
|
|
||||||
|
|
||||||
- 使用 Composition API(`<script setup>`)
|
|
||||||
- 响应式数据用 `ref` / `reactive`,计算属性用 `computed`
|
|
||||||
- 字典选项传给组件时用 `computed(() => dict.getOptions('XxxOptions'))`,保持响应式
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 新增 CRUD 模块检查清单
|
|
||||||
|
|
||||||
**后端(必须全部完成,顺序建议从下往上):**
|
|
||||||
|
|
||||||
- [ ] `internal/consts/<module>.go` — 常量定义、选项变量、`init()` 注册字典
|
|
||||||
- [ ] 使用 goframe CLI 生成:`entity`、`do`、`dao/internal`、`dao`(禁止手写)
|
|
||||||
- [ ] `internal/model/input/sysin/<module>.go` — 入参/出参/过滤模型
|
|
||||||
- [ ] `internal/service/sys.go` — 追加接口声明与注册函数
|
|
||||||
- [ ] `internal/logic/sys/<module>.go` — 业务实现
|
|
||||||
- [ ] `internal/controller/admin/sys/<module>.go` — 薄控制器
|
|
||||||
- [ ] `api/admin/<module>/<module>.go` — API 契约
|
|
||||||
- [ ] `internal/router/genrouter/<module>.go` — 路由注册(`LoginRequiredRouter` 追加)
|
|
||||||
|
|
||||||
**前端(必须全部完成):**
|
|
||||||
|
|
||||||
- [ ] `web/src/api/<module>/index.ts` — HTTP 封装
|
|
||||||
- [ ] `web/src/views/<module>/model.ts` — State、schemas、columns、rules、loadOptions
|
|
||||||
- [ ] `web/src/views/<module>/index.vue` — 列表页
|
|
||||||
- [ ] `web/src/views/<module>/edit.vue` — 编辑页
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 参考实现
|
|
||||||
|
|
||||||
**所有新模块必须严格对齐以下文件的风格,生成前请逐一阅读:**
|
|
||||||
|
|
||||||
**主模块 CRUD 参考:**
|
|
||||||
|
|
||||||
| 文件 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `server/internal/consts/status.go` | 字典常量定义与注册标准写法 |
|
|
||||||
| `server/api/admin/curddemo/curddemo.go` | API 契约标准写法 |
|
|
||||||
| `server/internal/controller/admin/sys/curd_demo.go` | 薄控制器标准写法 |
|
|
||||||
| `server/internal/logic/sys/curd_demo.go` | Logic 标准写法(含关联查询、导出、字段过滤) |
|
|
||||||
| `server/internal/model/input/sysin/curd_demo.go` | 入参/出参模型标准写法 |
|
|
||||||
| `server/internal/router/genrouter/curd_demo.go` | 主模块路由注册标准写法 |
|
|
||||||
| `web/src/api/curdDemo/index.ts` | 前端 API 封装标准写法 |
|
|
||||||
| `web/src/views/curdDemo/model.ts` | 前端 model 标准写法(含字典加载) |
|
|
||||||
| `web/src/views/curdDemo/index.vue` | 列表页标准写法 |
|
|
||||||
| `web/src/views/curdDemo/edit.vue` | 编辑页标准写法 |
|
|
||||||
|
|
||||||
**插件参考(以 hgexample 为标准):**
|
|
||||||
|
|
||||||
| 文件 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `server/addons/hgexample/main.go` | 插件入口标准写法 |
|
|
||||||
| `server/addons/hgexample/global/init.go` | 插件 global 标准写法 |
|
|
||||||
| `server/addons/hgexample/router/admin.go` | 插件路由注册标准写法 |
|
|
||||||
| `server/addons/hgexample/router/genrouter/init.go` | 插件 genrouter 标准写法 |
|
|
||||||
| `server/addons/hgexample/router/genrouter/tenant_order.go` | 插件模块路由追加标准写法 |
|
|
||||||
| `server/addons/hgexample/logic/sys/tenant_order.go` | 插件业务逻辑标准写法 |
|
|
||||||
| `server/addons/hgexample/logic/sys/config.go` | 插件调用主模块服务标准写法 |
|
|
||||||
|
|
||||||
代码生成模板:
|
|
||||||
- 主模块 CRUD:`server/resource/generate/default/curd/`
|
|
||||||
- 插件脚手架:`server/resource/generate/default/addon/`
|
|
||||||
|
|
||||||
以上模板可参考逻辑,**禁止直接修改模板文件**。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 错误处理规范
|
|
||||||
|
|
||||||
### 基本原则
|
|
||||||
|
|
||||||
- 业务错误直接用 `gerror.New("描述清晰的中文信息")` 返回,GoFrame 框架会统一处理响应码
|
|
||||||
- 错误信息要面向用户,清晰说明**发生了什么**,而不是堆栈路径
|
|
||||||
|
|
||||||
### 错误创建方式
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/gogf/gf/v2/errors/gerror"
|
|
||||||
|
|
||||||
// 普通业务错误(最常用)
|
|
||||||
return gerror.New("用户名已存在")
|
|
||||||
|
|
||||||
// 包装底层错误,追加上下文(调用第三方/dao 层出错时使用)
|
|
||||||
if err := dao.User.Ctx(ctx).Data(data).Insert(); err != nil {
|
|
||||||
return gerror.Wrap(err, "创建用户失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 带格式化参数
|
|
||||||
return gerror.Newf("订单 %d 状态不合法,当前状态:%d", in.Id, order.Status)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 错误传递原则
|
|
||||||
|
|
||||||
- **logic 层**:遇到底层错误用 `gerror.Wrap` 追加上下文后返回;纯业务校验失败用 `gerror.New` 直接返回
|
|
||||||
- **controller 层**:直接 `return` 透传 logic 的 error,**不再包装**,不打印日志(框架统一处理)
|
|
||||||
- **禁止**在 controller 层 `fmt.Println(err)` 或 `g.Log().Error` 打印已经会被框架记录的错误
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 缓存使用规范
|
|
||||||
|
|
||||||
### 统一使用 `cache.Instance()`
|
|
||||||
|
|
||||||
**禁止直接调用 `g.Redis().Do()`**,项目统一通过 `cache.Instance()` 操作缓存,底层适配器(Memory / Redis / File)由配置决定,业务层无需关心。
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"hotgo/internal/library/cache"
|
|
||||||
"github.com/gogf/gf/v2/os/gcache"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 设置缓存(带过期时间)
|
|
||||||
err := cache.Instance().Set(ctx, "user:info:1", userInfo, 30*time.Minute)
|
|
||||||
|
|
||||||
// 获取缓存
|
|
||||||
val, err := cache.Instance().Get(ctx, "user:info:1")
|
|
||||||
if err != nil || val.IsNil() {
|
|
||||||
// 缓存未命中,查数据库
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除缓存
|
|
||||||
_, err = cache.Instance().Remove(ctx, "user:info:1")
|
|
||||||
|
|
||||||
// GetOrSet:缓存不存在时自动执行函数并写入(推荐用于只读类缓存)
|
|
||||||
val, err := cache.Instance().GetOrSet(ctx, "user:info:1", func(ctx context.Context) (interface{}, error) {
|
|
||||||
return dao.AdminMember.Ctx(ctx).Where(...).One()
|
|
||||||
}, 30*time.Minute)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 缓存 Key 命名规范
|
|
||||||
|
|
||||||
- 格式:`模块:实体:唯一标识`,例如:`user:info:1`、`config:site:basic`、`dict:options:XxxStatus`
|
|
||||||
- 同一模块的 Key 统一在 `internal/consts/cache.go`(或对应模块的 consts 文件)中定义为常量,禁止散落在 logic 里硬编码
|
|
||||||
- 插件缓存 Key 加插件名前缀:`hgexample:order:1`
|
|
||||||
|
|
||||||
### 缓存使用原则
|
|
||||||
|
|
||||||
- 更新或删除数据后,**主动清除**相关缓存,不依赖过期自动失效
|
|
||||||
- 缓存时间:频繁更新的数据(配置、状态)用较短时间(5~30 分钟);基本不变的数据(字典、枚举)可用更长时间
|
|
||||||
- 缓存穿透场景:查询结果为空时也写入短时缓存(如 1 分钟)防止击穿
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 日志规范
|
|
||||||
|
|
||||||
### 日志级别选择
|
|
||||||
|
|
||||||
| 级别 | 方法 | 适用场景 |
|
|
||||||
|------|------|---------|
|
|
||||||
| Info | `g.Log().Info` / `g.Log().Infof` | 正常业务流程的关键节点(登录成功、订单创建、支付回调等) |
|
|
||||||
| Warning | `g.Log().Warning` / `g.Log().Warningf` | **遇到错误但不影响主流程**(重试、降级、外部服务异常、非致命校验失败) |
|
|
||||||
| Panic | `g.Log().Panic` / `g.Log().Panicf` | 极其严重、必须立即终止的情况(配置缺失、核心依赖不可用) |
|
|
||||||
|
|
||||||
### 使用示例
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Info:记录正常流程关键事件
|
|
||||||
g.Log().Infof(ctx, "用户登录成功 uid:%d ip:%s", member.Id, ip)
|
|
||||||
|
|
||||||
// Info:记录外部调用结果
|
|
||||||
g.Log().Info(ctx, "支付回调处理完成", g.Map{"orderId": orderId, "status": status})
|
|
||||||
|
|
||||||
// Warning:外部接口失败但已降级处理
|
|
||||||
g.Log().Warningf(ctx, "短信发送失败,已跳过 mobile:%s err:%+v", mobile, err)
|
|
||||||
|
|
||||||
// Warning:业务异常但不中断流程
|
|
||||||
g.Log().Warning(ctx, "用户余额不足,跳过自动扣款", g.Map{"uid": uid, "balance": balance})
|
|
||||||
|
|
||||||
// Panic:启动时核心配置缺失
|
|
||||||
g.Log().Panicf(ctx, "缓存未初始化,无法启动: %+v", err)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 日志上下文原则
|
|
||||||
|
|
||||||
- 日志**必须传入 `ctx`**(第一个参数),便于链路追踪
|
|
||||||
- 关键日志需携带足够的业务字段(uid、orderId、requestId 等),用 `g.Map{}` 附加结构化信息
|
|
||||||
- **禁止**用 `fmt.Println` 替代日志,禁止在 logic/controller 层裸打印调试信息
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 数据库建表约定
|
|
||||||
|
|
||||||
建表时遵循以下字段命名约定,代码生成器和 ORM hook 会自动识别并处理:
|
|
||||||
|
|
||||||
| 字段名 | 类型 | 说明 |
|
|
||||||
|--------|------|------|
|
|
||||||
| `id` | bigint(20) NOT NULL AUTO_INCREMENT | 主键,必须 |
|
|
||||||
| `created_at` | datetime | 创建时间,**自动写入**,禁止手动赋值 |
|
|
||||||
| `updated_at` | datetime | 更新时间,**自动维护**,禁止手动赋值 |
|
|
||||||
| `deleted_at` | datetime | 软删除时间,存在时查询自动加 `IS NULL`,删除只更新此字段 |
|
|
||||||
| `created_by` | bigint(20) | 创建者 ID,**自动写入** |
|
|
||||||
| `updated_by` | bigint(20) | 更新者 ID,**自动维护** |
|
|
||||||
| `deleted_by` | bigint(20) | 删除者 ID,**自动写入** |
|
|
||||||
| `status` | tinyint | 状态字段,默认使用系统字典 `sys_normal_disable` |
|
|
||||||
| `sort` | int | 排序字段,存在时编辑表单自动获取最大值+1填充 |
|
|
||||||
| `pid` | bigint(20) | 树表上级ID(树表必须) |
|
|
||||||
| `level` | int | 树等级(树表必须,自动维护) |
|
|
||||||
| `tree` | varchar(512) | 关系树(树表必须,自动维护) |
|
|
||||||
| `tenant_id` | bigint(20) | 租户ID(多租户场景按需加) |
|
|
||||||
|
|
||||||
**特殊字段查询方式(代码生成器默认生成):**
|
|
||||||
- `string` 类型字段 → `LIKE` 模糊查询
|
|
||||||
- `int/uint/int64` → `=` 精确查询
|
|
||||||
- `created_by`/`updated_by`/`deleted_by` → 关键词查询(ID/用户名/手机号匹配),调用 `service.AdminMember().GetIdsByKeyword()`
|
|
||||||
|
|
||||||
**数据类型 → Go 类型映射(影响生成代码的字段类型):**
|
|
||||||
- `tinyint/int/smallint` → `int`;加 `unsigned` → `uint`
|
|
||||||
- `bigint` → `int64`;加 `unsigned` → `uint64`
|
|
||||||
- `varchar/text/char` → `string`
|
|
||||||
- `datetime/timestamp` → `*gtime.Time`
|
|
||||||
- `json/jsonb` → `*gjson.Json`
|
|
||||||
- `decimal/float/double` → `float64`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 数据权限(权限过滤)
|
|
||||||
|
|
||||||
业务查询中如需过滤数据权限(仅自己/所属部门/下级等),在 ORM 链式调用中加入 handler:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "hotgo/internal/library/hgorm/handler"
|
|
||||||
|
|
||||||
// 按登录用户的数据权限范围过滤(表需含 created_by 或 member_id 字段)
|
|
||||||
dao.XxxTable.Ctx(ctx).Handler(handler.FilterAuth).Scan(&res)
|
|
||||||
|
|
||||||
// 表中无标准字段时,指定自定义字段
|
|
||||||
dao.XxxTable.Ctx(ctx).Handler(handler.FilterAuthWithField("custom_field")).Scan(&res)
|
|
||||||
|
|
||||||
// 多租户数据权限过滤(表需含 tenant_id 字段)
|
|
||||||
// 在 Model() 方法中通过 handler.Option 开启
|
|
||||||
func (s *sSysXxx) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
|
|
||||||
if len(option) == 0 {
|
|
||||||
option = append(option, &handler.Option{FilterTenant: true})
|
|
||||||
}
|
|
||||||
return handler.Model(dao.XxxTable.Ctx(ctx), option...)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
多租户增改时自动维护租户关系,在 ORM 操作后加 `.Hook(hook.SaveTenant)`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "hotgo/internal/library/hgorm/hook"
|
|
||||||
|
|
||||||
// 新增时自动写入 tenant_id/merchant_id/user_id
|
|
||||||
dao.XxxTable.Ctx(ctx).Fields(sysin.XxxInsertFields{}).Hook(hook.SaveTenant).Data(in).Insert()
|
|
||||||
|
|
||||||
// 更新时自动维护
|
|
||||||
s.Model(ctx).Fields(sysin.XxxUpdateFields{}).WherePri(in.Id).Data(in).Hook(hook.SaveTenant).Update()
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 定时任务(Crons)
|
|
||||||
|
|
||||||
定时任务通过实现接口 + `init()` 注册,在后台「系统设置 → 定时任务」中配置执行策略:
|
|
||||||
|
|
||||||
**主模块**:新建 `server/internal/crons/<name>.go`
|
|
||||||
**插件**:新建 `server/addons/<addonName>/crons/<name>.go`
|
|
||||||
|
|
||||||
```go
|
|
||||||
package crons
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"hotgo/internal/library/cron"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cron.Register(MyTask)
|
|
||||||
}
|
|
||||||
|
|
||||||
var MyTask = &cMyTask{name: "myTask"} // name 与后台配置的任务名称一致
|
|
||||||
|
|
||||||
type cMyTask struct{ name string }
|
|
||||||
|
|
||||||
func (c *cMyTask) GetName() string { return c.name }
|
|
||||||
|
|
||||||
func (c *cMyTask) Execute(ctx context.Context, parser *cron.Parser) (err error) {
|
|
||||||
parser.Logger.Infof(ctx, "任务执行:%v", ...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 消息队列(Queues)
|
|
||||||
|
|
||||||
队列采用接口 + `init()` 注册,topic 统一定义在 `internal/consts/queue.go`(或对应模块 consts 文件)。
|
|
||||||
|
|
||||||
**主模块**:新建 `server/internal/queues/<name>.go`
|
|
||||||
**插件**:新建 `server/addons/<addonName>/queues/<name>.go`
|
|
||||||
|
|
||||||
```go
|
|
||||||
package queues
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"hotgo/internal/consts"
|
|
||||||
"hotgo/internal/library/queue"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
queue.RegisterConsumer(MyConsumer)
|
|
||||||
}
|
|
||||||
|
|
||||||
var MyConsumer = &qMyConsumer{}
|
|
||||||
|
|
||||||
type qMyConsumer struct{}
|
|
||||||
|
|
||||||
func (q *qMyConsumer) GetTopic() string { return consts.QueueMyTopic }
|
|
||||||
|
|
||||||
func (q *qMyConsumer) Handle(ctx context.Context, mqMsg queue.MqMsg) (err error) {
|
|
||||||
var data MyData
|
|
||||||
if err = json.Unmarshal(mqMsg.Body, &data); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 处理消息...
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**发送消息:**
|
|
||||||
|
|
||||||
```go
|
|
||||||
// 即时消息
|
|
||||||
queue.Push(consts.QueueMyTopic, data)
|
|
||||||
|
|
||||||
// 延迟消息(仅 redis/rocketmq 驱动支持)
|
|
||||||
queue.SendDelayMsg(consts.QueueMyTopic, data, 10) // redis: 延迟秒数;rocketmq: 延迟级别
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 工具库使用规范
|
|
||||||
|
|
||||||
**后端(`server/utility/`)优先使用已有工具,禁止重复造轮子:**
|
|
||||||
|
|
||||||
| 包 | 用途 |
|
|
||||||
|----|------|
|
|
||||||
| `utility/convert` | 数据类型转换 |
|
|
||||||
| `utility/encrypt` | 加密/解密 |
|
|
||||||
| `utility/excel` | 电子表格导出/导入(导出接口用此包) |
|
|
||||||
| `utility/validate` | 数据验证工具 |
|
|
||||||
| `utility/tree` | 树形结构处理 |
|
|
||||||
| `utility/simple` | 简捷函数集合 |
|
|
||||||
| `utility/format` | 数据格式化 |
|
|
||||||
|
|
||||||
**前端(`web/src/utils/`)优先使用已有工具:**
|
|
||||||
|
|
||||||
| 工具 | 用途 |
|
|
||||||
|------|------|
|
|
||||||
| `@/utils/http/axios`(`http.request`) | HTTP 请求,**唯一入口** |
|
|
||||||
| `@/utils/dateUtil`(`defRangeShortcuts`) | 日期范围快捷选项 |
|
|
||||||
| `@/utils`(`renderImage`、`renderFile`、`renderPopoverMemberSumma`) | 表格渲染工具函数 |
|
|
||||||
| `@/store/modules/dict`(`useDictStore`) | 字典数据加载与渲染 |
|
|
||||||
| `@/hooks/web/usePermission`(`hasPermission`) | 权限判断 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 树表(Tree CRUD)特殊约定
|
|
||||||
|
|
||||||
树表在普通 CRUD 基础上有以下差异:
|
|
||||||
|
|
||||||
- 表中必须含 `pid`、`level`、`tree` 字段(参见建表约定)
|
|
||||||
- `pid`/`level`/`tree` 字段**由系统自动维护**,禁止在编辑表单中手动设置这三个字段
|
|
||||||
- 前端列表页使用树形表格(`BasicTable` 的 `childrenKey` 或 `treeData` 模式),而非普通分页列表
|
|
||||||
- 参考实现:`server/internal/logic/sys/tree_demo.go`、`web/src/views/develop/curd/treeDemo/`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 响应格式约定
|
|
||||||
|
|
||||||
所有接口统一响应格式(由框架中间件自动处理,**无需在 controller 手动包装**):
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "code": 0, "message": "操作成功", "timestamp": 1234567890, "traceID": "xxx", "data": {} }
|
|
||||||
```
|
|
||||||
|
|
||||||
- 成功状态码:`0`;失败状态码:`-1`(GoFrame 内置,无需手动设置)
|
|
||||||
- `gerror.Wrap(err, "用户友好的提示")` → 客户端只看到最外层提示,开发者日志可见完整堆栈
|
|
||||||
- 禁止在 controller 层手动 `Write`/`WriteJSON` 等直接写响应(破坏统一格式)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 常见错误禁止清单
|
|
||||||
|
|
||||||
**后端:**
|
|
||||||
- 禁止在 controller 层直接调用 dao
|
|
||||||
- 禁止硬编码字段名字符串(用 `dao.Table.Columns().Field`)
|
|
||||||
- 禁止手改 `entity/`、`do/`、`dao/internal/` 目录下的文件
|
|
||||||
- 禁止在 logic 层重复做 `Filter()` 已完成的校验
|
|
||||||
- 禁止在 `internal/service/sys.go` 之外新建主模块 service 文件(同文件追加)
|
|
||||||
- 禁止插件 import 另一个插件的包(插件间完全隔离,通过主模块 service 通信)
|
|
||||||
- 禁止在插件路由文件里硬编码路由前缀(用 `addons.RouterPrefix()` 生成)
|
|
||||||
- 禁止在 `internal/library/` 下修改基础库(如需扩展,提 issue 或在 utility/ 添加)
|
|
||||||
|
|
||||||
**前端:**
|
|
||||||
- 禁止直接使用 axios,必须用 `http.request`
|
|
||||||
- 禁止硬编码字典值文本,必须用 `dict.getLabel()` 渲染
|
|
||||||
- 禁止引入 Naive UI 以外的 UI 框架
|
|
||||||
- 禁止内联 style
|
|
||||||
- 禁止在源码里硬编码菜单路由路径
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
FROM node:20-alpine AS web-build
|
|
||||||
|
|
||||||
WORKDIR /web
|
|
||||||
RUN corepack enable && corepack prepare pnpm@10.18.3 --activate
|
|
||||||
COPY web/package.json web/pnpm-lock.yaml web/pnpm-workspace.yaml ./
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
COPY web/ ./
|
|
||||||
RUN pnpm run build
|
|
||||||
|
|
||||||
FROM golang:1.24-alpine AS server-build
|
|
||||||
|
|
||||||
WORKDIR /src
|
|
||||||
COPY server/go.mod server/go.sum ./
|
|
||||||
RUN go mod download
|
|
||||||
RUN go install github.com/gogf/gf/cmd/gf/v2@v2.10.0
|
|
||||||
COPY server/ ./
|
|
||||||
COPY --from=web-build /web/dist/ ./resource/public/admin/
|
|
||||||
RUN gf pack resource internal/packed/packed.go --keepPath=true \
|
|
||||||
&& CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/hotgo .
|
|
||||||
|
|
||||||
FROM alpine:3.22
|
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates tzdata \
|
|
||||||
&& addgroup -S hotgo \
|
|
||||||
&& adduser -S -G hotgo hotgo
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=server-build /out/hotgo /app/hotgo
|
|
||||||
COPY --from=server-build /src/manifest /app/manifest
|
|
||||||
COPY --from=server-build /src/resource /app/resource
|
|
||||||
COPY --from=web-build /web/dist/ /app/resource/public/admin/
|
|
||||||
RUN mkdir -p /app/storage /app/logs \
|
|
||||||
&& chown -R hotgo:hotgo /app
|
|
||||||
USER hotgo
|
|
||||||
EXPOSE 8000
|
|
||||||
ENTRYPOINT ["/app/hotgo"]
|
|
||||||
CMD ["all"]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2021-present HotGo
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@@ -1,167 +1,2 @@
|
|||||||
# HotGo-V2
|
# olons_admin
|
||||||
<div align="center">
|
|
||||||
<img width="140px" src="https://gmycos.facms.cn/hotgo/logo.sig.png">
|
|
||||||
<p>
|
|
||||||
<h1>HotGo V2</h1>
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://goframe.org/pages/viewpage.action?pageId=1114119" target="_blank">
|
|
||||||
<img src="https://img.shields.io/badge/goframe-2.10.0-green" alt="goframe">
|
|
||||||
</a>
|
|
||||||
<a href="https://v3.vuejs.org/" target="_blank">
|
|
||||||
<img src="https://img.shields.io/badge/vue.js-vue3.4-green" alt="vue">
|
|
||||||
</a>
|
|
||||||
<a href="https://www.naiveui.com" target="_blank">
|
|
||||||
<img src="https://img.shields.io/badge/naiveui-%3E2.44.1-blue" alt="naiveui">
|
|
||||||
</a>
|
|
||||||
<a href="https://www.tslang.cn/" target="_blank">
|
|
||||||
<img src="https://img.shields.io/badge/typescript-%3E4.0.0-blue" alt="typescript">
|
|
||||||
</a>
|
|
||||||
<a href="https://vitejs.dev/" target="_blank">
|
|
||||||
<img src="https://img.shields.io/badge/vite-%3E5.4.2-yellow" alt="vite">
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/bufanyun/hotgo/blob/v2.0/LICENSE" target="_blank">
|
|
||||||
<img src="https://img.shields.io/badge/license-MIT-success" alt="license">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
## 平台简介
|
|
||||||
* 基于 GoFrame2 + Vue3 + NaiveUI + uniapp 的企业级全栈框架,为二次开发而生。
|
|
||||||
* 前端采用 Naive-Ui-Admin、Vue、Naive UI、uniapp。
|
|
||||||
* 企业级 AI 赋能基础开发平台,内置 AI 开发规范,适配主流 AI 开发工具,实现人机协同开发,大幅提升开发效率。
|
|
||||||
|
|
||||||
## 演示地址
|
|
||||||
- [https://hotgo.facms.cn/admin](https://hotgo.facms.cn/admin)
|
|
||||||
> 账号:admin 密码:123456
|
|
||||||
|
|
||||||
### 使用文档
|
|
||||||
|
|
||||||
[安装文档](docs/guide-zh-CN/start-installation.md) · [本地文档](docs/guide-zh-CN/README.md) · [更新历史](docs/guide-zh-CN/start-update-log.md) · [常见问题](docs/guide-zh-CN/start-issue.md)
|
|
||||||
|
|
||||||
|
|
||||||
## 特征
|
|
||||||
* 高生产率:极强的可扩展性,应用化、模块化、插件化机制敏捷开发,几分钟即可搭建一个应用开发骨架。
|
|
||||||
* 多应用入口:多入口分为 Admin (后台)、Home (前台页面)、Api (对外通用接口)、WebSocket (即时通讯接口),不同的业务,进入不同的应用入口。
|
|
||||||
* 极致的插件化: 微核架构,功能隔离,高可定制性,可以渐进式开发,亦可以多人协同开发。支持一键创建插件模板、一键安装、更新、卸载插件、可以非常方便的将插件迁移到新项目中。
|
|
||||||
* 快速生成代码:无需编写代码,只需创建表进行简单配置就能生成一个完善的 CURD、树表等常用的开发代码,其中所需表单控件也是勾选即可直接生成。
|
|
||||||
* 认证机制:采用 JWT 的用户状态认证及 casbin 的权限认证
|
|
||||||
* 路由模式:得益于 GoFrame 提供了规范化的路由注册方式,无需注解自动生成api文档
|
|
||||||
* 模块化设计,面向接口开发
|
|
||||||
|
|
||||||
|
|
||||||
## 内置功能
|
|
||||||
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
|
||||||
2. 部门管理:配置系统组织机构(公司、部门、岗位),树结构展现支持数据权限。
|
|
||||||
3. 岗位管理:配置系统用户所属担任职务。
|
|
||||||
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
|
|
||||||
5. 角色管理:角色菜单权限分配、设置角色按机构或按上下级关系进行数据范围权限划分。
|
|
||||||
6. 字典管理:对系统中经常使用的一些特定数据进行维护,支持枚举字典和自定义方法字典。
|
|
||||||
7. 配置管理:对系统动态配置常用参数。
|
|
||||||
8. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
|
||||||
9. 登录日志:系统登录日志记录查询包含登录异常。
|
|
||||||
10. 服务日志:服务端运行所产生的警告、异常、崩溃日志的详细数据和堆栈信息。
|
|
||||||
11. 支付网关:集成支付宝、微信支付、QQ支付等多种支付方式,只需简单配置即可使用。
|
|
||||||
12. 资金管理:支持在线充值、订单申请/原路退款、资金提现、资金/积分变动明细等通用模块。
|
|
||||||
13. 在线用户:当前系统中活跃用户状态监控。
|
|
||||||
14. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
|
|
||||||
15. 代码生成:支持自动化生成前后端代码。CURD关联表、树表、消息队列、定时任务一键生成等。
|
|
||||||
16. 插件应用:支持一键生成插件模板,每个插件之间开发隔离,拥有独立多应用入口、独立配置。完美支持多人协同开发、插件插拔不会对原系统产生影响等。
|
|
||||||
17. 服务监控:监视当前系统CPU、内存、磁盘、网络、堆栈等相关信息。
|
|
||||||
18. 附件管理:文件图片上传,大文件分片上传、断点续传,支持本地、阿里云oss、腾讯云cos、ucloud对象存储、七牛云对象存储、minio等多种上传驱动,后台一键切换配置,并集成了文件选择器。
|
|
||||||
19. TCP服务:基于gtcp的服务应用,支持长连接、断线重连、服务认证、路由分发、RPC消息、拦截器和数据绑定等。简化和规范了服务器开发流程。
|
|
||||||
20. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
|
|
||||||
21. 通知公告:采用WebSocket实时推送在线用户最新通知、公告、私信消息。
|
|
||||||
22. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
|
|
||||||
23. 常用工具:集成常用的工具包和命令行工具,可以快速开发自定义命令行,多种启动入口。
|
|
||||||
|
|
||||||
|
|
||||||
> HotGo开源以来得到了大家的很多支持,本项目初衷只为互相学习交流,没有任何盈利性目的!欢迎为HotGo贡献代码或提供建议!
|
|
||||||
|
|
||||||
|
|
||||||
## 演示图
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/1.png"/></td>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/2.png"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/3.png"/></td>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/4.png"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/5.png"/></td>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/6.png"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/7.png"/></td>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/8.png"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/9.png"/></td>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/10.png"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/11.png"/></td>
|
|
||||||
<td><img src="./docs/guide-zh-CN/images/demo/12.png"/></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
## 感谢(排名不分先后)
|
|
||||||
> gf框架 [https://github.com/gogf/gf](https://github.com/gogf/gf)
|
|
||||||
>
|
|
||||||
> naive-ui [https://www.naiveui.com](https://www.naiveui.com)
|
|
||||||
>
|
|
||||||
> naive-ui-admin [https://github.com/jekip/naive-ui-admin](https://github.com/jekip/naive-ui-admin)
|
|
||||||
>
|
|
||||||
> websocket [https://github.com/gorilla/websocket](github.com/gorilla/websocket)
|
|
||||||
>
|
|
||||||
> casbin [https://github.com/casbin/casbin](https://github.com/casbin/casbin)
|
|
||||||
>
|
|
||||||
> gopay [https://github.com/go-pay/gopay](https://github.com/go-pay/gopay)
|
|
||||||
|
|
||||||
|
|
||||||
## 交流QQ群
|
|
||||||
交流群①:190966648 <a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=mJafkvme3VNyiQlCFIFNRtY8Xlr7pj9U&jump_from=webapi&authKey=jL10vIESr+vO8wpxwyd6DlChzkrbHpzN9uhAsIHgAinL/Vvd+nvuRyilf2UqUlCy"><img border="0" src="https://gmycos.facms.cn/hotgo/group.png" alt="HotGo框架交流1群" title="HotGo框架交流1群"></a>
|
|
||||||
> <img src="https://gmycos.facms.cn/hotgo/hotgo1qun.png" width="400px"/>
|
|
||||||
|
|
||||||
|
|
||||||
## 商用说明
|
|
||||||
|
|
||||||
> HotGo 是开源免费的,遵循 MIT 开源协议,意味着您无需支付任何费用,也无需授权,即可将它应用到您的产品中。
|
|
||||||
|
|
||||||
* 使用本项目必须保留所有版权信息。
|
|
||||||
|
|
||||||
* 本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
|
||||||
|
|
||||||
* 版权所有Copyright © 2020-2026 by Ms (https://github.com/bufanyun/hotgo)
|
|
||||||
|
|
||||||
* All rights reserved。
|
|
||||||
|
|
||||||
|
|
||||||
## 免责声明:
|
|
||||||
* HotGo为开源学习项目,一切商业行为与HotGo无关。
|
|
||||||
|
|
||||||
* 用户不得利用HotGo从事非法行为,用户应当合法合规的使用,发现用户在使用产品时有任何的非法行为,HotGo有权配合有关机关进行调查或向政府部门举报,HotGo不承担用户因非法行为造成的任何法律责任,一切法律责任由用户自行承担,如因用户使用造成第三方损害的,用户应当依法予以赔偿。
|
|
||||||
|
|
||||||
* 所有与使用HotGo相关的资源直接风险均由用户承担。
|
|
||||||
|
|
||||||
|
|
||||||
#### 如果对您有帮助,您可以点右上角 💘Star💘支持
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [感谢JetBrains提供的免费GoLand](https://jb.gg/OpenSource)
|
|
||||||
[](https://jb.gg/OpenSource)
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
|
||||||
[MIT © HotGo-2026](./LICENSE)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,864 +0,0 @@
|
|||||||
# Olons 全功能测试用例
|
|
||||||
|
|
||||||
> 文档版本:V1.1
|
|
||||||
> 编制日期:2026-10-16
|
|
||||||
> 覆盖范围:Olons C 端、HotGo 管理后台、业务 API、数据库一致性、客服 IM 及跨端业务闭环
|
|
||||||
> 代码基线:`olons_server` 与 `olons_admin` 当前工作区实现
|
|
||||||
> 用途:测试执行、联调验收、发布前回归和缺陷复测
|
|
||||||
|
|
||||||
## 1. 测试目标与范围
|
|
||||||
|
|
||||||
本用例集以当前代码路由、服务端校验、页面按钮和后台菜单为准,重点验证以下内容:
|
|
||||||
|
|
||||||
- C 端注册登录、首页、领取、订单、商城、储入、取出、个人中心、内容页和在线客服。
|
|
||||||
- 后台首页、门户、会员、等级、任务大厅、交易、商品、任务、组织、权限、系统应用和系统设置。
|
|
||||||
- 后台配置、审核及上下架操作对 C 端展示和业务状态的实时影响。
|
|
||||||
- 金额、字符长度、文件大小、分页、时间窗口、次数限制等边界值。
|
|
||||||
- 未登录、越权、重复提交、并发、超时、断网、服务异常及脏数据场景。
|
|
||||||
- 钱包余额、冻结额、业务单、账变流水、审核记录和状态机的一致性。
|
|
||||||
- Olons 与 118IM 之间的账号创建、好友关系、会话、文本及媒体消息链路。
|
|
||||||
|
|
||||||
本轮不包含第三方真实支付清算、短信供应商实发、压力容量定标和渗透测试,但保留相应接口降级与安全验收项。
|
|
||||||
|
|
||||||
当前共 548 条用例,其中页面逐项验收 188 条(通用页面 8 条、C 端页面 90 条、后台页面 90 条),其余 360 条用于补充业务规则、接口、安全、数据一致性和跨端闭环。执行时应先完成第 4 章页面用例,再执行对应模块的深层用例。
|
|
||||||
|
|
||||||
## 2. 测试依据
|
|
||||||
|
|
||||||
| 类型 | 依据 |
|
|
||||||
| --- | --- |
|
|
||||||
| C 端路由 | `olons_server/web/src/router/index.ts` |
|
|
||||||
| C 端接口 | `olons_server/internal/httpapi/` |
|
|
||||||
| C 端业务规则 | `olons_server/internal/accounts`、`finance`、`tasks`、`mall`、`support`、`attachments` |
|
|
||||||
| 后台页面 | `olons_admin/web/src/views/` |
|
|
||||||
| 后台接口 | `olons_admin/server/api/admin/`、`server/internal/logic/sys/` |
|
|
||||||
| 菜单与初始化 | `olons_admin/server/storage/data/migrations/`、`seeds/` |
|
|
||||||
| 产品基线 | `后台管理系统需求文档.md`、`后台管理系统概要设计.md`、`后台功能与数据库表映射.md` |
|
|
||||||
| IM 对接 | `olons_server/docs/IM-前后端对接文档.md`、`Olons-客服IM系统对接设计.md` |
|
|
||||||
|
|
||||||
## 3. 执行约定
|
|
||||||
|
|
||||||
### 3.1 优先级
|
|
||||||
|
|
||||||
| 优先级 | 定义 | 发布要求 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| P0 | 登录、资金、权限、订单结算、数据泄露等核心链路 | 必须 100% 通过 |
|
|
||||||
| P1 | 主要业务功能及重要异常分支 | 不得存在阻断性缺陷 |
|
|
||||||
| P2 | 次要功能、显示、兼容和易用性 | 可评估后带已知问题发布 |
|
|
||||||
|
|
||||||
### 3.2 通用前置条件
|
|
||||||
|
|
||||||
- 浏览器时间、服务端时间和数据库时间同步,业务时区按 Asia/Shanghai 验证。
|
|
||||||
- 准备独立测试租户,禁止在生产真实会员上执行资金、删除、禁用和权限用例。
|
|
||||||
- 每个资金用例执行前记录钱包 `available_amount`、`frozen_amount`、`version` 和最近流水。
|
|
||||||
- 每个配置联动用例记录配置版本号、发布时间及 C 端接口响应,执行后恢复原配置。
|
|
||||||
- 所有 API 写请求记录 `request_id`;幂等接口记录幂等键、业务单号及返回结果。
|
|
||||||
|
|
||||||
### 3.3 测试账号与数据矩阵
|
|
||||||
|
|
||||||
| 数据代号 | 准备要求 |
|
|
||||||
| --- | --- |
|
|
||||||
| U-NORMAL | 正常真人会员,已设置登录密码和交易密码,已绑已验证收款账户,余额充足 |
|
|
||||||
| U-NEW | 新注册会员,无交易密码、无收款账户、无订单 |
|
|
||||||
| U-LOW | 可用余额低于领取/提现下限 |
|
|
||||||
| U-LIMIT | 当日领取次数或提现次数已达到等级上限 |
|
|
||||||
| U-PENDING | 存在匹配中或待处理订单 |
|
|
||||||
| U-DISABLED | 会员状态禁用或钱包状态禁用 |
|
|
||||||
| U-FAKE | 假人类别会员,用于统计隔离验证 |
|
|
||||||
| U-MANUAL | 派单模式为手动 |
|
|
||||||
| U-AUTO | 派单模式为自动 |
|
|
||||||
| URL-ENABLED | 地址池中的启用地址,域名未绑定或已绑定少量会员 |
|
|
||||||
| URL-INVALID | 地址池中的失效地址,保留历史绑定会员 |
|
|
||||||
| URL-UNKNOWN | 未录入地址池的注册域名,用于验证注册成功但不建立绑定 |
|
|
||||||
| XLS-URL | 地址池导入文件,包含合法、重复、非法 URL、空值和超长数据 |
|
|
||||||
| A-SUPER | 超级管理员,拥有全部菜单和按钮权限 |
|
|
||||||
| A-PARENT | 父角色管理员,只有部分业务菜单 |
|
|
||||||
| A-CHILD | A-PARENT 的子角色,权限必须为父角色子集 |
|
|
||||||
| A-CS/A-FIN/A-OPS | 客服、财务、运营最小权限账号 |
|
|
||||||
| P-ON/P-OFF | 已发布商品/已下架商品 |
|
|
||||||
| T-ON/T-OFF | 已发布任务/已下线任务 |
|
|
||||||
| IM-3 | 客服依依、客服琪琪、客服琳琳,均已绑定 IM 用户及头像 |
|
|
||||||
|
|
||||||
## 4. 页面逐项验收主用例
|
|
||||||
|
|
||||||
本章是测试人员的主要执行入口,按照“进入页面 → 检查默认展示 → 操作页面控件 → 检查弹窗 → 验证成功/失败反馈 → 返回或刷新”的顺序执行。后续章节用于补充接口、状态机、并发和数据一致性,不应替代本章的页面操作。
|
|
||||||
|
|
||||||
### 4.1 每个页面都必须执行的八项检查
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-COM-001 | P1 | 从菜单、快捷入口或站内链接进入页面 | 路由、页面标题、面包屑和菜单高亮正确 |
|
|
||||||
| UI-COM-002 | P1 | 首次进入页面并观察加载过程 | 有加载反馈;加载结束后不会永久转圈或闪烁 |
|
|
||||||
| UI-COM-003 | P1 | 检查页面全部文字、金额、时间、图片、状态标签 | 无错别字、乱码、单位错误、破图或状态空白 |
|
|
||||||
| UI-COM-004 | P1 | 逐个点击页面可见按钮、链接、图标和表格行 | 每个控件均有响应,目标页面或弹窗正确 |
|
|
||||||
| UI-COM-005 | P1 | 打开弹窗后测试右上角关闭、取消、遮罩和 Esc | 按约定关闭;未保存内容不产生后台写入 |
|
|
||||||
| UI-COM-006 | P1 | 对页面输入框执行空值、合法值、边界值和非法值 | 校验位置与文案明确,错误输入不能提交 |
|
|
||||||
| UI-COM-007 | P1 | 模拟空数据、接口失败、超时和无权限 | 分别显示空态、错误态、重试或无权限提示 |
|
|
||||||
| UI-COM-008 | P2 | 刷新、后退、前进、切换标签页和改变窗口宽度 | 页面不白屏;数据和布局按约定恢复 |
|
|
||||||
|
|
||||||
### 4.2 C 端页面逐项测试
|
|
||||||
|
|
||||||
#### 4.2.1 登录与注册页 `/app/auth`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-AUTH-001 | P1 | 打开登录页 | 仅显示账号登录/注册业务控件,不出现微信、抖音、手机号登录和演示角色入口 |
|
|
||||||
| UI-C-AUTH-002 | P1 | 点击“账号登录”“注册账号”“已有账户,马上登录” | 登录与注册表单正确切换,已有输入按页面约定保留或清空 |
|
|
||||||
| UI-C-AUTH-003 | P1 | 登录模式检查手机号、密码框和密码显隐图标 | 占位符、输入类型、显隐切换和键盘类型正确 |
|
|
||||||
| UI-C-AUTH-004 | P0 | 输入合法账号并点击“登录” | 按钮显示“请稍候”并禁用,成功进入原目标页 |
|
|
||||||
| UI-C-AUTH-005 | P1 | 输入错误账号并点击“登录” | 页面停留,错误提示清楚,密码不明文残留在日志或 URL |
|
|
||||||
| UI-C-AUTH-006 | P1 | 注册模式检查姓名、手机号、密码、邀请码、协议勾选框 | 字段与当前注册规则一致,邀请码和协议为必填 |
|
|
||||||
| UI-C-AUTH-007 | P0 | 未勾选协议点击“注册” | 页面阻止注册并定位协议区域 |
|
|
||||||
| UI-C-AUTH-008 | P1 | 点击隐私协议/用户协议链接后返回 | 内容页可读,返回后注册表单状态合理保留 |
|
|
||||||
|
|
||||||
#### 4.2.2 首页 `/app/home`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-HOME-001 | P1 | 打开首页并等待加载完成 | 顶部信息、Banner、快捷功能、滚动信息、内容入口和底部导航完整显示 |
|
|
||||||
| UI-C-HOME-002 | P1 | 左右滑动 Banner、点击圆点和 Banner 本体 | 切换流畅;有效跳转正确;无跳转 Banner 不误跳 |
|
|
||||||
| UI-C-HOME-003 | P1 | 点击搜索框 | 进入商城或约定搜索页面,返回首页位置正确 |
|
|
||||||
| UI-C-HOME-004 | P0 | 依次点击“领取、储入、取出、商城” | 分别进入领取、储入、取出、商城页面 |
|
|
||||||
| UI-C-HOME-005 | P1 | 后台关闭四个功能后检查对应入口 | 置灰且无法进入;置灰文字仍可辨识 |
|
|
||||||
| UI-C-HOME-006 | P1 | 点击平台介绍、规则说明、公司资质、代理合作 | 均进入正确内容页,标题和正文相符 |
|
|
||||||
| UI-C-HOME-007 | P1 | 点击滚动公告/弹窗通知 | 展开对应详情,不跳到错误会员或订单页面 |
|
|
||||||
| UI-C-HOME-008 | P1 | 点击底部“首页、记录、领取、客服、我的” | 五个页面均可达,当前项高亮正确 |
|
|
||||||
|
|
||||||
#### 4.2.3 领取页 `/app/claim`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-CLAIM-001 | P1 | 打开领取页 | 总资产、昨日佣金、今日佣金、今日领取数和领取主按钮完整显示 |
|
|
||||||
| UI-C-CLAIM-002 | P0 | 满足条件时点击领取主按钮 | 按钮进入加载态,不能重复点击;随后展示匹配结果 |
|
|
||||||
| UI-C-CLAIM-003 | P1 | 不满足余额/等级/营业时间/次数条件时点击领取 | 弹层显示对应原因,不出现笼统“失败” |
|
|
||||||
| UI-C-CLAIM-004 | P1 | 有在途订单时点击“查看任务” | 进入该订单详情,不新建第二张订单 |
|
|
||||||
| UI-C-CLAIM-005 | P1 | 匹配中观察进度、等待和倒计时区域 | 状态能刷新,离开再返回仍能恢复当前订单 |
|
|
||||||
| UI-C-CLAIM-006 | P1 | 结果失败时点击“重新领取” | 重新检查资格;按钮加载态和结果更新正确 |
|
|
||||||
| UI-C-CLAIM-007 | P1 | 点击“稍后去记录查看”“查看记录”“返回首页” | 分别进入订单列表、订单详情或首页 |
|
|
||||||
|
|
||||||
#### 4.2.4 订单列表与详情 `/app/orders`、`/app/orders/:id`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-ORDER-001 | P1 | 打开订单列表 | 默认标签、订单卡片、状态、金额、商品图和时间正确 |
|
|
||||||
| UI-C-ORDER-002 | P1 | 依次点击“全部、待处理、已完成” | 列表只显示对应订单;无数据时显示空态 |
|
|
||||||
| UI-C-ORDER-003 | P1 | 点击任一订单卡片 | 进入该订单详情,订单号和列表所选记录一致 |
|
|
||||||
| UI-C-ORDER-004 | P1 | 详情页检查商品、金额、佣金、状态、时间线和流水 | 字段完整,长文本/图片不撑破布局 |
|
|
||||||
| UI-C-ORDER-005 | P0 | 可提交的手动订单点击“提交确认” | 打开二次确认弹窗,金额和提示与当前订单一致 |
|
|
||||||
| UI-C-ORDER-006 | P1 | 在确认弹窗点击“暂不提交”、关闭和遮罩 | 弹窗关闭,订单和余额不变 |
|
|
||||||
| UI-C-ORDER-007 | P0 | 点击“确认提交” | 按钮防重复;成功提示、状态和余额立即更新 |
|
|
||||||
| UI-C-ORDER-008 | P1 | 余额不足时查看按钮并尝试提交 | 按钮显示“余额不足,无法提交”或引导储入,不错误扣款 |
|
|
||||||
| UI-C-ORDER-009 | P1 | 冻结、超时、取消、失败订单进入详情 | 不显示不允许的提交按钮,提供客服入口或明确说明 |
|
|
||||||
| UI-C-ORDER-010 | P1 | 点击详情返回按钮和浏览器后退 | 返回原列表及原标签位置 |
|
|
||||||
|
|
||||||
#### 4.2.5 商城列表与详情 `/app/mall`、`/app/mall/:id`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-MALL-001 | P1 | 打开商城 | 搜索框、搜索按钮、推荐任务/限时任务标签和商品卡片显示完整 |
|
|
||||||
| UI-C-MALL-002 | P1 | 输入关键词后点击“搜索”及清空关键词重搜 | 结果按关键词过滤,清空后恢复全部 |
|
|
||||||
| UI-C-MALL-003 | P1 | 切换“推荐任务”“限时任务” | 商品集合和按钮文字同步变化,无重复或串页 |
|
|
||||||
| UI-C-MALL-004 | P1 | 点击商品图片、名称、“领取/抢单” | 均进入同一商品详情 |
|
|
||||||
| UI-C-MALL-005 | P1 | 详情页检查图片、名称、店铺、价格、说明、时限 | 与后台发布内容一致,富文本安全显示 |
|
|
||||||
| UI-C-MALL-006 | P1 | 商品已下架或过期时刷新详情 | 显示不可用状态,不允许继续领取 |
|
|
||||||
|
|
||||||
#### 4.2.6 储入页 `/app/recharge`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-RC-001 | P1 | 打开储入页 | 储入方式、金额、姓名和提交按钮完整显示 |
|
|
||||||
| UI-C-RC-002 | P1 | 展开“储入方式”下拉并逐项选择 | 只列启用渠道;所选值和渠道提示同步更新 |
|
|
||||||
| UI-C-RC-003 | P1 | 金额留空、越界、输入字母后点击提交 | 页面在金额字段提示,不发起有效订单 |
|
|
||||||
| UI-C-RC-004 | P1 | 姓名留空或输入超长内容 | 阻止提交并显示字段错误 |
|
|
||||||
| UI-C-RC-005 | P0 | 填写合法数据点击“提交” | 按钮显示提交中并禁用;成功提示后跳转客服中心 |
|
|
||||||
| UI-C-RC-006 | P1 | 接口失败后观察页面 | 不跳客服;表单可修改并重新提交 |
|
|
||||||
|
|
||||||
#### 4.2.7 取出页 `/app/profile/withdrawal`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-WD-001 | P1 | 打开取出页 | 可用余额、金额输入、全部提现、收款账户和申请按钮显示完整 |
|
|
||||||
| UI-C-WD-002 | P1 | 点击“全部提现” | 输入框填入当前可用余额;如超过渠道上限,报价时明确提示而不创建取出单 |
|
|
||||||
| UI-C-WD-003 | P1 | 查看收款账户区域并点击 | 有已核验账户时显示银行及尾号;无账户时进入绑定信息页 |
|
|
||||||
| UI-C-WD-004 | P1 | 输入合法金额点击“申请提现” | 出现确认弹窗,申请金额、手续费和预计到账金额与报价一致 |
|
|
||||||
| UI-C-WD-005 | P1 | 未设置支付密码点击“去设置支付密码”,填写 6 位数字密码和正确登录密码后点击“确认设置” | 原弹窗切换为设置表单;设置成功返回确认申请界面并保留报价,不自动提交取出单 |
|
|
||||||
| UI-C-WD-006 | P1 | 分别在确认取出和设置支付密码界面点击右上角关闭叉号;重新打开后点击“返回确认申请” | 两种界面均可关闭;密码输入被清空、未创建取出单;返回确认时保留报价且仍需再次点击“确认申请” |
|
|
||||||
| UI-C-WD-007 | P0 | 输入支付密码并点击“确认申请” | 加载态防重复;成功关闭弹层并更新余额/记录 |
|
|
||||||
| UI-C-WD-008 | P1 | 密码错误、次数受限、报价过期 | 分别显示明确提示,弹窗状态可恢复或重新报价 |
|
|
||||||
| UI-C-WD-009 | P1 | 未设置支付密码时查看“确认申请”,或设置时输入非 6 位密码/错误登录密码 | 未设置时确认按钮不可提交;格式错误在本地提示,接口失败后保留设置界面且不创建取出单 |
|
|
||||||
| UI-C-WD-010 | P1 | 设置或提交请求进行中连续点击关闭叉号与主按钮 | 请求期间关闭和重复提交被禁止;请求结束后可按状态继续操作 |
|
|
||||||
|
|
||||||
#### 4.2.8 我的页面 `/app/profile`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-ME-001 | P1 | 打开“我的” | 用户名、邀请码、账户余额及功能菜单完整显示 |
|
|
||||||
| UI-C-ME-002 | P2 | 点击邀请码复制按钮 | 显示复制成功,剪贴板内容为当前邀请码 |
|
|
||||||
| UI-C-ME-003 | P0 | 点击“立即取出”“立即储入” | 分别进入取出和储入页面 |
|
|
||||||
| UI-C-ME-004 | P1 | 点击个人信息、储入记录、取出记录、账户明细、弹窗明细 | 五个入口分别进入正确页面 |
|
|
||||||
| UI-C-ME-005 | P1 | 点击“退出登录”后点击取消 | 弹窗关闭并保持登录 |
|
|
||||||
| UI-C-ME-006 | P0 | 点击“退出登录”后点击确定 | 清除会话并进入登录页,后退不能看到有效敏感页面 |
|
|
||||||
|
|
||||||
#### 4.2.9 个人信息、银行卡与密码页面
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-FORM-001 | P1 | 打开个人信息页 | 头像、本人手机号、取出信息、密码管理、支付密码管理按原型分组展示;头像行和三个入口均可点击 |
|
|
||||||
| UI-C-FORM-002 | P1 | 点击头像行选择合法图片,等待上传完成并刷新页面 | 文件选择器可打开;图片先上传附件再更新本人头像,成功提示且刷新后仍显示新头像 |
|
|
||||||
| UI-C-FORM-003 | P1 | 打开绑定信息页 | 已绑定账户先显示本人原始信息;新增表单的姓名、身份证、卡号、开户行、选填数字人民币编码、微信码、支付宝码字段齐全 |
|
|
||||||
| UI-C-FORM-004 | P1 | 点击两处“点击上传”并分别选图 | 上传中、预览和失败重试状态正确,两张图不会串位 |
|
|
||||||
| UI-C-FORM-005 | P0 | 填完银行卡信息点击“确认绑定” | 按钮防重复;成功后从个人信息进入的返回个人信息,从取出进入的返回取出;本人绑定信息页显示原文,通用账户列表仍脱敏 |
|
|
||||||
| UI-C-FORM-006 | P1 | 打开修改登录密码页并点击“确定修改” | 当前密码、新密码、确认密码校验正确,成功后给出明确反馈 |
|
|
||||||
| UI-C-FORM-007 | P1 | 新密码和确认密码不一致 | 页面本地拦截,不请求修改接口 |
|
|
||||||
| UI-C-FORM-008 | P1 | 打开支付密码页 | 新支付密码、登录密码、已设置时的旧支付密码展示逻辑正确 |
|
|
||||||
| UI-C-FORM-009 | P0 | 填写合法信息点击“确定” | 按钮防重复,成功后返回且支付密码状态更新 |
|
|
||||||
| UI-C-FORM-010 | P0 | 点击个人信息中的“取出信息”查看已绑定账户 | 本人姓名、身份证号、银行名、完整银行卡号、已填的数字人民币编码和两张收款码图片正确展示,不以星号替代原值 |
|
|
||||||
| UI-C-FORM-011 | P1 | 无绑定账户或有多张账户时打开取出信息 | 无账户时可直接新增;多账户逐条对应展示,不串姓名、卡号和收款码 |
|
|
||||||
| UI-C-FORM-012 | P1 | 数字人民币编码留空后提交绑卡 | 页面不把该字段当必填;成功后详情不出现伪造的编码,其他必填项仍正常校验 |
|
|
||||||
| UI-C-FORM-013 | P1 | 头像选择 GIF、伪装扩展名、超过 5MB 图片,或模拟上传/更新接口失败 | 明确提示失败;旧头像不变,可重新选择文件重试 |
|
|
||||||
|
|
||||||
#### 4.2.10 记录、账变、通知和内容页
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-REC-001 | P1 | 从“储入记录”进入并切换记录标签 | 默认定位储入,状态、金额和时间正确 |
|
|
||||||
| UI-C-REC-002 | P1 | 从“取出记录”进入并切换记录标签 | 默认定位取出,手续费、实到和原因正确 |
|
|
||||||
| UI-C-REC-003 | P1 | 点击记录行查看详情 | 进入对应订单详情或展开详情,记录 ID 不串行 |
|
|
||||||
| UI-C-REC-004 | P1 | 账户明细筛选收入/支出并翻页 | 筛选和分页正确,前后余额可读 |
|
|
||||||
| UI-C-REC-005 | P1 | 弹窗明细打开未读通知并返回 | 正文可见,已读状态更新,列表位置合理保留 |
|
|
||||||
| UI-C-REC-006 | P1 | 平台介绍、规则、代理、资质和通用内容页点击返回 | 标题、正文和返回路径正确 |
|
|
||||||
|
|
||||||
#### 4.2.11 客服列表与聊天页 `/app/support`、`/app/support/:id`
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-C-CS-001 | P1 | 打开客服列表 | 三名客服名称、头像、在线/忙碌状态完整显示 |
|
|
||||||
| UI-C-CS-002 | P1 | 依次点击三个客服卡片并返回 | 分别进入对应会话,标题和头像不串客服 |
|
|
||||||
| UI-C-CS-003 | P1 | 连接失败时点击“重新连接” | 显示连接过程,成功恢复输入区;失败可再次操作 |
|
|
||||||
| UI-C-CS-004 | P1 | 输入文字,检查发送按钮显隐并点击 | 有文本时显示清晰的发送按钮;发送中禁用 |
|
|
||||||
| UI-C-CS-005 | P1 | 输入框为空时点击“+” | 展开表情、照片、视频工具;再次点击按约定收起 |
|
|
||||||
| UI-C-CS-006 | P1 | 点击“表情”并切换最近/表情/手势/物品 | 面板紧凑显示,选中表情插入输入框 |
|
|
||||||
| UI-C-CS-007 | P1 | 点击“照片”“视频”并取消系统文件选择 | 不发送空消息,工具区恢复可用 |
|
|
||||||
| UI-C-CS-008 | P0 | 选择合法照片或视频 | 显示上传进度,发送后本方气泡和客服端均可见 |
|
|
||||||
| UI-C-CS-009 | P1 | 点击图片、播放视频、滚动历史消息 | 预览/播放正常,滚动不遮挡底部输入区 |
|
|
||||||
| UI-C-CS-010 | P1 | 检查双方头像、左右气泡、时间和发送状态 | 客服在左、本人在右;头像及已发送/失败状态清楚 |
|
|
||||||
|
|
||||||
### 4.3 后台页面逐项测试
|
|
||||||
|
|
||||||
#### 4.3.1 后台登录与全局框架
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-A-FRAME-001 | P1 | 打开后台登录页 | 标题为“企业办公管理系统”,只显示账号登录表单 |
|
|
||||||
| UI-A-FRAME-002 | P0 | 填写账号密码点击登录 | 加载态防重复;成功进入首页,失败留在登录页 |
|
|
||||||
| UI-A-FRAME-003 | P1 | 逐个展开一级菜单 | 二级菜单、图标、顺序和折叠状态正确 |
|
|
||||||
| UI-A-FRAME-004 | P1 | 依次点击主页、会员、交易、商品、任务下全部二级菜单 | 每个菜单可打开,面包屑和标签页标题正确 |
|
|
||||||
| UI-A-FRAME-005 | P1 | 点击已打开标签、关闭单个、关闭其他、刷新标签 | 标签行为正确,不关闭固定首页 |
|
|
||||||
| UI-A-FRAME-006 | P1 | 点击全局菜单搜索并搜索页面名称 | 结果正确,点击进入目标页面 |
|
|
||||||
| UI-A-FRAME-007 | P1 | 点击右上角头像/个人中心/退出 | 个人中心可达;退出确认后回登录页 |
|
|
||||||
|
|
||||||
#### 4.3.2 首页与门户管理
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-A-HOME-001 | P1 | 打开主控台,逐个检查指标卡、图表和刷新 | 数据、单位、时间范围、刷新时间正确 |
|
|
||||||
| UI-A-HOME-002 | P1 | 点击可跳转指标卡 | 进入对应业务列表并携带正确筛选条件 |
|
|
||||||
| UI-A-SITE-001 | P1 | 打开网站设置,检查所有分组和默认值 | 品牌、交易、佣金、时段、门槛和开关字段完整回显 |
|
|
||||||
| UI-A-SITE-002 | P1 | 修改字段后点击保存/取消/重置 | 保存有反馈;取消/重置不写入;刷新结果符合选择 |
|
|
||||||
| UI-A-SITE-003 | P1 | 点击历史、提交、发布、回滚入口 | 对应列表/弹窗完整,按钮只在合法状态可用 |
|
|
||||||
| UI-A-TEXT-001 | P1 | 打开文本管理,使用查询、重置和分页 | 仅显示文本字段和 12 条初始化数据,内容标识列隐藏 |
|
|
||||||
| UI-A-TEXT-002 | P1 | 点击新增/编辑,检查弹窗和所有字段 | 弹窗足够宽,无图片字段,标题和正文可编辑 |
|
|
||||||
| UI-A-TEXT-003 | P1 | 点击确定、取消、关闭、发布、下线、删除 | 每个动作提示和列表刷新正确,危险动作有确认 |
|
|
||||||
| UI-A-BANNER-001 | P1 | 打开 Banner 设置并测试查询、添加、编辑 | 图片、位置、链接、时段、排序和状态字段齐全 |
|
|
||||||
| UI-A-BANNER-002 | P1 | 测试上传、预览、更换和移除图片 | 预览正确,取消不保存,失败可重试 |
|
|
||||||
| UI-A-BANNER-003 | P1 | 测试发布/下线/删除及确认弹窗 | 状态更新且 C 端同步,取消确认无副作用 |
|
|
||||||
| UI-A-MANUAL-001 | P1 | 打开手工商城并测试查询、添加、编辑 | 名称、价格、展示图片和时间字段完整 |
|
|
||||||
| UI-A-MANUAL-002 | P1 | 测试发布/下架/删除和分页 | 按钮状态与商品状态匹配,列表刷新正确 |
|
|
||||||
|
|
||||||
#### 4.3.3 会员管理页面
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-A-MEMBER-001 | P1 | 逐项填写会员查询条件并点击查询/重置 | 每项条件有效,重置清空并回第一页 |
|
|
||||||
| UI-A-MEMBER-002 | P1 | 拖动表格横向滚动条和操作列独立滚动条 | 所有数据列和操作按钮可达,固定列不漂移 |
|
|
||||||
| UI-A-MEMBER-003 | P1 | 点击添加、详情、编辑 | 对应弹窗字段完整,详情只读,编辑正确回显 |
|
|
||||||
| UI-A-MEMBER-004 | P1 | 点击“更多”或操作弹层 | 银行卡、地址、团队、账变、弹幕、奖励、真人/假人、启禁用、删除均可见 |
|
|
||||||
| UI-A-MEMBER-005 | P1 | 逐个打开银行卡、地址、团队弹窗并关闭 | 标题、表格、按钮和关闭行为正确 |
|
|
||||||
| UI-A-MEMBER-006 | P0 | 点击授权查看明文,未勾选确认或未填用途 | 确认按钮不可提交或明确校验 |
|
|
||||||
| UI-A-MEMBER-007 | P1 | 打开账变、奖励金、弹幕、状态弹窗 | 金额/原因/内容/范围字段和风险提示完整 |
|
|
||||||
| UI-A-MEMBER-008 | P1 | 点击设为真人/假人、启用/禁用、删除并取消确认 | 取消后列表状态不变 |
|
|
||||||
| UI-A-MEMBER-009 | P1 | 点击分页、每页条数和跳页 | 总数、页码、选中行和滚动位置合理更新 |
|
|
||||||
| UI-A-MEMBER-010 | P1 | 输入完整或部分注册域名查询,并组合域名状态筛选 | 支持模糊匹配;待绑定、启用域名、失效域名结果准确 |
|
|
||||||
| UI-A-MEMBER-011 | P1 | 查看会员列表和详情中的注册域名、域名状态、绑定时间 | 三项信息一致;未绑定显示“待绑定”,不显示伪造域名 |
|
|
||||||
| UI-A-MEMBER-012 | P1 | 检查会员列表标题栏和编辑弹窗 | 后台不显示新增会员入口;只允许编辑已有会员 |
|
|
||||||
| UI-A-LEVEL-001 | P1 | 打开会员等级,点击新增和编辑 | 等级、金额、次数、佣金、状态字段完整回显 |
|
|
||||||
| UI-A-LEVEL-002 | P1 | 点击保存、取消、停用/启用、删除 | 每个动作反馈正确,删除显示引用限制 |
|
|
||||||
| UI-A-HALL-001 | P1 | 打开任务大厅,测试查询、新增、编辑和等级选择 | 字段、图标、比例和等级选择正确 |
|
|
||||||
| UI-A-HALL-002 | P1 | 测试单删、勾选多行、批量删除和取消 | 选中态与成功/失败数量提示准确 |
|
|
||||||
| UI-A-URL-001 | P1 | 打开 URL 地址池页面 | 汇总卡、查询栏、列表及操作栏完整;列表按累计绑定次数升序、ID 升序显示 |
|
|
||||||
| UI-A-URL-002 | P1 | 按地址名称、域名、状态和创建时间查询及重置 | 每项筛选有效,域名支持模糊匹配,重置恢复第一页 |
|
|
||||||
| UI-A-URL-003 | P1 | 点击新增/编辑,填写地址名称、注册入口 URL、状态和备注 | URL 被标准化并正确回显;非法协议、查询参数、片段或重复域名不能保存 |
|
|
||||||
| UI-A-URL-004 | P1 | 点击“详情”,查询绑定会员并翻页 | 显示累计/当前绑定次数、最后绑定时间及全部绑定会员;手机号脱敏 |
|
|
||||||
| UI-A-URL-005 | P1 | 点击“设为失效”或“启用”,再点击复制链接 | 状态立即更新;复制内容为标准化注册入口;页面无删除按钮 |
|
|
||||||
| UI-A-URL-006 | P1 | 打开 Excel 批量导入弹窗并检查说明、关闭和取消 | 明确必填表头、格式、大小和 5000 条限制;关闭不上传文件 |
|
|
||||||
| UI-A-URL-007 | P1 | 分别导入合法、重复和含错误行的 XLS-URL | 合法行导入且均为启用;重复跳过;错误行按 Excel 行号展示;汇总与列表刷新 |
|
|
||||||
| UI-A-MLOGIN-001 | P1 | 打开会员登录日志,按会员、方式、结果、域名、IP 和时间查询 | 筛选、重置、分页和空态正确,不与后台管理员登录日志混用 |
|
|
||||||
| UI-A-MLOGIN-002 | P1 | 查看成功和失败日志详情 | 请求 ID、会员、方式、结果、脱敏手机/IP、地区、域名、系统和浏览器完整准确 |
|
|
||||||
| UI-A-MLOGIN-003 | P1 | 按当前筛选条件导出会员登录日志 | 文件可打开,条数和字段与筛选结果一致,无 IP 密文、Token 或密码 |
|
|
||||||
|
|
||||||
#### 4.3.4 交易管理页面
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-A-ORDER-001 | P1 | 订单列表逐项测试筛选、查询、重置和分页 | 条件生效,状态和金额显示正确 |
|
|
||||||
| UI-A-ORDER-002 | P1 | 点击详情 | 订单、会员、商品、任务、金额、时间线和流水信息完整 |
|
|
||||||
| UI-A-ORDER-003 | P0 | 点击“匹配订单”并搜索、清理筛选、选择商品、取消 | 弹窗列表和选中态正确;取消不修改订单 |
|
|
||||||
| UI-A-ORDER-004 | P0 | 选择商品后点击确定 | 加载态防重复,成功关闭并刷新订单 |
|
|
||||||
| UI-A-ORDER-005 | P1 | 点击“更改金额”,测试输入、取消和确定 | 金额校验清楚,取消无副作用,成功后刷新 |
|
|
||||||
| UI-A-ORDER-006 | P0 | 点击“强制付款”“冻结订单”并取消/确认 | 风险文案清晰,取消无副作用,确认结果正确 |
|
|
||||||
| UI-A-ORDER-007 | P1 | 点击“审核任务”或等待会员付款禁用按钮 | 前者跳会员任务审核,后者不可误点 |
|
|
||||||
| UI-A-RC-001 | P1 | 充值列表测试筛选、汇总卡、详情和凭证预览 | 筛选准确,汇总与列表一致,凭证可查看 |
|
|
||||||
| UI-A-RC-002 | P0 | 点击“通过”,填写审核说明,取消/确认 | 取消不入账;确认加载态防重复并刷新状态 |
|
|
||||||
| UI-A-RC-003 | P0 | 点击“驳回”,测试空原因、合法原因和确认 | 必填校验有效,确认后状态和原因正确 |
|
|
||||||
| UI-A-WD-001 | P1 | 提现列表测试筛选、详情和收款信息展示 | 金额、手续费、实到、状态和脱敏信息正确 |
|
|
||||||
| UI-A-WD-002 | P0 | 点击通过/驳回,测试确认弹窗 | 按钮仅在合法状态显示,确认后刷新 |
|
|
||||||
| UI-A-WD-003 | P0 | 处理中记录点击完成并填写外部单号 | 必填校验、加载态和完成结果正确 |
|
|
||||||
| UI-A-CS-001 | P1 | 客服管理测试查询、新增和编辑 | 名称、头像、工作时间、在线状态、IM 绑定、排序和状态完整 |
|
|
||||||
| UI-A-CS-002 | P1 | 点击启用/停用 | 开关与状态标签同步,C 端列表同步 |
|
|
||||||
| UI-A-CS-003 | P1 | 点击删除,测试空原因、取消和确认 | 空原因阻止;取消无副作用;停用记录可删除 |
|
|
||||||
|
|
||||||
#### 4.3.5 商品与任务管理页面
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-A-PROD-001 | P1 | 商品列表填写名称/分类并点击查询 | 列表过滤正确,字段及总数完整 |
|
|
||||||
| UI-A-PROD-002 | P1 | 点击添加/编辑并逐项检查表单 | 商品、分类、价格、店铺、图片、状态、推荐等字段正确 |
|
|
||||||
| UI-A-PROD-003 | P1 | 点击发布/下架并取消/确认 | 弹窗文案对应当前状态,成功后按钮文字反转 |
|
|
||||||
| UI-A-PROD-004 | P1 | 点击推荐/不推荐 | 状态和按钮立即更新,不影响发布状态 |
|
|
||||||
| UI-A-PROD-005 | P1 | 点击删除或勾选后批量删除 | 已引用限制提示清楚,成功/失败数量准确 |
|
|
||||||
| UI-A-PROD-006 | P2 | 检查操作按钮换行和不同窗口宽度 | 编辑、发布/下架、推荐、删除始终可见可点 |
|
|
||||||
| UI-A-TASK-001 | P1 | 任务列表测试查询、新增、编辑 | 商品、等级、佣金、详情、时段等字段完整 |
|
|
||||||
| UI-A-TASK-002 | P1 | 点击发布/下线/删除并取消/确认 | 状态限制和引用提示正确,列表刷新 |
|
|
||||||
| UI-A-SUB-001 | P1 | 会员任务审核测试查询和详情 | 会员、订单、任务、证据、佣金、状态完整 |
|
|
||||||
| UI-A-SUB-002 | P0 | 待审记录点击审核,切换通过/驳回 | 提示文字和意见字段随结论变化 |
|
|
||||||
| UI-A-SUB-003 | P0 | 点击确认审核并连续点击 | 按钮防重复;成功关闭、刷新且只结算一次 |
|
|
||||||
| UI-A-SUB-004 | P1 | 已审核记录点击详情 | 只读展示结果和意见,不再显示可提交审核按钮 |
|
|
||||||
|
|
||||||
#### 4.3.6 组织、权限、系统应用和系统设置页面
|
|
||||||
|
|
||||||
| ID | 优先级 | 页面操作 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UI-A-ORG-001 | P1 | 后台用户页测试查询、新增、编辑、启停、重置密码、删除 | 每个按钮按权限出现,弹窗和确认流程完整 |
|
|
||||||
| UI-A-ORG-002 | P1 | 部门页展开/收起树,新增同级/下级、编辑、删除 | 树层级和父节点选择正确 |
|
|
||||||
| UI-A-ORG-003 | P1 | 岗位页测试查询、新增、编辑、启停、删除 | 表单和状态操作正确 |
|
|
||||||
| UI-A-MENU-001 | P1 | 菜单页展开树,点击新增、编辑、删除 | 目录/菜单/按钮字段随类型正确显示 |
|
|
||||||
| UI-A-MENU-002 | P1 | 菜单图标选择、路由、组件、权限标识校验 | 图标预览和字段校验正确 |
|
|
||||||
| UI-A-ROLE-001 | P1 | 角色页新增/编辑/启停/删除 | 角色树、上级角色和基本字段正确 |
|
|
||||||
| UI-A-ROLE-002 | P0 | 点击“分配菜单”,勾选父节点、子节点、全选和取消 | 级联/半选正确,保存后重新打开保持一致 |
|
|
||||||
| UI-A-ROLE-003 | P0 | 子角色打开分配菜单弹窗 | 只能操作父角色权限子集,范围外不可选 |
|
|
||||||
| UI-A-ROLE-004 | P1 | 点击数据权限并切换范围 | 选项和部门树正确,保存后查询范围生效 |
|
|
||||||
| UI-A-APP-001 | P1 | 打开系统应用各二级菜单和个人中心 | 页面均可达,个人设置可保存和取消 |
|
|
||||||
| UI-A-DICT-001 | P1 | 字典类型和字典数据页测试查询、新增、编辑、启停、删除 | 类型与数据联动,弹窗和确认正确 |
|
|
||||||
| UI-A-CONFIG-001 | P1 | 系统配置逐个切换分组并保存 | 各分组字段无错位,保存反馈和重新加载正确 |
|
|
||||||
| UI-A-CRON-001 | P1 | 定时任务测试查询、新增、编辑、启停、执行、日志 | 每个按钮可达,执行结果和日志正确 |
|
|
||||||
| UI-A-BLACK-001 | P1 | 黑名单测试查询、新增、编辑、启停、删除 | 表单、确认、状态和列表刷新正确 |
|
|
||||||
| UI-A-LOG-001 | P1 | 操作/登录/短信/邮件/服务日志逐页查询、重置、详情 | 筛选、分页、详情和脱敏正确 |
|
|
||||||
| UI-A-ATT-001 | P1 | 附件页测试预览、下载、筛选和删除确认 | 图片/文件预览正确,被引用附件删除受限 |
|
|
||||||
|
|
||||||
## 5. 通用与基础能力测试
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| GEN-001 | P0 | 未登录直接访问任一需要登录的 C 端路由 | 跳转账号登录页,登录后回到原目标路由 |
|
|
||||||
| GEN-002 | P0 | 未登录调用任一 C 端受保护 API | 返回 401,响应不包含业务数据 |
|
|
||||||
| GEN-003 | P0 | 未登录直接访问后台业务路由 | 跳转后台登录页,不短暂显示受保护页面 |
|
|
||||||
| GEN-004 | P0 | 使用失效、伪造、被注销的 Token 调用接口 | 统一拒绝;前端清理会话并引导重新登录 |
|
|
||||||
| GEN-005 | P1 | 连续快速点击新增、保存、提交、审核按钮 | 按钮加载中禁用;只产生一次有效写入 |
|
|
||||||
| GEN-006 | P1 | 刷新列表、切换分页、返回上一页 | 查询条件、分页和数据状态符合页面约定,无重复行 |
|
|
||||||
| GEN-007 | P1 | 请求返回空数组 | 显示明确空状态,不报错、不展示演示假数据 |
|
|
||||||
| GEN-008 | P1 | API 返回 400/403/404/409/422/429/500 | 展示可理解提示;500 类保留 request_id;页面可重试 |
|
|
||||||
| GEN-009 | P1 | 请求中断、离线、超时后恢复网络 | 加载态可结束,可重新请求,不产生幽灵提交 |
|
|
||||||
| GEN-010 | P1 | 输入前后空格、全角字符、Emoji、HTML/脚本片段 | 按字段规则规范化或拒绝;展示时不执行脚本 |
|
|
||||||
| GEN-011 | P1 | 两个浏览器同时编辑同一带版本号记录 | 后提交者收到版本冲突并要求刷新,不静默覆盖 |
|
|
||||||
| GEN-012 | P1 | 租户 A 携带租户 B 的资源 ID 请求详情或编辑 | 返回无权限或不存在,绝不返回跨租户数据 |
|
|
||||||
| GEN-013 | P1 | 列表页横向滚动、窄屏及操作列按钮较多 | 所有按钮可达;操作列不遮挡,滚动条可操作 |
|
|
||||||
| GEN-014 | P2 | 页面刷新、前进后退、复制带参数 URL 打开 | 路由、标题、筛选参数正确,无白屏 |
|
|
||||||
| GEN-015 | P2 | 动态资源发版后旧页面加载过期 chunk | 最多自动刷新一次并恢复,10 秒内不循环刷新 |
|
|
||||||
|
|
||||||
## 6. C 端功能测试
|
|
||||||
|
|
||||||
### 6.1 注册、登录与会话
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| C-AUTH-001 | P0 | 用合法姓名、11 位手机号、合法密码、6 位邀请码并勾选协议注册 | 注册成功并建立会话;会员、钱包及上下级关系正确创建 |
|
|
||||||
| C-AUTH-002 | P1 | 姓名分别输入 0、1、10、11 个字符 | 1~10 个合法文字通过;0 和 11 拒绝 |
|
|
||||||
| C-AUTH-003 | P1 | 姓名含汉字、字母、组合音标及间隔点“·” | 允许;数字、空格、符号和脚本字符拒绝 |
|
|
||||||
| C-AUTH-004 | P1 | 手机号测试空值、10 位、11 位非 1 开头、第二位 0/2、含字母、合法 13~19 段 | 仅 `1[3-9]` 开头的 11 位数字通过 |
|
|
||||||
| C-AUTH-005 | P1 | 密码测试 5 个字符、6 个字符、72 字节、73 字节和多字节字符 | 少于 6 个字符或超过 72 字节拒绝;边界值按规则处理 |
|
|
||||||
| C-AUTH-006 | P1 | 邀请码测试空值、5 位、6 位、7 位、含字母及不存在的邀请码 | 仅存在的 6 位数字邀请码通过 |
|
|
||||||
| C-AUTH-007 | P0 | 未勾选隐私协议提交注册 | 注册被拒绝,数据库无会员和钱包残留 |
|
|
||||||
| C-AUTH-008 | P0 | 使用已注册手机号再次注册 | 明确提示已存在,不新增重复会员 |
|
|
||||||
| C-AUTH-009 | P0 | 正确手机号密码登录 | 登录成功,记录登录时间/日志,会话 Token 可访问受保护接口 |
|
|
||||||
| C-AUTH-010 | P0 | 正确手机号配错误密码、未注册手机号登录 | 统一凭证错误提示,不泄露手机号是否存在 |
|
|
||||||
| C-AUTH-011 | P0 | 同一手机号 15 分钟内连续错误登录 10 次,再试正确密码 | 第 10 次阈值后限流;返回 429;窗口后或策略解除后恢复 |
|
|
||||||
| C-AUTH-012 | P1 | 错误数未达阈值时成功登录,再次输错 | 成功登录清除此前失败计数 |
|
|
||||||
| C-AUTH-013 | P0 | 登出后使用旧 Token 请求 `/v1/me` | 旧 Token 失效;返回登录页 |
|
|
||||||
| C-AUTH-014 | P1 | 会话自然过期时停留在业务页继续操作 | 不提交业务;提示登录失效并跳转登录页 |
|
|
||||||
| C-AUTH-015 | P2 | 身份验证/短信找回入口点击获取验证码 | 当前未开放时明确提示暂未开放,不显示伪成功、不修改密码 |
|
|
||||||
| C-AUTH-016 | P0 | 使用 URL-ENABLED 的注册入口完成注册 | 注册成功;会员、钱包和 `hg_member_url_binding` 在同一事务创建,返回绑定成功及标准化域名 |
|
|
||||||
| C-AUTH-017 | P0 | 从 URL-UNKNOWN 域名或缺少可识别来源的页面注册 | 会员和钱包仍创建成功,不生成域名绑定,不因地址池无匹配记录阻断注册 |
|
|
||||||
| C-AUTH-018 | P0 | 从 URL-INVALID 的域名注册 | 注册成功但不建立绑定;失效地址累计绑定次数和最后绑定时间不变化 |
|
|
||||||
| C-AUTH-019 | P1 | 使用大小写域名、末尾点、默认 80/443 端口注册 | 域名按统一规则规范化并命中同一地址,不产生重复地址或重复绑定 |
|
|
||||||
| C-AUTH-020 | P0 | 同一注册请求重复提交或事务中模拟绑定写入失败 | 不重复创建会员/钱包/绑定;绑定写入失败时整个注册事务回滚 |
|
|
||||||
| C-AUTH-021 | P0 | 账号密码登录成功 | 更新会员最后登录时间、IP 密文、IP 脱敏值和地区,并新增一条成功会员登录日志 |
|
|
||||||
| C-AUTH-022 | P1 | 使用错误密码、禁用会员或风控会员登录 | 登录失败且不更新会员主表最后登录字段;分别记录脱敏的失败日志和可理解原因 |
|
|
||||||
| C-AUTH-023 | P1 | 手机验证码登录成功、验证码错误或过期 | 成功/失败均按手机登录方式记录独立日志;成功时更新会员最后登录信息 |
|
|
||||||
|
|
||||||
### 6.2 首页、内容、通知与排行榜
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| C-HOME-001 | P1 | 打开首页 | Banner、用户摘要、快捷入口、公告/滚动信息及导航正常加载 |
|
|
||||||
| C-HOME-002 | P1 | 后台关闭领取、储入、取出、商城开关后刷新首页 | 对应入口置灰且不可点击,其他入口不受影响 |
|
|
||||||
| C-HOME-003 | P1 | 重新开启功能开关 | 对应入口恢复可点击并进入正确页面 |
|
|
||||||
| C-HOME-004 | P1 | Banner 未到生效时间、已过期、已下线 | C 端不展示;生效期内按排序展示 |
|
|
||||||
| C-HOME-005 | P1 | Banner 无跳转、内部路由、合法 HTTPS 外链 | 分别不跳转、站内跳转、受控打开外链;非法协议不执行 |
|
|
||||||
| C-HOME-006 | P2 | Banner 图片失效或加载失败 | 显示占位,不导致页面布局塌陷 |
|
|
||||||
| C-HOME-007 | P1 | 后台发布平台介绍、规则、代理合作、公司资质文本 | C 端对应内容页显示最新已发布版本 |
|
|
||||||
| C-HOME-008 | P1 | 后台保存草稿但不发布 | C 端继续显示旧已发布版本 |
|
|
||||||
| C-HOME-009 | P1 | 下线内容或内容不存在 | C 端显示友好空状态,不泄露草稿正文 |
|
|
||||||
| C-HOME-010 | P1 | 发布全局通知和指定会员通知 | 目标会员可见;非目标会员不可见;已过有效期不展示 |
|
|
||||||
| C-HOME-011 | P1 | 标记通知已读并刷新 | 已读状态保持;未读数量正确减少,不影响其他会员 |
|
|
||||||
| C-HOME-012 | P1 | 排行榜混合真人、假人、禁用用户和同分用户 | 按产品口径展示;禁用/应排除数据不出现;同分排序稳定 |
|
|
||||||
|
|
||||||
### 6.3 领取、订单与任务状态机
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| C-TASK-001 | P0 | 正常会员在营业时间进入领取页 | 总资产、昨日/今日佣金、今日领取数与数据库一致 |
|
|
||||||
| C-TASK-002 | P0 | 后台关闭任务功能后领取 | 返回 `TASK_DISABLED`,不创建订单 |
|
|
||||||
| C-TASK-003 | P1 | 在营业开始前 1 秒、开始时刻、结束时刻、结束后 1 秒领取 | 两端点允许,窗口外拒绝 |
|
|
||||||
| C-TASK-004 | P1 | 营业时段配置为跨午夜,如 22:00~02:00 | 22:00~次日 02:00 可领取,其余时间拒绝 |
|
|
||||||
| C-TASK-005 | P0 | U-AUTO 余额为最低余额减 1 分、等于最低余额、加 1 分 | 小于阈值拒绝;等于和大于阈值通过 |
|
|
||||||
| C-TASK-006 | P1 | U-MANUAL 余额低于最低余额进入领取资格检查 | 按手动派单规则返回;不错误套用自动派单最低余额校验 |
|
|
||||||
| C-TASK-007 | P0 | 当日领取数为上限减 1、等于上限 | 前者可领取;等于上限返回 `DAILY_LIMIT_REACHED` |
|
|
||||||
| C-TASK-008 | P0 | 存在匹配中、待处理、审核中或冻结订单时再次领取 | 返回 `PENDING_ORDER_EXISTS`,并提供查看原订单入口 |
|
|
||||||
| C-TASK-009 | P1 | 当前会员等级不属于任务大厅允许等级 | 返回 `LEVEL_NOT_ELIGIBLE`,不创建订单 |
|
|
||||||
| C-TASK-010 | P0 | 禁用会员或禁用钱包领取 | 返回账户受限,不创建订单及流水 |
|
|
||||||
| C-TASK-011 | P0 | 连续双击领取或并发发起两次领取 | 最多产生一个在途订单,次数只增加一次 |
|
|
||||||
| C-TASK-012 | P1 | 自动派单延迟配置为 0、正常值、负值、最大值小于最小值 | 0 立即调度;负值归零;反向区间归一;不 panic |
|
|
||||||
| C-TASK-013 | P0 | 自动派单匹配已发布、CNY、价格在配置区间内的商品 | 匹配成功,订单快照、商品、金额和佣金正确 |
|
|
||||||
| C-TASK-014 | P0 | 候选商品为下架、删除、非 CNY 或价格越界 | 不被匹配;无候选时订单保持可解释状态 |
|
|
||||||
| C-TASK-015 | P0 | 手动派单后会员余额足够并确认提交 | 扣除可用余额、结算佣金、订单完成、生成对应流水 |
|
|
||||||
| C-TASK-016 | P0 | 手动派单后后台改价导致会员余额不足 | 提交被拒并引导储入;余额、冻结额和订单状态不被错误修改 |
|
|
||||||
| C-TASK-017 | P0 | 同一订单重复点击确认或并发确认 | 只扣一次、只发一次佣金、只生成一组有效流水 |
|
|
||||||
| C-TASK-018 | P1 | 订单超过截止时间后确认 | 状态转已超时或拒绝提交,不扣款、不结算 |
|
|
||||||
| C-TASK-019 | P1 | 查询订单列表 `page=0`、`page=1`、`page_size=1/100/101` | 0 使用默认页;1 和 100 有效;101 拒绝 |
|
|
||||||
| C-TASK-020 | P1 | 使用 all、matching、pending、processing、completed、expired、frozen、cancelled、failed 过滤 | 返回对应状态;未知状态返回校验错误 |
|
|
||||||
| C-TASK-021 | P1 | 查看本人订单详情和他人订单 ID | 本人可见完整时间线;他人订单返回不存在/无权限 |
|
|
||||||
| C-TASK-022 | P1 | 提交凭证正文 0、2000、2001 字符 | 0 和 2000 按当前规则通过;2001 拒绝 |
|
|
||||||
| C-TASK-023 | P1 | 提交附件 0、9、10 个,或包含 0/负数/重复 ID | 0 和最多 9 个合法唯一 ID 通过;其余拒绝 |
|
|
||||||
| C-TASK-024 | P0 | 使用其他会员上传的附件 ID 提交任务 | 服务端拒绝,不能越权引用附件 |
|
|
||||||
| C-TASK-025 | P0 | 提交成功后核对订单、任务提交、钱包和流水 | 状态、佣金、前后余额、业务单号及时间在同一事务内一致 |
|
|
||||||
| C-TASK-026 | P1 | 后台下线任务后查看已领取订单 | 已领取订单仍可按原快照完成;不能新领取该任务 |
|
|
||||||
|
|
||||||
### 6.4 储入、收款账户、取出与账变
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| C-FIN-001 | P1 | 打开储入页 | 只展示启用渠道,显示渠道最小/最大金额和手续费信息 |
|
|
||||||
| C-FIN-002 | P0 | 储入金额测试 0、负数、最小值减 1 分、最小值、最大值、最大值加 1 分 | 仅渠道区间内金额可提交 |
|
|
||||||
| C-FIN-003 | P1 | 渠道最大值为 0 | 按无上限处理,但仍校验正数和数据库金额范围 |
|
|
||||||
| C-FIN-004 | P1 | 金额输入空值、字母、多小数位、科学计数法、超大数 | 前端不产生错误分值;服务端拒绝非法或溢出输入 |
|
|
||||||
| C-FIN-005 | P1 | 储入备注 500 和 501 个字符 | 500 通过,501 拒绝 |
|
|
||||||
| C-FIN-006 | P1 | 储入凭证附件 0、9、10 个 | 0~9 个合法附件通过;10 个拒绝 |
|
|
||||||
| C-FIN-007 | P0 | 凭证 ID 含重复、0、负数或他人附件 | 拒绝,订单不创建 |
|
|
||||||
| C-FIN-008 | P0 | 正常提交储入 | 只创建一张待处理充值单,随后跳转客服中心 |
|
|
||||||
| C-FIN-009 | P1 | 储入提交失败 | 保留输入并展示错误,不跳客服、不产生半成品订单 |
|
|
||||||
| C-FIN-010 | P1 | 查看储入记录全部状态 | 待支付、审核中、成功、失败、过期、取消文案及金额正确 |
|
|
||||||
| C-FIN-011 | P1 | 待支付订单创建后 30 分钟边界 | 过期时间显示正确,状态由服务端规则处理 |
|
|
||||||
| C-FIN-012 | P0 | 创建收款账户,输入合法姓名、身份证、卡号、开户行、两张不同收款码 | 创建成功;通用账户列表仅返回脱敏值,本人详情接口可还原原始字段 |
|
|
||||||
| C-FIN-013 | P1 | 持有人姓名长度 1、2、64、65,或含控制字符/尖括号 | 2~64 且无危险字符通过,其余拒绝 |
|
|
||||||
| C-FIN-014 | P1 | 身份证输入 15 位、18 位、末位 X、小写 x、空格或连字符 | 合法格式规范化后通过;非法位数和首位 0 拒绝 |
|
|
||||||
| C-FIN-015 | P1 | 银行名长度 1、2、100、101 | 2~100 通过,其余拒绝 |
|
|
||||||
| C-FIN-016 | P1 | 银行卡号长度 7、8、32、33 或含非数字 | 8~32 位数字通过,其余拒绝 |
|
|
||||||
| C-FIN-017 | P1 | 数字人民币编码空值、5、6、32、33 位或含非数字 | 空值或 6~32 位数字通过,其余拒绝 |
|
|
||||||
| C-FIN-018 | P0 | 微信码、支付宝码缺一个或使用同一附件 ID | 拒绝;必须是两个不同的合法图片附件 |
|
|
||||||
| C-FIN-019 | P0 | 上传收款码:空文件、JPEG/PNG/WebP、GIF、伪造扩展名、5MB、5MB+1B | 仅真实 JPEG/PNG/WebP 且不超过 5MB 通过 |
|
|
||||||
| C-FIN-020 | P0 | 使用其他会员的附件设置头像/收款账户 | 服务端拒绝附件越权 |
|
|
||||||
| C-FIN-021 | P1 | 未绑卡点击取出 | 引导添加银行卡,不进入无账户确认页 |
|
|
||||||
| C-FIN-022 | P1 | 账户待验证、已验证、已拒绝时申请取出 | 仅已验证账户可报价和申请 |
|
|
||||||
| C-FIN-023 | P0 | 后台关闭取出开关后报价和提交 | 均拒绝,不能只在前端置灰 |
|
|
||||||
| C-FIN-024 | P0 | 取出金额测试渠道最小值±1 分、最大值±1 分、可用余额±1 分 | 严格按渠道和余额边界处理 |
|
|
||||||
| C-FIN-025 | P1 | 取出手续费为固定、比例、固定+比例三种 | 手续费向上取整规则正确,实到金额=申请金额-手续费 |
|
|
||||||
| C-FIN-026 | P0 | 手续费小于 0、费率超过 10000、手续费大于等于金额 | 渠道视为无效,禁止提交 |
|
|
||||||
| C-FIN-027 | P0 | 未设置交易密码申请取出 | 引导在确认弹窗内设置 6 位数字交易密码;设置成功不自动取出,用户输入新密码并再次点击确认申请后才创建订单 |
|
|
||||||
| C-FIN-028 | P1 | 新交易密码测试 5/6/7 位、非数字、与旧密码相同 | 仅 6 位数字且不同于旧密码通过 |
|
|
||||||
| C-FIN-029 | P0 | 交易密码错误 4 次、第 5 次及限流后正确输入 | 第 5 次达到阈值后 15 分钟限流;正确密码不能绕过 |
|
|
||||||
| C-FIN-030 | P0 | 当日提现次数为上限减 1、等于上限 | 前者可申请,等于上限拒绝 |
|
|
||||||
| C-FIN-031 | P0 | 同一提现请求使用同一 8~80 位幂等键重复提交 | 返回同一业务结果,余额只冻结一次 |
|
|
||||||
| C-FIN-032 | P1 | 幂等键长度 7、8、80、81 或含非法字符 | 8~80 且仅允许字母数字及 `._:-` 通过 |
|
|
||||||
| C-FIN-033 | P0 | 两个不同幂等键并发提取超过总余额 | 最多一单成功;钱包不可出现负余额 |
|
|
||||||
| C-FIN-034 | P0 | 取出成功创建后核对钱包 | 可用余额减少、冻结额增加、版本递增并生成成对流水 |
|
|
||||||
| C-FIN-035 | P1 | 查看取出记录所有状态 | 待审核、审核中、处理中、成功、失败、驳回、取消正确显示 |
|
|
||||||
| C-FIN-036 | P1 | 账变筛选 income、expense、all、未知值 | 前三者正确;未知值拒绝 |
|
|
||||||
| C-FIN-037 | P1 | 账变 `biz_type` 长度 32 和 33 | 32 通过,33 拒绝 |
|
|
||||||
| C-FIN-038 | P0 | 查看账变前后余额 | 每笔 `after = before ± amount`;相邻流水首尾连续 |
|
|
||||||
| C-FIN-039 | P0 | 本人登录后请求 `GET /v1/payment-accounts/details` | 只返回当前租户、当前会员的完整姓名、身份证号、银行卡号、已填的数字人民币编码及本人收款码 URL;无账户返回空数组 |
|
|
||||||
| C-FIN-040 | P0 | 使用未登录会话、另一会员或另一租户访问本人取出信息详情 | 未登录被拒绝;其他身份只能看到各自绑定信息,不能通过请求参数指定目标会员或租户 |
|
|
||||||
| C-FIN-041 | P0 | 将微信/支付宝附件换成他人附件、失效附件,或两张附件对应关系交叉 | 详情接口不返回非本人或失效图片 URL;页面不把微信码、支付宝码串位 |
|
|
||||||
| C-FIN-042 | P0 | 数据库中某账户的必填密文损坏后请求本人详情 | 安全失败,不返回部分原始字段,不输出密文、解密错误细节或堆栈 |
|
|
||||||
| C-FIN-043 | P1 | 同一账户分别请求通用列表和本人详情 | 通用列表的姓名、身份证、卡号、数字人民币编码保持脱敏;仅本人详情返回原值 |
|
|
||||||
| C-FIN-044 | P1 | 数字人民币编码留空创建账户,随后读取详情 | 保存时不生成该字段的密文、哈希或掩码;详情返回空值,银行卡及收款码仍正常使用 |
|
|
||||||
|
|
||||||
### 6.5 商城、个人中心与安全设置
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| C-MY-001 | P1 | 商城查看推荐和限时标签 | 仅已发布、分类启用、有效期内的手工商城商品出现 |
|
|
||||||
| C-MY-002 | P1 | 搜索商品名称,输入不存在关键词、前后空格及大小写 | 搜索结果正确;无结果显示空状态 |
|
|
||||||
| C-MY-003 | P1 | 打开本人可见商品详情及不存在/下架商品 ID | 有效商品正常;无效商品返回友好不存在 |
|
|
||||||
| C-MY-004 | P1 | 限时商品在开始前、开始时、结束时、结束后 | 仅有效窗口允许领取/展示可用动作 |
|
|
||||||
| C-MY-005 | P1 | 个人中心展示账号、邀请码、等级、余额 | 与 `/v1/me` 一致,金额单位正确 |
|
|
||||||
| C-MY-006 | P2 | 点击复制邀请码 | 剪贴板内容准确;失败时给出替代提示 |
|
|
||||||
| C-MY-007 | P0 | 修改登录密码:旧密码错误、空、新密码 5/6 字符、超过 72 字节、与旧密码相同 | 仅旧密码正确且新密码满足规则并不同于旧密码时成功 |
|
|
||||||
| C-MY-008 | P0 | 修改登录密码成功后用新旧密码登录 | 新密码可登录,旧密码不可登录;既有会话按当前安全策略处理 |
|
|
||||||
| C-MY-009 | P1 | 首次设置交易密码时填写旧交易密码 | 拒绝;首次设置不应要求或接受旧交易密码 |
|
|
||||||
| C-MY-010 | P1 | 已有交易密码时不填/填错旧交易密码 | 分别提示必填/错误;不更新密码 |
|
|
||||||
| C-MY-011 | P1 | 更换头像上传合法图片并刷新 | 头像更新且只关联本人附件;首页、我的、IM 头像一致 |
|
|
||||||
| C-MY-012 | P1 | 财务记录、账户明细为空和多页数据 | 空态、分页、金额、状态和时间正确 |
|
|
||||||
| C-MY-013 | P0 | U-DISABLED 打开个人资料及发起交易 | 可按策略查看必要信息,但所有受限写操作被服务端拒绝 |
|
|
||||||
| C-MY-014 | P1 | 点击退出并取消/确认 | 取消保留会话;确认清除会话并返回登录页 |
|
|
||||||
| C-MY-015 | P1 | 从个人信息页修改头像后返回“我的”、首页和客服会话 | 新头像在重新读取资料后保持一致;失败时保留旧头像,不出现仅本页临时预览成功的假象 |
|
|
||||||
|
|
||||||
### 6.6 在线客服与 118IM
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| C-IM-001 | P1 | 打开客服列表 | 展示客服依依、客服琪琪、客服琳琳的名称、女性头像及在线状态 |
|
|
||||||
| C-IM-002 | P0 | 首次点击客服 | 自动创建/恢复会员 IM 身份、建立好友关系和 P2P 会话 |
|
|
||||||
| C-IM-003 | P0 | 客服未绑定 IM 用户或租户代码不一致 | 明确提示客服暂不可用,不进入可发送假状态 |
|
|
||||||
| C-IM-004 | P1 | 好友关系为 none、friend、pending、denied | none 发起申请;friend 进入会话;pending/denied 给出对应提示 |
|
|
||||||
| C-IM-005 | P0 | 本地保存的 IM 密码失效 | 服务端重置并保存凭据后重试一次,成功恢复或明确失败 |
|
|
||||||
| C-IM-006 | P0 | IM 登录返回的用户 ID 与本地身份不一致 | 拒绝建立会话,防止串号 |
|
|
||||||
| C-IM-007 | P1 | 会话打开时加载历史消息 | 历史与实时消息分界明确,顺序、发送人、时间正确 |
|
|
||||||
| C-IM-008 | P1 | 发送空文本、1 字符、1000 字符、1001 字符 | 空文本不发送;1~1000 可发送;超过输入上限不可提交 |
|
|
||||||
| C-IM-009 | P0 | 快速连续发送文本或网络抖动 | 不丢失、不重复;发送中/失败/成功状态可见 |
|
|
||||||
| C-IM-010 | P1 | 断开 WebSocket 后点击重新连接 | 恢复会话并续收消息,不重复展示历史消息 |
|
|
||||||
| C-IM-011 | P1 | 打开表情面板,切换最近/表情/手势/物品并选择 | 分类与布局正确;表情插入输入框,可随文本发送 |
|
|
||||||
| C-IM-012 | P1 | 上传 JPEG/PNG/WebP/GIF 图片,大小为 10MB 和 10MB+1B | 合法且不超过 10MB 可发送;超限前端拒绝 |
|
|
||||||
| C-IM-013 | P1 | 上传 MP4/WebM/QuickTime 视频,大小为 50MB 和 50MB+1B | 合法且不超过 50MB 可发送;超限拒绝 |
|
|
||||||
| C-IM-014 | P0 | 伪造文件后缀或上传脚本/可执行文件 | 客户端和服务端均拒绝,不能作为可执行内容访问 |
|
|
||||||
| C-IM-015 | P1 | 大文件上传过程取消、断网或接口 500 | 进度结束并提示失败;输入区恢复可用,可重新选择 |
|
|
||||||
| C-IM-016 | P0 | 会员发图后客服 Web 端查看 | 接收方拥有附件读取权限,图片正常显示,不返回 403 |
|
|
||||||
| C-IM-017 | P0 | 客服发图后会员端查看 | 会员可读取;无关第三人不能读取附件 |
|
|
||||||
| C-IM-018 | P0 | 历史绝对地址和同源相对地址媒体混合加载 | 均能通过授权地址显示;不得因 CORS 修复而绕过 ACL |
|
|
||||||
| C-IM-019 | P1 | 头像 URL 为空、失效、跨域受限 | 使用稳定占位头像;不影响消息发送 |
|
|
||||||
| C-IM-020 | P1 | 会话 Token 过期后发送 | 自动重连或明确提示重新连接;消息不静默丢失 |
|
|
||||||
|
|
||||||
## 7. 管理后台功能测试
|
|
||||||
|
|
||||||
### 7.1 后台登录、菜单、组织与 RBAC
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| A-RBAC-001 | P0 | 正确/错误后台账号密码登录 | 正确进入首页;错误统一提示并记录登录日志 |
|
|
||||||
| A-RBAC-002 | P0 | 登录页检查其他登录方式、手机号登录、注册、演示角色 | 这些入口均不显示,只保留账号登录 |
|
|
||||||
| A-RBAC-003 | P2 | 检查登录页系统名 | 显示“企业办公管理系统” |
|
|
||||||
| A-RBAC-004 | P1 | 展开组织管理、权限管理、系统应用、系统设置 | 二级菜单均有合适图标且可点击 |
|
|
||||||
| A-RBAC-005 | P1 | 检查系统应用下个人中心 | 菜单可见并能进入个人设置 |
|
|
||||||
| A-RBAC-006 | P0 | 为 A-CHILD 分配菜单 | 弹窗只显示 A-PARENT 已有菜单范围或范围外禁选 |
|
|
||||||
| A-RBAC-007 | P0 | 通过构造请求给子角色分配父角色没有的菜单 | 服务端拒绝,数据库不写入越权关系 |
|
|
||||||
| A-RBAC-008 | P1 | 勾选一级菜单 | 可按设计级联勾选全部可选子菜单和按钮权限 |
|
|
||||||
| A-RBAC-009 | P1 | 取消一级菜单或部分子菜单 | 父子半选状态正确,不残留不可达按钮权限 |
|
|
||||||
| A-RBAC-010 | P0 | 无页面权限用户直接输入 URL | 页面不可访问;对应接口同样返回 403 |
|
|
||||||
| A-RBAC-011 | P0 | 有页面权限但无新增/编辑/删除按钮权限 | 按钮不显示;直接调用写接口仍被拒绝 |
|
|
||||||
| A-RBAC-012 | P1 | 新增、编辑、停用部门和岗位 | 树关系、排序、状态和成员关联正确 |
|
|
||||||
| A-RBAC-013 | P1 | 删除存在下级或在用成员的部门/角色 | 被阻止并提示依赖关系 |
|
|
||||||
| A-RBAC-014 | P1 | 修改管理员角色后刷新其会话 | 菜单和接口权限按系统策略及时生效 |
|
|
||||||
| A-RBAC-015 | P0 | 非超管尝试编辑超管或给自己提权 | 服务端拒绝并记录操作日志 |
|
|
||||||
| A-RBAC-016 | P1 | 菜单新增、编辑、排序、隐藏、外链和按钮权限 | 路由树刷新正确,隐藏菜单可按直接路由策略访问 |
|
|
||||||
| A-RBAC-017 | P1 | 字典增删改、启停并刷新业务页面 | 使用字典的下拉和标签同步更新,不在前端残留硬编码 |
|
|
||||||
| A-RBAC-018 | P1 | 修改个人资料和密码 | 校验正确;密码不回显;修改记录可追踪 |
|
|
||||||
|
|
||||||
### 7.2 首页、网站设置、文本、Banner 与手工商城
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| A-PORTAL-001 | P1 | 打开首页看板 | 会员、订单、充值、提现、任务等指标与筛选口径一致 |
|
|
||||||
| A-PORTAL-002 | P1 | 切换日期、刷新、点击指标卡 | 数据区间正确;跳转明细时继承筛选条件 |
|
|
||||||
| A-PORTAL-003 | P1 | 无业务数据或统计接口失败 | 分别显示 0/空态或错误提示,不混淆 |
|
|
||||||
| A-PORTAL-004 | P0 | 网站设置读取、修改并保存 | 字段完整回显;保存生成新版本并立即按当前实现生效 |
|
|
||||||
| A-PORTAL-005 | P1 | 最小金额大于最大金额、反向时间、负次数、非法 URL | 前后端拒绝并定位字段 |
|
|
||||||
| A-PORTAL-006 | P1 | 营业时间配置正常窗口、全天和跨午夜 | 保存后 C 端按相同语义执行 |
|
|
||||||
| A-PORTAL-007 | P0 | 两人同时编辑同一网站配置版本 | 后提交者发生版本冲突,不覆盖先提交者 |
|
|
||||||
| A-PORTAL-008 | P1 | 提交、发布、回滚网站配置 | 状态流转合法;回滚形成可审计新版本,不篡改历史 |
|
|
||||||
| A-PORTAL-009 | P1 | 切换领取/储入/取出/商城开关 | C 端入口和服务端行为同步变化 |
|
|
||||||
| A-PORTAL-010 | P1 | 文本列表初始化数据 | 仅约定的 12 条原始文本;列表不显示“内容标识”列 |
|
|
||||||
| A-PORTAL-011 | P1 | 新增/编辑文本,正文为空、超长、含脚本和恶意链接 | 必填及长度校验有效;危险 HTML 被拒绝或净化 |
|
|
||||||
| A-PORTAL-012 | P1 | 文本发布、下线、删除 | C 端只显示已发布版本;有历史引用时保留历史 |
|
|
||||||
| A-PORTAL-013 | P1 | 编辑文本弹窗 | 宽度适合正文编辑,标题为文本管理语义,不出现商品图片字段 |
|
|
||||||
| A-PORTAL-014 | P1 | Banner 新增、编辑、排序、发布、下线 | C 端按状态、有效期和排序展示 |
|
|
||||||
| A-PORTAL-015 | P1 | Banner 上传非图片、超限、异常比例或失效 URL | 阻止或明确提示;列表不出现破损数据 |
|
|
||||||
| A-PORTAL-016 | P1 | 删除已发布 Banner | 按规则先下线或软删除;C 端立即不可见 |
|
|
||||||
| A-PORTAL-017 | P1 | 手工商城新增/编辑名称、价格、图片、展示时间 | 保存成功并正确回显,`product_type=2` |
|
|
||||||
| A-PORTAL-018 | P1 | 手工商品发布/下架/删除 | C 端商城展示同步;已关联历史保留快照 |
|
|
||||||
| A-PORTAL-019 | P0 | 租户 A 管理门户资源 | 不能查看或修改租户 B 的配置、内容、Banner、商品 |
|
|
||||||
| A-PORTAL-020 | P1 | 查看配置和内容历史 | 操作者、版本、时间、状态和差异可追溯 |
|
|
||||||
|
|
||||||
### 7.3 会员、等级与任务大厅
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| A-MEM-001 | P1 | 会员列表按账号、手机号、时间、状态、派单模式、类别查询 | 筛选准确,重置恢复默认条件 |
|
|
||||||
| A-MEM-002 | P1 | 列表检查派单模式和类别 | 派单模式显示自动/手动;类别显示真人/假人 |
|
|
||||||
| A-MEM-003 | P1 | 操作列在 180px 宽度内横向滚动 | 按钮靠左、可滚动查看全部;细滚动条可拖动 |
|
|
||||||
| A-MEM-004 | P1 | 操作弹层查看编辑、删除、银行卡、地址、团队、账变、弹幕、奖励、类别、状态 | 按权限显示,按钮尺寸和换行不遮挡 |
|
|
||||||
| A-MEM-005 | P0 | 新增会员使用重复手机号/邀请码冲突 | 拒绝重复;不产生孤立钱包或资料 |
|
|
||||||
| A-MEM-006 | P1 | 编辑会员基础资料 | 普通编辑不能直接改钱包余额;敏感字段不明文回显 |
|
|
||||||
| A-MEM-007 | P0 | 切换自动/手动派单和真人/假人 | 保存后 C 端领取规则及统计口径同步更新 |
|
|
||||||
| A-MEM-008 | P0 | 授权查看会员、银行卡、地址明文 | 必须填写用途并确认;有单独权限;生成敏感访问日志 |
|
|
||||||
| A-MEM-009 | P0 | 无敏感权限构造明文查看请求 | 返回 403,日志与错误响应不泄露明文 |
|
|
||||||
| A-MEM-010 | P1 | 新增/编辑/删除银行卡和地址 | 脱敏展示、归属校验、默认项及软删除正确 |
|
|
||||||
| A-MEM-011 | P1 | 团队查询层级 1、10、11 | 1~10 可查;超过 10 被限制;上下级关系不串租户 |
|
|
||||||
| A-MEM-012 | P0 | 封禁/解封个人或团队 | 审批、执行、状态日志完整;C 端权限即时受限/恢复 |
|
|
||||||
| A-MEM-013 | P0 | 同一状态审批重复执行 | 只执行一次,重复请求不重复写状态日志 |
|
|
||||||
| A-MEM-014 | P0 | 发起账变后未审批直接执行 | 被拒绝;余额和流水不变化 |
|
|
||||||
| A-MEM-015 | P0 | 审批通过后执行加款/扣款 | 钱包、版本和不可变流水一致,不能扣成负数(除明确授权场景) |
|
|
||||||
| A-MEM-016 | P0 | 使用相同幂等键重复执行账变/奖励金 | 仅入账一次 |
|
|
||||||
| A-MEM-017 | P1 | 创建、查看和撤回会员通知/弹幕 | 目标、来源、有效期正确;撤回后 C 端不再展示 |
|
|
||||||
| A-MEM-018 | P0 | 删除有余额、在途订单或历史流水的会员 | 禁止物理删除;按规则注销/软删除并保留台账 |
|
|
||||||
| A-MEM-019 | P1 | 会员等级新增/编辑 | 名称、金额、日订单数、佣金率、日提现数校验正确 |
|
|
||||||
| A-MEM-020 | P1 | 等级金额为负、次数为小数、佣金率越界 | 保存被拒绝,提示具体字段 |
|
|
||||||
| A-MEM-021 | P1 | 等级编辑、启停、删除 | 操作列仅编辑/停启用/删除;在用等级不能直接删除 |
|
|
||||||
| A-MEM-022 | P1 | 等级规则变更后检查在途订单 | 在途订单继续使用规则快照,新订单使用新规则 |
|
|
||||||
| A-MEM-023 | P1 | 任务大厅新增、编辑、启停、单删和批删 | 等级关联、排序和 C 端入口同步;失败项逐条提示 |
|
|
||||||
| A-MEM-024 | P1 | 删除被任务或历史订单引用的任务大厅 | 被阻止或仅下线,不破坏历史 |
|
|
||||||
| A-MEM-025 | P1 | 隐藏菜单“资金调账、会员通知” | 左侧菜单不显示,但会员操作入口和授权接口仍正常 |
|
|
||||||
| A-MEM-026 | P1 | 检查后台会员列表及 `/appMember/edit` | 页面无新增会员按钮;无 ID 的创建请求被拒绝,不创建会员 |
|
|
||||||
| A-MEM-027 | P1 | 按注册域名输入完整值、前缀、中间片段和大小写关键词 | 均按标准化域名模糊查询,结果不串租户 |
|
|
||||||
| A-MEM-028 | P1 | 组合待绑定、启用域名、失效域名状态及其他会员条件查询 | 列表、总数、详情的域名状态一致,地址启停后状态实时变化 |
|
|
||||||
| A-URL-001 | P1 | 新增 HTTP/HTTPS 地址,省略路径或使用自定义端口 | 省略路径时补 `/register`;保留非默认端口;默认 80/443 端口被规范化 |
|
|
||||||
| A-URL-002 | P1 | 新增 ftp、带账号、查询参数、片段、空域名或超过 512 字符的入口 | 服务端逐项拒绝并返回明确错误,不写入半成品地址 |
|
|
||||||
| A-URL-003 | P0 | 新增大小写、默认端口或尾点不同但标准化后相同的域名 | 唯一约束和业务校验均阻止重复地址 |
|
|
||||||
| A-URL-004 | P1 | 编辑未绑定地址的名称、URL、状态和备注 | 合法字段保存;域名哈希、协议和基础 URL 同步更新 |
|
|
||||||
| A-URL-005 | P0 | 编辑已有绑定会员的地址并尝试更换域名 | 拒绝更换域名;允许修改名称、状态和备注;历史绑定保持不变 |
|
|
||||||
| A-URL-006 | P1 | 地址池混合 0、1、相同及较大累计绑定次数后查询 | 始终按使用次数升序、ID 升序稳定排列,分页边界不重复不漏行 |
|
|
||||||
| A-URL-007 | P0 | 将启用地址设为失效后从该域名注册,再重新启用后注册 | 失效期间注册成功但不绑定;重新启用后新会员正常绑定,历史绑定不删除 |
|
|
||||||
| A-URL-008 | P0 | 两个会员并发从同一启用域名注册 | 每个会员只产生一个绑定;累计绑定次数精确增加,最后绑定时间更新 |
|
|
||||||
| A-URL-009 | P1 | 查看地址详情并按会员关键词、绑定时间筛选 | 返回该地址全部绑定会员且手机号脱敏;其他地址会员不混入 |
|
|
||||||
| A-URL-010 | P1 | 导入合法 `.xlsx`/`.xlsm`,表头为中文或支持的英文别名 | 所有合法地址批量写入且状态统一为启用,创建/更新人及租户正确 |
|
|
||||||
| A-URL-011 | P1 | 导入缺少必填表头、空文件、非 Excel、超过 10MB 或超过 5000 条 | 整体拒绝并给出明确原因,不发生部分未知写入 |
|
|
||||||
| A-URL-012 | P1 | 导入文件内重复域名、数据库已有域名和多行格式错误 | 重复项计入跳过数;合法行导入;失败数及最多 100 条行号明细准确 |
|
|
||||||
| A-MLOGIN-001 | P0 | 分别执行账号成功、账号失败、手机成功和手机失败登录 | `hg_app_member_login_log` 每次各写一条,登录方式、结果、会员 ID 和时间准确 |
|
|
||||||
| A-MLOGIN-002 | P0 | 检查会员登录日志的账号、手机、IP、请求头及错误信息 | 手机和 IP 仅存/展示脱敏值;原始 IP 仅加密保存;密码、验证码和 Token 不落库 |
|
|
||||||
| A-MLOGIN-003 | P1 | 登录请求携带 Origin、仅 Host、大小写域名或无有效域名 | 优先记录标准化 Origin 域名;回退 Host;无合法来源时域名为空且不影响日志 |
|
|
||||||
| A-MLOGIN-004 | P1 | IP 地区解析失败或日志队列不可用时登录 | 登录主流程不被地区解析阻断;队列失败降级同步落库并记录警告 |
|
|
||||||
| A-MLOGIN-005 | P1 | 按会员、账号、脱敏手机、登录方式、结果、域名、IP 和时间组合查询 | 列表总数、分页、详情及倒序排列准确,不能看到其他租户日志 |
|
|
||||||
| A-MLOGIN-006 | P1 | 导出大于一页的当前筛选结果 | 导出遵循当前筛选和分页约定;字段脱敏,不包含 `login_ip_cipher` |
|
|
||||||
|
|
||||||
### 7.4 交易管理
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| A-TRADE-001 | P1 | 订单列表按单号、会员、状态、派单方式、时间查询 | 结果准确,金额和状态字典正确 |
|
|
||||||
| A-TRADE-002 | P1 | 查看订单详情 | 商品/任务快照、时间线、会员、金额、流水完整且脱敏 |
|
|
||||||
| A-TRADE-003 | P0 | 打开匹配商品弹窗 | 只显示已发布、未删除、CNY、符合价格规则的商品 |
|
|
||||||
| A-TRADE-004 | P1 | 新商品保存为草稿/下架后搜索匹配 | 不出现;发布后立即可选 |
|
|
||||||
| A-TRADE-005 | P0 | 给手动订单匹配商品 | 订单进入待会员处理;快照和金额正确,不提前扣款 |
|
|
||||||
| A-TRADE-006 | P0 | 对同一订单并发执行两次匹配 | 仅一次成功,后一次状态冲突 |
|
|
||||||
| A-TRADE-007 | P0 | 更改手动订单金额为 0、负数、余额边界及超大值 | 非法值拒绝;合法值更新快照和后续校验 |
|
|
||||||
| A-TRADE-008 | P0 | 强制付款导致余额为负 | 仅有专门权限可执行;明确二次确认;流水标记强制操作 |
|
|
||||||
| A-TRADE-009 | P0 | 冻结订单 | 状态变冻结,C 端不可继续提交并提示联系客服 |
|
|
||||||
| A-TRADE-010 | P0 | 普通任务订单尝试调用手动订单专用操作 | 服务端按订单类型和状态拒绝 |
|
|
||||||
| A-TRADE-011 | P0 | 提交人工处理审批并由无权限/同一人执行 | 按审批规则拒绝越权或不合规执行 |
|
|
||||||
| A-TRADE-012 | P1 | 充值列表和金额汇总 | 总额、已支付、未支付、人工审核、人工驳回口径与明细一致 |
|
|
||||||
| A-TRADE-013 | P1 | 查看充值凭证 | 仅授权人员可见;附件归属和可访问性正确 |
|
|
||||||
| A-TRADE-014 | P0 | 审核通过待审充值 | 状态成功,钱包仅增加一次,生成充值流水和审核记录 |
|
|
||||||
| A-TRADE-015 | P0 | 驳回充值 | 状态失败/驳回,余额不增加,原因回显 C 端 |
|
|
||||||
| A-TRADE-016 | P0 | 重复点击充值通过或并发审核 | 第二次返回已处理;不重复入账 |
|
|
||||||
| A-TRADE-017 | P0 | 审核已过期、取消或已成功充值单 | 拒绝非法状态迁移 |
|
|
||||||
| A-TRADE-018 | P1 | 充值审核说明为空、超长、含脚本 | 按决策必填规则校验;展示时转义 |
|
|
||||||
| A-TRADE-019 | P1 | 提现列表查看脱敏收款账户和风险信息 | 默认脱敏;明文访问单独授权并留痕 |
|
|
||||||
| A-TRADE-020 | P0 | 通过待审核提现 | 进入处理中;冻结资金保持,审核记录完整 |
|
|
||||||
| A-TRADE-021 | P0 | 驳回提现 | 冻结额释放回可用余额,只生成一次冲正流水 |
|
|
||||||
| A-TRADE-022 | P0 | 完成处理中提现 | 状态成功,冻结额扣除,外部单号及完成时间保存 |
|
|
||||||
| A-TRADE-023 | P0 | 完成失败的提现或重复完成 | 拒绝非法状态;不重复扣冻结额 |
|
|
||||||
| A-TRADE-024 | P0 | 审核过程中会员钱包并发变化 | 使用锁/版本控制,余额守恒且不丢更新 |
|
|
||||||
| A-TRADE-025 | P1 | 新增客服,填写名称、头像、工作时间、在线状态、IM 租户和用户 | 保存成功并在 C 端展示 |
|
|
||||||
| A-TRADE-026 | P1 | 客服启用/停用 | 停用客服不再出现在 C 端新列表,历史会话不被删除 |
|
|
||||||
| A-TRADE-027 | P1 | 删除启用客服 | 被阻止;停用并填写删除原因后方可软删除 |
|
|
||||||
| A-TRADE-028 | P0 | 客服 IM 用户重复绑定或绑定不存在用户 | 拒绝或明确报错,不能产生不可连接配置 |
|
|
||||||
| A-TRADE-029 | P1 | 交易操作权限分别授予客服、财务、运营 | 只显示职责内操作;财务动作不对运营开放 |
|
|
||||||
| A-TRADE-030 | P0 | 所有资金审核完成后核对台账 | 业务单状态、钱包、流水、审核和审计记录可相互追溯 |
|
|
||||||
|
|
||||||
### 7.5 商品、任务与会员任务审核
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| A-PT-001 | P1 | 商品列表查询、新增和编辑 | 名称、编号、分类、价格、币种、图片、推荐、有效期正确保存 |
|
|
||||||
| A-PT-002 | P1 | 商品价格测试 0、负数、1 分、超大值、小数精度 | 按分存储;非法或溢出拒绝,页面元/分转换准确 |
|
|
||||||
| A-PT-003 | P1 | 商品发布/下架按钮 | 状态切换成功;文案、颜色及二次确认正确 |
|
|
||||||
| A-PT-004 | P0 | 商品发布后打开订单匹配弹窗 | 商品可见;下架后立即不可用于新匹配 |
|
|
||||||
| A-PT-005 | P1 | 推荐/取消推荐 | 列表状态和 C 端推荐区域同步 |
|
|
||||||
| A-PT-006 | P1 | 删除未引用商品 | 软删除成功,列表及 C 端不再显示 |
|
|
||||||
| A-PT-007 | P0 | 删除已被订单引用商品 | 禁止删除,只允许下架;历史订单仍显示商品快照 |
|
|
||||||
| A-PT-008 | P1 | 批量删除混合可删和被引用商品 | 可删项成功,失败项保留并汇总提示 |
|
|
||||||
| A-PT-009 | P2 | 商品操作列在常见分辨率下显示 | 按钮自动换行,编辑/发布下架/推荐/删除均可达 |
|
|
||||||
| A-PT-010 | P1 | 任务新增/编辑并绑定商品和会员等级 | 规则、佣金、详情、有效期和等级关系正确 |
|
|
||||||
| A-PT-011 | P1 | 任务佣金金额、佣金万分比和数量边界 | 非负、精度和上限校验正确,不发生单位误读 |
|
|
||||||
| A-PT-012 | P1 | 发布/下线任务 | 发布后目标等级可领取;下线不影响已领取订单 |
|
|
||||||
| A-PT-013 | P1 | 删除未引用/已引用任务 | 未引用软删除;已引用仅下线并保留历史 |
|
|
||||||
| A-PT-014 | P1 | 会员任务审核列表按会员、订单、状态筛选 | 返回准确,能从交易订单带条件跳转 |
|
|
||||||
| A-PT-015 | P1 | 查看提交详情 | 正文、附件、任务/订单、佣金、提交时间完整 |
|
|
||||||
| A-PT-016 | P0 | 审核通过待审提交 | 在同一事务内更新提交和订单并发放一次佣金 |
|
|
||||||
| A-PT-017 | P0 | 审核驳回且允许重提 | 保存原因和证据,C 端显示原因并按规则允许重提 |
|
|
||||||
| A-PT-018 | P1 | 驳回时不填补充说明、通过时不填审核意见 | 页面按当前必填规则阻止提交 |
|
|
||||||
| A-PT-019 | P0 | 两名管理员并发审核同一提交 | 只有一人成功;佣金只发一次 |
|
|
||||||
| A-PT-020 | P0 | 已结算提交再次审核或更改结论 | 服务端拒绝,历史结果不可覆盖 |
|
|
||||||
| A-PT-021 | P0 | 提交所含附件已删除或无权限 | 审核页安全降级,不泄露其他会员附件 |
|
|
||||||
| A-PT-022 | P1 | 等级规则发布后新旧任务订单 | 老订单使用快照,新订单使用新版本 |
|
|
||||||
| A-PT-023 | P1 | 任务/商品有效期端点测试 | 开始和结束端点语义统一,前后台结果一致 |
|
|
||||||
| A-PT-024 | P0 | 将租户 B 商品 ID 绑定到租户 A 任务 | 服务端拒绝跨租户关系 |
|
|
||||||
| A-PT-025 | P1 | 发布缺商品、缺等级或无有效佣金规则的任务 | 阻止发布并提示缺失项 |
|
|
||||||
|
|
||||||
### 7.6 HotGo 系统设置与运维功能
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| A-SYS-001 | P1 | 系统配置各分组读取、编辑、保存 | 保存成功并按缓存策略生效,敏感密钥不明文回显 |
|
|
||||||
| A-SYS-002 | P1 | 上传设置限制类型、大小和存储驱动 | 前端提示与服务端实际限制一致 |
|
|
||||||
| A-SYS-003 | P1 | 黑名单新增、启停、删除并从目标 IP 访问 | 生效范围正确,不误封管理员当前地址 |
|
|
||||||
| A-SYS-004 | P1 | 定时任务新增、修改 cron、启停、手动执行 | 规则校验、执行日志和状态正确 |
|
|
||||||
| A-SYS-005 | P1 | 配置非法 cron 表达式 | 保存被拒绝,不影响现有任务 |
|
|
||||||
| A-SYS-006 | P1 | 附件列表预览、下载、删除 | 权限、MIME 和引用检查正确;被引用附件不盲删 |
|
|
||||||
| A-SYS-007 | P1 | 通知公告新增、发布、撤回和阅读 | 目标后台用户可见,阅读状态正确 |
|
|
||||||
| A-SYS-008 | P1 | 操作日志按用户、模块、结果和时间筛选 | 可定位本用例产生的关键写操作 |
|
|
||||||
| A-SYS-009 | P0 | 日志检查密码、Token、银行卡、身份证和密钥 | 不记录明文敏感数据 |
|
|
||||||
| A-SYS-010 | P1 | 登录日志检查成功、失败、IP 和设备 | 记录准确且符合脱敏规则 |
|
|
||||||
| A-SYS-011 | P1 | 在线用户强制下线 | 目标会话失效,不影响其他用户 |
|
|
||||||
| A-SYS-012 | P1 | 地区数据树查询 | 层级、编码和父子关系正确 |
|
|
||||||
| A-SYS-013 | P1 | 插件管理页面在无操作权限下访问 | 只读或拒绝,不能安装/卸载插件 |
|
|
||||||
| A-SYS-014 | P1 | 服务/Redis/数据库短暂不可用 | 页面展示可诊断错误,恢复后无需清库即可继续 |
|
|
||||||
| A-SYS-015 | P2 | 切换主题、语言、侧栏折叠和标签页 | 状态保持,业务表格和弹窗不变形 |
|
|
||||||
|
|
||||||
## 8. 跨端端到端业务场景
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| E2E-001 | P0 | 后台建等级→建大厅→建商品并发布→建任务并发布→会员领取完成 | 全链路可用,规则和金额一致 |
|
|
||||||
| E2E-002 | P0 | C 端提交储入→后台通过→C 端查看余额和记录 | 余额增加一次,状态和流水一致,提交后可进入客服 |
|
|
||||||
| E2E-003 | P0 | C 端申请取出→后台通过→完成 | 可用转冻结再扣除,状态和三阶段时间正确 |
|
|
||||||
| E2E-004 | P0 | C 端申请取出→后台驳回 | 冻结资金完整退回,生成冲正流水 |
|
|
||||||
| E2E-005 | P0 | 手动会员领取→客服匹配商品→会员确认 | 匹配、余额校验、扣款和结算闭环正确 |
|
|
||||||
| E2E-006 | P0 | 自动会员领取→延迟自动匹配 | 在配置延迟内完成,商品金额不超过余额及配置区间 |
|
|
||||||
| E2E-007 | P0 | 会员提交任务→后台审核通过 | 订单、提交、钱包和佣金流水一致且幂等 |
|
|
||||||
| E2E-008 | P1 | 后台发布/下线 Banner、文本、手工商品 | C 端仅展示当前有效发布版本 |
|
|
||||||
| E2E-009 | P1 | 后台封禁会员→会员继续领取/储入/取出/客服 | 所有受限动作按策略拒绝且已有数据可追溯 |
|
|
||||||
| E2E-010 | P1 | 后台切换功能开关→C 端首页和直连接口测试 | UI 与服务端双重生效,不能绕过置灰入口 |
|
|
||||||
| E2E-011 | P0 | 会员点击客服→发文字、表情、图片、视频→客服回复 | 双端实时可见,头像、历史、附件 ACL 均正确 |
|
|
||||||
| E2E-012 | P0 | 子角色仅有充值查看权限登录后台 | 只见允许菜单和查看能力,不能审核或访问其他业务 API |
|
|
||||||
| E2E-013 | P0 | 后台新增启用地址→会员从该域名注册→查看会员和地址详情 | 注册成功并建立唯一绑定;会员详情、地址绑定会员和累计次数一致 |
|
|
||||||
| E2E-014 | P1 | 后台将已绑定地址设为失效→旧会员登录→新会员注册 | 旧会员绑定历史保留且显示失效;登录正常记日志;新会员注册成功但不绑定 |
|
|
||||||
| E2E-015 | P1 | Excel 导入地址→从其中一个域名注册→按域名筛会员→导出登录日志 | 导入地址为启用,注册绑定、会员筛选和登录日志链路完整可追溯 |
|
|
||||||
| E2E-016 | P0 | 会员个人信息页绑定银行卡(数字人民币留空)→查看本人原始取出信息→打开取出报价→在弹窗设置支付密码→再次确认申请 | 绑卡、本人详情、收款码、报价和密码状态一致;设置密码本身不创建取出单,仅最后一次明确确认产生一张订单 |
|
|
||||||
|
|
||||||
## 9. API、安全、数据一致性与异常测试
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| API-001 | P0 | 请求体增加未知 JSON 字段 | C 端 API 按严格解码返回 400,不忽略可疑字段 |
|
|
||||||
| API-002 | P0 | 使用 GET 调写接口或 POST 调只读接口 | 返回 405,不执行副作用 |
|
|
||||||
| API-003 | P0 | 修改请求中的 member_id、tenant_id、operator_id | 服务端以会话身份为准,忽略或拒绝越权字段 |
|
|
||||||
| API-004 | P0 | 数值传字符串、浮点、null、超出 int64 | 返回字段校验错误,不截断、不溢出 |
|
|
||||||
| API-005 | P1 | 分页 page=-1、page_size=-1/0/101、极大页码 | 非法值拒绝或按明确默认;极大页返回空数组 |
|
|
||||||
| API-006 | P0 | 将他人订单、充值、提现、附件、会话 ID 逐项替换 | 均不可读取或修改 |
|
|
||||||
| API-007 | P0 | 重放充值审核、提现执行、任务结算、账变请求 | 状态机/幂等保护生效,不重复记账 |
|
|
||||||
| API-008 | P0 | 在事务中途模拟数据库错误 | 整个事务回滚,不出现订单成功但无流水等半状态 |
|
|
||||||
| API-009 | P0 | 高并发更新同一钱包 | 乐观锁/行锁生效,最终余额守恒,版本连续 |
|
|
||||||
| API-010 | P0 | 校验每个资金业务单的流水唯一键 | 唯一且可反查业务单;冲正指向原流水 |
|
|
||||||
| API-011 | P0 | 访问上传文件使用路径穿越、双扩展名和恶意 MIME | 被拒绝或安全下载,不可执行服务器文件 |
|
|
||||||
| API-012 | P0 | 富文本插入 script、onerror、javascript URL、未知 iframe | 存储或渲染前净化,CSP 下不执行 |
|
|
||||||
| API-013 | P0 | 搜索框输入 SQL 元字符及超长条件 | 参数化查询,无 SQL 注入、无 500 |
|
|
||||||
| API-014 | P0 | 检查 API、浏览器缓存和导出中的敏感字段 | 通用列表、导出中的身份证和卡号默认脱敏;仅已认证的本人取出信息详情可返回原值且禁缓存;密码、密钥永不返回 |
|
|
||||||
| API-015 | P0 | 跨域站点调用带凭证业务接口 | CORS 只允许配置源;不使用通配凭证策略 |
|
|
||||||
| API-016 | P1 | 同一接口连续触发限流 | 返回 429 和合理重试时间,不永久锁死 |
|
|
||||||
| API-017 | P1 | 数据库中制造孤立引用后打开列表/详情 | 页面可降级并提示,不 panic;提供数据修复线索 |
|
|
||||||
| API-018 | P1 | Redis 短暂不可用时登录、限流、资金提交 | 安全失败,不绕过认证/限流/幂等;恢复后可继续 |
|
|
||||||
| API-019 | P1 | IM 服务不可用、慢响应、证书错误 | 客服页可重试并给备用提示,不影响其他业务页面 |
|
|
||||||
| API-020 | P1 | 检查所有错误响应 | 结构统一包含 code/reason/message/request_id,生产不返回堆栈和 SQL |
|
|
||||||
| API-021 | P0 | 无 `/urlPool/import`、`/urlPool/status` 或会员登录日志权限直接调用对应接口 | 返回 403;不能通过隐藏按钮、构造请求或导出绕过权限 |
|
|
||||||
| API-022 | P0 | 跨租户传入地址池 ID、绑定会员 ID 或会员登录日志 ID | 统一返回无权限或不存在,不泄露域名、会员及登录信息 |
|
|
||||||
| API-023 | P0 | 未登录请求 `GET /v1/payment-accounts/details`,或使用其他 HTTP 方法调用 | 未登录拒绝、非 GET 返回 405;响应不包含任何原始绑定信息 |
|
|
||||||
| API-024 | P0 | 登录后请求本人取出信息详情并检查响应头、代理缓存、浏览器缓存和访问日志 | 响应设置 `Cache-Control: no-store`;原始身份证、卡号及数字人民币编码不进入缓存或日志 |
|
|
||||||
|
|
||||||
## 10. 兼容性、易用性与可恢复性
|
|
||||||
|
|
||||||
| ID | 优先级 | 场景与步骤 | 预期结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| UX-001 | P1 | iOS Safari、Android Chrome、桌面 Chrome/Edge 最新两个主版本执行冒烟 | 核心流程一致,无白屏和不可点击控件 |
|
|
||||||
| UX-002 | P1 | C 端宽度 320、375、390、430px | 无横向溢出;底部导航、弹窗和键盘区域可用 |
|
|
||||||
| UX-003 | P1 | 后台 1366×768、1440×900、1920×1080 | 表格、固定操作列、弹窗和滚动条可操作 |
|
|
||||||
| UX-004 | P2 | 浏览器缩放 80%、100%、125%、150% | 关键按钮和文字不被裁切 |
|
|
||||||
| UX-005 | P2 | 键盘 Tab、Enter、Esc 操作表单和弹窗 | 焦点顺序合理,危险操作不被误触 |
|
|
||||||
| UX-006 | P2 | 图片慢加载、长用户名、长商品名、长错误信息 | 截断/换行合理,详情仍可查看完整内容 |
|
|
||||||
| UX-007 | P1 | 提交后刷新或返回 | 已成功业务不重复提交;未成功表单按安全策略保留或清空 |
|
|
||||||
| UX-008 | P1 | 服务发布期间页面打开旧版本 | 静态资源恢复机制有效,API 兼容或给出刷新提示 |
|
|
||||||
|
|
||||||
## 11. 发布前最小回归集
|
|
||||||
|
|
||||||
每次发布至少执行以下 P0 链路:
|
|
||||||
|
|
||||||
1. 正常登录、错误登录限流、退出后 Token 失效。
|
|
||||||
2. 首页四个功能开关与服务端直连接口同时生效。
|
|
||||||
3. 自动领取、手动匹配、余额不足、重复领取和重复确认。
|
|
||||||
4. 储入提交、后台通过、余额及流水核对。
|
|
||||||
5. 取出报价、未设支付密码时的弹窗设置与关闭、再次确认申请、幂等提交、后台通过/驳回/完成及余额核对。
|
|
||||||
6. 商品发布后可匹配、下架后不可匹配、已引用商品不可删除。
|
|
||||||
7. 任务发布、会员提交、后台审核及佣金只结算一次。
|
|
||||||
8. 子角色菜单不超过父角色;无按钮权限时接口也不可调用。
|
|
||||||
9. 客服会话首开、断线重连、文本、表情、图片、视频及双端附件显示。
|
|
||||||
10. 跨租户、跨会员 IDOR、通用列表脱敏、本人取出信息原文与禁缓存、操作日志检查。
|
|
||||||
11. 启用域名注册绑定、失效/未知域名注册不绑定,以及会员注册域名筛选。
|
|
||||||
12. 地址池新增、启停、详情、使用次数排序、Excel 导入及会员登录日志查询导出。
|
|
||||||
13. 个人信息页头像选图更新、取出信息入口、数字人民币选填和本人绑定信息原文展示。
|
|
||||||
|
|
||||||
## 12. 准入、准出与缺陷判定
|
|
||||||
|
|
||||||
### 12.1 测试准入
|
|
||||||
|
|
||||||
- 前后端构建通过,数据库迁移和种子数据在空库及存量库各验证一次。
|
|
||||||
- C 端、后台、MySQL、Redis、上传目录及 IM 环境可访问。
|
|
||||||
- 产品配置、测试账号、支付/提现渠道、商品和任务数据已准备。
|
|
||||||
- 本次变更清单、数据库脚本、回滚方案和发布版本号明确。
|
|
||||||
|
|
||||||
### 12.2 发布准出
|
|
||||||
|
|
||||||
- P0 用例 100% 通过,P1 通过率不低于 98%。
|
|
||||||
- 不存在未关闭的阻断、资金错误、越权、数据泄露或不可逆数据损坏缺陷。
|
|
||||||
- 所有失败用例均有缺陷单、影响范围、临时措施和修复计划。
|
|
||||||
- 资金抽样满足:业务单金额 = 钱包变化 = 流水金额;重复请求不重复入账。
|
|
||||||
- 核心业务日志包含 request_id、业务单号和操作者,且无敏感明文。
|
|
||||||
|
|
||||||
### 12.3 缺陷记录模板
|
|
||||||
|
|
||||||
| 字段 | 内容 |
|
|
||||||
| --- | --- |
|
|
||||||
| 缺陷标题 | `[端/模块][严重级别] 简明现象` |
|
|
||||||
| 环境与版本 | 前端版本、后端版本、数据库迁移版本、浏览器/设备 |
|
|
||||||
| 前置数据 | 租户、账号代号、订单号、配置版本;不得粘贴真实敏感信息 |
|
|
||||||
| 复现步骤 | 可重复的最小步骤 |
|
|
||||||
| 实际结果 | 页面、接口状态码、reason、request_id、必要截图 |
|
|
||||||
| 预期结果 | 引用本文件用例 ID |
|
|
||||||
| 数据影响 | 涉及表、记录数、金额、是否可回滚 |
|
|
||||||
| 附件 | 脱敏截图、HAR、日志片段、SQL 核对结果 |
|
|
||||||
|
|
||||||
## 13. 执行记录模板
|
|
||||||
|
|
||||||
| 用例 ID | 执行人 | 日期 | 环境/版本 | 结果(通过/失败/阻塞) | 缺陷号 | 备注 |
|
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
|
||||||
| 示例:C-FIN-031 | | | | | | |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
说明:配置型金额、次数和时间不在本文写死具体业务数值。执行时应读取当前已发布配置,并使用“下限减 1、下限、下限加 1;上限减 1、上限、上限加 1”的方法验证。代码固定限制(例如分页最大 100、图片 5MB/10MB、视频 50MB、备注 500 字、任务正文 2000 字、附件最多 9 个)已在对应测试用例中明确列出。
|
|
||||||
@@ -1,349 +0,0 @@
|
|||||||
# Olons 功能测试执行报告(2026-10-16)
|
|
||||||
|
|
||||||
## 1. 执行说明
|
|
||||||
|
|
||||||
- 测试依据:`Olons全功能测试用例.md`(用户补充后的 548 条版本)
|
|
||||||
- 执行重点:优先从页面真实操作验证,其次执行构建与后端自动化检查
|
|
||||||
- C 端环境:`https://olns-web.118im.com/admin/`
|
|
||||||
- 管理后台环境:`https://olons-admin.118im.com/admin`
|
|
||||||
- 执行策略:第一轮仅做不破坏现有业务数据的页面检查;2026-10-16 用户随后授权使用专用测试数据执行新增、删除、审核、资金及配置变更测试
|
|
||||||
- 状态含义:`通过`、`部分通过`、`失败`、`阻塞`、`未执行`
|
|
||||||
|
|
||||||
## 2. 第一轮结论
|
|
||||||
|
|
||||||
第一轮已完成 C 端主要页面的真实加载、数据回显及主要入口检查,并执行了两套前端生产构建和后台 Go 测试。当前发现 1 个明确的页面功能缺陷、1 个测试工程问题;管理后台逐按钮测试因执行机器锁屏暂时中断,锁屏问题不计入产品缺陷。
|
|
||||||
|
|
||||||
| 类别 | 结果 |
|
|
||||||
|---|---|
|
|
||||||
| C 端生产构建 | 通过 |
|
|
||||||
| 管理后台生产构建 | 通过(需绕过 pnpm 的自动安装检查,直接使用现有依赖构建) |
|
|
||||||
| 后台 Go 全量测试 | 失败:Casbin、TCP、存储器用例依赖运行环境或测试数据,出现 panic |
|
|
||||||
| C 端页面冒烟 | 首页、领取、记录、商城、储入、取出、我的、个人信息、客服中心均可加载 |
|
|
||||||
| 明确产品缺陷 | 1 个:已有收款账户未在“绑定信息”页回显 |
|
|
||||||
| 后台页面逐按钮 | 阻塞:执行机器进入锁屏,待解锁续测 |
|
|
||||||
|
|
||||||
## 3. C 端页面执行记录
|
|
||||||
|
|
||||||
| 页面/关联用例 | 状态 | 实际结果 |
|
|
||||||
|---|---|---|
|
|
||||||
| 首页 `/app/home`;UI-C-HOME-001、UI-C-HOME-003、UI-C-HOME-004 | 部分通过 | 页面正常显示会员信息、余额、领取/储入/取出/商城四个入口、排行、平台介绍、规则说明、公司资质、代理合作及底部导航;本轮未执行会产生业务状态变化的领取动作 |
|
|
||||||
| 领取 `/app/claim`;UI-C-CLAIM-001、UI-C-CLAIM-005 | 通过 | 页面正常显示总资产、昨日佣金、今日佣金、今日领取数;当前会员存在未完成订单,页面正确提示“存在未完成订单”并提供“查看任务”入口 |
|
|
||||||
| 订单 `/app/orders`;UI-C-ORDER-001、UI-C-ORDER-002 | 部分通过 | 全部、待处理、已完成标签及订单卡片正常显示;本轮未对订单执行提交或取消 |
|
|
||||||
| 商城 `/app/mall`;UI-C-MALL-001、UI-C-MALL-002 | 部分通过 | 搜索、推荐、限时区域及商品卡片正常显示;“验收临时商品-商品页已编辑”可见 |
|
|
||||||
| 储入 `/app/recharge`;UI-C-RECHARGE-001、UI-C-RECHARGE-002 | 部分通过 | 等级说明、微信/支付宝/银行卡/人工审核渠道、金额、姓名及提交入口正常显示;未执行真实提交 |
|
|
||||||
| 取出 `/app/profile/withdrawal`;UI-C-WITHDRAW-001、UI-C-WITHDRAW-002 | 部分通过 | 可用余额、全部提现、已绑定账户 `icbc 6655******4555` 及申请提现入口正常显示;未执行真实提现 |
|
|
||||||
| 我的 `/app/profile`;UI-C-PROFILE-001、UI-C-PROFILE-002 | 通过 | 会员 potter、邀请码 100005、余额及个人中心入口正常显示 |
|
|
||||||
| 个人信息 `/app/profile/info`;UI-C-FORM-001、UI-C-FORM-002 | 通过 | 头像、手机号、取出信息、密码管理、支付密码管理入口正常显示 |
|
|
||||||
| 绑定信息 `/app/profile/bank-card`;UI-C-FORM-003、UI-C-FORM-010、C-FIN-039 | 失败 | 该会员在取出页已有银行卡,但绑定信息页仍显示空白新增表单,没有回显本人原始账户信息 |
|
|
||||||
| 客服中心 `/app/support`;UI-C-SUPPORT-001 | 通过 | 客服依依、客服琪琪、客服琳琳均显示;在线/离线状态、工作时间和联系电话正常显示 |
|
|
||||||
|
|
||||||
## 4. 缺陷记录
|
|
||||||
|
|
||||||
### DEF-C-001 已绑定收款账户未在“绑定信息”页回显
|
|
||||||
|
|
||||||
| 项目 | 内容 |
|
|
||||||
|---|---|
|
|
||||||
| 严重级别 | P1 |
|
|
||||||
| 关联用例 | UI-C-FORM-003、UI-C-FORM-010、UI-C-FORM-011、C-FIN-039 |
|
|
||||||
| 前置条件 | 会员已登录,且已有收款账户 |
|
|
||||||
| 复现步骤 | 1. 打开“我的 → 取出”,确认页面显示 `icbc 6655******4555`;2. 打开“我的 → 个人信息 → 取出信息/绑定信息” |
|
|
||||||
| 预期结果 | 页面显示本人姓名、身份证号、银行名、完整卡号,以及已上传的微信/支付宝收款码;允许按业务规则编辑或继续新增 |
|
|
||||||
| 实际结果 | 页面只显示空白的新增绑定表单,已有账户信息未回显 |
|
|
||||||
| 影响 | 用户无法从个人中心核对已有收款资料,容易重复绑定或误判资料丢失 |
|
|
||||||
| 建议检查 | 检查页面是否调用 `/v1/payment-accounts/details`;确认接口返回账户列表后是否被表单初始化逻辑覆盖;多账户场景需逐条展示并保持收款码对应关系 |
|
|
||||||
|
|
||||||
补充诊断:
|
|
||||||
|
|
||||||
- 已核对线上 C 端静态资源,当前发布包包含 `/v1/payment-accounts/details`、`已绑定的取出信息` 和 `添加银行卡`,不是前端漏发版。
|
|
||||||
- 已只读核对测试库:会员 `potter`(member_id=9、tenant_id=0)确有 1 条未删除的 `icbc` 收款账户,脱敏卡号为 `6655******4555`,密文字段及微信/支付宝附件 ID 均非空。
|
|
||||||
- 本地代码的详情接口会解密敏感字段;只要服务端 finance key 未配置、与写入时密钥不一致,或详情接口返回异常,页面就会保留空数组并显示新增表单。下一步应抓取该登录会话下 `/v1/payment-accounts/details` 的真实响应,重点检查 `OLONS_SERVER_FINANCE_MASTER_KEY` 与该账户写入时使用的密钥是否一致。
|
|
||||||
|
|
||||||
## 5. 构建与自动化检查
|
|
||||||
|
|
||||||
### 5.1 C 端前端构建
|
|
||||||
|
|
||||||
- 目录:`olons_server/web`
|
|
||||||
- 命令:`pnpm run build`
|
|
||||||
- 结果:通过
|
|
||||||
- 构建结果:4186 个模块完成转换,生产包成功生成
|
|
||||||
|
|
||||||
### 5.2 管理后台前端构建
|
|
||||||
|
|
||||||
- 目录:`olons_admin/web`
|
|
||||||
- 常规 `pnpm run build`:被 pnpm 的依赖脚本安全检查阻断,提示 `ERR_PNPM_IGNORED_BUILDS`
|
|
||||||
- 使用已有依赖直接执行 Vite 与 HotGo postBuild:通过
|
|
||||||
- 构建结果:6728 个模块完成转换,`dist/app.config.js` 正常生成
|
|
||||||
- 说明:这是本机 pnpm 依赖脚本策略问题,不是业务代码编译失败;CI 应固定 pnpm 版本及 `onlyBuiltDependencies/approve-builds` 配置,避免发布时临时阻断
|
|
||||||
|
|
||||||
### 5.3 后台 Go 测试
|
|
||||||
|
|
||||||
- 目录:`olons_admin/server`
|
|
||||||
- 命令:`go test ./...`
|
|
||||||
- 结果:失败
|
|
||||||
- 失败 1:`internal/library/casbin.TestNew`,错误为 `casbin model file does not exist:manifest/config/casbin.conf`
|
|
||||||
- 失败 2:`internal/library/network/tcp_test.TestSendMsg`,依赖的 `127.0.0.1:8002` 未启动;连接失败后仍调用空连接的 `Send`,触发空指针 panic
|
|
||||||
- 失败 3:`internal/library/storager.TestMergePartFile`,测试数据/参数无效后仍继续使用空对象,触发空指针 panic
|
|
||||||
- 判断:上述均属于测试工程对当前目录、外部服务或本地文件的隐式依赖,同时缺少失败后的安全返回;本轮 `internal/logic/sys` 等核心业务包测试通过
|
|
||||||
- 建议:Casbin 测试使用可确定的项目根路径或 `testdata`;TCP 测试自建临时监听服务;存储测试自建临时文件;所有前置失败后立即 `t.Fatal` 或返回,避免二次 panic
|
|
||||||
|
|
||||||
### 5.4 线上可用性与未登录鉴权
|
|
||||||
|
|
||||||
| 检查项 | 实际结果 | 结论 |
|
|
||||||
|---|---|---|
|
|
||||||
| `GET https://olns-web.118im.com/api/health` | HTTP 200 | 通过 |
|
|
||||||
| 未登录访问 `GET /v1/me` | HTTP 401 | 通过 |
|
|
||||||
| 未登录访问 `GET /v1/payment-accounts/details` | HTTP 401 | 通过 |
|
|
||||||
| 管理后台入口 | HTTP 200 | 通过 |
|
|
||||||
|
|
||||||
## 6. 阻塞与待执行项
|
|
||||||
|
|
||||||
1. 管理后台 URL 地址池、会员登录日志及其他菜单逐按钮验收:执行机器锁屏,待解锁后续测。
|
|
||||||
2. 新增、编辑、删除、发布/下架、审核、充值、提现、任务提交、客服发消息等写操作:需要专用测试数据并确认允许产生或清理测试记录后执行。
|
|
||||||
3. URL 地址池 Excel 合法、重复、错误行导入:需要使用用例中的 XLS-URL 文件执行,会产生数据库写入,暂未提交。
|
|
||||||
4. 多账户详情、收款码图片一致性、敏感信息展示权限:需在专用测试会员上执行,避免暴露或修改真实会员资料。
|
|
||||||
|
|
||||||
## 7. 下一轮计划
|
|
||||||
|
|
||||||
1. 解锁后从后台菜单真实点击进入 URL 地址池,依次验证查询、重置、新增/编辑弹窗、详情、启用/失效、复制链接、Excel 导入弹窗及无删除按钮。
|
|
||||||
2. 验证会员登录日志查询、分页、详情和导出入口。
|
|
||||||
3. 按菜单顺序完成交易、商品、任务、组织、权限、系统应用、系统设置页面的所有可逆操作。
|
|
||||||
4. 建立专用测试会员、商品、订单和 URL 地址数据,再执行会改变业务状态的 P0/P1 用例。
|
|
||||||
5. 修复 DEF-C-001 后,执行绑定信息与提现账户关联回归。
|
|
||||||
|
|
||||||
## 8. 第二轮后台页面执行记录(解锁后)
|
|
||||||
|
|
||||||
### 8.1 URL 地址池与会员登录日志
|
|
||||||
|
|
||||||
| 页面/关联用例 | 状态 | 实际结果 |
|
|
||||||
|---|---|---|
|
|
||||||
| URL 地址池;UI-A-URL-001、002 | 通过 | 汇总卡、筛选、展开/收起、查询、重置、分页和空状态正常;重置可清空条件 |
|
|
||||||
| URL 地址池新增;UI-A-URL-003 | 部分通过 | 新增弹窗包含地址名称、注册入口 URL、状态、备注及保存/取消;未提交写库 |
|
|
||||||
| URL 地址池详情/启停/复制;UI-A-URL-004、005 | 阻塞 | 当前列表 0 条,无可操作数据 |
|
|
||||||
| URL Excel 导入;UI-A-URL-006 | 部分失败 | 格式说明、关闭入口、`.xlsx/.xlsm`、5000 条限制、重复跳过和错误行说明完整,但弹窗没有“取消”按钮 |
|
|
||||||
| 会员登录日志;UI-A-MLOGIN 系列 | 部分通过 | 会员、方式、状态、域名、IP、时间筛选齐全;查询、重置、展开/收起和导出均可用;当前列表 0 条,详情无法验证 |
|
|
||||||
|
|
||||||
### 8.2 交易管理
|
|
||||||
|
|
||||||
| 页面/关联用例 | 状态 | 实际结果 |
|
|
||||||
|---|---|---|
|
|
||||||
| 订单列表;UI-A-ORDER-001 | 部分失败 | 单号、用户名、手机号、状态、时间筛选可用,但缺少用例要求的“派单方式”筛选 |
|
|
||||||
| 订单详情;UI-A-ORDER-002、A-TRADE-002 | 失败 | 仅显示订单号、会员、商品/任务、等级、金额和规则快照;缺少时间线、资金流水等追溯信息 |
|
|
||||||
| 匹配订单;UI-A-ORDER-003、A-TRADE-003 | 通过 | 弹窗可按商品名和价格筛选;发布商品可见,保时捷跑车、新手体验商品等均能查询;清理筛选和取消正常 |
|
|
||||||
| 充值列表;UI-A-RC-001 | 部分失败 | 汇总卡、列表、通过/驳回入口正常;多条真实记录的“真实姓名”列为空,仅在备注中出现登录名 |
|
|
||||||
| 充值通过/驳回;UI-A-RC-002、003 | 部分通过 | 通过弹窗包含实付金额、外部支付单号和审核说明;驳回弹窗包含原因与说明;取消无副作用,未执行最终审核 |
|
|
||||||
| 提现列表;UI-A-WD-001 | 部分通过 | 金额、手续费、实到、状态和银行卡脱敏正常;当前 potter 记录的支付宝/微信收款码均显示“-”,需结合账户附件继续核对 |
|
|
||||||
| 提现通过/驳回;UI-A-WD-002 | 通过 | 合法状态显示按钮,二次确认文案正确,取消无副作用;未执行最终审核 |
|
|
||||||
| 客服管理;UI-A-CS-001、002 | 部分通过 | 查询、新增/编辑表单、IM 账号和备用联系方式完整;启停操作即时生效,测试后已恢复原状态;未执行删除 |
|
|
||||||
|
|
||||||
### 8.3 商品、任务和权限
|
|
||||||
|
|
||||||
| 页面/关联用例 | 状态 | 实际结果 |
|
|
||||||
|---|---|---|
|
|
||||||
| 商品列表;UI-A-PROD-001、006 | 通过 | 名称/分类筛选、添加、批量删除入口完整;编辑、发布/下架、推荐/不推荐、删除均可见且操作列未截断 |
|
|
||||||
| 商品表单;UI-A-PROD-002 | 部分通过 | 名称、分类、店铺、价格、图片、详情字段完整;未保存写库 |
|
|
||||||
| 任务列表;UI-A-TASK-001 | 失败 | 列表、状态操作和任务基本字段正常,但新增任务弹窗没有“商品”选择字段,与用例和任务关联设计不一致 |
|
|
||||||
| 会员任务审核;UI-A-SUB-001、004 | 失败 | 列表“任务标题”全部为空;详情中的“任务”也为空,并且没有订单信息,不能完成会员—订单—任务追溯 |
|
|
||||||
| 角色菜单权限;UI-A-ROLE-002、003 | 部分通过 | 弹窗明确限制为父角色权限子集;主页、组织管理、系统应用、系统设置等根节点均可勾选;勾选组织管理后“后台用户”自动选中,父子级联正常;未提交保存 |
|
|
||||||
| 系统应用菜单;UI-A-APP-001 | 通过 | 日志管理、附件管理、个人中心入口均存在,个人中心已恢复可见 |
|
|
||||||
|
|
||||||
## 9. 第二轮新增缺陷
|
|
||||||
|
|
||||||
### DEF-A-001 URL 地址池 Excel 导入弹窗缺少取消按钮
|
|
||||||
|
|
||||||
- 严重级别:P2
|
|
||||||
- 关联用例:UI-A-URL-006
|
|
||||||
- 实际结果:弹窗仅提供右上角关闭,没有底部取消按钮。
|
|
||||||
- 影响:与后台其他弹窗交互不一致,触屏或窄屏下关闭入口不够明显。
|
|
||||||
|
|
||||||
### DEF-A-002 订单详情缺少完整业务追溯信息
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-ORDER-002、A-TRADE-002、A-TRADE-030
|
|
||||||
- 实际结果:详情只展示基础字段和 JSON 规则快照,没有订单状态时间线、付款/冻结/佣金流水、审核记录。
|
|
||||||
- 影响:客服和财务无法从单一页面核对订单状态与资金变化。
|
|
||||||
- 代码定位:`TradeOrderViewModel` 只在列表模型上补充 `taskId/productId/memberLevelId/ruleSnapshot`,`trade_order.go` 的 `View` 也只组装这些字段;前端详情弹窗没有请求或渲染资金流水、审批动作和状态时间线。
|
|
||||||
|
|
||||||
### DEF-A-003 多个后台交易页面直接显示完整手机号
|
|
||||||
|
|
||||||
> 处理结论(2026-10-16):产品方确认会员列表、详情及相关业务页面允许显示完整手机号,本项改判为“已接受设计”,不再作为缺陷,不实施手机号脱敏改造。
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 涉及页面:会员列表/详情、订单列表/详情、充值列表、会员任务审核列表/详情
|
|
||||||
- 实际结果:显示 `13311111111`、`15122421111` 等完整手机号。
|
|
||||||
- 预期结果:默认脱敏;只有具备单独敏感信息权限的人员才能查看明文,且需留痕。
|
|
||||||
- 代码定位:订单和任务审核查询直接选择 `hg_app_member.mobile`,前端表格直接绑定 `mobile`;当前链路没有脱敏 DTO,也没有敏感字段权限判断。
|
|
||||||
- 补测结果:会员详情明确提供“授权查看明文”按钮,但未授权前手机号已经完整显示,说明当前授权入口只停留在 UI,未形成真正的数据隔离。
|
|
||||||
|
|
||||||
### DEF-A-004 订单列表缺少派单方式筛选
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-ORDER-001、A-TRADE-001
|
|
||||||
- 实际结果:高级筛选只有用户名、手机号、订单状态和下单时间,没有自动/手动派单方式。
|
|
||||||
- 代码定位:前端 `trade/order/model.ts` 的 `schemas` 和后端 `TradeOrderListInp` 均没有派单方式查询字段,属于前后端共同缺项。
|
|
||||||
|
|
||||||
### DEF-A-005 新增任务弹窗缺少商品字段
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-TASK-001
|
|
||||||
- 实际结果:弹窗包含任务大厅、等级、佣金、数量、周期、封面和详情,但没有关联商品选择。
|
|
||||||
- 影响:无法按设计建立任务与商品的明确关联。
|
|
||||||
- 代码定位:`hg_task` 对应实体和 `TaskEditInp` 均没有 `product_id`,不是单纯前端漏控件,需要先确认任务是否应直接关联商品,再同步迁移、实体、接口和页面。
|
|
||||||
|
|
||||||
### DEF-A-006 会员任务记录缺少任务标题和订单关联
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-SUB-001、UI-A-SUB-004
|
|
||||||
- 实际结果:列表的任务标题为空;详情的任务字段为空;详情未显示订单。
|
|
||||||
- 影响:审核记录无法追溯到具体任务和订单,已结算记录也难以审计。
|
|
||||||
- 数据与代码定位:只读核对最新记录,`task_id` 均为 `0`,但 `trade_order_id` 有值;`task_submission.go` 只按 `s.task_id = t.id` 关联任务,没有通过交易订单/商品兜底,因此标题必然为空。审核逻辑还会再次按 `task_id` 查任务,待审核记录可能直接报“关联任务不存在”。
|
|
||||||
|
|
||||||
### DEF-A-007 充值列表真实姓名缺失
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-RC-001、A-TRADE-012
|
|
||||||
- 实际结果:多条真实充值记录的“真实姓名”列为空,备注中仅显示 `姓名:potter` 等登录名。
|
|
||||||
- 影响:人工审核无法直接核对付款人真实姓名,容易造成误审。
|
|
||||||
|
|
||||||
## 10. 第三轮后台页面执行记录
|
|
||||||
|
|
||||||
### 10.1 主页与门户配置
|
|
||||||
|
|
||||||
| 页面/关联用例 | 状态 | 实际结果 |
|
|
||||||
|---|---|---|
|
|
||||||
| 商城统计首页;UI-A-HOME-001、002 | 失败 | 今日默认区间无汇总;切换近 30 日后能显示指标和微信/支付宝/银行卡渠道数据,但数据截止时间为 `2026-10-11 13:46:46`,页面提示延迟约 107 小时,汇总任务明显停滞 |
|
|
||||||
| 网站设置;UI-A-SITE-001、002 | 部分失败 | 表单字段和保存入口完整,但线上已保存配置中隐私网址为空,大量标记“必填”的交易阈值、次数、佣金和自动派单值均为 0;字段“未订单的支付等待时长”文案不通顺,疑为“未支付订单” |
|
|
||||||
| 文本管理;UI-A-CONTENT-001~004 | 通过 | 初始化数据共 12 条,与原型数量一致;列表已隐藏内容标识;新增、编辑、版本、预览、上下线和删除入口完整;本轮仅打开新增、版本和预览并取消,未写库 |
|
|
||||||
| Banner 设置;UI-A-BANNER-001、002 | 失败 | 6 条记录状态与操作入口可见,但列表图片列全部为空;打开编辑后,必填 Banner 图片也未回显,现有演示记录不满足接口对图片必填的约束 |
|
|
||||||
| 手工商城;UI-A-MANUAL-001~003 | 失败 | 4 条记录可查询、编辑和删除,但图片列全部为空;编辑弹窗的必填展示图片未回显;页面没有发布/下架入口,也不显示发布状态 |
|
|
||||||
|
|
||||||
### 10.2 会员管理补测
|
|
||||||
|
|
||||||
| 页面/关联用例 | 状态 | 实际结果 |
|
|
||||||
|---|---|---|
|
|
||||||
| 会员列表;UI-A-MEMBER-001、002 | 部分失败 | 17 条会员可查询,类别与派单模式显示正确,操作列横向滚动条可用;但页面声明“会员资料默认脱敏展示”,列表和详情仍直接显示完整手机号 |
|
|
||||||
| 会员详情敏感信息;UI-A-MEMBER-003 | 失败 | 详情存在“授权查看明文”按钮,但尚未授权时手机号已经是明文,授权入口没有起到敏感数据隔离作用 |
|
|
||||||
| 会员银行卡信息;UI-A-MEMBER-004、C-FIN-039 | 失败 | 查询 `potter` 后打开银行卡信息,只有银行名 `icbc` 回显;开户人、开户电话、卡号、支付宝/微信收款码全部为空,与提现页已存在的账户及数据库记录不一致 |
|
|
||||||
| 会员等级;UI-A-LEVEL-001~003 | 部分通过 | 7 个初始化等级、价格、赠送金额、接单/提现次数、佣金比例、会员数和编辑/启停/删除入口正常;图标列均为空;删除有二次确认并提示仅无会员且未被任务大厅引用时可删,本轮取消未提交 |
|
|
||||||
| 任务大厅;UI-A-HALL-001~003 | 失败 | 6 条初始化记录可编辑/删除,但图标列为空;后端已有发布状态和状态接口,页面却不显示状态,也没有发布/下架操作 |
|
|
||||||
| 后台用户;UI-A-ADMIN-001、002 | 部分通过 | 菜单真实路径为 `/org/user`,新增表单字段完整;空表单提交能阻止保存并提示填写用户名/密码;当前角色范围列表为 0 条,编辑、状态和删除无法继续验证 |
|
|
||||||
| 管理后台登录日志;UI-A-LOG-001~003 | 通过 | 共 30 条记录,查询、重置、展开、导出、详情、单条/批量删除入口完整;本轮未删除日志 |
|
|
||||||
|
|
||||||
### 10.3 本轮操作安全说明
|
|
||||||
|
|
||||||
- 文本新增、Banner 编辑、手工商城编辑仅打开弹窗查看字段后取消,没有保存。
|
|
||||||
- 首页只切换统计周期,没有触发交易、审核或资金操作。
|
|
||||||
- 角色权限上一轮的勾选联动验证未提交;客服状态验证后已恢复原状态。
|
|
||||||
|
|
||||||
## 11. 第三轮新增缺陷
|
|
||||||
|
|
||||||
### DEF-A-008 首页汇总任务停滞,统计数据延迟 107 小时
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-HOME-001、UI-A-HOME-002
|
|
||||||
- 实际结果:近 30 日指标可以加载,但数据截至 `2026-10-11 13:46:46`,在 `2026-10-16` 验收时页面提示延迟约 107 小时。
|
|
||||||
- 影响:首页经营指标无法反映当前订单、充值、提现和余额情况,不能作为运营决策依据。
|
|
||||||
- 代码定位:仓库只有 `hg_dashboard_daily_stat` 的读取逻辑和演示数据 seed,未检索到生产汇总表的写入/刷新任务;需确认是否由仓库外 ETL 承担,如无则缺少汇总任务实现。
|
|
||||||
|
|
||||||
### DEF-A-009 网站设置存在不完整的线上配置
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-SITE-001、UI-A-SITE-002
|
|
||||||
- 实际结果:隐私网址为空;多个必填业务参数为 0;网站名称仍为“演示站点-3”。
|
|
||||||
- 影响:隐私协议入口、订单等待、交易限制、佣金和自动派单等 C 端行为可能失效或采用异常零值。
|
|
||||||
- 建议:发布前建立配置完整性校验和默认值迁移;加载历史无效配置时给出显著告警,不允许无提示继续运行。
|
|
||||||
|
|
||||||
### DEF-A-010 Banner 与手工商城初始化记录缺少必填图片
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-BANNER-001、UI-A-BANNER-002、UI-A-MANUAL-001、UI-A-MANUAL-002
|
|
||||||
- 实际结果:两个列表的图片列均为空,编辑弹窗也没有回显图片;后端过滤逻辑却要求 Banner `imageUrl`、手工商品 `coverUrl` 必填。
|
|
||||||
- 影响:C 端可能出现空白横幅/商品图;旧记录打开后可能无法在不重新上传图片的情况下保存。
|
|
||||||
- 建议:修正初始化数据并补数据校验脚本;列表为空图时显示明确占位和“图片缺失”告警。
|
|
||||||
|
|
||||||
### DEF-A-011 手工商城发布状态功能未接入页面
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-MANUAL-001、UI-A-MANUAL-003
|
|
||||||
- 实际结果:后端已有 `ManualProductStatus` 接口和发布状态字段,但列表不显示状态、没有发布/下架按钮;编辑接口还会把商品直接改为已发布。
|
|
||||||
- 影响:运营无法在手工商城页面控制上下架,编辑草稿或已下架商品会绕过明确确认直接发布。
|
|
||||||
- 建议:列表增加状态列和发布/下架操作;编辑仅保存内容,不隐式改变发布状态。
|
|
||||||
|
|
||||||
### DEF-A-012 会员银行卡编辑页未回显已有敏感账户资料
|
|
||||||
|
|
||||||
- 严重级别:P0
|
|
||||||
- 关联用例:UI-A-MEMBER-004、UI-C-FORM-003、C-FIN-039、DEF-C-001
|
|
||||||
- 复现步骤:会员列表查询 `potter`,点击“银行卡信息”。
|
|
||||||
- 实际结果:仅开户银行 `icbc` 回显;开户人、开户电话、银行卡号、支付宝与微信收款码均为空。
|
|
||||||
- 预期结果:经过敏感信息授权后完整回显;未授权时至少显示脱敏值和已有附件占位,且禁止空值覆盖密文。
|
|
||||||
- 影响:后台人员无法核对已有账户,直接保存存在把已有敏感字段和附件清空的高风险;同时解释了 C 端绑定信息页为何显示空表单。
|
|
||||||
- 建议:优先检查 finance key 与历史数据加密密钥是否一致、详情接口的解密错误是否被吞掉;编辑接口必须采用“未传不更新”语义,附件 ID 不得因前端未回显而被置空。
|
|
||||||
|
|
||||||
### DEF-A-013 任务大厅发布状态功能未接入页面
|
|
||||||
|
|
||||||
- 严重级别:P1
|
|
||||||
- 关联用例:UI-A-HALL-001、UI-A-HALL-003
|
|
||||||
- 实际结果:列表不显示发布状态,仅有编辑和删除;草稿、待审、已发布、已下线、已归档等状态只能从演示名称猜测。
|
|
||||||
- 代码定位:后端 `task_hall.go` 已实现 `Status`,前端 API 也定义了 `/taskHall/status`,但 `app-member/task-hall/index.vue` 未导入或调用 `Status`,操作列只有编辑/删除;新增大厅还会直接设为已发布。
|
|
||||||
- 影响:运营无法进行清晰的发布/下架流程,新增内容绕过发布确认直接对 C 端生效。
|
|
||||||
- 建议:增加状态列和发布/下架按钮;新增与编辑只保存内容,发布必须走单独状态接口并保留审计记录。
|
|
||||||
|
|
||||||
## 12. 当前阶段结论与修复优先级
|
|
||||||
|
|
||||||
- 当前累计登记 14 项,其中 13 个有效缺陷(P0 1 个、P1 11 个、P2 1 个)和 1 项已接受设计;C 端收款账户回显缺陷与 P0 后台问题属于同一根因链,合并修复与回归。
|
|
||||||
- 第一优先级:DEF-A-012 / DEF-C-001,先恢复历史收款账户的安全解密与回显,并防止空表单覆盖密文和附件。
|
|
||||||
- 第二优先级:DEF-A-006、DEF-A-008,修复任务审核关联和首页汇总任务,否则审核与运营数据均不可信。
|
|
||||||
- 发布前必须处理:网站配置完整性、Banner/商品图片缺失、手工商城与任务大厅发布状态入口。
|
|
||||||
|
|
||||||
## 13. 缺陷修复实施记录
|
|
||||||
|
|
||||||
| 编号 | 处理结果 | 修复内容 |
|
|
||||||
|---|---|---|
|
|
||||||
| DEF-C-001 / DEF-A-012 | 已修复,待发布回归 | C 端详情接口在历史密钥不可用时回退脱敏字段,不再因单条解密失败让整页为空;后台回显姓名、身份证、手机、账号、数字人民币和双收款码脱敏信息;敏感字段和附件采用“未传不更新”语义,并保留授权查看入口 |
|
|
||||||
| DEF-A-001 | 已修复 | URL 地址 Excel 导入弹窗增加底部取消按钮 |
|
|
||||||
| DEF-A-002 | 已修复 | 订单详情增加状态、创建/更新时间、状态时间线、资金流水和审批动作 |
|
|
||||||
| DEF-A-003 | 已接受设计 | 产品方确认允许展示完整手机号,不修改 |
|
|
||||||
| DEF-A-004 | 已修复 | 订单列表新增自动/手动派单模式筛选,后端同步按规则快照查询 |
|
|
||||||
| DEF-A-005 | 已修复 | `hg_task` 增加 `product_id` 迁移并重新生成 DAO/实体;任务新增/编辑增加商品选择、校验和列表回显 |
|
|
||||||
| DEF-A-006 | 已修复 | 审核列表通过交易订单兜底任务标题并显示订单号/商品;`task_id=0` 时按订单归属校验后允许审核,不再误报任务不存在 |
|
|
||||||
| DEF-A-007 | 已修复 | 充值真实姓名优先取实名资料,缺失时回退默认银行卡开户人脱敏值 |
|
|
||||||
| DEF-A-008 | 已修复 | 增加 `dashboard_daily_summary` 汇总任务并注册到 HotGo 定时任务管理;默认每 10 分钟重算今天和昨天,可在后台启停、改表达式和手动执行 |
|
|
||||||
| DEF-A-009 | 已修复 | 后端强制校验隐私地址、交易余额、等待时长、次数、最低充值和自动派单参数;迁移补齐历史零值并修正文案 |
|
|
||||||
| DEF-A-010 | 已修复 | 增加随服务部署的 Banner/商品占位资源,迁移只补齐历史空图片记录 |
|
|
||||||
| DEF-A-011 | 已修复 | 手工商城显示发布状态并增加发布/下架;新增默认草稿,编辑不再隐式发布 |
|
|
||||||
| DEF-A-013 | 已修复 | 任务大厅显示发布状态并增加发布/下线;新增默认草稿 |
|
|
||||||
|
|
||||||
### 13.1 修复后自动化验证
|
|
||||||
|
|
||||||
- 管理后台:`go test ./internal/logic/sys ./internal/crons ./internal/model/input/sysin` 通过。
|
|
||||||
- 管理后台前端:`npm run build` 生产构建通过,6728 个模块完成转换。
|
|
||||||
- C 端:`go test ./internal/finance ./internal/store` 通过;新增“历史密钥不可用时回退脱敏数据”回归用例。
|
|
||||||
- C 端前端:`npm run build` 通过,4186 个模块完成转换。
|
|
||||||
- 新增迁移已在本地 MySQL 8.4 验证;定时任务记录成功初始化,Banner 和商品空图片数量均变为 0。
|
|
||||||
- 页面回归暂未完成:执行机器再次进入锁屏状态,无法继续通过浏览器点击;服务与前端均已在本地启动,解锁后可直接续测。
|
|
||||||
|
|
||||||
## 14. 测试环境发布后回归(2026-10-16)
|
|
||||||
|
|
||||||
### 14.1 已通过
|
|
||||||
|
|
||||||
- URL 地址池 Excel 导入弹窗已显示“取消”,点击后正常关闭。
|
|
||||||
- 订单列表已显示自动/手动派单模式,展开查询条件后可见派单模式筛选。
|
|
||||||
- 订单详情已显示状态、冻结状态、创建/更新时间、状态时间线、资金流水和审批记录。
|
|
||||||
- 会员任务审核列表已回显任务/商品名称和订单号,历史数据不再空白。
|
|
||||||
- 会员银行卡信息弹窗已回显开户人、身份证、银行卡、数字钱包和两类收款码;C 端“绑定信息”页也正常显示历史账户。
|
|
||||||
- 手工商城和任务大厅已显示发布状态及发布/下架(下线)操作。
|
|
||||||
- Banner 和商品列表的现有图片资源均能正常加载。
|
|
||||||
- 网站设置已回显站点名称、HTTPS 隐私地址、交易余额、等待时长、次数、最低充值和自动派单范围。
|
|
||||||
- 经营看板用同一套 `RefreshDaily` 逻辑手工触发后,显示 17 会员、9 商品、余额与昨日订单/充值数据,数据延迟 14 秒。
|
|
||||||
|
|
||||||
### 14.2 发布过程中已补齐
|
|
||||||
|
|
||||||
- 首次进入任务列表时接口报错,根因为测试库未执行 `hg_task.product_id` 迁移;补执后页面恢复。
|
|
||||||
- 已在测试库初始化 `dashboard_daily_summary` 定时任务,并补齐站点配置及空图片默认值。
|
|
||||||
- 站点配置迁移原先把数字写成 JSON 字符串,已改为强制写入 JSON 数值,页面回显正常。
|
|
||||||
|
|
||||||
### 14.3 需再发布后复测
|
|
||||||
|
|
||||||
- 新增任务弹窗请求商品时使用了 `perPage=500`,超过后端上限 200;已改为 200。
|
|
||||||
- 部分历史充值单没有实名档案和收款账户,但备注中存在“姓名:xxx”;已增加从备注回退显示姓名。
|
|
||||||
- 定时任务记录是在当前服务进程启动后插入的,现进程尚未加载该任务;再次发布/重启后需等待一个 10 分钟周期,确认 `calculated_at` 自动推进。
|
|
||||||
- 当前测试账号 `potter`(系统管理员角色)没有“定时任务”菜单权限,无法在页面手动执行;需使用超级管理员或在角色权限中授予该菜单。
|
|
||||||
@@ -1,952 +0,0 @@
|
|||||||
# URL 地址池与会员注册域名绑定设计方案
|
|
||||||
|
|
||||||
> 文档状态:方案设计
|
|
||||||
> 方案版本:v2.1
|
|
||||||
> 最后更新:2026-10-15
|
|
||||||
> 适用项目:Olons Admin / HotGo
|
|
||||||
> 关联模块:会员注册、会员登录、会员管理、URL 地址池管理、会员登录日志
|
|
||||||
|
|
||||||
## 1. 方案变更说明
|
|
||||||
|
|
||||||
原方案采用“会员注册时从 URL 地址池轮询取出一个 URL”的模式。现调整为“会员通过哪个域名打开注册页面,就与哪个域名建立绑定关系”。
|
|
||||||
|
|
||||||
新流程如下:
|
|
||||||
|
|
||||||
```text
|
|
||||||
管理员或推广人员先向用户提供一个注册链接
|
|
||||||
→ 用户通过该链接打开注册页面
|
|
||||||
→ 注册页面获取浏览器地址栏中的域名
|
|
||||||
→ 用户提交注册
|
|
||||||
→ 后端校验本次请求的真实注册域名
|
|
||||||
→ 创建会员
|
|
||||||
→ 建立会员与注册域名的绑定关系
|
|
||||||
```
|
|
||||||
|
|
||||||
本方案不再使用 URL 轮询顺序、分配游标和自动轮询算法。URL 地址池的作用调整为:
|
|
||||||
|
|
||||||
1. 维护允许用于会员注册的域名;
|
|
||||||
2. 管理域名的启用、失效状态;
|
|
||||||
3. 统计每个域名带来的注册会员;
|
|
||||||
4. 查询会员与注册域名的绑定关系。
|
|
||||||
|
|
||||||
每个地址同时维护累计绑定次数。地址池列表默认把绑定次数较少的地址排在前面;点击地址详情可以查看当前绑定该地址的全部会员。
|
|
||||||
|
|
||||||
## 2. 设计目标
|
|
||||||
|
|
||||||
1. 用户使用某个域名注册时,自动与该域名绑定。
|
|
||||||
2. 注册域名由后端根据可信请求信息确认,不能只信任前端传入值。
|
|
||||||
3. 每个会员只能存在一个当前绑定域名。
|
|
||||||
4. 域名未配置或已失效时,会员仍允许注册成功,但保持“待绑定”。
|
|
||||||
5. 后台不提供创建会员、手动绑定或重新绑定域名的入口。
|
|
||||||
6. 域名失效后不再接受新的自动绑定,但保留原有绑定用于审计。
|
|
||||||
7. 支持同域部署、前后端跨域部署以及 CDN/反向代理部署。
|
|
||||||
8. 所有注册自动绑定和地址状态变更都有业务审计记录。
|
|
||||||
9. 每个地址记录累计绑定次数,地址池列表默认按绑定次数升序排列。
|
|
||||||
10. 后台可以手动将启用地址切换为失效,也可以将失效地址重新启用。
|
|
||||||
11. C 端会员登录成功后更新会员最后登录时间、IP脱敏信息和地区。
|
|
||||||
12. C 端会员每次登录成功或失败均记录独立日志,并可在后台查询、查看和导出。
|
|
||||||
|
|
||||||
## 3. 核心概念
|
|
||||||
|
|
||||||
### 3.1 注册 URL
|
|
||||||
|
|
||||||
管理员或推广人员提供给用户的完整注册链接,例如:
|
|
||||||
|
|
||||||
```text
|
|
||||||
https://register-a.example.com/register?inviteCode=ABC123
|
|
||||||
```
|
|
||||||
|
|
||||||
完整 URL 中可能包含路径、邀请码或其他查询参数,但会员绑定只取域名部分:
|
|
||||||
|
|
||||||
```text
|
|
||||||
register-a.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
默认端口不作为域名的一部分:
|
|
||||||
|
|
||||||
```text
|
|
||||||
https://register-a.example.com:443 → register-a.example.com
|
|
||||||
http://register-a.example.com:80 → register-a.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
非默认端口的测试环境可以保留端口:
|
|
||||||
|
|
||||||
```text
|
|
||||||
http://127.0.0.1:5173 → 127.0.0.1:5173
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.2 URL 地址池
|
|
||||||
|
|
||||||
URL 地址池是允许用于注册绑定的域名白名单。地址池中的域名分为:
|
|
||||||
|
|
||||||
| 值 | 状态 | 说明 |
|
|
||||||
|---:|---|---|
|
|
||||||
| 1 | 启用 | 允许新注册会员自动绑定 |
|
|
||||||
| 2 | 失效 | 不允许新注册会员自动绑定,保留原绑定关系 |
|
|
||||||
|
|
||||||
### 3.3 会员域名绑定
|
|
||||||
|
|
||||||
会员注册成功后,如果识别出的域名在地址池中存在且为启用状态,则创建绑定记录。
|
|
||||||
|
|
||||||
一个会员最多有一个绑定域名。绑定只允许在 C 端会员注册事务中自动建立,后台只能查看,不能手动绑定、解除绑定或重新绑定。
|
|
||||||
|
|
||||||
### 3.4 待绑定会员
|
|
||||||
|
|
||||||
以下情况会员注册成功但不建立域名绑定:
|
|
||||||
|
|
||||||
- 请求中无法识别有效注册域名;
|
|
||||||
- 注册域名没有配置在地址池中;
|
|
||||||
- 注册域名已经失效;
|
|
||||||
|
|
||||||
没有绑定记录的会员统一显示为“待绑定”。
|
|
||||||
|
|
||||||
## 4. 业务规则
|
|
||||||
|
|
||||||
### 4.1 正常注册绑定
|
|
||||||
|
|
||||||
```text
|
|
||||||
用户打开 https://register-a.example.com/register
|
|
||||||
→ 前端读取 window.location.origin
|
|
||||||
→ 用户提交注册
|
|
||||||
→ 后端确认真实来源域名为 register-a.example.com
|
|
||||||
→ 查询地址池
|
|
||||||
→ 地址存在且启用
|
|
||||||
→ 创建会员及钱包
|
|
||||||
→ 创建会员与 register-a.example.com 的绑定
|
|
||||||
→ 注册成功
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.2 地址池没有该域名
|
|
||||||
|
|
||||||
```text
|
|
||||||
用户通过 unknown.example.com 注册
|
|
||||||
→ 后端未在地址池找到该域名
|
|
||||||
→ 会员和钱包正常创建
|
|
||||||
→ 不创建域名绑定记录
|
|
||||||
→ 记录“未知注册域名”业务审计
|
|
||||||
→ 会员显示为待绑定
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.3 域名已经失效
|
|
||||||
|
|
||||||
```text
|
|
||||||
用户通过已失效域名注册
|
|
||||||
→ 会员正常创建
|
|
||||||
→ 不建立自动绑定
|
|
||||||
→ 记录“通过失效域名注册”业务审计
|
|
||||||
→ 会员显示为待绑定
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.4 重复注册请求
|
|
||||||
|
|
||||||
同一会员创建请求因网络原因重复提交时,应通过现有手机号、用户名唯一约束和注册幂等机制防止重复创建。
|
|
||||||
|
|
||||||
对已经存在的会员重复执行域名绑定:
|
|
||||||
|
|
||||||
- 已绑定同一域名:直接返回成功;
|
|
||||||
- 已绑定其他域名:不能由注册接口覆盖,也不提供后台改绑入口;
|
|
||||||
- 既有会员尚未绑定:保持待绑定,注册接口不做事后补绑。
|
|
||||||
|
|
||||||
## 5. 注册域名识别
|
|
||||||
|
|
||||||
### 5.1 前端采集
|
|
||||||
|
|
||||||
注册页面提交以下辅助字段:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const registerOrigin = window.location.origin;
|
|
||||||
const registerHost = window.location.host;
|
|
||||||
```
|
|
||||||
|
|
||||||
请求示例:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"username": "demo_user",
|
|
||||||
"mobile": "13800000000",
|
|
||||||
"password": "******",
|
|
||||||
"registerOrigin": "https://register-a.example.com",
|
|
||||||
"registerHost": "register-a.example.com"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
前端字段只用于辅助校验和问题排查,不能作为后端绑定的唯一依据,因为普通 HTTP 客户端可以伪造请求参数。
|
|
||||||
|
|
||||||
禁止保存完整 `window.location.href`,避免把邀请码、临时令牌或其他查询参数写入数据库和日志。
|
|
||||||
|
|
||||||
### 5.2 后端可信来源
|
|
||||||
|
|
||||||
后端按照部署方式解析真实注册域名。
|
|
||||||
|
|
||||||
#### 同域部署
|
|
||||||
|
|
||||||
注册页面和 API 使用同一个域名时,优先读取:
|
|
||||||
|
|
||||||
```text
|
|
||||||
HTTP Host
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 前后端跨域部署
|
|
||||||
|
|
||||||
例如:
|
|
||||||
|
|
||||||
```text
|
|
||||||
注册页面:https://register-a.example.com
|
|
||||||
注册接口:https://api.example.com/api/member/register
|
|
||||||
```
|
|
||||||
|
|
||||||
此时 API 的 `Host` 是 `api.example.com`,不能用于会员绑定。浏览器跨域请求通常携带:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Origin: https://register-a.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
后端应从经过 CORS 白名单校验的 `Origin` 中提取注册域名。
|
|
||||||
|
|
||||||
#### CDN 或反向代理部署
|
|
||||||
|
|
||||||
后端可能收到:
|
|
||||||
|
|
||||||
```text
|
|
||||||
X-Forwarded-Host
|
|
||||||
X-Forwarded-Proto
|
|
||||||
Forwarded
|
|
||||||
```
|
|
||||||
|
|
||||||
只有请求来自配置的可信代理 IP 时,才允许使用这些请求头。外部客户端直接传入的 `X-Forwarded-Host` 不可信。
|
|
||||||
|
|
||||||
### 5.3 建议解析优先级
|
|
||||||
|
|
||||||
```text
|
|
||||||
1. 已通过 CORS 白名单校验的 Origin 域名
|
|
||||||
2. 来自可信代理的 X-Forwarded-Host / Forwarded
|
|
||||||
3. HTTP Host
|
|
||||||
4. 前端 registerHost,仅用于一致性校验,不单独作为可信值
|
|
||||||
```
|
|
||||||
|
|
||||||
当可信来源域名与前端 `registerHost` 不一致时:
|
|
||||||
|
|
||||||
- 会员仍可注册;
|
|
||||||
- 不自动绑定域名;
|
|
||||||
- 写入安全警告和业务审计;
|
|
||||||
- 后台显示“注册域名校验异常”。
|
|
||||||
|
|
||||||
### 5.4 域名标准化
|
|
||||||
|
|
||||||
后端统一执行:
|
|
||||||
|
|
||||||
- 转换为小写;
|
|
||||||
- 移除首尾空格;
|
|
||||||
- 移除末尾的点;
|
|
||||||
- 国际化域名转换为 Punycode;
|
|
||||||
- 移除默认端口 `80` 和 `443`;
|
|
||||||
- 拒绝包含路径、用户名、密码、Fragment 的值;
|
|
||||||
- 开发环境允许配置带非默认端口的 Host;
|
|
||||||
- 生产环境建议只允许 HTTPS 注册入口。
|
|
||||||
|
|
||||||
## 6. 数据模型
|
|
||||||
|
|
||||||
域名绑定方案使用两张业务表,不再需要轮询游标表。会员登录审计另增一张独立日志表。
|
|
||||||
|
|
||||||
```text
|
|
||||||
hg_url_pool
|
|
||||||
│ 1
|
|
||||||
│
|
|
||||||
│ N
|
|
||||||
hg_member_url_binding ─── N:1 ─── hg_app_member
|
|
||||||
|
|
||||||
hg_app_member ─── 1:N ─── hg_app_member_login_log
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6.1 URL 地址池表 `hg_url_pool`
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TABLE IF NOT EXISTS `hg_url_pool` (
|
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
|
||||||
`tenant_id` bigint unsigned NOT NULL DEFAULT 0 COMMENT '租户ID',
|
|
||||||
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '地址名称',
|
|
||||||
`scheme` varchar(10) NOT NULL DEFAULT 'https' COMMENT '协议:http或https',
|
|
||||||
`domain` varchar(255) NOT NULL COMMENT '标准化域名,可含非默认端口',
|
|
||||||
`domain_hash` char(64) NOT NULL COMMENT '标准化域名SHA256',
|
|
||||||
`base_url` varchar(512) NOT NULL COMMENT '注册入口基础地址',
|
|
||||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1启用,2失效',
|
|
||||||
`bind_count` bigint unsigned NOT NULL DEFAULT 0 COMMENT '累计成功绑定次数',
|
|
||||||
`last_bound_at` datetime(3) DEFAULT NULL COMMENT '最后绑定时间',
|
|
||||||
`remark` varchar(500) NOT NULL DEFAULT '' COMMENT '备注',
|
|
||||||
`created_by` bigint unsigned NOT NULL DEFAULT 0 COMMENT '创建者ID',
|
|
||||||
`updated_by` bigint unsigned NOT NULL DEFAULT 0 COMMENT '更新者ID',
|
|
||||||
`deleted_by` bigint unsigned NOT NULL DEFAULT 0 COMMENT '删除者ID',
|
|
||||||
`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 '更新时间',
|
|
||||||
`deleted_at` datetime(3) DEFAULT NULL COMMENT '删除时间',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `uk_url_pool_domain` (`tenant_id`,`domain_hash`),
|
|
||||||
KEY `idx_url_pool_list` (`tenant_id`,`bind_count`,`id`,`deleted_at`),
|
|
||||||
KEY `idx_url_pool_status` (`tenant_id`,`status`,`bind_count`,`deleted_at`),
|
|
||||||
KEY `idx_url_pool_deleted` (`deleted_at`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
|
||||||
COMMENT='URL地址池';
|
|
||||||
```
|
|
||||||
|
|
||||||
字段说明:
|
|
||||||
|
|
||||||
| 字段 | 说明 |
|
|
||||||
|---|---|
|
|
||||||
| `scheme` | 注册入口协议,生产环境一般为 HTTPS |
|
|
||||||
| `domain` | 绑定和匹配使用的标准化域名 |
|
|
||||||
| `domain_hash` | 用于唯一索引,避免域名大小写或格式差异导致重复 |
|
|
||||||
| `base_url` | 后台展示、复制链接时使用,例如 `https://a.example.com/register` |
|
|
||||||
| `bind_count` | C 端注册成功并实际建立域名绑定的累计次数 |
|
|
||||||
| `last_bound_at` | 最近一次成功建立绑定的时间 |
|
|
||||||
|
|
||||||
地址一旦产生会员绑定,禁止直接修改 `domain`。需要使用新域名时应新增地址;已有会员继续保留原绑定关系。
|
|
||||||
|
|
||||||
`bind_count` 是累计使用次数。当前绑定会员数通过 `hg_member_url_binding` 按 `url_pool_id` 实时统计。正常情况下两者一致;保留累计字段便于快速排序和审计校验。
|
|
||||||
|
|
||||||
### 6.2 会员域名绑定表 `hg_member_url_binding`
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TABLE IF NOT EXISTS `hg_member_url_binding` (
|
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
|
||||||
`tenant_id` bigint unsigned NOT NULL DEFAULT 0 COMMENT '租户ID',
|
|
||||||
`member_id` bigint unsigned NOT NULL COMMENT '会员ID',
|
|
||||||
`url_pool_id` bigint unsigned NOT NULL COMMENT 'URL地址池ID',
|
|
||||||
`domain_snapshot` varchar(255) NOT NULL COMMENT '绑定时域名快照',
|
|
||||||
`origin_snapshot` varchar(512) NOT NULL DEFAULT '' COMMENT '绑定时Origin快照',
|
|
||||||
`bound_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) 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_member_url_binding` (`tenant_id`,`member_id`),
|
|
||||||
KEY `idx_member_url_pool` (`tenant_id`,`url_pool_id`,`member_id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
|
||||||
COMMENT='会员注册域名绑定';
|
|
||||||
```
|
|
||||||
|
|
||||||
设计说明:
|
|
||||||
|
|
||||||
- 未绑定会员没有该表记录;
|
|
||||||
- `member_id` 唯一约束保证一个会员只有一个当前绑定;
|
|
||||||
- `domain_snapshot` 用于保留绑定时的域名;
|
|
||||||
- `origin_snapshot` 只保存 Scheme 和 Host,不保存路径及查询参数;
|
|
||||||
- 绑定记录由 C 端注册事务创建,后台仅提供只读查询。
|
|
||||||
|
|
||||||
### 6.3 会员登录日志表 `hg_app_member_login_log`
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TABLE IF NOT EXISTS `hg_app_member_login_log` (
|
|
||||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '日志ID',
|
|
||||||
`tenant_id` bigint unsigned NOT NULL DEFAULT 0 COMMENT '租户ID',
|
|
||||||
`req_id` varchar(64) NOT NULL DEFAULT '' COMMENT '请求ID',
|
|
||||||
`member_id` bigint unsigned NOT NULL DEFAULT 0 COMMENT '会员ID,未识别会员时为0',
|
|
||||||
`username` varchar(64) NOT NULL DEFAULT '' COMMENT '用户名快照',
|
|
||||||
`mobile_mask` varchar(32) NOT NULL DEFAULT '' COMMENT '手机号脱敏值',
|
|
||||||
`login_type` tinyint NOT NULL DEFAULT 1 COMMENT '登录方式:1账号密码,2手机验证码',
|
|
||||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '登录状态:1成功,2失败',
|
|
||||||
`err_msg` varchar(255) NOT NULL DEFAULT '' COMMENT '失败原因',
|
|
||||||
`login_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '登录时间',
|
|
||||||
`login_ip_cipher` text COMMENT '登录IP密文',
|
|
||||||
`login_ip_mask` varchar(64) NOT NULL DEFAULT '' COMMENT '登录IP脱敏值',
|
|
||||||
`login_region` varchar(128) NOT NULL DEFAULT '' COMMENT '登录地区',
|
|
||||||
`login_domain` varchar(255) NOT NULL DEFAULT '' COMMENT '登录页面标准化域名',
|
|
||||||
`user_agent` varchar(512) NOT NULL DEFAULT '' COMMENT '浏览器UA',
|
|
||||||
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `idx_member_login_time` (`tenant_id`,`member_id`,`login_at`),
|
|
||||||
KEY `idx_member_login_status` (`tenant_id`,`status`,`login_at`),
|
|
||||||
KEY `idx_member_login_username` (`tenant_id`,`username`,`login_at`),
|
|
||||||
KEY `idx_member_login_domain` (`tenant_id`,`login_domain`,`login_at`),
|
|
||||||
KEY `idx_member_login_req` (`req_id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
|
||||||
COMMENT='C端会员登录日志';
|
|
||||||
```
|
|
||||||
|
|
||||||
设计说明:
|
|
||||||
|
|
||||||
- 登录成功和失败都必须写入日志;
|
|
||||||
- 登录失败且无法识别会员时,`member_id` 为 `0`,仅保存用户名快照或手机号脱敏值;
|
|
||||||
- 不保存密码、短信验证码、Token、完整手机号及登录响应正文;
|
|
||||||
- IP 仅保存密文和脱敏值,后台页面不得返回 IP 密文;
|
|
||||||
- 日志为审计数据,后台只读,不提供人工新增、编辑和删除功能;
|
|
||||||
- 操作系统和浏览器名称由 `user_agent` 在查询时解析,无需重复存储。
|
|
||||||
|
|
||||||
## 7. 字典设计
|
|
||||||
|
|
||||||
继续使用 HotGo 后端统一字典,不在前端硬编码。
|
|
||||||
|
|
||||||
```go
|
|
||||||
const (
|
|
||||||
UrlPoolStatusEnabled = 1 // 启用
|
|
||||||
UrlPoolStatusInvalid = 2 // 失效
|
|
||||||
|
|
||||||
AppMemberLoginTypePassword = 1 // 账号密码
|
|
||||||
AppMemberLoginTypeSms = 2 // 手机验证码
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
建议字典:
|
|
||||||
|
|
||||||
| 字典键 | 说明 |
|
|
||||||
|---|---|
|
|
||||||
| `urlPoolStatus` | URL 地址状态 |
|
|
||||||
| `appMemberLoginTypeOptions` | C 端会员登录方式,新建后端枚举字典 |
|
|
||||||
| `sys_login_status` | 登录成功/失败状态,直接复用 HotGo 已有字典 |
|
|
||||||
|
|
||||||
会员绑定状态不需要单独存储:
|
|
||||||
|
|
||||||
- 存在绑定记录:已绑定;
|
|
||||||
- 不存在绑定记录:待绑定;
|
|
||||||
- 存在绑定但地址池状态为失效:绑定域名已失效。
|
|
||||||
|
|
||||||
## 8. 注册事务设计
|
|
||||||
|
|
||||||
### 8.1 注册流程
|
|
||||||
|
|
||||||
```text
|
|
||||||
解析可信注册域名
|
|
||||||
→ 查询 URL 地址池
|
|
||||||
→ 开启事务
|
|
||||||
→ 创建会员主档
|
|
||||||
→ 初始化会员钱包
|
|
||||||
→ 如果域名存在且启用,创建绑定
|
|
||||||
→ 地址池 bind_count 加 1,并更新 last_bound_at
|
|
||||||
→ 写业务审计
|
|
||||||
→ 提交事务
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8.2 错误边界
|
|
||||||
|
|
||||||
以下情况不阻断注册:
|
|
||||||
|
|
||||||
- 没有识别到域名;
|
|
||||||
- 域名未配置;
|
|
||||||
- 域名已经失效;
|
|
||||||
- 前端域名与可信来源不一致。
|
|
||||||
|
|
||||||
以上情况注册成功但会员保持待绑定,并写入审计。
|
|
||||||
|
|
||||||
以下情况必须回滚注册:
|
|
||||||
|
|
||||||
- 查询地址池时数据库异常;
|
|
||||||
- 创建会员失败;
|
|
||||||
- 初始化钱包失败;
|
|
||||||
- 已确认需要绑定,但插入绑定记录失败;
|
|
||||||
- 更新注册统计失败;
|
|
||||||
|
|
||||||
不能将数据库错误误判成“域名不存在”。
|
|
||||||
|
|
||||||
### 8.3 并发与幂等
|
|
||||||
|
|
||||||
- `hg_member_url_binding(tenant_id, member_id)` 唯一,防止重复绑定;
|
|
||||||
- `hg_url_pool(tenant_id, domain_hash)` 唯一,防止重复域名;
|
|
||||||
- 创建绑定前先查询会员现有绑定;
|
|
||||||
- 同域名重复绑定直接返回成功;
|
|
||||||
- 注册接口不允许覆盖不同域名的已有绑定。
|
|
||||||
|
|
||||||
只有 C 端注册事务实际新建绑定时才增加 `bind_count`。同一会员对同一地址的幂等重试不增加次数。
|
|
||||||
|
|
||||||
## 9. 后端服务设计
|
|
||||||
|
|
||||||
建议新增共享服务:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type RegisterDomainModel struct {
|
|
||||||
Scheme string
|
|
||||||
Domain string
|
|
||||||
Origin string
|
|
||||||
Trusted bool
|
|
||||||
Source string
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemberDomainResult struct {
|
|
||||||
Bound bool `json:"bound"`
|
|
||||||
UrlPoolId uint64 `json:"urlPoolId"`
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
BaseUrl string `json:"baseUrl"`
|
|
||||||
StatusLabel string `json:"statusLabel"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
核心方法:
|
|
||||||
|
|
||||||
```text
|
|
||||||
ResolveRegisterDomain(ctx, registerOrigin, registerHost)
|
|
||||||
解析并校验真实注册域名
|
|
||||||
|
|
||||||
BindOnRegister(ctx, memberId, domain)
|
|
||||||
注册事务内自动绑定
|
|
||||||
|
|
||||||
GetMemberDomain(ctx, memberId)
|
|
||||||
查询会员当前绑定及域名有效状态
|
|
||||||
```
|
|
||||||
|
|
||||||
会员登录日志服务增加:
|
|
||||||
|
|
||||||
```text
|
|
||||||
PushMemberLoginLog(ctx, member, loginType, err)
|
|
||||||
收集请求上下文并推送会员登录日志
|
|
||||||
|
|
||||||
WriteMemberLoginLog(ctx, log)
|
|
||||||
队列消费或同步兜底写入日志
|
|
||||||
|
|
||||||
UpdateMemberLastLogin(ctx, memberId, ipData)
|
|
||||||
登录成功后更新会员主表最后登录信息
|
|
||||||
```
|
|
||||||
|
|
||||||
项目现有 `/site/register` 是后台管理员账号注册,不是 `hg_app_member` 的 C 端会员注册。新域名绑定应接入真正的 C 端会员注册接口。
|
|
||||||
|
|
||||||
后台当前不提供创建 C 端会员的产品功能,本方案也不新增该入口。会员及其域名绑定只能由 C 端注册流程创建。
|
|
||||||
|
|
||||||
## 10. 后台地址池管理
|
|
||||||
|
|
||||||
### 10.1 菜单位置
|
|
||||||
|
|
||||||
```text
|
|
||||||
会员管理
|
|
||||||
└── URL地址池
|
|
||||||
```
|
|
||||||
|
|
||||||
### 10.2 汇总数据
|
|
||||||
|
|
||||||
- URL 总数;
|
|
||||||
- 启用 URL 数;
|
|
||||||
- 失效 URL 数;
|
|
||||||
- 已绑定会员数;
|
|
||||||
- 待绑定会员数;
|
|
||||||
- 绑定域名已失效会员数。
|
|
||||||
|
|
||||||
### 10.3 查询条件
|
|
||||||
|
|
||||||
- 地址名称;
|
|
||||||
- 域名关键词;
|
|
||||||
- URL 状态;
|
|
||||||
- 创建时间。
|
|
||||||
|
|
||||||
### 10.4 列表字段
|
|
||||||
|
|
||||||
- 地址名称;
|
|
||||||
- 注册域名;
|
|
||||||
- 注册入口 URL;
|
|
||||||
- 状态;
|
|
||||||
- 当前绑定会员数;
|
|
||||||
- 累计绑定次数;
|
|
||||||
- 最后绑定时间;
|
|
||||||
- 备注;
|
|
||||||
- 创建时间;
|
|
||||||
- 操作。
|
|
||||||
|
|
||||||
列表默认排序固定为:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
ORDER BY bind_count ASC, id ASC
|
|
||||||
```
|
|
||||||
|
|
||||||
即累计绑定次数最少的地址排在最前面;绑定次数相同时,先创建的地址排在前面。分页查询必须由后端应用该排序,不能只在前端对当前页排序。
|
|
||||||
|
|
||||||
### 10.5 操作按钮
|
|
||||||
|
|
||||||
| 按钮 | 条件 | 功能 |
|
|
||||||
|---|---|---|
|
|
||||||
| 新增地址 | 有新增权限 | 添加注册域名和入口地址 |
|
|
||||||
| Excel批量导入 | 有导入权限 | 按“地址名称、注册入口URL、备注”批量导入,导入地址统一启用 |
|
|
||||||
| 编辑 | 始终可见 | 编辑名称、入口路径和备注 |
|
|
||||||
| 启用 | 当前失效 | 手动将地址切换为启用,恢复自动注册绑定 |
|
|
||||||
| 设为失效 | 当前启用 | 手动将地址切换为失效,停止新的自动绑定 |
|
|
||||||
| 复制注册链接 | 当前启用 | 复制完整注册入口 URL |
|
|
||||||
| 详情 | 始终可见 | 进入地址详情页,查看地址信息和全部绑定会员 |
|
|
||||||
|
|
||||||
地址池不提供删除功能,历史地址统一通过“启用/失效”管理。启用和失效由管理员手动点击切换。状态变更成功后立即刷新列表,并写入业务审计。地址变为失效后:
|
|
||||||
|
|
||||||
- 不再接受新的注册自动绑定;
|
|
||||||
- 已有会员绑定关系保留;
|
|
||||||
- 详情页仍然可以查看原有绑定会员。
|
|
||||||
|
|
||||||
### 10.6 地址详情页
|
|
||||||
|
|
||||||
点击列表中的“详情”进入独立详情页。页面分为地址信息和绑定会员两个区域。
|
|
||||||
|
|
||||||
地址信息展示:
|
|
||||||
|
|
||||||
- 地址名称;
|
|
||||||
- 注册域名;
|
|
||||||
- 注册入口 URL;
|
|
||||||
- 当前状态;
|
|
||||||
- 累计绑定次数;
|
|
||||||
- 当前绑定会员数;
|
|
||||||
- 最后绑定时间;
|
|
||||||
- 创建人、创建时间;
|
|
||||||
- 备注。
|
|
||||||
|
|
||||||
绑定会员列表展示当前绑定该地址的全部会员,并支持分页。字段包括:
|
|
||||||
|
|
||||||
- 会员编号;
|
|
||||||
- 用户名;
|
|
||||||
- 手机号脱敏值;
|
|
||||||
- 会员状态;
|
|
||||||
- 绑定时间。
|
|
||||||
|
|
||||||
详情页会员列表支持按用户名、手机号和绑定时间查询。这里的“全部用户”指绑定该地址的全部会员,列表仅供查看,不提供添加、解绑或改绑操作。
|
|
||||||
|
|
||||||
## 11. 会员列表扩展
|
|
||||||
|
|
||||||
会员列表增加字段:
|
|
||||||
|
|
||||||
- 注册域名;
|
|
||||||
- 域名绑定状态;
|
|
||||||
- 绑定时间。
|
|
||||||
|
|
||||||
增加筛选:
|
|
||||||
|
|
||||||
| 筛选值 | 条件 |
|
|
||||||
|---|---|
|
|
||||||
| 全部 | 不限制 |
|
|
||||||
| 已绑定 | 存在绑定且域名启用 |
|
|
||||||
| 待绑定 | 不存在绑定记录 |
|
|
||||||
| 域名已失效 | 存在绑定但域名已失效 |
|
|
||||||
|
|
||||||
操作栏不增加绑定、解绑或重新绑定按钮。会员详情可只读查看域名信息。
|
|
||||||
|
|
||||||
会员详情增加“注册域名信息”区域,展示:
|
|
||||||
|
|
||||||
- 当前域名;
|
|
||||||
- 注册入口;
|
|
||||||
- 域名状态;
|
|
||||||
- 绑定时间。
|
|
||||||
|
|
||||||
## 12. 会员登录与日志设计
|
|
||||||
|
|
||||||
### 12.1 建设范围
|
|
||||||
|
|
||||||
当前项目的登录日志分为两类理解:
|
|
||||||
|
|
||||||
- `hg_sys_login_log` 及“系统登录日志”页面记录的是后台管理员登录。现有后台账号、手机号登录均会调用 `SysLoginLog().Push()` 写入成功或失败结果;
|
|
||||||
- `hg_app_member` 虽然预留了 `last_login_at`、`last_login_ip_cipher`、`last_login_ip_mask`、`last_login_region` 字段,会员列表也展示最后登录信息,但当前代码中没有找到 C 端会员登录接口对这些字段的更新逻辑;
|
|
||||||
- 当前也没有独立的会员登录历史表或会员登录日志列表。
|
|
||||||
|
|
||||||
因此,现状结论是:**后台管理员登录有日志,C 端会员登录目前没有完整可用的日志功能**。
|
|
||||||
|
|
||||||
本次将以下两项能力纳入正式实施范围:
|
|
||||||
|
|
||||||
1. 登录成功后更新会员主表中的最后登录时间、IP 脱敏值和地区;
|
|
||||||
2. 使用独立的 `hg_app_member_login_log` 记录每次会员登录成功或失败,避免与后台管理员的 `hg_sys_login_log` 混用。
|
|
||||||
|
|
||||||
### 12.2 登录成功后的会员主表更新
|
|
||||||
|
|
||||||
会员身份校验通过后、返回登录成功响应前,更新 `hg_app_member`:
|
|
||||||
|
|
||||||
| 字段 | 更新内容 |
|
|
||||||
|---|---|
|
|
||||||
| `last_login_at` | 当前登录成功时间 |
|
|
||||||
| `last_login_ip_cipher` | 使用项目统一加密工具保存的客户端 IP 密文 |
|
|
||||||
| `last_login_ip_mask` | 用于后台展示的 IP 脱敏值 |
|
|
||||||
| `last_login_region` | 根据客户端 IP 解析的国家/省/市摘要 |
|
|
||||||
|
|
||||||
处理规则:
|
|
||||||
|
|
||||||
- 只有登录成功才更新上述字段,登录失败不得覆盖会员最后一次成功登录信息;
|
|
||||||
- 客户端 IP 使用项目现有 `location.GetClientIp()` 识别,并遵守可信代理配置;
|
|
||||||
- 地区解析失败不阻断登录,地区保存为空,同时记录 Warning 日志;
|
|
||||||
- 会员主表更新失败时不签发 Token,向客户端返回“登录失败,请稍后重试”;
|
|
||||||
- 更新字段必须使用 DAO 列名,禁止硬编码字段字符串;
|
|
||||||
- 不在业务日志中输出 IP 密文、密码、短信验证码或 Token。
|
|
||||||
|
|
||||||
### 12.3 会员登录日志写入流程
|
|
||||||
|
|
||||||
所有 C 端会员登录入口必须调用同一个会员登录日志服务,不允许每种登录方式自行拼装日志。
|
|
||||||
|
|
||||||
```text
|
|
||||||
收到登录请求
|
|
||||||
→ 解析请求ID、登录方式、客户端IP、地区、域名和User-Agent
|
|
||||||
→ 校验会员及登录凭证
|
|
||||||
→ 失败:写入失败日志,返回统一登录错误
|
|
||||||
→ 成功:更新会员最后登录信息
|
|
||||||
→ 签发Token
|
|
||||||
→ 写入成功日志
|
|
||||||
→ 返回登录结果
|
|
||||||
```
|
|
||||||
|
|
||||||
为保证失败请求也能记录,登录控制器或登录服务应使用统一的收口逻辑,在方法返回前根据最终 `err` 和会员识别结果生成日志。日志优先通过项目消息队列异步写入;队列推送失败时同步写库兜底,并记录 Warning。日志写入最终失败不得把已经完成的身份认证改成登录失败,但必须留下服务端告警。
|
|
||||||
|
|
||||||
失败原因只记录可审计的标准化文案,例如:
|
|
||||||
|
|
||||||
- 账号或密码错误;
|
|
||||||
- 验证码错误或已过期;
|
|
||||||
- 会员不存在;
|
|
||||||
- 会员已禁用;
|
|
||||||
- 风控限制登录;
|
|
||||||
- 系统异常。
|
|
||||||
|
|
||||||
### 12.4 后台会员登录日志页面
|
|
||||||
|
|
||||||
菜单位置:
|
|
||||||
|
|
||||||
```text
|
|
||||||
会员管理
|
|
||||||
└── 会员登录日志
|
|
||||||
```
|
|
||||||
|
|
||||||
查询条件:
|
|
||||||
|
|
||||||
- 会员编号、用户名或手机号关键词;
|
|
||||||
- 登录方式;
|
|
||||||
- 登录状态;
|
|
||||||
- 登录域名;
|
|
||||||
- IP 脱敏值;
|
|
||||||
- 登录时间范围。
|
|
||||||
|
|
||||||
列表默认按照 `login_at DESC, id DESC` 排序,展示:
|
|
||||||
|
|
||||||
- 日志ID;
|
|
||||||
- 会员编号;
|
|
||||||
- 用户名;
|
|
||||||
- 手机号脱敏值;
|
|
||||||
- 登录方式;
|
|
||||||
- 登录状态;
|
|
||||||
- 登录时间;
|
|
||||||
- 登录IP脱敏值;
|
|
||||||
- 登录地区;
|
|
||||||
- 登录域名;
|
|
||||||
- 操作系统;
|
|
||||||
- 浏览器;
|
|
||||||
- 失败原因;
|
|
||||||
- 操作。
|
|
||||||
|
|
||||||
操作栏只提供“详情”。列表顶部提供“导出”,导出内容与当前查询条件一致。详情弹窗补充展示请求ID和完整 User-Agent,但不展示 IP 密文及任何登录凭证。
|
|
||||||
|
|
||||||
列表查询必须按 `tenant_id` 隔离数据。使用完整手机号查询时,先在会员表中匹配会员ID,再按 `member_id` 查询日志;对无法识别会员的失败记录,只支持按已保存的手机号脱敏值查询。
|
|
||||||
|
|
||||||
## 13. 接口设计
|
|
||||||
|
|
||||||
### 13.1 后台接口
|
|
||||||
|
|
||||||
| 接口 | 方法 | 说明 |
|
|
||||||
|---|---|---|
|
|
||||||
| `/urlPool/list` | GET | 地址池分页列表 |
|
|
||||||
| `/urlPool/view` | GET | 地址详情及绑定统计 |
|
|
||||||
| `/urlPool/edit` | POST | 新增或编辑地址 |
|
|
||||||
| `/urlPool/import` | POST | Excel批量导入地址,成功记录统一设为启用 |
|
|
||||||
| `/urlPool/status` | POST | 启用或设为失效 |
|
|
||||||
| `/urlPool/memberList` | GET | 分页查看域名当前绑定的全部会员 |
|
|
||||||
| `/urlPool/summary` | GET | 地址池汇总数据 |
|
|
||||||
| `/appMemberLoginLog/list` | GET | 会员登录日志分页列表 |
|
|
||||||
| `/appMemberLoginLog/view` | GET | 会员登录日志详情 |
|
|
||||||
| `/appMemberLoginLog/export` | GET | 按当前条件导出会员登录日志 |
|
|
||||||
|
|
||||||
### 13.2 C 端接口
|
|
||||||
|
|
||||||
注册请求增加:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"registerOrigin": "https://register-a.example.com",
|
|
||||||
"registerHost": "register-a.example.com"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
会员查询当前域名响应建议:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"bound": true,
|
|
||||||
"domain": "register-a.example.com",
|
|
||||||
"baseUrl": "https://register-a.example.com/register",
|
|
||||||
"domainStatus": 1,
|
|
||||||
"domainStatusLabel": "启用"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
未绑定时:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"bound": false,
|
|
||||||
"domain": "",
|
|
||||||
"baseUrl": "",
|
|
||||||
"domainStatus": 0,
|
|
||||||
"domainStatusLabel": "待绑定"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
所有 C 端会员登录接口的响应格式保持不变,日志采集由服务端统一完成,不要求前端额外提交 IP、地区或 User-Agent。跨域部署时,前端可提交 `loginHost` 作为辅助校验值,但最终登录域名仍按可信 `Origin`、可信代理转发头和 `Host` 解析。
|
|
||||||
|
|
||||||
## 14. HotGo 模块结构
|
|
||||||
|
|
||||||
建议作为主模块开发:
|
|
||||||
|
|
||||||
```text
|
|
||||||
server/
|
|
||||||
├── api/admin/urlpool/urlpool.go
|
|
||||||
├── api/admin/appmemberloginlog/appmemberloginlog.go
|
|
||||||
├── internal/consts/url_pool.go
|
|
||||||
├── internal/consts/app_member_login_log.go
|
|
||||||
├── internal/controller/admin/sys/url_pool.go
|
|
||||||
├── internal/controller/admin/sys/app_member_login_log.go
|
|
||||||
├── internal/logic/sys/url_pool.go
|
|
||||||
├── internal/logic/sys/app_member_login_log.go
|
|
||||||
├── internal/model/input/sysin/url_pool.go
|
|
||||||
├── internal/model/input/sysin/app_member_login_log.go
|
|
||||||
├── internal/router/genrouter/url_pool.go
|
|
||||||
├── internal/router/genrouter/app_member_login_log.go
|
|
||||||
├── internal/queues/app_member_login_log.go
|
|
||||||
├── internal/service/sys.go # 追加 ISysUrlPool、ISysAppMemberLoginLog
|
|
||||||
├── internal/dao/url_pool.go # CLI 生成
|
|
||||||
├── internal/dao/member_url_binding.go # CLI 生成
|
|
||||||
├── internal/dao/app_member_login_log.go # CLI 生成
|
|
||||||
├── storage/data/migrations/<date>_url_pool.sql
|
|
||||||
└── storage/data/migrations/<date>_app_member_login_log.sql
|
|
||||||
|
|
||||||
web/src/
|
|
||||||
├── api/urlPool/index.ts
|
|
||||||
├── api/appMemberLoginLog/index.ts
|
|
||||||
├── views/app-member/url-pool/
|
|
||||||
├── index.vue
|
|
||||||
├── edit.vue
|
|
||||||
├── detail.vue
|
|
||||||
└── model.ts
|
|
||||||
└── views/app-member/login-log/
|
|
||||||
├── index.vue
|
|
||||||
├── detail.vue
|
|
||||||
└── model.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
DAO、Entity、DO 和 DAO Internal 必须通过 GoFrame CLI 生成,不手工修改。
|
|
||||||
|
|
||||||
## 15. 权限设计
|
|
||||||
|
|
||||||
```text
|
|
||||||
/urlPool/list
|
|
||||||
/urlPool/view
|
|
||||||
/urlPool/edit
|
|
||||||
/urlPool/import
|
|
||||||
/urlPool/status
|
|
||||||
/urlPool/memberList
|
|
||||||
/urlPool/summary
|
|
||||||
/appMemberLoginLog/list
|
|
||||||
/appMemberLoginLog/view
|
|
||||||
/appMemberLoginLog/export
|
|
||||||
```
|
|
||||||
|
|
||||||
域名启用/失效和注册自动绑定均写入业务审计。
|
|
||||||
|
|
||||||
## 16. 缓存设计
|
|
||||||
|
|
||||||
会员当前域名可以使用项目统一缓存:
|
|
||||||
|
|
||||||
```text
|
|
||||||
urlpool:member:{tenantId}:{memberId}
|
|
||||||
```
|
|
||||||
|
|
||||||
地址池域名查询可以缓存:
|
|
||||||
|
|
||||||
```text
|
|
||||||
urlpool:domain:{tenantId}:{domainHash}
|
|
||||||
```
|
|
||||||
|
|
||||||
建议缓存 10~30 分钟。以下操作后主动清除缓存:
|
|
||||||
|
|
||||||
- 地址编辑;
|
|
||||||
- 地址启用或失效;
|
|
||||||
- 注册自动绑定;
|
|
||||||
|
|
||||||
缓存统一使用 `cache.Instance()`,数据库仍是唯一事实来源。
|
|
||||||
|
|
||||||
## 17. 安全要求
|
|
||||||
|
|
||||||
1. 不得只信任前端 `registerHost` 参数。
|
|
||||||
2. `Origin` 必须通过地址池或 CORS 白名单校验。
|
|
||||||
3. 转发请求头只能在可信代理来源下使用。
|
|
||||||
4. 后台保存域名前必须进行标准化和 URL 解析。
|
|
||||||
5. 禁止保存包含用户名、密码、Token 的 URL。
|
|
||||||
6. 日志只记录标准化域名和 Origin,不记录完整注册查询参数。
|
|
||||||
7. 后台不得提供会员域名绑定、解绑或改绑接口。
|
|
||||||
8. 生产环境建议只允许 HTTPS 注册入口。
|
|
||||||
9. 域名变更不得静默覆盖已有会员绑定。
|
|
||||||
10. 未知或校验异常域名不自动创建地址池记录。
|
|
||||||
11. 会员登录日志不得保存密码、短信验证码、Token、完整手机号或登录响应正文。
|
|
||||||
12. 后台日志接口不得返回 `last_login_ip_cipher` 或 `login_ip_cipher`。
|
|
||||||
13. 失败日志使用统一错误文案,避免暴露账号是否存在等敏感认证细节。
|
|
||||||
14. 会员登录日志列表、详情和导出必须执行租户隔离,禁止跨租户查询。
|
|
||||||
|
|
||||||
## 18. 异常处理
|
|
||||||
|
|
||||||
| 场景 | 处理方式 |
|
|
||||||
|---|---|
|
|
||||||
| 地址池为空 | 注册成功,会员待绑定 |
|
|
||||||
| 注册域名未配置 | 注册成功,会员待绑定并写审计 |
|
|
||||||
| 注册域名失效 | 注册成功,会员待绑定并写审计 |
|
|
||||||
| 前端域名与可信来源不一致 | 注册成功但不绑定,记录安全警告 |
|
|
||||||
| 域名重复添加 | 拒绝保存 |
|
|
||||||
| 已绑定同一域名 | 幂等返回成功 |
|
|
||||||
| 注册接口试图覆盖其他域名 | 拒绝覆盖,保留原绑定关系 |
|
|
||||||
| 地址池查询数据库异常 | 注册失败并回滚 |
|
|
||||||
| 创建绑定失败 | 注册事务回滚 |
|
|
||||||
| 已产生绑定的域名被直接修改 | 拒绝修改域名字段 |
|
|
||||||
| 列表绑定次数相同 | 按地址ID升序稳定排序 |
|
|
||||||
| 登录成功但会员最后登录信息更新失败 | 不签发Token,返回通用系统错误并记录失败日志 |
|
|
||||||
| 登录IP地区解析失败 | 登录继续,地区留空并记录Warning |
|
|
||||||
| 登录日志队列推送失败 | 同步写入日志表兜底并记录Warning |
|
|
||||||
| 队列与同步写入均失败 | 不撤销已完成登录,记录服务端告警供运维处理 |
|
|
||||||
| 登录失败且无法识别会员 | 以 `member_id=0` 写入脱敏失败日志 |
|
|
||||||
|
|
||||||
## 19. 验收标准
|
|
||||||
|
|
||||||
### 19.1 注册绑定
|
|
||||||
|
|
||||||
- 用户通过 A 域名注册后,会员绑定 A。
|
|
||||||
- 用户通过 B 域名注册后,会员绑定 B。
|
|
||||||
- URL 路径和查询参数不同但域名相同,绑定结果相同。
|
|
||||||
- 默认端口不会造成重复域名。
|
|
||||||
- 地址池为空时会员仍注册成功并显示待绑定。
|
|
||||||
- 未配置域名和失效域名不会建立自动绑定。
|
|
||||||
|
|
||||||
### 19.2 部署场景
|
|
||||||
|
|
||||||
- 前后端同域部署能够从 Host 正确识别域名。
|
|
||||||
- 前后端跨域部署能够从通过校验的 Origin 正确识别域名。
|
|
||||||
- CDN/反向代理部署能够从可信转发头正确识别域名。
|
|
||||||
- 外部客户端伪造 `X-Forwarded-Host` 不会产生错误绑定。
|
|
||||||
- 前端伪造 `registerHost` 不会覆盖后端可信域名。
|
|
||||||
|
|
||||||
### 19.3 并发和幂等
|
|
||||||
|
|
||||||
- 并发提交不会为同一会员创建多条绑定。
|
|
||||||
- 相同注册请求重试不会重复创建会员或绑定。
|
|
||||||
- 已绑定会员不能通过普通注册接口更换域名。
|
|
||||||
|
|
||||||
### 19.4 后台管理
|
|
||||||
|
|
||||||
- 可以新增、编辑、启用和失效注册域名。
|
|
||||||
- 可以使用 Excel 批量导入地址,表头包含“地址名称、注册入口URL、备注”,所有导入地址默认为启用。
|
|
||||||
- 可以手动点击“启用”或“设为失效”,状态立即生效。
|
|
||||||
- 地址池列表默认按累计绑定次数升序排列。
|
|
||||||
- 可以复制完整注册链接。
|
|
||||||
- 点击地址详情可以分页查看当前绑定的全部会员。
|
|
||||||
- 每次实际建立新绑定时,地址累计绑定次数准确加一。
|
|
||||||
- 幂等重试不会重复增加累计绑定次数。
|
|
||||||
- 后台不存在创建会员入口。
|
|
||||||
- 后台不存在会员域名绑定、解绑或重新绑定入口。
|
|
||||||
- 失效域名不允许新增绑定。
|
|
||||||
- 所有关键操作均可在业务审计中查询。
|
|
||||||
|
|
||||||
### 19.5 会员登录日志
|
|
||||||
|
|
||||||
- 会员登录成功后,会员主表最后登录时间、IP密文、IP脱敏值和地区正确更新。
|
|
||||||
- 登录失败不会覆盖会员最后一次成功登录信息。
|
|
||||||
- 账号密码登录和手机验证码登录均写入独立会员登录日志。
|
|
||||||
- 登录成功、密码错误、验证码错误、账号禁用和系统异常场景均能生成对应日志。
|
|
||||||
- 无法识别会员的失败请求以 `member_id=0` 记录,且不保存完整手机号。
|
|
||||||
- 后台“会员登录日志”可以按会员、方式、状态、域名、IP和时间查询。
|
|
||||||
- 日志列表默认按登录时间倒序排列,可以查看详情并按筛选条件导出。
|
|
||||||
- 后台页面和导出文件均不出现IP密文、密码、验证码或Token。
|
|
||||||
- 登录日志队列异常时会同步写库兜底;两种写入都失败时产生服务端 Warning 告警。
|
|
||||||
|
|
||||||
## 20. 待确认事项
|
|
||||||
|
|
||||||
1. 生产环境是否强制只允许 HTTPS。
|
|
||||||
2. 前端页面和注册 API 是同域部署还是跨域部署。
|
|
||||||
3. 是否存在 App、桌面客户端等没有浏览器 `Origin` 的注册入口。
|
|
||||||
4. 注册入口是否统一为 `/register`,还是每个域名可以配置不同路径。
|
|
||||||
5. 地址池是否需要按业务线、渠道或租户进一步分组。
|
|
||||||
6. 会员登录日志的在线保留时长,以及是否需要定时归档历史日志。
|
|
||||||
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 302 KiB |
|
Before Width: | Height: | Size: 377 KiB |
|
Before Width: | Height: | Size: 237 KiB |
|
Before Width: | Height: | Size: 319 KiB |
|
Before Width: | Height: | Size: 380 KiB |
|
Before Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 264 KiB |
|
Before Width: | Height: | Size: 386 KiB |
|
Before Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 395 KiB |
|
Before Width: | Height: | Size: 287 KiB |
|
Before Width: | Height: | Size: 369 KiB |
|
Before Width: | Height: | Size: 235 KiB |
|
Before Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 484 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 266 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 434 KiB |
|
Before Width: | Height: | Size: 426 KiB |
|
Before Width: | Height: | Size: 322 KiB |
|
Before Width: | Height: | Size: 138 KiB |
@@ -1,130 +0,0 @@
|
|||||||
# 后台功能与数据库表映射
|
|
||||||
|
|
||||||
> 更新时间:2026-10-09
|
|
||||||
> 范围:当前 HotGo 后台、已实现业务模块及数据库 `olons_admin` 现有表
|
|
||||||
> 说明:一个页面可能关联多张表;部分公共表会被多个业务模块共同使用。
|
|
||||||
|
|
||||||
## 1. 当前业务菜单
|
|
||||||
|
|
||||||
| 一级菜单 | 功能 | 核心表 | 关联表 | 说明 |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| 主页 | 首页数据看板 | `hg_dashboard_daily_stat` | `hg_app_member`、`hg_trade_order`、`hg_recharge_order`、`hg_withdrawal_order`、`hg_task_submission` | 展示会员、订单、充值、提现、任务等汇总数据;部分指标实时统计,日指标可落汇总表。 |
|
|
||||||
| 主页 | 网站设置 | `hg_site_config_version` | — | 站点名称、Logo、隐私网址、交易限制、佣金、时间段、功能开关、自动派单等整份保存在 `config_json`;当前页面直接保存并生效。 |
|
|
||||||
| 主页 | 文本管理 | `hg_content` | `hg_content_version` | `hg_content` 保存内容主档,`hg_content_version` 保存正文版本。 |
|
|
||||||
| 主页 | Banner 设置 | `hg_banner` | `hg_sys_attachment` | 管理 Banner 图片、位置、跳转方式、展示时间和排序。 |
|
|
||||||
| 主页 | 手工商城 | `hg_product` | `hg_sys_attachment` | 与商品管理共用商品表,以 `product_type=2` 区分手工商城商品;当前只维护名称、价格和展示图片。 |
|
|
||||||
| 会员管理 | 会员列表 | `hg_app_member` | `hg_app_member_profile`、`hg_app_member_address`、`hg_app_member_payment_account`、`hg_app_member_status_log` | 会员主档、实名/扩展资料、地址、银行卡或收款账户、状态变更记录。 |
|
|
||||||
| 会员管理 | 会员列表—余额与账变 | `hg_wallet_account` | `hg_wallet_ledger`、`hg_wallet_adjustment_request` | 钱包余额保存在账户表,所有变动写入不可变流水;人工账变入口保留在会员列表操作栏。 |
|
|
||||||
| 会员管理 | 会员等级 | `hg_app_member_level` | `hg_app_member_level_version`、`hg_app_member` | 等级规则及等级版本;会员主档关联当前等级。 |
|
|
||||||
| 会员管理 | 任务大厅 | `hg_task_hall` | `hg_task_hall_level`、`hg_app_member_level` | 配置大厅入口及允许参与的会员等级。 |
|
|
||||||
| 交易管理 | 订单列表 | `hg_trade_order` | `hg_app_member`、`hg_product`、`hg_task`、`hg_wallet_ledger` | 交易订单主档及会员、商品、任务、资金流水关联。 |
|
|
||||||
| 交易管理 | 充值管理 | `hg_recharge_order` | `hg_payment_channel`、`hg_wallet_account`、`hg_wallet_ledger`、`hg_finance_review` | 充值申请、渠道信息、审核结果和入账流水。 |
|
|
||||||
| 交易管理 | 提现管理 | `hg_withdrawal_order` | `hg_wallet_account`、`hg_wallet_ledger`、`hg_finance_review`、`hg_app_member_payment_account` | 提现申请、余额冻结/扣减/退回、审核以及收款账户信息。 |
|
|
||||||
| 交易管理 | 客服管理 | `hg_customer_service` | — | 客服名称、联系方式、工作时间、在线状态和排序。 |
|
|
||||||
| 商品管理 | 商品列表 | `hg_product` | `hg_product_category`、`hg_sys_attachment` | 正式商品主档,以 `product_type=1` 区分;分类保存在商品分类表。 |
|
|
||||||
| 任务管理 | 任务列表 | `hg_task` | `hg_task_level`、`hg_product`、`hg_app_member_level` | 任务主体、关联商品、适用会员等级及佣金规则。 |
|
|
||||||
| 任务管理 | 会员任务审核 | `hg_task_submission` | `hg_task`、`hg_app_member`、`hg_app_member_level`、`hg_wallet_account`、`hg_wallet_ledger` | 审核会员提交的任务;通过后结算佣金并生成钱包流水。 |
|
|
||||||
|
|
||||||
## 2. 已隐藏菜单但保留的业务能力
|
|
||||||
|
|
||||||
| 原菜单 | 保留表 | 当前入口/处理方式 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 资金调账 | `hg_wallet_adjustment_request`、`hg_wallet_account`、`hg_wallet_ledger` | 独立菜单已隐藏;相关权限和接口保留,由会员列表中的“账变”操作进入。 |
|
|
||||||
| 会员通知 | `hg_app_member_notice` | 独立菜单已隐藏;通知/弹幕相关能力和接口保留,可从会员列表操作或后续 C 端消息中心复用。 |
|
|
||||||
| 审批中心 | `hg_approval_request`、`hg_approval_action` | 独立治理菜单已移除;表和服务仍可供高风险业务复用。 |
|
|
||||||
| 业务审计 | `hg_biz_audit_log` | 独立菜单已移除;重要操作仍可写入审计记录。 |
|
|
||||||
|
|
||||||
## 3. HotGo 原生后台功能
|
|
||||||
|
|
||||||
### 3.1 组织与权限
|
|
||||||
|
|
||||||
| 功能 | 核心表 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 后台用户 | `hg_admin_member` | 后台管理员账号。 |
|
|
||||||
| 部门管理 | `hg_admin_dept` | 组织部门树。 |
|
|
||||||
| 岗位管理 | `hg_admin_post`、`hg_admin_member_post` | 岗位定义及管理员岗位关系。 |
|
|
||||||
| 角色权限 | `hg_admin_role`、`hg_admin_member_role` | 角色树、管理员角色关系。子角色可选菜单不得超过直接父角色范围。 |
|
|
||||||
| 菜单权限 | `hg_admin_menu`、`hg_admin_role_menu` | 菜单、页面、按钮权限及角色菜单关系。 |
|
|
||||||
| 接口鉴权 | `hg_admin_role_casbin` | Casbin 接口权限规则。 |
|
|
||||||
| 第三方登录 | `hg_admin_oauth` | 后台账号第三方授权关系。 |
|
|
||||||
|
|
||||||
### 3.2 系统设置与运维
|
|
||||||
|
|
||||||
| 功能 | 核心表 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 配置管理 | `hg_sys_config` | HotGo 系统配置。网站业务配置不写入此表,而写入 `hg_site_config_version`。 |
|
|
||||||
| 字典管理 | `hg_sys_dict_type`、`hg_sys_dict_data` | 动态字典类型和选项数据;代码枚举通过 HotGo 字典注册机制提供。 |
|
|
||||||
| 定时任务 | `hg_sys_cron_group`、`hg_sys_cron` | 定时任务分组、执行策略及状态。 |
|
|
||||||
| 黑名单 | `hg_sys_blacklist` | IP 等访问黑名单。 |
|
|
||||||
| 通知公告 | `hg_admin_notice`、`hg_admin_notice_read` | 面向后台管理员的公告及阅读状态,与会员通知不是同一张表。 |
|
|
||||||
| 附件管理 | `hg_sys_attachment` | 上传文件和图片元数据。 |
|
|
||||||
| 地区编码 | `hg_sys_provinces` | 省市区层级数据。 |
|
|
||||||
| 操作日志 | `hg_sys_log` | 后台接口操作日志。 |
|
|
||||||
| 登录日志 | `hg_sys_login_log` | 后台登录记录。 |
|
|
||||||
| 短信/邮件日志 | `hg_sys_sms_log`、`hg_sys_ems_log` | 短信和邮件发送记录。 |
|
|
||||||
| 服务日志 | `hg_sys_serve_log` | 服务运行日志。 |
|
|
||||||
| 服务授权/监控 | `hg_sys_serve_license` | 服务连接与授权状态;在线用户主要依赖会话/缓存,不单独落业务表。 |
|
|
||||||
|
|
||||||
### 3.3 HotGo 资金与支付基础能力
|
|
||||||
|
|
||||||
| 功能 | 核心表 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 后台资金账户 | `hg_admin_cash`、`hg_admin_credits_log` | HotGo 原生后台账户资金及积分/余额变动。与 C 端会员钱包表分离。 |
|
|
||||||
| HotGo 订单 | `hg_admin_order` | HotGo 原生支付订单,与业务交易订单 `hg_trade_order` 分离。 |
|
|
||||||
| 支付与退款日志 | `hg_pay_log`、`hg_pay_refund` | 支付请求、回调及退款记录。 |
|
|
||||||
|
|
||||||
### 3.4 插件与开发工具
|
|
||||||
|
|
||||||
| 功能 | 核心表 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 插件管理 | `hg_sys_addons_install`、`hg_sys_addons_config` | 插件安装状态及插件配置。 |
|
|
||||||
| 代码生成 | `hg_sys_gen_codes` | 代码生成配置。 |
|
|
||||||
| 示例插件 | `hg_addon_hgexample_table`、`hg_addon_hgexample_tenant_order` | HotGo 示例数据,不属于正式业务。 |
|
|
||||||
| 生成示例 | `hg_sys_gen_curd_demo`、`hg_sys_gen_tree_demo`、`hg_test_category` | CRUD/树表/分类演示,不属于正式业务。 |
|
|
||||||
|
|
||||||
## 4. 公共支撑表
|
|
||||||
|
|
||||||
| 表 | 用途 | 典型使用模块 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `hg_approval_request` | 审批请求主表 | 会员状态、资金调账、充值、提现等高风险操作。 |
|
|
||||||
| `hg_approval_action` | 审批动作流水 | 记录提交、通过、拒绝等动作。 |
|
|
||||||
| `hg_biz_audit_log` | 业务审计日志 | 资金、任务审核、状态变化等重要操作。 |
|
|
||||||
| `hg_sensitive_access_log` | 敏感数据查看记录 | 会员手机号、实名、银行卡等完整信息查看。 |
|
|
||||||
| `hg_idempotency_record` | 幂等控制 | 支付、审核执行、钱包入账等不可重复操作。 |
|
|
||||||
| `hg_outbox_event` | 事务消息/事件出站箱 | 业务提交后异步通知或跨模块事件。 |
|
|
||||||
| `hg_dashboard_daily_stat` | 每日统计快照 | 首页看板。 |
|
|
||||||
|
|
||||||
## 5. 核心数据关系
|
|
||||||
|
|
||||||
```text
|
|
||||||
会员 hg_app_member
|
|
||||||
├── 扩展资料 hg_app_member_profile
|
|
||||||
├── 地址 hg_app_member_address
|
|
||||||
├── 收款账户 hg_app_member_payment_account
|
|
||||||
├── 等级 hg_app_member_level
|
|
||||||
├── 钱包 hg_wallet_account
|
|
||||||
│ ├── 账变流水 hg_wallet_ledger
|
|
||||||
│ └── 人工调账 hg_wallet_adjustment_request
|
|
||||||
├── 交易订单 hg_trade_order
|
|
||||||
├── 充值订单 hg_recharge_order
|
|
||||||
├── 提现订单 hg_withdrawal_order
|
|
||||||
└── 任务提交 hg_task_submission
|
|
||||||
|
|
||||||
商品 hg_product
|
|
||||||
├── 分类 hg_product_category
|
|
||||||
├── 交易订单 hg_trade_order
|
|
||||||
└── 任务 hg_task
|
|
||||||
├── 等级投放 hg_task_level
|
|
||||||
└── 会员提交 hg_task_submission
|
|
||||||
```
|
|
||||||
|
|
||||||
## 6. 数据存储约定
|
|
||||||
|
|
||||||
- 业务金额统一以“分”存入 `bigint` 字段,页面负责格式化为元。
|
|
||||||
- 会员敏感信息采用密文、检索哈希和脱敏展示值分离保存。
|
|
||||||
- 钱包余额以 `hg_wallet_account` 为当前值,`hg_wallet_ledger` 为不可变账变依据。
|
|
||||||
- 网站设置字段集中保存在 `hg_site_config_version.config_json`,因此新增配置项通常无需增加数据库列。
|
|
||||||
- 商品管理和手工商城共用 `hg_product`,通过 `product_type` 区分。
|
|
||||||
- 后台管理员资金表与 C 端会员钱包表完全分离,禁止混用。
|
|
||||||
- 带 `tenant_id` 的业务表通过 HotGo 多租户过滤器隔离数据。
|
|
||||||
- 带 `deleted_at` 的表使用软删除,不直接物理删除历史业务记录。
|
|
||||||
@@ -1,453 +0,0 @@
|
|||||||
# 后台管理系统开发总结
|
|
||||||
|
|
||||||
> 文档版本:V1.0
|
|
||||||
> 编制日期:2026-10-08
|
|
||||||
> 需求基线:[后台管理系统需求文档](./后台管理系统需求文档.md)
|
|
||||||
> 概要设计:[后台管理系统概要设计](./后台管理系统概要设计.md)
|
|
||||||
> 项目目录:`/Users/youshunlai/go_workspace/olons_admin`
|
|
||||||
|
|
||||||
## 1. 文档说明
|
|
||||||
|
|
||||||
本文档汇总当前已经完成的后台管理系统开发内容,用于后续联调、测试、验收和继续开发。
|
|
||||||
|
|
||||||
文档中的状态分为:
|
|
||||||
|
|
||||||
- **已开发**:已完成数据库、后端接口、前端页面和菜单权限的主体实现。
|
|
||||||
- **复用现有系统**:HotGo 已提供对应能力,本项目不重复开发。
|
|
||||||
- **后续补充**:已有基础模型,但仍需按专项设计补齐业务闭环。
|
|
||||||
|
|
||||||
## 2. 总体完成情况
|
|
||||||
|
|
||||||
| 章节 | 模块 | 当前状态 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 第 4 章 | 首页数据看板 | 已开发 | 已接入真实业务统计与待办入口 |
|
|
||||||
| 第 5 章 | 门户、内容与 Banner | 已开发 | 已完成配置版本、文本、Banner、手工商城 |
|
|
||||||
| 第 6 章 | 会员管理 | 已开发 | 已完成会员、隐私、团队、钱包调账和通知 |
|
|
||||||
| 第 7 章 | 会员等级与任务大厅 | 已开发 | 已完成等级版本发布和任务大厅管理 |
|
|
||||||
| 第 8 章 | 交易管理 | 已开发 | 已完成订单、充值、提现和客服管理 |
|
|
||||||
| 第 9 章 | 商品与任务管理 | 已开发 | 已完成商品、任务和会员任务审核 |
|
|
||||||
| 第 10 章 | 管理员、角色与权限 | 复用现有系统 | HotGo 原有组织、管理员、角色和菜单权限满足主体需求 |
|
|
||||||
| 第 11 章 | 数据字典与个人设置 | 复用现有系统 | HotGo 原有字典、个人资料和安全设置满足主体需求 |
|
|
||||||
| 第 12 章 | 状态机与数据模型 | 后续补充 | 核心模型已有,冲正、归档和严格状态转换仍需补强 |
|
|
||||||
|
|
||||||
## 3. 技术实现概况
|
|
||||||
|
|
||||||
### 3.1 后端
|
|
||||||
|
|
||||||
- Go + GoFrame v2。
|
|
||||||
- 遵循 `api → controller → service → logic → dao` 分层。
|
|
||||||
- 业务模块使用主模块实现,没有引入额外 Addon。
|
|
||||||
- 表字段通过 `dao.Xxx.Columns()` 引用。
|
|
||||||
- 多租户数据通过现有 `handler.Model` 和 `hook.SaveTenant` 处理。
|
|
||||||
- 金额统一按“分”存储,比例统一按“万分比”存储。
|
|
||||||
- 业务字典优先复用 HotGo 字典系统,代码枚举统一在 `internal/consts` 注册。
|
|
||||||
|
|
||||||
### 3.2 前端
|
|
||||||
|
|
||||||
- Vue 3 + Vite + TypeScript。
|
|
||||||
- UI 统一使用 Naive UI 和项目已有的 `BasicTable`、`BasicForm`、`BasicModal`。
|
|
||||||
- HTTP 请求统一通过 `@/utils/http/axios` 的 `http.request`。
|
|
||||||
- 菜单由后端数据驱动,页面操作使用接口路径进行权限判断。
|
|
||||||
- 状态标签和筛选项从后端字典加载,不在页面硬编码业务枚举。
|
|
||||||
|
|
||||||
### 3.3 基础治理
|
|
||||||
|
|
||||||
在业务模块开发前已建设以下共用能力:
|
|
||||||
|
|
||||||
- 审批请求与审批动作。
|
|
||||||
- 业务审计日志和哈希链。
|
|
||||||
- 敏感信息查看记录。
|
|
||||||
- 幂等记录。
|
|
||||||
- Outbox 事件表。
|
|
||||||
- 看板每日汇总表。
|
|
||||||
- 高风险操作的申请、审批、执行分离。
|
|
||||||
|
|
||||||
对应迁移:
|
|
||||||
|
|
||||||
- `20261008_001_governance.sql`
|
|
||||||
- `20261008_002_governance_menu.sql`
|
|
||||||
|
|
||||||
## 4. 第 4 章:首页数据看板
|
|
||||||
|
|
||||||
### 4.1 已实现功能
|
|
||||||
|
|
||||||
- 今日新增会员、订单、充值、提现等核心指标。
|
|
||||||
- 业务金额、订单和会员数据汇总。
|
|
||||||
- 待审批和异常业务入口。
|
|
||||||
- 按管理员权限控制敏感金额展示。
|
|
||||||
- 原 HotGo 控制台菜单复用并扩展业务统计接口。
|
|
||||||
|
|
||||||
### 4.2 主要接口
|
|
||||||
|
|
||||||
- `GET /console/stat`
|
|
||||||
- `GET /dashboard/summary`
|
|
||||||
|
|
||||||
### 4.3 主要代码
|
|
||||||
|
|
||||||
- 后端:`server/internal/logic/sys/dashboard.go`
|
|
||||||
- 前端:`web/src/views/dashboard/console/`
|
|
||||||
- 前端 API:`web/src/api/dashboard/console.ts`
|
|
||||||
- 菜单迁移:`20261008_003_dashboard_menu.sql`
|
|
||||||
|
|
||||||
### 4.4 测试
|
|
||||||
|
|
||||||
- 已增加 `server/internal/logic/sys/dashboard_test.go`。
|
|
||||||
|
|
||||||
## 5. 第 5 章:门户、内容与 Banner 管理
|
|
||||||
|
|
||||||
### 5.1 网站设置
|
|
||||||
|
|
||||||
- 站点配置按完整快照保存。
|
|
||||||
- 支持草稿保存、提交审批、发布和历史版本查看。
|
|
||||||
- 支持根据历史版本生成回滚草稿。
|
|
||||||
- 使用摘要和乐观锁避免并发覆盖。
|
|
||||||
|
|
||||||
主要接口:
|
|
||||||
|
|
||||||
- `/siteConfig/current`
|
|
||||||
- `/siteConfig/history`
|
|
||||||
- `/siteConfig/save`
|
|
||||||
- `/siteConfig/submit`
|
|
||||||
- `/siteConfig/publish`
|
|
||||||
- `/siteConfig/rollback`
|
|
||||||
|
|
||||||
### 5.2 文本管理
|
|
||||||
|
|
||||||
- 文本内容列表、详情、新增和编辑。
|
|
||||||
- 内容正文按版本保存。
|
|
||||||
- 支持发布、下线和软删除。
|
|
||||||
- 保存当前发布版本 ID,历史版本不被覆盖。
|
|
||||||
|
|
||||||
主要接口:
|
|
||||||
|
|
||||||
- `/portalContent/list`
|
|
||||||
- `/portalContent/view`
|
|
||||||
- `/portalContent/edit`
|
|
||||||
- `/portalContent/publish`
|
|
||||||
- `/portalContent/offline`
|
|
||||||
- `/portalContent/delete`
|
|
||||||
|
|
||||||
### 5.3 Banner 管理
|
|
||||||
|
|
||||||
- Banner 列表、详情、新增、编辑和删除。
|
|
||||||
- 支持投放位置、图片、替代文本、跳转方式、生效时间、排序和发布状态。
|
|
||||||
- 支持发布和下线状态切换。
|
|
||||||
|
|
||||||
### 5.4 手工商城
|
|
||||||
|
|
||||||
- 手工商城商品列表、详情、新增、编辑、删除和上下架。
|
|
||||||
- 支持商品类型、支付方式、金额、封面、详情、推荐和展示时间。
|
|
||||||
|
|
||||||
### 5.5 数据表与代码
|
|
||||||
|
|
||||||
新增数据表:
|
|
||||||
|
|
||||||
- `hg_site_config_version`
|
|
||||||
- `hg_content`
|
|
||||||
- `hg_content_version`
|
|
||||||
- `hg_banner`
|
|
||||||
- `hg_product`
|
|
||||||
|
|
||||||
主要代码:
|
|
||||||
|
|
||||||
- 后端:`server/internal/logic/sys/portal.go`
|
|
||||||
- API:`server/api/admin/portal/portal.go`
|
|
||||||
- 前端:`web/src/views/portal/`
|
|
||||||
- 前端 API:`web/src/api/portal/index.ts`
|
|
||||||
- 迁移:`20261008_004_portal_content.sql`
|
|
||||||
- 测试:`server/internal/logic/sys/portal_test.go`
|
|
||||||
|
|
||||||
## 6. 第 6 章:会员管理
|
|
||||||
|
|
||||||
### 6.1 会员主档
|
|
||||||
|
|
||||||
- 会员列表、详情、新增、编辑和注销。
|
|
||||||
- 用户名、等级、上级、风控、信用分、自动派单和测试账号管理。
|
|
||||||
- 手机号、姓名、证件号按密文、检索哈希和脱敏值分离保存。
|
|
||||||
- 注销采用状态和软删除标记,不删除历史审计主体。
|
|
||||||
|
|
||||||
### 6.2 收款账户和地址
|
|
||||||
|
|
||||||
- 多类型收款账户管理。
|
|
||||||
- 银行卡、开户名和手机号敏感字段加密及脱敏。
|
|
||||||
- 会员地址列表、新增、编辑和删除。
|
|
||||||
|
|
||||||
### 6.3 敏感信息查看
|
|
||||||
|
|
||||||
- 完整敏感值通过独立授权接口查看。
|
|
||||||
- 必须填写查看目的。
|
|
||||||
- 记录操作人、目标、字段集、授权号和查看结果。
|
|
||||||
|
|
||||||
### 6.4 团队关系
|
|
||||||
|
|
||||||
- 支持查询会员下级团队。
|
|
||||||
- 使用 `pid`、`level` 和 `tree` 保存层级关系。
|
|
||||||
- 支持控制查询层级和分页。
|
|
||||||
|
|
||||||
### 6.5 会员状态
|
|
||||||
|
|
||||||
- 支持发起会员状态变更审批。
|
|
||||||
- 审批通过后由执行接口完成状态变更。
|
|
||||||
- 保存状态变更原因、审批单和操作记录。
|
|
||||||
|
|
||||||
### 6.6 钱包调账
|
|
||||||
|
|
||||||
- 钱包账户区分可用余额和冻结余额。
|
|
||||||
- 调账必须先申请审批,再执行入账。
|
|
||||||
- 每次资金变化写入不可变台账。
|
|
||||||
- 支持幂等键、前后余额和冲正关联字段。
|
|
||||||
|
|
||||||
### 6.7 会员通知
|
|
||||||
|
|
||||||
- 支持全体或指定会员通知。
|
|
||||||
- 区分真实通知与运营模拟。
|
|
||||||
- 支持有效期和撤回。
|
|
||||||
|
|
||||||
### 6.8 数据表与代码
|
|
||||||
|
|
||||||
新增数据表:
|
|
||||||
|
|
||||||
- `hg_app_member`
|
|
||||||
- `hg_app_member_profile`
|
|
||||||
- `hg_app_member_address`
|
|
||||||
- `hg_app_member_payment_account`
|
|
||||||
- `hg_app_member_status_log`
|
|
||||||
- `hg_wallet_account`
|
|
||||||
- `hg_wallet_ledger`
|
|
||||||
- `hg_wallet_adjustment_request`
|
|
||||||
- `hg_app_member_notice`
|
|
||||||
|
|
||||||
主要代码:
|
|
||||||
|
|
||||||
- 后端:`server/internal/logic/sys/app_member.go`
|
|
||||||
- API:`server/api/admin/appmember/appmember.go`
|
|
||||||
- 前端:`web/src/views/app-member/list/`、`wallet/`、`notice/`
|
|
||||||
- 前端 API:`web/src/api/appMember/index.ts`
|
|
||||||
- 迁移:`20261008_005_member_management.sql`
|
|
||||||
|
|
||||||
## 7. 第 7 章:会员等级与任务大厅
|
|
||||||
|
|
||||||
### 7.1 会员等级
|
|
||||||
|
|
||||||
- 会员等级列表和详情。
|
|
||||||
- 等级规则保存为不可变版本。
|
|
||||||
- 支持草稿、提交审批、发布、历史版本和回滚草稿。
|
|
||||||
- 使用乐观锁防止并发覆盖。
|
|
||||||
- 支持等级启停和删除。
|
|
||||||
|
|
||||||
主要接口:
|
|
||||||
|
|
||||||
- `/memberLevel/list`
|
|
||||||
- `/memberLevel/view`
|
|
||||||
- `/memberLevel/save`
|
|
||||||
- `/memberLevel/submit`
|
|
||||||
- `/memberLevel/publish`
|
|
||||||
- `/memberLevel/rollback`
|
|
||||||
- `/memberLevel/history`
|
|
||||||
- `/memberLevel/status`
|
|
||||||
- `/memberLevel/delete`
|
|
||||||
|
|
||||||
### 7.2 任务大厅
|
|
||||||
|
|
||||||
- 任务大厅列表、详情、新增和编辑。
|
|
||||||
- 支持封面、描述、开放时间、排序和发布状态。
|
|
||||||
- 支持配置允许进入的会员等级。
|
|
||||||
- 支持发布、下线和删除。
|
|
||||||
|
|
||||||
### 7.3 数据表与代码
|
|
||||||
|
|
||||||
新增数据表:
|
|
||||||
|
|
||||||
- `hg_app_member_level`
|
|
||||||
- `hg_app_member_level_version`
|
|
||||||
- `hg_task_hall`
|
|
||||||
- `hg_task_hall_level`
|
|
||||||
|
|
||||||
主要代码:
|
|
||||||
|
|
||||||
- 后端:`member_level.go`、`task_hall.go`
|
|
||||||
- API:`server/api/admin/memberlevel/`、`taskhall/`
|
|
||||||
- 前端:`web/src/views/app-member/level/`、`task-hall/`
|
|
||||||
- 前端 API:`web/src/api/memberLevel/`、`taskHall/`
|
|
||||||
- 迁移:`20261008_006_member_level_task_hall.sql`
|
|
||||||
|
|
||||||
## 8. 第 8 章:交易管理
|
|
||||||
|
|
||||||
### 8.1 交易订单
|
|
||||||
|
|
||||||
- 订单列表和详情。
|
|
||||||
- 支持商品、任务和手工商城订单类型。
|
|
||||||
- 保存商品名称、金额、会员等级和规则快照。
|
|
||||||
- 人工取消匹配、重新匹配和解冻必须经过审批。
|
|
||||||
- 执行时重新检查订单和审批状态。
|
|
||||||
|
|
||||||
### 8.2 充值管理
|
|
||||||
|
|
||||||
- 充值列表、金额汇总和详情。
|
|
||||||
- 支持线上支付和人工充值。
|
|
||||||
- 人工审核采用申请与执行分离。
|
|
||||||
- 审核通过后在事务内更新钱包并写入台账。
|
|
||||||
- 审核结果保存审批单、财务复核快照和审核原因。
|
|
||||||
|
|
||||||
### 8.3 提现管理
|
|
||||||
|
|
||||||
- 提现列表和脱敏详情。
|
|
||||||
- 支持初审、复核、付款中、成功、失败和驳回状态。
|
|
||||||
- 提现审核和执行通过事务、行锁、审批和台账处理。
|
|
||||||
- 付款结果单独登记,保存外部付款单号。
|
|
||||||
|
|
||||||
### 8.4 客服管理
|
|
||||||
|
|
||||||
- 客服列表、详情、新增、编辑、启停和删除。
|
|
||||||
- 支持客服类型、显示名称、联系方式、工作时间和排序。
|
|
||||||
|
|
||||||
### 8.5 数据表与代码
|
|
||||||
|
|
||||||
新增数据表:
|
|
||||||
|
|
||||||
- `hg_trade_order`
|
|
||||||
- `hg_payment_channel`
|
|
||||||
- `hg_recharge_order`
|
|
||||||
- `hg_withdrawal_order`
|
|
||||||
- `hg_finance_review`
|
|
||||||
- `hg_customer_service`
|
|
||||||
|
|
||||||
主要代码:
|
|
||||||
|
|
||||||
- 后端:`trade_order.go`、`recharge_order.go`、`withdrawal_order.go`、`customer_service.go`
|
|
||||||
- API:`server/api/admin/tradeorder/`、`rechargeorder/`、`withdrawalorder/`、`customerservice/`
|
|
||||||
- 前端:`web/src/views/trade/`
|
|
||||||
- 前端 API:`web/src/api/trade/index.ts`
|
|
||||||
- 迁移:`20261008_007_trade_management.sql`
|
|
||||||
|
|
||||||
## 9. 第 9 章:商品与任务管理
|
|
||||||
|
|
||||||
### 9.1 商品管理
|
|
||||||
|
|
||||||
- 商品列表、详情、新增和编辑。
|
|
||||||
- 支持分类、类型、支付方式、店铺、价格、封面、详情和展示时间。
|
|
||||||
- 支持上下架、推荐切换和删除。
|
|
||||||
|
|
||||||
### 9.2 任务管理
|
|
||||||
|
|
||||||
- 任务列表、详情、新增和编辑。
|
|
||||||
- 支持任务大厅、会员等级、封面、详情、固定佣金和比例佣金。
|
|
||||||
- 支持每日数量、单会员限制和任务有效期。
|
|
||||||
- 支持发布、下线和删除。
|
|
||||||
|
|
||||||
### 9.3 会员任务审核
|
|
||||||
|
|
||||||
- 按会员、任务和审核状态查询提交记录。
|
|
||||||
- 展示任务、会员、等级、佣金、成功率、证据和审核结果。
|
|
||||||
- 待审核记录支持通过和驳回。
|
|
||||||
- 驳回保存标准原因、补充说明和是否允许重新提交。
|
|
||||||
- 审核通过后在事务内结算佣金并写入钱包台账。
|
|
||||||
|
|
||||||
### 9.4 数据表与代码
|
|
||||||
|
|
||||||
新增数据表:
|
|
||||||
|
|
||||||
- `hg_product_category`
|
|
||||||
- `hg_task`
|
|
||||||
- `hg_task_level`
|
|
||||||
- `hg_task_submission`
|
|
||||||
|
|
||||||
主要代码:
|
|
||||||
|
|
||||||
- 后端:`product.go`、`task.go`、`task_submission.go`
|
|
||||||
- API:`server/api/admin/product/`、`task/`、`tasksubmission/`
|
|
||||||
- 前端:`web/src/views/product-task/`
|
|
||||||
- 前端 API:`web/src/api/productTask/index.ts`
|
|
||||||
- 迁移:`20261008_008_product_task_management.sql`
|
|
||||||
|
|
||||||
菜单“商品与任务”的根布局标识已统一为 HotGo 识别的 `LAYOUT`,进入子页面时左侧菜单和顶部布局可以正常保留。
|
|
||||||
|
|
||||||
## 10. 复用 HotGo 的现有功能
|
|
||||||
|
|
||||||
### 10.1 管理员、角色与权限
|
|
||||||
|
|
||||||
第 10 章不重复开发,复用:
|
|
||||||
|
|
||||||
- 组织管理中的管理员维护。
|
|
||||||
- 角色管理和菜单权限树。
|
|
||||||
- 接口路径权限控制。
|
|
||||||
- 部门、岗位和数据权限。
|
|
||||||
- 登录、禁用、密码重置等现有能力。
|
|
||||||
|
|
||||||
### 10.2 数据字典与个人设置
|
|
||||||
|
|
||||||
第 11 章不重复开发,复用:
|
|
||||||
|
|
||||||
- “系统设置 → 字典管理”的字典类型和字典数据 CRUD。
|
|
||||||
- 字典标签、键值、值类型、标签样式、排序和状态。
|
|
||||||
- “个人中心 → 个人设置”的基本资料维护。
|
|
||||||
- 手机号和邮箱验证码换绑。
|
|
||||||
- 当前密码校验和登录密码修改。
|
|
||||||
|
|
||||||
密码强度、全部会话撤销、敏感配置版本管理等属于后续安全增强,不纳入当前已开发范围。
|
|
||||||
|
|
||||||
## 11. 数据库迁移清单
|
|
||||||
|
|
||||||
| 顺序 | 文件 | 用途 |
|
|
||||||
| ---: | --- | --- |
|
|
||||||
| 1 | `20261008_001_governance.sql` | 审批、审计、幂等、Outbox、看板汇总 |
|
|
||||||
| 2 | `20261008_002_governance_menu.sql` | 治理模块菜单和权限 |
|
|
||||||
| 3 | `20261008_003_dashboard_menu.sql` | 首页看板菜单和权限 |
|
|
||||||
| 4 | `20261008_004_portal_content.sql` | 门户、内容、Banner、手工商城 |
|
|
||||||
| 5 | `20261008_005_member_management.sql` | 会员、敏感资料、钱包和通知 |
|
|
||||||
| 6 | `20261008_006_member_level_task_hall.sql` | 会员等级和任务大厅 |
|
|
||||||
| 7 | `20261008_007_trade_management.sql` | 订单、充值、提现和客服 |
|
|
||||||
| 8 | `20261008_008_product_task_management.sql` | 商品、任务和会员任务审核 |
|
|
||||||
|
|
||||||
以上迁移均采用可重复执行的建表或条件插入方式,菜单、字典和角色权限随对应业务迁移配置。
|
|
||||||
|
|
||||||
## 12. 当前运行与交付状态
|
|
||||||
|
|
||||||
- 本地后端运行地址:`http://127.0.0.1:8000`。
|
|
||||||
- 本地前端运行地址:`http://127.0.0.1:8001`。
|
|
||||||
- 动态菜单已加载首页、治理、门户、会员、交易、商品与任务模块。
|
|
||||||
- 第 4~9 章页面已经可以从后台菜单进入查看。
|
|
||||||
- 第 10、11 章继续使用 HotGo 原有页面。
|
|
||||||
|
|
||||||
### 12.1 本地演示数据
|
|
||||||
|
|
||||||
已为本次新增的 35 张业务表写入关联演示数据,覆盖审批、发布、会员、风控、订单、充值、提现、任务审核、调账和客服等全部已定义状态。演示业务编号统一使用 `DEMO` 前缀。
|
|
||||||
|
|
||||||
可重复执行的数据脚本:
|
|
||||||
|
|
||||||
```text
|
|
||||||
server/storage/data/seeds/20261008_business_demo_data.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
本地重新导入命令:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mysql -h127.0.0.1 -P3306 -uroot -proot olons_admin \
|
|
||||||
< server/storage/data/seeds/20261008_business_demo_data.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
正式上线前仍需执行完整的接口回归、权限角色矩阵检查、并发资金测试和生产配置核对。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 补充项:第 12 章状态机与数据模型补强
|
|
||||||
|
|
||||||
第 12 章不是新的一级菜单,而是对现有会员、资金、任务和内容模块的业务约束补强。当前核心数据表、审批、台账和审计基础已经具备,但以下内容尚未列入“已完成”:
|
|
||||||
|
|
||||||
1. 会员状态合法转换和注销不可逆。
|
|
||||||
2. 充值成功后的审批冲正。
|
|
||||||
3. 已结算任务佣金的审批冲正。
|
|
||||||
4. 文本内容归档和历史版本生成回滚草稿。
|
|
||||||
5. 状态转换、重复执行、并发执行和余额不足测试。
|
|
||||||
|
|
||||||
专项设计已单独整理,后续开发以该文档为实施依据:
|
|
||||||
|
|
||||||
[第12章状态机与数据模型补强设计](./第12章状态机与数据模型补强设计.md)
|
|
||||||
|
|
||||||
建议后续新增迁移:
|
|
||||||
|
|
||||||
```text
|
|
||||||
server/storage/data/migrations/20261008_009_state_machine_hardening.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
MFA 真实认证流程不与本次状态机补强混合实施,后续作为独立安全增强项处理。
|
|
||||||
@@ -1,508 +0,0 @@
|
|||||||
# 后台管理系统需求文档
|
|
||||||
|
|
||||||
参考管理端功能拆解、C 端映射与安全重构方案
|
|
||||||
|
|
||||||
目标:基于参考管理系统的实际页面、按钮、链接与弹窗,形成可直接用于产品设计、前后端开发、测试和运维的后台需求基线;保留业务闭环,不复制品牌资产和真实用户数据。
|
|
||||||
|
|
||||||
主要读者:产品负责人、交互设计师、前端开发、后端开发、测试、运营、客服、财务、风控、安全与审计。
|
|
||||||
|
|
||||||
观察日期:2026-10-07 参考环境:Web 管理后台 文档版本:V1.0
|
|
||||||
|
|
||||||
> **结论:** 后台覆盖门户配置、会员、交易、商品、任务、RBAC 与个人设置七大域。复刻时应优先修复敏感数据裸露、资金操作单人审批、配置无校验、接口错误和审计不足。
|
|
||||||
|
|
||||||
## 目录
|
|
||||||
|
|
||||||
- [1 文档范围与走查方法](#1-文档范围与走查方法)
|
|
||||||
- [2 产品定位与后台角色](#2-产品定位与后台角色)
|
|
||||||
- [3 C 端与后台功能映射](#3-c-端与后台功能映射)
|
|
||||||
- [4 首页数据看板](#4-首页数据看板)
|
|
||||||
- [5 门户、内容与 Banner 管理](#5-门户内容与-banner-管理)
|
|
||||||
- [6 会员管理](#6-会员管理)
|
|
||||||
- [7 会员等级与任务大厅](#7-会员等级与任务大厅)
|
|
||||||
- [8 交易管理](#8-交易管理)
|
|
||||||
- [9 商品与任务管理](#9-商品与任务管理)
|
|
||||||
- [10 管理员、角色与权限](#10-管理员角色与权限)
|
|
||||||
- [11 数据字典与个人设置](#11-数据字典与个人设置)
|
|
||||||
- [12 状态机与数据模型](#12-状态机与数据模型)
|
|
||||||
- [13 推荐接口清单](#13-推荐接口清单)
|
|
||||||
- [14 安全、隐私与审计](#14-安全隐私与审计)
|
|
||||||
- [15 非功能需求](#15-非功能需求)
|
|
||||||
- [16 端到端验收场景](#16-端到端验收场景)
|
|
||||||
- [17 研发里程碑](#17-研发里程碑)
|
|
||||||
- [18 原型图说明](#18-原型图说明)
|
|
||||||
- [19 待确认事项](#19-待确认事项)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1 文档范围与走查方法
|
|
||||||
|
|
||||||
本需求对后台 21 个可见页面入口进行了逐项走查,并打开新增、编辑、查看、分配、审核等代表性弹窗。为了保护现网数据,没有执行最终确定、上传、删除、禁用、设为假人、审核通过或驳回、资金调整、奖励金发放、权限保存和改密。
|
|
||||||
|
|
||||||
### 1.1 已覆盖入口
|
|
||||||
|
|
||||||
| 一级模块 | 页面 | 主要控件 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 主页 | 首页、网站设置、文本管理、Banner 设置、手工商城 | 指标卡、保存、上传、编辑、删除、发布 |
|
|
||||||
| 会员管理 | 会员列表、会员等级、任务大厅 | 搜索、新增、编辑、团队、账变、奖励金、等级配置 |
|
|
||||||
| 交易管理 | 订单、充值、提现、客服 | 筛选、自动刷新、匹配、凭证、审核、客服嵌入 |
|
|
||||||
| 商城管理 | 商品列表 | 搜索、新增、编辑、推荐、删除、富文本 |
|
|
||||||
| 任务管理 | 任务列表、会员任务审核 | 任务新增、编辑、通过、驳回 |
|
|
||||||
| 管理员 | 后台管理员、角色、权限、数据字典 | 账号、角色、权限树、配置项 |
|
|
||||||
| 设置 | 基本资料、修改密码 | 资料修改、密码修改 |
|
|
||||||
|
|
||||||
### 1.2 操作边界
|
|
||||||
|
|
||||||
- 只验证页面、按钮和弹窗是否可达,未提交会改变会员、资金、权限或配置的数据。
|
|
||||||
- 删除、禁用、设为假人、审核、账变、奖励金、改密等高风险入口仅记录需求,不执行最终动作。
|
|
||||||
- 原型图基于实测界面脱敏重绘,手机号、姓名、IP、银行卡、订单号均为掩码或虚构值。
|
|
||||||
- 接口名称以推荐实现命名;现网真实接口需在开发前通过代码或服务端文档二次核验。
|
|
||||||
|
|
||||||
### 1.3 证据等级
|
|
||||||
|
|
||||||
| 等级 | 定义 | 使用方式 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| A 实测 | 页面、按钮、表格或弹窗在走查中直接可见 | 可作为复刻基线 |
|
|
||||||
| B 推导 | 由相邻页面、C 端闭环或字段关系推导 | 开发前需确认 |
|
|
||||||
| C 建议 | 为安全、合规、可用性提出的重构要求 | 作为新系统强制规范 |
|
|
||||||
|
|
||||||
## 2 产品定位与后台角色
|
|
||||||
|
|
||||||
该后台用于运营一个移动端会员任务与账户平台。C 端会员进行注册、余额储入、领取订单、任务提交、佣金结算、提现和客服咨询;后台完成内容配置、会员治理、商品与任务配置、交易审核、财务对账和权限审计。
|
|
||||||
|
|
||||||
| 角色 | 职责 | 允许范围 | 禁止范围 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 超级管理员 | 系统与权限治理 | 账号、角色、权限、系统参数 | 不得绕过双人复核直接放款 |
|
|
||||||
| 运营 | 内容、Banner、商品、任务、等级 | 草稿、预览、发布申请 | 不得查看完整银行卡或改余额 |
|
|
||||||
| 客服 | 会员与订单查询、工单 | 脱敏资料、只读订单、备注 | 不得资金审核或导出全量用户 |
|
|
||||||
| 财务 | 充值、提现、对账 | 凭证、审核、支付状态 | 不得修改会员身份与权限 |
|
|
||||||
| 风控 | 异常行为与冻结复核 | 设备、IP 风险、冻结申请 | 不得单人完成冻结与解冻 |
|
|
||||||
| 审计 | 只读复核与导出 | 日志、审批链、差异报表 | 不得修改业务数据 |
|
|
||||||
|
|
||||||
### 2.1 信息架构
|
|
||||||
|
|
||||||
采用“一级业务域 + 二级页面 + 多标签工作区”的桌面后台结构。一级菜单固定在左侧,二级页面以标签页打开;标签支持关闭、刷新和回到首页。任何页面刷新后,应保持当前路由但不保留未提交敏感表单。
|
|
||||||
|
|
||||||
### 2.2 全局交互规范
|
|
||||||
|
|
||||||
- 列表页统一:查询区、主操作区、表格、固定操作列、分页;查询条件可重置并写入 URL。
|
|
||||||
- 弹窗统一:标题、关闭、表单、确定、取消;确定前做前后端双重校验,提交后禁止重复点击。
|
|
||||||
- 危险操作使用红色按钮并要求对象、影响、理由和二次确认;资金与权限操作额外要求复核人。
|
|
||||||
- 敏感值默认脱敏;查看完整值需单独权限、再次确认、限定时长,并记录操作者、目标、时间和用途。
|
|
||||||
- 加载超过 2 秒展示骨架与取消,接口失败展示错误码、重试和上报入口,不长期停留空白页。
|
|
||||||
- 操作成功后提供结果提示与审计编号;失败不得只显示“error”。
|
|
||||||
|
|
||||||
## 3 C 端与后台功能映射
|
|
||||||
|
|
||||||
后台不是独立工具,其配置和操作必须能解释 C 端每个入口、状态和金额。以下矩阵为联调的单一事实源。
|
|
||||||
|
|
||||||
| C 端能力 | 后台来源 | 后台操作 | 一致性要求 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 首页横幅与快捷入口 | Banner、网站设置 | 排序、有效期、跳转、开关 | 发布后按版本生效 |
|
|
||||||
| 平台简介/规则/公告 | 文本管理 | 富文本编辑、预览、发布 | CSP 与 HTML 白名单 |
|
|
||||||
| 手工商城 | 手工商城 | 商品增删改、图片、价格、时间 | C 端仅显示已上架 |
|
|
||||||
| 会员等级 | 会员等级 | 门槛、赠送、次数、佣金、提现次数 | 计算与展示同源 |
|
|
||||||
| 领取中心 | 网站设置、商品、订单 | 营业时间、最低余额、匹配规则 | 服务端状态机判定 |
|
|
||||||
| 订单记录 | 订单列表 | 查询、冻结、匹配、异常处理 | 业务单号和台账可追溯 |
|
|
||||||
| 储入 | 充值管理 | 凭证、审核、入账、驳回 | 幂等入账与自动对账 |
|
|
||||||
| 取出 | 提现管理、银行卡信息 | 收款资料、审核、通道、结果 | 金额、手续费、到账同源 |
|
|
||||||
| 任务大厅与任务 | 任务大厅、任务列表、会员任务审核 | 配置、分发、审核 | 等级、佣金、状态一致 |
|
|
||||||
| 个人资料 | 会员列表 | 资料、团队、状态、风控 | 敏感字段默认脱敏 |
|
|
||||||
| 通知与弹幕 | 文本、会员弹幕 | 发布、定向、撤回、查看记录 | 真实性标识和审计 |
|
|
||||||
| 客服 | 客服管理 | 客服入口、工作时间、会话映射 | 失败有备用通道 |
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
图 1 C 端与后台业务闭环(脱敏重绘原型)
|
|
||||||
|
|
||||||
## 4 首页数据看板
|
|
||||||
|
|
||||||
首页展示用户、商品、订单、充值、提现、佣金、利息宝转入、下级返佣与账户余额等汇总卡,并展示微信、支付宝和银行卡渠道统计。新系统应把口径、时间区间、刷新时间和数据延迟显式化。
|
|
||||||
|
|
||||||
| 指标 | 定义 | 筛选维度 | 权限 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 用户总量/新增 | 去重有效会员数 | 今日、昨日、自定义日期 | 运营只读 |
|
|
||||||
| 充值用户 | 至少一笔成功充值的会员数 | 时间、渠道、等级 | 财务/运营 |
|
|
||||||
| 订单量与金额 | 按订单状态和完成时间统计 | 状态、商品、等级 | 运营/财务 |
|
|
||||||
| 充值/提现 | 成功与待处理金额分开 | 渠道、状态、时间 | 财务 |
|
|
||||||
| 佣金/返佣 | 任务佣金与层级返佣分开 | 类型、等级、时间 | 财务/审计 |
|
|
||||||
| 账户余额 | 钱包可用与冻结余额总和 | 币种、账户状态 | 财务/审计 |
|
|
||||||
|
|
||||||
- 卡片可点击进入对应明细页,并继承时间筛选;无权限用户只能看到隐藏金额或不可点击状态。
|
|
||||||
- 页面顶部展示“数据截至时间”和刷新按钮;自动刷新不得造成重复请求风暴。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
图 2 后台首页看板(按实测界面脱敏重绘)
|
|
||||||
|
|
||||||
## 5 门户、内容与 Banner 管理
|
|
||||||
|
|
||||||
### 5.1 网站设置
|
|
||||||
|
|
||||||
| 配置组 | 字段 | 要求 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 品牌 | Logo、站点名称、隐私政策 URL | Logo 可预览;URL 仅允许 HTTPS 白名单 |
|
|
||||||
| 交易 | 交易余额、等待时间、每日次数、奖励次数 | 数值范围校验;修改按版本发布 |
|
|
||||||
| 佣金 | 0–5 级普通佣金 | Decimal;总和上限;法务开关 |
|
|
||||||
| 时间 | 提现、充值、交易、签到时间 | 支持多区间;禁止结束早于开始 |
|
|
||||||
| 门槛 | 最低充值、自动派单时间与金额 | 最小值≤最大值;币种与单位清晰 |
|
|
||||||
| 开关 | 免费领取、手工商城、首页任务、签到、商品模式、验证码 | 每项写明 C 端影响和降级文案 |
|
|
||||||
|
|
||||||
实测问题:交易等待时间输入框提示语与字段无关;签到时段出现“18:00–17:00”反向区间。新系统保存前必须做语义校验,并支持草稿、预览、发布、回滚。
|
|
||||||
|
|
||||||
### 5.2 文本管理
|
|
||||||
|
|
||||||
内容类型包括平台公告、平台简介、订单规则、代理合作、FAQ、指南、利息宝规则、首页滚动、订单提示、活动、首页弹窗和公司资质。编辑器需支持标题、正文、图片、链接、预览、定时发布、版本和回滚。
|
|
||||||
|
|
||||||
- 富文本使用标签/属性白名单;禁止 script、事件属性、javascript: URL 和未知 iframe。
|
|
||||||
- 现网编辑弹窗标题错误显示“编辑商品”,新系统标题必须与内容类型一致。
|
|
||||||
|
|
||||||
### 5.3 Banner 设置
|
|
||||||
|
|
||||||
支持多张首页 Banner 的上传、删除、排序、上下线、有效期、跳转类型与替代文本。上传前预览并校验尺寸、比例、MIME、文件大小和恶意内容。删除需要二次确认,已发布素材优先下线而非物理删除。
|
|
||||||
|
|
||||||
### 5.4 手工商城
|
|
||||||
|
|
||||||
列表字段为图片、名称、价格、时间与操作;新增/编辑字段为产品名称、价格、图片与展示时间。现网新增弹窗曾长时间停留 loading,需增加 8 秒超时、重试和错误上报。
|
|
||||||
|
|
||||||
## 6 会员管理
|
|
||||||
|
|
||||||
### 6.1 会员列表
|
|
||||||
|
|
||||||
查询条件:用户名、手机号、注册时间、状态、自动派单。列表字段:ID、账号、绑卡姓名、用户名、账户余额、冻结金额、上级用户、邀请码、注册时间、最后登录 IP、IP 属地、自动抢单、状态、当日交易次数。
|
|
||||||
|
|
||||||
| 操作 | 页面或弹窗 | 关键校验 | 审计要求 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 添加/编辑 | 会员表单 | 手机号唯一;余额不可由普通编辑修改;密码强度 | 记录前后值,密码永不回显 |
|
|
||||||
| 银行卡信息 | 开户人、银行、电话、卡号、数字钱包、云闪付、收款码 | 必要性与格式;图片扫描 | 完整值查看留痕 |
|
|
||||||
| 地址信息 | 姓名、电话、地区、详细地址 | 最小化收集;字段脱敏 | 查看和修改留痕 |
|
|
||||||
| 查看团队 | 当前用户、层级、人数、余额、佣金、充值、提现 | 仅展示授权层级 | 导出单独授权 |
|
|
||||||
| 账变 | 余额调整或流水 | 金额、类型、理由、业务单号 | 双人复核;不可直接改余额 |
|
|
||||||
| 弹幕 | 会员定向或模拟内容 | 标注来源、有效期、撤回 | 禁止伪造真实用户行为 |
|
|
||||||
| 奖励金 | 奖励金额与原因 | 非负、额度、幂等 | 财务复核与凭证 |
|
|
||||||
| 设为假人 | 账号标记 | 不得混入真实统计或 C 端荣誉榜 | 仅测试环境默认启用 |
|
|
||||||
| 禁用 | 账号状态 | 理由、范围、时长、申诉 | 双人复核;通知用户 |
|
|
||||||
| 删除 | 软删除/注销 | 检查资金与订单;不可物理删台账 | 高风险二次确认 |
|
|
||||||
|
|
||||||
> **P0 风险:** 现网页面默认显示完整手机号、姓名与登录 IP。新系统必须默认脱敏,按角色和目的临时授权查看;列表、导出、日志、埋点和截图统一执行同一脱敏规则。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
图 3 会员列表脱敏原型
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
图 4 添加会员弹窗原型
|
|
||||||
|
|
||||||
## 7 会员等级与任务大厅
|
|
||||||
|
|
||||||
### 7.1 会员等级
|
|
||||||
|
|
||||||
列表字段为等级名称、升级价格、赠送金额、接单次数、佣金比例和提现次数;支持编辑与受控删除。等级配置直接影响 C 端充值、领取和提现,必须使用版本化发布,不得修改后立即影响进行中的订单。
|
|
||||||
|
|
||||||
| 规则 | 校验 | 生效策略 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 升级价格/赠送金额 | ≥0;货币精度;赠送比例上限 | 新会员或下个结算周期 |
|
|
||||||
| 接单次数 | 整数;按日重置时区明确 | 发布后次日生效 |
|
|
||||||
| 佣金比例 | 0–1 Decimal;展示百分比 | 锁定到任务订单快照 |
|
|
||||||
| 提现次数 | 整数;与提现时间窗一致 | 发布后次日生效 |
|
|
||||||
| 删除等级 | 无有效会员与在途订单方可删除 | 优先停用并保留历史 |
|
|
||||||
|
|
||||||
### 7.2 任务大厅
|
|
||||||
|
|
||||||
页面字段为名称、图标、比例、简介、创建时间;新增弹窗还包含会员等级。实测列表接口直接显示“数据接口请求异常:error”,但新增弹窗可打开。新系统需要标准错误码、可重试状态、traceId 与空数据区分。
|
|
||||||
|
|
||||||
- 任务大厅条目必须绑定可用会员等级、比例单位、图标和 C 端跳转。
|
|
||||||
- 停用条目不影响已领取任务;删除仅允许无历史引用的数据,建议统一软删除。
|
|
||||||
|
|
||||||
## 8 交易管理
|
|
||||||
|
|
||||||
### 8.1 订单列表
|
|
||||||
|
|
||||||
查询条件:订单号、手机号、用户名、日期;支持开启/关闭自动刷新。列表含绑卡姓名、用户名、自动派单、余额、手机号、当日交易次数、商品、数量、金额、佣金、下单时间、解冻时间、消息、订单状态、冻结状态和操作。
|
|
||||||
|
|
||||||
| 状态 | 后台操作 | 约束 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 匹配中 | 查看进度、取消匹配 | 同一会员仅一笔匹配;需幂等 |
|
|
||||||
| 待处理 | 查看详情、发送提醒 | 不可手动完成;服务端倒计时 |
|
|
||||||
| 冻结 | 查看风险、发起解冻复核 | 冻结理由、时长、申诉路径 |
|
|
||||||
| 已完成 | 查看台账 | 金额、佣金、解冻三方一致 |
|
|
||||||
| 异常/失败 | 重新匹配、人工处理申请 | 人工改状态必须双人审批 |
|
|
||||||
|
|
||||||
### 8.2 充值管理
|
|
||||||
|
|
||||||
顶部展示全部、用户已支付、用户未支付、手动审核、手动驳回等汇总金额。列表字段:订单号、真实姓名、手机号、余额、交易金额、打款凭证、添加时间、支付方式、类型、处理时间、备注和操作。
|
|
||||||
|
|
||||||
- 审核通过前校验凭证、订单金额、收款主体、重复订单和账户状态;入账使用幂等键。
|
|
||||||
- 驳回必须选择标准原因并可补充说明;通知 C 端且允许补充材料。
|
|
||||||
|
|
||||||
### 8.3 提现管理
|
|
||||||
|
|
||||||
查询条件:订单号、用户名、日期。列表含用户余额、提现金额、手续费、实际到账、银行名称、开户名称、银行卡号、云闪付、数字钱包、支付宝/微信收款码、发起与处理时间、操作。
|
|
||||||
|
|
||||||
> **P0 风险:** 现网直接显示完整银行卡号与多个钱包账号。新系统列表只显示掩码,完整值不进入普通 DOM;付款处理时通过一次性授权查看,超时自动隐藏。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
图 5 提现审核脱敏原型
|
|
||||||
|
|
||||||
### 8.4 客服管理
|
|
||||||
|
|
||||||
实测页面在加载后保持空白。新系统至少提供客服账号、名称、工作时间、在线状态、跳转 URL、排序、启停和会话映射;第三方 iframe 失败时显示备用联系方式和错误编号。
|
|
||||||
|
|
||||||
## 9 商品与任务管理
|
|
||||||
|
|
||||||
### 9.1 商品列表
|
|
||||||
|
|
||||||
查询条件:商品名称、支付类型。列表:ID、图片、名称、商品价格、店铺名称、创建时间、是否推荐、操作。新增/编辑字段:商品名称、分类、店铺名称、商品单价、展示图片、商品详情富文本。
|
|
||||||
|
|
||||||
- 推荐/不推荐为明确状态切换,提交前展示影响范围;列表筛选和 C 端排序一致。
|
|
||||||
- 价格采用 Decimal;图片与富文本执行内容安全校验;商品被订单引用后只允许停用。
|
|
||||||
|
|
||||||
### 9.2 任务列表
|
|
||||||
|
|
||||||
按会员类型筛选;字段为任务编号、封面、标题、描述、等级、佣金、创建时间。新增弹窗含标题、描述、封面、等级、佣金和详情。实测新增任务弹窗标题误用“添加大厅任务”,需修正。
|
|
||||||
|
|
||||||
### 9.3 会员任务审核
|
|
||||||
|
|
||||||
按手机号、用户名查询;列表含记录 ID、用户名、手机、任务标题、等级、佣金、成功率、状态、备注、创建时间和操作。待审核记录支持通过与驳回。
|
|
||||||
|
|
||||||
| 动作 | 前置条件 | 提交内容 | 结果 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 通过 | 任务存在、会员有效、未重复审核 | 审核意见、证据摘要、幂等键 | 发放佣金或进入结算队列 |
|
|
||||||
| 驳回 | 记录为待审核 | 标准原因、补充说明、是否允许重提 | 通知会员并保留证据 |
|
|
||||||
| 撤回审核 | 仅异常且未结算 | 变更单与复核人 | 冲正而非修改历史记录 |
|
|
||||||
|
|
||||||
## 10 管理员、角色与权限
|
|
||||||
|
|
||||||
### 10.1 后台管理员
|
|
||||||
|
|
||||||
查询条件为登录名、手机、邮箱、角色;列表含姓名、登录名、手机号、邮箱、角色、更新时间和创建时间。新增字段为姓名、用户名、密码、手机、邮箱和多选角色。
|
|
||||||
|
|
||||||
- 密码强度至少 12 位,禁止默认密码,首次登录强制改密;密码永不回显。
|
|
||||||
- 禁用优先于删除;删除账号时保留历史审计主体,不得影响日志可追溯性。
|
|
||||||
|
|
||||||
### 10.2 角色管理
|
|
||||||
|
|
||||||
角色列表支持新增、编辑、删除和分配权限。分配弹窗为可展开/折叠的权限树。保存权限属于高风险操作,必须展示新增与移除差异,并由另一名管理员复核。
|
|
||||||
|
|
||||||
### 10.3 权限管理
|
|
||||||
|
|
||||||
权限树字段为 ID、名称、权限标识、父级 ID 和操作;支持添加顶级权限、添加子级、编辑、删除、展开/折叠。权限标识唯一且不可随意改名;被角色引用时禁止删除。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
图 6 建议 RBAC 权限矩阵
|
|
||||||
|
|
||||||
## 11 数据字典与个人设置
|
|
||||||
|
|
||||||
### 11.1 数据字典
|
|
||||||
|
|
||||||
列表字段为 ID、名称、值、创建时间;支持新增、编辑、删除。现网同时存在英文 key、中文名称和缺失名称的条目,并与网站设置重复维护。建议将字典拆为“系统常量”和“业务配置”,以结构化 Schema 管理。
|
|
||||||
|
|
||||||
| 字段 | 要求 |
|
|
||||||
| --- | --- |
|
|
||||||
| key | 全局唯一;小写或大写规范统一;发布后不可改名 |
|
|
||||||
| value | 按 Schema 校验类型、范围、枚举、时间段和单位 |
|
|
||||||
| description | 必填,说明业务含义、C 端影响和默认值 |
|
|
||||||
| scope | 环境、租户、渠道、会员等级等作用域 |
|
|
||||||
| version | 草稿、已发布、已回滚;记录生效时间 |
|
|
||||||
| secret | 敏感配置不得明文显示,使用密钥管理系统 |
|
|
||||||
|
|
||||||
### 11.2 基本资料
|
|
||||||
|
|
||||||
字段为用户名(不可修改)、名称、手机、邮箱,提交按钮为“确认修改”。修改手机或邮箱需验证当前身份和新联系方式;成功后记录审计并通知原联系方式。
|
|
||||||
|
|
||||||
### 11.3 修改密码
|
|
||||||
|
|
||||||
字段为当前密码、新密码、确认新密码,现网提示 6–16 个字符。新系统建议至少 12 位并支持密码管理器;最终提交必须由用户本人完成,成功后撤销其他会话并发送安全通知。
|
|
||||||
|
|
||||||
## 12 状态机与数据模型
|
|
||||||
|
|
||||||
### 12.1 核心状态机
|
|
||||||
|
|
||||||
| 实体 | 状态 | 允许转换 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 会员 | 正常、受限、禁用、注销 | 正常→受限/禁用;复核后恢复;注销不可逆 |
|
|
||||||
| 订单 | 匹配中、待处理、处理中、完成、超时、冻结、取消、失败 | 仅服务端状态机转换 |
|
|
||||||
| 充值 | 待支付、待审核、成功、驳回、过期、取消 | 成功后只允许冲正 |
|
|
||||||
| 提现 | 待审核、复核中、处理中、成功、失败、驳回、取消 | 付款前可取消;成功后只允许冲正 |
|
|
||||||
| 任务审核 | 待审核、通过、驳回、已结算、已冲正 | 结算后不可回到待审核 |
|
|
||||||
| 内容 | 草稿、待审、已发布、已下线、已归档 | 发布需审批;可回滚版本 |
|
|
||||||
| 配置 | 草稿、待发布、已发布、已回滚 | 发布后生成不可变版本 |
|
|
||||||
|
|
||||||
### 12.2 核心实体
|
|
||||||
|
|
||||||
| 实体 | 关键字段 | 约束 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| AdminUser | id, loginName, roles, status, mfa, lastLogin | 管理员身份与会话 |
|
|
||||||
| Role/Permission | roleId, permissionKey, scope | 最小权限与数据范围 |
|
|
||||||
| Member | id, mobileEnc, nameEnc, levelId, status | 敏感字段加密、索引分离 |
|
|
||||||
| Wallet | available, frozen, currency, version | 只允许台账事务修改 |
|
|
||||||
| LedgerEntry | bizNo, type, amount, before, after, reversalOf | 不可变、幂等、可冲正 |
|
|
||||||
| Order | orderNo, memberId, productSnapshot, amount, commission, status | 保存规则快照 |
|
|
||||||
| Deposit/Withdrawal | bizNo, amount, fee, channel, status, reviewer | 审批链与支付回执 |
|
|
||||||
| Content/Banner | type, body, version, publishAt, operator | 预览与版本化发布 |
|
|
||||||
| ConfigVersion | key, value, schema, effectiveAt | 语义校验与回滚 |
|
|
||||||
| AuditLog | actor, action, target, before, after, reason, traceId | 防篡改与长期留存 |
|
|
||||||
|
|
||||||
## 13 推荐接口清单
|
|
||||||
|
|
||||||
接口为新系统建议设计,统一前缀 /admin-api/v1。响应包含 data、code、message、traceId;所有写接口必须携带 Idempotency-Key,资金与权限写操作同时携带审批单号。
|
|
||||||
|
|
||||||
| 方法 | 路径 | 用途 | 关键参数 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| GET | /dashboard/summary | 首页指标 | timeRange, dimensions |
|
|
||||||
| GET/PUT | /site-settings | 读取/保存站点配置草稿 | version, settings |
|
|
||||||
| POST | /site-settings/publish | 发布配置 | draftVersion, reason |
|
|
||||||
| GET/POST | /contents | 内容列表/新建 | type, status, body |
|
|
||||||
| POST | /contents/{id}/publish | 内容发布 | publishAt, approver |
|
|
||||||
| GET/POST | /banners | Banner 查询/新建 | imageAssetId, sort, target |
|
|
||||||
| GET/POST | /members | 会员查询/新建 | filters, profile |
|
|
||||||
| GET/PATCH | /members/{id} | 会员详情/编辑 | editableProfile, version |
|
|
||||||
| POST | /members/{id}/adjustment-requests | 账变申请 | type, amount, reason, evidence |
|
|
||||||
| POST | /members/{id}/status-requests | 禁用/解禁申请 | targetStatus, reason, duration |
|
|
||||||
| GET/POST | /member-levels | 等级查询/草稿 | rules, effectiveAt |
|
|
||||||
| GET/POST | /products | 商品查询/新建 | category, price, assets, detail |
|
|
||||||
| GET/POST | /tasks | 任务查询/新建 | levelIds, commission, detail |
|
|
||||||
| GET | /orders | 订单列表 | orderNo, member, status, timeRange |
|
|
||||||
| POST | /orders/{id}/exception-requests | 异常处理申请 | action, reason |
|
|
||||||
| GET | /deposits | 充值列表 | status, channel, timeRange |
|
|
||||||
| POST | /deposits/{id}/review | 充值审核 | decision, reason, version |
|
|
||||||
| GET | /withdrawals | 提现列表 | status, member, timeRange |
|
|
||||||
| POST | /withdrawals/{id}/review | 提现审核 | decision, reason, version |
|
|
||||||
| GET | /withdrawals/{id}/sensitive-view | 一次性查看收款信息 | purpose, challengeToken |
|
|
||||||
| GET/POST | /task-submissions | 任务审核列表/决定 | decision, reason |
|
|
||||||
| GET/POST | /admin-users | 管理员查询/新建 | profile, roleIds |
|
|
||||||
| GET/POST | /roles | 角色查询/新建 | name, scope |
|
|
||||||
| POST | /roles/{id}/permission-change-requests | 权限变更申请 | add, remove, reason |
|
|
||||||
| GET | /audit-logs | 审计查询 | actor, action, target, timeRange |
|
|
||||||
|
|
||||||
## 14 安全、隐私与审计
|
|
||||||
|
|
||||||
| 风险 | 现网表现 | 新系统要求 | 优先级 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 个人信息裸露 | 完整手机号、姓名、IP | 默认脱敏;临时授权;全链路审计 | P0 |
|
|
||||||
| 金融信息裸露 | 完整银行卡与钱包账号 | 应用层加密;非 DOM 展示;一次性查看 | P0 |
|
|
||||||
| 资金单人操作 | 通过/驳回、账变、奖励入口直接可达 | 职责分离、双人复核、额度和幂等 | P0 |
|
|
||||||
| 伪造行为 | 设为假人、弹幕入口 | 测试数据隔离;禁止混入真实榜单与统计 | P0 |
|
|
||||||
| 富文本 XSS | 商品与内容支持富文本 | 白名单、CSP、上传扫描、预览隔离 | P0 |
|
|
||||||
| 配置误发布 | 时间反向、字段提示错误 | Schema 校验、预览、审批、回滚 | P0 |
|
|
||||||
| 接口不可用 | 任务大厅 error、客服空白 | 错误码、重试、熔断、监控和降级 | P1 |
|
|
||||||
| 权限漂移 | 多角色与权限树直接保存 | 差异预览、审批、定期复核 | P0 |
|
|
||||||
|
|
||||||
### 14.1 审计日志
|
|
||||||
|
|
||||||
- 记录登录、查看敏感信息、导出、查询大范围数据、资金审核、账变、奖励、冻结、配置发布、权限变更和改密。
|
|
||||||
- 字段至少包含操作者、角色、MFA、目标、动作、前值、后值、理由、审批人、IP、设备、traceId、时间和结果。
|
|
||||||
- 日志写入独立存储并防篡改;业务管理员无删除权限;按监管与公司政策设定留存期。
|
|
||||||
- 导出文件水印、加密、限时下载;下载与转发均可追踪。
|
|
||||||
|
|
||||||
### 14.2 登录与会话
|
|
||||||
|
|
||||||
- 管理员必须启用 MFA;高风险动作触发再次认证。
|
|
||||||
- 闲置 15–30 分钟自动锁定;会话撤销、设备列表和异地登录提醒。
|
|
||||||
- 连续失败触发限流与告警;不得依赖前端验证码作为唯一防护。
|
|
||||||
- 服务端密码使用 Argon2id 或 bcrypt;任何日志、监控和前端状态都不得保存密码。
|
|
||||||
|
|
||||||
## 15 非功能需求
|
|
||||||
|
|
||||||
| 类别 | 目标 | 验收指标 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 性能 | 常用列表与详情快速可用 | 列表 P95<1s;写操作 P95<1.5s;首屏<2.5s |
|
|
||||||
| 可用性 | 关键交易全年可用 | 资金审核 99.95%;其余 99.9% |
|
|
||||||
| 容量 | 支持 10 万会员与百万级订单 | 游标分页、索引与冷热分层 |
|
|
||||||
| 并发 | 自动刷新与多运营并发安全 | 乐观锁、版本号、冲突提示 |
|
|
||||||
| 可观测 | 定位每次请求与资金变更 | traceId、指标、日志、告警、审计关联 |
|
|
||||||
| 兼容 | 主流桌面浏览器 | Chrome/Edge 最近两个稳定版;1366×768 可用 |
|
|
||||||
| 可访问 | 键盘与读屏可操作 | 焦点、标签、颜色对比、44px 点击区 |
|
|
||||||
| 灾备 | 配置与交易可恢复 | RPO≤5 分钟,RTO≤30 分钟;季度演练 |
|
|
||||||
|
|
||||||
### 15.1 列表与弹窗通用验收
|
|
||||||
|
|
||||||
- 查询条件、分页、排序、刷新后可恢复;空数据、加载中、失败、无权限均有独立状态。
|
|
||||||
- 横向宽表固定关键列和操作列;敏感字段不因横向滚动或 tooltip 意外暴露。
|
|
||||||
- 弹窗关闭与取消不产生写操作;表单脏数据关闭前提示;成功后只刷新受影响区域。
|
|
||||||
- 重复点击、网络重试和浏览器回退不会重复创建、重复审核或重复入账。
|
|
||||||
- 所有时间显示时区,金额显示币种和精度,百分比与小数含义统一。
|
|
||||||
|
|
||||||
## 16 端到端验收场景
|
|
||||||
|
|
||||||
| 编号 | 场景与验收路径 |
|
|
||||||
| --- | --- |
|
|
||||||
| A01 内容发布 | 运营新建公告→预览→提交审核→审批→定时发布→C 端显示相同版本→回滚 |
|
|
||||||
| A02 会员查询 | 客服按掩码手机号查询→查看脱敏资料→申请查看完整值→审计留痕→超时隐藏 |
|
|
||||||
| A03 任务闭环 | 配置任务→C 端领取→生成订单→提交→后台审核→佣金入账→台账核对 |
|
|
||||||
| A04 充值审核 | C 端提交→后台待审核→重复回调→单次入账→通知→对账一致 |
|
|
||||||
| A05 提现复核 | C 端申请→风控命中→财务初审→复核→通道付款→状态与到账金额一致 |
|
|
||||||
| A06 禁用会员 | 客服发起→填写理由和时长→风控复核→会员受限→通知与申诉→解禁 |
|
|
||||||
| A07 账变 | 运营申请奖励→财务复核→台账入账→重复提交被幂等拦截→审计可追溯 |
|
|
||||||
| A08 权限变更 | 管理员申请新增提现审核权限→展示差异→复核→即时生效→历史会话重新鉴权 |
|
|
||||||
| A09 配置错误 | 输入反向时间/非法比例→前后端阻止→错误定位到字段→不生成草稿版本 |
|
|
||||||
| A10 服务降级 | 任务大厅 API 失败/客服 iframe 失败→清晰错误→重试/备用入口→告警产生 |
|
|
||||||
|
|
||||||
### 16.1 发布门槛
|
|
||||||
|
|
||||||
- P0 风险全部关闭;资金、权限、隐私与上传通过专项安全测试。
|
|
||||||
- C 端和后台使用同一配置版本、状态枚举、金额口径和错误码。
|
|
||||||
- 关键写操作完成幂等、并发、回滚、重试、超时与断网测试。
|
|
||||||
- 审计日志可以从一次用户投诉还原完整操作者、审批链和资金流水。
|
|
||||||
- 备份恢复、支付对账、权限复核和事故响应完成演练。
|
|
||||||
|
|
||||||
## 17 研发里程碑
|
|
||||||
|
|
||||||
| 阶段 | 范围 | 退出条件 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| M0 设计基线 | 信息架构、组件、状态机、RBAC、字段字典 | 产品/设计/技术/安全评审通过 |
|
|
||||||
| M1 基础后台 | 登录、管理员、角色、权限、审计、内容、Banner | MFA、审计、发布流可用 |
|
|
||||||
| M2 会员与配置 | 会员、等级、团队、配置中心 | 脱敏、临时授权、版本发布完成 |
|
|
||||||
| M3 商品与任务 | 商品、任务、任务大厅、审核 | C 端联调与佣金快照通过 |
|
|
||||||
| M4 交易与资金 | 订单、充值、提现、对账、复核 | 支付沙箱、幂等、双人复核通过 |
|
|
||||||
| M5 运营与稳定性 | 看板、客服、监控、灾备、性能 | SLO、告警、恢复演练通过 |
|
|
||||||
|
|
||||||
### 17.1 建议开发顺序
|
|
||||||
|
|
||||||
1. 先建设统一认证、RBAC、审计、脱敏和配置发布,再开发具体业务页。
|
|
||||||
1. 会员、商品、任务可先使用模拟资金;充值和提现必须最后接真实通道。
|
|
||||||
1. 资金域上线前实行沙箱、小流量、额度限制和人工对账。
|
|
||||||
1. 上线后第一周每日权限复核、账务核对和错误率复盘。
|
|
||||||
|
|
||||||
## 18 原型图说明
|
|
||||||
|
|
||||||
文档中的界面图按实测后台的布局、菜单、表格、弹窗和业务字段脱敏重绘,可直接用于讨论信息层级和交互。它们不是视觉稿:品牌、颜色、图标和真实数据应在 UI 设计阶段重新建立。
|
|
||||||
|
|
||||||
### 18.1 首页看板(脱敏重绘)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 18.2 会员列表(脱敏重绘)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 18.3 会员弹窗(脱敏重绘)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 18.4 提现审核(脱敏重绘)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 18.5 角色权限(脱敏重绘)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 18.6 业务闭环(脱敏重绘)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 19 待确认事项
|
|
||||||
|
|
||||||
- 目标系统是否处理真实资金,适用司法辖区、支付牌照与实名要求是什么。
|
|
||||||
- “设为假人、弹幕、奖励金、层级返佣”是否保留;若保留,业务合法性和真实性如何证明。
|
|
||||||
- 充值、提现、账变和会员禁用的初审/复核角色与金额阈值。
|
|
||||||
- C 端现有接口能否修改,还是需要后台兼容旧字段和状态枚举。
|
|
||||||
- 客服使用自建工单还是第三方服务,允许向第三方传输哪些数据。
|
|
||||||
- 运营内容是否需要多语言、定时发布、区域差异与灰度发布。
|
|
||||||
- 历史用户、订单、银行卡和台账的迁移范围、清洗规则和保留年限。
|
|
||||||
- 生产环境数据导出、敏感值查看和紧急权限的审批人。
|
|
||||||
|
|
||||||
在上述事项确认前,可以完成认证、RBAC、审计、内容、会员脱敏查询、商品任务配置和沙箱交易;不得接入真实收款、放款或自动资金调整。
|
|
||||||
@@ -1,484 +0,0 @@
|
|||||||
# 第 12 章状态机与数据模型补强设计
|
|
||||||
|
|
||||||
> 文档版本:V1.0
|
|
||||||
> 编制日期:2026-10-08
|
|
||||||
> 依据:[后台管理系统需求文档](./后台管理系统需求文档.md)第 12 章
|
|
||||||
> 关联设计:[后台管理系统概要设计](./后台管理系统概要设计.md)
|
|
||||||
> 适用项目:`olons_admin`
|
|
||||||
|
|
||||||
## 1. 文档目标
|
|
||||||
|
|
||||||
本文档用于补齐需求文档第 12 章中尚未闭环的状态机、资金冲正、内容归档与历史版本回滚能力,作为数据库迁移、后端接口、前端操作、权限配置和测试验收的实施依据。
|
|
||||||
|
|
||||||
本次设计遵循以下原则:
|
|
||||||
|
|
||||||
1. 复用现有 HotGo 分层、字典、审批、审计、权限和多租户能力。
|
|
||||||
2. 不修改已经投入使用的状态编号,只追加新状态或转换规则。
|
|
||||||
3. 客户端只提交业务意图,最终状态由服务端状态机决定。
|
|
||||||
4. 已生效资金不得修改或删除历史台账,只能生成反向流水冲正。
|
|
||||||
5. 历史内容和配置不得原地覆盖,回滚必须生成新的草稿版本。
|
|
||||||
6. 所有高风险执行都必须重新检查业务状态、审批状态和当前数据版本。
|
|
||||||
|
|
||||||
## 2. 实施范围
|
|
||||||
|
|
||||||
### 2.1 本期范围
|
|
||||||
|
|
||||||
- 会员状态合法转换和注销不可逆。
|
|
||||||
- 充值入账后的审批冲正。
|
|
||||||
- 任务佣金结算后的审批冲正。
|
|
||||||
- 文本内容归档和历史版本生成回滚草稿。
|
|
||||||
- 状态转换、重复执行、并发执行和资金一致性测试。
|
|
||||||
- 新增操作对应的菜单权限、业务审计和幂等保护。
|
|
||||||
|
|
||||||
### 2.2 不在本期范围
|
|
||||||
|
|
||||||
- 管理员 MFA 的真实认证流程。
|
|
||||||
- 支付渠道退款接口和外部清算实现。
|
|
||||||
- 新建独立的状态机管理页面。
|
|
||||||
- 修改 HotGo 原有管理员、角色、字典和个人设置模块。
|
|
||||||
- 直接修改 GoFrame CLI 生成的 `entity`、`do`、`dao/internal` 文件。
|
|
||||||
|
|
||||||
MFA 数据字段继续保留,但真实验证码、再认证凭证和会话升级机制后续单独设计开发。
|
|
||||||
|
|
||||||
## 3. 现状评估
|
|
||||||
|
|
||||||
| 领域 | 已有能力 | 本次缺口 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 会员 | 正常、禁用、注销;风险状态;双人审批;状态日志 | 未限制全部非法转换,注销后仍可能被旧审批恢复 |
|
|
||||||
| 钱包 | 可用余额、冻结余额、乐观锁、不可变台账、幂等键、`reversal_of` | 充值和任务佣金尚未提供完整冲正入口 |
|
|
||||||
| 充值 | 待支付、待审核、成功、驳回、过期、取消;审核入账 | 成功后无冲正状态、审批和执行流程 |
|
|
||||||
| 任务审核 | 待审核、通过、驳回、已结算、已冲正;佣金台账字段 | 已冲正仅有字典和字段,缺少业务实现 |
|
|
||||||
| 内容 | 草稿、待审、已发布、已下线、已归档;内容版本 | 缺少归档和历史版本生成回滚草稿接口 |
|
|
||||||
| 配置 | 草稿、审批、发布、版本、回滚草稿 | 已满足本章要求,本期不重做 |
|
|
||||||
| 审计 | Trace ID、前后摘要、哈希链、审批单号 | 新增流程需要补充结构化差异和冲正关联信息 |
|
|
||||||
|
|
||||||
## 4. 状态机设计
|
|
||||||
|
|
||||||
### 4.1 通用规则
|
|
||||||
|
|
||||||
每个状态变更必须依次执行:
|
|
||||||
|
|
||||||
1. 查询目标记录并加行锁。
|
|
||||||
2. 校验记录存在且属于当前租户。
|
|
||||||
3. 校验当前状态与申请时的 `fromStatus` 一致。
|
|
||||||
4. 校验 `fromStatus → toStatus` 在允许转换表中。
|
|
||||||
5. 校验审批已通过、尚未执行,且申请人与执行人符合职责分离要求。
|
|
||||||
6. 在同一事务内完成业务状态、台账、审批执行时间和审计记录更新。
|
|
||||||
7. 事务提交后再触发缓存清理、通知或 Outbox 事件。
|
|
||||||
|
|
||||||
状态转换判断统一放在后端,不接受前端直接指定任意结果状态。
|
|
||||||
|
|
||||||
### 4.2 会员状态
|
|
||||||
|
|
||||||
现有会员状态编号保持不变:
|
|
||||||
|
|
||||||
| 常量 | 值 | 含义 |
|
|
||||||
| --- | ---: | --- |
|
|
||||||
| `AppMemberStatusNormal` | 1 | 正常 |
|
|
||||||
| `AppMemberStatusDisabled` | 2 | 禁用 |
|
|
||||||
| `AppMemberStatusCancelled` | 3 | 已注销 |
|
|
||||||
|
|
||||||
允许转换:
|
|
||||||
|
|
||||||
| 当前状态 | 目标状态 | 是否允许 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 正常 | 禁用 | 是 | 必须审批 |
|
|
||||||
| 正常 | 注销 | 是 | 必须审批,执行后不可恢复 |
|
|
||||||
| 禁用 | 正常 | 是 | 必须审批 |
|
|
||||||
| 禁用 | 注销 | 是 | 必须审批 |
|
|
||||||
| 注销 | 任意状态 | 否 | 注销不可逆 |
|
|
||||||
| 任意状态 | 相同状态 | 否 | 防止无意义重复申请 |
|
|
||||||
|
|
||||||
需求中的“受限”继续由现有 `risk_status` 表达,不新增或重排会员主状态:
|
|
||||||
|
|
||||||
- `AppMemberRiskNormal`:正常。
|
|
||||||
- `AppMemberRiskWatch`:观察或限制部分能力。
|
|
||||||
- `AppMemberRiskBlocked`:拦截高风险能力。
|
|
||||||
|
|
||||||
发起状态审批时保存 `fromStatus`;执行时必须重新比对。如果会员状态已变化,则旧审批失效,不得覆盖最新状态。
|
|
||||||
|
|
||||||
### 4.3 充值状态
|
|
||||||
|
|
||||||
保留现有 1~6 状态,追加:
|
|
||||||
|
|
||||||
| 常量 | 值 | 含义 |
|
|
||||||
| --- | ---: | --- |
|
|
||||||
| `RechargeReversed` | 7 | 已冲正 |
|
|
||||||
|
|
||||||
核心转换:
|
|
||||||
|
|
||||||
| 当前状态 | 目标状态 | 触发方式 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 用户未支付 | 手动审核 | 支付凭证或支付结果进入审核 |
|
|
||||||
| 用户未支付 | 已过期/已取消 | 超时任务或用户取消 |
|
|
||||||
| 手动审核 | 已入账 | 审批通过并写入入账台账 |
|
|
||||||
| 手动审核 | 手动驳回 | 审批驳回 |
|
|
||||||
| 已入账 | 已冲正 | 冲正审批通过并生成反向台账 |
|
|
||||||
|
|
||||||
`已入账 → 已冲正` 是成功充值唯一允许的后续资金状态转换。已冲正记录不得再次冲正。
|
|
||||||
|
|
||||||
### 4.4 任务审核状态
|
|
||||||
|
|
||||||
保留现有状态编号:
|
|
||||||
|
|
||||||
| 常量 | 值 | 含义 |
|
|
||||||
| --- | ---: | --- |
|
|
||||||
| `TaskSubmissionPending` | 1 | 待审核 |
|
|
||||||
| `TaskSubmissionApproved` | 2 | 已通过 |
|
|
||||||
| `TaskSubmissionRejected` | 3 | 已驳回 |
|
|
||||||
| `TaskSubmissionSettled` | 4 | 已结算 |
|
|
||||||
| `TaskSubmissionReversed` | 5 | 已冲正 |
|
|
||||||
|
|
||||||
当前佣金为同步结算时,可在同一事务中完成“待审核 → 已通过 → 已结算”,数据库最终状态为“已结算”;若以后改为异步结算,“已通过”可作为中间状态。
|
|
||||||
|
|
||||||
允许转换:
|
|
||||||
|
|
||||||
| 当前状态 | 目标状态 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 待审核 | 已驳回 | 保存驳回原因和是否允许重提 |
|
|
||||||
| 待审核 | 已结算 | 审核通过并成功写入佣金台账 |
|
|
||||||
| 已结算 | 已冲正 | 冲正审批通过并写入反向台账 |
|
|
||||||
| 已驳回 | 其他状态 | 禁止;重新提交需生成新提交记录 |
|
|
||||||
| 已冲正 | 其他状态 | 禁止 |
|
|
||||||
|
|
||||||
### 4.5 内容状态
|
|
||||||
|
|
||||||
使用现有 `BizPublishStatusOptions`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
草稿 → 待审 → 已发布 → 已下线 → 已归档
|
|
||||||
```
|
|
||||||
|
|
||||||
规则:
|
|
||||||
|
|
||||||
- 只有草稿可以提交审核。
|
|
||||||
- 只有审批通过的版本可以发布。
|
|
||||||
- 只有已发布内容可以下线。
|
|
||||||
- 只有已下线内容可以归档。
|
|
||||||
- 已归档内容不可直接编辑、发布或恢复。
|
|
||||||
- 历史版本回滚不修改历史版本,而是复制为一个版本号更大的新草稿。
|
|
||||||
|
|
||||||
站点配置继续使用现有“历史版本 → 新回滚草稿 → 审批 → 发布”流程,不增加直接覆盖线上配置的接口。
|
|
||||||
|
|
||||||
## 5. 数据库变更
|
|
||||||
|
|
||||||
新增迁移文件:
|
|
||||||
|
|
||||||
```text
|
|
||||||
server/storage/data/migrations/20261008_009_state_machine_hardening.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.1 `hg_recharge_order`
|
|
||||||
|
|
||||||
| 字段 | 类型 | 默认值 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `reversal_approval_id` | bigint unsigned | 0 | 冲正审批单 ID |
|
|
||||||
| `reversal_ledger_id` | bigint unsigned | 0 | 冲正台账 ID |
|
|
||||||
| `reversed_at` | datetime(3) | NULL | 冲正执行时间 |
|
|
||||||
|
|
||||||
建议增加索引:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
KEY `idx_recharge_reversal_approval` (`tenant_id`,`reversal_approval_id`)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.2 `hg_task_submission`
|
|
||||||
|
|
||||||
保留已有 `reversal_approval_id`,新增:
|
|
||||||
|
|
||||||
| 字段 | 类型 | 默认值 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `reversal_ledger_id` | bigint unsigned | 0 | 佣金冲正台账 ID |
|
|
||||||
| `reversed_at` | datetime(3) | NULL | 冲正执行时间 |
|
|
||||||
|
|
||||||
建议增加索引:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
KEY `idx_task_submission_reversal` (`tenant_id`,`reversal_approval_id`)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.3 `hg_content_version`
|
|
||||||
|
|
||||||
为了保留回滚来源,新增:
|
|
||||||
|
|
||||||
| 字段 | 类型 | 默认值 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `base_version_id` | bigint unsigned | 0 | 新版本来源的历史版本 ID |
|
|
||||||
|
|
||||||
正常新增版本可为 0;通过回滚生成的新草稿必须保存来源版本 ID。
|
|
||||||
|
|
||||||
### 5.4 生成代码
|
|
||||||
|
|
||||||
迁移执行后,使用 GoFrame CLI 重新生成下列表对应的代码:
|
|
||||||
|
|
||||||
- `hg_recharge_order`
|
|
||||||
- `hg_task_submission`
|
|
||||||
- `hg_content_version`
|
|
||||||
|
|
||||||
生成范围包括 `entity`、`do`、`dao/internal` 和 `dao`,禁止手工修改生成文件。
|
|
||||||
|
|
||||||
## 6. 后端接口设计
|
|
||||||
|
|
||||||
### 6.1 会员状态
|
|
||||||
|
|
||||||
复用现有接口:
|
|
||||||
|
|
||||||
- `POST /appMember/statusRequest`
|
|
||||||
- `POST /appMember/statusExecute`
|
|
||||||
|
|
||||||
补强内容:
|
|
||||||
|
|
||||||
- `StatusRequest` 校验允许转换并写入申请时状态。
|
|
||||||
- `StatusExecute` 锁定会员记录后再次校验允许转换。
|
|
||||||
- 已注销会员禁止发起和执行任何恢复状态请求。
|
|
||||||
- 业务审计必须记录 `before.memberStatus` 和 `after.memberStatus`。
|
|
||||||
|
|
||||||
### 6.2 充值冲正
|
|
||||||
|
|
||||||
新增接口:
|
|
||||||
|
|
||||||
| 接口 | Method | 权限 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `/rechargeOrder/reversalRequest` | POST | `/rechargeOrder/reversalRequest` | 发起充值冲正审批 |
|
|
||||||
| `/rechargeOrder/reversalExecute` | POST | `/rechargeOrder/reversalExecute` | 执行已通过的充值冲正 |
|
|
||||||
|
|
||||||
申请参数至少包括:
|
|
||||||
|
|
||||||
- 充值单 ID。
|
|
||||||
- 标准原因编码。
|
|
||||||
- 补充说明。
|
|
||||||
- 幂等键。
|
|
||||||
- 证据附件或证据摘要,按现有 JSON 附件格式保存。
|
|
||||||
|
|
||||||
申请前置条件:
|
|
||||||
|
|
||||||
- 充值单状态为“已入账”。
|
|
||||||
- 存在原入账台账。
|
|
||||||
- 尚未发起或执行冲正。
|
|
||||||
- 原审批和入账结果有效。
|
|
||||||
|
|
||||||
执行必须在同一事务中:
|
|
||||||
|
|
||||||
1. 锁定审批单、充值单、钱包账户和原台账。
|
|
||||||
2. 校验审批已通过且未执行。
|
|
||||||
3. 校验充值单仍为“已入账”。
|
|
||||||
4. 校验原台账属于该充值单和该钱包。
|
|
||||||
5. 生成金额相同、方向相反的新台账,并设置 `reversal_of=原台账ID`。
|
|
||||||
6. 更新钱包余额和乐观锁版本,余额不得为负数。
|
|
||||||
7. 更新充值单为“已冲正”,保存冲正审批、台账和时间。
|
|
||||||
8. 标记审批已执行并写入业务审计。
|
|
||||||
|
|
||||||
### 6.3 任务佣金冲正
|
|
||||||
|
|
||||||
新增接口:
|
|
||||||
|
|
||||||
| 接口 | Method | 权限 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `/taskSubmission/reversalRequest` | POST | `/taskSubmission/reversalRequest` | 发起佣金冲正审批 |
|
|
||||||
| `/taskSubmission/reversalExecute` | POST | `/taskSubmission/reversalExecute` | 执行已通过的佣金冲正 |
|
|
||||||
|
|
||||||
申请前置条件:
|
|
||||||
|
|
||||||
- 提交记录状态为“已结算”。
|
|
||||||
- `ledger_id` 有效。
|
|
||||||
- 尚未发起或执行冲正。
|
|
||||||
- 必须填写标准原因和补充说明。
|
|
||||||
|
|
||||||
执行逻辑与充值冲正一致,但业务状态更新为 `TaskSubmissionReversed`,冲正流水指向佣金原流水。
|
|
||||||
|
|
||||||
### 6.4 内容归档与回滚
|
|
||||||
|
|
||||||
新增接口:
|
|
||||||
|
|
||||||
| 接口 | Method | 权限 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `/content/archive` | POST | `/content/archive` | 将已下线内容归档 |
|
|
||||||
| `/content/rollback` | POST | `/content/rollback` | 根据历史版本生成新草稿 |
|
|
||||||
|
|
||||||
归档规则:
|
|
||||||
|
|
||||||
- 当前内容必须为“已下线”。
|
|
||||||
- 归档后不可编辑或直接重新发布。
|
|
||||||
- 保存操作人、原因和审计记录。
|
|
||||||
|
|
||||||
回滚规则:
|
|
||||||
|
|
||||||
- 指定内容 ID 和历史版本 ID。
|
|
||||||
- 历史版本必须属于该内容。
|
|
||||||
- 新版本号为当前最大版本号加 1。
|
|
||||||
- 复制历史版本正文、摘要、封面和附件信息。
|
|
||||||
- 新版本状态为“草稿”,`base_version_id` 指向来源版本。
|
|
||||||
- 不修改当前线上版本和历史版本。
|
|
||||||
|
|
||||||
## 7. 后端代码影响范围
|
|
||||||
|
|
||||||
按 HotGo 分层补充以下内容:
|
|
||||||
|
|
||||||
| 层级 | 主要文件 |
|
|
||||||
| --- | --- |
|
|
||||||
| 常量与字典 | `server/internal/consts/trade.go`、`product_task.go`、`portal.go` |
|
|
||||||
| API 契约 | `server/api/admin/rechargeorder/`、`tasksubmission/`、`portal/` |
|
|
||||||
| Controller | `server/internal/controller/admin/sys/` 对应薄控制器 |
|
|
||||||
| Service | 在 `server/internal/service/sys.go` 的现有接口中追加方法 |
|
|
||||||
| Input | `server/internal/model/input/sysin/` 对应模块文件 |
|
|
||||||
| Logic | `app_member.go`、`recharge_order.go`、`task_submission.go`、`portal.go` |
|
|
||||||
| 路由 | 复用现有模块控制器注册,无需新增一级菜单 |
|
|
||||||
| 迁移 | `20261008_009_state_machine_hardening.sql` |
|
|
||||||
|
|
||||||
状态值合法性通过后端字典校验;字段名使用 `dao.Xxx.Columns()`,禁止在 Logic 中硬编码数据库列名。
|
|
||||||
|
|
||||||
## 8. 前端设计
|
|
||||||
|
|
||||||
不增加一级菜单,只在现有页面增加操作入口。
|
|
||||||
|
|
||||||
### 8.1 充值管理
|
|
||||||
|
|
||||||
- 状态为“已入账”且拥有申请权限时显示“申请冲正”。
|
|
||||||
- 已存在冲正审批时显示审批状态,不允许重复申请。
|
|
||||||
- 审批通过且拥有执行权限时显示“执行冲正”。
|
|
||||||
- 已冲正记录显示原台账和冲正台账关联信息。
|
|
||||||
|
|
||||||
### 8.2 会员任务审核
|
|
||||||
|
|
||||||
- 状态为“已结算”时显示“申请冲正”。
|
|
||||||
- 申请弹窗包含原因字典、补充说明和证据。
|
|
||||||
- 审批通过后由有执行权限的管理员执行。
|
|
||||||
- 状态为“已冲正”后不再显示审核或冲正按钮。
|
|
||||||
|
|
||||||
### 8.3 文本管理
|
|
||||||
|
|
||||||
- 已下线内容显示“归档”。
|
|
||||||
- 历史版本列表显示“生成回滚草稿”。
|
|
||||||
- 回滚前明确提示“不会覆盖当前线上版本”。
|
|
||||||
- 已归档内容的编辑和发布按钮禁用。
|
|
||||||
|
|
||||||
前端继续使用 Naive UI、`BasicTable`、`BasicForm`、`BasicModal` 和 `http.request`,状态标签通过后端字典渲染。
|
|
||||||
|
|
||||||
## 9. 权限设计
|
|
||||||
|
|
||||||
新增操作权限:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/rechargeOrder/reversalRequest
|
|
||||||
/rechargeOrder/reversalExecute
|
|
||||||
/taskSubmission/reversalRequest
|
|
||||||
/taskSubmission/reversalExecute
|
|
||||||
/content/archive
|
|
||||||
/content/rollback
|
|
||||||
```
|
|
||||||
|
|
||||||
权限规则:
|
|
||||||
|
|
||||||
- 申请权限和执行权限分离。
|
|
||||||
- 申请人不得审批或执行自己的高风险申请。
|
|
||||||
- 执行接口必须独立校验权限,不能只依赖前端按钮隐藏。
|
|
||||||
- 新权限通过 `hg_admin_menu` 的按钮类型记录配置,并授权给管理角色和业务角色。
|
|
||||||
|
|
||||||
## 10. 台账、幂等与审计
|
|
||||||
|
|
||||||
### 10.1 台账要求
|
|
||||||
|
|
||||||
- 原台账不可更新和删除。
|
|
||||||
- 冲正台账金额必须等于原台账金额。
|
|
||||||
- 冲正台账方向必须与原台账相反。
|
|
||||||
- `reversal_of` 必须指向原台账 ID。
|
|
||||||
- 同一原台账只能存在一条有效冲正台账。
|
|
||||||
- 钱包变更后必须满足 `after_amount = before_amount ± amount`。
|
|
||||||
- 可用余额和冻结余额不得小于 0。
|
|
||||||
|
|
||||||
### 10.2 幂等要求
|
|
||||||
|
|
||||||
- 申请接口使用调用方传入的幂等键。
|
|
||||||
- 执行接口以审批单 ID 和业务单 ID 共同保证幂等。
|
|
||||||
- 重复执行已完成审批时返回清晰业务错误,不重复写钱包和台账。
|
|
||||||
- 数据库唯一索引冲突必须转换为用户可理解的业务错误。
|
|
||||||
|
|
||||||
### 10.3 审计要求
|
|
||||||
|
|
||||||
业务审计至少记录:
|
|
||||||
|
|
||||||
- 模块和动作。
|
|
||||||
- 操作人、目标类型和目标 ID。
|
|
||||||
- 原状态和目标状态。
|
|
||||||
- 原台账 ID 和冲正台账 ID。
|
|
||||||
- 冲正金额、原因和证据摘要。
|
|
||||||
- 审批单号和 Trace ID。
|
|
||||||
- 变更前后摘要与结构化差异。
|
|
||||||
|
|
||||||
## 11. 异常与并发处理
|
|
||||||
|
|
||||||
| 场景 | 处理要求 |
|
|
||||||
| --- | --- |
|
|
||||||
| 重复点击执行 | 只允许第一次成功,后续返回“审批已执行” |
|
|
||||||
| 两个管理员同时执行 | 通过事务行锁保证只有一个事务成功 |
|
|
||||||
| 审批后业务状态变化 | 拒绝执行,要求重新发起审批 |
|
|
||||||
| 钱包余额不足以冲正 | 整体回滚,不产生台账和状态变化 |
|
|
||||||
| 原台账不存在或归属不符 | 拒绝执行并记录 Warning 日志 |
|
|
||||||
| 审批通过但事务失败 | 审批保持未执行,可排查后重试 |
|
|
||||||
| 审计写入失败 | 核心事务整体回滚 |
|
|
||||||
| 通知发送失败 | 不回滚核心事务,记录 Warning 并通过队列重试 |
|
|
||||||
|
|
||||||
## 12. 测试方案
|
|
||||||
|
|
||||||
### 12.1 状态机测试
|
|
||||||
|
|
||||||
每个状态机都要覆盖:
|
|
||||||
|
|
||||||
- 所有允许转换成功。
|
|
||||||
- 所有禁止转换失败。
|
|
||||||
- 相同状态重复申请失败。
|
|
||||||
- 注销会员恢复失败。
|
|
||||||
- 申请后状态变化导致执行失败。
|
|
||||||
- 已执行审批重复执行失败。
|
|
||||||
|
|
||||||
### 12.2 资金测试
|
|
||||||
|
|
||||||
- 充值入账冲正后余额正确。
|
|
||||||
- 任务佣金冲正后余额正确。
|
|
||||||
- 原台账保持不变。
|
|
||||||
- 冲正台账方向、金额和 `reversal_of` 正确。
|
|
||||||
- 幂等键重复提交不产生重复台账。
|
|
||||||
- 两个并发执行请求只生成一条冲正台账。
|
|
||||||
- 余额不足时业务状态、钱包和台账均不变化。
|
|
||||||
- 审计日志、审批单和台账可以相互追溯。
|
|
||||||
|
|
||||||
### 12.3 内容测试
|
|
||||||
|
|
||||||
- 只有已下线内容可以归档。
|
|
||||||
- 已归档内容不可编辑和发布。
|
|
||||||
- 历史版本回滚生成新草稿。
|
|
||||||
- 回滚不改变当前发布版本。
|
|
||||||
- 新草稿的 `base_version_id`、版本号和内容正确。
|
|
||||||
|
|
||||||
### 12.4 回归测试
|
|
||||||
|
|
||||||
- 原充值审核、提现审核和任务审核流程不受影响。
|
|
||||||
- 原会员禁用和恢复流程仍可使用。
|
|
||||||
- 原站点配置版本与回滚流程不受影响。
|
|
||||||
- 字典加载、权限菜单和审计列表正常。
|
|
||||||
|
|
||||||
## 13. 验收标准
|
|
||||||
|
|
||||||
满足以下条件后视为第 12 章补强完成:
|
|
||||||
|
|
||||||
1. 注销会员无法通过任何后台状态接口恢复。
|
|
||||||
2. 充值成功后只能通过审批冲正,不允许直接修改余额或原台账。
|
|
||||||
3. 已结算任务佣金可以通过审批冲正,且不可重复冲正。
|
|
||||||
4. 每次冲正都能从业务单追溯到原台账、冲正台账、审批单和审计记录。
|
|
||||||
5. 已下线内容可以归档,历史版本可以生成新草稿且不覆盖线上数据。
|
|
||||||
6. 所有新增接口具有后端权限校验和明确的中文业务错误。
|
|
||||||
7. 非法转换、重复执行、并发执行和余额不足测试全部通过。
|
|
||||||
8. 后端编译、前端类型检查和现有模块回归测试通过。
|
|
||||||
|
|
||||||
## 14. 推荐实施顺序
|
|
||||||
|
|
||||||
1. 新增数据库迁移并用 GoFrame CLI 重新生成模型和 DAO。
|
|
||||||
2. 补充状态字典和统一转换判断。
|
|
||||||
3. 修复会员状态申请与执行校验。
|
|
||||||
4. 实现充值冲正申请与执行。
|
|
||||||
5. 实现任务佣金冲正申请与执行。
|
|
||||||
6. 实现内容归档和历史版本回滚草稿。
|
|
||||||
7. 增加按钮权限和角色授权。
|
|
||||||
8. 增加前端操作按钮、弹窗和状态展示。
|
|
||||||
9. 完成状态机、资金并发和回归测试。
|
|
||||||
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
## 目录
|
|
||||||
|
|
||||||
#### 介绍安装
|
|
||||||
|
|
||||||
- [系统介绍](../../README.md)
|
|
||||||
- [环境搭建](start-environment.md)
|
|
||||||
- [系统安装](start-installation.md)
|
|
||||||
- [生产部署](start-deploy.md)
|
|
||||||
- [如何提问](start-questions.md)
|
|
||||||
- [常见问题](start-issue.md)
|
|
||||||
- [更新历史](start-update-log.md)
|
|
||||||
|
|
||||||
|
|
||||||
#### 系统开发
|
|
||||||
|
|
||||||
- [目录结构](sys-catalog.md)
|
|
||||||
- [开发规范](sys-exploit.md)
|
|
||||||
- [控制台](sys-console.md)
|
|
||||||
- [中间件/拦截器](sys-middleware.md)
|
|
||||||
- [WebHook](sys-webhook.md)
|
|
||||||
- [权限控制](sys-auth.md)
|
|
||||||
- [支付网关](sys-payment.md)
|
|
||||||
- [定时任务](sys-cron.md)
|
|
||||||
- [消息队列](sys-queue.md)
|
|
||||||
- [功能扩展库](sys-library.md)
|
|
||||||
- [工具方法](sys-utility.md)
|
|
||||||
- [WebSocket服务器](sys-websocket-server.md)
|
|
||||||
- [TCP服务器](sys-tcp-server.md)
|
|
||||||
- [SaaS多租户](sys-tenant.md)
|
|
||||||
- [国际化](sys-i18n.md)
|
|
||||||
- [单元测试](sys-test.md)
|
|
||||||
|
|
||||||
|
|
||||||
#### 插件模块开发
|
|
||||||
|
|
||||||
- [模块介绍及目录](addon-introduce-catalog.md)
|
|
||||||
- [模块开发流程](addon-flow.md)
|
|
||||||
- [模块辅助说明](addon-helper.md)
|
|
||||||
|
|
||||||
|
|
||||||
#### 生成代码
|
|
||||||
- [使用前提](code-start.md)
|
|
||||||
- [数据库](sys-db.md)
|
|
||||||
- [生成配置](code-config.md)
|
|
||||||
- [生成CURD](code-curd.md)
|
|
||||||
- [生成关联表CURD](code-curd-join.md)
|
|
||||||
- [生成树型CURD](code-tree.md)
|
|
||||||
- [生成业务模板](code-business.md)
|
|
||||||
- [生成模板开发](code-template-dev.md)
|
|
||||||
- [生成常见问题](code-help.md)
|
|
||||||
|
|
||||||
|
|
||||||
### 前端开发
|
|
||||||
- [表单组件](web-form.md)
|
|
||||||
- [WebSocket客户端](sys-websocket-client.md)
|
|
||||||
- [独立部署](web-deploy.md)
|
|
||||||
|
|
||||||
|
|
||||||
#### 附录
|
|
||||||
- [网址收录](append-website.md)
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
## 模块开发流程
|
|
||||||
|
|
||||||
目录
|
|
||||||
|
|
||||||
- 创建新插件
|
|
||||||
- 开发
|
|
||||||
- 调用主模块服务接口
|
|
||||||
- 访问路径
|
|
||||||
- 数据迁移
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 创建新插件
|
|
||||||
|
|
||||||
1、HotGo 后台进入 开发工具->插件管理->找到创建新插件,根据引导进行创建即可。
|
|
||||||
|
|
||||||
```shell
|
|
||||||
创建成功后默认情况下会在以下目录中生成插件文件,假设新生成的插件名为:hgexample
|
|
||||||
|
|
||||||
1. /server/addons/hgexample/ # 插件模块目录
|
|
||||||
2. /server/addons/modules/hgexample.go # 隐式注册插件文件
|
|
||||||
3. /server/resource/addons/hgexample # 静态资源和页面模板目录,属于扩展功能选项,勾选对应选项后才会生成
|
|
||||||
4. /web/src/api/addons/hgexample # webApi目录
|
|
||||||
5. /web/src/views/addons/hgexample # web页面目录
|
|
||||||
|
|
||||||
# 默认情况下没有为web页面生成菜单权限,因为在实际场景中插件不一定需要用到web页面,所以如有需要请手动到后台 权限管理 -> 菜单权限->自行添加菜单和配置权限
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
2、创建插件完毕重启服务端后,插件管理中会出现你新创建的插件信息。操作栏有几个按钮,在此进行说明
|
|
||||||
- 安装:会自动执行 server/hgexample/main.go 文件中的Install方法,方法中的具体逻辑默认为空,可以根据实际情况自行配置。如生成后台菜单、生成插件配置表初始化数据、迁移home页面、web项目文件等。
|
|
||||||
```go
|
|
||||||
// Install 安装模块
|
|
||||||
func (m *module) Install(ctx context.Context) (err error) {
|
|
||||||
// ...
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- 更新:会自动执行 server/hgexample/main.go 文件中的Upgrade方法,方法中的具体逻辑默认为空,可以根据实际情况自行配置。
|
|
||||||
```go
|
|
||||||
// Upgrade 更新模块
|
|
||||||
func (m *module) Upgrade(ctx context.Context) (err error) {
|
|
||||||
// ...
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- 卸载:会自动执行 server/hgexample/main.go 文件中的UnInstall方法,方法中的具体逻辑默认为空,可以根据实际情况自行配置。如会清除所有的数据表和已安装的信息等。
|
|
||||||
```go
|
|
||||||
// UnInstall 卸载模块
|
|
||||||
func (m *module) UnInstall(ctx context.Context) (err error) {
|
|
||||||
// ...
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 开发
|
|
||||||
|
|
||||||
完全可以根据HotGo正常的开发流程去开发对应的API、控制器、业务逻辑、插件内的应用
|
|
||||||
|
|
||||||
### 调用主模块服务接口
|
|
||||||
|
|
||||||
这里推荐的方式是在插件input层新建一个结构,继承主模块中的input结构。这样做的目的是为了服务与服务之间的输入/输出关系解耦,便于参数扩展和避免插件模块下使用`gf gen service`时出现`import cycle not allowed`。
|
|
||||||
|
|
||||||
一个简单的例子:
|
|
||||||
> 假设hgexample插件模块要通过主模块的服务接口更新插件配置
|
|
||||||
|
|
||||||
插件模块input:\server\addons\hgexample\model\input\sysin\config.go
|
|
||||||
```go
|
|
||||||
package sysin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"hotgo/internal/model/input/sysin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpdateConfigInp 更新指定配置
|
|
||||||
type UpdateConfigInp struct {
|
|
||||||
sysin.UpdateAddonsConfigInp
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
插件模块业务逻辑:\server\addons\hgexample\logic\sys\config.go
|
|
||||||
```go
|
|
||||||
package sys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"hotgo/addons/hgexample/global"
|
|
||||||
"hotgo/addons/hgexample/model/input/sysin"
|
|
||||||
"hotgo/addons/hgexample/service"
|
|
||||||
isc "hotgo/internal/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
type sSysConfig struct{}
|
|
||||||
|
|
||||||
func NewSysConfig() *sSysConfig {
|
|
||||||
return &sSysConfig{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
service.RegisterSysConfig(NewSysConfig())
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateConfigByGroup 更新指定分组的配置
|
|
||||||
func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error {
|
|
||||||
in.UpdateAddonsConfigInp.AddonName = global.GetSkeleton().Name
|
|
||||||
return isc.SysAddonsConfig().UpdateConfigByGroup(ctx, in.UpdateAddonsConfigInp)
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
主模块input:\server\internal\model\input\sysin\addons_config.go
|
|
||||||
```go
|
|
||||||
package sysin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpdateAddonsConfigInp 更新指定插件的配置
|
|
||||||
type UpdateAddonsConfigInp struct {
|
|
||||||
AddonName string `json:"addonName"`
|
|
||||||
Group string `json:"group"`
|
|
||||||
List g.Map `json:"list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
主模块业务逻辑:\server\internal\logic\sys\addons_config.go
|
|
||||||
```go
|
|
||||||
package sys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"hotgo/internal/model/input/sysin"
|
|
||||||
"hotgo/internal/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
type sSysAddonsConfig struct{}
|
|
||||||
|
|
||||||
func NewSysAddonsConfig() *sSysAddonsConfig {
|
|
||||||
return &sSysAddonsConfig{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
service.RegisterSysAddonsConfig(NewSysAddonsConfig())
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateConfigByGroup 更新指定分组的配置
|
|
||||||
func (s *sSysAddonsConfig) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateAddonsConfigInp) error {
|
|
||||||
// ...
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 访问路径
|
|
||||||
|
|
||||||
#### 后台插件访问路径
|
|
||||||
|
|
||||||
```
|
|
||||||
// IP+端口或域名/admin/插件名称/API路径
|
|
||||||
如:127.0.0.1:8000/admin/hgexample/index/test
|
|
||||||
```
|
|
||||||
|
|
||||||
- 对应控制器路径:`server/addons/hgexample/controller/admin/sys/index.go`
|
|
||||||
|
|
||||||
#### 前端API插件访问路径
|
|
||||||
|
|
||||||
```
|
|
||||||
// IP+端口或域名/api/插件名称/API路径
|
|
||||||
如:127.0.0.1:8000/api/hgexample/index/test
|
|
||||||
```
|
|
||||||
|
|
||||||
- 对应控制器路径:`server/addons/hgexample/controller/api/index.go`
|
|
||||||
|
|
||||||
#### 前台页面插件访问路径
|
|
||||||
|
|
||||||
```
|
|
||||||
// IP+端口或域名/home/插件名称/API路径
|
|
||||||
如:127.0.0.1:8000/home/hgexample/index/test
|
|
||||||
```
|
|
||||||
|
|
||||||
- 对应控制器路径:`server/addons/hgexample/controller/home/index.go`
|
|
||||||
- 对应模板路径:`server/addons/hgexample/resource/public/template`
|
|
||||||
|
|
||||||
#### 静态资源插件访问路径
|
|
||||||
|
|
||||||
```
|
|
||||||
// IP+端口或域名/home/插件名称/API路径
|
|
||||||
如:127.0.0.1:8000/addons/hgexample/default
|
|
||||||
```
|
|
||||||
|
|
||||||
- 对应资源路径:`server/addons/hgexample/resource/public`
|
|
||||||
|
|
||||||
|
|
||||||
#### Websocket插件访问路径
|
|
||||||
|
|
||||||
```
|
|
||||||
// IP+端口或域名/socket/插件名称/API路径
|
|
||||||
如:127.0.0.1:8000/socket/hgexample/index/test
|
|
||||||
```
|
|
||||||
|
|
||||||
- 对应控制器路径:`server/addons/hgexample/controller/socket/index.go`
|
|
||||||
|
|
||||||
|
|
||||||
### 数据迁移
|
|
||||||
|
|
||||||
- 可以将数据迁移逻辑写进server/xxx插件/main.go 文件中的Install方法中,并遵循系统规范进行数据安装
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
## 模块辅助说明
|
|
||||||
|
|
||||||
目录
|
|
||||||
|
|
||||||
- 模块结构
|
|
||||||
- 获取模块信息
|
|
||||||
- 插件路由规则
|
|
||||||
|
|
||||||
|
|
||||||
#### 模块结构
|
|
||||||
- 文件路径:server/internal/library/addons/module.go
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Skeleton 模块骨架
|
|
||||||
type Skeleton struct {
|
|
||||||
Label string `json:"label"` // 标识
|
|
||||||
Name string `json:"name"` // 名称
|
|
||||||
Group int `json:"group"` // 分组
|
|
||||||
Logo string `json:"logo"` // logo
|
|
||||||
Brief string `json:"brief"` // 简介
|
|
||||||
Description string `json:"description"` // 详细描述
|
|
||||||
Author string `json:"author"` // 作者
|
|
||||||
Version string `json:"version"` // 版本号
|
|
||||||
RootPath string `json:"rootPath"` // 根路径
|
|
||||||
View *gview.View `json:"view"` // 模板引擎
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Skeleton) GetModule() Module {
|
|
||||||
return GetModule(s.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module 插件模块
|
|
||||||
type Module interface {
|
|
||||||
Start(option *Option) (err error) // 启动模块
|
|
||||||
Stop() (err error) // 停止模块
|
|
||||||
Ctx() context.Context // 上下文
|
|
||||||
GetSkeleton() *Skeleton // 获取模块
|
|
||||||
Install(ctx context.Context) (err error) // 安装模块
|
|
||||||
Upgrade(ctx context.Context) (err error) // 更新模块
|
|
||||||
UnInstall(ctx context.Context) (err error) // 卸载模块
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 获取模块信息
|
|
||||||
|
|
||||||
- 在插件模块内
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"hotgo/addons/hgexample/global"
|
|
||||||
)
|
|
||||||
|
|
||||||
func test() {
|
|
||||||
fmt.Printf("当前插件模块是:%+v", global.GetSkeleton())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- 在插件模块外
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"hotgo/internal/library/addons"
|
|
||||||
"hotgo/internal/library/contexts"
|
|
||||||
)
|
|
||||||
|
|
||||||
func test(ctx context.Context) {
|
|
||||||
fmt.Printf("当前是否为插件请求:%v", contexts.IsAddonRequest(ctx))
|
|
||||||
if contexts.IsAddonRequest(ctx) {
|
|
||||||
fmt.Printf("当前插件名称:%v", contexts.GetAddonName(ctx))
|
|
||||||
fmt.Printf("当前插件信息:%v", addons.GetModule(contexts.GetAddonName(ctx)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- 更多辅助方法请参考插件功能库:server/internal/library/addons
|
|
||||||
|
|
||||||
#### 插件路由规则
|
|
||||||
- 如果你不喜欢现在的路由风格,可以自行调整。修改位置在:\server\internal\library\addons\addons.go的RouterPrefix方法。
|
|
||||||
- 注意调整后如web前端页面中如有之前的路由风格也需同步修改。
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
## 模块介绍及目录
|
|
||||||
|
|
||||||
目录
|
|
||||||
|
|
||||||
- 模块介绍
|
|
||||||
- 启动流程
|
|
||||||
- 目录结构
|
|
||||||
|
|
||||||
### 模块介绍
|
|
||||||
|
|
||||||
> 定位:开发独立、临时性、工具类型的功能时推荐使用插件化开发,例如:小游戏(大转盘/消消乐/抽奖/大屏互动/红包等)、小插件(广告管理/文章管理/友情链接等等)、小模块(报名/投票/签到)、小程序、大型插件微商城等等。
|
|
||||||
|
|
||||||
> 插件模块方便多项目复用,同时完美支持多人协同开发,每个插件模块都有独立的微架构目录结构,多插件之间完全隔离。
|
|
||||||
|
|
||||||
### 启动流程
|
|
||||||
|
|
||||||
HotGo 入口文件->隐式注入(hotgo/addons/modules)->注册所有插件->初始化已安装的插件->写入路由组->根据 HotGo 正常的开发和访问流程去开发访问插件
|
|
||||||
|
|
||||||
|
|
||||||
### 目录结构
|
|
||||||
- 详细介绍请参考:[目录结构](sys-catalog.md)
|
|
||||||
```
|
|
||||||
/server
|
|
||||||
├── addons
|
|
||||||
│ ├── modules
|
|
||||||
│ ├── xxx插件
|
|
||||||
│ | ├── api
|
|
||||||
│ | ├── consts
|
|
||||||
│ | ├── controller
|
|
||||||
│ | ├── crons
|
|
||||||
│ | ├── global
|
|
||||||
│ | ├── logic
|
|
||||||
│ | ├── model
|
|
||||||
│ | ├── queues
|
|
||||||
│ | ├── resource
|
|
||||||
│ | ├── router
|
|
||||||
│ | ├── service
|
|
||||||
│ | ├── main.go
|
|
||||||
│ | └── README.md
|
|
||||||
```
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
目录
|
|
||||||
|
|
||||||
- 框架文档
|
|
||||||
- [goframe](https://goframe.org/pages/viewpage.action?pageId=1114119)
|
|
||||||
- [naiveui](https://www.naiveui.com)
|
|
||||||
- [naive-ui-admin](https://docs.naiveadmin.com/)
|
|
||||||
|
|
||||||
|
|
||||||
- 常用组件
|
|
||||||
- [websocket](https://github.com/gorilla/websocket)
|
|
||||||
- [casbin](https://github.com/casbin/casbin)
|
|
||||||
- [tailwind](https://tailwind.docs.73zls.com/docs/flex-direction)
|
|
||||||
|
|
||||||
|
|
||||||
- 系统通用
|
|
||||||
- [redis](https://redis.io/)
|
|
||||||
|
|
||||||
|
|
||||||
- 其他
|
|
||||||
- [awesome-go](https://github.com/avelino/awesome-go)
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
## 生成业务模板
|
|
||||||
|
|
||||||
根据`api`接口文件一键生成业务模板:api、controller、logic、service
|
|
||||||
|
|
||||||
待写。
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
## 生成配置
|
|
||||||
|
|
||||||
目录
|
|
||||||
|
|
||||||
- 模板配置
|
|
||||||
- CLI配置
|
|
||||||
- 多数据库使用
|
|
||||||
|
|
||||||
### 模板配置
|
|
||||||
|
|
||||||
- 配置路径:server/manifest/config/config.yaml
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# 生成代码
|
|
||||||
hggen:
|
|
||||||
allowedIPs: [ "127.0.0.1", "*" ] # 白名单,*代表所有,只有允许的IP后台才能使用生成代码功能
|
|
||||||
selectDbs: [ "default" ] # 可选生成表的数据库配置名称,支持多库
|
|
||||||
disableTables: [ "hg_sys_gen_codes","hg_admin_role_casbin" ] # 禁用的表,禁用以后将不会在选择表中看到
|
|
||||||
delimiters: [ "@{", "}" ] # 模板引擎变量分隔符号
|
|
||||||
# 生成应用模型,所有生成模板允许自定义,可以参考default模板进行改造
|
|
||||||
application:
|
|
||||||
# CRUD和关系树列表模板
|
|
||||||
crud:
|
|
||||||
templates:
|
|
||||||
# 默认的主包模板
|
|
||||||
- group: "default" # 分组名称
|
|
||||||
isAddon: false # 是否为插件模板 false|true
|
|
||||||
masterPackage: "sys" # 主包名称,需和controllerPath、logicPath、inputPath保持关联
|
|
||||||
templatePath: "./resource/generate/default/curd" # 模板路径
|
|
||||||
apiPath: "./api/admin" # goApi生成路径
|
|
||||||
controllerPath: "./internal/controller/admin/sys" # 控制器生成路径
|
|
||||||
logicPath: "./internal/logic/sys" # 主要业务生成路径
|
|
||||||
inputPath: "./internal/model/input/sysin" # 表单过滤器生成路径
|
|
||||||
routerPath: "./internal/router/genrouter" # 生成路由表路径
|
|
||||||
sqlPath: "./storage/data/generate" # 生成sql语句路径
|
|
||||||
webApiPath: "../web/src/api" # webApi生成路径
|
|
||||||
webViewsPath: "../web/src/views" # web页面生成路径
|
|
||||||
|
|
||||||
# 默认的插件包模板,{$name}会自动替换成实际的插件名称
|
|
||||||
- group: "addon" # 分组名称
|
|
||||||
isAddon: true # 是否为插件模板 false|true
|
|
||||||
masterPackage: "sys" # 主包名称,需和controllerPath、logicPath、inputPath保持关联
|
|
||||||
templatePath: "./resource/generate/default/curd" # 模板路径
|
|
||||||
apiPath: "./addons/{$name}/api/admin" # goApi生成路径
|
|
||||||
controllerPath: "./addons/{$name}/controller/admin/sys" # 控制器生成路径
|
|
||||||
logicPath: "./addons/{$name}/logic/sys" # 主要业务生成路径
|
|
||||||
inputPath: "./addons/{$name}/model/input/sysin" # 表单过滤器生成路径
|
|
||||||
routerPath: "./addons/{$name}/router/genrouter" # 生成路由表路径
|
|
||||||
sqlPath: "./storage/data/generate/addons" # 生成sql语句路径
|
|
||||||
webApiPath: "../web/src/api/addons/{$name}" # webApi生成路径
|
|
||||||
webViewsPath: "../web/src/views/addons/{$name}" # web页面生成路径
|
|
||||||
|
|
||||||
# 消息队列模板
|
|
||||||
queue:
|
|
||||||
templates:
|
|
||||||
- group: "default"
|
|
||||||
templatePath: "./resource/generate/default/queue"
|
|
||||||
|
|
||||||
# 定时任务模板
|
|
||||||
cron:
|
|
||||||
templates:
|
|
||||||
- group: "default"
|
|
||||||
templatePath: "./resource/generate/default/cron"
|
|
||||||
|
|
||||||
# 生成插件模块,通过后台创建新插件时使用的模板,允许自定义,可以参考default模板进行改造
|
|
||||||
addon:
|
|
||||||
srcPath: "./resource/generate/default/addon" # 生成模板路径
|
|
||||||
webApiPath: "../web/src/api/addons/{$name}" # webApi生成路径
|
|
||||||
webViewsPath: "../web/src/views/addons/{$name}" # web页面生成路径
|
|
||||||
```
|
|
||||||
|
|
||||||
### CLI配置
|
|
||||||
|
|
||||||
- hotgo在生成dao、service配置时,默认了和gf官方一致的配置方式和代码生成规则。所以无论你是通过hotgo亦或gf命令生成,最终代码格式完全一致,遵循一致的代码规范。
|
|
||||||
|
|
||||||
- 配置路径:[server/hack/config.yaml](../../server/hack/config.yaml)
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
gfcli:
|
|
||||||
build:
|
|
||||||
name: "hotgo" # 编译后的可执行文件名称
|
|
||||||
# arch: "all" #不填默认当前系统架构,可选:386,amd64,arm,all
|
|
||||||
# system: "all" #不填默认当前系统平台,可选:linux,darwin,windows,all
|
|
||||||
mod: "none"
|
|
||||||
cgo: 0
|
|
||||||
packSrc: "resource" # 将resource目录打包进可执行文件,静态资源无需单独部署
|
|
||||||
packDst: "internal/packed/packed.go" # 打包后生成的Go文件路径,一般使用相对路径指定到本项目目录中
|
|
||||||
version: ""
|
|
||||||
output: "./temp/hotgo" # 可执行文件生成路径
|
|
||||||
extra: ""
|
|
||||||
|
|
||||||
gen:
|
|
||||||
dao:
|
|
||||||
- link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true"
|
|
||||||
# - link: "pgsql:postgres:hg123456@tcp(127.0.0.1:5432)/hotgo"
|
|
||||||
group: "default" # 分组 使用hotgo代码生成功能时必须填
|
|
||||||
# tables: "" # 指定当前数据库中需要执行代码生成的数据表。如果为空,表示数据库的所有表都会生成。
|
|
||||||
tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。
|
|
||||||
removePrefix: "hg_"
|
|
||||||
descriptionTag: true
|
|
||||||
noModelComment: true
|
|
||||||
jsonCase: "CamelLower"
|
|
||||||
gJsonSupport: true
|
|
||||||
clear: true
|
|
||||||
|
|
||||||
service: # 生成业务配置
|
|
||||||
srcFolder: "internal/logic"
|
|
||||||
dstFolder: "internal/service"
|
|
||||||
dstFileNameCase: "CamelLower"
|
|
||||||
clear: true
|
|
||||||
```
|
|
||||||
|
|
||||||
### 多数据库使用
|
|
||||||
|
|
||||||
- 假设我们要增加一个库名为`hotgo2`、分组为`default2`的数据库,并要为其生成代码
|
|
||||||
|
|
||||||
1. 配置[server/hack/config.yaml](../../server/hack/config.yaml) 如下:
|
|
||||||
```yaml
|
|
||||||
gen:
|
|
||||||
dao:
|
|
||||||
- link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true"
|
|
||||||
group: "default" # 分组 使用hotgo代码生成功能时必须填
|
|
||||||
tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。
|
|
||||||
removePrefix: "hg_"
|
|
||||||
descriptionTag: true
|
|
||||||
noModelComment: true
|
|
||||||
jsonCase: "CamelLower"
|
|
||||||
gJsonSupport: true
|
|
||||||
clear: false
|
|
||||||
- link: "mysql:hotgo2:hg123456.@tcp(127.0.0.1:3306)/hotgo2?loc=Local&parseTime=true"
|
|
||||||
group: "default2" # 分组 使用hotgo代码生成功能时必须填
|
|
||||||
tablesEx: "hg_sys_addons_install" # 指定当前数据库中需要排除代码生成的数据表。
|
|
||||||
removePrefix: ""
|
|
||||||
descriptionTag: true
|
|
||||||
noModelComment: true
|
|
||||||
jsonCase: "CamelLower"
|
|
||||||
gJsonSupport: true
|
|
||||||
clear: false
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 配置`server/manifest/config/config.yaml`,
|
|
||||||
|
|
||||||
`database`配置如下:
|
|
||||||
```yaml
|
|
||||||
database:
|
|
||||||
logger:
|
|
||||||
level: "all"
|
|
||||||
stdout: true
|
|
||||||
default:
|
|
||||||
link: "mysql:hotgo:hg123456.@tcp(127.0.0.1:3306)/hotgo?loc=Local&parseTime=true"
|
|
||||||
# link: "pgsql:postgres:hg123456@tcp(127.0.0.1:5432)/hotgo"
|
|
||||||
debug: true
|
|
||||||
Prefix: "hg_"
|
|
||||||
default2:
|
|
||||||
link: "mysql:hotgo2:hg123456.@tcp(127.0.0.1:3306)/hotgo2?loc=Local&parseTime=true"
|
|
||||||
debug: true
|
|
||||||
Prefix: ""
|
|
||||||
```
|
|
||||||
|
|
||||||
`hggen`配置如下:
|
|
||||||
```yaml
|
|
||||||
hggen:
|
|
||||||
allowedIPs: ["127.0.0.1", "*"] # 白名单,*代表所有,只有允许的IP后台才能使用生成代码功能
|
|
||||||
selectDbs: [ "default", "default2" ] # 可选生成表的数据库配置名称,支持多库
|
|
||||||
disableTables : ["hg_sys_gen_codes","hg_admin_role_casbin"] # 禁用的表,禁用以后将不会在选择表中看到
|
|
||||||
delimiters: ["@{", "}"] # 模板引擎变量分隔符号
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 登录HotGo后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,就会发现`数据库`选项增加了一个`default2`,后续生成步骤和生成例子完全一样
|
|
||||||
|
|
||||||
> 注意:上述的配置中所有的`default2`名称必须保持一致
|
|
||||||
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
## 生成关联表CURD
|
|
||||||
|
|
||||||
### 热编译启动
|
|
||||||
- 推荐使用热编译方式启动HotGo,这样生成完成页面自动刷新即可看到新生成内容,无需手动重启
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 服务端
|
|
||||||
cd server
|
|
||||||
gf run main.go
|
|
||||||
|
|
||||||
# web端
|
|
||||||
cd web
|
|
||||||
pnpm run dev 或 npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
以下是一个关联表的CURD生成流程
|
|
||||||
|
|
||||||
### 创建表结构
|
|
||||||
- 以下表结构和数据为了方便功能演示已经内置无需再次创建
|
|
||||||
|
|
||||||
|
|
||||||
- 创建主表:hg_sys_gen_curd_demo
|
|
||||||
```sql
|
|
||||||
CREATE TABLE `hg_sys_gen_curd_demo` (
|
|
||||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
|
||||||
`category_id` bigint(20) DEFAULT '0' COMMENT '分类ID',
|
|
||||||
`title` varchar(64) NOT NULL COMMENT '标题',
|
|
||||||
`description` varchar(255) DEFAULT '' COMMENT '描述',
|
|
||||||
`content` text COMMENT '内容',
|
|
||||||
`image` varchar(255) DEFAULT NULL COMMENT '单图',
|
|
||||||
`attachfile` varchar(255) DEFAULT NULL COMMENT '附件',
|
|
||||||
`city_id` bigint(20) DEFAULT '0' COMMENT '所在城市',
|
|
||||||
`switch` int(11) DEFAULT '1' COMMENT '显示开关',
|
|
||||||
`sort` int(11) DEFAULT NULL COMMENT '排序',
|
|
||||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态',
|
|
||||||
`created_by` bigint(20) DEFAULT '0' COMMENT '创建者',
|
|
||||||
`updated_by` bigint(20) DEFAULT '0' COMMENT '更新者',
|
|
||||||
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
|
|
||||||
`updated_at` datetime DEFAULT NULL COMMENT '修改时间',
|
|
||||||
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COMMENT='系统_生成curd演示';
|
|
||||||
```
|
|
||||||
|
|
||||||
创建关联表:hg_test_category
|
|
||||||
```sql
|
|
||||||
CREATE TABLE `hg_test_category` (
|
|
||||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类ID',
|
|
||||||
`name` varchar(255) NOT NULL COMMENT '分类名称',
|
|
||||||
`short_name` varchar(128) DEFAULT NULL COMMENT '简称',
|
|
||||||
`description` varchar(255) DEFAULT NULL COMMENT '描述',
|
|
||||||
`sort` int(11) NOT NULL COMMENT '排序',
|
|
||||||
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
|
|
||||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态',
|
|
||||||
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
|
|
||||||
`updated_at` datetime DEFAULT NULL COMMENT '修改时间',
|
|
||||||
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='测试分类';
|
|
||||||
```
|
|
||||||
|
|
||||||
### 表字段要求
|
|
||||||
- 使用生成时,表中必须具有以下字段和属性
|
|
||||||
|
|
||||||
| 字段名称 | 字段含义 | 字段类型 | 可为空 |
|
|
||||||
|--------|----------------------|---------------------|-----|
|
|
||||||
| id | 主键ID | bigint(20) | 否 |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 创建生成配置
|
|
||||||
- 登录HotGo后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,选择和填写如下参数:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 基本设置
|
|
||||||
- 确认无误后,点击生成配置会跳转到生成配置页面,如下:
|
|
||||||
- 你可以在该页面调整生成表格表头/表列的接口功能、菜单权限、高级设置和关联表设置
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 主表字段设置
|
|
||||||
|
|
||||||
- 在该页面你可以调整生成表格字段名称、表单组件、表单编辑/验证项、列表展示/查询项、字段排序、重置和同步字段
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 关联表字段设置
|
|
||||||
- 在该页面你可以调整生成表格关联表字段名称、列表展示/查询项、字段排序、重置和同步字段
|
|
||||||
- 如果存在多个关联表,也可以对多个关联表字段进行设置
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 预览并生成
|
|
||||||
|
|
||||||
点击`预览代码`查看生成的代码内容。如果无需继续调整直接点击`提交生成`即可,以下是预览代码效果:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- 如果你使用的热编译,那么页面会在生成成功后立即刷新,刷新完成你即可在后台菜单栏中看到`测试表格`菜单。如果不是使用热编译启动,请手动重启服务后刷新。
|
|
||||||
|
|
||||||
|
|
||||||
### 生成完成
|
|
||||||
|
|
||||||
- 让我们看看生成的表格页面,效果如下:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 常见问题
|
|
||||||
|
|
||||||
- [生成常见问题](code-help.md)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
## 生成CURD
|
|
||||||
|
|
||||||
### 热编译启动
|
|
||||||
- 推荐使用热编译方式启动HotGo,这样生成完成页面自动刷新即可看到新生成内容,无需手动重启
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 服务端
|
|
||||||
cd server
|
|
||||||
gf run main.go
|
|
||||||
|
|
||||||
# web端
|
|
||||||
cd web
|
|
||||||
pnpm run dev 或 npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
以下是一个基本的CURD生成流程
|
|
||||||
|
|
||||||
### 创建表结构
|
|
||||||
- 以下表结构和数据为了方便功能演示已经内置无需再次创建
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TABLE `hg_test_category` (
|
|
||||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类ID',
|
|
||||||
`name` varchar(255) NOT NULL COMMENT '分类名称',
|
|
||||||
`short_name` varchar(128) DEFAULT NULL COMMENT '简称',
|
|
||||||
`description` varchar(255) DEFAULT NULL COMMENT '描述',
|
|
||||||
`sort` int(11) NOT NULL COMMENT '排序',
|
|
||||||
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
|
|
||||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态',
|
|
||||||
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
|
|
||||||
`updated_at` datetime DEFAULT NULL COMMENT '修改时间',
|
|
||||||
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='测试分类';
|
|
||||||
```
|
|
||||||
|
|
||||||
### 表字段要求
|
|
||||||
- 使用生成时,表中必须具有以下字段和属性
|
|
||||||
|
|
||||||
| 字段名称 | 字段含义 | 字段类型 | 可为空 |
|
|
||||||
|--------|----------------------|---------------------|-----|
|
|
||||||
| id | 主键ID | bigint(20) | 否 |
|
|
||||||
|
|
||||||
|
|
||||||
### 创建生成配置
|
|
||||||
- 登录HotGo后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,选择和填写如下参数:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 基本设置
|
|
||||||
- 确认无误后,点击生成配置会跳转到生成配置页面,如下:
|
|
||||||
- 你可以在该页面调整生成表格表头/表列的接口功能、菜单权限、高级设置和关联表设置
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 表字段设置
|
|
||||||
|
|
||||||
- 在该页面你可以调整生成表格字段名称、表单组件、表单编辑/验证项、列表展示/查询项、字段排序、重置和同步字段
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 预览并生成
|
|
||||||
|
|
||||||
点击`预览代码`查看生成的代码内容。如果无需继续调整直接点击`提交生成`即可,以下是预览代码效果:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- 如果你使用的热编译,那么页面会在生成成功后立即刷新,刷新完成你即可在后台菜单栏中看到`测试表格`菜单。如果不是使用热编译启动,请手动重启服务后刷新。
|
|
||||||
|
|
||||||
|
|
||||||
### 生成完成
|
|
||||||
|
|
||||||
- 让我们看看生成的表格页面,效果如下:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 常见问题
|
|
||||||
|
|
||||||
- [生成常见问题](code-help.md)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
## 生成常见问题
|
|
||||||
|
|
||||||
### 生成完后页面提示:服务器错误,请稍候重试!
|
|
||||||
|
|
||||||
- 热编译环境下,web端往往会快于服务端重启并加载完成,此时接口访问会出现`服务器错误,请稍候重试!`或`404`。这是服务端正在重启导致的,一般稍等几秒就好,如果不行就手动重启下服务端。
|
|
||||||
|
|
||||||
|
|
||||||
### fetching tables failed: SHOW TABLES: Error 1045 (28000): Access denied for user * (using password: YES)
|
|
||||||
|
|
||||||
- 请去确认`server/manifest/config/config.yaml`和`server/hack/config.yaml`下的数据库配置一致并且权限正确
|
|
||||||
- 参考:[生成配置](code-config.md)
|
|
||||||
|
|
||||||
|
|
||||||
### 为什么后台找不到开发工具菜单
|
|
||||||
|
|
||||||
- 请去确认`server/manifest/config/config.yaml`中的`system.mode`不为`product`。product模式下后台【开发工具】菜单自动隐藏
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
## 使用前提
|
|
||||||
|
|
||||||
|
|
||||||
在HotGo中可以通过后台开发工具快速的一键生成CRUD,自动生成Api、控制器、业务逻辑、Web页面、表单组件、菜单权限等。
|
|
||||||
|
|
||||||
|
|
||||||
- hotgo 版本号 >= 2.13.1
|
|
||||||
- 使用前必须配置 [生成配置](code-config.md)
|
|
||||||
- 使用前必须了解 [数据库](sys-db.md)
|
|
||||||
|
|
||||||
|
|
||||||
相关目录
|
|
||||||
|
|
||||||
- [生成配置](code-config.md)
|
|
||||||
- [生成CURD](code-curd.md)
|
|
||||||
- [生成关联表CURD](code-curd-join.md)
|
|
||||||
- [生成树型CURD](code-tree.md)
|
|
||||||
- [生成业务模板](code-business.md)
|
|
||||||
- [生成模板开发](code-template-dev.md)
|
|
||||||
- [生成常见问题](code-help.md)
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
## 生成模板开发
|
|
||||||
|
|
||||||
### 自定义生成模板
|
|
||||||
|
|
||||||
- HotGo允许你新建新的模板分组来满足你的需求,模板可根据现有模板基础拷贝一份出来做改造,默认模板目录:[server/resource/generate/default](../../server/resource/generate/default)
|
|
||||||
|
|
||||||
- 系统内置了两组CURD生成模板,请参考[生成模板配置](sys-code.md#生成模板配置)。default:是默认的生成到主模块下;addon:是默认生成到指定的插件下
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 内置gf-cli
|
|
||||||
|
|
||||||
- 为了确保生成代码的依赖稳定性,在面对`gf`版本更新可能导致向下不兼容情况时,HotGo将`gf-cli`工具内置到系统中并进行在线执行调整,从而提供更可靠和一致的生成代码功能。
|
|
||||||
|
|
||||||
- 后续我们也将开放在线运行`gf gen ...`功能。在做插件开发时也会支持到在线生成插件下的service接口,这将会使得插件开发更加方便
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 指定gf-cli版本
|
|
||||||
|
|
||||||
- HotGo多数情况下会和最新版本的gf-cli保持同步,如果更新不及时或你不想使用最新版本的gf-cli来生成代码,可以找到自己想要的版本进行替换即可。
|
|
||||||
|
|
||||||
- 下面大致做一些替换步骤说明:
|
|
||||||
|
|
||||||
1. 打开`github.com/gogf/gf` 找到你想要使用的版本`clone`下来
|
|
||||||
2. 将`clone`代码中`gf/cmd/gf/internal/`目录覆盖到`server/internal/library/hggen/internal`
|
|
||||||
3. 将覆盖过来的目录文件中引入包名`github.com/gogf/gf/cmd/gf/v2/`批量改为`hotgo/internal/library/hggen/`
|
|
||||||
4. 运行`go mod tidy`
|
|
||||||
5. 运行`go run main.go`,如果没有报错,那么恭喜你已经完成了。如果有报错一般都是版本差异带来的影响,需要根据情况自行调整
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 指定数据库驱动
|
|
||||||
|
|
||||||
> HotGo默认使用mysql驱动,如果你想用其他数据库驱动打开下方文件中注释即可,目前已支持mysql、pgsql
|
|
||||||
|
|
||||||
- 修改文件路径:[server/internal/library/hggen/internal/cmd/cmd_gen_dao.go](../../server/internal/library/hggen/internal/cmd/cmd_gen_dao.go)
|
|
||||||
|
|
||||||
```go
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
//_ "github.com/gogf/gf/contrib/drivers/clickhouse/v2"
|
|
||||||
//_ "github.com/gogf/gf/contrib/drivers/mssql/v2"
|
|
||||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
|
||||||
//_ "github.com/gogf/gf/contrib/drivers/oracle/v2"
|
|
||||||
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
|
||||||
//_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
|
|
||||||
|
|
||||||
"hotgo/internal/library/hggen/internal/cmd/gendao"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
cGenDao = gendao.CGenDao
|
|
||||||
)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
修改完成后运行`go mod tidy`
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
## 生成树型CURD
|
|
||||||
|
|
||||||
### 热编译启动
|
|
||||||
- 推荐使用热编译方式启动HotGo,这样生成完成页面自动刷新即可看到新生成内容,无需手动重启
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 服务端
|
|
||||||
cd server
|
|
||||||
gf run main.go
|
|
||||||
|
|
||||||
# web端
|
|
||||||
cd web
|
|
||||||
pnpm run dev 或 npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
以下是一个基本的树形CURD生成流程
|
|
||||||
|
|
||||||
### 创建表结构
|
|
||||||
- 以下表结构和数据为了方便功能演示已经内置无需再次创建
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TABLE `hg_sys_gen_tree_demo` (
|
|
||||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
|
||||||
`pid` bigint(20) DEFAULT NULL COMMENT '上级ID',
|
|
||||||
`level` int(11) DEFAULT '1' COMMENT '关系树级别',
|
|
||||||
`tree` varchar(512) COMMENT '关系树',
|
|
||||||
`category_id` bigint(20) DEFAULT '0' COMMENT '分类ID',
|
|
||||||
`title` varchar(64) NOT NULL COMMENT '标题',
|
|
||||||
`description` varchar(255) DEFAULT '' COMMENT '描述',
|
|
||||||
`sort` int(11) DEFAULT NULL COMMENT '排序',
|
|
||||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态',
|
|
||||||
`created_by` bigint(20) DEFAULT '0' COMMENT '创建者',
|
|
||||||
`updated_by` bigint(20) DEFAULT '0' COMMENT '更新者',
|
|
||||||
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
|
|
||||||
`updated_at` datetime DEFAULT NULL COMMENT '修改时间',
|
|
||||||
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COMMENT='系统_生成树表演示';
|
|
||||||
```
|
|
||||||
|
|
||||||
### 表字段要求
|
|
||||||
- 使用生成时,表中必须具有以下字段和属性
|
|
||||||
|
|
||||||
| 字段名称 | 字段含义 | 字段类型 | 可为空 |
|
|
||||||
|--------|----------------------|---------------------|-----|
|
|
||||||
| id | 主键ID | bigint(20) | 否 |
|
|
||||||
| pid | 上级树ID | bigint(20) | 是 |
|
|
||||||
| level | 关系树级别 | int(11) | 否 |
|
|
||||||
| tree | 关系树 | varchar(512) | 是 |
|
|
||||||
|
|
||||||
### 创建生成配置
|
|
||||||
- 登录HotGo后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,选择和填写如下参数:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 基本设置
|
|
||||||
- 确认无误后,点击生成配置会跳转到生成配置页面,如下:
|
|
||||||
- 你可以在该页面调整生成表格表头/表列的接口功能、菜单权限、高级设置和关联表设置
|
|
||||||
- 相比普通CURD,这里多了`树名称字段`和`树表格样式`选项
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 表字段设置
|
|
||||||
|
|
||||||
- 在该页面你可以调整生成表格字段名称、表单组件、表单编辑/验证项、列表展示/查询项、字段排序、重置和同步字段
|
|
||||||
- 树表中的pid、level、tree字段由系统维护,单独设置编辑表单功能无效!
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 预览并生成
|
|
||||||
|
|
||||||
点击`预览代码`查看生成的代码内容。如果无需继续调整直接点击`提交生成`即可,以下是预览代码效果:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- 如果你使用的热编译,那么页面会在生成成功后立即刷新,刷新完成你即可在后台菜单栏中看到`测试表格`菜单。如果不是使用热编译启动,请手动重启服务后刷新。
|
|
||||||
|
|
||||||
|
|
||||||
### 生成完成
|
|
||||||
|
|
||||||
- 让我们看看生成的表格页面,效果如下:
|
|
||||||
|
|
||||||
- 普通树表
|
|
||||||

|
|
||||||
|
|
||||||
- 选项式树表
|
|
||||||

|
|
||||||
|
|
||||||
### 常见问题
|
|
||||||
|
|
||||||
- [生成常见问题](code-help.md)
|
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 217 KiB |
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 636 KiB |
|
Before Width: | Height: | Size: 697 KiB |
|
Before Width: | Height: | Size: 512 KiB |
|
Before Width: | Height: | Size: 589 KiB |
|
Before Width: | Height: | Size: 681 KiB |
|
Before Width: | Height: | Size: 722 KiB |
|
Before Width: | Height: | Size: 666 KiB |
|
Before Width: | Height: | Size: 603 KiB |
|
Before Width: | Height: | Size: 491 KiB |
|
Before Width: | Height: | Size: 450 KiB |
|
Before Width: | Height: | Size: 634 KiB |
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 255 KiB |
|
Before Width: | Height: | Size: 294 KiB |
|
Before Width: | Height: | Size: 1012 KiB |