From 48f41ef72a6b4bf26abc9fd5241cb7ca081df994 Mon Sep 17 00:00:00 2001 From: guoshengxiong <1923636941@qq.com> Date: Mon, 8 Sep 2025 17:04:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B9=BF=E6=92=AD=E5=92=8C=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E5=88=86=E7=BB=84=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/zhgd/xmgl/async/AsyncAiAnalyse.java | 1 + .../xmgl/call/ShiZiWangBroadcastCall.java | 47 ++++++ .../xmgl/call/api/BroadcastManufacturer.java | 22 +++ .../factory/BroadcastManufacturerFactory.java | 33 ++++ .../impl/EnvironmentAlarmServiceImpl.java | 1 + .../service/IEnableMessageDevRuleService.java | 7 + .../impl/EnableMessageDevRuleServiceImpl.java | 18 +++ .../RiskListSourceDataCenterController.java | 29 ---- .../video/controller/VideoItemController.java | 152 +++++++++++++++++- .../xmgl/modules/video/entity/VideoItem.java | 6 + .../entity/dto/MoveGroupVideoItemDto.java | 14 ++ .../video/mapper/xml/VideoItemMapper.xml | 3 + .../video/service/IVideoItemService.java | 8 + .../service/impl/VideoItemServiceImpl.java | 73 ++++++++- .../zhgd/xmgl/task/MessageDevRuleTask.java | 10 +- .../java/com/zhgd/xmgl/util/ExcelUtils.java | 56 +++++++ .../java/com/zhgd/xmgl/util/FileUtils.java | 30 +++- .../videoitem/监控点导入模版(isc).xlsx | Bin 0 -> 11309 bytes .../videoitem/监控点导入模版(大华).xlsx | Bin 0 -> 11309 bytes .../videoitem/监控点导入模版(萤石云).xlsx | Bin 0 -> 11282 bytes 20 files changed, 467 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/zhgd/xmgl/call/ShiZiWangBroadcastCall.java create mode 100644 src/main/java/com/zhgd/xmgl/call/api/BroadcastManufacturer.java create mode 100644 src/main/java/com/zhgd/xmgl/call/factory/BroadcastManufacturerFactory.java create mode 100644 src/main/java/com/zhgd/xmgl/modules/video/entity/dto/MoveGroupVideoItemDto.java create mode 100644 src/main/resources/excel/videoitem/监控点导入模版(isc).xlsx create mode 100644 src/main/resources/excel/videoitem/监控点导入模版(大华).xlsx create mode 100644 src/main/resources/excel/videoitem/监控点导入模版(萤石云).xlsx diff --git a/src/main/java/com/zhgd/xmgl/async/AsyncAiAnalyse.java b/src/main/java/com/zhgd/xmgl/async/AsyncAiAnalyse.java index 0bfaefc04..035859eef 100644 --- a/src/main/java/com/zhgd/xmgl/async/AsyncAiAnalyse.java +++ b/src/main/java/com/zhgd/xmgl/async/AsyncAiAnalyse.java @@ -150,6 +150,7 @@ public class AsyncAiAnalyse { enableMessageDevRuleService.sendSms(messageDevRule, templateParams, text, null); } enableMessageDevRuleService.sendSystemMessage(messageDevRule, "8"); + enableMessageDevRuleService.sendBroadcast(messageDevRule); }, threadPoolTaskExecutor); } diff --git a/src/main/java/com/zhgd/xmgl/call/ShiZiWangBroadcastCall.java b/src/main/java/com/zhgd/xmgl/call/ShiZiWangBroadcastCall.java new file mode 100644 index 000000000..7bbb387b8 --- /dev/null +++ b/src/main/java/com/zhgd/xmgl/call/ShiZiWangBroadcastCall.java @@ -0,0 +1,47 @@ +package com.zhgd.xmgl.call; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.io.FileUtil; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSONObject; +import com.zhgd.xmgl.call.api.BroadcastManufacturer; +import com.zhgd.xmgl.modules.broadcast.entity.SmartBroadcastConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class ShiZiWangBroadcastCall implements BroadcastManufacturer { + private SmartBroadcastConfig config; + + @Override + public SmartBroadcastConfig getConfig() { + return config; + } + + @Override + public void setConfig(SmartBroadcastConfig config) { + this.config = config; + } + + @Override + public void playVoiceFile(List devSns, String fileName, String filePath) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("SerialNums", devSns); + jsonObject.put("PlayText", fileName); + jsonObject.put("PlayFileContent", Base64.encode(FileUtil.readBytes(filePath))); + String body = jsonObject.toJSONString(); + String url = "https://norsos.lionking110.com/sos/v1/mntn/adap/business/external/group/play"; + log.info("狮子王播放语音文件url:{},body:{}", url, body); + String result = HttpRequest.post(url) + .body(body) + .timeout(20000) + .execute().body(); + log.info("狮子王播放语音文件结果:{}", result); + } +} diff --git a/src/main/java/com/zhgd/xmgl/call/api/BroadcastManufacturer.java b/src/main/java/com/zhgd/xmgl/call/api/BroadcastManufacturer.java new file mode 100644 index 000000000..74d0ecf12 --- /dev/null +++ b/src/main/java/com/zhgd/xmgl/call/api/BroadcastManufacturer.java @@ -0,0 +1,22 @@ +package com.zhgd.xmgl.call.api; + +import com.zhgd.xmgl.modules.broadcast.entity.SmartBroadcastConfig; + +import java.util.List; + +public interface BroadcastManufacturer { + + SmartBroadcastConfig getConfig(); + + void setConfig(SmartBroadcastConfig config); + + /** + * 播放语音文件 + * + * @param devSns 设备snList + * @param fileName 文件名称 + * @param filePath 文件路径 + * @return + */ + void playVoiceFile(List devSns, String fileName, String filePath); +} diff --git a/src/main/java/com/zhgd/xmgl/call/factory/BroadcastManufacturerFactory.java b/src/main/java/com/zhgd/xmgl/call/factory/BroadcastManufacturerFactory.java new file mode 100644 index 000000000..f670a7b73 --- /dev/null +++ b/src/main/java/com/zhgd/xmgl/call/factory/BroadcastManufacturerFactory.java @@ -0,0 +1,33 @@ +package com.zhgd.xmgl.call.factory; + +import com.zhgd.jeecg.common.util.SpringContextUtils; +import com.zhgd.xmgl.call.ShiZiWangBroadcastCall; +import com.zhgd.xmgl.call.api.BroadcastManufacturer; +import com.zhgd.xmgl.modules.broadcast.entity.SmartBroadcastConfig; +import com.zhgd.xmgl.modules.broadcast.service.ISmartBroadcastConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Objects; + +@Component +public class BroadcastManufacturerFactory { + @Lazy + @Autowired + private ISmartBroadcastConfigService smartBroadcastConfigService; + + public BroadcastManufacturer getManufacturer(HashMap param) { + SmartBroadcastConfig config = smartBroadcastConfigService.getUseConfig(param); + if (config == null) { + return null; + } + BroadcastManufacturer manufacturer = null; + if (Objects.equals(config.getManufacturerType(), 1)) { + manufacturer = SpringContextUtils.getBean(ShiZiWangBroadcastCall.class); + manufacturer.setConfig(config); + } + return manufacturer; + } +} diff --git a/src/main/java/com/zhgd/xmgl/modules/environment/service/impl/EnvironmentAlarmServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/environment/service/impl/EnvironmentAlarmServiceImpl.java index 48f5584d4..98134c228 100644 --- a/src/main/java/com/zhgd/xmgl/modules/environment/service/impl/EnvironmentAlarmServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/environment/service/impl/EnvironmentAlarmServiceImpl.java @@ -842,6 +842,7 @@ public class EnvironmentAlarmServiceImpl extends ServiceImpl() + .put("projectSn", rule.getProjectSn()) + .build()); + manufacturer.playVoiceFile(StrUtil.split(rule.getBroadcastDevices(), ","), FileUtils.urlToFileName(rule.getVoiceFileConfiguration()), FileUtils.urlToFilePath(rule.getVoiceFileConfiguration())); + } + } + } diff --git a/src/main/java/com/zhgd/xmgl/modules/risk/controller/RiskListSourceDataCenterController.java b/src/main/java/com/zhgd/xmgl/modules/risk/controller/RiskListSourceDataCenterController.java index cd46731fd..19f389e58 100644 --- a/src/main/java/com/zhgd/xmgl/modules/risk/controller/RiskListSourceDataCenterController.java +++ b/src/main/java/com/zhgd/xmgl/modules/risk/controller/RiskListSourceDataCenterController.java @@ -336,35 +336,6 @@ public class RiskListSourceDataCenterController { && DateUtil.compare(bo.getDate(), time) >= 0; } - /** - * 获取已排查的数量List - * - * @param sourceVos - * @return - */ - private List getSourceCheckNumBo(List sourceVos) { - List sourceIds = sourceVos.stream().map(RiskListSourceVo::getId).collect(Collectors.toList()); - List securityList = xzSecurityQualityInspectionRecordService.list(new LambdaQueryWrapper() - .eq(XzSecurityQualityInspectionRecord::getType, 10) - .in(XzSecurityQualityInspectionRecord::getEngineeringId, sourceIds) - ); - List unbuilts = riskListSourceUnbuiltService.list(new LambdaQueryWrapper() - .in(RiskListSourceUnbuilt::getSourceId, sourceIds)); - List collect = securityList.stream().map(o -> { - SourceCheckNumBo bo = new SourceCheckNumBo(); - bo.setSourceId(o.getEngineeringId()); - bo.setDate(DateUtil.parseDate(o.getInspectTime())); - return bo; - }).collect(Collectors.toList()); - collect.addAll(unbuilts.stream().map(o -> { - SourceCheckNumBo bo = new SourceCheckNumBo(); - bo.setSourceId(o.getSourceId()); - bo.setDate(o.getInspectionTime()); - return bo; - }).collect(Collectors.toList())); - return collect; - } - @ApiOperation(value = "风险类别占比图", notes = "风险类别占比图", httpMethod = "GET") @ApiImplicitParams({ @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "query", required = true, dataType = "Integer"), diff --git a/src/main/java/com/zhgd/xmgl/modules/video/controller/VideoItemController.java b/src/main/java/com/zhgd/xmgl/modules/video/controller/VideoItemController.java index fb862af99..5ccdc51cc 100644 --- a/src/main/java/com/zhgd/xmgl/modules/video/controller/VideoItemController.java +++ b/src/main/java/com/zhgd/xmgl/modules/video/controller/VideoItemController.java @@ -1,16 +1,28 @@ package com.zhgd.xmgl.modules.video.controller; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.zhgd.annotation.OperLog; import com.zhgd.jeecg.common.api.vo.Result; +import com.zhgd.jeecg.common.execption.OpenAlertException; import com.zhgd.jeecg.common.mybatis.EntityMap; import com.zhgd.xmgl.async.AsyncProject; +import com.zhgd.xmgl.modules.project.entity.ProjectVideoConfig; +import com.zhgd.xmgl.modules.project.service.IProjectVideoConfigService; +import com.zhgd.xmgl.modules.video.entity.VideoGroup; import com.zhgd.xmgl.modules.video.entity.VideoItem; +import com.zhgd.xmgl.modules.video.entity.dto.MoveGroupVideoItemDto; import com.zhgd.xmgl.modules.video.entity.vo.CaptureVo; import com.zhgd.xmgl.modules.video.entity.vo.HistoryCaptureVo; import com.zhgd.xmgl.modules.video.entity.vo.TalkURLsV2Vo; +import com.zhgd.xmgl.modules.video.service.IVideoGroupService; import com.zhgd.xmgl.modules.video.service.IVideoItemService; import com.zhgd.xmgl.modules.xz.entity.vo.CountStatusVo; +import com.zhgd.xmgl.util.ExcelUtils; +import com.zhgd.xmgl.util.MessageUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -19,12 +31,16 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.MapUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import springfox.documentation.annotations.ApiIgnore; -import java.util.List; -import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import java.util.*; import java.util.concurrent.ExecutionException; +import java.util.function.Function; +import java.util.stream.Collectors; /** @@ -44,6 +60,12 @@ public class VideoItemController { private IVideoItemService videoItemService; @Autowired private AsyncProject asyncProject; + @Lazy + @Autowired + private IVideoGroupService videoGroupService; + @Lazy + @Autowired + private IProjectVideoConfigService projectVideoConfigService; /** * 添加 @@ -99,7 +121,6 @@ public class VideoItemController { return Result.ok(); } - @OperLog(operModul = "视频管理", operType = "修改视频设备地图坐标", operDesc = "修改视频设备地图坐标") @ApiOperation(value = "修改视频设备地图坐标", notes = "修改视频设备地图坐标", httpMethod = "POST") @PostMapping(value = "/updateVideoItemCoordinate") @@ -288,7 +309,6 @@ public class VideoItemController { return Result.success(videoItemService.selectUserVideoList(map)); } - @ApiOperation(value = "按照摄像头类型查询具有AI功能的摄像头数量", notes = "按照摄像头类型查询具有AI功能的摄像头数量") @ApiImplicitParams({ @ApiImplicitParam(name = "projectSn", value = "项目SN", paramType = "body", required = true, dataType = "String"), @@ -367,7 +387,6 @@ public class VideoItemController { return Result.success(videoItemService.callPostPlaybackUrlsV2(map)); } - @ApiOperation(value = "统计监控点在线率", notes = "统计监控点在线率", httpMethod = "POST") @ApiImplicitParams({ @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "body", required = true, dataType = "String"), @@ -402,7 +421,6 @@ public class VideoItemController { return Result.success(videoItemService.searchCameraFromHk(param)); } - @ApiOperation(value = "根据视频设备监控点编号抓拍图片", notes = "根据视频设备监控点编号抓拍图片", httpMethod = "POST") @ApiImplicitParams({ @ApiImplicitParam(name = "projectSn", value = "项目SN", paramType = "body", required = false, dataType = "String"), @@ -484,6 +502,128 @@ public class VideoItemController { return Result.ok(); } + @OperLog(operModul = "视频管理", operType = "批量删除", operDesc = "批量删除视频设备") + @ApiOperation(value = "批量删除视频设备", notes = "批量删除视频设备", httpMethod = "POST") + @ApiImplicitParam(name = "itemIds", value = "视频设备itemIds(多个,分隔)", paramType = "body", required = true, dataType = "String") + @PostMapping(value = "/deleteBatch") + public Result deleteBatch(@ApiIgnore @RequestBody Map map) { + Result result = new Result<>(); + String ids = MapUtils.getString(map, "itemIds"); + if (ids == null || "".equals(ids.trim())) { + result.error500("参数不识别!"); + } else { + videoItemService.removeByIds(Arrays.asList(ids.split(","))); + Result.success("删除成功!"); + } + return result; + } + @OperLog(operModul = "视频管理", operType = "移动视频设备", operDesc = "移动视频设备") + @ApiOperation(value = "移动视频设备", notes = "移动视频设备", httpMethod = "POST") + @PostMapping(value = "/moveGroup") + @Transactional(rollbackFor = Exception.class) + public Result moveGroup(@RequestBody MoveGroupVideoItemDto dto) { + List itemIds = dto.getItemIds(); + VideoGroup videoGroup = videoGroupService.getById(dto.getVideoGroupId()); + if (videoGroup == null) { + throw new OpenAlertException("视频分组不存在"); + } + videoItemService.update(null, new LambdaUpdateWrapper() + .set(VideoItem::getGroupId, dto.getVideoGroupId()) + .set(VideoItem::getParentObj, JSON.toJSONString(videoGroup)) + .in(VideoItem::getItemId, itemIds) + ); + return Result.ok(); + } + @ApiOperation(value = "导入模板下载", notes = "导入模板下载") + @ApiImplicitParams({ + @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "query", required = true, dataType = "String"), + @ApiImplicitParam(name = "videoType", value = "视频类型,1:萤石云,3:ISC,4:ICC", paramType = "body", required = true, dataType = "String"), + }) + @GetMapping("/downloadExcelTemplate") + public void downloadExcelTemplate(HttpServletResponse response, @RequestParam HashMap param) { + String projectSn = MapUtils.getString(param, "projectSn"); + Integer videoType = MapUtils.getInteger(param, "videoType"); + List groupNames = videoGroupService.list(new LambdaQueryWrapper() + .eq(VideoGroup::getProjectSn, projectSn)).stream().map(VideoGroup::getGroupName).collect(Collectors.toList()); + List pullDowns = Arrays.asList(new ExcelUtils.ExportExcelTemplatePullDown("视频分组", 0, groupNames)); + String downLoadFileName = null; + if (Objects.equals(videoType, 1)) { + downLoadFileName = "监控点导入模版(萤石云).xlsx"; + } else if (Objects.equals(videoType, 3)) { + downLoadFileName = "监控点导入模版(isc).xlsx"; + } else if (Objects.equals(videoType, 4)) { + downLoadFileName = "监控点导入模版(大华).xlsx"; + } + ExcelUtils.exportExcelTemplate("excel/videoitem/" + downLoadFileName, downLoadFileName, pullDowns, response); + } + + @ApiOperation(value = "导入excel", notes = "导入excel") + @ApiImplicitParams({ + @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "body", required = true, dataType = "String"), + @ApiImplicitParam(name = "excelFile", value = "导入文件", paramType = "body", required = true, dataType = "String"), + @ApiImplicitParam(name = "videoType", value = "视频类型,1:萤石云,3:ISC,4:ICC", paramType = "body", required = true, dataType = "String"), + }) + @PostMapping(value = "/importExcel") + @Transactional(rollbackFor = Exception.class) + public Result importExcel(MultipartFile excelFile, @RequestBody HashMap param) { + try { + String projectSn = MapUtils.getString(param, "projectSn"); + Integer videoType = MapUtils.getInteger(param, "videoType"); + List> list = ExcelUtils.jxlExlToList(excelFile.getInputStream(), 0); + if (list == null || list.size() == 0) { + throw new OpenAlertException(MessageUtil.get("excelNotDataErr")); + } + Map groupMap = videoGroupService.list(new LambdaQueryWrapper() + .eq(VideoGroup::getProjectSn, projectSn)).stream().collect(Collectors.toMap(VideoGroup::getGroupName, Function.identity(), (o1, o2) -> o1)); + ProjectVideoConfig videoConfig = projectVideoConfigService.getOne(new LambdaQueryWrapper() + .eq(ProjectVideoConfig::getProjectSn, projectSn) + .eq(ProjectVideoConfig::getVideoType, videoType) + ); + if (videoConfig == null) { + throw new OpenAlertException("请先启用该视频类型"); + } + List videoItems = new ArrayList<>(); + List sucList = new ArrayList<>(); + List failVideoList = new ArrayList<>(); + List failGroupList = new ArrayList<>(); + for (Map importInfo : list) { + VideoGroup group = groupMap.get(importInfo.get("*视频分组")); + String videoName = importInfo.get("*设备名称"); + String serialNumber = importInfo.get("*监控点"); + String deviceType = importInfo.get("设备类型"); + String verificationCode = importInfo.get("*通道号"); + String aiVideoUrl = importInfo.get("AI分析视频地址"); + String mrql = importInfo.get("默认取流"); + Integer defaultStreamType = null; + if (StrUtil.isNotBlank(mrql)) { + defaultStreamType = Objects.equals(mrql, "子码流") ? 1 : 2; + } + Integer aiFunctionType = Objects.equals(importInfo.get("是否具有AI识别功能"), "是") ? 1 : 0; + if (group == null) { + failGroupList.add(videoName); + continue; + } + VideoItem videoItem = new VideoItem(); + videoItem.setVideoId(videoConfig.getId()); + videoItem.setVideoName(videoName); + videoItem.setSerialNumber(serialNumber); + videoItem.setVerificationCode(verificationCode); + videoItem.setDeviceType(videoItemService.getDeviceType(deviceType)); + videoItem.setCreateTime(new Date()); + videoItem.setDeviceState(2); + videoItem.setGroupId(group.getId()); + videoItem.setAiFunctionType(aiFunctionType); + videoItem.setParentObj(JSON.toJSONString(group)); + videoItem.setAiVideoUrl(aiVideoUrl); + videoItem.setDefaultStreamType(defaultStreamType); + videoItems.add(videoItem); + } + videoItemService.saveBatch(videoItems); + return Result.ok(StrUtil.format("导入完成。导入成功:你好,阿爸{};导入失败:嘉兴、囧扥就(),军方,周邓个(){}")); + } catch (Exception e) { + throw new OpenAlertException("导入excel失败", e); + } + } } diff --git a/src/main/java/com/zhgd/xmgl/modules/video/entity/VideoItem.java b/src/main/java/com/zhgd/xmgl/modules/video/entity/VideoItem.java index 5dcf7bc1e..11b916bd4 100644 --- a/src/main/java/com/zhgd/xmgl/modules/video/entity/VideoItem.java +++ b/src/main/java/com/zhgd/xmgl/modules/video/entity/VideoItem.java @@ -166,6 +166,12 @@ public class VideoItem implements Serializable { */ @ApiModelProperty(value = "默认码流类型:1、子码流,2、主码流,默认子码流") private Integer defaultStreamType; + /** + * 智能广播设备devSns(多个,分隔) + */ + @ApiModelProperty(value = "智能广播设备devSns(多个,分隔)") + private String broadcastDevs; + /** * 项目sn */ diff --git a/src/main/java/com/zhgd/xmgl/modules/video/entity/dto/MoveGroupVideoItemDto.java b/src/main/java/com/zhgd/xmgl/modules/video/entity/dto/MoveGroupVideoItemDto.java new file mode 100644 index 000000000..eb046949a --- /dev/null +++ b/src/main/java/com/zhgd/xmgl/modules/video/entity/dto/MoveGroupVideoItemDto.java @@ -0,0 +1,14 @@ +package com.zhgd.xmgl.modules.video.entity.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class MoveGroupVideoItemDto { + @ApiModelProperty("视频设备idList") + private List itemIds; + @ApiModelProperty("视频分组id") + private Long videoGroupId; +} diff --git a/src/main/java/com/zhgd/xmgl/modules/video/mapper/xml/VideoItemMapper.xml b/src/main/java/com/zhgd/xmgl/modules/video/mapper/xml/VideoItemMapper.xml index d80e54833..90c56e454 100644 --- a/src/main/java/com/zhgd/xmgl/modules/video/mapper/xml/VideoItemMapper.xml +++ b/src/main/java/com/zhgd/xmgl/modules/video/mapper/xml/VideoItemMapper.xml @@ -25,6 +25,9 @@ and vi.group_id = #{groupId} + + and vi.video_name = #{videoName} + and vi.item_id in diff --git a/src/main/java/com/zhgd/xmgl/modules/video/service/IVideoItemService.java b/src/main/java/com/zhgd/xmgl/modules/video/service/IVideoItemService.java index f4de674f3..76f739f49 100644 --- a/src/main/java/com/zhgd/xmgl/modules/video/service/IVideoItemService.java +++ b/src/main/java/com/zhgd/xmgl/modules/video/service/IVideoItemService.java @@ -23,6 +23,14 @@ import java.util.concurrent.ExecutionException; * @version: V1.0 */ public interface IVideoItemService extends IService { + /** + * 根据设备类型文字获取对应的数字编码 + * + * @param deviceName 设备类型名称 + * @return 对应的数字编码 + */ + Integer getDeviceType(String deviceName); + /** * 添加视频设备列表信息 * diff --git a/src/main/java/com/zhgd/xmgl/modules/video/service/impl/VideoItemServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/video/service/impl/VideoItemServiceImpl.java index 0436946b7..f314fca9d 100644 --- a/src/main/java/com/zhgd/xmgl/modules/video/service/impl/VideoItemServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/video/service/impl/VideoItemServiceImpl.java @@ -1,5 +1,6 @@ package com.zhgd.xmgl.modules.video.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; @@ -189,7 +190,7 @@ public class VideoItemServiceImpl extends ServiceImpl integerMap = getTotalAndOnlineNum(jsonObject); + jsonObject.putAll(integerMap); + } + } data.put("type", 2); return data; } + /** + * 递归统计所有下级有serialNumber的节点数量 + * 并设置总数和在线视频监控数量 + * + * @param jsonObject JSON对象 + * @return 包含totalNum和onlineNum的Map + */ + private static Map getTotalAndOnlineNum(JSONObject jsonObject) { + Map result = new HashMap<>(); + int totalNum = 0; + int onlineNum = 0; + // 检查当前节点是否有serialNumber(算作一个设备) + if (jsonObject.containsKey("videoName")) { + totalNum = 1; + // 假设在线状态字段为"online"或"status" + if (Objects.equals(jsonObject.getInteger("deviceState"), 1)) { + onlineNum = 1; + } + } + // 递归处理子节点 + JSONArray children = jsonObject.getJSONArray("children"); + if (CollUtil.isNotEmpty(children)) { + for (int i = 0; i < children.size(); i++) { + JSONObject child = children.getJSONObject(i); + Map childStats = getTotalAndOnlineNum(child); + // 累加子节点的统计结果 + totalNum += childStats.getOrDefault("totalNum", 0); + onlineNum += childStats.getOrDefault("onlineNum", 0); + child.putAll(childStats); + } + } + result.put("totalNum", totalNum); + result.put("onlineNum", onlineNum); + return result; + } + + @Override public List selecAllVideoList(Map map) { return videoItemMapper.selectProjectVideoList(map); @@ -1131,4 +1177,27 @@ public class VideoItemServiceImpl extends ServiceImpl> + * + * @param is + * @param index + * @return + * @throws Exception + */ public static List> jxlExlToList(InputStream is, int index) throws Exception { Workbook book = null; List> list = null; @@ -993,4 +1003,50 @@ public class ExcelUtils { // } //} + /** + * 导出excel模板 + * + * @param templatePath classPath文件路径 + * @param downLoadFileName 下载名称 + * @param pullDowns 下拉 + * @param response + */ + public static void exportExcelTemplate(String templatePath, String downLoadFileName, List pullDowns, HttpServletResponse response) { + try { + ClassPathResource classPathResource = new ClassPathResource(templatePath); + InputStream inputStream = classPathResource.getInputStream(); + XSSFWorkbook workbook = new XSSFWorkbook(inputStream); + //下拉列 + if (CollUtil.isNotEmpty(pullDowns)) { + for (ExportExcelTemplatePullDown pullDown : pullDowns) { + XSSFSheet sheet = workbook.getSheet(pullDown.getSheetName()); + for (int i = 0; i < pullDown.getContents().size(); i++) { + XSSFRow row = sheet.createRow(i); + XSSFCell cell = row.createCell(pullDown.getColumnIndex()); + cell.setCellType(CellType.STRING); + cell.setCellValue(pullDown.getContents().get(i)); + } + } + } + downLoadExcel(downLoadFileName, response, workbook); + } catch (IOException e) { + log.error("exportExcelTemplate:", e); + } + } + + @Data + public static class ExportExcelTemplatePullDown { + private String sheetName; + private Integer columnIndex; + private List contents; + + public ExportExcelTemplatePullDown(String sheetName, Integer columnIndex, List contents) { + this.contents = contents; + this.columnIndex = columnIndex; + this.sheetName = sheetName; + } + + public ExportExcelTemplatePullDown() { + } + } } diff --git a/src/main/java/com/zhgd/xmgl/util/FileUtils.java b/src/main/java/com/zhgd/xmgl/util/FileUtils.java index d75f8ef24..7d2b80915 100644 --- a/src/main/java/com/zhgd/xmgl/util/FileUtils.java +++ b/src/main/java/com/zhgd/xmgl/util/FileUtils.java @@ -174,11 +174,33 @@ public class FileUtils { return PathUtil.getBasePath() + "/" + fileUrl1; } + /** + * url(如:xxx*xxxx,xxx*xxxx,[],xxx.jpg等等)转换成本地文件名称 + * + * @param fileUrl + * @return + */ + public static String urlToFileName(String fileUrl) { + List fileObjs = parseUrlString(fileUrl); + if (CollUtil.isEmpty(fileObjs)) { + return null; + } + String fileName = fileObjs.get(0).getFileName(); + if (StrUtil.isNotBlank(fileName)) { + return fileName; + } + String fileUrl1 = fileObjs.get(0).getFileUrl(); + if (fileUrl1.contains("http") || fileUrl1.contains("https")) { + fileUrl1 = StringUtils.substringAfter(fileUrl1, "/image/"); + } + return new File(PathUtil.getBasePath() + "/" + fileUrl1).getName(); + } + public static void main(String[] args) { - System.out.println(urlToFilePath("图片2.png*http://jxj.zhgdyun.com:21000/image/68afb689e6ca0a85c0ef03dd.png")); - System.out.println(urlToFilePath("68afb8b6e6ca0a85c0ef03de.png*68afb8b6e6ca0a85c0ef03de.png")); - System.out.println(urlToFilePath("68afb8b6e6ca0a85c0ef03de.png")); - System.out.println(urlToFilePath("68afb8b6e6ca0a85c0ef03de.png,123.png")); + System.out.println(urlToFileName("图片2.png*http://jxj.zhgdyun.com:21000/image/0012710f3eac4542b30314130873ae6e1.png")); + System.out.println(urlToFileName("文件名称.png*0012710f3eac4542b30314130873ae6e.png")); + System.out.println(urlToFileName("0012710f3eac4542b30314130873ae6e1.png")); + System.out.println(urlToFileName("0012710f3eac4542b30314130873ae6e.png,123.png")); } @Data diff --git a/src/main/resources/excel/videoitem/监控点导入模版(isc).xlsx b/src/main/resources/excel/videoitem/监控点导入模版(isc).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..002d6b458bb554cd373291ddcfb2f3383b80d7a5 GIT binary patch literal 11309 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