签入版本

This commit is contained in:
2026-10-08 17:50:29 +08:00
parent 809750b47e
commit e213a9b31d
444 changed files with 39366 additions and 37533 deletions
+179 -62
View File
@@ -8,14 +8,15 @@
| 特性 | 说明 |
|------|------|
| 基类 | BaseLogic(系统共享,不隔离) |
| Service 基类 | `BaseService`(系统共享,不隔离);读取封装 `ConfigService` |
| 关联 | 与 ConfigItem 一对多(通过 config_id) |
| 用途 | 网站名称、Logo、版权信息等动态配置 |
| 缓存 | DictService 两级缓存(请求级 + Redis),减少数据库查询 |
| 控制器 | `ConfigController`(配置组)+ `ConfigItemController`(配置项) |
| 值处理 | `HasConfigValueProcessing` Trait:按 type 做文件迁移与 `valueList` 生成 |
## 数据库表结构
### 主表 `think_config`(配置组)
### 主表 `laravel_config`(配置组)
| 字段 | 类型 | 说明 |
|------|------|------|
@@ -24,31 +25,25 @@
| code | varchar(150) | 配置组编码(如 `website_config`) |
| sort | int | 排序(升序) |
| note | varchar(255) | 备注说明 |
| create_user | varchar(50) | 创建人(BaseModel 自动写入) |
| create_time | datetime | 创建时间(BaseModel 自动写入) |
| update_user | varchar(50) | 更新人(BaseModel 自动写入) |
| update_time | datetime | 更新时间(BaseModel 自动写入) |
| create_user / create_time / update_user / update_time | | 审计字段(模型 Trait 自动写入) |
| is_delete | int | 软删除标记(0=正常,1=已删除) |
### 子表 `think_config_item`(配置项)
### 子表 `laravel_config_item`(配置项)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | int | 主键,自增 |
| config_id | int | 所属配置组 ID(关联 think_config.id) |
| config_id | int | 所属配置组 ID(关联 laravel_config.id) |
| name | varchar(150) | 配置项名称(如「网站名称」) |
| code | varchar(150) | 配置项编码(如 `site_name`) |
| value | varchar(1000) | 配置值 |
| options | text | 配置选项(JSON 格式,用于 select/radio 等类型) |
| type | varchar(150) | 值类型(text / textarea / number / switch / image / file / select) |
| value | text | 配置值,按 type 存相对路径、`文件名\|路径`、逗号串或富文本 HTML |
| options | text | 选项串 `k=v,k=v`(逗号分隔),用于 radio / checkbox / select 等类型 |
| type | varchar(150) | 表单类型:hidden / readonly / number / text / textarea / password / radio / checkbox / select / selects / icon / date / datetime / image / images / file / files / ueditor |
| status | int | 状态(1=正常,2=停用) |
| sort | int | 排序(升序) |
| note | varchar(255) | 配置项备注 |
| create_user | varchar(50) | 创建人(BaseModel 自动写入) |
| create_time | datetime | 创建时间(BaseModel 自动写入) |
| update_user | varchar(50) | 更新人(BaseModel 自动写入) |
| update_time | datetime | 更新时间(BaseModel 自动写入) |
| is_delete | int | 软删除标记(0=正常,1=已删除) |
| create_user / create_time / update_user / update_time | | 审计字段 |
| is_delete | int | 软删除标记 |
## API 接口
@@ -58,28 +53,92 @@
|------|------|--------|------|
| GET | `/api/config/page` | sys:config:page | 分页列表 |
| GET | `/api/config/list` | sys:config:list | 全量列表 |
| GET | `/api/config/detail/:id` | sys:config:detail | 详情 |
| GET | `/api/config/detail/{id}` | sys:config:detail | 详情 |
| POST | `/api/config/add` | sys:config:add | 新增 |
| PUT | `/api/config/update` | sys:config:update | 修改 |
| DELETE | `/api/config/delete/:id` | sys:config:delete | 删除 |
| DELETE | `/api/config/delete/{id}` | sys:config:delete | 删除 |
| DELETE | `/api/config/batchDelete` | sys:config:batchDelete | 批量删除 |
### 网站配置(快捷接口)
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/config/web/index` | sys:config:web | 获取网站配置(按组返回所有配置项) |
| POST | `/api/config/web/save` | sys:config:web | 保存网站配置(批量更新配置项值) |
| GET | `/api/config/web/index` | sys:config:webIndex | 获取网站配置(按组返回所有配置项) |
| POST | `/api/config/web/save` | sys:config:update | 保存网站配置(批量更新配置项值) |
### 配置项
| 方法 | 路径 | 权限码 | 说明 |
|------|------|--------|------|
| GET | `/api/config/item/page` | sys:config:item:page | 分页列表 |
| GET | `/api/config/item/list` | sys:config:item:list | 全量列表 |
| GET | `/api/config/item/detail/:id` | sys:config:item:detail | 详情 |
| POST | `/api/config/item/add` | sys:config:item:add | 新增 |
| PUT | `/api/config/item/update` | sys:config:item:update | 修改 |
| DELETE | `/api/config/item/delete/:id` | sys:config:item:delete | 删除 |
| GET | `/api/config/item/page` | sys:config:page | 分页列表 |
| GET | `/api/config/item/list` | sys:config:list | 全量列表 |
| GET | `/api/config/item/detail/{id}` | sys:config:detail | 详情 |
| POST | `/api/config/item/add` | sys:config:add | 新增 |
| PUT | `/api/config/item/update` | sys:config:update | 修改 |
| DELETE | `/api/config/item/delete/{id}` | sys:config:delete | 删除 |
| DELETE | `/api/config/item/batchDelete` | sys:config:batchDelete | 批量删除 |
### 配置项详情响应
`GET /api/config/item/detail/{id}`:
- `value` — 数据库存储的原始值;
- `valueList` — 按类型加工后的可展示值,供前端直接使用(不涉及的类型为 `null`);
- `configCode` — 所属配置组编码。
```json
{
"code": 0,
"ok": true,
"msg": "操作成功",
"data": {
"id": 7,
"name": "网站图集",
"code": "website_album",
"value": "config/20260923/110133_AtVRHXAW.png,config/20260923/110133_8ERxsPCx.png,config/20260923/110133_lYnVEf9f.png",
"options": "",
"configId": 1,
"type": "images",
"status": 1,
"sort": 30,
"note": "网站图集",
"createUser": "admin",
"createTime": "2026-09-01 10:37:35",
"updateUser": "admin",
"updateTime": "2026-09-01 10:37:35",
"isDelete": 0,
"configCode": "website_config",
"valueList": [
"http://cdn.example.com/config/20260923/110133_AtVRHXAW.png",
"http://cdn.example.com/config/20260923/110133_8ERxsPCx.png",
"http://cdn.example.com/config/20260923/110133_lYnVEf9f.png"
]
}
}
```
## value 的类型化处理
配置项的 `value` 随 `type` 变化,保存与读取由 `HasConfigValueProcessing` Trait 统一处理,
`ConfigItemService`(配置项 CRUD)与 `ConfigService`(网站配置)共用。
文件一律落在 `config/file.php` 的 `upload_dir` 下的 `config/` 子目录。
| type | 入库 value | 详情 value | 详情 valueList |
|------|-----------|-----------|----------------|
| `image` | `config/Ymd/xxx.png`(去域名 + 临时文件迁移) | 完整 URL | `null` |
| `images` | 逗号分隔的相对路径 | 原值 | 逐个完整 URL |
| `file` / `files` | `文件名\|相对路径`(逗号分隔) | 原值 | `文件名\|完整URL` |
| `checkbox` | 逗号分隔原值 | 原值 | 拆分后的数组 |
| `ueditor` | 富文本 HTML,内嵌图片迁移为 `[IMG_URL]/config/...` 占位 | 占位还原为当前 `FILE_DOMAIN_URL` | `null` |
| 其余类型 | 原值 | 原值 | `null` |
处理规则:
- **保存**(`beforeAdd` / `beforeUpdate`):走 `save_file()` —— 去掉域名前缀、把 `temp/` 临时文件迁移到正式目录;
富文本走 `save_content()` —— 迁移内容中的图片并写入 `[IMG_URL]` 占位;
- **读取**:走 `get_file_url()` 补全域名;富文本把 `[IMG_URL]` 还原为 `FILE_DOMAIN_URL`;
- 迁移失败时保留原值,不清空字段;
- `image` 与 `ueditor` 的 `value` 直接返回可渲染值(前端回显直连 `value`),其余类型 `value` 保持原值。
## 使用场景
@@ -96,63 +155,119 @@
### 后端获取配置值
项目中没有 `ConfigService`,配置值通过 `ConfigItem` 模型直接查询:
配置值可通过 `ConfigService`(网站配置快捷接口的封装)或 `ConfigItem` 模型直接查询:
```php
<?php
use app\model\ConfigItem;
use app\model\Config;
use App\Models\ConfigItem;
use App\Models\Config;
// 获取单个配置项的值(按配置组 code + 配置项 code 查询)
$value = ConfigItem::whereHas('config', function ($query) {
$query->where('code', 'website_config')->where('is_delete', 0);
})
->where('code', 'site_name')
->where('status', 1)
->where('is_delete', 0)
->value('value');
// 返回:'RXThinkCMF'
$config = Config::where('code', 'website_config')->where('is_delete', 0)->first();
$value = $config
? ConfigItem::where('config_id', $config->id)
->where('code', 'site_name')
->where('status', 1)
->where('is_delete', 0)
->value('value')
: null;
// 返回:'My CMS'
// 获取整个配置组的所有配置项(关联数组)
$config = Config::where('code', 'website_config')->where('is_delete', 0)->find();
$config = Config::where('code', 'website_config')->where('is_delete', 0)->first();
if ($config) {
$items = ConfigItem::where('config_id', $config->id)
->where('status', 1)
->where('is_delete', 0)
->column('value', 'code');
// 返回:['site_name' => 'RXThinkCMF', 'site_logo' => '...', 'copyright' => '...']
->pluck('value', 'code');
// 返回:['site_name' => 'My CMS', 'site_logo' => '...', 'copyright' => '...']
}
```
// 通过 API 获取网站配置(推荐,含类型处理和 URL 拼接)
// GET /api/config/web/index → 返回按配置组组织的完整数据
### 网站配置快捷服务
```php
// app/Services/ConfigService.php
public function getWebConfig(): array // GET /api/config/web/index:按组返回 configId/configName/dataList(含 param、valueList)
public function saveWebConfig(array $data): void // POST /api/config/web/save:按编码批量回写,经 save_file / save_content 归一化
```
### 前端获取配置值
`GET /api/config/web/index` 返回按配置组分组的配置项数组:
```json
[
{
"configId": 1,
"configName": "网站配置",
"dataList": [
{
"id": 3, "configId": 1, "name": "网站Logo", "code": "website_logo",
"value": "http://cdn.example.com/config/20260923/110055_w3KY8kS7.png",
"valueList": null, "options": "", "type": "image",
"status": 1, "sort": 10, "note": "网站Logo", "param": null
},
{
"id": 7, "code": "website_album", "type": "images",
"value": "config/20260923/110133_AtVRHXAW.png,config/20260923/110133_8ERxsPCx.png",
"valueList": [
"http://cdn.example.com/config/20260923/110133_AtVRHXAW.png",
"http://cdn.example.com/config/20260923/110133_8ERxsPCx.png"
],
"param": null
},
{
"id": 11, "code": "website_keywords", "type": "checkbox",
"value": "1,2,5,3",
"valueList": ["1", "2", "5", "3"],
"options": "1=软件架构,2=官方网站",
"param": { "1": "软件架构", "2": "官方网站" }
}
]
}
]
```
取值约定:
- `image` 与 `ueditor` 读 `value`(返回可直接渲染的完整 URL / 富文本 HTML);
- `images` / `files` 读 `valueList`(完整 URL 串、`文件名|完整URL` 串);
- `radio` / `checkbox` / `select` 的候选项读 `param`(由 `options` 解析成键值对象);
- 其余类型的 `value` 为数据库原值,拼接 `FILE_DOMAIN_URL` 即可访问。
```typescript
// 获取网站配置
// 获取网站配置(按配置组分组)
const { data } = await http.get('/api/config/web/index')
// 使用配置值
const siteName = data.site_name
const siteLogo = data.site_logo
data.forEach((group) => {
group.dataList.forEach((item) => {
// image / ueditor 取 value,images / files 取 valueList,选项类取 param
})
})
```
### 网站配置保存接口
`POST /api/config/web/save` 的请求体为「配置项编码 => 配置值」的扁平结构,
只更新已存在的生效配置项,编码不存在时忽略;数组值(多图 / 多文件 / 复选)按逗号拼接后入库,
文件与图片同样迁移到 `config/` 子目录。
```bash
# -----------------------------------------------------------------------------
# 批量保存网站配置(按配置组 code 批量更新)
# 批量保存网站配置(key 为配置项编码)
# -----------------------------------------------------------------------------
curl -X POST http://localhost:8000/api/config/web/save \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"website": {
"site_name": "RXThinkCMF",
"site_logo": "/uploads/logo.png",
"copyright": "© 2026 RXThinkCMF"
}
"website_name": "My CMS",
"website_logo": "http://cdn.example.com/temp/20261007/123456_a1b2c3d4.png",
"website_album": [
"http://cdn.example.com/temp/20261007/123456_a1b2c3d4.png",
"http://cdn.example.com/temp/20261007/123456_e5f6a7b8.png"
],
"website_keywords": ["1", "2"]
}'
```
@@ -163,30 +278,32 @@ curl -X POST http://localhost:8000/api/config/web/save \
| 数据结构 | 分组 + 配置项(一对多) | 独立参数实体 |
| 适用场景 | 关联性强的配置(如网站配置包含多个字段) | 独立的开关、阈值 |
| 管理界面 | 按组展示,表单式编辑 | 列表式管理 |
| 获取方式 | `ConfigItem` 模型查询或 `/api/config/web/index` 接口 | `ParamService::getValue(code)` |
| 缓存策略 | 两级缓存(请求级 + Redis) | 两级缓存(请求级 + Redis) |
| 获取方式 | `ConfigItem` 模型查询或 `/api/config/web/index` 接口 | `ParamService::get(code)` |
| 服务封装 | `ConfigService`(webIndex/webSave) | `ParamService`(带缓存) |
## 数据库操作示例
```sql
-- 查询所有未删除的配置组
SELECT * FROM think_config WHERE is_delete = 0 ORDER BY sort;
SELECT * FROM laravel_config WHERE is_delete = 0 ORDER BY sort;
-- 查询某个配置组下的所有启用配置项
SELECT ci.* FROM think_config_item ci
INNER JOIN think_config c ON ci.config_id = c.id
SELECT ci.* FROM laravel_config_item ci
INNER JOIN laravel_config c ON ci.config_id = c.id
WHERE c.code = 'website_config' AND ci.status = 1 AND ci.is_delete = 0
ORDER BY ci.sort;
-- 直接更新配置项值
UPDATE think_config_item SET value = '新网站名称'
UPDATE laravel_config_item SET value = '新网站名称'
WHERE code = 'site_name' AND config_id = (
SELECT id FROM think_config WHERE code = 'website_config' AND is_delete = 0
SELECT id FROM laravel_config WHERE code = 'website_config' AND is_delete = 0
);
```
## 相关文档
- [5.12 系统参数管理](/zh/core/param.html) — 独立参数实体管理
- [5.13 系统参数管理](/zh/core/param.html) — 独立参数实体管理
- [5.10 字典模块](/zh/core/dict.html) — 枚举/字典数据管理
- [5.11 系统配置管理](/zh/core/config.html) — 本文档
- [7.1 文件上传全流程](/zh/tools/upload.html) — 配置项图片/附件的上传与临时文件迁移
- [7.3 富文本处理](/zh/tools/rich-text.html) — `[IMG_URL]` 占位符机制
- [附录 C 配置项速查](/zh/appendix/config-reference.html) — `config/*.php` 配置文件速查(与本模块的"动态配置"不同,后者存数据库)