Эх сурвалжийг харах

feat(config): 添加系统配置管理功能

- 新增系统配置相关实体类 TConfig
- 实现系统配置的增删改查接口功能
- 添加配置分页查询和关键字模糊匹配功能
- 集成 MyBatis-Plus 进行数据持久化操作
- 编写系统配置 API 文档
- 在 TAiStyle 实体中增加媒体类型字段
ChenYu 7 сар өмнө
parent
commit
c8edd66b34

+ 162 - 0
doc/CONFIG_API.md

@@ -0,0 +1,162 @@
+# 系统配置 API 文档
+
+本文档描述系统配置 `t_config` 相关接口。
+
+## 1. 基础信息
+
+*   **URL 前缀**: `/v2/config`
+*   **响应格式**: 统一使用 `GlobalResponseWrapper`
+
+---
+
+## 2. 接口列表
+
+### 2.1 获取全部配置
+
+*   **URL**: `/list`
+*   **Method**: `GET`
+*   **描述**: 查询全部系统配置,默认按 `configKey` 升序返回。
+
+#### 请求参数
+
+无
+
+#### 响应参数 (`data` 字段)
+
+返回 `TConfig` 对象列表,元素结构如下:
+
+| 字段名 | 类型 | 说明 |
+| :--- | :--- | :--- |
+| `configKey` | string | 配置 key,主键 |
+| `configValue` | string | 配置值 |
+| `remark` | string | 说明 |
+| `createTime` | string | 创建时间,格式:`yyyy-MM-dd HH:mm:ss` |
+| `updateTime` | string | 更新时间,格式:`yyyy-MM-dd HH:mm:ss` |
+
+#### 示例响应
+
+```json
+{
+  "code": 200,
+  "message": "success",
+  "data": [
+    {
+      "configKey": "site_name",
+      "configValue": "Aitori BI",
+      "remark": "站点名称",
+      "createTime": "2026-03-25 10:00:00",
+      "updateTime": "2026-03-25 10:00:00"
+    }
+  ]
+}
+```
+
+### 2.2 分页查询配置
+
+*   **URL**: `/page`
+*   **Method**: `GET`
+*   **描述**: 分页查询系统配置,支持按 `configKey`、`configValue`、`remark` 关键字模糊匹配。
+
+#### 请求参数
+
+| 字段名 | 类型 | 必填 | 说明 |
+| :--- | :--- | :--- | :--- |
+| `page` | integer | 否 | 页码,默认 `1` |
+| `size` | integer | 否 | 每页大小,默认 `10` |
+| `keyword` | string | 否 | 关键字,支持配置 key / 配置值 / 说明模糊匹配 |
+
+#### 响应参数 (`data` 字段)
+
+| 字段名 | 类型 | 说明 |
+| :--- | :--- | :--- |
+| `records` | array | 当前页配置列表 |
+| `total` | integer | 总记录数 |
+| `size` | integer | 每页数量 |
+| `current` | integer | 当前页码 |
+| `pages` | integer | 总页数 |
+
+### 2.3 获取配置详情
+
+*   **URL**: `/get/{configKey}`
+*   **Method**: `GET`
+*   **描述**: 根据配置 key 获取单个系统配置。
+
+#### 请求参数
+
+| 字段名 | 类型 | 必填 | 说明 |
+| :--- | :--- | :--- | :--- |
+| `configKey` | string | 是 | 配置 key |
+
+#### 响应参数 (`data` 字段)
+
+返回单个 `TConfig` 对象,字段说明同“获取全部配置”。
+
+### 2.4 新增配置
+
+*   **URL**: `/add`
+*   **Method**: `POST`
+*   **Content-Type**: `application/json`
+*   **描述**: 新增一条系统配置。`configKey` 不能为空,且不能重复。
+
+#### 请求参数 (Body)
+
+| 字段名 | 类型 | 必填 | 说明 |
+| :--- | :--- | :--- | :--- |
+| `configKey` | string | 是 | 配置 key,主键 |
+| `configValue` | string | 否 | 配置值 |
+| `remark` | string | 否 | 说明 |
+
+#### 请求示例
+
+```json
+{
+  "configKey": "site_name",
+  "configValue": "Aitori BI",
+  "remark": "站点名称"
+}
+```
+
+#### 响应参数
+
+| 类型 | 说明 |
+| :--- | :--- |
+| boolean | 操作结果 (`true/false`) |
+
+### 2.5 更新配置
+
+*   **URL**: `/update`
+*   **Method**: `PUT`
+*   **Content-Type**: `application/json`
+*   **描述**: 更新已存在的系统配置。`configKey` 不能为空,且必须已存在。
+
+#### 请求参数 (Body)
+
+| 字段名 | 类型 | 必填 | 说明 |
+| :--- | :--- | :--- | :--- |
+| `configKey` | string | 是 | 配置 key,主键 |
+| `configValue` | string | 否 | 配置值 |
+| `remark` | string | 否 | 说明 |
+
+#### 响应参数
+
+| 类型 | 说明 |
+| :--- | :--- |
+| boolean | 操作结果 (`true/false`) |
+
+### 2.6 删除配置
+
+*   **URL**: `/delete/{configKey}`
+*   **Method**: `DELETE`
+*   **描述**: 根据配置 key 删除系统配置。
+
+#### 请求参数
+
+| 字段名 | 类型 | 必填 | 说明 |
+| :--- | :--- | :--- | :--- |
+| `configKey` | string | 是 | 配置 key |
+
+#### 响应参数
+
+| 类型 | 说明 |
+| :--- | :--- |
+| boolean | 操作结果 (`true/false`) |

+ 58 - 0
src/main/java/com/aitori/controller/TConfigController.java

@@ -0,0 +1,58 @@
+package com.aitori.controller;
+
+import com.aitori.entity.TConfig;
+import com.aitori.entity.request.ConfigQueryRequest;
+import com.aitori.service.TConfigService;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/v2/config")
+@Tag(name = "系统配置管理接口")
+@RequiredArgsConstructor
+public class TConfigController {
+
+    private final TConfigService configService;
+
+    @GetMapping("/list")
+    @Operation(summary = "系统配置列表", description = "查询全部系统配置")
+    public List<TConfig> list() {
+        return configService.listAllConfigs();
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "系统配置分页", description = "分页查询系统配置,支持配置key/配置值/说明模糊匹配")
+    public IPage<TConfig> page(ConfigQueryRequest request) {
+        return configService.getConfigPage(new Page<>(request.getPage(), request.getSize()), request);
+    }
+
+    @GetMapping("/get/{configKey}")
+    @Operation(summary = "系统配置详情", description = "根据配置key获取系统配置详情")
+    public TConfig get(@PathVariable String configKey) {
+        return configService.getById(configKey);
+    }
+
+    @PostMapping("/add")
+    @Operation(summary = "新增系统配置")
+    public boolean add(@RequestBody TConfig config) {
+        return configService.saveConfig(config);
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新系统配置")
+    public boolean update(@RequestBody TConfig config) {
+        return configService.updateConfig(config);
+    }
+
+    @DeleteMapping("/delete/{configKey}")
+    @Operation(summary = "删除系统配置")
+    public boolean delete(@PathVariable String configKey) {
+        return configService.deleteByKey(configKey);
+    }
+}

+ 3 - 0
src/main/java/com/aitori/entity/TAiStyle.java

@@ -34,6 +34,9 @@ public class TAiStyle implements Serializable {
     @Schema(description = "风格封面,可以是一个视频封面")
     private String coverImg;
 
+    @Schema(description = "媒体类型:0:图片,1:视频,2:图片视频混合")
+    private String mediaType;
+
     @Schema(description = "详情图(逗号分割)")
     private String detailImg;
 

+ 40 - 0
src/main/java/com/aitori/entity/TConfig.java

@@ -0,0 +1,40 @@
+package com.aitori.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@TableName("t_config")
+@Schema(description = "系统配置表")
+public class TConfig implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "config_key", type = IdType.INPUT)
+    @Schema(description = "配置key")
+    private String configKey;
+
+    @Schema(description = "配置值")
+    private String configValue;
+
+    @Schema(description = "说明")
+    private String remark;
+
+    @TableField(fill = FieldFill.INSERT)
+    @Schema(description = "创建时间")
+    private LocalDateTime createTime;
+
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @Schema(description = "更新时间")
+    private LocalDateTime updateTime;
+}

+ 20 - 0
src/main/java/com/aitori/entity/request/ConfigQueryRequest.java

@@ -0,0 +1,20 @@
+package com.aitori.entity.request;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@Schema(description = "系统配置分页查询请求")
+public class ConfigQueryRequest implements Serializable {
+
+    @Schema(description = "页码", defaultValue = "1")
+    private Integer page = 1;
+
+    @Schema(description = "每页大小", defaultValue = "10")
+    private Integer size = 10;
+
+    @Schema(description = "搜索关键字,支持配置key/配置值/说明模糊匹配")
+    private String keyword;
+}

+ 7 - 0
src/main/java/com/aitori/mapper/TConfigMapper.java

@@ -0,0 +1,7 @@
+package com.aitori.mapper;
+
+import com.aitori.entity.TConfig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface TConfigMapper extends BaseMapper<TConfig> {
+}

+ 21 - 0
src/main/java/com/aitori/service/TConfigService.java

@@ -0,0 +1,21 @@
+package com.aitori.service;
+
+import com.aitori.entity.TConfig;
+import com.aitori.entity.request.ConfigQueryRequest;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+public interface TConfigService extends IService<TConfig> {
+    List<TConfig> listAllConfigs();
+
+    IPage<TConfig> getConfigPage(Page<TConfig> page, ConfigQueryRequest request);
+
+    boolean saveConfig(TConfig config);
+
+    boolean updateConfig(TConfig config);
+
+    boolean deleteByKey(String configKey);
+}

+ 74 - 0
src/main/java/com/aitori/service/impl/TConfigServiceImpl.java

@@ -0,0 +1,74 @@
+package com.aitori.service.impl;
+
+import com.aitori.entity.TConfig;
+import com.aitori.entity.request.ConfigQueryRequest;
+import com.aitori.mapper.TConfigMapper;
+import com.aitori.service.TConfigService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class TConfigServiceImpl extends ServiceImpl<TConfigMapper, TConfig> implements TConfigService {
+
+    @Override
+    public List<TConfig> listAllConfigs() {
+        LambdaQueryWrapper<TConfig> wrapper = new LambdaQueryWrapper<>();
+        wrapper.orderByAsc(TConfig::getConfigKey);
+        return this.list(wrapper);
+    }
+
+    @Override
+    public IPage<TConfig> getConfigPage(Page<TConfig> page, ConfigQueryRequest request) {
+        LambdaQueryWrapper<TConfig> wrapper = new LambdaQueryWrapper<>();
+        wrapper.and(StringUtils.isNotBlank(request.getKeyword()), q -> q
+                .like(TConfig::getConfigKey, request.getKeyword())
+                .or()
+                .like(TConfig::getConfigValue, request.getKeyword())
+                .or()
+                .like(TConfig::getRemark, request.getKeyword()));
+        wrapper.orderByDesc(TConfig::getUpdateTime)
+                .orderByDesc(TConfig::getCreateTime);
+        return this.page(page, wrapper);
+    }
+
+    @Override
+    public boolean saveConfig(TConfig config) {
+        String configKey = normalizeConfigKey(config);
+        if (this.getById(configKey) != null) {
+            throw new IllegalArgumentException("配置key已存在: " + configKey);
+        }
+        return this.save(config);
+    }
+
+    @Override
+    public boolean updateConfig(TConfig config) {
+        String configKey = normalizeConfigKey(config);
+        if (this.getById(configKey) == null) {
+            throw new IllegalArgumentException("配置不存在: " + configKey);
+        }
+        return this.updateById(config);
+    }
+
+    @Override
+    public boolean deleteByKey(String configKey) {
+        if (StringUtils.isBlank(configKey)) {
+            throw new IllegalArgumentException("配置key不能为空");
+        }
+        return this.removeById(configKey.trim());
+    }
+
+    private String normalizeConfigKey(TConfig config) {
+        if (config == null || StringUtils.isBlank(config.getConfigKey())) {
+            throw new IllegalArgumentException("配置key不能为空");
+        }
+        String configKey = config.getConfigKey().trim();
+        config.setConfigKey(configKey);
+        return configKey;
+    }
+}