# 5.12 系统配置管理 :::tip 概述 系统配置管理用于动态配置参数,支持分组管理。与参数管理的区别:配置管理支持键值对的分组管理(如网站配置、邮件配置),参数管理是独立的参数实体(如单个开关、阈值)。 ::: ## 模块特点 | 特性 | 说明 | |------|------| | Service 基类 | `BaseService`(系统共享,不隔离);读取封装 `ConfigService` | | 关联 | 与 ConfigItem 一对多(通过 config_id) | | 用途 | 网站名称、Logo、版权信息等动态配置 | | 控制器 | `ConfigController`(配置组)+ `ConfigItemController`(配置项) | | 值处理 | `HasConfigValueProcessing` Trait:按 type 做文件迁移与 `valueList` 生成 | ## 数据库表结构 ### 主表 `laravel_config`(配置组) | 字段 | 类型 | 说明 | |------|------|------| | id | int | 主键,自增 | | name | varchar(150) | 配置组名称(如「网站配置」) | | code | varchar(150) | 配置组编码(如 `website_config`) | | sort | int | 排序(升序) | | note | varchar(255) | 备注说明 | | create_user / create_time / update_user / update_time | | 审计字段(模型 Trait 自动写入) | | is_delete | int | 软删除标记(0=正常,1=已删除) | ### 子表 `laravel_config_item`(配置项) | 字段 | 类型 | 说明 | |------|------|------| | id | int | 主键,自增 | | config_id | int | 所属配置组 ID(关联 laravel_config.id) | | name | varchar(150) | 配置项名称(如「网站名称」) | | code | varchar(150) | 配置项编码(如 `site_name`) | | 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 / create_time / update_user / update_time | | 审计字段 | | is_delete | int | 软删除标记 | ## API 接口 ### 配置组 | 方法 | 路径 | 权限码 | 说明 | |------|------|--------|------| | GET | `/api/config/page` | sys:config:page | 分页列表 | | GET | `/api/config/list` | sys:config:list | 全量列表 | | 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/batchDelete` | sys:config:batchDelete | 批量删除 | ### 网站配置(快捷接口) | 方法 | 路径 | 权限码 | 说明 | |------|------|--------|------| | GET | `/api/config/web/index` | sys:config:webIndex | 获取网站配置(按组返回所有配置项) | | POST | `/api/config/web/save` | sys:config:update | 保存网站配置(批量更新配置项值) | ### 配置项 | 方法 | 路径 | 权限码 | 说明 | |------|------|--------|------| | 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` 保持原值。 ## 使用场景 | 场景 | 配置组 | 配置项示例 | |------|--------|----------| | 网站基本信息 | 网站配置 | 网站名称、Logo、版权信息、ICP备案号 | | 邮件配置 | 邮件配置 | SMTP服务器、端口、用户名、密码、发件人 | | 短信配置 | 短信配置 | API Key、模板ID、签名 | | 存储配置 | 存储配置 | 存储类型(本地/OSS)、AccessKey、Bucket | | 支付配置 | 支付配置 | 商户号、密钥、回调地址 | | 其他 | 自定义分组 | 任何需要后台动态配置的参数 | ## 代码示例 ### 后端获取配置值 配置值可通过 `ConfigService`(网站配置快捷接口的封装)或 `ConfigItem` 模型直接查询: ```php 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)->first(); if ($config) { $items = ConfigItem::where('config_id', $config->id) ->where('status', 1) ->where('is_delete', 0) ->pluck('value', 'code'); // 返回:['site_name' => 'My CMS', 'site_logo' => '...', 'copyright' => '...'] } ``` ### 网站配置快捷服务 ```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') data.forEach((group) => { group.dataList.forEach((item) => { // image / ueditor 取 value,images / files 取 valueList,选项类取 param }) }) ``` ### 网站配置保存接口 `POST /api/config/web/save` 的请求体为「配置项编码 => 配置值」的扁平结构, 只更新已存在的生效配置项,编码不存在时忽略;数组值(多图 / 多文件 / 复选)按逗号拼接后入库, 文件与图片同样迁移到 `config/` 子目录。 ```bash # ----------------------------------------------------------------------------- # 批量保存网站配置(key 为配置项编码) # ----------------------------------------------------------------------------- curl -X POST http://localhost:8000/api/config/web/save \ -H "Content-Type: application/json" \ -H "Authorization: Bearer " \ -d '{ "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"] }' ``` ## 与参数管理的区别 | 维度 | 配置管理(Config) | 参数管理(Param) | |------|-------------------|-------------------| | 数据结构 | 分组 + 配置项(一对多) | 独立参数实体 | | 适用场景 | 关联性强的配置(如网站配置包含多个字段) | 独立的开关、阈值 | | 管理界面 | 按组展示,表单式编辑 | 列表式管理 | | 获取方式 | `ConfigItem` 模型查询或 `/api/config/web/index` 接口 | `ParamService::get(code)` | | 服务封装 | `ConfigService`(webIndex/webSave) | `ParamService`(带缓存) | ## 数据库操作示例 ```sql -- 查询所有未删除的配置组 SELECT * FROM laravel_config WHERE is_delete = 0 ORDER BY sort; -- 查询某个配置组下的所有启用配置项 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 laravel_config_item SET value = '新网站名称' WHERE code = 'site_name' AND config_id = ( SELECT id FROM laravel_config WHERE code = 'website_config' AND is_delete = 0 ); ``` ## 相关文档 - [5.13 系统参数管理](/zh/core/param.html) — 独立参数实体管理 - [5.10 字典模块](/zh/core/dict.html) — 枚举/字典数据管理 - [7.1 文件上传全流程](/zh/tools/upload.html) — 配置项图片/附件的上传与临时文件迁移 - [7.3 富文本处理](/zh/tools/rich-text.html) — `[IMG_URL]` 占位符机制 - [附录 C 配置项速查](/zh/appendix/config-reference.html) — `config/*.php` 配置文件速查(与本模块的"动态配置"不同,后者存数据库)