From 76f47bce37e34ee1010f53a363b6a01aa528b7c3 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Thu, 1 May 2025 16:57:58 +0800 Subject: [PATCH] =?UTF-8?q?update:=E5=AD=97=E5=85=B8=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/xiaozhi/common/redis/RedisKeys.java | 7 + .../service/impl/ModelConfigServiceImpl.java | 4 - .../sys/controller/SysDictDataController.java | 21 +- .../sys/controller/SysDictTypeController.java | 11 +- .../modules/sys/dao/SysDictDataDao.java | 12 + .../sys/service/SysDictDataService.java | 17 + .../service/impl/SysDictDataServiceImpl.java | 65 +- .../service/impl/SysDictTypeServiceImpl.java | 19 +- .../sys/service/impl/SysUserServiceImpl.java | 1 + .../modules/sys/vo/AdminPageUserVO.java | 5 + .../modules/sys/vo/SysDictDataItem.java | 20 + .../resources/db/changelog/202504301340.sql | 20 - .../resources/db/changelog/202504301341.sql | 85 ++ .../db/changelog/db.changelog-master.yaml | 4 +- .../resources/mapper/sys/SysDictDataDao.xml | 12 + main/manager-web/src/apis/api.js | 7 +- main/manager-web/src/apis/module/dict.js | 227 +++++ .../src/components/DictDataDialog.vue | 105 +++ .../src/components/DictTypeDialog.vue | 86 ++ .../src/components/FirmwareDialog.vue | 10 +- main/manager-web/src/components/HeaderBar.vue | 60 +- main/manager-web/src/router/index.js | 8 +- main/manager-web/src/utils/index.js | 60 -- .../src/views/DeviceManagement.vue | 18 +- main/manager-web/src/views/DictManagement.vue | 835 ++++++++++++++++++ main/manager-web/src/views/OtaManagement.vue | 20 +- main/manager-web/src/views/UserManagement.vue | 12 +- main/manager-web/src/views/roleConfig.vue | 124 +-- 28 files changed, 1653 insertions(+), 222 deletions(-) create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/sys/vo/SysDictDataItem.java delete mode 100644 main/manager-api/src/main/resources/db/changelog/202504301340.sql create mode 100644 main/manager-api/src/main/resources/db/changelog/202504301341.sql create mode 100644 main/manager-web/src/apis/module/dict.js create mode 100644 main/manager-web/src/components/DictDataDialog.vue create mode 100644 main/manager-web/src/components/DictTypeDialog.vue create mode 100644 main/manager-web/src/views/DictManagement.vue diff --git a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java index 5d3b4f32..7cadad2b 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java +++ b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java @@ -96,4 +96,11 @@ public class RedisKeys { public static String getOtaDownloadCountKey(String uuid) { return "ota:download:count:" + uuid; } + + /** + * 获取字典数据的缓存key + */ + public static String getDictDataByTypeKey(String dictType) { + return "sys:dict:data:" + dictType; + } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java index 25b03034..1f006d93 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java @@ -21,9 +21,7 @@ import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.service.impl.BaseServiceImpl; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.modules.agent.dao.AgentDao; -import xiaozhi.modules.agent.dao.AgentTemplateDao; import xiaozhi.modules.agent.entity.AgentEntity; -import xiaozhi.modules.agent.service.AgentTemplateService; import xiaozhi.modules.model.dao.ModelConfigDao; import xiaozhi.modules.model.dto.ModelBasicInfoDTO; import xiaozhi.modules.model.dto.ModelConfigBodyDTO; @@ -41,8 +39,6 @@ public class ModelConfigServiceImpl extends BaseServiceImpl> page(@Parameter(hidden = true) @RequestParam Map params) { ValidatorUtils.validateEntity(params); // 强制校验dictTypeId是否存在 @@ -84,7 +85,7 @@ public class SysDictDataController { return new Result<>(); } - @DeleteMapping("/delete") + @PostMapping("/delete") @Operation(summary = "删除字典数据") @RequiresPermissions("sys:role:superAdmin") @Parameter(name = "ids", description = "ID数组", required = true) @@ -93,4 +94,12 @@ public class SysDictDataController { return new Result<>(); } + @GetMapping("/type/{dictType}") + @Operation(summary = "获取字典数据列表") + @RequiresPermissions("sys:role:superAdmin") + public Result> getDictDataByType(@PathVariable("dictType") String dictType) { + List list = sysDictDataService.getDictDataByType(dictType); + return new Result>().ok(list); + } + } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysDictTypeController.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysDictTypeController.java index bf152c19..f16409b0 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysDictTypeController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysDictTypeController.java @@ -3,7 +3,6 @@ package xiaozhi.modules.sys.controller; import java.util.Map; import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -42,10 +41,10 @@ public class SysDictTypeController { @GetMapping("/page") @Operation(summary = "分页查询字典类型") @RequiresPermissions("sys:role:superAdmin") - @Parameters({@Parameter(name = "dictType", description = "字典类型编码"), - @Parameter(name = "dictName", description = "字典类型名称"), - @Parameter(name = Constant.PAGE, description = "当前页码,从1开始", required = true), - @Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true)}) + @Parameters({ @Parameter(name = "dictType", description = "字典类型编码"), + @Parameter(name = "dictName", description = "字典类型名称"), + @Parameter(name = Constant.PAGE, description = "当前页码,从1开始", required = true), + @Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true) }) public Result> page(@Parameter(hidden = true) @RequestParam Map params) { ValidatorUtils.validateEntity(params); PageData page = sysDictTypeService.page(params); @@ -82,7 +81,7 @@ public class SysDictTypeController { return new Result<>(); } - @DeleteMapping("/delete") + @PostMapping("/delete") @Operation(summary = "删除字典类型") @RequiresPermissions("sys:role:superAdmin") @Parameter(name = "ids", description = "ID数组", required = true) diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysDictDataDao.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysDictDataDao.java index 3ca5fb8c..e5c4c7bb 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysDictDataDao.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysDictDataDao.java @@ -1,9 +1,12 @@ package xiaozhi.modules.sys.dao; +import java.util.List; + import org.apache.ibatis.annotations.Mapper; import xiaozhi.common.dao.BaseDao; import xiaozhi.modules.sys.entity.SysDictDataEntity; +import xiaozhi.modules.sys.vo.SysDictDataItem; /** * 字典数据 @@ -11,4 +14,13 @@ import xiaozhi.modules.sys.entity.SysDictDataEntity; @Mapper public interface SysDictDataDao extends BaseDao { + List getDictDataByType(String dictType); + + /** + * 根据字典类型ID获取字典类型编码 + * + * @param dictTypeId 字典类型ID + * @return 字典类型编码 + */ + String getTypeByTypeId(Long dictTypeId); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysDictDataService.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysDictDataService.java index 5b4a9317..ea898447 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysDictDataService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysDictDataService.java @@ -1,11 +1,13 @@ package xiaozhi.modules.sys.service; +import java.util.List; import java.util.Map; import xiaozhi.common.page.PageData; import xiaozhi.common.service.BaseService; import xiaozhi.modules.sys.dto.SysDictDataDTO; import xiaozhi.modules.sys.entity.SysDictDataEntity; +import xiaozhi.modules.sys.vo.SysDictDataItem; import xiaozhi.modules.sys.vo.SysDictDataVO; /** @@ -50,4 +52,19 @@ public interface SysDictDataService extends BaseService { */ void delete(Long[] ids); + /** + * 根据字典类型ID删除对应的字典数据 + * + * @param dictTypeId 字典类型ID + */ + void deleteByTypeId(Long dictTypeId); + + /** + * 根据字典类型获取字典数据列表 + * + * @param dictType 字典类型 + * @return 返回字典数据列表 + */ + List getDictDataByType(String dictType); + } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictDataServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictDataServiceImpl.java index 6ca83eea..ffe88986 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictDataServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictDataServiceImpl.java @@ -1,6 +1,5 @@ package xiaozhi.modules.sys.service.impl; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; @@ -19,6 +18,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.AllArgsConstructor; import xiaozhi.common.exception.RenException; import xiaozhi.common.page.PageData; +import xiaozhi.common.redis.RedisKeys; +import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.service.impl.BaseServiceImpl; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.modules.sys.dao.SysDictDataDao; @@ -27,6 +28,7 @@ import xiaozhi.modules.sys.dto.SysDictDataDTO; import xiaozhi.modules.sys.entity.SysDictDataEntity; import xiaozhi.modules.sys.entity.SysUserEntity; import xiaozhi.modules.sys.service.SysDictDataService; +import xiaozhi.modules.sys.vo.SysDictDataItem; import xiaozhi.modules.sys.vo.SysDictDataVO; /** @@ -35,8 +37,9 @@ import xiaozhi.modules.sys.vo.SysDictDataVO; @Service @AllArgsConstructor public class SysDictDataServiceImpl extends BaseServiceImpl - implements SysDictDataService { + implements SysDictDataService { private final SysUserDao sysUserDao; + private final RedisUtils redisUtils; @Override public PageData page(Map params) { @@ -50,9 +53,9 @@ public class SysDictDataServiceImpl extends BaseServiceImpl getWrapper(Map params) { - String dictTypeId = (String)params.get("dictTypeId"); - String dictLabel = (String)params.get("dictLabel"); - String dictValue = (String)params.get("dictValue"); + String dictTypeId = (String) params.get("dictTypeId"); + String dictLabel = (String) params.get("dictLabel"); + String dictValue = (String) params.get("dictValue"); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("dict_type_id", Long.parseLong(dictTypeId)); @@ -78,6 +81,9 @@ public class SysDictDataServiceImpl extends BaseServiceImpl wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysDictDataEntity::getDictTypeId, dictTypeId); + baseDao.delete(wrapper); } /** @@ -106,14 +129,14 @@ public class SysDictDataServiceImpl extends BaseServiceImpl sysDictDataList) { // 收集所有用户 ID Set userIds = sysDictDataList.stream().flatMap(vo -> Stream.of(vo.getCreator(), vo.getUpdater())) - .filter(Objects::nonNull).collect(Collectors.toSet()); + .filter(Objects::nonNull).collect(Collectors.toSet()); // 设置更新者和创建者名称 if (!userIds.isEmpty()) { List sysUserEntities = sysUserDao.selectBatchIds(userIds); // 把List转成Map,Map Map userNameMap = sysUserEntities.stream().collect(Collectors.toMap(SysUserEntity::getId, - SysUserEntity::getUsername, (existing, replacement) -> existing)); + SysUserEntity::getUsername, (existing, replacement) -> existing)); sysDictDataList.forEach(vo -> { vo.setCreatorName(userNameMap.get(vo.getCreator())); @@ -133,4 +156,28 @@ public class SysDictDataServiceImpl extends BaseServiceImpl getDictDataByType(String dictType) { + if (StringUtils.isBlank(dictType)) { + return null; + } + + // 先从Redis获取缓存 + String key = RedisKeys.getDictDataByTypeKey(dictType); + List cachedData = (List) redisUtils.get(key); + if (cachedData != null) { + return cachedData; + } + + // 如果缓存中没有,则从数据库获取 + List data = baseDao.getDictDataByType(dictType); + + // 存入Redis缓存 + if (data != null) { + redisUtils.set(key, data); + } + + return data; + } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictTypeServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictTypeServiceImpl.java index 415b7adb..91522482 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictTypeServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysDictTypeServiceImpl.java @@ -26,6 +26,7 @@ import xiaozhi.modules.sys.dao.SysUserDao; import xiaozhi.modules.sys.dto.SysDictTypeDTO; import xiaozhi.modules.sys.entity.SysDictTypeEntity; import xiaozhi.modules.sys.entity.SysUserEntity; +import xiaozhi.modules.sys.service.SysDictDataService; import xiaozhi.modules.sys.service.SysDictTypeService; import xiaozhi.modules.sys.vo.SysDictTypeVO; @@ -35,9 +36,9 @@ import xiaozhi.modules.sys.vo.SysDictTypeVO; @Service @AllArgsConstructor public class SysDictTypeServiceImpl extends BaseServiceImpl - implements SysDictTypeService { - + implements SysDictTypeService { private final SysUserDao sysUserDao; + private final SysDictDataService sysDictDataService; @Override public PageData page(Map params) { @@ -51,8 +52,8 @@ public class SysDictTypeServiceImpl extends BaseServiceImpl getWrapper(Map params) { - String dictType = (String)params.get("dictType"); - String dictName = (String)params.get("dictName"); + String dictType = (String) params.get("dictType"); + String dictName = (String) params.get("dictName"); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.like(StringUtils.isNotBlank(dictType), "dict_type", dictType); @@ -96,7 +97,11 @@ public class SysDictTypeServiceImpl extends BaseServiceImpl sysDictTypeList) { // 收集所有用户 ID Set userIds = sysDictTypeList.stream().flatMap(vo -> Stream.of(vo.getCreator(), vo.getUpdater())) - .filter(Objects::nonNull).collect(Collectors.toSet()); + .filter(Objects::nonNull).collect(Collectors.toSet()); // 设置更新者和创建者名称 if (!userIds.isEmpty()) { List sysUserEntities = sysUserDao.selectBatchIds(userIds); // 把List转成Map,Map Map userNameMap = sysUserEntities.stream().collect(Collectors.toMap(SysUserEntity::getId, - SysUserEntity::getUsername, (existing, replacement) -> existing)); + SysUserEntity::getUsername, (existing, replacement) -> existing)); sysDictTypeList.forEach(vo -> { vo.setCreatorName(userNameMap.get(vo.getCreator())); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysUserServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysUserServiceImpl.java index 30976229..97944ba9 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysUserServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysUserServiceImpl.java @@ -169,6 +169,7 @@ public class SysUserServiceImpl extends BaseServiceImpl(list, page.getTotal()); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/vo/AdminPageUserVO.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/vo/AdminPageUserVO.java index a406848f..9f832372 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/vo/AdminPageUserVO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/vo/AdminPageUserVO.java @@ -1,5 +1,7 @@ package xiaozhi.modules.sys.vo; +import java.util.Date; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -23,4 +25,7 @@ public class AdminPageUserVO { @Schema(description = "用户id") private String userid; + + @Schema(description = "注册时间") + private Date createDate; } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/vo/SysDictDataItem.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/vo/SysDictDataItem.java new file mode 100644 index 00000000..f6c81500 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/vo/SysDictDataItem.java @@ -0,0 +1,20 @@ +package xiaozhi.modules.sys.vo; + +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 字典数据VO + */ +@Data +@Schema(description = "字典数据项") +public class SysDictDataItem implements Serializable { + + @Schema(description = "字典标签") + private String name; + + @Schema(description = "字典值") + private String key; +} diff --git a/main/manager-api/src/main/resources/db/changelog/202504301340.sql b/main/manager-api/src/main/resources/db/changelog/202504301340.sql deleted file mode 100644 index 1f0e2f7c..00000000 --- a/main/manager-api/src/main/resources/db/changelog/202504301340.sql +++ /dev/null @@ -1,20 +0,0 @@ -update `ai_model_provider` set `fields` = -'[{"key": "api_url","label": "API地址","type": "string"},{"key": "voice","label": "音色","type": "string"},{"key": "output_dir","label": "输出目录","type": "string"},{"key": "authorization","label": "授权","type": "string"},{"key": "appid","label": "应用ID","type": "string"},{"key": "access_token","label": "访问令牌","type": "string"},{"key": "cluster","label": "集群","type": "string"},{"key": "speed_ratio","label": "语速","type": "number"},{"key": "volume_ratio","label": "音量","type": "number"},{"key": "pitch_ratio","label": "音高","type": "number"}]' -where `id` = 'SYSTEM_TTS_doubao'; - --- 添加阿里云ASR供应器 -INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES -('SYSTEM_ASR_AliyunASR', 'ASR', 'aliyun', '阿里云语音识别', '[{"key":"appkey","label":"应用AppKey","type":"string"},{"key":"token","label":"临时Token","type":"string"},{"key":"access_key_id","label":"AccessKey ID","type":"string"},{"key":"access_key_secret","label":"AccessKey Secret","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 5, 1, NOW(), 1, NOW()); - --- 添加阿里云ASR模型配置 -INSERT INTO `ai_model_config` VALUES ('ASR_AliyunASR', 'ASR', 'AliyunASR', '阿里云语音识别', 0, 1, '{\"type\": \"aliyun\", \"appkey\": \"\", \"token\": \"\", \"access_key_id\": \"\", \"access_key_secret\": \"\", \"output_dir\": \"tmp/\"}', NULL, NULL, 6, NULL, NULL, NULL, NULL); - --- 更新阿里云ASR模型配置的说明文档 -UPDATE `ai_model_config` SET -`doc_link` = 'https://nls-portal.console.aliyun.com/', -`remark` = '阿里云ASR配置说明: -1. 访问 https://nls-portal.console.aliyun.com/ 开通服务 -2. 访问 https://nls-portal.console.aliyun.com/applist 获取appkey -3. 访问 https://nls-portal.console.aliyun.com/overview 获取token -4. 获取access_key_id和access_key_secret -5. 填入配置文件中' WHERE `id` = 'ASR_AliyunASR'; diff --git a/main/manager-api/src/main/resources/db/changelog/202504301341.sql b/main/manager-api/src/main/resources/db/changelog/202504301341.sql new file mode 100644 index 00000000..a88ee783 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202504301341.sql @@ -0,0 +1,85 @@ +update `ai_model_provider` set `fields` = +'[{"key": "api_url","label": "API地址","type": "string"},{"key": "voice","label": "音色","type": "string"},{"key": "output_dir","label": "输出目录","type": "string"},{"key": "authorization","label": "授权","type": "string"},{"key": "appid","label": "应用ID","type": "string"},{"key": "access_token","label": "访问令牌","type": "string"},{"key": "cluster","label": "集群","type": "string"},{"key": "speed_ratio","label": "语速","type": "number"},{"key": "volume_ratio","label": "音量","type": "number"},{"key": "pitch_ratio","label": "音高","type": "number"}]' +where `id` = 'SYSTEM_TTS_doubao'; + +-- 添加阿里云ASR供应器 +delete from `ai_model_provider` where `id` = 'SYSTEM_ASR_AliyunASR'; +INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES +('SYSTEM_ASR_AliyunASR', 'ASR', 'aliyun', '阿里云语音识别', '[{"key":"appkey","label":"应用AppKey","type":"string"},{"key":"token","label":"临时Token","type":"string"},{"key":"access_key_id","label":"AccessKey ID","type":"string"},{"key":"access_key_secret","label":"AccessKey Secret","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 5, 1, NOW(), 1, NOW()); + +-- 添加阿里云ASR模型配置 +delete from `ai_model_config` where `id` = 'ASR_AliyunASR'; +INSERT INTO `ai_model_config` VALUES ('ASR_AliyunASR', 'ASR', 'AliyunASR', '阿里云语音识别', 0, 1, '{\"type\": \"aliyun\", \"appkey\": \"\", \"token\": \"\", \"access_key_id\": \"\", \"access_key_secret\": \"\", \"output_dir\": \"tmp/\"}', NULL, NULL, 6, NULL, NULL, NULL, NULL); + +-- 更新阿里云ASR模型配置的说明文档 +UPDATE `ai_model_config` SET +`doc_link` = 'https://nls-portal.console.aliyun.com/', +`remark` = '阿里云ASR配置说明: +1. 访问 https://nls-portal.console.aliyun.com/ 开通服务 +2. 访问 https://nls-portal.console.aliyun.com/applist 获取appkey +3. 访问 https://nls-portal.console.aliyun.com/overview 获取token +4. 获取access_key_id和access_key_secret +5. 填入配置文件中' WHERE `id` = 'ASR_AliyunASR'; + +-- 插入固件类型字典类型 +delete from `sys_dict_type` where `id` = 101; +INSERT INTO `sys_dict_type` (`id`, `dict_type`, `dict_name`, `remark`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES +(101, 'FIRMWARE_TYPE', '固件类型', '固件类型字典', 0, 1, NOW(), 1, NOW()); + +-- 插入固件类型字典数据 +delete from `sys_dict_data` where `dict_type_id` = 101; +INSERT INTO `sys_dict_data` (`id`, `dict_type_id`, `dict_label`, `dict_value`, `remark`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES +(101001, 101, '面包板新版接线(WiFi)', 'bread-compact-wifi', '面包板新版接线(WiFi)', 1, 1, NOW(), 1, NOW()), +(101002, 101, '面包板新版接线(WiFi)+ LCD', 'bread-compact-wifi-lcd', '面包板新版接线(WiFi)+ LCD', 2, 1, NOW(), 1, NOW()), +(101003, 101, '面包板新版接线(ML307 AT)', 'bread-compact-ml307', '面包板新版接线(ML307 AT)', 3, 1, NOW(), 1, NOW()), +(101004, 101, '面包板(WiFi) ESP32 DevKit', 'bread-compact-esp32', '面包板(WiFi) ESP32 DevKit', 4, 1, NOW(), 1, NOW()), +(101005, 101, '面包板(WiFi+ LCD) ESP32 DevKit', 'bread-compact-esp32-lcd', '面包板(WiFi+ LCD) ESP32 DevKit', 5, 1, NOW(), 1, NOW()), +(101006, 101, 'DFRobot 行空板 k10', 'df-k10', 'DFRobot 行空板 k10', 6, 1, NOW(), 1, NOW()), +(101007, 101, 'ESP32 CGC', 'esp32-cgc', 'ESP32 CGC', 7, 1, NOW(), 1, NOW()), +(101008, 101, 'ESP BOX 3', 'esp-box-3', 'ESP BOX 3', 8, 1, NOW(), 1, NOW()), +(101009, 101, 'ESP BOX', 'esp-box', 'ESP BOX', 9, 1, NOW(), 1, NOW()), +(101010, 101, 'ESP BOX Lite', 'esp-box-lite', 'ESP BOX Lite', 10, 1, NOW(), 1, NOW()), +(101011, 101, 'Kevin Box 1', 'kevin-box-1', 'Kevin Box 1', 11, 1, NOW(), 1, NOW()), +(101012, 101, 'Kevin Box 2', 'kevin-box-2', 'Kevin Box 2', 12, 1, NOW(), 1, NOW()), +(101013, 101, 'Kevin C3', 'kevin-c3', 'Kevin C3', 13, 1, NOW(), 1, NOW()), +(101014, 101, 'Kevin SP V3开发板', 'kevin-sp-v3-dev', 'Kevin SP V3开发板', 14, 1, NOW(), 1, NOW()), +(101015, 101, 'Kevin SP V4开发板', 'kevin-sp-v4-dev', 'Kevin SP V4开发板', 15, 1, NOW(), 1, NOW()), +(101016, 101, '鱼鹰科技3.13LCD开发板', 'kevin-yuying-313lcd', '鱼鹰科技3.13LCD开发板', 16, 1, NOW(), 1, NOW()), +(101017, 101, '立创·实战派ESP32-S3开发板', 'lichuang-dev', '立创·实战派ESP32-S3开发板', 17, 1, NOW(), 1, NOW()), +(101018, 101, '立创·实战派ESP32-C3开发板', 'lichuang-c3-dev', '立创·实战派ESP32-C3开发板', 18, 1, NOW(), 1, NOW()), +(101019, 101, '神奇按钮 Magiclick_2.4', 'magiclick-2p4', '神奇按钮 Magiclick_2.4', 19, 1, NOW(), 1, NOW()), +(101020, 101, '神奇按钮 Magiclick_2.5', 'magiclick-2p5', '神奇按钮 Magiclick_2.5', 20, 1, NOW(), 1, NOW()), +(101021, 101, '神奇按钮 Magiclick_C3', 'magiclick-c3', '神奇按钮 Magiclick_C3', 21, 1, NOW(), 1, NOW()), +(101022, 101, '神奇按钮 Magiclick_C3_v2', 'magiclick-c3-v2', '神奇按钮 Magiclick_C3_v2', 22, 1, NOW(), 1, NOW()), +(101023, 101, 'M5Stack CoreS3', 'm5stack-core-s3', 'M5Stack CoreS3', 23, 1, NOW(), 1, NOW()), +(101024, 101, 'AtomS3 + Echo Base', 'atoms3-echo-base', 'AtomS3 + Echo Base', 24, 1, NOW(), 1, NOW()), +(101025, 101, 'AtomS3R + Echo Base', 'atoms3r-echo-base', 'AtomS3R + Echo Base', 25, 1, NOW(), 1, NOW()), +(101026, 101, 'AtomS3R CAM/M12 + Echo Base', 'atoms3r-cam-m12-echo-base', 'AtomS3R CAM/M12 + Echo Base', 26, 1, NOW(), 1, NOW()), +(101027, 101, 'AtomMatrix + Echo Base', 'atommatrix-echo-base', 'AtomMatrix + Echo Base', 27, 1, NOW(), 1, NOW()), +(101028, 101, '虾哥 Mini C3', 'xmini-c3', '虾哥 Mini C3', 28, 1, NOW(), 1, NOW()), +(101029, 101, 'ESP32S3_KORVO2_V3开发板', 'esp32s3-korvo2-v3', 'ESP32S3_KORVO2_V3开发板', 29, 1, NOW(), 1, NOW()), +(101030, 101, 'ESP-SparkBot开发板', 'esp-sparkbot', 'ESP-SparkBot开发板', 30, 1, NOW(), 1, NOW()), +(101031, 101, 'ESP-Spot-S3', 'esp-spot-s3', 'ESP-Spot-S3', 31, 1, NOW(), 1, NOW()), +(101032, 101, 'Waveshare ESP32-S3-Touch-AMOLED-1.8', 'esp32-s3-touch-amoled-1.8', 'Waveshare ESP32-S3-Touch-AMOLED-1.8', 32, 1, NOW(), 1, NOW()), +(101033, 101, 'Waveshare ESP32-S3-Touch-LCD-1.85C', 'esp32-s3-touch-lcd-1.85c', 'Waveshare ESP32-S3-Touch-LCD-1.85C', 33, 1, NOW(), 1, NOW()), +(101034, 101, 'Waveshare ESP32-S3-Touch-LCD-1.85', 'esp32-s3-touch-lcd-1.85', 'Waveshare ESP32-S3-Touch-LCD-1.85', 34, 1, NOW(), 1, NOW()), +(101035, 101, 'Waveshare ESP32-S3-Touch-LCD-1.46', 'esp32-s3-touch-lcd-1.46', 'Waveshare ESP32-S3-Touch-LCD-1.46', 35, 1, NOW(), 1, NOW()), +(101036, 101, 'Waveshare ESP32-S3-Touch-LCD-3.5', 'esp32-s3-touch-lcd-3.5', 'Waveshare ESP32-S3-Touch-LCD-3.5', 36, 1, NOW(), 1, NOW()), +(101037, 101, '土豆子', 'tudouzi', '土豆子', 37, 1, NOW(), 1, NOW()), +(101038, 101, 'LILYGO T-Circle-S3', 'lilygo-t-circle-s3', 'LILYGO T-Circle-S3', 38, 1, NOW(), 1, NOW()), +(101039, 101, 'LILYGO T-CameraPlus-S3', 'lilygo-t-cameraplus-s3', 'LILYGO T-CameraPlus-S3', 39, 1, NOW(), 1, NOW()), +(101040, 101, 'Movecall Moji 小智AI衍生版', 'movecall-moji-esp32s3', 'Movecall Moji 小智AI衍生版', 40, 1, NOW(), 1, NOW()), +(101041, 101, 'Movecall CuiCan 璀璨·AI吊坠', 'movecall-cuican-esp32s3', 'Movecall CuiCan 璀璨·AI吊坠', 41, 1, NOW(), 1, NOW()), +(101042, 101, '正点原子DNESP32S3开发板', 'atk-dnesp32s3', '正点原子DNESP32S3开发板', 42, 1, NOW(), 1, NOW()), +(101043, 101, '正点原子DNESP32S3-BOX', 'atk-dnesp32s3-box', '正点原子DNESP32S3-BOX', 43, 1, NOW(), 1, NOW()), +(101044, 101, '嘟嘟开发板CHATX(wifi)', 'du-chatx', '嘟嘟开发板CHATX(wifi)', 44, 1, NOW(), 1, NOW()), +(101045, 101, '太极小派esp32s3', 'taiji-pi-s3', '太极小派esp32s3', 45, 1, NOW(), 1, NOW()), +(101046, 101, '无名科技星智0.85(WIFI)', 'xingzhi-cube-0.85tft-wifi', '无名科技星智0.85(WIFI)', 46, 1, NOW(), 1, NOW()), +(101047, 101, '无名科技星智0.85(ML307)', 'xingzhi-cube-0.85tft-ml307', '无名科技星智0.85(ML307)', 47, 1, NOW(), 1, NOW()), +(101048, 101, '无名科技星智0.96(WIFI)', 'xingzhi-cube-0.96oled-wifi', '无名科技星智0.96(WIFI)', 48, 1, NOW(), 1, NOW()), +(101049, 101, '无名科技星智0.96(ML307)', 'xingzhi-cube-0.96oled-ml307', '无名科技星智0.96(ML307)', 49, 1, NOW(), 1, NOW()), +(101050, 101, '无名科技星智1.54(WIFI)', 'xingzhi-cube-1.54tft-wifi', '无名科技星智1.54(WIFI)', 50, 1, NOW(), 1, NOW()), +(101051, 101, '无名科技星智1.54(ML307)', 'xingzhi-cube-1.54tft-ml307', '无名科技星智1.54(ML307)', 51, 1, NOW(), 1, NOW()), +(101052, 101, 'SenseCAP Watcher', 'sensecap-watcher', 'SenseCAP Watcher', 52, 1, NOW(), 1, NOW()), +(101053, 101, '四博智联AI陪伴盒子', 'doit-s3-aibox', '四博智联AI陪伴盒子', 53, 1, NOW(), 1, NOW()), +(101054, 101, '元控·青春', 'mixgo-nova', '元控·青春', 54, 1, NOW(), 1, NOW()); diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index 1d965a15..ffe96a9b 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -87,9 +87,9 @@ databaseChangeLog: encoding: utf8 path: classpath:db/changelog/202504291043.sql - changeSet: - id: 202504301340 + id: 202504301341 author: Goody changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202504301340.sql \ No newline at end of file + path: classpath:db/changelog/202504301341.sql \ No newline at end of file diff --git a/main/manager-api/src/main/resources/mapper/sys/SysDictDataDao.xml b/main/manager-api/src/main/resources/mapper/sys/SysDictDataDao.xml index f1044e27..39848831 100644 --- a/main/manager-api/src/main/resources/mapper/sys/SysDictDataDao.xml +++ b/main/manager-api/src/main/resources/mapper/sys/SysDictDataDao.xml @@ -2,5 +2,17 @@ + + \ No newline at end of file diff --git a/main/manager-web/src/apis/api.js b/main/manager-web/src/apis/api.js index 1b9f0a9e..0a3e8d18 100755 --- a/main/manager-web/src/apis/api.js +++ b/main/manager-web/src/apis/api.js @@ -2,11 +2,11 @@ import admin from './module/admin.js' import agent from './module/agent.js' import device from './module/device.js' +import dict from './module/dict.js' import model from './module/model.js' +import ota from './module/ota.js' import timbre from "./module/timbre.js" import user from './module/user.js' -import ota from './module/ota.js' - /** * 接口地址 * 开发时自动读取使用.env.development文件 @@ -32,5 +32,6 @@ export default { device, model, timbre, - ota + ota, + dict } diff --git a/main/manager-web/src/apis/module/dict.js b/main/manager-web/src/apis/module/dict.js new file mode 100644 index 00000000..caf78279 --- /dev/null +++ b/main/manager-web/src/apis/module/dict.js @@ -0,0 +1,227 @@ +import { getServiceUrl } from '../api'; +import RequestService from '../httpRequest'; + +export default { + // 获取字典类型列表 + getDictTypeList(params, callback) { + const queryParams = new URLSearchParams({ + dictType: params.dictType || '', + dictName: params.dictName || '', + page: params.page || 1, + limit: params.limit || 10 + }).toString(); + + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/type/page?${queryParams}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取字典类型列表失败:', err) + this.$message.error(err.msg || '获取字典类型列表失败') + RequestService.reAjaxFun(() => { + this.getDictTypeList(params, callback) + }) + }).send() + }, + + // 获取字典类型详情 + getDictTypeDetail(id, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/type/${id}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取字典类型详情失败:', err) + this.$message.error(err.msg || '获取字典类型详情失败') + RequestService.reAjaxFun(() => { + this.getDictTypeDetail(id, callback) + }) + }).send() + }, + + // 新增字典类型 + addDictType(data, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/type/save`) + .method('POST') + .data(data) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('新增字典类型失败:', err) + this.$message.error(err.msg || '新增字典类型失败') + RequestService.reAjaxFun(() => { + this.addDictType(data, callback) + }) + }).send() + }, + + // 更新字典类型 + updateDictType(data, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/type/update`) + .method('PUT') + .data(data) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('更新字典类型失败:', err) + this.$message.error(err.msg || '更新字典类型失败') + RequestService.reAjaxFun(() => { + this.updateDictType(data, callback) + }) + }).send() + }, + + // 删除字典类型 + deleteDictType(ids, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/type/delete`) + .method('POST') + .data(ids) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('删除字典类型失败:', err) + this.$message.error(err.msg || '删除字典类型失败') + RequestService.reAjaxFun(() => { + this.deleteDictType(ids, callback) + }) + }).send() + }, + + // 获取字典数据列表 + getDictDataList(params, callback) { + const queryParams = new URLSearchParams({ + dictTypeId: params.dictTypeId, + dictLabel: params.dictLabel || '', + dictValue: params.dictValue || '', + page: params.page || 1, + limit: params.limit || 10 + }).toString(); + + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/data/page?${queryParams}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取字典数据列表失败:', err) + this.$message.error(err.msg || '获取字典数据列表失败') + RequestService.reAjaxFun(() => { + this.getDictDataList(params, callback) + }) + }).send() + }, + + // 获取字典数据详情 + getDictDataDetail(id, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/data/${id}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取字典数据详情失败:', err) + this.$message.error(err.msg || '获取字典数据详情失败') + RequestService.reAjaxFun(() => { + this.getDictDataDetail(id, callback) + }) + }).send() + }, + + // 新增字典数据 + addDictData(data, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/data/save`) + .method('POST') + .data(data) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('新增字典数据失败:', err) + this.$message.error(err.msg || '新增字典数据失败') + RequestService.reAjaxFun(() => { + this.addDictData(data, callback) + }) + }).send() + }, + + // 更新字典数据 + updateDictData(data, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/data/update`) + .method('PUT') + .data(data) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('更新字典数据失败:', err) + this.$message.error(err.msg || '更新字典数据失败') + RequestService.reAjaxFun(() => { + this.updateDictData(data, callback) + }) + }).send() + }, + + // 删除字典数据 + deleteDictData(ids, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/data/delete`) + .method('POST') + .data(ids) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('删除字典数据失败:', err) + this.$message.error(err.msg || '删除字典数据失败') + RequestService.reAjaxFun(() => { + this.deleteDictData(ids, callback) + }) + }).send() + }, + + // 获取字典数据列表 + getDictDataByType(dictType) { + return new Promise((resolve, reject) => { + RequestService.sendRequest() + .url(`${getServiceUrl()}/admin/dict/data/type/${dictType}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + if (res.data && res.data.code === 0) { + resolve(res.data) + } else { + reject(new Error(res.data?.msg || '获取字典数据列表失败')) + } + }) + .fail((err) => { + console.error('获取字典数据列表失败:', err) + reject(err) + }).send() + }) + } + +} \ No newline at end of file diff --git a/main/manager-web/src/components/DictDataDialog.vue b/main/manager-web/src/components/DictDataDialog.vue new file mode 100644 index 00000000..7934602b --- /dev/null +++ b/main/manager-web/src/components/DictDataDialog.vue @@ -0,0 +1,105 @@ + + + + + \ No newline at end of file diff --git a/main/manager-web/src/components/DictTypeDialog.vue b/main/manager-web/src/components/DictTypeDialog.vue new file mode 100644 index 00000000..a9a7aa07 --- /dev/null +++ b/main/manager-web/src/components/DictTypeDialog.vue @@ -0,0 +1,86 @@ + + + + + \ No newline at end of file diff --git a/main/manager-web/src/components/FirmwareDialog.vue b/main/manager-web/src/components/FirmwareDialog.vue index fab99a57..940fbbeb 100644 --- a/main/manager-web/src/components/FirmwareDialog.vue +++ b/main/manager-web/src/components/FirmwareDialog.vue @@ -38,7 +38,6 @@ + + \ No newline at end of file diff --git a/main/manager-web/src/views/OtaManagement.vue b/main/manager-web/src/views/OtaManagement.vue index 106e12fb..300e83ad 100644 --- a/main/manager-web/src/views/OtaManagement.vue +++ b/main/manager-web/src/views/OtaManagement.vue @@ -96,8 +96,8 @@ - + @@ -109,7 +109,6 @@ import Api from "@/apis/api"; import FirmwareDialog from "@/components/FirmwareDialog.vue"; import HeaderBar from "@/components/HeaderBar.vue"; import VersionFooter from "@/components/VersionFooter.vue"; -import { FIRMWARE_TYPES } from "@/utils"; import { formatDate, formatFileSize } from "@/utils/format"; export default { @@ -136,10 +135,12 @@ export default { remark: "", firmwarePath: "" }, + firmwareTypes: [], }; }, created() { this.fetchFirmwareList(); + this.getFirmwareTypes(); }, computed: { @@ -387,9 +388,18 @@ export default { }, formatDate, formatFileSize, + async getFirmwareTypes() { + try { + const res = await Api.dict.getDictDataByType('FIRMWARE_TYPE') + this.firmwareTypes = res.data + } catch (error) { + console.error('获取固件类型失败:', error) + this.$message.error(error.message || '获取固件类型失败') + } + }, getFirmwareTypeName(type) { - const firmwareType = FIRMWARE_TYPES.find(item => item.key === type); - return firmwareType ? firmwareType.name : type; + const firmwareType = this.firmwareTypes.find(item => item.key === type) + return firmwareType ? firmwareType.name : type }, }, }; diff --git a/main/manager-web/src/views/UserManagement.vue b/main/manager-web/src/views/UserManagement.vue index eb43a959..87ce3747 100644 --- a/main/manager-web/src/views/UserManagement.vue +++ b/main/manager-web/src/views/UserManagement.vue @@ -26,6 +26,11 @@ + + +