Compare commits

..

29 Commits

Author SHA1 Message Date
670e37e7a6 fix(basic): 修正阿里云 OSS 文件存储域名
All checks were successful
ZhenTu-BE/pipeline/head This commit looks good
- 移除了之前在 DeviceFactory 类中对 AliOssStorageOperator 初始化时添加的 "-internal" 后缀- 此修改解决了因内部域名错误导致的文件存储失败问题
2025-09-09 13:43:03 +08:00
13640c88d3 Merge branch 'fix' 2025-09-09 13:40:50 +08:00
ac91921c28 refactor(device): 优化文件列表获取逻辑
- 移除了不必要的循环遍历,简化了代码结构
- 仅根据起始日期获取一次文件列表,提高了效率- 清除了无用的日历操作,减少了代码复杂性
2025-09-09 13:32:58 +08:00
9e9e245801 fix(task): 调整视频剪辑命令的参数顺序
- 将 '-ss' 参数及其值移动到 '-i' 参数之后
- 优化了 ffmpeg 命令的参数顺序,提高视频处理效率
2025-09-09 13:13:17 +08:00
9587354d0a fix(device): 修复阿里云 OSS 文件检索和连接问题
- 修改 AliOssStorageOperator 中的时间增量,从分钟改为天
- 在 DeviceFactory 中为阿里云 OSS操作器添加域名替换,以解决连接问题
2025-09-09 13:08:42 +08:00
3697093bed refactor(task): 移除视频上传相关代码
- 删除了 TaskTaskServiceImpl 中的视频上传调用
- 移除了 VideoReUploader 中的 addVideoTask 方法和相关代码
- 优化了代码结构,减少了不必要的导入
2025-09-09 12:59:55 +08:00
1e3d2e9e3a perf(task): 调整 FFmpeg 命令参数顺序以优化视频处理
- 将 -ss 参数移到 -i 参数之前,以提高视频处理效率
-这种修改可以减少 FFmpeg 在处理视频时的计算量,从而加快处理速度
2025-09-09 12:52:45 +08:00
c593e0c7e9 fix(task): 修复巡逻时长计算逻辑
- 将 endDate 的计算方式从 0 分钟偏移改为 1 分钟偏移
- 这样可以确保包含第一张人脸采样图片在内的时间区间为 [startDate, endDate)- 从而更准确地计算巡逻时长
2025-09-09 12:18:05 +08:00
a641acee88 refactor(TaskTaskServiceImpl): 添加 DeviceConfigManager 导入
- 在 TaskTaskServiceImpl 类中添加了 DeviceConfigManager 的导入
- 此
2025-09-09 11:41:18 +08:00
ef61ce9d63 Merge branch 'render-worker-microservice'
# Conflicts:
#	src/main/java/com/ycwl/basic/integration/scenic/service/ScenicIntegrationService.java
#	src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java
2025-09-09 11:00:10 +08:00
aa683a62c4 refactor(task): 优化任务获取逻辑
- 在 TaskTaskServiceImpl 中添加 limit(1) 以限制获取的任务数量为 1
- 在 TaskMapper.xml 中移除 selectNotRunning 查询中的 limit 1条件
2025-09-09 10:57:56 +08:00
5426f61328 fix(task): 修复获取工作者信息逻辑
- 在获取工作者信息时增加状态检查
- 确保只返回状态为 1 的
2025-09-09 10:03:16 +08:00
9ec222a155 Merge branch 'rem_old_price_config' 2025-09-09 09:47:45 +08:00
a8711f6d19 fix(viid): 修复人脸上传适配器为空时的处理逻辑
- 增加了对人脸上传适配器为空的检查,避免空指针异常
- 优化了人脸添加的逻辑,增加了异常捕获和日志记录
- 调整了任务调度的顺序,确保人脸添加成功后再添加任务
2025-09-09 09:46:45 +08:00
c3101ceb6b feat(task): 优化任务分发逻辑
- 新增自托管景点缓存机制,减少重复查询
- 修改任务分配逻辑,排除自托管景点的任务
- 优化景点唯一性配置的读取方式
2025-09-08 10:47:07 +08:00
4ee79b5db8 refactor: 删除渲染机管理相关代码
- 移除 RenderWorkerController、RenderWorkerMapper、RenderWorkerEntity、RenderWorkerService 等类
- 删除相关的 XML 配置文件
- 清理数据库表结构
2025-09-08 00:12:18 +08:00
502eca10f6 refactor(integration): 重构渲染工作器相关 DTO 类的字段命名
- 将蛇形命名法(snake_case)改为驼峰命名法(camelCase)
- 更新了以下几个 DTO 类的字段名: - RenderWorkerConfigV2DTO  - CreateRenderWorkerRequest - RenderWorkerV2DTO - RenderWorkerV2WithConfigDTO
  - UpdateRenderWorkerRequest- 主要更改集中在配置键、值、类型以及时间相关字段上
2025-09-07 14:57:47 +08:00
e574f49177 refactor(integration): 重构设备和服务配置
- 修改 DefaultConfigIntegrationService 类名以更准确地反映其功能
- 移除不必要的导入和注解
- 统一命名规范

# Conflicts:
#	src/main/java/com/ycwl/basic/integration/questionnaire/config/QuestionnaireIntegrationConfig.java
2025-09-07 14:45:21 +08:00
7696c934b1 feat(pc): 重构渲染工作器管理接口并添加配置管理功能- 重新设计了渲染工作器管理接口,简化了操作流程- 添加了渲染工作器配置管理相关接口,包括创建、更新、删除等操作
- 优化了代码结构,提高了可维护性和可扩展性
2025-09-07 14:43:36 +08:00
c4acdc576a refactor(pc): 重构价格配置相关代码
- 移除了 PriceConfigController 中的冗余方法- 删除了 VideoController 中的 @Deprecated 注解
- 移除了 PriceConfigEntity 中的 @TableName 注解
- 重构了 PriceRepository 中的 getPriceByScenicTypeGoods 方法
- 删除了 PriceConfigServiceImpl 和 PriceConfigService 接口- 移除了 PriceConfigMapper接口和对应的 XML 文件
2025-09-07 14:31:35 +08:00
d7c6ce9f40 refactor(basic): 重构渲染机相关代码
- 移除了 RenderWorkerMapper 中的未使用的接口
- 精简了 RenderWorkerEntity 中的字段
-重构了 RenderWorkerRepository 中的缓存逻辑
- 更新了 RenderWorkerService 接口和实现类,使用新的 RenderWorkerRespVO 响应对象
- 调整了 TaskTaskServiceImpl 中的渲染机相关代码,使用新的配置管理方式
2025-09-06 00:18:50 +08:00
ffad1c9f59 refactor(device): 重构默认配置接口返回类型
- 将 DefaultConfigClient 中的 listDefaultConfigs 方法返回类型由 PageResponse 改为 CommonResponse<PageResponse>
- 更新 DefaultConfigIntegrationService 中的调用方式
- 移除 handlePageResponse 方法,改为使用 handleResponse 方法处理响应
2025-09-05 16:51:47 +08:00
c9f7080615 refactor(device): 优化默认配置示例代码
- 移除了不必要的 getData() 调用,直接使用 getList() 和 getTotal() 方法
- 使用 Java 8 Stream API 简化了部分代码,提高了可读性
- 优化了配置类型分布统计逻辑,使用更简洁的方式
2025-09-05 15:48:54 +08:00
7b22baeb66 refactor(device): 更新验证注解导入
- 将 javax.validation相关的导入语句替换为 jakarta.validation
- 此更改是为了适应 Jakarta EE 规范的最新版本
2025-09-05 15:48:03 +08:00
b2a95ed862 feat(integration): 添加渲染工作器配置管理功能
- 新增 RenderWorkerConfigManager 类实现渲染工作器配置的管理功能
- 在 RenderWorkerRepository 中集成 RenderWorkerConfigManager
- 添加方法 getWorkerConfigManager 获取渲染工作器配置管理器实例
- 优化 getWorkerByAccessKey 和 getWorker 方法,使用集成服务获取工作器信息
2025-09-05 14:49:19 +08:00
933818d458 feat(device): 添加默认配置管理功能
- 新增 DefaultConfigClient接口,用于与设备微服务进行默认配置相关的操作
- 实现 DefaultConfigIntegrationService 类,提供默认配置管理的高阶服务- 添加批量配置请求构建器 BatchDefaultConfigRequestBuilder,简化批量操作
- 新增 DefaultConfigIntegrationExample 示例类,演示默认配置管理的使用方法
- 更新 CLAUDE.md 文档,增加默认配置管理的详细使用说明和示例代码
2025-09-05 14:49:06 +08:00
933a1209e7 refactor(render): 重构渲染工作器列表接口和 DTO
- 更新 RenderWorkerV2Client 中的 listWorkers 和 listWorkersWithConfig 方法返回类型
- 删除 RenderWorkerV2ListResponse 和 RenderWorkerV2WithConfigListResponse 类
- 更新 CreateRenderWorkerRequest 中的导入路径- 重构 RenderWorkerIntegrationService 中的 listWorkers 和 listWorkersWithConfig 方法
2025-09-05 12:17:44 +08:00
aa4a6c29c6 refactor(device): 重构设备列表接口返回类型
- 将 DeviceV2ListResponse 和 DeviceV2WithConfigListResponse 替换为通用的 PageResponse 类
- 更新相关控制器、服务和客户端接口以使用新的返回类型
- 删除冗余的 DeviceV2ListResponse 和 DeviceV2WithConfigListResponse 类
- 调整 FilterDevicesByConfigsResponse 中的 total 字段类型
2025-09-05 12:17:33 +08:00
60ce65f3e4 feat(integration): 添加渲染工作器服务集成
- 新增 RenderWorkerConfigV2Client 和 RenderWorkerV2Client 接口
- 实现 RenderWorkerConfigIntegrationService 和 RenderWorkerIntegrationService 服务类
- 添加相关 DTO 类和 BatchConfigBuilder 工具类
- 在 IntegrationProperties 中增加 render 相关配置
- 更新 CommonResponse 类,增加 success 字段
- 新增 RenderWorkerIntegrationConfig 配置类
2025-09-05 11:46:19 +08:00
64 changed files with 2749 additions and 983 deletions

View File

@@ -1,7 +1,7 @@
package com.ycwl.basic.controller.pc; package com.ycwl.basic.controller.pc;
import com.ycwl.basic.integration.scenic.dto.config.DefaultConfigDTO; import com.ycwl.basic.integration.scenic.dto.config.DefaultConfigDTO;
import com.ycwl.basic.integration.scenic.service.DefaultConfigIntegrationService; import com.ycwl.basic.integration.scenic.service.ScenicDefaultConfigIntegrationService;
import com.ycwl.basic.utils.ApiConst; import com.ycwl.basic.utils.ApiConst;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -20,7 +20,7 @@ import java.util.List;
@RequiredArgsConstructor @RequiredArgsConstructor
public class DefaultConfigController { public class DefaultConfigController {
private final DefaultConfigIntegrationService defaultConfigIntegrationService; private final ScenicDefaultConfigIntegrationService scenicDefaultConfigIntegrationService;
/** /**
* 获取默认配置列表 * 获取默认配置列表
@@ -29,7 +29,7 @@ public class DefaultConfigController {
public ApiResponse<List<DefaultConfigDTO>> listDefaultConfigs() { public ApiResponse<List<DefaultConfigDTO>> listDefaultConfigs() {
log.info("获取默认配置列表"); log.info("获取默认配置列表");
try { try {
List<DefaultConfigDTO> configs = defaultConfigIntegrationService.listDefaultConfigs(); List<DefaultConfigDTO> configs = scenicDefaultConfigIntegrationService.listDefaultConfigs();
return ApiResponse.success(configs); return ApiResponse.success(configs);
} catch (Exception e) { } catch (Exception e) {
log.error("获取默认配置列表失败", e); log.error("获取默认配置列表失败", e);
@@ -44,7 +44,7 @@ public class DefaultConfigController {
public ApiResponse<DefaultConfigDTO> getDefaultConfig(@PathVariable String configKey) { public ApiResponse<DefaultConfigDTO> getDefaultConfig(@PathVariable String configKey) {
log.info("获取默认配置, configKey: {}", configKey); log.info("获取默认配置, configKey: {}", configKey);
try { try {
DefaultConfigDTO config = defaultConfigIntegrationService.getDefaultConfig(configKey); DefaultConfigDTO config = scenicDefaultConfigIntegrationService.getDefaultConfig(configKey);
return ApiResponse.success(config); return ApiResponse.success(config);
} catch (Exception e) { } catch (Exception e) {
log.error("获取默认配置失败, configKey: {}", configKey, e); log.error("获取默认配置失败, configKey: {}", configKey, e);
@@ -59,7 +59,7 @@ public class DefaultConfigController {
public ApiResponse<DefaultConfigDTO> createDefaultConfig(@RequestBody DefaultConfigDTO request) { public ApiResponse<DefaultConfigDTO> createDefaultConfig(@RequestBody DefaultConfigDTO request) {
log.info("创建默认配置, configKey: {}", request.getConfigKey()); log.info("创建默认配置, configKey: {}", request.getConfigKey());
try { try {
DefaultConfigDTO config = defaultConfigIntegrationService.createDefaultConfig(request); DefaultConfigDTO config = scenicDefaultConfigIntegrationService.createDefaultConfig(request);
return ApiResponse.success(config); return ApiResponse.success(config);
} catch (Exception e) { } catch (Exception e) {
log.error("创建默认配置失败, configKey: {}", request.getConfigKey(), e); log.error("创建默认配置失败, configKey: {}", request.getConfigKey(), e);
@@ -75,7 +75,7 @@ public class DefaultConfigController {
@RequestBody DefaultConfigDTO request) { @RequestBody DefaultConfigDTO request) {
log.info("更新默认配置, configKey: {}", configKey); log.info("更新默认配置, configKey: {}", configKey);
try { try {
DefaultConfigDTO config = defaultConfigIntegrationService.updateDefaultConfig(configKey, request); DefaultConfigDTO config = scenicDefaultConfigIntegrationService.updateDefaultConfig(configKey, request);
return ApiResponse.success(config); return ApiResponse.success(config);
} catch (Exception e) { } catch (Exception e) {
log.error("更新默认配置失败, configKey: {}", configKey, e); log.error("更新默认配置失败, configKey: {}", configKey, e);
@@ -90,7 +90,7 @@ public class DefaultConfigController {
public ApiResponse<Void> deleteDefaultConfig(@PathVariable String configKey) { public ApiResponse<Void> deleteDefaultConfig(@PathVariable String configKey) {
log.info("删除默认配置, configKey: {}", configKey); log.info("删除默认配置, configKey: {}", configKey);
try { try {
defaultConfigIntegrationService.deleteDefaultConfig(configKey); scenicDefaultConfigIntegrationService.deleteDefaultConfig(configKey);
return ApiResponse.buildResponse(ApiConst.Code.CODE_SUCCESS.code(), null, "删除成功"); return ApiResponse.buildResponse(ApiConst.Code.CODE_SUCCESS.code(), null, "删除成功");
} catch (Exception e) { } catch (Exception e) {
log.error("删除默认配置失败, configKey: {}", configKey, e); log.error("删除默认配置失败, configKey: {}", configKey, e);

View File

@@ -1,6 +1,7 @@
package com.ycwl.basic.controller.pc; package com.ycwl.basic.controller.pc;
import com.ycwl.basic.integration.device.dto.config.*; import com.ycwl.basic.integration.device.dto.config.*;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.device.*; import com.ycwl.basic.integration.device.dto.device.*;
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService; import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService; import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
@@ -35,7 +36,7 @@ public class DeviceV2Controller {
* 设备V2核心信息分页列表 * 设备V2核心信息分页列表
*/ */
@GetMapping("/") @GetMapping("/")
public ApiResponse<DeviceV2ListResponse> listDevices(@RequestParam(defaultValue = "1") Integer page, public ApiResponse<PageResponse<DeviceV2DTO>> listDevices(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String name, @RequestParam(required = false) String name,
@RequestParam(required = false) String no, @RequestParam(required = false) String no,
@@ -51,7 +52,7 @@ public class DeviceV2Controller {
} }
try { try {
DeviceV2ListResponse response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, isActive, scenicId); PageResponse<DeviceV2DTO> response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, isActive, scenicId);
return ApiResponse.success(response); return ApiResponse.success(response);
} catch (Exception e) { } catch (Exception e) {
log.error("分页查询设备核心信息列表失败", e); log.error("分页查询设备核心信息列表失败", e);
@@ -63,7 +64,7 @@ public class DeviceV2Controller {
* 设备V2带配置信息分页列表 * 设备V2带配置信息分页列表
*/ */
@GetMapping("/with-config") @GetMapping("/with-config")
public ApiResponse<DeviceV2WithConfigListResponse> listDevicesWithConfig(@RequestParam(defaultValue = "1") Integer page, public ApiResponse<PageResponse<DeviceV2WithConfigDTO>> listDevicesWithConfig(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String name, @RequestParam(required = false) String name,
@RequestParam(required = false) String no, @RequestParam(required = false) String no,
@@ -79,7 +80,7 @@ public class DeviceV2Controller {
} }
try { try {
DeviceV2WithConfigListResponse response = deviceIntegrationService.listDevicesWithConfig(page, pageSize, name, no, type, isActive, scenicId); PageResponse<DeviceV2WithConfigDTO> response = deviceIntegrationService.listDevicesWithConfig(page, pageSize, name, no, type, isActive, scenicId);
return ApiResponse.success(response); return ApiResponse.success(response);
} catch (Exception e) { } catch (Exception e) {
log.error("分页查询设备带配置信息列表失败", e); log.error("分页查询设备带配置信息列表失败", e);
@@ -431,12 +432,12 @@ public class DeviceV2Controller {
* 获取景区IPC设备列表 * 获取景区IPC设备列表
*/ */
@GetMapping("/scenic/{scenicId}/ipc") @GetMapping("/scenic/{scenicId}/ipc")
public ApiResponse<DeviceV2ListResponse> getScenicIpcDevices(@PathVariable Long scenicId, public ApiResponse<PageResponse<DeviceV2DTO>> getScenicIpcDevices(@PathVariable Long scenicId,
@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize) { @RequestParam(defaultValue = "10") Integer pageSize) {
log.info("获取景区IPC设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize); log.info("获取景区IPC设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize);
try { try {
DeviceV2ListResponse response = deviceIntegrationService.getScenicIpcDevices(scenicId, page, pageSize); PageResponse<DeviceV2DTO> response = deviceIntegrationService.getScenicIpcDevices(scenicId, page, pageSize);
return ApiResponse.success(response); return ApiResponse.success(response);
} catch (Exception e) { } catch (Exception e) {
log.error("获取景区IPC设备列表失败, scenicId: {}", scenicId, e); log.error("获取景区IPC设备列表失败, scenicId: {}", scenicId, e);
@@ -448,12 +449,12 @@ public class DeviceV2Controller {
* 获取景区激活设备列表 * 获取景区激活设备列表
*/ */
@GetMapping("/scenic/{scenicId}/active") @GetMapping("/scenic/{scenicId}/active")
public ApiResponse<DeviceV2ListResponse> getScenicActiveDevices(@PathVariable Long scenicId, public ApiResponse<PageResponse<DeviceV2DTO>> getScenicActiveDevices(@PathVariable Long scenicId,
@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize) { @RequestParam(defaultValue = "10") Integer pageSize) {
log.info("获取景区激活设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize); log.info("获取景区激活设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize);
try { try {
DeviceV2ListResponse response = deviceIntegrationService.getScenicActiveDevices(scenicId, page, pageSize); PageResponse<DeviceV2DTO> response = deviceIntegrationService.getScenicActiveDevices(scenicId, page, pageSize);
return ApiResponse.success(response); return ApiResponse.success(response);
} catch (Exception e) { } catch (Exception e) {
log.error("获取景区激活设备列表失败, scenicId: {}", scenicId, e); log.error("获取景区激活设备列表失败, scenicId: {}", scenicId, e);
@@ -465,12 +466,12 @@ public class DeviceV2Controller {
* 获取景区所有设备列表 * 获取景区所有设备列表
*/ */
@GetMapping("/scenic/{scenicId}/all") @GetMapping("/scenic/{scenicId}/all")
public ApiResponse<DeviceV2ListResponse> getScenicAllDevices(@PathVariable Long scenicId, public ApiResponse<PageResponse<DeviceV2DTO>> getScenicAllDevices(@PathVariable Long scenicId,
@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize) { @RequestParam(defaultValue = "10") Integer pageSize) {
log.info("获取景区所有设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize); log.info("获取景区所有设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize);
try { try {
DeviceV2ListResponse response = deviceIntegrationService.listDevices(page, pageSize, null, null, null, null, scenicId); PageResponse<DeviceV2DTO> response = deviceIntegrationService.listDevices(page, pageSize, null, null, null, null, scenicId);
return ApiResponse.success(response); return ApiResponse.success(response);
} catch (Exception e) { } catch (Exception e) {
log.error("获取景区所有设备列表失败, scenicId: {}", scenicId, e); log.error("获取景区所有设备列表失败, scenicId: {}", scenicId, e);

View File

@@ -1,13 +1,7 @@
package com.ycwl.basic.controller.pc; package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageHelper; import com.ycwl.basic.biz.PriceBiz;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO; import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import com.ycwl.basic.repository.PriceRepository;
import com.ycwl.basic.service.pc.PriceConfigService;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -19,61 +13,11 @@ import java.util.List;
public class PriceConfigController { public class PriceConfigController {
@Autowired @Autowired
private PriceConfigService priceConfigService; private PriceBiz priceBiz;
@Autowired
private PriceRepository priceRepository;
@GetMapping("/goodsList") @GetMapping("/goodsList")
public ApiResponse<List<GoodsListRespVO>> goodsList(@RequestParam Long scenicId) { public ApiResponse<List<GoodsListRespVO>> goodsList(@RequestParam Long scenicId) {
return ApiResponse.success(priceConfigService.listGoodsByScenic(scenicId)); return ApiResponse.success(priceBiz.listGoodsByScenic(scenicId));
} }
@PostMapping("/add")
public ApiResponse<PriceConfigEntity> addPriceConfig(@RequestBody PriceConfigEntity priceConfig) {
priceConfig.setId(null);
priceConfigService.save(priceConfig);
return ApiResponse.success(priceConfig);
}
@PostMapping("/update")
public ApiResponse<PriceConfigEntity> updatePriceConfig(@RequestBody PriceConfigEntity priceConfig) {
priceRepository.clearPriceCache(priceConfig.getId());
priceConfigService.updateById(priceConfig);
priceRepository.clearPriceCache(priceConfig.getId());
return ApiResponse.success(priceConfig);
}
@DeleteMapping("/delete/{id}")
public ApiResponse<Boolean> deletePriceConfig(@PathVariable Integer id) {
priceRepository.clearPriceCache(id);
priceConfigService.removeById(id);
priceRepository.clearPriceCache(id);
return ApiResponse.success(true);
}
@PostMapping("/{id}/status")
public ApiResponse<Boolean> updateStatus(@PathVariable Integer id) {
priceRepository.clearPriceCache(id);
priceConfigService.updateStatus(id);
priceRepository.clearPriceCache(id);
return ApiResponse.success(true);
}
@GetMapping("/{id}")
public ApiResponse<PriceConfigRespVO> getPriceConfigById(@PathVariable Integer id) {
PriceConfigRespVO config = priceConfigService.findById(id);
priceConfigService.fillGoodsName(config);
return ApiResponse.success(config);
}
@GetMapping("/list")
public ApiResponse<PageInfo<PriceConfigRespVO>> list(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
@ModelAttribute PriceConfigListReq req) {
PageHelper.startPage(pageNum, pageSize);
List<PriceConfigRespVO> result = priceConfigService.listByCondition(req);
priceConfigService.fillGoodsName(result);
PageInfo<PriceConfigRespVO> pageInfo = new PageInfo<>(result);
return ApiResponse.success(pageInfo);
}
} }

View File

@@ -0,0 +1,196 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest;
import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO;
import com.ycwl.basic.integration.render.service.RenderWorkerConfigIntegrationService;
import com.ycwl.basic.utils.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 渲染工作器配置管理 V2 版本控制器
* 基于 zt-render-worker 微服务标准接口实现
*
* @author Claude Code
* @date 2025-09-06
*/
@Slf4j
@RestController
@RequestMapping("/api/render/worker/config/v2")
@RequiredArgsConstructor
public class RenderWorkerConfigV2Controller {
private final RenderWorkerConfigIntegrationService configIntegrationService;
/**
* 获取工作器所有配置
*
* @param workerId 工作器ID
* @return 工作器配置列表
*/
@GetMapping("/{workerId}")
public ApiResponse<List<RenderWorkerConfigV2DTO>> getWorkerConfigs(@PathVariable Long workerId) {
log.info("获取渲染工作器配置列表, workerId: {}", workerId);
try {
List<RenderWorkerConfigV2DTO> configs = configIntegrationService.getWorkerConfigs(workerId);
return ApiResponse.success(configs);
} catch (Exception e) {
log.error("获取渲染工作器配置列表失败, workerId: {}", workerId, e);
return ApiResponse.fail("获取渲染工作器配置列表失败: " + e.getMessage());
}
}
/**
* 获取工作器平铺配置
*
* @param workerId 工作器ID
* @return 平铺配置Map
*/
@GetMapping("/{workerId}/flat")
public ApiResponse<Map<String, Object>> getWorkerFlatConfig(@PathVariable Long workerId) {
log.info("获取渲染工作器平铺配置, workerId: {}", workerId);
try {
Map<String, Object> flatConfig = configIntegrationService.getWorkerFlatConfig(workerId);
return ApiResponse.success(flatConfig);
} catch (Exception e) {
log.error("获取渲染工作器平铺配置失败, workerId: {}", workerId, e);
return ApiResponse.fail("获取渲染工作器平铺配置失败: " + e.getMessage());
}
}
/**
* 根据配置键获取特定配置
*
* @param workerId 工作器ID
* @param configKey 配置键
* @return 配置信息
*/
@GetMapping("/{workerId}/key/{configKey}")
public ApiResponse<RenderWorkerConfigV2DTO> getWorkerConfigByKey(@PathVariable Long workerId,
@PathVariable String configKey) {
log.info("根据配置键获取渲染工作器配置, workerId: {}, configKey: {}", workerId, configKey);
try {
RenderWorkerConfigV2DTO config = configIntegrationService.getWorkerConfigByKey(workerId, configKey);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("根据配置键获取渲染工作器配置失败, workerId: {}, configKey: {}", workerId, configKey, e);
return ApiResponse.fail("根据配置键获取渲染工作器配置失败: " + e.getMessage());
}
}
/**
* 创建工作器配置
*
* @param workerId 工作器ID
* @param config 配置信息
* @return 创建的配置信息
*/
@PostMapping("/{workerId}")
public ApiResponse<RenderWorkerConfigV2DTO> createWorkerConfig(@PathVariable Long workerId,
@Valid @RequestBody RenderWorkerConfigV2DTO config) {
log.info("创建渲染工作器配置, workerId: {}, configKey: {}", workerId, config.getConfigKey());
try {
RenderWorkerConfigV2DTO result = configIntegrationService.createWorkerConfig(workerId, config);
return ApiResponse.success(result);
} catch (Exception e) {
log.error("创建渲染工作器配置失败, workerId: {}", workerId, e);
return ApiResponse.fail("创建渲染工作器配置失败: " + e.getMessage());
}
}
/**
* 更新工作器配置
*
* @param workerId 工作器ID
* @param configId 配置ID
* @param updates 更新内容
* @return 操作结果
*/
@PutMapping("/{workerId}/{configId}")
public ApiResponse<Void> updateWorkerConfig(@PathVariable Long workerId,
@PathVariable Long configId,
@Valid @RequestBody Map<String, Object> updates) {
log.info("更新渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
try {
configIntegrationService.updateWorkerConfig(workerId, configId, updates);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("更新渲染工作器配置失败, workerId: {}, configId: {}", workerId, configId, e);
return ApiResponse.fail("更新渲染工作器配置失败: " + e.getMessage());
}
}
/**
* 删除工作器配置
*
* @param workerId 工作器ID
* @param configId 配置ID
* @return 操作结果
*/
@DeleteMapping("/{workerId}/{configId}")
public ApiResponse<Void> deleteWorkerConfig(@PathVariable Long workerId,
@PathVariable Long configId) {
log.info("删除渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
try {
configIntegrationService.deleteWorkerConfig(workerId, configId);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("删除渲染工作器配置失败, workerId: {}, configId: {}", workerId, configId, e);
return ApiResponse.fail("删除渲染工作器配置失败: " + e.getMessage());
}
}
/**
* 批量更新工作器配置
*
* @param workerId 工作器ID
* @param request 批量配置请求
* @return 操作结果
*/
@PostMapping("/{workerId}/batch")
public ApiResponse<Void> batchUpdateWorkerConfigs(@PathVariable Long workerId,
@Valid @RequestBody BatchRenderWorkerConfigRequest request) {
log.info("批量更新渲染工作器配置, workerId: {}, configCount: {}",
workerId, request.getConfigs() != null ? request.getConfigs().size() : 0);
try {
configIntegrationService.batchUpdateWorkerConfigs(workerId, request);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("批量更新渲染工作器配置失败, workerId: {}", workerId, e);
return ApiResponse.fail("批量更新渲染工作器配置失败: " + e.getMessage());
}
}
/**
* 批量平铺更新工作器配置
*
* @param workerId 工作器ID
* @param flatConfigs 平铺配置Map
* @return 操作结果
*/
@PostMapping("/{workerId}/flat-batch")
public ApiResponse<Void> batchFlatUpdateWorkerConfigs(@PathVariable Long workerId,
@Valid @RequestBody Map<String, Object> flatConfigs) {
log.info("批量平铺更新渲染工作器配置, workerId: {}, configCount: {}", workerId, flatConfigs.size());
try {
configIntegrationService.batchFlatUpdateWorkerConfigs(workerId, flatConfigs);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("批量平铺更新渲染工作器配置失败, workerId: {}", workerId, e);
return ApiResponse.fail("批量平铺更新渲染工作器配置失败: " + e.getMessage());
}
}
}

View File

@@ -1,61 +0,0 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery;
import com.ycwl.basic.service.pc.RenderWorkerService;
import com.ycwl.basic.utils.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @Author:longbinbin
* @Date:2024/12/3 14:59
*/
@RestController
@RequestMapping("/api/renderWorker/v1")
// 渲染机管理
public class RenderWorkerController {
@Autowired
private RenderWorkerService renderWorkerService;
// 分页查询渲染机
@PostMapping("/page")
public ApiResponse pageQuery(@RequestBody RenderWorkerReqQuery renderWorkerReqQuery){
return renderWorkerService.pageQuery(renderWorkerReqQuery);
}
// 渲染机列表查询
@PostMapping("/list")
public ApiResponse list(@RequestBody RenderWorkerReqQuery renderWorkerReqQuery){
return renderWorkerService.list(renderWorkerReqQuery);
}
// 渲染机详情查询
@GetMapping("/detail/{id}")
public ApiResponse detail(@PathVariable Long id){
return renderWorkerService.detail(id);
}
// 渲染机新增
@PostMapping("/add")
public ApiResponse add(@RequestBody RenderWorkerEntity renderWorker){
return renderWorkerService.add(renderWorker);
}
// 渲染机删除
@DeleteMapping("/delete/{id}")
public ApiResponse deleteById(@PathVariable Long id){
return renderWorkerService.deleteById(id);
}
// 渲染机修改
@PostMapping("/update")
public ApiResponse update(@RequestBody RenderWorkerEntity renderWorker){
return renderWorkerService.update(renderWorker);
}
// 渲染机修改状态
@PutMapping("/updateStatus/{id}")
public ApiResponse updateStatus(@PathVariable Long id) {
return renderWorkerService.updateStatus(id);
}
}

View File

@@ -0,0 +1,142 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.render.dto.worker.CreateRenderWorkerRequest;
import com.ycwl.basic.integration.render.dto.worker.RenderWorkerV2DTO;
import com.ycwl.basic.integration.render.dto.worker.UpdateRenderWorkerRequest;
import com.ycwl.basic.integration.render.service.RenderWorkerIntegrationService;
import com.ycwl.basic.utils.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
* 渲染工作器管理 V2 版本控制器
* 基于 zt-render-worker 微服务标准接口实现
*
* @author Claude Code
* @date 2025-09-06
*/
@Slf4j
@RestController
@RequestMapping("/api/render/worker/v2")
@RequiredArgsConstructor
public class RenderWorkerV2Controller {
private final RenderWorkerIntegrationService renderWorkerIntegrationService;
/**
* 分页查询渲染工作器列表
*
* @param page 页码,从1开始
* @param pageSize 每页大小,默认10,最大100
* @param isEnabled 是否启用(0-禁用,1-启用)
* @param name 工作器名称(模糊搜索)
* @return 分页查询结果
*/
@GetMapping
public ApiResponse<PageResponse<RenderWorkerV2DTO>> listWorkers(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer isEnabled,
@RequestParam(required = false) String name) {
log.info("分页查询渲染工作器列表, page: {}, pageSize: {}, isEnabled: {}, name: {}",
page, pageSize, isEnabled, name);
// 参数验证:限制pageSize最大值为100
if (pageSize > 100) {
pageSize = 100;
}
try {
PageResponse<RenderWorkerV2DTO> result = renderWorkerIntegrationService.listWorkers(
page, pageSize, isEnabled, name);
return ApiResponse.success(result);
} catch (Exception e) {
log.error("分页查询渲染工作器列表失败", e);
return ApiResponse.fail("分页查询渲染工作器列表失败: " + e.getMessage());
}
}
/**
* 根据ID获取渲染工作器详情
*
* @param id 工作器ID
* @return 工作器详情
*/
@GetMapping("/{id}")
public ApiResponse<RenderWorkerV2DTO> getWorker(@PathVariable Long id) {
log.info("获取渲染工作器详情, id: {}", id);
try {
RenderWorkerV2DTO worker = renderWorkerIntegrationService.getWorker(id);
return ApiResponse.success(worker);
} catch (Exception e) {
log.error("获取渲染工作器详情失败, id: {}", id, e);
return ApiResponse.fail("获取渲染工作器详情失败: " + e.getMessage());
}
}
/**
* 创建渲染工作器
*
* @param request 创建请求
* @return 创建的工作器信息
*/
@PostMapping
public ApiResponse<RenderWorkerV2DTO> createWorker(@Valid @RequestBody CreateRenderWorkerRequest request) {
log.info("创建渲染工作器, name: {}, key: {}, isActive: {}",
request.getName(), request.getKey(), request.getIsActive());
try {
RenderWorkerV2DTO worker = renderWorkerIntegrationService.createWorker(request);
return ApiResponse.success(worker);
} catch (Exception e) {
log.error("创建渲染工作器失败", e);
return ApiResponse.fail("创建渲染工作器失败: " + e.getMessage());
}
}
/**
* 更新渲染工作器
*
* @param id 工作器ID
* @param request 更新请求
* @return 操作结果
*/
@PutMapping("/{id}")
public ApiResponse<Void> updateWorker(@PathVariable Long id,
@Valid @RequestBody UpdateRenderWorkerRequest request) {
log.info("更新渲染工作器, id: {}, name: {}, isActive: {}",
id, request.getName(), request.getIsActive());
try {
renderWorkerIntegrationService.updateWorker(id, request);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("更新渲染工作器失败, id: {}", id, e);
return ApiResponse.fail("更新渲染工作器失败: " + e.getMessage());
}
}
/**
* 删除渲染工作器
*
* @param id 工作器ID
* @return 操作结果
*/
@DeleteMapping("/{id}")
public ApiResponse<Void> deleteWorker(@PathVariable Long id) {
log.info("删除渲染工作器, id: {}", id);
try {
renderWorkerIntegrationService.deleteWorker(id);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("删除渲染工作器失败, id: {}", id, e);
return ApiResponse.fail("删除渲染工作器失败: " + e.getMessage());
}
}
}

View File

@@ -9,9 +9,8 @@ import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterPageResponse;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest; import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigListResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService; import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService;
import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService; import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService;
@@ -52,7 +51,7 @@ public class ScenicV2Controller {
* 景区V2核心信息分页列表 * 景区V2核心信息分页列表
*/ */
@GetMapping("/") @GetMapping("/")
public ApiResponse<ScenicV2ListResponse> listScenics(@RequestParam(defaultValue = "1") Integer page, public ApiResponse<PageResponse<ScenicV2DTO>> listScenics(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer status, @RequestParam(required = false) Integer status,
@RequestParam(required = false) String name) { @RequestParam(required = false) String name) {
@@ -64,7 +63,7 @@ public class ScenicV2Controller {
} }
try { try {
ScenicV2ListResponse response = scenicIntegrationService.listScenics(page, pageSize, status, name); PageResponse<ScenicV2DTO> response = scenicIntegrationService.listScenics(page, pageSize, status, name);
return ApiResponse.success(response); return ApiResponse.success(response);
} catch (Exception e) { } catch (Exception e) {
log.error("分页查询景区核心信息列表失败", e); log.error("分页查询景区核心信息列表失败", e);
@@ -76,7 +75,7 @@ public class ScenicV2Controller {
* 景区V2带配置信息分页列表 * 景区V2带配置信息分页列表
*/ */
@GetMapping("/with-config") @GetMapping("/with-config")
public ApiResponse<ScenicV2WithConfigListResponse> listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page, public ApiResponse<PageResponse<ScenicV2WithConfigDTO>> listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer status, @RequestParam(required = false) Integer status,
@RequestParam(required = false) String name) { @RequestParam(required = false) String name) {
@@ -88,7 +87,7 @@ public class ScenicV2Controller {
} }
try { try {
ScenicV2WithConfigListResponse response = scenicIntegrationService.listScenicsWithConfig(page, pageSize, status, name); PageResponse<ScenicV2WithConfigDTO> response = scenicIntegrationService.listScenicsWithConfig(page, pageSize, status, name);
return ApiResponse.success(response); return ApiResponse.success(response);
} catch (Exception e) { } catch (Exception e) {
log.error("分页查询景区带配置信息列表失败", e); log.error("分页查询景区带配置信息列表失败", e);
@@ -178,11 +177,11 @@ public class ScenicV2Controller {
* 只支持根据状态筛选 * 只支持根据状态筛选
*/ */
@GetMapping("/list") @GetMapping("/list")
public ApiResponse<ScenicV2ListResponse> listScenicsByStatus(@RequestParam(required = false) Integer status) { public ApiResponse<PageResponse<ScenicV2DTO>> listScenicsByStatus(@RequestParam(required = false) Integer status) {
log.info("查询景区列表, status: {}", status); log.info("查询景区列表, status: {}", status);
try { try {
// 默认查询1000条数据,第1页 // 默认查询1000条数据,第1页
ScenicV2ListResponse scenics = scenicIntegrationService.listScenics(1, 1000, status, null); PageResponse<ScenicV2DTO> scenics = scenicIntegrationService.listScenics(1, 1000, status, null);
return ApiResponse.success(scenics); return ApiResponse.success(scenics);
} catch (Exception e) { } catch (Exception e) {
log.error("查询景区列表失败, status: {}", status, e); log.error("查询景区列表失败, status: {}", status, e);

View File

@@ -18,7 +18,6 @@ import java.util.List;
@RestController @RestController
@RequestMapping("/api/video/v1") @RequestMapping("/api/video/v1")
@Deprecated
// 视频成片管理 // 视频成片管理
public class VideoController { public class VideoController {

View File

@@ -308,6 +308,10 @@ public class ViidController {
} }
IStorageAdapter scenicStorageAdapter = scenicService.getScenicStorageAdapter(scenicId); IStorageAdapter scenicStorageAdapter = scenicService.getScenicStorageAdapter(scenicId);
IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId); IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
if (faceBodyAdapter == null) {
log.warn("人脸上传适配器不存在:" + scenicId);
continue;
}
FacePositionObject facePosition = new FacePositionObject(); FacePositionObject facePosition = new FacePositionObject();
facePosition.setLtY(face.getLeftTopY()); facePosition.setLtY(face.getLeftTopY());
facePosition.setLtX(face.getLeftTopX()); facePosition.setLtX(face.getLeftTopX());
@@ -344,13 +348,18 @@ public class ViidController {
faceSampleMapper.add(faceSample); faceSampleMapper.add(faceSample);
ThreadPoolExecutor executor = getExecutor(scenicId); ThreadPoolExecutor executor = getExecutor(scenicId);
executor.execute(() -> { executor.execute(() -> {
if (faceBodyAdapter != null) { taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString()); AddFaceResp addFaceResp;
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString()); try {
if (addFaceResp != null) { addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
faceSample.setScore(addFaceResp.getScore()); } catch (Exception e) {
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore()); log.error("人脸添加失败:{}", e.getMessage());
} return;
}
if (addFaceResp != null) {
faceSample.setScore(addFaceResp.getScore());
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore());
} }
if (Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) { if (Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) {
DynamicTaskGenerator.addTask(faceSample.getId()); DynamicTaskGenerator.addTask(faceSample.getId());
@@ -436,16 +445,20 @@ public class ViidController {
DynamicTaskGenerator.addTask(faceSample.getId()); DynamicTaskGenerator.addTask(faceSample.getId());
ThreadPoolExecutor executor = getExecutor(scenicId); ThreadPoolExecutor executor = getExecutor(scenicId);
executor.execute(() -> { executor.execute(() -> {
if (faceBodyAdapter != null) { taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString()); AddFaceResp addFaceResp;
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString()); try {
if (addFaceResp != null) { addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
faceSample.setScore(addFaceResp.getScore()); } catch (Exception e) {
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore()); log.error("人脸添加失败:{}", e.getMessage());
} return;
} }
if (Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) { if (addFaceResp != null) {
DynamicTaskGenerator.addTask(faceSample.getId()); faceSample.setScore(addFaceResp.getScore());
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore());
if (Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
} }
}); });
log.info("模式1人脸信息入库成功!设备ID:{}", deviceID); log.info("模式1人脸信息入库成功!设备ID:{}", deviceID);

View File

@@ -69,22 +69,14 @@ public class AliOssStorageOperator extends ADeviceStorageOperator {
if (startDate == null || endDate == null) { if (startDate == null || endDate == null) {
return null; return null;
} }
List<FileObject> fileList = new ArrayList<>();
if (startDate.after(endDate)) {
return fileList;
}
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate); calendar.setTime(startDate);
calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.SECOND, 0);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
while (calendar.getTime().before(endDate)) { String prefix = dateFormat.format(calendar.getTime());
String prefix = dateFormat.format(calendar.getTime()); List<FileObject> fileList = getOssFileListByPrefix(prefix);
List<FileObject> fileListByPrefix = getOssFileListByPrefix(prefix); if (fileList == null) {
if (fileListByPrefix == null) { return null;
return null;
}
fileList.addAll(fileListByPrefix);
calendar.add(Calendar.MINUTE, 1);
} }
calendar.clear(); calendar.clear();
return fileList.stream() return fileList.stream()

View File

@@ -23,6 +23,7 @@ The integration package (`com.ycwl.basic.integration`) is responsible for extern
Currently implemented: Currently implemented:
- **Scenic Integration** (`com.ycwl.basic.integration.scenic`): ZT-Scenic microservice integration - **Scenic Integration** (`com.ycwl.basic.integration.scenic`): ZT-Scenic microservice integration
- **Device Integration** (`com.ycwl.basic.integration.device`): ZT-Device microservice integration - **Device Integration** (`com.ycwl.basic.integration.device`): ZT-Device microservice integration
- **Render Worker Integration** (`com.ycwl.basic.integration.render`): ZT-Render-Worker microservice integration
### Integration Pattern ### Integration Pattern
@@ -226,10 +227,12 @@ fallbackService.clearAllFallbackCache("zt-scenic");
#### Feign Clients #### Feign Clients
- **DeviceV2Client**: Main device operations (CRUD, filtering, listing) - **DeviceV2Client**: Main device operations (CRUD, filtering, listing)
- **DeviceConfigV2Client**: Device configuration management - **DeviceConfigV2Client**: Device configuration management
- **DefaultConfigClient**: Default configuration management
#### Services #### Services
- **DeviceIntegrationService**: High-level device operations (with automatic fallback) - **DeviceIntegrationService**: High-level device operations (with automatic fallback)
- **DeviceConfigIntegrationService**: Device configuration management (with automatic fallback) - **DeviceConfigIntegrationService**: Device configuration management (with automatic fallback)
- **DefaultConfigIntegrationService**: Default configuration management (with automatic fallback)
#### Configuration #### Configuration
```yaml ```yaml
@@ -241,6 +244,13 @@ integration:
readTimeout: 10000 readTimeout: 10000
retryEnabled: false retryEnabled: false
maxRetries: 3 maxRetries: 3
render:
enabled: true
serviceName: zt-render-worker
connectTimeout: 5000
readTimeout: 10000
retryEnabled: false
maxRetries: 3
``` ```
### Usage Examples ### Usage Examples
@@ -369,6 +379,355 @@ fallbackService.clearFallbackCache("zt-device", "device:1001");
fallbackService.clearAllFallbackCache("zt-device"); fallbackService.clearAllFallbackCache("zt-device");
``` ```
## Default Configuration Management (ZT-Device Microservice)
### Key Components
#### Default Configuration API
The zt-device microservice provides a comprehensive default configuration management API at `/api/device/config/v2/defaults` that allows:
- Creating and managing default configuration templates
- Batch operations with conflict detection
- Configuration type validation and enforcement
- Usage tracking and analytics
#### Feign Client
- **DefaultConfigClient**: Default configuration management operations
#### Service
- **DefaultConfigIntegrationService**: High-level default configuration operations (with automatic fallback for queries)
### Usage Examples
#### Basic Default Configuration Operations (with Automatic Fallback)
```java
@Autowired
private DefaultConfigIntegrationService defaultConfigService;
// Get default configuration list (automatically falls back to cache on failure)
PageResponse<DefaultConfigResponse> configList = defaultConfigService.listDefaultConfigs(1, 10);
log.info("Default configs: total={}, current page={}",
configList.getData().getTotal(), configList.getData().getList().size());
// Get specific default configuration (automatically falls back to cache on failure)
DefaultConfigResponse config = defaultConfigService.getDefaultConfig("resolution");
if (config != null) {
log.info("Default resolution: {}", config.getConfigValue());
}
// Create new default configuration (direct operation, fails immediately on error)
DefaultConfigRequest newConfig = new DefaultConfigRequest();
newConfig.setConfigKey("bitrate");
newConfig.setConfigValue("2000000");
newConfig.setConfigType("int");
newConfig.setDescription("Default video bitrate in bps");
boolean created = defaultConfigService.createDefaultConfig(newConfig);
// Update default configuration with conflict detection (direct operation)
Map<String, Object> updates = new HashMap<>();
updates.put("configValue", "4000000");
updates.put("description", "Updated default bitrate - high quality");
DefaultConfigConflict conflict = defaultConfigService.updateDefaultConfig("bitrate", updates);
if (conflict != null) {
log.warn("Configuration update conflict detected:");
log.warn(" Key: {}, Type: {}, Affected devices: {}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
log.warn(" Current type: {}, Proposed type: {}",
conflict.getCurrentType(), conflict.getProposedType());
// Handle conflict - show affected device IDs
if (conflict.getConflictDevices() != null) {
log.warn(" Conflicted device IDs: {}", conflict.getConflictDevices());
}
} else {
log.info("Configuration updated successfully without conflicts");
}
// Delete default configuration (direct operation, fails immediately on error)
boolean deleted = defaultConfigService.deleteDefaultConfig("bitrate");
```
#### Batch Default Configuration Operations
```java
// Using Builder Pattern for batch operations
BatchDefaultConfigRequest batchRequest = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 30, "H265") // Add video configuration group
.addNetworkConfig("192.168.1.100", 554, "RTSP") // Add network configuration group
.addConfig("recording_enabled", "true", "bool", "Enable recording by default")
.addConfig("storage_retention", "30", "int", "Storage retention in days")
.addConfig("quality_profile", "high", "string", "Default video quality profile")
.build();
// Execute batch update (direct operation, no fallback)
BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(batchRequest);
// Process batch results
log.info("Batch operation completed: {} success, {} failed", result.getSuccess(), result.getFailed());
// Handle conflicts
if (result.getConflicts() != null && !result.getConflicts().isEmpty()) {
log.warn("Configuration conflicts detected:");
for (DefaultConfigConflict conflict : result.getConflicts()) {
log.warn(" Key: {}, Type: {}, Devices affected: {}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
}
}
// Review processed items
if (result.getProcessedItems() != null) {
result.getProcessedItems().forEach(item -> {
if ("success".equals(item.getStatus())) {
log.info("✅ {} {} successfully (type: {})",
item.getConfigKey(), item.getAction(), item.getFinalType());
} else {
log.warn("❌ {} failed: {}", item.getConfigKey(), item.getMessage());
}
});
}
// Handle errors
if (result.getErrors() != null && !result.getErrors().isEmpty()) {
result.getErrors().forEach(error -> log.error("Batch operation error: {}", error));
}
```
#### Device Type Specific Default Configuration Patterns
```java
// Create IPC camera default configurations
BatchDefaultConfigRequest ipcDefaults = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 25, "H264") // Standard HD resolution
.addConfig("night_vision", "true", "bool", "Enable night vision")
.addConfig("motion_detection", "true", "bool", "Enable motion detection")
.addConfig("stream_profile", "main", "string", "Default stream profile")
.addConfig("ptz_enabled", "false", "bool", "PTZ control enabled")
.addConfig("audio_enabled", "true", "bool", "Audio recording enabled")
.build();
// Create NVR default configurations
BatchDefaultConfigRequest nvrDefaults = defaultConfigService.createBatchConfigBuilder()
.addConfig("max_channels", "16", "int", "Maximum supported channels")
.addConfig("storage_mode", "continuous", "string", "Recording storage mode")
.addConfig("backup_enabled", "true", "bool", "Enable automatic backup")
.addConfig("raid_level", "5", "int", "Default RAID level")
.addConfig("disk_quota", "80", "int", "Disk usage quota percentage")
.build();
// Apply device-type-specific defaults
BatchDefaultConfigResponse ipcResult = defaultConfigService.batchUpdateDefaultConfigs(ipcDefaults);
BatchDefaultConfigResponse nvrResult = defaultConfigService.batchUpdateDefaultConfigs(nvrDefaults);
log.info("IPC defaults: {} success, {} failed", ipcResult.getSuccess(), ipcResult.getFailed());
log.info("NVR defaults: {} success, {} failed", nvrResult.getSuccess(), nvrResult.getFailed());
```
#### Configuration Validation and Management Patterns
```java
// Validate system configuration completeness
PageResponse<DefaultConfigResponse> allDefaults = defaultConfigService.listDefaultConfigs(1, 100);
// Check for required default configurations
String[] requiredDefaults = {
"resolution", "frameRate", "codec", "bitrate",
"protocol", "port", "username", "password"
};
Map<String, Boolean> configStatus = new HashMap<>();
for (String required : requiredDefaults) {
boolean exists = allDefaults.getData().getList().stream()
.anyMatch(config -> required.equals(config.getConfigKey()));
configStatus.put(required, exists);
if (!exists) {
log.warn("Missing required default configuration: {}", required);
}
}
// Generate configuration completeness report
long totalConfigs = allDefaults.getData().getTotal();
long completeConfigs = configStatus.values().stream().mapToLong(exists -> exists ? 1 : 0).sum();
double completeness = (double) completeConfigs / requiredDefaults.length * 100;
log.info("Configuration completeness: {:.1f}% ({}/{} required configs present)",
completeness, completeConfigs, requiredDefaults.length);
log.info("Total default configurations in system: {}", totalConfigs);
// Analyze configuration type distribution
Map<String, Long> typeDistribution = allDefaults.getData().getList().stream()
.collect(Collectors.groupingBy(
DefaultConfigResponse::getConfigType,
Collectors.counting()
));
log.info("Configuration type distribution: {}", typeDistribution);
// Find most and least used configurations
DefaultConfigResponse mostUsed = allDefaults.getData().getList().stream()
.max(Comparator.comparing(DefaultConfigResponse::getUsageCount))
.orElse(null);
DefaultConfigResponse leastUsed = allDefaults.getData().getList().stream()
.min(Comparator.comparing(DefaultConfigResponse::getUsageCount))
.orElse(null);
if (mostUsed != null) {
log.info("Most used default config: {} (used {} times)",
mostUsed.getConfigKey(), mostUsed.getUsageCount());
}
if (leastUsed != null) {
log.info("Least used default config: {} (used {} times)",
leastUsed.getConfigKey(), leastUsed.getUsageCount());
}
```
#### Advanced Batch Configuration with Error Handling
```java
// Complex batch operation with comprehensive error handling
try {
BatchDefaultConfigRequest complexBatch = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("3840x2160", 60, "H265") // 4K configuration
.addConfig("hdr_enabled", "true", "bool", "HDR video support")
.addConfig("ai_analysis", "enabled", "string", "AI analysis features")
.addConfig("edge_processing", "true", "bool", "Edge computing enabled")
.addConfig("cloud_sync", "auto", "string", "Cloud synchronization mode")
.build();
BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(complexBatch);
// Detailed result analysis
if (result.getSuccess() == complexBatch.getConfigs().size()) {
log.info("✅ All {} configurations processed successfully", result.getSuccess());
} else if (result.getSuccess() > 0) {
log.warn("⚠️ Partial success: {} succeeded, {} failed", result.getSuccess(), result.getFailed());
// Analyze what succeeded vs failed
if (result.getProcessedItems() != null) {
Map<String, Long> statusCounts = result.getProcessedItems().stream()
.collect(Collectors.groupingBy(
ProcessedConfigItem::getStatus,
Collectors.counting()
));
log.info("Processing breakdown: {}", statusCounts);
}
} else {
log.error("❌ All configurations failed to process");
}
// Handle different types of conflicts
if (result.getConflicts() != null) {
Map<String, List<DefaultConfigConflict>> conflictsByType = result.getConflicts().stream()
.collect(Collectors.groupingBy(DefaultConfigConflict::getConflictType));
conflictsByType.forEach((conflictType, conflicts) -> {
log.warn("Conflict type '{}' affects {} configurations:", conflictType, conflicts.size());
conflicts.forEach(conflict ->
log.warn(" {} affects {} devices", conflict.getConfigKey(), conflict.getDeviceCount())
);
});
}
} catch (Exception e) {
log.error("Batch default configuration operation failed", e);
// Implement retry logic or fallback behavior as needed
}
```
#### Fallback Cache Management for Default Configurations
```java
@Autowired
private IntegrationFallbackService fallbackService;
// Check fallback cache status for default configurations
boolean hasDefaultListCache = fallbackService.hasFallbackCache("zt-device", "defaults:list:1:10");
boolean hasSpecificConfigCache = fallbackService.hasFallbackCache("zt-device", "defaults:config:resolution");
// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-device");
log.info("Default config fallback cache: {} items, TTL: {} days",
stats.getTotalCacheCount(), stats.getFallbackTtlDays());
// Clear specific default configuration cache
fallbackService.clearFallbackCache("zt-device", "defaults:config:resolution");
// Clear all default configuration caches
fallbackService.clearAllFallbackCache("zt-device");
```
### Default Configuration Types and Common Keys
#### Video Configuration Defaults
- `resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720")
- `frameRate`: Video frame rate (integer: 15, 25, 30, 60)
- `codec`: Video codec ("H264", "H265", "MJPEG")
- `bitrate`: Video bitrate in bps (integer)
- `quality`: Video quality level ("low", "medium", "high", "ultra")
#### Network Configuration Defaults
- `protocol`: Network protocol ("RTSP", "HTTP", "ONVIF")
- `port`: Network port (integer: 554, 80, 8080)
- `timeout`: Connection timeout in seconds (integer)
- `retry_count`: Maximum retry attempts (integer)
#### Authentication Defaults
- `username`: Default username (string)
- `password`: Default password (string)
- `auth_method`: Authentication method ("basic", "digest", "none")
#### Storage and Recording Defaults
- `storage_path`: Default storage path (string)
- `recording_enabled`: Enable recording (boolean)
- `retention_days`: Storage retention period (integer)
- `max_file_size`: Maximum file size in MB (integer)
#### Feature Control Defaults
- `motion_detection`: Enable motion detection (boolean)
- `night_vision`: Enable night vision (boolean)
- `audio_enabled`: Enable audio recording (boolean)
- `ptz_enabled`: Enable PTZ control (boolean)
- `ai_analysis`: AI analysis features ("enabled", "disabled", "auto")
### Error Handling and Responses
#### HTTP Status Codes
- **200 OK**: Configuration retrieved/updated successfully
- **201 Created**: New configuration created successfully
- **202 Accepted**: Operation completed with conflicts (check response for details)
- **400 Bad Request**: Invalid request parameters or validation errors
- **404 Not Found**: Configuration key not found
- **409 Conflict**: Configuration conflicts prevent operation (includes conflict details)
#### Conflict Resolution
When updating default configurations that are actively used by devices, the API performs conflict detection:
1. **Type Conflicts**: Changing configuration type when devices use different types
2. **Value Validation**: Ensuring new values are compatible with existing device configurations
3. **Dependency Conflicts**: Checking for configuration dependencies and relationships
The response includes detailed conflict information to help resolve issues:
```java
// Example conflict handling
DefaultConfigConflict conflict = updateResult;
if (conflict != null) {
switch (conflict.getConflictType()) {
case "TYPE_MISMATCH":
log.warn("Type conflict: {} devices using '{}' type, proposed '{}'type",
conflict.getDeviceCount(), conflict.getCurrentType(), conflict.getProposedType());
// Handle type conversion or device updates
break;
case "VALUE_RANGE":
log.warn("Value range conflict for key '{}' affects {} devices",
conflict.getConfigKey(), conflict.getDeviceCount());
// Handle value range adjustments
break;
case "DEPENDENCY":
log.warn("Dependency conflict detected for '{}'", conflict.getConfigKey());
// Handle dependency resolution
break;
}
}
```
### Enhanced Batch Configuration API ### Enhanced Batch Configuration API
Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules. Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules.
@@ -424,6 +783,23 @@ Each processed item includes:
- **IPC**: IP Camera devices for video monitoring - **IPC**: IP Camera devices for video monitoring
- **CUSTOM**: Custom device types for sensors, controllers, etc. - **CUSTOM**: Custom device types for sensors, controllers, etc.
### Testing Default Configuration Integration
```bash
# Run default configuration integration tests
mvn test -Dtest=DefaultConfigIntegrationServiceTest
# Run all device integration tests (including default configs)
mvn test -Dtest="com.ycwl.basic.integration.device.*Test"
# Enable example runner in application-dev.yml
integration:
device:
example:
default-config:
enabled: true
```
### Common Configuration Keys ### Common Configuration Keys
- `ip_address`: Device IP address - `ip_address`: Device IP address
- `resolution`: Video resolution (e.g., "1920x1080", "3840x2160") - `resolution`: Video resolution (e.g., "1920x1080", "3840x2160")
@@ -534,6 +910,11 @@ integration:
enabled: true # Enable fallback for device service enabled: true # Enable fallback for device service
ttlDays: 5 # Custom TTL for device (shorter due to dynamic data) ttlDays: 5 # Custom TTL for device (shorter due to dynamic data)
# cachePrefix: "device:fallback:" # Optional custom prefix # cachePrefix: "device:fallback:" # Optional custom prefix
render:
enabled: true # Enable fallback for render worker service
ttlDays: 7 # Custom TTL for render worker (medium due to stable worker data)
# cachePrefix: "render:fallback:" # Optional custom prefix
# Service configurations # Service configurations
scenic: scenic:
@@ -587,6 +968,205 @@ class ScenicIntegrationServiceTest {
### Integration Testing ### Integration Testing
Use `@SpringBootTest` with test profiles and mock external services. Use `@SpringBootTest` with test profiles and mock external services.
## Render Worker Integration (ZT-Render-Worker Microservice)
### Key Components
#### Feign Clients
- **RenderWorkerV2Client**: Main render worker operations (CRUD, listing)
- **RenderWorkerConfigV2Client**: Render worker configuration management
#### Services
- **RenderWorkerIntegrationService**: High-level render worker operations (with automatic fallback)
- **RenderWorkerConfigIntegrationService**: Configuration management (with automatic fallback)
#### Configuration
```yaml
integration:
render:
enabled: true
serviceName: zt-render-worker
connectTimeout: 5000
readTimeout: 10000
retryEnabled: false
maxRetries: 3
```
### Usage Examples
#### Basic Render Worker Operations (with Automatic Fallback)
```java
@Autowired
private RenderWorkerIntegrationService renderWorkerService;
// Get render worker basic info (automatically falls back to cache on failure)
RenderWorkerV2DTO worker = renderWorkerService.getWorker(workerId);
// Get render worker with configuration (automatically falls back to cache on failure)
RenderWorkerV2WithConfigDTO workerWithConfig = renderWorkerService.getWorkerWithConfig(workerId);
// Get render worker by key (automatically falls back to cache on failure)
RenderWorkerV2DTO workerByKey = renderWorkerService.getWorkerByKey("video-renderer-001");
// Get render worker with config by key (automatically falls back to cache on failure)
RenderWorkerV2WithConfigDTO workerWithConfigByKey = renderWorkerService.getWorkerWithConfigByKey("video-renderer-001");
// Create new render worker (direct operation, fails immediately on error)
CreateRenderWorkerRequest request = new CreateRenderWorkerRequest();
request.setName("Video Renderer");
request.setKey("video-renderer-001");
request.setIsActive(1);
RenderWorkerV2DTO newWorker = renderWorkerService.createWorker(request);
// Update render worker (direct operation, fails immediately on error)
UpdateRenderWorkerRequest updateRequest = new UpdateRenderWorkerRequest();
updateRequest.setName("Updated Video Renderer");
renderWorkerService.updateWorker(workerId, updateRequest);
// Delete render worker (direct operation, fails immediately on error)
renderWorkerService.deleteWorker(workerId);
// List render workers (no fallback for list operations)
List<RenderWorkerV2DTO> workers = renderWorkerService.listWorkers(1, 10, 1, null);
// List render workers with config (no fallback for list operations)
List<RenderWorkerV2WithConfigDTO> workersWithConfig =
renderWorkerService.listWorkersWithConfig(1, 10, 1, null);
```
#### Configuration Management (with Automatic Fallback)
```java
@Autowired
private RenderWorkerConfigIntegrationService configService;
// Get worker configurations (with fallback)
List<RenderWorkerConfigV2DTO> configs = configService.getWorkerConfigs(workerId);
// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> flatConfig = configService.getWorkerFlatConfig(workerId);
// Get specific configuration by key (with fallback)
RenderWorkerConfigV2DTO config = configService.getWorkerConfigByKey(workerId, "render_quality");
// Create configuration (direct operation, fails immediately on error)
RenderWorkerConfigV2DTO newConfig = new RenderWorkerConfigV2DTO();
newConfig.setConfigKey("max_concurrent_tasks");
newConfig.setConfigValue("4");
newConfig.setConfigType("int");
newConfig.setDescription("Maximum concurrent render tasks");
newConfig.setIsActive(1);
RenderWorkerConfigV2DTO created = configService.createWorkerConfig(workerId, newConfig);
// Update configuration (direct operation, fails immediately on error)
Map<String, Object> updates = new HashMap<>();
updates.put("configValue", "8");
configService.updateWorkerConfig(workerId, configId, updates);
// Delete configuration (direct operation, fails immediately on error)
configService.deleteWorkerConfig(workerId, configId);
```
#### Enhanced Batch Configuration API
```java
// Using Builder Pattern for batch configuration
BatchRenderWorkerConfigRequest request = configService.createBatchConfigBuilder()
.addRenderConfig("high", "mp4", "1920x1080") // Render settings
.addPerformanceConfig(8, 3600) // Performance settings
.addConfig("output_path", "/data/renders", "string", "Output directory")
.addConfig("enable_gpu", "true", "bool", "Enable GPU acceleration")
.build();
// Batch update configurations (direct operation, fails immediately on error)
configService.batchUpdateWorkerConfigs(workerId, request);
// Batch flat update configurations (direct operation, fails immediately on error)
Map<String, Object> flatUpdates = new HashMap<>();
flatUpdates.put("render_quality", "ultra");
flatUpdates.put("max_concurrent_tasks", 12);
flatUpdates.put("enable_preview", true);
configService.batchFlatUpdateWorkerConfigs(workerId, flatUpdates);
```
#### Render Worker Management Patterns
```java
// Create and configure render worker in one operation
CreateRenderWorkerRequest workerRequest = new CreateRenderWorkerRequest();
workerRequest.setName("4K Video Renderer");
workerRequest.setKey("4k-video-renderer");
RenderWorkerV2DTO worker = renderWorkerService.createWorker(workerRequest);
// Configure the worker for 4K video rendering
BatchRenderWorkerConfigRequest config = configService.createBatchConfigBuilder()
.addRenderConfig("ultra", "mp4", "3840x2160")
.addPerformanceConfig(4, 7200) // 4 concurrent tasks, 2 hour timeout
.addConfig("gpu_memory_limit", "8192", "int", "GPU memory limit in MB")
.addConfig("codec", "h265", "string", "Video codec")
.addConfig("bitrate", "50000", "int", "Video bitrate in kbps")
.build();
configService.batchUpdateWorkerConfigs(worker.getId(), config);
// Monitor worker configuration completeness (with automatic fallback)
Map<String, Object> workerConfig = configService.getWorkerFlatConfig(worker.getId());
boolean hasRenderConfig = workerConfig.containsKey("render_quality");
boolean hasPerformanceConfig = workerConfig.containsKey("max_concurrent_tasks");
// log configuration status...
// Get all active workers for monitoring
List<RenderWorkerV2WithConfigDTO> activeWorkers =
renderWorkerService.listWorkersWithConfig(1, 100, 1, null);
// Check worker health and configuration
for (RenderWorkerV2WithConfigDTO activeWorker : activeWorkers) {
Map<String, Object> config = activeWorker.getConfig();
boolean isConfigured = config.containsKey("render_quality") &&
config.containsKey("max_concurrent_tasks");
// log worker status...
}
```
#### Fallback Cache Management for Render Workers
```java
@Autowired
private IntegrationFallbackService fallbackService;
// Check fallback cache status
boolean hasWorkerCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:1001");
boolean hasWorkerByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:video-renderer-001");
boolean hasConfigCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:flat:config:1001");
boolean hasConfigByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:config:video-renderer-001");
// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats =
fallbackService.getFallbackCacheStats("zt-render-worker");
log.info("Render worker fallback cache: {} items, TTL: {} days",
stats.getTotalCacheCount(), stats.getFallbackTtlDays());
// Clear specific cache
fallbackService.clearFallbackCache("zt-render-worker", "worker:1001");
// Clear all render worker caches
fallbackService.clearAllFallbackCache("zt-render-worker");
```
### Render Worker Types and Configuration
#### Common Configuration Keys
- `render_quality`: Render quality level ("low", "medium", "high", "ultra")
- `render_format`: Output format ("mp4", "avi", "mov", "webm")
- `render_resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720")
- `max_concurrent_tasks`: Maximum concurrent render tasks (integer)
- `task_timeout`: Task timeout in seconds (integer)
- `output_path`: Render output directory path (string)
- `enable_gpu`: Enable GPU acceleration (boolean)
- `gpu_memory_limit`: GPU memory limit in MB (integer)
- `codec`: Video codec ("h264", "h265", "vp9")
- `bitrate`: Video bitrate in kbps (integer)
- `enable_preview`: Enable preview generation (boolean)
#### Worker Status
- **Active (isActive=1)**: Worker is available for tasks
- **Inactive (isActive=0)**: Worker is disabled
## Common Development Tasks ## Common Development Tasks
### Running Integration Tests ### Running Integration Tests
@@ -600,6 +1180,10 @@ mvn test -Dtest="com.ycwl.basic.integration.*Test"
# Run device integration tests # Run device integration tests
mvn test -Dtest=DeviceIntegrationServiceTest mvn test -Dtest=DeviceIntegrationServiceTest
mvn test -Dtest="com.ycwl.basic.integration.device.*Test" mvn test -Dtest="com.ycwl.basic.integration.device.*Test"
# Run render worker integration tests
mvn test -Dtest=RenderWorkerIntegrationServiceTest
mvn test -Dtest="com.ycwl.basic.integration.render.*Test"
``` ```
### Adding New DTOs ### Adding New DTOs

View File

@@ -26,6 +26,11 @@ public class IntegrationProperties {
*/ */
private DeviceConfig device = new DeviceConfig(); private DeviceConfig device = new DeviceConfig();
/**
* 渲染工作器服务配置
*/
private RenderWorkerConfig render = new RenderWorkerConfig();
@Data @Data
public static class ScenicConfig { public static class ScenicConfig {
/** /**
@@ -98,6 +103,32 @@ public class IntegrationProperties {
*/ */
private ServiceFallbackConfig scenic = new ServiceFallbackConfig(); private ServiceFallbackConfig scenic = new ServiceFallbackConfig();
private ServiceFallbackConfig device = new ServiceFallbackConfig(); private ServiceFallbackConfig device = new ServiceFallbackConfig();
private ServiceFallbackConfig render = new ServiceFallbackConfig();
}
@Data
public static class RenderWorkerConfig {
/**
* 是否启用渲染工作器服务集成
*/
private boolean enabled = true;
/**
* 服务名称
*/
private String serviceName = "zt-render-worker";
/**
* 超时配置(毫秒)
*/
private int connectTimeout = 5000;
private int readTimeout = 10000;
/**
* 重试配置
*/
private boolean retryEnabled = false;
private int maxRetries = 3;
} }
@Data @Data

View File

@@ -0,0 +1,82 @@
package com.ycwl.basic.integration.common.manager;
import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO;
import java.util.List;
/**
* 渲染工作器配置管理器
* 基于通用ConfigManager实现渲染工作器配置的管理功能
*/
public class RenderWorkerConfigManager extends ConfigManager<RenderWorkerConfigV2DTO> {
public RenderWorkerConfigManager(List<RenderWorkerConfigV2DTO> configs) {
super(configs);
}
@Override
protected String getConfigKey(RenderWorkerConfigV2DTO config) {
return config != null ? config.getConfigKey() : null;
}
@Override
protected Object getConfigValue(RenderWorkerConfigV2DTO config) {
return config != null ? config.getConfigValue() : null;
}
/**
* 获取渲染工作器配置类型
*/
public String getConfigType(String key) {
RenderWorkerConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getConfigType() : null;
}
/**
* 获取渲染工作器配置描述
*/
public String getConfigDescription(String key) {
RenderWorkerConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getDescription() : null;
}
/**
* 获取渲染工作器配置ID
*/
public Long getConfigId(String key) {
RenderWorkerConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getId() : null;
}
/**
* 获取工作器ID
*/
public Long getWorkerId(String key) {
RenderWorkerConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getWorkerId() : null;
}
/**
* 检查配置是否启用
*/
public boolean isActive(String key) {
RenderWorkerConfigV2DTO config = findConfigByKey(key);
return config != null && config.getIsActive() != null && config.getIsActive() == 1;
}
/**
* 获取配置的创建时间
*/
public String getCreateTime(String key) {
RenderWorkerConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getCreateTime() : null;
}
/**
* 获取配置的更新时间
*/
public String getUpdateTime(String key) {
RenderWorkerConfigV2DTO config = findConfigByKey(key);
return config != null ? config.getUpdateTime() : null;
}
}

View File

@@ -12,29 +12,33 @@ import lombok.AllArgsConstructor;
public class CommonResponse<T> { public class CommonResponse<T> {
private Integer code; private Integer code;
private String message; private String message;
private Boolean success;
private T data; private T data;
public static <T> CommonResponse<T> success() { public static <T> CommonResponse<T> success() {
return new CommonResponse<>(200, "OK", null); return new CommonResponse<>(200, "OK", true, null);
} }
public static <T> CommonResponse<T> success(T data) { public static <T> CommonResponse<T> success(T data) {
return new CommonResponse<>(200, "OK", data); return new CommonResponse<>(200, "OK", true, data);
} }
public static <T> CommonResponse<T> success(String message, T data) { public static <T> CommonResponse<T> success(String message, T data) {
return new CommonResponse<>(200, message, data); return new CommonResponse<>(200, message, true, data);
} }
public static <T> CommonResponse<T> error(Integer code, String message) { public static <T> CommonResponse<T> error(Integer code, String message) {
return new CommonResponse<>(code, message, null); return new CommonResponse<>(code, message, false, null);
} }
public static <T> CommonResponse<T> error(String message) { public static <T> CommonResponse<T> error(String message) {
return new CommonResponse<>(5000, message, null); return new CommonResponse<>(5000, message, false, null);
} }
public boolean isSuccess() { public boolean isSuccess() {
return code != null && code == 200; if (success == null) { // compatible
return code != null && code == 200;
}
return success;
} }
} }

View File

@@ -0,0 +1,54 @@
package com.ycwl.basic.integration.device.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.defaults.*;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 默认配置管理 Feign 客户端
*/
@FeignClient(name = "zt-device", contextId = "device-default-config", path = "/api/device/config/v2/defaults")
public interface DefaultConfigClient {
/**
* 获取默认配置列表
*/
@GetMapping
CommonResponse<PageResponse<DefaultConfigResponse>> listDefaultConfigs(@RequestParam(value = "page", defaultValue = "1") int page,
@RequestParam(value = "pageSize", defaultValue = "10") int pageSize);
/**
* 根据配置键获取默认配置
*/
@GetMapping("/{configKey}")
CommonResponse<DefaultConfigResponse> getDefaultConfig(@PathVariable("configKey") String configKey);
/**
* 创建默认配置
*/
@PostMapping
CommonResponse<String> createDefaultConfig(@RequestBody DefaultConfigRequest request);
/**
* 更新默认配置
*/
@PutMapping("/{configKey}")
CommonResponse<Map<String, Object>> updateDefaultConfig(@PathVariable("configKey") String configKey,
@RequestBody Map<String, Object> updates);
/**
* 删除默认配置
*/
@DeleteMapping("/{configKey}")
CommonResponse<String> deleteDefaultConfig(@PathVariable("configKey") String configKey);
/**
* 批量更新默认配置
*/
@PostMapping("/batch")
CommonResponse<BatchDefaultConfigResponse> batchUpdateDefaultConfigs(@RequestBody BatchDefaultConfigRequest request);
}

View File

@@ -1,6 +1,7 @@
package com.ycwl.basic.integration.device.client; package com.ycwl.basic.integration.device.client;
import com.ycwl.basic.integration.common.response.CommonResponse; import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.device.*; import com.ycwl.basic.integration.device.dto.device.*;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -55,7 +56,7 @@ public interface DeviceV2Client {
* 分页获取设备列表(核心信息) * 分页获取设备列表(核心信息)
*/ */
@GetMapping("/") @GetMapping("/")
CommonResponse<DeviceV2ListResponse> listDevices( CommonResponse<PageResponse<DeviceV2DTO>> listDevices(
@RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(value = "name", required = false) String name, @RequestParam(value = "name", required = false) String name,
@@ -68,7 +69,7 @@ public interface DeviceV2Client {
* 分页获取设备列表(含配置) * 分页获取设备列表(含配置)
*/ */
@GetMapping("/with-config") @GetMapping("/with-config")
CommonResponse<DeviceV2WithConfigListResponse> listDevicesWithConfig( CommonResponse<PageResponse<DeviceV2WithConfigDTO>> listDevicesWithConfig(
@RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(value = "name", required = false) String name, @RequestParam(value = "name", required = false) String name,

View File

@@ -0,0 +1,18 @@
package com.ycwl.basic.integration.device.dto.defaults;
import lombok.Data;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
/**
* 批量默认配置操作请求模型
*/
@Data
public class BatchDefaultConfigRequest {
@NotEmpty(message = "配置列表不能为空")
@Valid
private List<DefaultConfigRequest> configs;
}

View File

@@ -0,0 +1,23 @@
package com.ycwl.basic.integration.device.dto.defaults;
import com.ycwl.basic.integration.device.dto.config.ProcessedConfigItem;
import lombok.Data;
import java.util.List;
/**
* 批量默认配置操作响应模型
*/
@Data
public class BatchDefaultConfigResponse {
private Integer success;
private Integer failed;
private List<DefaultConfigConflict> conflicts;
private List<ProcessedConfigItem> processedItems;
private List<String> errors;
}

View File

@@ -0,0 +1,24 @@
package com.ycwl.basic.integration.device.dto.defaults;
import lombok.Data;
import java.util.List;
/**
* 冲突信息模型
*/
@Data
public class DefaultConfigConflict {
private String configKey;
private String conflictType;
private Integer deviceCount;
private String currentType;
private String proposedType;
private List<Long> conflictDevices;
}

View File

@@ -0,0 +1,26 @@
package com.ycwl.basic.integration.device.dto.defaults;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 默认配置请求模型
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DefaultConfigRequest {
@NotBlank(message = "配置键不能为空")
private String configKey;
@NotBlank(message = "配置值不能为空")
private String configValue;
@NotBlank(message = "配置类型不能为空")
private String configType;
@NotBlank(message = "配置描述不能为空")
private String description;
}

View File

@@ -0,0 +1,28 @@
package com.ycwl.basic.integration.device.dto.defaults;
import lombok.Data;
/**
* 默认配置响应模型
*/
@Data
public class DefaultConfigResponse {
private String id;
private String configKey;
private String configValue;
private String configType;
private String description;
private Integer isActive;
private String createTime;
private String updateTime;
private Integer usageCount;
}

View File

@@ -1,13 +0,0 @@
package com.ycwl.basic.integration.device.dto.device;
import lombok.Data;
import java.util.List;
@Data
public class DeviceV2ListResponse {
private List<DeviceV2DTO> list;
private Integer total;
private Integer page;
private Integer pageSize;
}

View File

@@ -1,13 +0,0 @@
package com.ycwl.basic.integration.device.dto.device;
import lombok.Data;
import java.util.List;
@Data
public class DeviceV2WithConfigListResponse {
private List<DeviceV2WithConfigDTO> list;
private Integer total;
private Integer page;
private Integer pageSize;
}

View File

@@ -17,7 +17,7 @@ public class FilterDevicesByConfigsResponse {
/** /**
* 总数 * 总数
*/ */
private String total; private Integer total;
/** /**
* 页码 * 页码

View File

@@ -0,0 +1,275 @@
package com.ycwl.basic.integration.device.example;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.defaults.*;
import com.ycwl.basic.integration.device.service.DeviceDefaultConfigIntegrationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 默认配置集成服务使用示例
*
* 通过在 application.yml 中设置 integration.device.example.default-config.enabled=true 来启用
*/
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "integration.device.example.default-config.enabled", havingValue = "true")
public class DefaultConfigIntegrationExample implements CommandLineRunner {
private final DeviceDefaultConfigIntegrationService defaultConfigService;
@Override
public void run(String... args) throws Exception {
log.info("=== 默认配置集成服务使用示例 ===");
try {
// 1. 基础查询操作示例(支持自动 Fallback)
basicQueryExamples();
// 2. 配置管理操作示例(直接操作)
configManagementExamples();
// 3. 批量操作示例
batchOperationExamples();
// 4. 高级使用模式示例
advancedUsageExamples();
} catch (Exception e) {
log.error("默认配置集成示例执行失败", e);
}
}
/**
* 基础查询操作示例(支持自动 Fallback)
*/
private void basicQueryExamples() {
log.info("--- 基础查询操作示例(支持自动 Fallback)---");
try {
// 获取默认配置列表(自动缓存,服务不可用时返回缓存数据)
PageResponse<DefaultConfigResponse> configList = defaultConfigService.listDefaultConfigs(1, 10);
log.info("默认配置列表: 总数={}, 当前页配置数={}",
configList.getTotal(), configList.getList().size());
// 显示配置详情
for (DefaultConfigResponse config : configList.getList()) {
log.info("配置详情: key={}, value={}, type={}, description={}",
config.getConfigKey(), config.getConfigValue(),
config.getConfigType(), config.getDescription());
// 获取单个配置详情(自动缓存,服务不可用时返回缓存数据)
DefaultConfigResponse detailConfig = defaultConfigService.getDefaultConfig(config.getConfigKey());
if (detailConfig != null) {
log.info("配置详情获取成功: usageCount={}, isActive={}",
detailConfig.getUsageCount(), detailConfig.getIsActive());
}
break; // 只展示第一个
}
} catch (Exception e) {
log.error("基础查询操作失败", e);
}
}
/**
* 配置管理操作示例(直接操作)
*/
private void configManagementExamples() {
log.info("--- 配置管理操作示例(直接操作)---");
String testConfigKey = "example_test_config";
try {
// 1. 创建默认配置(直接操作,失败时立即报错)
DefaultConfigRequest createRequest = new DefaultConfigRequest();
createRequest.setConfigKey(testConfigKey);
createRequest.setConfigValue("1920x1080");
createRequest.setConfigType("string");
createRequest.setDescription("示例测试配置 - 默认分辨率");
boolean createResult = defaultConfigService.createDefaultConfig(createRequest);
log.info("创建默认配置结果: {}", createResult ? "成功" : "失败");
// 2. 更新默认配置(直接操作,可能返回冲突信息)
Map<String, Object> updates = new HashMap<>();
updates.put("configValue", "3840x2160");
updates.put("description", "更新后的默认分辨率 - 4K");
DefaultConfigConflict conflict = defaultConfigService.updateDefaultConfig(testConfigKey, updates);
if (conflict != null) {
log.warn("更新配置存在冲突: configKey={}, conflictType={}, deviceCount={}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
} else {
log.info("配置更新成功,无冲突");
}
// 3. 验证更新结果
DefaultConfigResponse updatedConfig = defaultConfigService.getDefaultConfig(testConfigKey);
if (updatedConfig != null) {
log.info("更新后配置值: {}", updatedConfig.getConfigValue());
}
// 4. 删除测试配置(直接操作)
boolean deleteResult = defaultConfigService.deleteDefaultConfig(testConfigKey);
log.info("删除默认配置结果: {}", deleteResult ? "成功" : "失败");
} catch (Exception e) {
log.error("配置管理操作失败", e);
}
}
/**
* 批量操作示例
*/
private void batchOperationExamples() {
log.info("--- 批量操作示例 ---");
try {
// 1. 使用构建器模式创建批量配置
BatchDefaultConfigRequest batchRequest = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 30, "H264") // 添加视频配置组
.addNetworkConfig("192.168.1.100", 554, "RTSP") // 添加网络配置组
.addConfig("recording_enabled", "true", "bool", "是否启用录制")
.addConfig("storage_path", "/data/recordings", "string", "录制存储路径")
.addConfig("max_file_size", "1024", "int", "最大文件大小(MB)")
.build();
log.info("准备批量创建 {} 个默认配置", batchRequest.getConfigs().size());
// 2. 执行批量更新(直接操作)
BatchDefaultConfigResponse batchResult = defaultConfigService.batchUpdateDefaultConfigs(batchRequest);
// 3. 处理批量结果
log.info("批量操作结果: 成功={}, 失败={}", batchResult.getSuccess(), batchResult.getFailed());
if (batchResult.getConflicts() != null && !batchResult.getConflicts().isEmpty()) {
log.warn("发现 {} 个配置冲突:", batchResult.getConflicts().size());
for (DefaultConfigConflict conflict : batchResult.getConflicts()) {
log.warn("冲突配置: key={}, type={}, deviceCount={}",
conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
}
}
if (batchResult.getProcessedItems() != null) {
log.info("处理详情:");
batchResult.getProcessedItems().forEach(item ->
log.info(" 配置 {}: status={}, action={}, finalType={}",
item.getConfigKey(), item.getStatus(), item.getAction(), item.getFinalType())
);
}
if (batchResult.getErrors() != null && !batchResult.getErrors().isEmpty()) {
log.error("批量操作错误:");
batchResult.getErrors().forEach(error -> log.error(" {}", error));
}
} catch (Exception e) {
log.error("批量操作失败", e);
}
}
/**
* 高级使用模式示例
*/
private void advancedUsageExamples() {
log.info("--- 高级使用模式示例 ---");
try {
// 1. 设备类型特定的默认配置模式
createDeviceTypeSpecificConfigs();
// 2. 配置验证和完整性检查模式
validateConfigCompleteness();
// 3. 配置迁移和批量更新模式
configMigrationPattern();
} catch (Exception e) {
log.error("高级使用模式示例失败", e);
}
}
/**
* 创建设备类型特定的默认配置
*/
private void createDeviceTypeSpecificConfigs() {
log.info("创建设备类型特定的默认配置...");
// IPC摄像头默认配置
BatchDefaultConfigRequest ipcDefaults = defaultConfigService.createBatchConfigBuilder()
.addVideoConfig("1920x1080", 25, "H264")
.addConfig("night_vision", "true", "bool", "夜视功能")
.addConfig("motion_detection", "true", "bool", "移动检测")
.addConfig("stream_profile", "main", "string", "码流类型")
.build();
// NVR设备默认配置
BatchDefaultConfigRequest nvrDefaults = defaultConfigService.createBatchConfigBuilder()
.addConfig("max_channels", "16", "int", "最大通道数")
.addConfig("storage_mode", "continuous", "string", "存储模式")
.addConfig("backup_enabled", "true", "bool", "备份启用")
.build();
log.info("IPC默认配置项数: {}, NVR默认配置项数: {}",
ipcDefaults.getConfigs().size(), nvrDefaults.getConfigs().size());
}
/**
* 配置验证和完整性检查
*/
private void validateConfigCompleteness() {
log.info("验证配置完整性...");
// 获取所有默认配置
PageResponse<DefaultConfigResponse> allConfigs = defaultConfigService.listDefaultConfigs(1, 100);
// 检查必需的基础配置是否存在
String[] requiredConfigs = {"resolution", "frameRate", "codec", "protocol"};
for (String requiredConfig : requiredConfigs) {
boolean exists = allConfigs.getList().stream()
.anyMatch(config -> requiredConfig.equals(config.getConfigKey()));
log.info("必需配置 {} 存在: {}", requiredConfig, exists ? "" : "");
}
// 统计配置类型分布
Map<String, Long> typeDistribution = new HashMap<>();
allConfigs.getList().forEach(config ->
typeDistribution.merge(config.getConfigType(), 1L, Long::sum)
);
log.info("配置类型分布: {}", typeDistribution);
}
/**
* 配置迁移和批量更新模式
*/
private void configMigrationPattern() {
log.info("配置迁移模式示例...");
try {
// 1. 获取需要升级的配置
PageResponse<DefaultConfigResponse> oldConfigs = defaultConfigService.listDefaultConfigs(1, 50);
// 2. 创建升级配置批次
BatchDefaultConfigRequest upgradeRequest = defaultConfigService.createBatchConfigBuilder()
.addConfig("api_version", "v2", "string", "API版本")
.addConfig("security_mode", "enhanced", "string", "安全模式")
.build();
// 3. 执行批量升级
BatchDefaultConfigResponse upgradeResult = defaultConfigService.batchUpdateDefaultConfigs(upgradeRequest);
log.info("配置升级结果: 成功={}, 失败={}", upgradeResult.getSuccess(), upgradeResult.getFailed());
} catch (Exception e) {
log.warn("配置迁移示例执行失败(这是正常的,因为是示例代码)", e);
}
}
}

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.integration.device.example; package com.ycwl.basic.integration.device.example;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.device.*; import com.ycwl.basic.integration.device.dto.device.*;
import com.ycwl.basic.integration.device.dto.config.*; import com.ycwl.basic.integration.device.dto.config.*;
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService; import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
@@ -46,7 +47,7 @@ public class DeviceIntegrationExample {
log.info("获取设备配置: {}", deviceWithConfig.getName()); log.info("获取设备配置: {}", deviceWithConfig.getName());
// 分页查询景区设备列表 // 分页查询景区设备列表
DeviceV2ListResponse deviceList = deviceService.getScenicIpcDevices(1001L, 1, 10); PageResponse<DeviceV2DTO> deviceList = deviceService.getScenicIpcDevices(1001L, 1, 10);
log.info("景区设备列表: 总数={}", deviceList.getTotal()); log.info("景区设备列表: 总数={}", deviceList.getTotal());
// 启用设备 // 启用设备
@@ -80,7 +81,7 @@ public class DeviceIntegrationExample {
log.info("更新摄像头1排序为1(置顶)"); log.info("更新摄像头1排序为1(置顶)");
// 获取排序后的设备列表 // 获取排序后的设备列表
DeviceV2ListResponse sortedList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId); PageResponse<DeviceV2DTO> sortedList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId);
log.info("排序后的设备列表:"); log.info("排序后的设备列表:");
for (DeviceV2DTO device : sortedList.getList()) { for (DeviceV2DTO device : sortedList.getList()) {
log.info(" - {}: 排序={}, 类型={}", device.getName(), device.getSort(), device.getType()); log.info(" - {}: 排序={}, 类型={}", device.getName(), device.getSort(), device.getType());
@@ -147,7 +148,7 @@ public class DeviceIntegrationExample {
log.info("将普通摄像头置顶(排序值: 1)"); log.info("将普通摄像头置顶(排序值: 1)");
// 查看最终排序结果 // 查看最终排序结果
DeviceV2ListResponse finalList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId); PageResponse<DeviceV2DTO> finalList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId);
log.info("最终排序结果:"); log.info("最终排序结果:");
for (DeviceV2DTO device : finalList.getList()) { for (DeviceV2DTO device : finalList.getList()) {
log.info(" - {}: 排序={}", device.getName(), device.getSort()); log.info(" - {}: 排序={}", device.getName(), device.getSort());

View File

@@ -0,0 +1,218 @@
package com.ycwl.basic.integration.device.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.device.client.DefaultConfigClient;
import com.ycwl.basic.integration.device.dto.defaults.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Map;
/**
* 默认配置集成服务
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceDefaultConfigIntegrationService {
private final DefaultConfigClient defaultConfigClient;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-device";
/**
* 获取默认配置列表(支持 Fallback)
*/
public PageResponse<DefaultConfigResponse> listDefaultConfigs(int page, int pageSize) {
return fallbackService.executeWithFallback(
SERVICE_NAME,
"defaults:list:" + page + ":" + pageSize,
() -> {
CommonResponse<PageResponse<DefaultConfigResponse>> response = defaultConfigClient.listDefaultConfigs(page, pageSize);
return handleResponse(response, "获取默认配置列表失败");
},
PageResponse.class
);
}
/**
* 根据配置键获取默认配置(支持 Fallback)
*/
public DefaultConfigResponse getDefaultConfig(String configKey) {
return fallbackService.executeWithFallback(
SERVICE_NAME,
"defaults:config:" + configKey,
() -> {
log.info("获取默认配置, configKey: {}", configKey);
CommonResponse<DefaultConfigResponse> response = defaultConfigClient.getDefaultConfig(configKey);
return handleResponse(response, "获取默认配置失败");
},
DefaultConfigResponse.class
);
}
/**
* 创建默认配置(直接操作,不支持 Fallback)
*/
public boolean createDefaultConfig(DefaultConfigRequest request) {
log.info("创建默认配置, configKey: {}", request.getConfigKey());
CommonResponse<String> response = defaultConfigClient.createDefaultConfig(request);
String result = handleResponse(response, "创建默认配置失败");
return result != null;
}
/**
* 更新默认配置(直接操作,不支持 Fallback)
*/
public DefaultConfigConflict updateDefaultConfig(String configKey, Map<String, Object> updates) {
log.info("更新默认配置, configKey: {}, updates: {}", configKey, updates);
CommonResponse<Map<String, Object>> response = defaultConfigClient.updateDefaultConfig(configKey, updates);
Map<String, Object> result = handleResponse(response, "更新默认配置失败");
// 检查是否有冲突信息
if (result != null && result.containsKey("conflict")) {
Object conflictObj = result.get("conflict");
if (conflictObj instanceof Map) {
// 将Map转换为DefaultConfigConflict对象
return mapToDefaultConfigConflict((Map<String, Object>) conflictObj);
}
}
return null;
}
/**
* 删除默认配置(直接操作,不支持 Fallback)
*/
public boolean deleteDefaultConfig(String configKey) {
log.info("删除默认配置, configKey: {}", configKey);
CommonResponse<String> response = defaultConfigClient.deleteDefaultConfig(configKey);
String result = handleResponse(response, "删除默认配置失败");
return result != null;
}
/**
* 批量更新默认配置(直接操作,不支持 Fallback)
*/
public BatchDefaultConfigResponse batchUpdateDefaultConfigs(BatchDefaultConfigRequest request) {
log.info("批量更新默认配置, configs count: {}", request.getConfigs().size());
CommonResponse<BatchDefaultConfigResponse> response = defaultConfigClient.batchUpdateDefaultConfigs(request);
return handleResponse(response, "批量更新默认配置失败");
}
/**
* 创建批量配置请求构建器
*/
public BatchDefaultConfigRequestBuilder createBatchConfigBuilder() {
return new BatchDefaultConfigRequestBuilder();
}
/**
* 批量配置请求构建器
*/
public static class BatchDefaultConfigRequestBuilder {
private final BatchDefaultConfigRequest request = new BatchDefaultConfigRequest();
public BatchDefaultConfigRequestBuilder() {
request.setConfigs(new ArrayList<>());
}
/**
* 添加配置项
*/
public BatchDefaultConfigRequestBuilder addConfig(String configKey, String configValue,
String configType, String description) {
DefaultConfigRequest item = new DefaultConfigRequest();
item.setConfigKey(configKey);
item.setConfigValue(configValue);
item.setConfigType(configType);
item.setDescription(description);
request.getConfigs().add(item);
return this;
}
/**
* 添加视频配置
*/
public BatchDefaultConfigRequestBuilder addVideoConfig(String resolution, Integer frameRate, String codec) {
addConfig("resolution", resolution, "string", "视频分辨率");
addConfig("frameRate", frameRate.toString(), "int", "视频帧率");
addConfig("codec", codec, "string", "视频编码格式");
return this;
}
/**
* 添加网络配置
*/
public BatchDefaultConfigRequestBuilder addNetworkConfig(String ipAddress, Integer port, String protocol) {
addConfig("ipAddress", ipAddress, "string", "IP地址");
addConfig("port", port.toString(), "int", "端口号");
addConfig("protocol", protocol, "string", "网络协议");
return this;
}
/**
* 构建请求对象
*/
public BatchDefaultConfigRequest build() {
return request;
}
}
/**
* 将Map转换为DefaultConfigConflict对象
*/
@SuppressWarnings("unchecked")
private DefaultConfigConflict mapToDefaultConfigConflict(Map<String, Object> map) {
DefaultConfigConflict conflict = new DefaultConfigConflict();
if (map.containsKey("configKey")) {
conflict.setConfigKey((String) map.get("configKey"));
}
if (map.containsKey("conflictType")) {
conflict.setConflictType((String) map.get("conflictType"));
}
if (map.containsKey("deviceCount")) {
Object deviceCount = map.get("deviceCount");
if (deviceCount instanceof Number) {
conflict.setDeviceCount(((Number) deviceCount).intValue());
}
}
if (map.containsKey("currentType")) {
conflict.setCurrentType((String) map.get("currentType"));
}
if (map.containsKey("proposedType")) {
conflict.setProposedType((String) map.get("proposedType"));
}
if (map.containsKey("conflictDevices")) {
Object conflictDevices = map.get("conflictDevices");
if (conflictDevices instanceof Iterable) {
conflict.setConflictDevices(new ArrayList<>());
for (Object deviceId : (Iterable<?>) conflictDevices) {
if (deviceId instanceof Number) {
conflict.getConflictDevices().add(((Number) deviceId).longValue());
}
}
}
}
return conflict;
}
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.isSuccess()) {
String msg = response != null && response.getMessage() != null
? response.getMessage()
: errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, SERVICE_NAME);
}
return response.getData();
}
}

View File

@@ -4,6 +4,7 @@ import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse; import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService; import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.device.client.DeviceV2Client; import com.ycwl.basic.integration.device.client.DeviceV2Client;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.device.*; import com.ycwl.basic.integration.device.dto.device.*;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -91,20 +92,20 @@ public class DeviceIntegrationService {
handleResponse(response, "删除设备失败"); handleResponse(response, "删除设备失败");
} }
public DeviceV2ListResponse listDevices(Integer page, Integer pageSize, String name, String no, public PageResponse<DeviceV2DTO> listDevices(Integer page, Integer pageSize, String name, String no,
String type, Integer isActive, Long scenicId) { String type, Integer isActive, Long scenicId) {
log.debug("分页查询设备列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}", log.debug("分页查询设备列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}",
page, pageSize, name, no, type, isActive, scenicId); page, pageSize, name, no, type, isActive, scenicId);
CommonResponse<DeviceV2ListResponse> response = deviceV2Client.listDevices( CommonResponse<PageResponse<DeviceV2DTO>> response = deviceV2Client.listDevices(
page, pageSize, name, no, type, isActive, scenicId); page, pageSize, name, no, type, isActive, scenicId);
return handleResponse(response, "分页查询设备列表失败"); return handleResponse(response, "分页查询设备列表失败");
} }
public DeviceV2WithConfigListResponse listDevicesWithConfig(Integer page, Integer pageSize, String name, String no, public PageResponse<DeviceV2WithConfigDTO> listDevicesWithConfig(Integer page, Integer pageSize, String name, String no,
String type, Integer isActive, Long scenicId) { String type, Integer isActive, Long scenicId) {
log.debug("分页查询设备带配置列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}", log.debug("分页查询设备带配置列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}",
page, pageSize, name, no, type, isActive, scenicId); page, pageSize, name, no, type, isActive, scenicId);
CommonResponse<DeviceV2WithConfigListResponse> response = deviceV2Client.listDevicesWithConfig( CommonResponse<PageResponse<DeviceV2WithConfigDTO>> response = deviceV2Client.listDevicesWithConfig(
page, pageSize, name, no, type, isActive, scenicId); page, pageSize, name, no, type, isActive, scenicId);
return handleResponse(response, "分页查询设备带配置列表失败"); return handleResponse(response, "分页查询设备带配置列表失败");
} }
@@ -196,14 +197,14 @@ public class DeviceIntegrationService {
/** /**
* 获取景区的IPC设备列表 * 获取景区的IPC设备列表
*/ */
public DeviceV2ListResponse getScenicIpcDevices(Long scenicId, Integer page, Integer pageSize) { public PageResponse<DeviceV2DTO> getScenicIpcDevices(Long scenicId, Integer page, Integer pageSize) {
return listDevices(page, pageSize, null, null, "IPC", 1, scenicId); return listDevices(page, pageSize, null, null, "IPC", 1, scenicId);
} }
/** /**
* 获取景区的所有激活设备 * 获取景区的所有激活设备
*/ */
public DeviceV2ListResponse getScenicActiveDevices(Long scenicId, Integer page, Integer pageSize) { public PageResponse<DeviceV2DTO> getScenicActiveDevices(Long scenicId, Integer page, Integer pageSize) {
return listDevices(page, pageSize, null, null, null, 1, scenicId); return listDevices(page, pageSize, null, null, null, 1, scenicId);
} }

View File

@@ -0,0 +1,59 @@
package com.ycwl.basic.integration.render.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest;
import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 渲染工作器配置V2客户端
*/
@FeignClient(name = "zt-render-worker", contextId = "render-worker-config-v2", path = "/api/render/worker/config/v2")
public interface RenderWorkerConfigV2Client {
/**
* 获取工作器所有配置
*/
@GetMapping("/{workerId}")
CommonResponse<List<RenderWorkerConfigV2DTO>> getWorkerConfigs(@PathVariable("workerId") Long workerId);
/**
* 根据配置键获取特定配置
*/
@GetMapping("/{workerId}/key/{configKey}")
CommonResponse<RenderWorkerConfigV2DTO> getWorkerConfigByKey(@PathVariable("workerId") Long workerId,
@PathVariable("configKey") String configKey);
/**
* 创建配置
*/
@PostMapping("/{workerId}")
CommonResponse<RenderWorkerConfigV2DTO> createWorkerConfig(@PathVariable("workerId") Long workerId,
@RequestBody RenderWorkerConfigV2DTO config);
/**
* 更新配置
*/
@PutMapping("/{workerId}/{id}")
CommonResponse<Void> updateWorkerConfig(@PathVariable("workerId") Long workerId,
@PathVariable("id") Long id,
@RequestBody Map<String, Object> updates);
/**
* 删除配置
*/
@DeleteMapping("/{workerId}/{id}")
CommonResponse<Void> deleteWorkerConfig(@PathVariable("workerId") Long workerId,
@PathVariable("id") Long id);
/**
* 批量更新配置
*/
@PostMapping("/{workerId}/batch")
CommonResponse<Void> batchUpdateWorkerConfigs(@PathVariable("workerId") Long workerId,
@RequestBody BatchRenderWorkerConfigRequest request);
}

View File

@@ -0,0 +1,76 @@
package com.ycwl.basic.integration.render.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.render.dto.worker.*;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* 渲染工作器V2客户端
*/
@FeignClient(name = "zt-render-worker", contextId = "render-worker-v2", path = "/api/render/worker/v2")
public interface RenderWorkerV2Client {
/**
* 获取工作器核心信息
*/
@GetMapping("/{id}")
CommonResponse<RenderWorkerV2DTO> getWorker(@PathVariable("id") Long id);
/**
* 获取工作器含配置信息
*/
@GetMapping("/{id}/with-config")
CommonResponse<RenderWorkerV2WithConfigDTO> getWorkerWithConfig(@PathVariable("id") Long id);
/**
* 创建工作器
*/
@PostMapping
CommonResponse<RenderWorkerV2DTO> createWorker(@RequestBody CreateRenderWorkerRequest request);
/**
* 更新工作器
*/
@PutMapping("/{id}")
CommonResponse<Void> updateWorker(@PathVariable("id") Long id,
@RequestBody UpdateRenderWorkerRequest request);
/**
* 删除工作器
*/
@DeleteMapping("/{id}")
CommonResponse<Void> deleteWorker(@PathVariable("id") Long id);
/**
* 分页查询工作器列表(核心信息)
*/
@GetMapping
CommonResponse<PageResponse<RenderWorkerV2DTO>> listWorkers(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer isEnabled,
@RequestParam(required = false) String name);
/**
* 分页查询工作器列表(含配置信息)
*/
@GetMapping("/with-config")
CommonResponse<PageResponse<RenderWorkerV2WithConfigDTO>> listWorkersWithConfig(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer isEnabled,
@RequestParam(required = false) String name);
/**
* 根据key获取工作器核心信息
*/
@GetMapping("/key/{key}")
CommonResponse<RenderWorkerV2DTO> getWorkerByKey(@PathVariable("key") String key);
/**
* 根据key获取工作器完整信息(含配置)
*/
@GetMapping("/key/{key}/with-config")
CommonResponse<RenderWorkerV2WithConfigDTO> getWorkerWithConfigByKey(@PathVariable("key") String key);
}

View File

@@ -0,0 +1,17 @@
package com.ycwl.basic.integration.render.config;
import com.ycwl.basic.integration.common.config.IntegrationProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
/**
* 渲染工作器集成配置
*/
@Configuration
@ConditionalOnProperty(prefix = "integration.render", name = "enabled", havingValue = "true", matchIfMissing = true)
@RequiredArgsConstructor
public class RenderWorkerIntegrationConfig {
private final IntegrationProperties integrationProperties;
}

View File

@@ -0,0 +1,17 @@
package com.ycwl.basic.integration.render.dto.config;
import lombok.Data;
import java.util.List;
/**
* 批量更新渲染工作器配置请求DTO
*/
@Data
public class BatchRenderWorkerConfigRequest {
/**
* 配置列表
*/
private List<RenderWorkerConfigV2DTO> configs;
}

View File

@@ -0,0 +1,63 @@
package com.ycwl.basic.integration.render.dto.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 渲染工作器配置DTO
*/
@Data
public class RenderWorkerConfigV2DTO {
/**
* 配置ID
*/
private Long id;
/**
* 工作器ID
*/
@JsonProperty("workerId")
private Long workerId;
/**
* 配置键
*/
@JsonProperty("configKey")
private String configKey;
/**
* 配置值
*/
@JsonProperty("configValue")
private String configValue;
/**
* 配置类型 (string/int/float/bool/json)
*/
@JsonProperty("configType")
private String configType;
/**
* 描述
*/
private String description;
/**
* 是否启用 (0-禁用,1-启用)
*/
@JsonProperty("isActive")
private Integer isActive;
/**
* 创建时间
*/
@JsonProperty("createTime")
private String createTime;
/**
* 更新时间
*/
@JsonProperty("updateTime")
private String updateTime;
}

View File

@@ -0,0 +1,31 @@
package com.ycwl.basic.integration.render.dto.worker;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 创建渲染工作器请求DTO
*/
@Data
public class CreateRenderWorkerRequest {
/**
* 工作器名称
*/
@NotBlank(message = "工作器名称不能为空")
private String name;
/**
* 工作器标识
*/
@NotBlank(message = "工作器标识不能为空")
private String key;
/**
* 是否启用 (0-禁用,1-启用)
*/
@JsonProperty("isActive")
private Integer isActive = 1;
}

View File

@@ -0,0 +1,49 @@
package com.ycwl.basic.integration.render.dto.worker;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.Date;
/**
* 渲染工作器核心信息DTO
*/
@Data
public class RenderWorkerV2DTO {
/**
* 工作器ID
*/
private Long id;
/**
* 工作器名称
*/
private String name;
/**
* 工作器标识
*/
private String key;
/**
* 是否启用 (0-禁用,1-启用)
*/
@JsonProperty("isActive")
private Integer isActive;
/**
* 创建时间
*/
@JsonProperty("createTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 更新时间
*/
@JsonProperty("updateTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,55 @@
package com.ycwl.basic.integration.render.dto.worker;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.Date;
import java.util.Map;
/**
* 带配置的渲染工作器DTO
*/
@Data
public class RenderWorkerV2WithConfigDTO {
/**
* 工作器ID
*/
private Long id;
/**
* 工作器名称
*/
private String name;
/**
* 工作器标识
*/
private String key;
/**
* 是否启用 (0-禁用,1-启用)
*/
@JsonProperty("isActive")
private Integer isActive;
/**
* 创建时间
*/
@JsonProperty("createTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 更新时间
*/
@JsonProperty("updateTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
/**
* 动态配置信息
*/
private Map<String, Object> config;
}

View File

@@ -0,0 +1,27 @@
package com.ycwl.basic.integration.render.dto.worker;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 更新渲染工作器请求DTO
*/
@Data
public class UpdateRenderWorkerRequest {
/**
* 工作器名称
*/
private String name;
/**
* 工作器标识
*/
private String key;
/**
* 是否启用 (0-禁用,1-启用)
*/
@JsonProperty("isActive")
private Integer isActive;
}

View File

@@ -0,0 +1,287 @@
package com.ycwl.basic.integration.render.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.render.client.RenderWorkerConfigV2Client;
import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest;
import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 渲染工作器配置集成服务
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class RenderWorkerConfigIntegrationService {
private final RenderWorkerConfigV2Client renderWorkerConfigV2Client;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-render-worker";
/**
* 获取工作器所有配置(带降级)
*/
public List<RenderWorkerConfigV2DTO> getWorkerConfigs(Long workerId) {
log.info("获取渲染工作器配置列表, workerId: {}", workerId);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"worker:configs:" + workerId,
() -> {
CommonResponse<List<RenderWorkerConfigV2DTO>> response =
renderWorkerConfigV2Client.getWorkerConfigs(workerId);
List<RenderWorkerConfigV2DTO> configs = handleResponse(response, "获取渲染工作器配置列表失败");
return configs != null ? configs : Collections.emptyList();
},
List.class
);
}
/**
* 根据配置键获取特定配置(带降级)
*/
public RenderWorkerConfigV2DTO getWorkerConfigByKey(Long workerId, String configKey) {
log.info("根据配置键获取渲染工作器配置, workerId: {}, configKey: {}", workerId, configKey);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"worker:config:" + workerId + ":" + configKey,
() -> {
CommonResponse<RenderWorkerConfigV2DTO> response =
renderWorkerConfigV2Client.getWorkerConfigByKey(workerId, configKey);
return handleResponse(response, "根据配置键获取渲染工作器配置失败");
},
RenderWorkerConfigV2DTO.class
);
}
/**
* 获取工作器平铺配置(带降级)
*/
public Map<String, Object> getWorkerFlatConfig(Long workerId) {
log.info("获取渲染工作器平铺配置, workerId: {}", workerId);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"worker:flat:config:" + workerId,
() -> {
List<RenderWorkerConfigV2DTO> configs = getWorkerConfigsInternal(workerId);
return flattenConfigs(configs);
},
Map.class
);
}
/**
* 创建配置(直接调用,不降级)
*/
public RenderWorkerConfigV2DTO createWorkerConfig(Long workerId, RenderWorkerConfigV2DTO config) {
log.info("创建渲染工作器配置, workerId: {}, configKey: {}", workerId, config.getConfigKey());
CommonResponse<RenderWorkerConfigV2DTO> response =
renderWorkerConfigV2Client.createWorkerConfig(workerId, config);
return handleResponse(response, "创建渲染工作器配置失败");
}
/**
* 更新配置(直接调用,不降级)
*/
public void updateWorkerConfig(Long workerId, Long configId, Map<String, Object> updates) {
log.info("更新渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
CommonResponse<Void> response =
renderWorkerConfigV2Client.updateWorkerConfig(workerId, configId, updates);
handleVoidResponse(response, "更新渲染工作器配置失败");
}
/**
* 删除配置(直接调用,不降级)
*/
public void deleteWorkerConfig(Long workerId, Long configId) {
log.info("删除渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
CommonResponse<Void> response =
renderWorkerConfigV2Client.deleteWorkerConfig(workerId, configId);
handleVoidResponse(response, "删除渲染工作器配置失败");
}
/**
* 批量更新配置(直接调用,不降级)
*/
public void batchUpdateWorkerConfigs(Long workerId, BatchRenderWorkerConfigRequest request) {
log.info("批量更新渲染工作器配置, workerId: {}, configCount: {}",
workerId, request.getConfigs() != null ? request.getConfigs().size() : 0);
CommonResponse<Void> response =
renderWorkerConfigV2Client.batchUpdateWorkerConfigs(workerId, request);
handleVoidResponse(response, "批量更新渲染工作器配置失败");
}
/**
* 批量平铺更新配置(直接调用,不降级)
*/
public void batchFlatUpdateWorkerConfigs(Long workerId, Map<String, Object> flatConfigs) {
log.info("批量平铺更新渲染工作器配置, workerId: {}, configCount: {}",
workerId, flatConfigs.size());
BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest();
List<RenderWorkerConfigV2DTO> configs = flatConfigs.entrySet().stream()
.map(entry -> {
RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO();
config.setConfigKey(entry.getKey());
config.setConfigValue(String.valueOf(entry.getValue()));
config.setConfigType(determineConfigType(entry.getValue()));
config.setIsActive(1);
return config;
})
.toList();
request.setConfigs(configs);
batchUpdateWorkerConfigs(workerId, request);
}
/**
* 创建批量配置构建器
*/
public BatchConfigBuilder createBatchConfigBuilder() {
return new BatchConfigBuilder();
}
/**
* 内部获取配置方法(不使用降级)
*/
private List<RenderWorkerConfigV2DTO> getWorkerConfigsInternal(Long workerId) {
CommonResponse<List<RenderWorkerConfigV2DTO>> response =
renderWorkerConfigV2Client.getWorkerConfigs(workerId);
List<RenderWorkerConfigV2DTO> configs = handleResponse(response, "获取渲染工作器配置列表失败");
return configs != null ? configs : Collections.emptyList();
}
/**
* 将配置列表转换为平铺Map
*/
private Map<String, Object> flattenConfigs(List<RenderWorkerConfigV2DTO> configs) {
Map<String, Object> flatConfig = new HashMap<>();
for (RenderWorkerConfigV2DTO config : configs) {
if (config.getIsActive() == 1) {
Object value = convertConfigValue(config.getConfigValue(), config.getConfigType());
flatConfig.put(config.getConfigKey(), value);
}
}
return flatConfig;
}
/**
* 根据配置类型转换配置值
*/
private Object convertConfigValue(String configValue, String configType) {
if (configValue == null) return null;
return switch (configType) {
case "int" -> Integer.parseInt(configValue);
case "float" -> Double.parseDouble(configValue);
case "bool" -> Boolean.parseBoolean(configValue);
case "json" -> configValue; // 保持JSON字符串格式
default -> configValue; // string类型或其他
};
}
/**
* 自动判断配置类型
*/
private String determineConfigType(Object value) {
if (value instanceof Integer) return "int";
if (value instanceof Double || value instanceof Float) return "float";
if (value instanceof Boolean) return "bool";
return "string";
}
/**
* 处理通用响应
*/
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.getSuccess()) {
String msg = response != null && response.getMessage() != null ?
response.getMessage() : errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, SERVICE_NAME);
}
return response.getData();
}
/**
* 处理空响应
*/
private void handleVoidResponse(CommonResponse<Void> response, String errorMessage) {
if (response == null || !response.getSuccess()) {
String msg = response != null && response.getMessage() != null ?
response.getMessage() : errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, SERVICE_NAME);
}
}
/**
* 批量配置构建器
*/
public static class BatchConfigBuilder {
private final List<RenderWorkerConfigV2DTO> configs = new java.util.ArrayList<>();
/**
* 添加配置项
*/
public BatchConfigBuilder addConfig(String key, String value) {
return addConfig(key, value, "string", null);
}
/**
* 添加配置项(指定类型)
*/
public BatchConfigBuilder addConfig(String key, String value, String type) {
return addConfig(key, value, type, null);
}
/**
* 添加配置项(完整)
*/
public BatchConfigBuilder addConfig(String key, String value, String type, String description) {
RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO();
config.setConfigKey(key);
config.setConfigValue(value);
config.setConfigType(type);
config.setDescription(description);
config.setIsActive(1);
configs.add(config);
return this;
}
/**
* 添加渲染配置
*/
public BatchConfigBuilder addRenderConfig(String quality, String format, String resolution) {
return addConfig("render_quality", quality, "string", "渲染质量")
.addConfig("render_format", format, "string", "渲染格式")
.addConfig("render_resolution", resolution, "string", "渲染分辨率");
}
/**
* 添加性能配置
*/
public BatchConfigBuilder addPerformanceConfig(Integer maxTasks, Integer timeout) {
return addConfig("max_concurrent_tasks", String.valueOf(maxTasks), "int", "最大并发任务数")
.addConfig("task_timeout", String.valueOf(timeout), "int", "任务超时时间(秒)");
}
/**
* 构建批量配置请求
*/
public BatchRenderWorkerConfigRequest build() {
BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest();
request.setConfigs(configs);
return request;
}
}
}

View File

@@ -0,0 +1,168 @@
package com.ycwl.basic.integration.render.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.render.client.RenderWorkerV2Client;
import com.ycwl.basic.integration.render.dto.worker.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* 渲染工作器集成服务
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class RenderWorkerIntegrationService {
private final RenderWorkerV2Client renderWorkerV2Client;
private final IntegrationFallbackService fallbackService;
private static final String SERVICE_NAME = "zt-render-worker";
/**
* 获取工作器核心信息(带降级)
*/
public RenderWorkerV2DTO getWorker(Long id) {
log.info("获取渲染工作器信息, id: {}", id);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"worker:" + id,
() -> {
CommonResponse<RenderWorkerV2DTO> response = renderWorkerV2Client.getWorker(id);
return handleResponse(response, "获取渲染工作器信息失败");
},
RenderWorkerV2DTO.class
);
}
/**
* 获取工作器详细信息(含配置)(带降级)
*/
public RenderWorkerV2WithConfigDTO getWorkerWithConfig(Long id) {
log.info("获取渲染工作器详细信息, id: {}", id);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"worker:config:" + id,
() -> {
CommonResponse<RenderWorkerV2WithConfigDTO> response = renderWorkerV2Client.getWorkerWithConfig(id);
return handleResponse(response, "获取渲染工作器详细信息失败");
},
RenderWorkerV2WithConfigDTO.class
);
}
/**
* 创建工作器(直接调用,不降级)
*/
public RenderWorkerV2DTO createWorker(CreateRenderWorkerRequest request) {
log.info("创建渲染工作器, name: {}, key: {}", request.getName(), request.getKey());
CommonResponse<RenderWorkerV2DTO> response = renderWorkerV2Client.createWorker(request);
return handleResponse(response, "创建渲染工作器失败");
}
/**
* 更新工作器(直接调用,不降级)
*/
public void updateWorker(Long id, UpdateRenderWorkerRequest request) {
log.info("更新渲染工作器, id: {}, name: {}", id, request.getName());
CommonResponse<Void> response = renderWorkerV2Client.updateWorker(id, request);
handleVoidResponse(response, "更新渲染工作器失败");
}
/**
* 删除工作器(直接调用,不降级)
*/
public void deleteWorker(Long id) {
log.info("删除渲染工作器, id: {}", id);
CommonResponse<Void> response = renderWorkerV2Client.deleteWorker(id);
handleVoidResponse(response, "删除渲染工作器失败");
}
/**
* 分页查询工作器列表(核心信息)(不降级)
*/
public PageResponse<RenderWorkerV2DTO> listWorkers(Integer page, Integer pageSize, Integer isEnabled, String name) {
log.info("分页查询渲染工作器列表, page: {}, pageSize: {}, isEnabled: {}, name: {}",
page, pageSize, isEnabled, name);
CommonResponse<PageResponse<RenderWorkerV2DTO>> response =
renderWorkerV2Client.listWorkers(page, pageSize, isEnabled, name);
return handleResponse(response, "查询渲染工作器列表失败");
}
/**
* 分页查询工作器列表(含配置信息)(不降级)
*/
public PageResponse<RenderWorkerV2WithConfigDTO> listWorkersWithConfig(Integer page, Integer pageSize,
Integer isEnabled, String name) {
log.info("分页查询渲染工作器列表(含配置), page: {}, pageSize: {}, isEnabled: {}, name: {}",
page, pageSize, isEnabled, name);
CommonResponse<PageResponse<RenderWorkerV2WithConfigDTO>> response =
renderWorkerV2Client.listWorkersWithConfig(page, pageSize, isEnabled, name);
return handleResponse(response, "查询渲染工作器列表(含配置)失败");
}
/**
* 根据key获取工作器核心信息(带降级)
*/
public RenderWorkerV2DTO getWorkerByKey(String key) {
log.info("根据key获取渲染工作器信息, key: {}", key);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"worker:key:" + key,
() -> {
CommonResponse<RenderWorkerV2DTO> response = renderWorkerV2Client.getWorkerByKey(key);
return handleResponse(response, "根据key获取渲染工作器信息失败");
},
RenderWorkerV2DTO.class
);
}
/**
* 根据key获取工作器详细信息(含配置)(带降级)
*/
public RenderWorkerV2WithConfigDTO getWorkerWithConfigByKey(String key) {
log.info("根据key获取渲染工作器详细信息, key: {}", key);
return fallbackService.executeWithFallback(
SERVICE_NAME,
"worker:key:config:" + key,
() -> {
CommonResponse<RenderWorkerV2WithConfigDTO> response = renderWorkerV2Client.getWorkerWithConfigByKey(key);
return handleResponse(response, "根据key获取渲染工作器详细信息失败");
},
RenderWorkerV2WithConfigDTO.class
);
}
/**
* 处理通用响应
*/
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.getSuccess()) {
String msg = response != null && response.getMessage() != null ?
response.getMessage() : errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, SERVICE_NAME);
}
return response.getData();
}
/**
* 处理空响应
*/
private void handleVoidResponse(CommonResponse<Void> response, String errorMessage) {
if (response == null || !response.getSuccess()) {
String msg = response != null && response.getMessage() != null ?
response.getMessage() : errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, SERVICE_NAME);
}
}
}

View File

@@ -6,8 +6,7 @@ import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigListResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -38,13 +37,13 @@ public interface ScenicV2Client {
CommonResponse<ScenicFilterPageResponse> filterScenics(@RequestBody ScenicFilterRequest request); CommonResponse<ScenicFilterPageResponse> filterScenics(@RequestBody ScenicFilterRequest request);
@GetMapping("/") @GetMapping("/")
CommonResponse<ScenicV2ListResponse> listScenics(@RequestParam(defaultValue = "1") Integer page, CommonResponse<PageResponse<ScenicV2DTO>> listScenics(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer status, @RequestParam(required = false) Integer status,
@RequestParam(required = false) String name); @RequestParam(required = false) String name);
@GetMapping("/with-config") @GetMapping("/with-config")
CommonResponse<ScenicV2WithConfigListResponse> listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page, CommonResponse<PageResponse<ScenicV2WithConfigDTO>> listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer status, @RequestParam(required = false) Integer status,
@RequestParam(required = false) String name); @RequestParam(required = false) String name);

View File

@@ -1,21 +0,0 @@
package com.ycwl.basic.integration.scenic.dto.scenic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class ScenicV2ListResponse {
@JsonProperty("list")
private List<ScenicV2DTO> list;
@JsonProperty("total")
private Integer total;
@JsonProperty("page")
private Integer page;
@JsonProperty("pageSize")
private Integer pageSize;
}

View File

@@ -1,21 +0,0 @@
package com.ycwl.basic.integration.scenic.dto.scenic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class ScenicV2WithConfigListResponse {
@JsonProperty("list")
private List<ScenicV2WithConfigDTO> list;
@JsonProperty("total")
private Integer total;
@JsonProperty("page")
private Integer page;
@JsonProperty("pageSize")
private Integer pageSize;
}

View File

@@ -13,7 +13,7 @@ import java.util.List;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class DefaultConfigIntegrationService { public class ScenicDefaultConfigIntegrationService {
private final DefaultConfigClient defaultConfigClient; private final DefaultConfigClient defaultConfigClient;

View File

@@ -10,8 +10,7 @@ import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigListResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -93,15 +92,15 @@ public class ScenicIntegrationService {
return handleResponse(response, "筛选景区失败"); return handleResponse(response, "筛选景区失败");
} }
public ScenicV2ListResponse listScenics(Integer page, Integer pageSize, Integer status, String name) { public PageResponse<ScenicV2DTO> listScenics(Integer page, Integer pageSize, Integer status, String name) {
log.debug("分页查询景区列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name); log.debug("分页查询景区列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name);
CommonResponse<ScenicV2ListResponse> response = scenicV2Client.listScenics(page, pageSize, status, name); CommonResponse<PageResponse<ScenicV2DTO>> response = scenicV2Client.listScenics(page, pageSize, status, name);
return handleResponse(response, "分页查询景区列表失败"); return handleResponse(response, "分页查询景区列表失败");
} }
public ScenicV2WithConfigListResponse listScenicsWithConfig(Integer page, Integer pageSize, Integer status, String name) { public PageResponse<ScenicV2WithConfigDTO> listScenicsWithConfig(Integer page, Integer pageSize, Integer status, String name) {
log.debug("分页查询景区带配置列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name); log.debug("分页查询景区带配置列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name);
CommonResponse<ScenicV2WithConfigListResponse> response = scenicV2Client.listScenicsWithConfig(page, pageSize, status, name); CommonResponse<PageResponse<ScenicV2WithConfigDTO>> response = scenicV2Client.listScenicsWithConfig(page, pageSize, status, name);
return handleResponse(response, "分页查询景区带配置列表失败"); return handleResponse(response, "分页查询景区带配置列表失败");
} }

View File

@@ -1,22 +0,0 @@
package com.ycwl.basic.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface PriceConfigMapper extends BaseMapper<PriceConfigEntity> {
PriceConfigRespVO getById(@Param("id") Integer id);
List<PriceConfigRespVO> listByCondition(@Param("req") PriceConfigListReq req);
PriceConfigEntity getPriceByScenicTypeGoods(Long scenicId, Integer type, String goodsId);
int updateStatus(Integer id);
}

View File

@@ -1,26 +0,0 @@
package com.ycwl.basic.mapper;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @Author:longbinbin
* @Date:2024/11/29 17:22
* 渲染机管理表
*/
@Mapper
public interface RenderWorkerMapper {
List<RenderWorkerEntity> list(RenderWorkerReqQuery renderWorkerReqQuery);
RenderWorkerEntity getById(Long id);
int add(RenderWorkerEntity renderWorker);
int deleteById(Long id);
int update(RenderWorkerEntity renderWorker);
int updateStatus(Long id);
RenderWorkerEntity findByAccessKey(String accessKey);
int updateHost(Long id, RenderWorkerEntity status);
}

View File

@@ -1,17 +1,12 @@
package com.ycwl.basic.model.pc.price.entity; package com.ycwl.basic.model.pc.price.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
@Data @Data
@TableName("price_config")
public class PriceConfigEntity { public class PriceConfigEntity {
@TableId(type = IdType.AUTO)
private Integer id; private Integer id;
/** /**
* 景区ID * 景区ID

View File

@@ -14,50 +14,16 @@ import java.util.Date;
* 渲染机管理表 * 渲染机管理表
*/ */
@Data @Data
@TableName("render_worker")
public class RenderWorkerEntity { public class RenderWorkerEntity {
@TableId
private Long id; private Long id;
/** /**
* 渲染机名称 * 渲染机名称
*/ */
private String name; private String name;
/**
* 系统
*/
private String platform;
/**
* 运行环境
*/
private String runtimeVersion;
/**
* 版本
*/
private String version;
/** /**
* 访问秘钥 * 访问秘钥
*/ */
private String accessKey; private String accessKey;
/**
* cpu数量
*/
private Integer cpuCount;
/**
* cpu使用率
*/
private BigDecimal cpuUsage;
/**
* 内存总量,MB
*/
private BigDecimal memoryTotal;
/**
* 内存余量,MB
*/
private BigDecimal memoryAvailable;
/**
* 支持的功能,逗号隔开
*/
private String supportFeature;
/** /**
* 是否仅用于指定景区,空或0不适用,否则为景区ID * 是否仅用于指定景区,空或0不适用,否则为景区ID
*/ */
@@ -66,24 +32,10 @@ public class RenderWorkerEntity {
* 是否仅用于测试,0不是,1是 * 是否仅用于测试,0不是,1是
*/ */
private Integer testOnly; private Integer testOnly;
/**
* 是否在线,0不在,1在
*/
private Integer online;
/** /**
* 状态,0禁用,1启用 * 状态,0禁用,1启用
*/ */
private Integer status; private Integer status;
private Date createAt; private Date createAt;
private Date updateAt; private Date updateAt;
/**
* 存储类型
*/
private StorageType storeType;
/**
* 存储配置
*/
private String storeConfigJson;
} }

View File

@@ -3,23 +3,17 @@ package com.ycwl.basic.repository;
import com.ycwl.basic.pricing.entity.PriceOnePriceConfig; import com.ycwl.basic.pricing.entity.PriceOnePriceConfig;
import com.ycwl.basic.pricing.service.IOnePricePurchaseService; import com.ycwl.basic.pricing.service.IOnePricePurchaseService;
import com.ycwl.basic.utils.JacksonUtil; import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.mapper.PriceConfigMapper;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity; import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component @Component
public class PriceRepository { public class PriceRepository {
@Autowired
private PriceConfigMapper mapper;
@Autowired @Autowired
private RedisTemplate<String, String> redisTemplate; private RedisTemplate<String, String> redisTemplate;
public static final String PRICE_SCENIC_TYPE_GOODS_CACHE = "price:s%s:t%s:g%s";
public static final String PRICE_ID_CACHE = "price:%s"; public static final String PRICE_ID_CACHE = "price:%s";
@Autowired @Autowired
private IOnePricePurchaseService onePricePurchaseService; private IOnePricePurchaseService onePricePurchaseService;
@@ -39,19 +33,7 @@ public class PriceRepository {
entity.setGoodsIds(goodsId); entity.setGoodsIds(goodsId);
return entity; return entity;
} }
String cacheKey = String.format(PRICE_SCENIC_TYPE_GOODS_CACHE, scenicId, type, goodsId); return null;
PriceConfigEntity priceConfigEntity = null;
if (redisTemplate.hasKey(cacheKey)) {
priceConfigEntity = JacksonUtil.parseObject(redisTemplate.opsForValue().get(cacheKey), PriceConfigEntity.class);
}
if (priceConfigEntity == null) {
priceConfigEntity = mapper.getPriceByScenicTypeGoods(scenicId, type, goodsId);
if (priceConfigEntity != null) {
redisTemplate.opsForValue().set(cacheKey, JacksonUtil.toJSONString(priceConfigEntity), 12, TimeUnit.HOURS);
redisTemplate.opsForValue().set(String.format(PRICE_ID_CACHE, priceConfigEntity.getId()), JacksonUtil.toJSONString(priceConfigEntity), 12, TimeUnit.HOURS);
}
}
return priceConfigEntity;
} }
public PriceConfigEntity getPriceConfig(Integer id) { public PriceConfigEntity getPriceConfig(Integer id) {

View File

@@ -1,50 +1,50 @@
package com.ycwl.basic.repository; package com.ycwl.basic.repository;
import com.ycwl.basic.utils.JacksonUtil; import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.mapper.RenderWorkerMapper;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity; import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
import com.ycwl.basic.model.task.req.ClientStatusReqVo; import com.ycwl.basic.model.task.req.ClientStatusReqVo;
import com.ycwl.basic.integration.render.dto.worker.RenderWorkerV2DTO;
import com.ycwl.basic.integration.render.service.RenderWorkerIntegrationService;
import com.ycwl.basic.integration.render.service.RenderWorkerConfigIntegrationService;
import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO;
import com.ycwl.basic.integration.common.manager.RenderWorkerConfigManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Slf4j
@Component @Component
public class RenderWorkerRepository { public class RenderWorkerRepository {
@Autowired @Autowired
private RedisTemplate<String, String> redisTemplate; private RedisTemplate<String, String> redisTemplate;
public static final String RENDER_WORKER_CACHE_KEY = "render_worker:%s";
public static final String RENDER_WORKER_STATUS_CACHE_KEY = "render_worker:host_status:%s"; public static final String RENDER_WORKER_STATUS_CACHE_KEY = "render_worker:host_status:%s";
@Autowired @Autowired
private RenderWorkerMapper mapper; private RenderWorkerIntegrationService renderWorkerIntegrationService;
@Autowired
private RenderWorkerConfigIntegrationService renderWorkerConfigIntegrationService;
public RenderWorkerEntity getWorkerByAccessKey(String accessKey) { public RenderWorkerEntity getWorkerByAccessKey(String accessKey) {
String key = String.format(RENDER_WORKER_CACHE_KEY, accessKey); RenderWorkerV2DTO workerDTO = renderWorkerIntegrationService.getWorkerByKey(accessKey);
if (redisTemplate.hasKey(key)) { if (workerDTO == null) {
return JacksonUtil.parseObject(redisTemplate.opsForValue().get(key), RenderWorkerEntity.class); return null;
}
RenderWorkerEntity renderWorker = mapper.findByAccessKey(accessKey);
if (renderWorker != null) {
redisTemplate.opsForValue().set(key, JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS);
redisTemplate.opsForValue().set(String.format(RENDER_WORKER_CACHE_KEY, renderWorker.getId()), JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS);
} }
RenderWorkerEntity renderWorker = convertToEntity(workerDTO);
return renderWorker; return renderWorker;
} }
public RenderWorkerEntity getWorker(Long id) { public RenderWorkerEntity getWorker(Long id) {
String key = String.format(RENDER_WORKER_CACHE_KEY, id); RenderWorkerV2DTO workerDTO = renderWorkerIntegrationService.getWorker(id);
if (redisTemplate.hasKey(key)) { if (workerDTO == null) {
return JacksonUtil.parseObject(redisTemplate.opsForValue().get(key), RenderWorkerEntity.class); return null;
}
RenderWorkerEntity renderWorker = mapper.getById(id);
if (renderWorker != null) {
redisTemplate.opsForValue().set(key, JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS);
redisTemplate.opsForValue().set(String.format(RENDER_WORKER_CACHE_KEY, renderWorker.getAccessKey()), JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS);
} }
RenderWorkerEntity renderWorker = convertToEntity(workerDTO);
return renderWorker; return renderWorker;
} }
@@ -54,21 +54,6 @@ public class RenderWorkerRepository {
return; return;
} }
status.setUpdateAt(new Date()); status.setUpdateAt(new Date());
RenderWorkerEntity worker = new RenderWorkerEntity();
worker.setCpuCount(status.getCpu_count());
worker.setCpuUsage(status.getCpu_usage());
// 上报的是字节,存储的是兆
worker.setMemoryAvailable(status.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setMemoryTotal(status.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setPlatform(status.getPlatform());
worker.setRuntimeVersion(status.getRuntime_version());
worker.setSupportFeature(String.join(",", status.getSupport_feature()));
worker.setVersion(status.getVersion());
worker.setUpdateAt(status.getUpdateAt());
if (!redisTemplate.hasKey(key)) {
mapper.updateHost(id, worker);
}
redisTemplate.opsForValue().set(key, JacksonUtil.toJSONString(status), 1, TimeUnit.HOURS); redisTemplate.opsForValue().set(key, JacksonUtil.toJSONString(status), 1, TimeUnit.HOURS);
} }
@@ -81,12 +66,34 @@ public class RenderWorkerRepository {
return null; return null;
} }
public void clearCache(Long id) { private RenderWorkerEntity convertToEntity(RenderWorkerV2DTO dto) {
RenderWorkerEntity worker = getWorker(id); if (dto == null) {
redisTemplate.delete(String.format(RENDER_WORKER_CACHE_KEY, id)); return null;
if (worker != null) {
redisTemplate.delete(String.format(RENDER_WORKER_CACHE_KEY, worker.getAccessKey()));
} }
redisTemplate.delete(String.format(RENDER_WORKER_STATUS_CACHE_KEY, id)); RenderWorkerEntity entity = new RenderWorkerEntity();
entity.setId(dto.getId());
entity.setName(dto.getName());
entity.setAccessKey(dto.getKey());
entity.setStatus(dto.getIsActive());
entity.setCreateAt(dto.getCreateTime());
entity.setUpdateAt(dto.getUpdateTime());
return entity;
} }
/**
* 获取渲染工作器配置管理器
*
* @param workerId 工作器ID
* @return RenderWorkerConfigManager实例,如果获取失败返回null
*/
public RenderWorkerConfigManager getWorkerConfigManager(Long workerId) {
try {
List<RenderWorkerConfigV2DTO> configList = renderWorkerConfigIntegrationService.getWorkerConfigs(workerId);
return new RenderWorkerConfigManager(configList);
} catch (Exception e) {
log.error("获取渲染工作器配置管理器失败, workerId: {}", workerId, e);
return null;
}
}
} }

View File

@@ -3,7 +3,7 @@ package com.ycwl.basic.repository;
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType; import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
import com.ycwl.basic.integration.common.util.ConfigValueUtil; import com.ycwl.basic.integration.common.util.ConfigValueUtil;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService; import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService;
import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService; import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService;
@@ -212,7 +212,7 @@ public class ScenicRepository {
String name = scenicReqQuery.getName(); String name = scenicReqQuery.getName();
// 调用 zt-scenic 服务的 list 方法 // 调用 zt-scenic 服务的 list 方法
ScenicV2ListResponse response = scenicIntegrationService.listScenics(page, pageSize, status, name); PageResponse<ScenicV2DTO> response = scenicIntegrationService.listScenics(page, pageSize, status, name);
// 将 ScenicV2DTO 列表转换为 ScenicEntity 列表 // 将 ScenicV2DTO 列表转换为 ScenicEntity 列表
if (response != null && response.getList() != null) { if (response != null && response.getList() != null) {

View File

@@ -5,7 +5,8 @@ import com.github.pagehelper.PageInfo;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager; import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService; import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
import com.ycwl.basic.integration.device.dto.device.DeviceV2ListResponse; import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.mapper.ExtraDeviceMapper; import com.ycwl.basic.mapper.ExtraDeviceMapper;
import com.ycwl.basic.mapper.ScenicAccountMapper; import com.ycwl.basic.mapper.ScenicAccountMapper;
import com.ycwl.basic.model.jwt.JwtInfo; import com.ycwl.basic.model.jwt.JwtInfo;
@@ -86,7 +87,7 @@ public class AppScenicServiceImpl implements AppScenicService {
public ApiResponse<ScenicDeviceCountVO> deviceCountByScenicId(Long scenicId) { public ApiResponse<ScenicDeviceCountVO> deviceCountByScenicId(Long scenicId) {
JwtInfo worker = JwtTokenUtil.getWorker(); JwtInfo worker = JwtTokenUtil.getWorker();
// 通过zt-device服务获取设备统计 // 通过zt-device服务获取设备统计
DeviceV2ListResponse deviceListResponse = deviceIntegrationService.getScenicActiveDevices(scenicId, 1, 1000); PageResponse<DeviceV2DTO> deviceListResponse = deviceIntegrationService.getScenicActiveDevices(scenicId, 1, 1000);
ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO(); ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO();
if (deviceListResponse != null && deviceListResponse.getList() != null) { if (deviceListResponse != null && deviceListResponse.getList() != null) {
scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size()); scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size());
@@ -120,7 +121,7 @@ public class AppScenicServiceImpl implements AppScenicService {
} }
// 通过zt-device服务获取设备统计 // 通过zt-device服务获取设备统计
DeviceV2ListResponse deviceListResponse = deviceIntegrationService.getScenicActiveDevices(id, 1, 1000); PageResponse<DeviceV2DTO> deviceListResponse = deviceIntegrationService.getScenicActiveDevices(id, 1, 1000);
ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO(); ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO();
if (deviceListResponse != null && deviceListResponse.getList() != null) { if (deviceListResponse != null && deviceListResponse.getList() != null) {
scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size()); scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size());
@@ -276,7 +277,7 @@ public class AppScenicServiceImpl implements AppScenicService {
@Override @Override
public ApiResponse<List<DeviceRespVO>> getDevices(Long scenicId) { public ApiResponse<List<DeviceRespVO>> getDevices(Long scenicId) {
DeviceV2ListResponse deviceV2ListResponse = deviceIntegrationService.listDevices(1, 1000, null, null, null, 1, scenicId); PageResponse<DeviceV2DTO> deviceV2ListResponse = deviceIntegrationService.listDevices(1, 1000, null, null, null, 1, scenicId);
List<DeviceRespVO> deviceRespVOList = deviceV2ListResponse.getList().stream().map(device -> { List<DeviceRespVO> deviceRespVOList = deviceV2ListResponse.getList().stream().map(device -> {
DeviceRespVO deviceRespVO = new DeviceRespVO(); DeviceRespVO deviceRespVO = new DeviceRespVO();
deviceRespVO.setId(device.getId()); deviceRespVO.setId(device.getId());

View File

@@ -1,24 +0,0 @@
package com.ycwl.basic.service.pc;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import java.util.List;
public interface PriceConfigService extends IService<PriceConfigEntity> {
List<PriceConfigRespVO> listByCondition(PriceConfigListReq req);
PriceConfigRespVO findById(Integer id);
List<GoodsListRespVO> listGoodsByScenic(Long scenicId);
void fillGoodsName(List<PriceConfigRespVO> result);
void fillGoodsName(PriceConfigRespVO config);
void updateStatus(Integer id);
}

View File

@@ -1,22 +0,0 @@
package com.ycwl.basic.service.pc;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery;
import com.ycwl.basic.utils.ApiResponse;
import java.util.List;
/**
* @Author:longbinbin
* @Date:2024/12/3 15:07
*/
public interface RenderWorkerService {
ApiResponse<PageInfo<RenderWorkerEntity>> pageQuery(RenderWorkerReqQuery renderWorkerReqQuery);
ApiResponse<List<RenderWorkerEntity>> list(RenderWorkerReqQuery renderWorkerReqQuery);
ApiResponse<RenderWorkerEntity> detail(Long id);
ApiResponse<Integer> add(RenderWorkerEntity renderWorker);
ApiResponse<Integer> deleteById(Long id);
ApiResponse<Integer> update(RenderWorkerEntity renderWorker);
ApiResponse<Integer> updateStatus(Long id);
}

View File

@@ -1,85 +0,0 @@
package com.ycwl.basic.service.pc.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycwl.basic.biz.PriceBiz;
import com.ycwl.basic.mapper.PriceConfigMapper;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.repository.TemplateRepository;
import com.ycwl.basic.service.pc.PriceConfigService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class PriceConfigServiceImpl extends ServiceImpl<PriceConfigMapper, PriceConfigEntity> implements PriceConfigService {
@Autowired
private TemplateRepository templateRepository;
@Autowired
private PriceBiz priceBiz;
@Override
public List<PriceConfigRespVO> listByCondition(PriceConfigListReq req) {
return baseMapper.listByCondition(req);
}
@Override
public PriceConfigRespVO findById(Integer id) {
return baseMapper.getById(id);
}
@Override
public List<GoodsListRespVO> listGoodsByScenic(Long scenicId) {
return priceBiz.listGoodsByScenic(scenicId);
}
@Override
public void fillGoodsName(List<PriceConfigRespVO> result) {
for (PriceConfigRespVO item : result) {
fillGoodsName(item);
}
}
@Override
public void fillGoodsName(PriceConfigRespVO item) {
if (Integer.valueOf(-1).equals(item.getType())) {
item.setGoodsNames("景区内所有售卖商品");
} else if (Integer.valueOf(3).equals(item.getType())) {
item.setGoodsNames("打印照片");
} else if (StringUtils.isNotBlank(item.getGoodsIds())) {
List<String> goodsNames = new ArrayList<>();
for (String s : item.getGoodsIds().split(",")) {
if (Strings.CS.equals(s, "1")) {
goodsNames.add("录像集");
} else if (Strings.CS.equals(s, "2")) {
goodsNames.add("照片集");
} else {
if (StringUtils.isNumeric(s)) {
TemplateRespVO template = templateRepository.getTemplate(Long.valueOf(s));
if (template != null) {
goodsNames.add(template.getName());
} else {
goodsNames.add("?未知商品【"+s+"】?");
}
} else {
goodsNames.add("!未知商品【"+s+"】!");
}
}
}
item.setGoodsNames(StringUtils.join(goodsNames, ","));
}
}
@Override
public void updateStatus(Integer id) {
baseMapper.updateStatus(id);
}
}

View File

@@ -1,139 +0,0 @@
package com.ycwl.basic.service.pc.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.mapper.RenderWorkerMapper;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery;
import com.ycwl.basic.model.task.req.ClientStatusReqVo;
import com.ycwl.basic.repository.RenderWorkerRepository;
import com.ycwl.basic.service.pc.RenderWorkerService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.SnowFlakeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
/**
* @Author:longbinbin
* @Date:2024/12/3 15:09
*/
@Service
public class RenderWorkerServiceImpl implements RenderWorkerService {
@Autowired
private RenderWorkerMapper renderWorkerMapper;
@Autowired
private RenderWorkerRepository renderWorkerRepository;
@Override
public ApiResponse<PageInfo<RenderWorkerEntity>> pageQuery(RenderWorkerReqQuery renderWorkerReqQuery) {
PageHelper.startPage(renderWorkerReqQuery.getPageNum(), renderWorkerReqQuery.getPageSize());
List<RenderWorkerEntity> list = renderWorkerMapper.list(renderWorkerReqQuery);
list.forEach(worker -> {
ClientStatusReqVo clientStatus = renderWorkerRepository.getWorkerHostStatus(worker.getId());
if (clientStatus == null) {
return;
}
worker.setCpuCount(clientStatus.getCpu_count());
worker.setCpuUsage(clientStatus.getCpu_usage());
// 上报的是字节,存储的是兆
worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setPlatform(clientStatus.getPlatform());
worker.setRuntimeVersion(clientStatus.getRuntime_version());
worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature()));
worker.setVersion(clientStatus.getVersion());
worker.setUpdateAt(clientStatus.getUpdateAt());
});
PageInfo<RenderWorkerEntity> pageInfo = new PageInfo<>(list);
return ApiResponse.success(pageInfo);
}
@Override
public ApiResponse<List<RenderWorkerEntity>> list(RenderWorkerReqQuery renderWorkerReqQuery) {
List<RenderWorkerEntity> list = renderWorkerMapper.list(renderWorkerReqQuery);
list.forEach(worker -> {
ClientStatusReqVo clientStatus = renderWorkerRepository.getWorkerHostStatus(worker.getId());
if (clientStatus == null) {
return;
}
worker.setCpuCount(clientStatus.getCpu_count());
worker.setCpuUsage(clientStatus.getCpu_usage());
// 上报的是字节,存储的是兆
worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setPlatform(clientStatus.getPlatform());
worker.setRuntimeVersion(clientStatus.getRuntime_version());
worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature()));
worker.setVersion(clientStatus.getVersion());
worker.setUpdateAt(clientStatus.getUpdateAt());
});
return ApiResponse.success(list);
}
@Override
public ApiResponse<RenderWorkerEntity> detail(Long id) {
RenderWorkerEntity worker = renderWorkerMapper.getById(id);
ClientStatusReqVo clientStatus = renderWorkerRepository.getWorkerHostStatus(worker.getId());
if (clientStatus != null) {
worker.setCpuCount(clientStatus.getCpu_count());
worker.setCpuUsage(clientStatus.getCpu_usage());
// 上报的是字节,存储的是兆
worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setPlatform(clientStatus.getPlatform());
worker.setRuntimeVersion(clientStatus.getRuntime_version());
worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature()));
worker.setVersion(clientStatus.getVersion());
worker.setUpdateAt(clientStatus.getUpdateAt());
}
return ApiResponse.success(worker);
}
@Override
public ApiResponse<Integer> add(RenderWorkerEntity renderWorker) {
renderWorker.setId(SnowFlakeUtil.getLongId());
if (StringUtils.isEmpty(renderWorker.getAccessKey())) {
renderWorker.setAccessKey(SnowFlakeUtil.getId());
}
renderWorker.setStatus(0);
int add = renderWorkerMapper.add(renderWorker);
if (add == 0) {
return ApiResponse.fail("渲染机添加失败");
}else {
return ApiResponse.success(add);
}
}
@Override
public ApiResponse<Integer> deleteById(Long id) {
renderWorkerRepository.clearCache(id);
return ApiResponse.success(renderWorkerMapper.deleteById(id));
}
@Override
public ApiResponse<Integer> update(RenderWorkerEntity renderWorker) {
renderWorkerRepository.clearCache(renderWorker.getId());
int update = renderWorkerMapper.update(renderWorker);
if (update == 0) {
return ApiResponse.fail("渲染机修改失败");
}else {
return ApiResponse.success(update);
}
}
@Override
public ApiResponse<Integer> updateStatus(Long id) {
renderWorkerRepository.clearCache(id);
return ApiResponse.success(renderWorkerMapper.updateStatus(id));
}
}

View File

@@ -234,7 +234,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
if (tourMinutes > 0) { if (tourMinutes > 0) {
List<FaceSampleEntity> acceptFaceSampleList = faceSampleMapper.listByIds(acceptFaceSampleIds); List<FaceSampleEntity> acceptFaceSampleList = faceSampleMapper.listByIds(acceptFaceSampleIds);
Date startDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), -tourMinutes); Date startDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), -tourMinutes);
Date endDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), 0); Date endDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), 1);
acceptFaceSampleIds = acceptFaceSampleList.stream() acceptFaceSampleIds = acceptFaceSampleList.stream()
.filter(faceSample -> faceSample.getCreateAt().after(startDate) && faceSample.getCreateAt().before(endDate)) .filter(faceSample -> faceSample.getCreateAt().after(startDate) && faceSample.getCreateAt().before(endDate))
.map(FaceSampleEntity::getId) .map(FaceSampleEntity::getId)

View File

@@ -3,6 +3,8 @@ package com.ycwl.basic.service.task.impl;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.digest.MD5; import cn.hutool.crypto.digest.MD5;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager; import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.integration.common.manager.RenderWorkerConfigManager;
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.utils.JacksonUtil; import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.biz.OrderBiz; import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.biz.TaskStatusBiz; import com.ycwl.basic.biz.TaskStatusBiz;
@@ -12,7 +14,6 @@ import com.ycwl.basic.constant.TaskConstant;
import com.ycwl.basic.mapper.FaceMapper; import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper; import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.MemberMapper; import com.ycwl.basic.mapper.MemberMapper;
import com.ycwl.basic.mapper.RenderWorkerMapper;
import com.ycwl.basic.mapper.SourceMapper; import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.mapper.TaskMapper; import com.ycwl.basic.mapper.TaskMapper;
import com.ycwl.basic.mapper.TemplateMapper; import com.ycwl.basic.mapper.TemplateMapper;
@@ -83,6 +84,8 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
public class TaskTaskServiceImpl implements TaskService { public class TaskTaskServiceImpl implements TaskService {
private static final String WORKER_SELF_HOSTED_CACHE_KEY = "worker_self_hosted_scenic:%s";
private static final int CACHE_EXPIRE_MINUTES = 3;
@Autowired @Autowired
private TaskMapper taskMapper; private TaskMapper taskMapper;
@Autowired @Autowired
@@ -121,13 +124,40 @@ public class TaskTaskServiceImpl implements TaskService {
private DeviceRepository deviceRepository; private DeviceRepository deviceRepository;
@Autowired @Autowired
private VideoReUploader videoReUploader; private VideoReUploader videoReUploader;
@Autowired
private RedisTemplate<String, String> redisTemplate;
private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) { private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
String accessKey = req.getAccessKey(); String accessKey = req.getAccessKey();
if (accessKey == null) { if (accessKey == null) {
return null; return null;
} }
return repository.getWorkerByAccessKey(accessKey); RenderWorkerEntity worker = repository.getWorkerByAccessKey(accessKey);
if (worker == null) {
return null;
}
if (worker.getStatus() != 1) {
return null;
}
return worker;
}
private boolean isWorkerSelfHostedScenic(Long scenicId) {
String cacheKey = String.format(WORKER_SELF_HOSTED_CACHE_KEY, scenicId);
String cachedValue = redisTemplate.opsForValue().get(cacheKey);
if (cachedValue != null) {
return Boolean.parseBoolean(cachedValue);
}
// 缓存中没有,查询配置
ScenicConfigManager config = scenicRepository.getScenicConfigManager(scenicId);
boolean workerSelfHostedScenic = Boolean.TRUE.equals(config.getBoolean("worker_self_hosted"));
// 缓存结果,设置30分钟过期
redisTemplate.opsForValue().set(cacheKey, String.valueOf(workerSelfHostedScenic), CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
return workerSelfHostedScenic;
} }
@Override @Override
@@ -136,7 +166,6 @@ public class TaskTaskServiceImpl implements TaskService {
if (worker == null) { if (worker == null) {
return null; return null;
} }
worker.setOnline(1);
worker.setName(null); worker.setName(null);
worker.setStatus(null); worker.setStatus(null);
// get status // get status
@@ -162,21 +191,25 @@ public class TaskTaskServiceImpl implements TaskService {
} else { } else {
updTemplateList = templateRepository.getAllEnabledTemplateList(); updTemplateList = templateRepository.getAllEnabledTemplateList();
} }
RenderWorkerConfigManager configManager = repository.getWorkerConfigManager(worker.getId());
try { try {
if (lock.tryLock(2, TimeUnit.SECONDS)) { if (lock.tryLock(2, TimeUnit.SECONDS)) {
try { try {
List<TaskRespVO> taskList; List<TaskRespVO> taskList;
if (worker.getScenicOnly() != null) { if (Strings.isNotBlank(configManager.getString("scenic_only"))) {
taskList = taskMapper.selectNotRunningByScenicList(worker.getScenicOnly()); taskList = taskMapper.selectNotRunningByScenicList(configManager.getString("scenic_only"));
} else { } else {
taskList = taskMapper.selectNotRunning(); var _taskList = taskMapper.selectNotRunning();
taskList = _taskList.stream().filter(task -> {
boolean workerSelfHostedScenic = isWorkerSelfHostedScenic(task.getScenicId());
return !workerSelfHostedScenic;
}).limit(1).toList();
} }
resp.setTasks(taskList); resp.setTasks(taskList);
resp.setTemplates(updTemplateList); resp.setTemplates(updTemplateList);
taskList.forEach(task -> { taskList.forEach(task -> {
taskMapper.assignToWorker(task.getId(), worker.getId()); taskMapper.assignToWorker(task.getId(), worker.getId());
videoTaskRepository.clearTaskCache(task.getId()); videoTaskRepository.clearTaskCache(task.getId());
repository.clearCache(worker.getId());
}); });
} finally { } finally {
lock.unlock(); lock.unlock();
@@ -492,7 +525,6 @@ public class TaskTaskServiceImpl implements TaskService {
String hash = MD5.create().digestHex(task.getTaskParams()); String hash = MD5.create().digestHex(task.getTaskParams());
String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, hash + "_" + task.getScenicId() + ".mp4"); String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, hash + "_" + task.getScenicId() + ".mp4");
adapter.setAcl(StorageAcl.PUBLIC_READ, filename); adapter.setAcl(StorageAcl.PUBLIC_READ, filename);
videoReUploader.addVideoTask(video.getId());
int isBuy = 0; int isBuy = 0;
FaceEntity face = faceRepository.getFace(task.getFaceId()); FaceEntity face = faceRepository.getFace(task.getFaceId());
if (face != null) { if (face != null) {
@@ -551,10 +583,11 @@ public class TaskTaskServiceImpl implements TaskService {
if (worker == null) { if (worker == null) {
return null; return null;
} }
RenderWorkerConfigManager config = repository.getWorkerConfigManager(worker.getId());
IStorageAdapter adapter; IStorageAdapter adapter;
try { try {
adapter = StorageFactory.get(worker.getStoreType()); adapter = StorageFactory.get(config.getString("store_type"));
adapter.loadConfig(JacksonUtil.parseObject(worker.getStoreConfigJson(), Map.class)); adapter.loadConfig(config.getObject("store_config_json", Map.class));
} catch (Exception e) { } catch (Exception e) {
adapter = scenicService.getScenicStorageAdapter(task.getScenicId()); adapter = scenicService.getScenicStorageAdapter(task.getScenicId());
} }

View File

@@ -5,7 +5,7 @@ import com.ycwl.basic.device.DeviceFactory;
import com.ycwl.basic.device.operator.IDeviceStorageOperator; import com.ycwl.basic.device.operator.IDeviceStorageOperator;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager; import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService; import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
import com.ycwl.basic.integration.device.dto.device.DeviceV2ListResponse; import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO; import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity; import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
@@ -37,9 +37,8 @@ public class VideoPieceCleaner {
public void clean() { public void clean() {
log.info("开始删除视频文件"); log.info("开始删除视频文件");
// 通过zt-device服务获取所有激活设备 // 通过zt-device服务获取所有激活设备
DeviceV2ListResponse deviceListResponse = deviceIntegrationService.listDevices(1, 10000, null, null, null, 1, null); PageResponse<DeviceV2DTO> deviceListResponse = deviceIntegrationService.listDevices(1, 10000, null, null, null, 1, null);
List<DeviceEntity> deviceList; if (deviceListResponse == null || deviceListResponse.getList() == null) {
if (deviceListResponse == null) {
return; return;
} }
for (DeviceV2DTO device : deviceListResponse.getList()) { for (DeviceV2DTO device : deviceListResponse.getList()) {

View File

@@ -7,15 +7,12 @@ import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.mapper.VideoMapper; import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity; import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity; import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.VideoRepository; import com.ycwl.basic.repository.VideoRepository;
import com.ycwl.basic.service.pc.ScenicService; import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.storage.utils.StorageUtil; import com.ycwl.basic.storage.utils.StorageUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings; import org.apache.commons.lang3.Strings;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -94,44 +91,4 @@ public class VideoReUploader {
} }
}); });
} }
public void addVideoTask(Long videoId) {
VideoEntity entity = videoMapper.getEntity(videoId);
if (entity == null) {
return;
}
if (entity.getScenicId() == null) {
return;
}
final String dstFilePath = StorageUtil.joinPath(StorageConstant.VLOG_PATH, entity.getTaskId() + "_" + entity.getScenicId() + ".mp4");
final IStorageAdapter adapter = scenicService.getScenicStorageAdapter(entity.getScenicId());
if (Strings.CS.equals(entity.getVideoUrl(), adapter.getUrl(dstFilePath))) {
return;
}
String tmpFilePath = UUID.randomUUID().toString();
executor.execute(() -> {
// 先下载,后上传
File dstFile = new File(tmpFilePath);
log.info("下载视频:{};videoId:{}", entity.getVideoUrl(), videoId);
long size = HttpUtil.downloadFile(entity.getVideoUrl(), dstFile);
log.info("下载视频完成:{};大小:{};videoId:{}", entity.getVideoUrl(), size, videoId);
try {
log.info("开始上传:{};videoId:{}", dstFilePath, videoId);
String newUrl = adapter.uploadFile("video/mp4", dstFile, dstFilePath);
adapter.setAcl(StorageAcl.PUBLIC_READ, dstFilePath);
log.info("上传成功:{};videoId:{}", newUrl, videoId);
VideoEntity updateEntity = new VideoEntity();
updateEntity.setId(videoId);
updateEntity.setVideoUrl(newUrl);
videoMapper.update(updateEntity);
} catch (Exception e) {
log.info("上传失败:{};videoId:{}", dstFilePath, videoId, e);
} finally {
videoRepository.clearVideoCache(videoId);
try {
dstFile.delete();
} catch (Exception ignored) {
}
}
});
}
} }

View File

@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ycwl.basic.mapper.PriceConfigMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into price_config (scenic_id, type, goods_ids, price, slash_price, create_time, update_time)
values (#{scenicId}, #{type}, #{goodsIds}, #{price}, #{slashPrice}, now(), now())
</insert>
<update id="update">
update price_config
<set>
<if test="scenicId != null">scenic_id = #{scenicId},</if>
<if test="type != null">type = #{type},</if>
<if test="goodsIds != null">goods_ids = #{goodsIds},</if>
<if test="price != null">price = #{price},</if>
<if test="slashPrice != null">slash_price = #{slashPrice},</if>
update_time = now()
</set>
where id = #{id}
</update>
<update id="updateStatus">
update price_config
set `status` = IF(`status` = 0, 1, 0),
update_time = now()
where id = #{id}
</update>
<delete id="deleteById">
delete from price_config where id = #{id}
</delete>
<select id="getById" resultType="com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO">
select p.* from price_config p
where p.id = #{id}
</select>
<select id="listByCondition" resultType="com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO">
select p.* from price_config p
<where>
<if test="req.scenicId != null">
and p.scenic_id = #{req.scenicId}
</if>
<if test="req.type != null">
and p.type = #{req.type}
</if>
<if test="req.goodsId != null">
and p.goods_ids like concat('%', #{req.goodsId}, '%')
</if>
<if test="req.status != null">
and p.status = #{req.status}
</if>
</where>
</select>
<select id="getPriceByScenicTypeGoods" resultType="com.ycwl.basic.model.pc.price.entity.PriceConfigEntity">
select * from price_config
where scenic_id = #{scenicId}
and type = #{type} and status = 1
<if test="goodsId != null and goodsId != ''">
and goods_ids like concat('%', #{goodsId}, '%')
</if>
</select>
</mapper>

View File

@@ -1,142 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ycwl.basic.mapper.RenderWorkerMapper">
<insert id="add">
insert into render_worker(id, `name`, platform, runtime_version, version, access_key,
cpu_count, cpu_usage, memory_total, memory_available, support_feature, scenic_only, test_only, `online`, `status`)
VALUES (#{id}, #{name}, #{platform}, #{runtimeVersion}, #{version}, #{accessKey},
#{cpuCount}, #{cpuUsage}, #{memoryTotal}, #{memoryAvailable}, #{supportFeature}, #{scenicOnly}, #{testOnly}, #{online}, #{status})
</insert>
<update id="update">
update render_worker
<set>
<if test="name!= null and name!= ''">
name = #{name},
</if>
<if test="platform!= null and platform!= ''">
platform = #{platform},
</if>
<if test="runtimeVersion!= null and runtimeVersion!= ''">
runtime_version = #{runtimeVersion},
</if>
<if test="version!= null and version!= ''">
version = #{version},
</if>
<if test="accessKey!= null and accessKey!= ''">
access_key = #{accessKey},
</if>
<if test="cpuCount!= null">
cpu_count = #{cpuCount},
</if>
<if test="cpuUsage!= null">
cpu_usage = #{cpuUsage},
</if>
<if test="memoryTotal!= null">
memory_total = #{memoryTotal},
</if>
<if test="memoryAvailable!= null">
memory_available = #{memoryAvailable},
</if>
<if test="supportFeature!= null">
support_feature = #{supportFeature},
</if>
<if test="scenicOnly!= null">
scenic_only = #{scenicOnly},
</if>
<if test="testOnly!= null">
test_only = #{testOnly},
</if>
<if test="online!= null">
`online` = #{online},
</if>
</set>
where id = #{id}
</update>
<update id="updateStatus">
update render_worker
set status = (CASE
status
WHEN 1 THEN
0
WHEN 0 THEN
1
ELSE null
END)
where id = #{id}
</update>
<update id="updateHost">
update render_worker
set platform = #{status.platform},
runtime_version = #{status.runtimeVersion},
version = #{status.version},
cpu_count = #{status.cpuCount},
cpu_usage = #{status.cpuUsage},
memory_total = #{status.memoryTotal},
memory_available = #{status.memoryAvailable},
support_feature = #{status.supportFeature},
update_at = #{status.updateAt}
where id = #{id}
</update>
<delete id="deleteById">
delete from render_worker where id = #{id}
</delete>
<select id="list" resultType="com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity">
select id, `name`, platform, runtime_version, version, access_key,
cpu_count, cpu_usage, memory_total, memory_available, support_feature, scenic_only, test_only, `online`, `status`, create_at, update_at
from render_worker
<where>
<if test="name!= null and name!= ''">
and `name` like concat('%', #{name}, '%')
</if>
<if test="platform!= null and platform!= ''">
and platform like concat('%', #{platform}, '%')
</if>
<if test="runtimeVersion!= null and runtimeVersion!= ''">
and runtime_version like concat('%', #{runtimeVersion}, '%')
</if>
<if test="version!= null and version!= ''">
and version like concat('%', #{version}, '%')
</if>
<if test="cpuCount!= null">
and cpu_count = #{cpuCount}
</if>
<if test="cpuUsage!= null">
and cpu_usage = #{cpuUsage}
</if>
<if test="supportFeature!= null">
and support_feature like concat('%',#{supportFeature},'%')
</if>
<if test="scenicOnly!= null">
and scenic_only = #{scenicOnly}
</if>
<if test="testOnly!= null">
and test_only = #{testOnly}
</if>
<if test="online!= null">
and `online` = #{online}
</if>
<if test="status!= null">
and `status` = #{status}
</if>
<if test="startTime!=null">
and create_at >= #{startTime}
</if>
<if test="endTime!=null">
and create_at &lt;= #{endTime}
</if>
</where>
</select>
<select id="getById" resultType="com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity">
select id, `name`, platform, runtime_version, version, access_key,
cpu_count, cpu_usage, memory_total, memory_available, support_feature, scenic_only, test_only, `online`, `status`, create_at, update_at
from render_worker
where id = #{id}
</select>
<select id="findByAccessKey" resultType="com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity">
select id, `name`, scenic_only, test_only, `online`, `status`, create_at, update_at, store_type, store_config_json
from render_worker
where access_key = #{accessKey} and status = 1
</select>
</mapper>

View File

@@ -84,14 +84,6 @@
from task from task
where status = 0 where status = 0
and worker_id is null and worker_id is null
and NOT EXISTS (
SELECT 1
FROM render_worker rw
WHERE
rw.status = 1
AND FIND_IN_SET(task.scenic_id, rw.scenic_only) > 0 -- 检查scenic_id是否在逗号分隔的字符串中
)
limit 1
</select> </select>
<select id="selectAllNotRunning" resultType="com.ycwl.basic.model.pc.task.entity.TaskEntity"> <select id="selectAllNotRunning" resultType="com.ycwl.basic.model.pc.task.entity.TaskEntity">
select * select *