迭代方案确认
This commit is contained in:
237
docs/7月迭代/独立方案/基础规范/系统配置.md
Normal file
237
docs/7月迭代/独立方案/基础规范/系统配置.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# 基础设施:系统配置(tb_system_config)
|
||||
|
||||
> 状态:独立方案来源稿;最终口径以7月迭代标准评审稿为准。
|
||||
> 被依赖:需求 09(C端支付限制)
|
||||
|
||||
---
|
||||
|
||||
## 一、设计目标
|
||||
|
||||
将散落在代码里的"写死配置"提取到数据库,平台管理员可通过后台页面修改,无需重新部署。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor Admin as 平台超管
|
||||
participant Web as 后台配置页
|
||||
participant API as SystemConfig Application
|
||||
participant DB as PostgreSQL
|
||||
participant Redis as Redis
|
||||
participant Biz as 业务读取方
|
||||
|
||||
Admin->>Web: 修改受控配置表单
|
||||
Web->>API: PUT /api/admin/system/config/{config_key}
|
||||
API->>API: 按配置 key 注册规则校验类型和值域
|
||||
API->>DB: 更新值并写审计日志
|
||||
API->>Redis: 删除对应缓存
|
||||
API-->>Web: 返回最新配置和更新时间
|
||||
Biz->>Redis: 下次读取缓存未命中
|
||||
Biz->>DB: 读取最新配置并回填缓存
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、数据库
|
||||
|
||||
```sql
|
||||
-- 迁移文件:YYYYMMDD_create_tb_system_config.sql
|
||||
CREATE TABLE tb_system_config (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
config_key VARCHAR(100) NOT NULL, -- 唯一键,格式:module.group.name
|
||||
config_value TEXT NOT NULL DEFAULT '', -- 值(string/number/json字符串)
|
||||
value_type VARCHAR(20) NOT NULL DEFAULT 'string', -- string | int | bool | json
|
||||
module VARCHAR(50) NOT NULL DEFAULT 'general', -- 所属模块(便于按模块查询)
|
||||
description TEXT, -- 中文说明(前端展示用)
|
||||
is_readonly BOOLEAN NOT NULL DEFAULT FALSE, -- 是否只读(代码内部,不允许后台改)
|
||||
creator BIGINT NOT NULL DEFAULT 0,
|
||||
updater BIGINT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT uq_system_config_key UNIQUE (config_key)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE tb_system_config IS '系统全局配置表';
|
||||
|
||||
-- 初始化数据
|
||||
INSERT INTO tb_system_config (config_key, config_value, value_type, module, description) VALUES
|
||||
-- C端支付限制(需求9)
|
||||
('c2b.payment.card_allowed_methods', '["alipay","wallet"]', 'json', 'c2b.payment', '卡资产C端允许的支付方式(alipay/wechat/wallet)'),
|
||||
('c2b.payment.device_allowed_methods', '["wechat","wallet"]', 'json', 'c2b.payment', '设备C端允许的支付方式');
|
||||
```
|
||||
|
||||
需求02不写入全局默认实名策略。H5 始终读取卡或设备自身的 `realname_policy`;新建资产使用模型默认 `after_order`,避免全局 Key 与资产字段产生两套优先级。
|
||||
|
||||
---
|
||||
|
||||
## 三、Model
|
||||
|
||||
```go
|
||||
// internal/model/system_config.go
|
||||
|
||||
// SystemConfig 系统全局配置模型
|
||||
type SystemConfig struct {
|
||||
ID uint `gorm:"column:id;primaryKey" json:"id"`
|
||||
ConfigKey string `gorm:"column:config_key;uniqueIndex;not null" json:"config_key"`
|
||||
ConfigValue string `gorm:"column:config_value;type:text;not null;default:''" json:"config_value"`
|
||||
ValueType string `gorm:"column:value_type;type:varchar(20);not null;default:'string'" json:"value_type"`
|
||||
Module string `gorm:"column:module;type:varchar(50);not null;default:'general';index" json:"module"`
|
||||
Description string `gorm:"column:description;type:text" json:"description"`
|
||||
IsReadonly bool `gorm:"column:is_readonly;not null;default:false" json:"is_readonly"`
|
||||
Creator uint `gorm:"column:creator;not null;default:0" json:"creator"`
|
||||
Updater uint `gorm:"column:updater;not null;default:0" json:"updater"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (SystemConfig) TableName() string { return "tb_system_config" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、Store
|
||||
|
||||
```go
|
||||
// internal/store/postgres/system_config_store.go
|
||||
|
||||
type SystemConfigStore struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (s *SystemConfigStore) GetByKey(ctx context.Context, key string) (*model.SystemConfig, error)
|
||||
func (s *SystemConfigStore) GetByModule(ctx context.Context, module string) ([]model.SystemConfig, error)
|
||||
func (s *SystemConfigStore) UpdateValue(ctx context.Context, key string, value string, updaterID uint) error
|
||||
func (s *SystemConfigStore) BatchGet(ctx context.Context, keys []string) (map[string]*model.SystemConfig, error)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、配置读取辅助包
|
||||
|
||||
业务代码不直接操作 Store,通过辅助函数读取,带 Redis 缓存(5分钟TTL):
|
||||
|
||||
```go
|
||||
// pkg/sysconfig/config.go
|
||||
|
||||
// GetString 读取字符串配置,返回默认值
|
||||
func GetString(ctx context.Context, key string, defaultVal string) string
|
||||
|
||||
// GetStringSlice 读取 JSON 数组配置
|
||||
func GetStringSlice(ctx context.Context, key string) ([]string, error)
|
||||
|
||||
// GetBool 读取布尔配置
|
||||
func GetBool(ctx context.Context, key string, defaultVal bool) bool
|
||||
|
||||
// InvalidateCache 更新配置后清缓存(在 UpdateValue 后调用)
|
||||
func InvalidateCache(ctx context.Context, key string)
|
||||
```
|
||||
|
||||
Redis Key:`sys:config:{config_key}`,TTL 5分钟。
|
||||
|
||||
业务代码用法:
|
||||
```go
|
||||
// 读取卡的允许支付方式
|
||||
allowedMethods, _ := sysconfig.GetStringSlice(ctx, "c2b.payment.card_allowed_methods")
|
||||
// 返回 ["alipay","wallet"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、API 设计
|
||||
|
||||
### 6.1 获取配置列表
|
||||
|
||||
```
|
||||
GET /api/admin/system/config?module=c2b.payment
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"list": [
|
||||
{
|
||||
"config_key": "c2b.payment.card_allowed_methods",
|
||||
"config_value": "[\"alipay\",\"wallet\"]",
|
||||
"value_type": "json",
|
||||
"description": "卡资产C端允许的支付方式",
|
||||
"is_readonly": false,
|
||||
"updated_at": "2026-07-11T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 更新配置
|
||||
|
||||
```
|
||||
PUT /api/admin/system/config/{config_key}
|
||||
```
|
||||
|
||||
请求体:
|
||||
```json
|
||||
{
|
||||
"config_value": "[\"alipay\",\"wallet\",\"wechat\"]"
|
||||
}
|
||||
```
|
||||
|
||||
权限:仅平台超管可操作。
|
||||
|
||||
### DTO
|
||||
|
||||
```go
|
||||
// internal/model/dto/system_config_dto.go
|
||||
|
||||
// SystemConfigListRequest 配置列表查询请求
|
||||
type SystemConfigListRequest struct {
|
||||
Module string `query:"module" description:"按模块过滤(可选)"`
|
||||
}
|
||||
|
||||
// SystemConfigItem 配置项响应
|
||||
type SystemConfigItem struct {
|
||||
ConfigKey string `json:"config_key"`
|
||||
ConfigValue string `json:"config_value"`
|
||||
ValueType string `json:"value_type" description:"值类型 (string/int/bool/json)"`
|
||||
Module string `json:"module"`
|
||||
Description string `json:"description"`
|
||||
IsReadonly bool `json:"is_readonly"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// UpdateSystemConfigRequest 更新配置请求
|
||||
type UpdateSystemConfigRequest struct {
|
||||
ConfigValue string `json:"config_value" validate:"required" description:"新配置值"`
|
||||
}
|
||||
```
|
||||
|
||||
更新接口不能只校验 `value_type`。Application 需要按 `config_key` 注册允许值,例如支付方式只能来自 `alipay/wechat/wallet`,实名策略只能来自 `none/before_order/after_order`。未知 key 默认只读,禁止通过通用页面写入任意系统配置。
|
||||
|
||||
---
|
||||
|
||||
## 七、前端对接
|
||||
|
||||
### 页面:系统设置 > 系统配置
|
||||
|
||||
**初期可以做一个通用的 Key-Value 管理页面,按 module 分组展示。**
|
||||
|
||||
调用流程:
|
||||
1. 进入页面 → `GET /api/admin/system/config`(不传 module = 返回全部)
|
||||
2. 按 module 分组展示,`is_readonly=true` 的配置只读
|
||||
3. 修改某项 → `PUT /api/admin/system/config/{config_key}`,body: `{config_value}`
|
||||
4. 更新成功后后端立即删除该 key 的缓存,前端提示“配置已更新”并刷新当前值
|
||||
|
||||
**C端支付限制配置展示建议**(针对 `c2b.payment` 模块):
|
||||
|
||||
不要让后台用户手动填 JSON,前端渲染成 CheckboxGroup:
|
||||
|
||||
```
|
||||
卡资产允许支付方式:
|
||||
☑ 支付宝 ☑ 钱包 ☐ 微信
|
||||
|
||||
设备允许支付方式:
|
||||
☐ 支付宝 ☑ 钱包 ☑ 微信
|
||||
```
|
||||
|
||||
前端把选中项序列化成 `["alipay","wallet"]` 提交。
|
||||
|
||||
通用 Key-Value 页面只作为管理壳层,已知业务配置必须使用受控组件(单选、复选或开关),不向运营人员暴露 JSON 文本框。
|
||||
Reference in New Issue
Block a user