系统配置
This commit is contained in:
@@ -32,10 +32,20 @@ DROP TABLE IF EXISTS `tb_sys_config`;
|
||||
CREATE TABLE `tb_sys_config` (
|
||||
`id` VARCHAR(50) NOT NULL COMMENT '配置ID',
|
||||
`config_key` VARCHAR(100) NOT NULL COMMENT '配置键',
|
||||
`config_name` VARCHAR(100) DEFAULT NULL COMMENT '配置显示名称',
|
||||
`config_value` TEXT COMMENT '配置值',
|
||||
`config_type` VARCHAR(50) DEFAULT 'string' COMMENT '配置类型(string/number/boolean/json)',
|
||||
`config_type` VARCHAR(50) DEFAULT 'string' COMMENT '数据类型(string/number/boolean/json)',
|
||||
`render_type` VARCHAR(20) DEFAULT NULL COMMENT '前端渲染类型(input/textarea/number/switch/select/password)',
|
||||
`config_group` VARCHAR(50) DEFAULT NULL COMMENT '配置分组',
|
||||
`description` VARCHAR(255) DEFAULT NULL COMMENT '配置描述',
|
||||
`placeholder` VARCHAR(200) DEFAULT NULL COMMENT '输入框占位符',
|
||||
`remark` VARCHAR(500) DEFAULT NULL COMMENT '备注说明(显示在表单项下方)',
|
||||
`rows` INT DEFAULT NULL COMMENT '文本框行数(textarea用)',
|
||||
`min_value` INT DEFAULT NULL COMMENT '最小值(number用)',
|
||||
`max_value` INT DEFAULT NULL COMMENT '最大值(number用)',
|
||||
`unit` VARCHAR(20) DEFAULT NULL COMMENT '单位(number用)',
|
||||
`options` TEXT COMMENT '下拉选项(select用,JSON格式)',
|
||||
`order_num` INT DEFAULT 0 COMMENT '排序号',
|
||||
`is_system` TINYINT(1) DEFAULT 0 COMMENT '是否系统配置',
|
||||
`creator` VARCHAR(50) DEFAULT NULL COMMENT '创建者',
|
||||
`updater` VARCHAR(50) DEFAULT NULL COMMENT '更新者',
|
||||
@@ -45,7 +55,8 @@ CREATE TABLE `tb_sys_config` (
|
||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_config_key` (`config_key`),
|
||||
KEY `idx_group` (`config_group`)
|
||||
KEY `idx_group` (`config_group`),
|
||||
KEY `idx_order` (`order_num`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统配置表';
|
||||
|
||||
|
||||
|
||||
@@ -25,22 +25,9 @@ INSERT INTO `tb_tag` (id, tag_id, name, color, description, tag_type, creator, c
|
||||
('tag205', 'tag_task_005', '阶段任务', '#2d98da', '阶段性学习任务', 3, '1', now());
|
||||
|
||||
-- 插入系统配置数据
|
||||
INSERT INTO `tb_sys_config` (id, config_key, config_value, config_type, config_group, description, is_system, creator, create_time) VALUES
|
||||
('1', 'system.platform.name', '思政学习平台', 'string', 'platform', '平台名称', 1, '1', now()),
|
||||
('2', 'system.platform.logo', '/assets/logo.png', 'string', 'platform', '平台Logo', 1, '1', now()),
|
||||
('3', 'system.platform.school_badge', '/assets/school_badge.png', 'string', 'platform', '学校校徽', 1, '1', now()),
|
||||
('4', 'system.menu.home', '首页', 'string', 'menu', '首页菜单名称', 0, '1', now()),
|
||||
('5', 'system.menu.resource', '资源中心', 'string', 'menu', '资源中心菜单名称', 0, '1', now()),
|
||||
('6', 'system.menu.learning', '学习计划', 'string', 'menu', '学习计划菜单名称', 0, '1', now()),
|
||||
('7', 'system.menu.activity', '专题活动', 'string', 'menu', '专题活动菜单名称', 0, '1', now()),
|
||||
('8', 'system.menu.culture', '红色常信', 'string', 'menu', '红色常信菜单名称', 0, '1', now()),
|
||||
('9', 'system.banner.auto_play', 'true', 'boolean', 'banner', 'Banner自动播放', 0, '1', now()),
|
||||
('10', 'system.banner.interval', '5000', 'number', 'banner', 'Banner切换间隔(毫秒)', 0, '1', now()),
|
||||
('11', 'system.resource.auto_publish', 'false', 'boolean', 'resource', '资源自动发布', 0, '1', now()),
|
||||
('12', 'system.resource.auto_publish_time', '08:00', 'string', 'resource', '自动发布时间', 0, '1', now()),
|
||||
('13', 'system.ai.enabled', 'true', 'boolean', 'ai', '是否启用智能体', 0, '1', now()),
|
||||
('14', 'crawler.pythonPath', 'F:/Environment/Conda/envs/schoolNewsCrawler/python.exe', 'string', 'crawler', 'Python可执行文件路径', 1, '1', now()),
|
||||
('15', 'crawler.basePath', 'F:/Project/schoolNews/schoolNewsCrawler', 'string', 'crawler', '爬虫脚本根目录', 1, '1', now());
|
||||
INSERT INTO `tb_sys_config` (`id`, `config_key`, `config_name`, `config_value`, `config_type`, `render_type`, `config_group`, `description`, `placeholder`, `remark`, `rows`, `min_value`, `max_value`, `unit`, `options`, `order_num`, `is_system`, `creator`, `create_time`) VALUES
|
||||
('1', 'crawler.pythonPath', 'Python路径', 'F:/Environment/Conda/envs/schoolNewsCrawler/python.exe', 'string', 'input', '爬虫配置', 'Python可执行文件路径', '请输入Python可执行文件完整路径', '爬虫使用的Python解释器路径', NULL, NULL, NULL, NULL, NULL, 1, 1, '1', now()),
|
||||
('2', 'crawler.basePath', '爬虫根目录', 'F:/Project/schoolNews/schoolNewsCrawler', 'string', 'input', '爬虫配置', '爬虫脚本根目录', '请输入爬虫脚本根目录路径', '爬虫脚本文件的根目录', NULL, NULL, NULL, NULL, NULL, 2, 1, '1', now());
|
||||
|
||||
-- 注意:默认superadmin用户已在 initMenuData.sql 中创建,此处无需重复创建
|
||||
|
||||
|
||||
@@ -157,12 +157,11 @@ INSERT INTO `tb_sys_menu` VALUES
|
||||
('6000', 'menu_admin_ai_manage', '智能体管理', NULL, '', '', 'admin/agent.svg', 6, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:52:50', NULL, 0),
|
||||
('6002', 'menu_admin_ai_config', 'AI配置', 'menu_admin_ai_manage', '/admin/manage/ai/config', 'admin/manage/ai/AIConfigView', NULL, 2, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('6003', 'menu_admin_knowledge', '知识库管理', 'menu_admin_ai_manage', '/admin/manage/ai/knowledge', 'admin/manage/ai/KnowledgeManagementView', NULL, 3, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('7000', 'menu_admin_logs_manage', '系统日志', NULL, '', '', 'admin/logs.svg', 7, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:52:53', NULL, 0),
|
||||
('7000', 'menu_admin_logs_manage', '系统日志', 'menu_sys_manage', '', '', NULL, 6, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:52:53', NULL, 0),
|
||||
('7001', 'menu_admin_system_logs', '系统日志', 'menu_admin_logs_manage', '/admin/manage/logs/system', 'admin/manage/logs/SystemLogsView', NULL, 1, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('7002', 'menu_admin_login_logs', '登录日志', 'menu_admin_logs_manage', '/admin/manage/logs/login', 'admin/manage/logs/LoginLogsView', NULL, 2, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
-- ('7003', 'menu_admin_operation_logs', '操作日志', 'menu_admin_logs_manage', '/admin/manage/logs/operation', 'admin/manage/logs/OperationLogsView', NULL, 3, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
-- ('7004', 'menu_admin_system_config', '系统配置', 'menu_admin_logs_manage', '/admin/manage/logs/config', 'admin/manage/logs/SystemConfigView', NULL, 4, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('8000', 'menu_admin_crontab_manage', '定时任务管理', NULL, '', '', NULL, 8, 0, 'SidebarLayout', '1', '/admin/crontab.svg', '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('7003', 'menu_admin_system_config', '系统配置', 'menu_sys_manage', '/admin/manage/system/config', 'admin/manage/system/SystemConfigView', NULL, 7, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('8000', 'menu_admin_crontab_manage', '定时任务管理', NULL, '', '', 'admin/crontab.svg', 8, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('8002', 'menu_admin_crontab_log', '执行日志', 'menu_admin_crontab_manage', '/admin/manage/crontab/log', 'admin/manage/crontab/LogManagementView', NULL, 2, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('8003', 'menu_admin_news_crawler', '新闻爬虫配置', 'menu_admin_crontab_manage', '/admin/manage/crontab/news-crawler', 'admin/manage/crontab/NewsCrawlerView', NULL, 3, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
-- 消息通知模块菜单 (9000-9999)
|
||||
@@ -170,6 +169,7 @@ INSERT INTO `tb_sys_menu` VALUES
|
||||
-- 用户端消息中心菜单 (650-699)
|
||||
('650', 'menu_user_message_center', '消息中心', NULL, '/user/message', 'user/message/MyMessageListView', NULL, 7, 1, 'NavigationLayout', '1', NULL, '2025-11-13 10:00:00', '2025-11-13 10:00:00', NULL, 0),
|
||||
('651', 'menu_user_message_detail', '消息详情', 'menu_user_message_center', '/user/message/detail/:messageID', 'user/message/MyMessageDetailView', NULL, 1, 3, 'NavigationLayout', '1', NULL, '2025-11-13 10:00:00', '2025-11-13 10:00:00', NULL, 0);
|
||||
|
||||
-- 插入菜单权限关联数据
|
||||
INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, create_time) VALUES
|
||||
-- 前端菜单权限关联
|
||||
@@ -223,7 +223,6 @@ INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, creat
|
||||
('227', 'perm_system_manage', 'menu_admin_logs_manage', '1', now()),
|
||||
('228', 'perm_system_manage', 'menu_admin_system_logs', '1', now()),
|
||||
('229', 'perm_system_manage', 'menu_admin_login_logs', '1', now()),
|
||||
('230', 'perm_system_manage', 'menu_admin_operation_logs', '1', now()),
|
||||
('231', 'perm_system_manage', 'menu_admin_system_config', '1', now()),
|
||||
|
||||
-- 定时任务管理菜单权限关联
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package org.xyzh.api.system.config;
|
||||
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.dto.system.TbSysConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description 系统配置服务
|
||||
* @filename SysConfigService.java
|
||||
@@ -9,6 +16,8 @@ package org.xyzh.api.system.config;
|
||||
*/
|
||||
public interface SysConfigService {
|
||||
|
||||
// ==================== 配置读取接口(业务代码使用) ====================
|
||||
|
||||
Object getSysConfig(String key);
|
||||
|
||||
/**
|
||||
@@ -45,4 +54,62 @@ public interface SysConfigService {
|
||||
* @return 配置值,如果不存在或解析失败返回null
|
||||
*/
|
||||
Long getLongConfig(String key);
|
||||
|
||||
// ==================== 配置管理接口(管理界面使用) ====================
|
||||
|
||||
/**
|
||||
* 获取所有配置项
|
||||
* @return 配置项列表
|
||||
*/
|
||||
ResultDomain<TbSysConfig> getAllConfigs();
|
||||
|
||||
/**
|
||||
* 根据分组获取配置项
|
||||
* @param groupKey 分组键
|
||||
* @return 配置项列表
|
||||
*/
|
||||
ResultDomain<TbSysConfig> getConfigsByGroup(String groupKey);
|
||||
|
||||
/**
|
||||
* 批量保存配置项(仅更新值)
|
||||
* @param configs 配置项列表
|
||||
* @return 保存结果
|
||||
*/
|
||||
ResultDomain<Boolean> batchSaveConfigs(List<Map<String, String>> configs);
|
||||
|
||||
/**
|
||||
* 创建配置项
|
||||
* @param config 配置项
|
||||
* @return 创建结果
|
||||
*/
|
||||
ResultDomain<Boolean> createConfig(TbSysConfig config);
|
||||
|
||||
/**
|
||||
* 更新配置项
|
||||
* @param config 配置项
|
||||
* @return 更新结果
|
||||
*/
|
||||
ResultDomain<Boolean> updateConfig(TbSysConfig config);
|
||||
|
||||
/**
|
||||
* 删除配置项
|
||||
* @param id 配置ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
ResultDomain<Boolean> deleteConfig(String id);
|
||||
|
||||
/**
|
||||
* 分页查询配置项
|
||||
* @param filter 查询条件
|
||||
* @param pageParam 分页参数
|
||||
* @return 配置项分页列表
|
||||
*/
|
||||
ResultDomain<TbSysConfig> getConfigPage(TbSysConfig filter, PageParam pageParam);
|
||||
|
||||
/**
|
||||
* 根据ID获取配置项
|
||||
* @param id 配置ID
|
||||
* @return 配置项详情
|
||||
*/
|
||||
ResultDomain<TbSysConfig> getConfigById(String id);
|
||||
}
|
||||
|
||||
@@ -18,16 +18,26 @@ public class TbSysConfig extends BaseDTO {
|
||||
*/
|
||||
private String configKey;
|
||||
|
||||
/**
|
||||
* @description 配置显示名称
|
||||
*/
|
||||
private String configName;
|
||||
|
||||
/**
|
||||
* @description 配置值
|
||||
*/
|
||||
private String configValue;
|
||||
|
||||
/**
|
||||
* @description 配置类型(string/number/boolean/json)
|
||||
* @description 数据类型(string/number/boolean/json)
|
||||
*/
|
||||
private String configType;
|
||||
|
||||
/**
|
||||
* @description 前端渲染类型(input/textarea/number/switch/select/password)
|
||||
*/
|
||||
private String renderType;
|
||||
|
||||
/**
|
||||
* @description 配置分组
|
||||
*/
|
||||
@@ -38,6 +48,46 @@ public class TbSysConfig extends BaseDTO {
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* @description 输入框占位符
|
||||
*/
|
||||
private String placeholder;
|
||||
|
||||
/**
|
||||
* @description 备注说明(显示在表单项下方)
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* @description 文本框行数(textarea用)
|
||||
*/
|
||||
private Integer rows;
|
||||
|
||||
/**
|
||||
* @description 最小值(number用)
|
||||
*/
|
||||
private Integer minValue;
|
||||
|
||||
/**
|
||||
* @description 最大值(number用)
|
||||
*/
|
||||
private Integer maxValue;
|
||||
|
||||
/**
|
||||
* @description 单位(number用)
|
||||
*/
|
||||
private String unit;
|
||||
|
||||
/**
|
||||
* @description 下拉选项(select用,JSON格式)
|
||||
*/
|
||||
private String options;
|
||||
|
||||
/**
|
||||
* @description 排序号
|
||||
*/
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* @description 是否系统配置
|
||||
*/
|
||||
@@ -117,14 +167,97 @@ public class TbSysConfig extends BaseDTO {
|
||||
this.updater = updater;
|
||||
}
|
||||
|
||||
public String getConfigName() {
|
||||
return configName;
|
||||
}
|
||||
|
||||
public void setConfigName(String configName) {
|
||||
this.configName = configName;
|
||||
}
|
||||
|
||||
public String getRenderType() {
|
||||
return renderType;
|
||||
}
|
||||
|
||||
public void setRenderType(String renderType) {
|
||||
this.renderType = renderType;
|
||||
}
|
||||
|
||||
public String getPlaceholder() {
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
public void setPlaceholder(String placeholder) {
|
||||
this.placeholder = placeholder;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public Integer getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void setRows(Integer rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
public Integer getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
public void setMinValue(Integer minValue) {
|
||||
this.minValue = minValue;
|
||||
}
|
||||
|
||||
public Integer getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
public void setMaxValue(Integer maxValue) {
|
||||
this.maxValue = maxValue;
|
||||
}
|
||||
|
||||
public String getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public void setUnit(String unit) {
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public String getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(String options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public Integer getOrderNum() {
|
||||
return orderNum;
|
||||
}
|
||||
|
||||
public void setOrderNum(Integer orderNum) {
|
||||
this.orderNum = orderNum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TbSysConfig{" +
|
||||
"id=" + getID() +
|
||||
", configKey='" + configKey + '\'' +
|
||||
", configName='" + configName + '\'' +
|
||||
", configValue='" + configValue + '\'' +
|
||||
", configType='" + configType + '\'' +
|
||||
", renderType='" + renderType + '\'' +
|
||||
", configGroup='" + configGroup + '\'' +
|
||||
", orderNum=" + orderNum +
|
||||
", isSystem=" + isSystem +
|
||||
'}';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.xyzh.system.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.xyzh.api.system.config.SysConfigService;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
import org.xyzh.common.dto.system.TbSysConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description 系统配置管理控制器
|
||||
* @filename ConfigController.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/config")
|
||||
public class ConfigController {
|
||||
|
||||
@Autowired
|
||||
private SysConfigService sysConfigService;
|
||||
|
||||
/**
|
||||
* @description 获取所有配置项(前端配置视图使用)
|
||||
* @return ResultDomain<TbSysConfig> 配置项列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public ResultDomain<TbSysConfig> getAllConfigs() {
|
||||
return sysConfigService.getAllConfigs();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据分组获取配置项
|
||||
* @param groupKey 分组键
|
||||
* @return ResultDomain<TbSysConfig> 配置项列表
|
||||
*/
|
||||
@GetMapping("/group/{groupKey}")
|
||||
public ResultDomain<TbSysConfig> getConfigsByGroup(@PathVariable String groupKey) {
|
||||
return sysConfigService.getConfigsByGroup(groupKey);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description 保存配置项(批量保存)
|
||||
* @param configs 配置项列表
|
||||
* @return ResultDomain<Boolean> 保存结果
|
||||
*/
|
||||
@PostMapping("/save")
|
||||
public ResultDomain<Boolean> saveConfigs(@RequestBody List<Map<String, String>> configs) {
|
||||
return sysConfigService.batchSaveConfigs(configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 创建单个配置项
|
||||
* @param config 配置项
|
||||
* @return ResultDomain<Boolean> 创建结果
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public ResultDomain<Boolean> createConfig(@RequestBody TbSysConfig config) {
|
||||
return sysConfigService.createConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 更新单个配置项
|
||||
* @param config 配置项
|
||||
* @return ResultDomain<Boolean> 更新结果
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
public ResultDomain<Boolean> updateConfig(@RequestBody TbSysConfig config) {
|
||||
return sysConfigService.updateConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除配置项
|
||||
* @param id 配置ID
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResultDomain<Boolean> deleteConfig(@PathVariable String id) {
|
||||
return sysConfigService.deleteConfig(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分页查询配置项
|
||||
* @param pageRequest 分页请求
|
||||
* @return ResultDomain<TbSysConfig> 配置项分页列表
|
||||
*/
|
||||
@PostMapping("/page")
|
||||
public ResultDomain<TbSysConfig> getConfigPage(@RequestBody PageRequest<TbSysConfig> pageRequest) {
|
||||
return sysConfigService.getConfigPage(pageRequest.getFilter(), pageRequest.getPageParam());
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据ID获取配置项详情
|
||||
* @param id 配置ID
|
||||
* @return ResultDomain<TbSysConfig> 配置项详情
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResultDomain<TbSysConfig> getConfigById(@PathVariable String id) {
|
||||
return sysConfigService.getConfigById(id);
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,16 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.xyzh.api.system.config.SysConfigService;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageDomain;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.dto.system.TbSysConfig;
|
||||
import org.xyzh.system.mapper.SysConfigMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @description 系统配置服务实现
|
||||
* @author AI Assistant
|
||||
@@ -205,4 +212,163 @@ public class SysConfigServiceImpl implements SysConfigService {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 配置管理接口实现 ====================
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysConfig> getAllConfigs() {
|
||||
ResultDomain<TbSysConfig> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
List<TbSysConfig> configs = sysConfigMapper.selectAllSysConfig();
|
||||
resultDomain.success("查询成功", configs);
|
||||
return resultDomain;
|
||||
} catch (Exception e) {
|
||||
logger.error("获取所有配置失败", e);
|
||||
resultDomain.fail("获取配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysConfig> getConfigsByGroup(String groupKey) {
|
||||
ResultDomain<TbSysConfig> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
List<TbSysConfig> configs = sysConfigMapper.selectSysConfigByGroup(groupKey);
|
||||
resultDomain.success("查询成功", configs);
|
||||
return resultDomain;
|
||||
} catch (Exception e) {
|
||||
logger.error("根据分组获取配置失败: {}", groupKey, e);
|
||||
resultDomain.fail("获取配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<Boolean> batchSaveConfigs(List<Map<String, String>> configs) {
|
||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
for (Map<String, String> configMap : configs) {
|
||||
String configKey = configMap.get("configKey");
|
||||
String configValue = configMap.get("configValue");
|
||||
|
||||
TbSysConfig existingConfig = sysConfigMapper.selectSysConfigByKey(configKey);
|
||||
if (existingConfig != null) {
|
||||
existingConfig.setConfigValue(configValue);
|
||||
sysConfigMapper.updateSysConfig(existingConfig);
|
||||
} else {
|
||||
logger.warn("配置项不存在,跳过: {}", configKey);
|
||||
}
|
||||
}
|
||||
resultDomain.success("保存成功", true);
|
||||
return resultDomain;
|
||||
} catch (Exception e) {
|
||||
logger.error("批量保存配置失败", e);
|
||||
resultDomain.fail("保存配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<Boolean> createConfig(TbSysConfig config) {
|
||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
TbSysConfig existingConfig = sysConfigMapper.selectSysConfigByKey(config.getConfigKey());
|
||||
if (existingConfig != null) {
|
||||
resultDomain.fail("配置键已存在: " + config.getConfigKey());
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (config.getID() == null || config.getID().isEmpty()) {
|
||||
config.setID(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
int result = sysConfigMapper.insertSysConfig(config);
|
||||
if (result > 0) {
|
||||
resultDomain.success("创建成功", true);
|
||||
return resultDomain;
|
||||
} else {
|
||||
resultDomain.fail("创建配置失败");
|
||||
return resultDomain;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("创建配置失败", e);
|
||||
resultDomain.fail("创建配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<Boolean> updateConfig(TbSysConfig config) {
|
||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
int result = sysConfigMapper.updateSysConfig(config);
|
||||
if (result > 0) {
|
||||
resultDomain.success("更新成功", true);
|
||||
return resultDomain;
|
||||
} else {
|
||||
resultDomain.fail("更新配置失败");
|
||||
return resultDomain;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("更新配置失败", e);
|
||||
resultDomain.fail("更新配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<Boolean> deleteConfig(String id) {
|
||||
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
int result = sysConfigMapper.deleteSysConfig(id);
|
||||
if (result > 0) {
|
||||
resultDomain.success("删除成功", true);
|
||||
return resultDomain;
|
||||
} else {
|
||||
resultDomain.fail("删除配置失败");
|
||||
return resultDomain;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("删除配置失败: {}", id, e);
|
||||
resultDomain.fail("删除配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysConfig> getConfigPage(TbSysConfig filter, PageParam pageParam) {
|
||||
ResultDomain<TbSysConfig> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
int total = sysConfigMapper.countSelectSysConfig(filter);
|
||||
List<TbSysConfig> configs = sysConfigMapper.selectSysConfigPage(filter, pageParam);
|
||||
pageParam.setTotalElements(total);
|
||||
pageParam.setTotalPages((int) Math.ceil((double) total / pageParam.getPageSize()));
|
||||
PageDomain<TbSysConfig> pageDomain = new PageDomain<>(pageParam,configs);
|
||||
resultDomain.success("查询成功", pageDomain);
|
||||
return resultDomain;
|
||||
} catch (Exception e) {
|
||||
logger.error("分页查询配置失败", e);
|
||||
resultDomain.fail("查询配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysConfig> getConfigById(String id) {
|
||||
ResultDomain<TbSysConfig> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
TbSysConfig config = sysConfigMapper.selectSysConfigById(id);
|
||||
if (config != null) {
|
||||
resultDomain.success("查询成功", config);
|
||||
return resultDomain;
|
||||
} else {
|
||||
resultDomain.fail("配置不存在");
|
||||
return resultDomain;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("根据ID获取配置失败: {}", id, e);
|
||||
resultDomain.fail("获取配置失败: " + e.getMessage());
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,20 @@
|
||||
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.system.TbSysConfig">
|
||||
<id column="id" property="ID" />
|
||||
<result column="config_key" property="configKey" />
|
||||
<result column="config_name" property="configName" />
|
||||
<result column="config_value" property="configValue" />
|
||||
<result column="config_type" property="configType" />
|
||||
<result column="render_type" property="renderType" />
|
||||
<result column="config_group" property="configGroup" />
|
||||
<result column="description" property="description" />
|
||||
<result column="placeholder" property="placeholder" />
|
||||
<result column="remark" property="remark" />
|
||||
<result column="rows" property="rows" />
|
||||
<result column="min_value" property="minValue" />
|
||||
<result column="max_value" property="maxValue" />
|
||||
<result column="unit" property="unit" />
|
||||
<result column="options" property="options" />
|
||||
<result column="order_num" property="orderNum" />
|
||||
<result column="is_system" property="isSystem" />
|
||||
<result column="creator" property="creator" />
|
||||
<result column="updater" property="updater" />
|
||||
@@ -21,7 +31,8 @@
|
||||
|
||||
<!-- 字段列表 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, config_key, config_value, config_type, config_group, description,
|
||||
id, config_key, config_name, config_value, config_type, render_type, config_group,
|
||||
description, placeholder, remark, `rows`, min_value, max_value, unit, `options`, order_num,
|
||||
is_system, creator, updater, create_time, update_time, delete_time, deleted
|
||||
</sql>
|
||||
|
||||
@@ -47,22 +58,35 @@
|
||||
<!-- 插入系统配置 -->
|
||||
<insert id="insertSysConfig" parameterType="org.xyzh.common.dto.system.TbSysConfig">
|
||||
INSERT INTO tb_sys_config (
|
||||
id, config_key, config_value, config_type, config_group, description,
|
||||
id, config_key, config_name, config_value, config_type, render_type, config_group,
|
||||
description, placeholder, remark, `rows`, min_value, max_value, unit, `options`, order_num,
|
||||
is_system, creator, create_time
|
||||
) VALUES (
|
||||
#{config.ID}, #{config.configKey}, #{config.configValue}, #{config.configType},
|
||||
#{config.configGroup}, #{config.description}, #{config.isSystem},
|
||||
#{config.creator}, NOW()
|
||||
#{config.ID}, #{config.configKey}, #{config.configName}, #{config.configValue},
|
||||
#{config.configType}, #{config.renderType}, #{config.configGroup}, #{config.description},
|
||||
#{config.placeholder}, #{config.remark}, #{config.rows}, #{config.minValue},
|
||||
#{config.maxValue}, #{config.unit}, #{config.options}, #{config.orderNum},
|
||||
#{config.isSystem}, #{config.creator}, NOW()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 更新系统配置 -->
|
||||
<update id="updateSysConfig" parameterType="org.xyzh.common.dto.system.TbSysConfig">
|
||||
UPDATE tb_sys_config
|
||||
SET config_value = #{config.configValue},
|
||||
SET config_name = #{config.configName},
|
||||
config_value = #{config.configValue},
|
||||
config_type = #{config.configType},
|
||||
render_type = #{config.renderType},
|
||||
config_group = #{config.configGroup},
|
||||
description = #{config.description},
|
||||
placeholder = #{config.placeholder},
|
||||
remark = #{config.remark},
|
||||
`rows` = #{config.rows},
|
||||
min_value = #{config.minValue},
|
||||
max_value = #{config.maxValue},
|
||||
unit = #{config.unit},
|
||||
`options` = #{config.options},
|
||||
order_num = #{config.orderNum},
|
||||
is_system = #{config.isSystem},
|
||||
updater = #{config.updater},
|
||||
update_time = NOW()
|
||||
@@ -100,7 +124,7 @@
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM tb_sys_config
|
||||
WHERE deleted = 0
|
||||
ORDER BY config_group, config_key
|
||||
ORDER BY config_group, order_num, config_key
|
||||
</select>
|
||||
|
||||
<!-- 根据分组查询 -->
|
||||
@@ -109,7 +133,7 @@
|
||||
FROM tb_sys_config
|
||||
WHERE config_group = #{configGroup}
|
||||
AND deleted = 0
|
||||
ORDER BY config_key
|
||||
ORDER BY order_num, config_key
|
||||
</select>
|
||||
|
||||
<!-- 查询系统配置列表 -->
|
||||
@@ -117,7 +141,7 @@
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM tb_sys_config
|
||||
<include refid="Base_Where_Clause" />
|
||||
ORDER BY config_group, config_key
|
||||
ORDER BY config_group, order_num, config_key
|
||||
</select>
|
||||
|
||||
<!-- 分页查询 -->
|
||||
@@ -125,7 +149,7 @@
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM tb_sys_config
|
||||
<include refid="Base_Where_Clause" />
|
||||
ORDER BY config_group, config_key
|
||||
ORDER BY config_group, order_num, config_key
|
||||
LIMIT #{pageParam.offset}, #{pageParam.pageSize}
|
||||
</select>
|
||||
|
||||
|
||||
62
schoolNewsWeb/src/apis/system/config.ts
Normal file
62
schoolNewsWeb/src/apis/system/config.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @description 系统配置相关API
|
||||
* @author yslg
|
||||
* @since 2025-11-18
|
||||
*/
|
||||
|
||||
import { api } from '@/apis/index';
|
||||
import type { ResultDomain } from '@/types';
|
||||
import type { ConfigItem, SaveConfigParam } from '@/types/system/config';
|
||||
/**
|
||||
* 系统配置API服务
|
||||
*/
|
||||
export const configApi = {
|
||||
/**
|
||||
* 获取所有配置项
|
||||
* @returns Promise<ResultDomain<ConfigItem[]>>
|
||||
*/
|
||||
async getConfigs(): Promise<ResultDomain<ConfigItem[]>> {
|
||||
const response = await api.get<ConfigItem[]>('/system/config/list');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据分组获取配置项
|
||||
* @param groupKey 配置分组key
|
||||
* @returns Promise<ResultDomain<ConfigItem[]>>
|
||||
*/
|
||||
async getConfigsByGroup(groupKey: string): Promise<ResultDomain<ConfigItem[]>> {
|
||||
const response = await api.get<ConfigItem[]>(`/system/config/group/${groupKey}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存配置项
|
||||
* @param configs 配置项列表
|
||||
* @returns Promise<ResultDomain<boolean>>
|
||||
*/
|
||||
async saveConfigs(configs: SaveConfigParam[]): Promise<ResultDomain<boolean>> {
|
||||
const response = await api.post<boolean>('/system/config/save', configs);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据配置键获取配置值
|
||||
* @param configKey 配置键
|
||||
* @returns Promise<ResultDomain<string>>
|
||||
*/
|
||||
async getConfigValue(configKey: string): Promise<ResultDomain<string>> {
|
||||
const response = await api.get<string>(`/system/config/value/${configKey}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除配置项
|
||||
* @param configKey 配置键
|
||||
* @returns Promise<ResultDomain<boolean>>
|
||||
*/
|
||||
async deleteConfig(configKey: string): Promise<ResultDomain<boolean>> {
|
||||
const response = await api.delete<boolean>(`/system/config/${configKey}`);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
@@ -14,4 +14,5 @@ export { authApi } from './auth';
|
||||
export { fileApi } from './file';
|
||||
export { moduleApi } from './module';
|
||||
export { logApi } from './log';
|
||||
export { configApi} from './config';
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* @since 2025-10-06
|
||||
*/
|
||||
|
||||
import { SysUser, SysUserInfo } from '../user';
|
||||
import { SysUser, SysUserInfo } from '../system/user';
|
||||
import { UserDeptRoleVO } from '../dept';
|
||||
import { SysPermission } from '../permission';
|
||||
import { SysMenu } from '../menu';
|
||||
import { SysPermission } from '../system/permission';
|
||||
import { SysMenu } from '../system/menu';
|
||||
import { LoginType } from '../enums';
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
import { BaseDTO } from '../base';
|
||||
import { SysRole } from '../role';
|
||||
import { SysUserDeptRole } from '../user';
|
||||
import { SysRole } from '../system/role';
|
||||
import { SysUserDeptRole } from '../system/user';
|
||||
|
||||
/**
|
||||
* 系统部门
|
||||
|
||||
@@ -8,22 +8,22 @@
|
||||
export * from './base';
|
||||
|
||||
// 用户相关
|
||||
export * from './user';
|
||||
export * from './system/user';
|
||||
|
||||
// 角色相关
|
||||
export * from './role';
|
||||
export * from './system/role';
|
||||
|
||||
// 部门相关
|
||||
export * from './dept';
|
||||
|
||||
// 菜单相关
|
||||
export * from './menu';
|
||||
export * from './system/menu';
|
||||
|
||||
// 权限相关
|
||||
export * from './permission';
|
||||
export * from './system/permission';
|
||||
|
||||
// 系统相关
|
||||
export * from './module';
|
||||
export * from './system/module';
|
||||
|
||||
export * from './achievement';
|
||||
|
||||
|
||||
37
schoolNewsWeb/src/types/system/config.ts
Normal file
37
schoolNewsWeb/src/types/system/config.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { ResultDomain } from '@/types';
|
||||
|
||||
/**
|
||||
* 配置项接口定义(对应后端 TbSysConfig)
|
||||
*/
|
||||
export interface ConfigItem {
|
||||
// 后端 TbSysConfig 字段(完全匹配)
|
||||
configKey: string; // 配置键
|
||||
configName?: string; // 配置显示名称
|
||||
configValue: string; // 配置值
|
||||
configType: string; // 数据类型:string/number/boolean/json
|
||||
renderType?: string; // 前端渲染类型:input/textarea/number/switch/select/password
|
||||
configGroup: string; // 配置分组
|
||||
description?: string; // 配置描述
|
||||
placeholder?: string; // 输入框占位符
|
||||
remark?: string; // 备注说明(显示在表单项下方)
|
||||
rows?: number; // 文本框行数(textarea用)
|
||||
minValue?: number; // 最小值(number用)
|
||||
maxValue?: number; // 最大值(number用)
|
||||
unit?: string; // 单位(number用)
|
||||
options?: string; // 下拉选项(select用,JSON字符串)
|
||||
orderNum?: number; // 排序号
|
||||
isSystem?: boolean; // 是否系统配置
|
||||
creator?: string; // 创建者
|
||||
updater?: string; // 更新者
|
||||
createTime?: string; // 创建时间
|
||||
updateTime?: string; // 更新时间
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置项参数
|
||||
*/
|
||||
export interface SaveConfigParam {
|
||||
configKey: string;
|
||||
configValue: string;
|
||||
configGroup: string;
|
||||
}
|
||||
6
schoolNewsWeb/src/types/system/index.ts
Normal file
6
schoolNewsWeb/src/types/system/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from './config';
|
||||
export * from './menu';
|
||||
export * from './module';
|
||||
export * from './permission';
|
||||
export * from './role';
|
||||
export * from './user'
|
||||
@@ -5,9 +5,9 @@
|
||||
*/
|
||||
|
||||
import { BaseDTO } from '../base';
|
||||
import { SysMenu } from '../menu';
|
||||
import { SysRole } from '../role';
|
||||
import { SysModule } from '../module';
|
||||
import { SysMenu } from './menu';
|
||||
import { SysRole } from './role';
|
||||
import { SysModule } from './module';
|
||||
|
||||
/**
|
||||
* 系统权限
|
||||
390
schoolNewsWeb/src/views/admin/manage/system/SystemConfigView.vue
Normal file
390
schoolNewsWeb/src/views/admin/manage/system/SystemConfigView.vue
Normal file
@@ -0,0 +1,390 @@
|
||||
<template>
|
||||
<AdminLayout title="系统配置" subtitle="系统参数配置管理">
|
||||
<div class="system-config">
|
||||
<!-- 配置分类标签 - 动态生成 -->
|
||||
<el-tabs v-model="activeTab" type="border-card" v-loading="loading">
|
||||
<el-tab-pane
|
||||
v-for="group in configGroups"
|
||||
:key="group.groupKey"
|
||||
:label="group.groupName"
|
||||
:name="group.groupKey"
|
||||
>
|
||||
<el-form
|
||||
:model="configData[group.groupKey]"
|
||||
label-width="140px"
|
||||
class="config-form"
|
||||
>
|
||||
<!-- 动态渲染配置项 -->
|
||||
<template v-for="item in group.items" :key="item.configKey">
|
||||
<!-- 文本输入框 -->
|
||||
<el-form-item
|
||||
v-if="getRenderType(item) === 'input'"
|
||||
:label="item.configName || item.configKey"
|
||||
:prop="item.configKey"
|
||||
>
|
||||
<el-input
|
||||
v-model="configData[group.groupKey][item.configKey]"
|
||||
:placeholder="item.placeholder || `请输入${item.configName || item.configKey}`"
|
||||
/>
|
||||
<span v-if="item.remark" class="form-item-remark">{{ item.remark }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 多行文本框 -->
|
||||
<el-form-item
|
||||
v-else-if="getRenderType(item) === 'textarea'"
|
||||
:label="item.configName || item.configKey"
|
||||
:prop="item.configKey"
|
||||
>
|
||||
<el-input
|
||||
v-model="configData[group.groupKey][item.configKey]"
|
||||
type="textarea"
|
||||
:rows="item.rows || 3"
|
||||
:placeholder="item.placeholder || `请输入${item.configName || item.configKey}`"
|
||||
/>
|
||||
<span v-if="item.remark" class="form-item-remark">{{ item.remark }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 数字输入框 -->
|
||||
<el-form-item
|
||||
v-else-if="getRenderType(item) === 'number'"
|
||||
:label="item.configName || item.configKey"
|
||||
:prop="item.configKey"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="configData[group.groupKey][item.configKey]"
|
||||
:min="item.minValue"
|
||||
:max="item.maxValue"
|
||||
:placeholder="item.placeholder"
|
||||
/>
|
||||
<span v-if="item.unit" class="form-item-unit">{{ item.unit }}</span>
|
||||
<span v-if="item.remark" class="form-item-remark">{{ item.remark }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 开关 -->
|
||||
<el-form-item
|
||||
v-else-if="getRenderType(item) === 'switch'"
|
||||
:label="item.configName || item.configKey"
|
||||
:prop="item.configKey"
|
||||
>
|
||||
<el-switch v-model="configData[group.groupKey][item.configKey]" />
|
||||
<span v-if="item.remark" class="form-item-remark">{{ item.remark }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 下拉选择 -->
|
||||
<el-form-item
|
||||
v-else-if="getRenderType(item) === 'select'"
|
||||
:label="item.configName || item.configKey"
|
||||
:prop="item.configKey"
|
||||
>
|
||||
<el-select
|
||||
v-model="configData[group.groupKey][item.configKey]"
|
||||
:placeholder="item.placeholder || `请选择${item.configName || item.configKey}`"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in parseOptions(item.options)"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
<span v-if="item.remark" class="form-item-remark">{{ item.remark }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<el-form-item
|
||||
v-else-if="getRenderType(item) === 'password'"
|
||||
:label="item.configName || item.configKey"
|
||||
:prop="item.configKey"
|
||||
>
|
||||
<el-input
|
||||
v-model="configData[group.groupKey][item.configKey]"
|
||||
type="password"
|
||||
show-password
|
||||
:placeholder="item.placeholder || `请输入${item.configName || item.configKey}`"
|
||||
/>
|
||||
<span v-if="item.remark" class="form-item-remark">{{ item.remark }}</span>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="saveConfig(group.groupKey)"
|
||||
:loading="saving"
|
||||
>
|
||||
保存配置
|
||||
</el-button>
|
||||
<el-button @click="loadConfigs">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { AdminLayout } from '@/views/admin';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { configApi } from '@/apis/system';
|
||||
import type { ConfigItem } from '@/types/system/config';
|
||||
|
||||
defineOptions({
|
||||
name: 'SystemConfigView'
|
||||
});
|
||||
|
||||
// 配置分组接口定义
|
||||
interface ConfigGroup {
|
||||
groupKey: string;
|
||||
groupName: string;
|
||||
orderNum: number;
|
||||
items: ConfigItem[];
|
||||
}
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const activeTab = ref('');
|
||||
|
||||
// 配置分组列表
|
||||
const configGroups = ref<ConfigGroup[]>([]);
|
||||
|
||||
// 配置数据对象,按分组存储
|
||||
const configData = reactive<Record<string, Record<string, any>>>({});
|
||||
|
||||
onMounted(() => {
|
||||
loadConfigs();
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取配置项的渲染类型
|
||||
* @param item 配置项
|
||||
* @returns 渲染类型:input/textarea/number/switch/select/password
|
||||
*/
|
||||
function getRenderType(item: ConfigItem): string {
|
||||
// 如果明确指定了 renderType,直接使用
|
||||
if (item.renderType) {
|
||||
return item.renderType;
|
||||
}
|
||||
|
||||
// 根据 configType 自动推断渲染类型
|
||||
switch (item.configType?.toLowerCase()) {
|
||||
case 'boolean':
|
||||
return 'switch';
|
||||
case 'number':
|
||||
case 'integer':
|
||||
case 'long':
|
||||
case 'double':
|
||||
case 'float':
|
||||
return 'number';
|
||||
case 'json':
|
||||
return 'textarea';
|
||||
case 'string':
|
||||
default:
|
||||
// String 类型根据其他属性进一步判断
|
||||
if (item.options) {
|
||||
return 'select';
|
||||
}
|
||||
if (item.rows && item.rows > 1) {
|
||||
return 'textarea';
|
||||
}
|
||||
if (item.configKey?.includes('password') || item.configKey?.includes('secret')) {
|
||||
return 'password';
|
||||
}
|
||||
return 'input';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 options JSON 字符串
|
||||
* @param optionsStr JSON 字符串
|
||||
* @returns 选项数组
|
||||
*/
|
||||
function parseOptions(optionsStr?: string): Array<{ label: string; value: any }> {
|
||||
if (!optionsStr) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(optionsStr);
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
} catch (error) {
|
||||
console.warn('解析 options 失败:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载配置数据
|
||||
*/
|
||||
async function loadConfigs() {
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
// 调用API获取配置
|
||||
const result = await configApi.getConfigs();
|
||||
|
||||
if (!result.success) {
|
||||
ElMessage.error(result.message || '加载配置失败');
|
||||
return;
|
||||
}
|
||||
|
||||
// 后端返回的列表数据在 dataList 字段中
|
||||
const configItems: ConfigItem[] = (result.dataList || []) as unknown as ConfigItem[];
|
||||
|
||||
// 定义分组名称映射
|
||||
const groupNames: Record<string, string> = {
|
||||
basic: '基本配置',
|
||||
email: '邮件配置',
|
||||
storage: '存储配置',
|
||||
system: '系统参数'
|
||||
};
|
||||
|
||||
// 按分组组织配置
|
||||
const groupMap = new Map<string, ConfigGroup>();
|
||||
|
||||
configItems.forEach((item: ConfigItem) => {
|
||||
if (!groupMap.has(item.configGroup)) {
|
||||
groupMap.set(item.configGroup, {
|
||||
groupKey: item.configGroup,
|
||||
groupName: groupNames[item.configGroup] || item.configGroup,
|
||||
orderNum: Object.keys(groupNames).indexOf(item.configGroup),
|
||||
items: []
|
||||
});
|
||||
configData[item.configGroup] = {};
|
||||
}
|
||||
|
||||
const group = groupMap.get(item.configGroup)!;
|
||||
group.items.push(item);
|
||||
|
||||
// 初始化配置值,根据 configType 转换数据类型
|
||||
let value: any = item.configValue;
|
||||
switch (item.configType?.toLowerCase()) {
|
||||
case 'number':
|
||||
case 'integer':
|
||||
case 'long':
|
||||
case 'double':
|
||||
case 'float':
|
||||
value = Number(value);
|
||||
break;
|
||||
case 'boolean':
|
||||
value = value === 'true' || value === true || value === 1;
|
||||
break;
|
||||
case 'json':
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch {
|
||||
value = value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// string 类型保持原样
|
||||
break;
|
||||
}
|
||||
configData[item.configGroup][item.configKey] = value;
|
||||
});
|
||||
|
||||
// 转换为数组并排序
|
||||
configGroups.value = Array.from(groupMap.values()).sort(
|
||||
(a, b) => a.orderNum - b.orderNum
|
||||
);
|
||||
|
||||
// 每个分组内的配置项也排序
|
||||
configGroups.value.forEach(group => {
|
||||
group.items.sort((a, b) => (a.orderNum || 0) - (b.orderNum || 0));
|
||||
});
|
||||
|
||||
// 设置默认激活的标签页
|
||||
if (configGroups.value.length > 0) {
|
||||
activeTab.value = configGroups.value[0].groupKey;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载配置失败:', error);
|
||||
ElMessage.error('加载配置失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存指定分组的配置
|
||||
*/
|
||||
async function saveConfig(groupKey: string) {
|
||||
try {
|
||||
saving.value = true;
|
||||
|
||||
const groupData = configData[groupKey];
|
||||
const configItems = configGroups.value
|
||||
.find(g => g.groupKey === groupKey)
|
||||
?.items || [];
|
||||
|
||||
// 构建保存数据
|
||||
const saveData = configItems.map(item => ({
|
||||
configKey: item.configKey,
|
||||
configValue: String(groupData[item.configKey]),
|
||||
configGroup: groupKey
|
||||
}));
|
||||
|
||||
// TODO: 调用API保存配置
|
||||
// await configApi.saveConfigs(saveData);
|
||||
console.log('保存配置:', saveData);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
ElMessage.success('配置保存成功');
|
||||
} catch (error) {
|
||||
console.error('保存配置失败:', error);
|
||||
ElMessage.error('保存配置失败');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.system-config {
|
||||
padding: 20px;
|
||||
|
||||
:deep(.el-tabs--border-card) {
|
||||
border: none;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
:deep(.el-tabs__content) {
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.config-form {
|
||||
max-width: 800px;
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.el-input),
|
||||
:deep(.el-select),
|
||||
:deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.el-textarea__inner) {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.form-item-remark {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.form-item-unit {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -314,7 +314,7 @@ import { resourceTagApi } from '@/apis/resource';
|
||||
import { GenericSelector } from '@/components/base';
|
||||
import type { TaskVO, Course, TaskItemVO } from '@/types/study';
|
||||
import type { Resource, Tag } from '@/types/resource';
|
||||
import type { SysUser } from '@/types/user';
|
||||
import type { SysUser } from '@/types/system/user';
|
||||
|
||||
defineOptions({
|
||||
name: 'LearningTaskAdd'
|
||||
|
||||
@@ -20,7 +20,7 @@ import { useRoute } from 'vue-router';
|
||||
import { FloatingSidebar } from '@/components/base';
|
||||
import { UserCard } from '@/views/user/user-center/components';
|
||||
import { getParentChildrenRoutes } from '@/utils/routeUtils';
|
||||
import type { SysMenu } from '@/types/menu';
|
||||
import type { SysMenu } from '@/types/system/menu';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user