Compare commits

..
10 Commits
1969 changed files with 189786 additions and 133 deletions
+43 -132
View File
@@ -1,165 +1,76 @@
# ---> 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
# Go binaries and test/build artifacts
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
go.work.sum
# env file
.env
# ---> Node
# Logs
logs
# Node dependencies, logs, caches, and build output
node_modules/
jspm_packages/
web_modules/
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# 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
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
.nyc_output/
.grunt/
bower_components/
.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
build/Release/
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.npm/
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.rpt2_cache_cjs/
.rpt2_cache_es/
.rpt2_cache_umd/
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.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.*
# dotenv environment variable files
# Local environment files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# 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.*
# Local OS and editor metadata
.DS_Store
.idea/
.vscode/
# Python bytecode
__pycache__/
*.py[cod]
+960
View File
@@ -0,0 +1,960 @@
# 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
- 禁止在源码里硬编码菜单路由路径
+21
View File
@@ -0,0 +1,21 @@
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.
+166 -1
View File
@@ -1,2 +1,167 @@
# olons_admin
# HotGo-V2
<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)
[![avatar](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://jb.gg/OpenSource)
## License
[MIT © HotGo-2026](./LICENSE)
Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

@@ -0,0 +1,130 @@
# 后台功能与数据库表映射
> 更新时间: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` 的表使用软删除,不直接物理删除历史业务记录。
@@ -0,0 +1,453 @@
# 后台管理系统开发总结
> 文档版本: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 真实认证流程不与本次状态机补强混合实施,后续作为独立安全增强项处理。
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,508 @@
# 后台管理系统需求文档
参考管理端功能拆解、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 端仅显示已上架 |
| 会员等级 | 会员等级 | 门槛、赠送、次数、佣金、提现次数 | 计算与展示同源 |
| 领取中心 | 网站设置、商品、订单 | 营业时间、最低余额、匹配规则 | 服务端状态机判定 |
| 订单记录 | 订单列表 | 查询、冻结、匹配、异常处理 | 业务单号和台账可追溯 |
| 储入 | 充值管理 | 凭证、审核、入账、驳回 | 幂等入账与自动对账 |
| 取出 | 提现管理、银行卡信息 | 收款资料、审核、通道、结果 | 金额、手续费、到账同源 |
| 任务大厅与任务 | 任务大厅、任务列表、会员任务审核 | 配置、分发、审核 | 等级、佣金、状态一致 |
| 个人资料 | 会员列表 | 资料、团队、状态、风控 | 敏感字段默认脱敏 |
| 通知与弹幕 | 文本、会员弹幕 | 发布、定向、撤回、查看记录 | 真实性标识和审计 |
| 客服 | 客服管理 | 客服入口、工作时间、会话映射 | 失败有备用通道 |
![C 端与后台业务闭环原型](assets/prototype_06_flow.png)
图 1 C 端与后台业务闭环(脱敏重绘原型)
## 4 首页数据看板
首页展示用户、商品、订单、充值、提现、佣金、利息宝转入、下级返佣与账户余额等汇总卡,并展示微信、支付宝和银行卡渠道统计。新系统应把口径、时间区间、刷新时间和数据延迟显式化。
| 指标 | 定义 | 筛选维度 | 权限 |
| --- | --- | --- | --- |
| 用户总量/新增 | 去重有效会员数 | 今日、昨日、自定义日期 | 运营只读 |
| 充值用户 | 至少一笔成功充值的会员数 | 时间、渠道、等级 | 财务/运营 |
| 订单量与金额 | 按订单状态和完成时间统计 | 状态、商品、等级 | 运营/财务 |
| 充值/提现 | 成功与待处理金额分开 | 渠道、状态、时间 | 财务 |
| 佣金/返佣 | 任务佣金与层级返佣分开 | 类型、等级、时间 | 财务/审计 |
| 账户余额 | 钱包可用与冻结余额总和 | 币种、账户状态 | 财务/审计 |
- 卡片可点击进入对应明细页,并继承时间筛选;无权限用户只能看到隐藏金额或不可点击状态。
- 页面顶部展示“数据截至时间”和刷新按钮;自动刷新不得造成重复请求风暴。
![后台首页看板脱敏原型](assets/prototype_01_dashboard.png)
图 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。新系统必须默认脱敏,按角色和目的临时授权查看;列表、导出、日志、埋点和截图统一执行同一脱敏规则。
![会员列表脱敏原型](assets/prototype_02_member_list.png)
图 3 会员列表脱敏原型
![会员编辑弹窗原型](assets/prototype_03_member_modal.png)
图 4 添加会员弹窗原型
## 7 会员等级与任务大厅
### 7.1 会员等级
列表字段为等级名称、升级价格、赠送金额、接单次数、佣金比例和提现次数;支持编辑与受控删除。等级配置直接影响 C 端充值、领取和提现,必须使用版本化发布,不得修改后立即影响进行中的订单。
| 规则 | 校验 | 生效策略 |
| --- | --- | --- |
| 升级价格/赠送金额 | ≥0;货币精度;赠送比例上限 | 新会员或下个结算周期 |
| 接单次数 | 整数;按日重置时区明确 | 发布后次日生效 |
| 佣金比例 | 0–1 Decimal;展示百分比 | 锁定到任务订单快照 |
| 提现次数 | 整数;与提现时间窗一致 | 发布后次日生效 |
| 删除等级 | 无有效会员与在途订单方可删除 | 优先停用并保留历史 |
### 7.2 任务大厅
页面字段为名称、图标、比例、简介、创建时间;新增弹窗还包含会员等级。实测列表接口直接显示“数据接口请求异常:error”,但新增弹窗可打开。新系统需要标准错误码、可重试状态、traceId 与空数据区分。
- 任务大厅条目必须绑定可用会员等级、比例单位、图标和 C 端跳转。
- 停用条目不影响已领取任务;删除仅允许无历史引用的数据,建议统一软删除。
## 8 交易管理
### 8.1 订单列表
查询条件:订单号、手机号、用户名、日期;支持开启/关闭自动刷新。列表含绑卡姓名、用户名、自动派单、余额、手机号、当日交易次数、商品、数量、金额、佣金、下单时间、解冻时间、消息、订单状态、冻结状态和操作。
| 状态 | 后台操作 | 约束 |
| --- | --- | --- |
| 匹配中 | 查看进度、取消匹配 | 同一会员仅一笔匹配;需幂等 |
| 待处理 | 查看详情、发送提醒 | 不可手动完成;服务端倒计时 |
| 冻结 | 查看风险、发起解冻复核 | 冻结理由、时长、申诉路径 |
| 已完成 | 查看台账 | 金额、佣金、解冻三方一致 |
| 异常/失败 | 重新匹配、人工处理申请 | 人工改状态必须双人审批 |
### 8.2 充值管理
顶部展示全部、用户已支付、用户未支付、手动审核、手动驳回等汇总金额。列表字段:订单号、真实姓名、手机号、余额、交易金额、打款凭证、添加时间、支付方式、类型、处理时间、备注和操作。
- 审核通过前校验凭证、订单金额、收款主体、重复订单和账户状态;入账使用幂等键。
- 驳回必须选择标准原因并可补充说明;通知 C 端且允许补充材料。
### 8.3 提现管理
查询条件:订单号、用户名、日期。列表含用户余额、提现金额、手续费、实际到账、银行名称、开户名称、银行卡号、云闪付、数字钱包、支付宝/微信收款码、发起与处理时间、操作。
> **P0 风险:** 现网直接显示完整银行卡号与多个钱包账号。新系统列表只显示掩码,完整值不进入普通 DOM;付款处理时通过一次性授权查看,超时自动隐藏。
![提现审核脱敏原型](assets/prototype_04_withdrawal.png)
图 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 和操作;支持添加顶级权限、添加子级、编辑、删除、展开/折叠。权限标识唯一且不可随意改名;被角色引用时禁止删除。
![RBAC 角色权限原型](assets/prototype_05_rbac.png)
图 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 首页看板(脱敏重绘)
![后台首页看板脱敏原型](assets/prototype_01_dashboard.png)
### 18.2 会员列表(脱敏重绘)
![会员列表脱敏原型](assets/prototype_02_member_list.png)
### 18.3 会员弹窗(脱敏重绘)
![会员编辑弹窗原型](assets/prototype_03_member_modal.png)
### 18.4 提现审核(脱敏重绘)
![提现审核脱敏原型](assets/prototype_04_withdrawal.png)
### 18.5 角色权限(脱敏重绘)
![RBAC 角色权限原型](assets/prototype_05_rbac.png)
### 18.6 业务闭环(脱敏重绘)
![C 端与后台业务闭环原型](assets/prototype_06_flow.png)
## 19 待确认事项
- 目标系统是否处理真实资金,适用司法辖区、支付牌照与实名要求是什么。
- “设为假人、弹幕、奖励金、层级返佣”是否保留;若保留,业务合法性和真实性如何证明。
- 充值、提现、账变和会员禁用的初审/复核角色与金额阈值。
- C 端现有接口能否修改,还是需要后台兼容旧字段和状态枚举。
- 客服使用自建工单还是第三方服务,允许向第三方传输哪些数据。
- 运营内容是否需要多语言、定时发布、区域差异与灰度发布。
- 历史用户、订单、银行卡和台账的迁移范围、清洗规则和保留年限。
- 生产环境数据导出、敏感值查看和紧急权限的审批人。
在上述事项确认前,可以完成认证、RBAC、审计、内容、会员脱敏查询、商品任务配置和沙箱交易;不得接入真实收款、放款或自动资金调整。
@@ -0,0 +1,484 @@
# 第 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. 完成状态机、资金并发和回归测试。
+60
View File
@@ -0,0 +1,60 @@
## 目录
#### 介绍安装
- [系统介绍](../../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)
+216
View File
@@ -0,0 +1,216 @@
## 模块开发流程
目录
- 创建新插件
- 开发
- 调用主模块服务接口
- 访问路径
- 数据迁移
### 创建新插件
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方法中,并遵循系统规范进行数据安装
+86
View File
@@ -0,0 +1,86 @@
## 模块辅助说明
目录
- 模块结构
- 获取模块信息
- 插件路由规则
#### 模块结构
- 文件路径: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前端页面中如有之前的路由风格也需同步修改。
@@ -0,0 +1,40 @@
## 模块介绍及目录
目录
- 模块介绍
- 启动流程
- 目录结构
### 模块介绍
> 定位:开发独立、临时性、工具类型的功能时推荐使用插件化开发,例如:小游戏(大转盘/消消乐/抽奖/大屏互动/红包等)、小插件(广告管理/文章管理/友情链接等等)、小模块(报名/投票/签到)、小程序、大型插件微商城等等。
> 插件模块方便多项目复用,同时完美支持多人协同开发,每个插件模块都有独立的微架构目录结构,多插件之间完全隔离。
### 启动流程
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
```
+21
View File
@@ -0,0 +1,21 @@
目录
- 框架文档
- [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)
+5
View File
@@ -0,0 +1,5 @@
## 生成业务模板
根据`api`接口文件一键生成业务模板:api、controller、logic、service
待写。
+172
View File
@@ -0,0 +1,172 @@
## 生成配置
目录
- 模板配置
- 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`名称必须保持一致
+115
View File
@@ -0,0 +1,115 @@
## 生成关联表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后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,选择和填写如下参数:
![](images/code/join-add.png)
### 基本设置
- 确认无误后,点击生成配置会跳转到生成配置页面,如下:
- 你可以在该页面调整生成表格表头/表列的接口功能、菜单权限、高级设置和关联表设置
![](images/code/join-init.png)
### 主表字段设置
- 在该页面你可以调整生成表格字段名称、表单组件、表单编辑/验证项、列表展示/查询项、字段排序、重置和同步字段
![](images/code/join-fields.png)
### 关联表字段设置
- 在该页面你可以调整生成表格关联表字段名称、列表展示/查询项、字段排序、重置和同步字段
- 如果存在多个关联表,也可以对多个关联表字段进行设置
![](images/code/join-fields2.png)
### 预览并生成
点击`预览代码`查看生成的代码内容。如果无需继续调整直接点击`提交生成`即可,以下是预览代码效果:
![](images/code/join-preview.png)
- 如果你使用的热编译,那么页面会在生成成功后立即刷新,刷新完成你即可在后台菜单栏中看到`测试表格`菜单。如果不是使用热编译启动,请手动重启服务后刷新。
### 生成完成
- 让我们看看生成的表格页面,效果如下:
![](images/code/join-list.png)
### 常见问题
- [生成常见问题](code-help.md)
+84
View File
@@ -0,0 +1,84 @@
## 生成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后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,选择和填写如下参数:
![](images/code/curd-add.png)
### 基本设置
- 确认无误后,点击生成配置会跳转到生成配置页面,如下:
- 你可以在该页面调整生成表格表头/表列的接口功能、菜单权限、高级设置和关联表设置
![](images/code/curd-init.png)
### 表字段设置
- 在该页面你可以调整生成表格字段名称、表单组件、表单编辑/验证项、列表展示/查询项、字段排序、重置和同步字段
![](images/code/curd-fields.png)
### 预览并生成
点击`预览代码`查看生成的代码内容。如果无需继续调整直接点击`提交生成`即可,以下是预览代码效果:
![](images/code/curd-preview.png)
- 如果你使用的热编译,那么页面会在生成成功后立即刷新,刷新完成你即可在后台菜单栏中看到`测试表格`菜单。如果不是使用热编译启动,请手动重启服务后刷新。
### 生成完成
- 让我们看看生成的表格页面,效果如下:
![](images/code/curd-list.png)
### 常见问题
- [生成常见问题](code-help.md)
+18
View File
@@ -0,0 +1,18 @@
## 生成常见问题
### 生成完后页面提示:服务器错误,请稍候重试!
- 热编译环境下,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模式下后台【开发工具】菜单自动隐藏
+20
View File
@@ -0,0 +1,20 @@
## 使用前提
在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)
+59
View File
@@ -0,0 +1,59 @@
## 生成模板开发
### 自定义生成模板
- 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`
+93
View File
@@ -0,0 +1,93 @@
## 生成树型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后台 -> 开发工具 -> 代码生成 -> 找到立即生成按钮并打开,选择和填写如下参数:
![](images/code/tree-add.png)
### 基本设置
- 确认无误后,点击生成配置会跳转到生成配置页面,如下:
- 你可以在该页面调整生成表格表头/表列的接口功能、菜单权限、高级设置和关联表设置
- 相比普通CURD,这里多了`树名称字段`和`树表格样式`选项
![](images/code/tree-init.png)
### 表字段设置
- 在该页面你可以调整生成表格字段名称、表单组件、表单编辑/验证项、列表展示/查询项、字段排序、重置和同步字段
- 树表中的pid、level、tree字段由系统维护,单独设置编辑表单功能无效!
![](images/code/tree-fields.png)
### 预览并生成
点击`预览代码`查看生成的代码内容。如果无需继续调整直接点击`提交生成`即可,以下是预览代码效果:
![](images/code/tree-preview.png)
- 如果你使用的热编译,那么页面会在生成成功后立即刷新,刷新完成你即可在后台菜单栏中看到`测试表格`菜单。如果不是使用热编译启动,请手动重启服务后刷新。
### 生成完成
- 让我们看看生成的表格页面,效果如下:
- 普通树表
![](images/code/tree-list.png)
- 选项式树表
![](images/code/tree-list2.png)
### 常见问题
- [生成常见问题](code-help.md)
Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

+108
View File
@@ -0,0 +1,108 @@
## 生产部署
目录
- 编译配置
- 编译
- 修改生产配置文件
- 启动服务
- Nginx配置
### 编译配置
- 配置文件: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: ""
```
### 编译
- 以下方式任选其一即可
1、 make一键编译 (确认已安装`make环境`)
```shell
cd server && make build
```
2、 按步骤手动编译
```shell
cd server # 切换到服务端目录下
rm -rf ./resource/public/admin/ # 删除之前的web资源
mkdir ./resource/public/admin/ # 重新创建web资源存放目录,除首次编译后续可以跳过执行此步骤
cd ../web && pnpm run build # 切换到web项目下,编译web项目
\cp -rf ./dist/* ../server/resource/public/admin/ # 将编译好的web资源复制到server对应的资源存放路径下
cd ../server # 切换回服务端目录下
echo "y" | gf build # 编译hotgo服务端
# 不出意外你已经编译好了hotgo可执行文件!
```
3、分端编译 (多人开发时推荐)
```shell
# 编译服务端
cd server # 切换到服务端目录下
rm -rf ./resource/public/admin/ # 删除之前的web资源,如果开发环境没有这个目录可以忽略此步骤
echo "y" | gf build # 编译hotgo服务端
# 编译web端
cd web
pnpm run build 或 npm run build
# web端编译完成后,将web/dist/*中的文件上传到`server`端线上运行目录:/resource/public/admin即可
# 至此,web端和server端都可以独立覆盖更新
```
### 修改生产配置文件
- 配置文件:server/manifest/config/config.yaml
> 如关闭debug、mode设为生产环境、修改数据库地址、缓存驱动、队列驱动、日志路径等
### 启动服务
> 这里可以接使用gf官方推荐的启动方式,请参考:https://goframe.org/pages/viewpage.action?pageId=1114403
### Nginx配置
```
# websocket
location = /socket {
proxy_pass http://127.0.0.1:8000/socket;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_connect_timeout 600s;
proxy_read_timeout 600;
proxy_send_timeout 600s;
}
# http
location ^~ / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8000/;
proxy_redirect off;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
}
```

Some files were not shown because too many files have changed in this diff Show More