Commit 7d888274150e9415ae0fc16e67fefd1cdb4a69cc
1 parent
c5ddf598
处理服务重启或设备重新上线时的订阅,优化通道导入重复的处理
Showing
14 changed files
with
234 additions
and
25 deletions
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
| ... | ... | @@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.conf; |
| 3 | 3 | import org.springframework.beans.factory.annotation.Autowired; |
| 4 | 4 | import org.springframework.context.annotation.Bean; |
| 5 | 5 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
| 6 | -import org.springframework.scheduling.support.CronTrigger; | |
| 7 | 6 | import org.springframework.stereotype.Component; |
| 8 | 7 | |
| 9 | 8 | import java.util.Map; |
| ... | ... | @@ -40,4 +39,8 @@ public class DynamicTask { |
| 40 | 39 | } |
| 41 | 40 | } |
| 42 | 41 | |
| 42 | + public boolean contains(String key) { | |
| 43 | + return futureMap.get(key) != null; | |
| 44 | + } | |
| 45 | + | |
| 43 | 46 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java
| 1 | 1 | package com.genersoft.iot.vmp.conf.runner; |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 4 | 3 | import com.genersoft.iot.vmp.conf.UserSetup; |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 5 | +import com.genersoft.iot.vmp.service.IDeviceService; | |
| 5 | 6 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 6 | 7 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -28,6 +29,9 @@ public class SipDeviceRunner implements CommandLineRunner { |
| 28 | 29 | @Autowired |
| 29 | 30 | private UserSetup userSetup; |
| 30 | 31 | |
| 32 | + @Autowired | |
| 33 | + private IDeviceService deviceService; | |
| 34 | + | |
| 31 | 35 | @Override |
| 32 | 36 | public void run(String... args) throws Exception { |
| 33 | 37 | // 读取redis没有心跳信息的则设置为离线,等收到下次心跳设置为在线 |
| ... | ... | @@ -36,9 +40,15 @@ public class SipDeviceRunner implements CommandLineRunner { |
| 36 | 40 | List<String> onlineForAll = redisCatchStorage.getOnlineForAll(); |
| 37 | 41 | for (String deviceId : onlineForAll) { |
| 38 | 42 | storager.online(deviceId); |
| 43 | + Device device = redisCatchStorage.getDevice(deviceId); | |
| 44 | + if (device != null && device.getSubscribeCycleForCatalog() > 0) { | |
| 45 | + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | |
| 46 | + deviceService.addCatalogSubscribe(device); | |
| 47 | + } | |
| 39 | 48 | } |
| 40 | 49 | // 重置cseq计数 |
| 41 | 50 | redisCatchStorage.resetAllCSEQ(); |
| 42 | - // TODO 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | |
| 51 | + | |
| 52 | + | |
| 43 | 53 | } |
| 44 | 54 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
| ... | ... | @@ -35,6 +35,9 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
| 35 | 35 | |
| 36 | 36 | @Autowired |
| 37 | 37 | private IVideoManagerStorager storager; |
| 38 | + | |
| 39 | + @Autowired | |
| 40 | + private IDeviceService deviceService; | |
| 38 | 41 | |
| 39 | 42 | @Autowired |
| 40 | 43 | private RedisUtil redis; |
| ... | ... | @@ -57,6 +60,7 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
| 57 | 60 | logger.debug("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom()); |
| 58 | 61 | } |
| 59 | 62 | Device device = event.getDevice(); |
| 63 | + if (device == null) return; | |
| 60 | 64 | String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetup.getServerId() + "_" + event.getDevice().getDeviceId(); |
| 61 | 65 | |
| 62 | 66 | switch (event.getFrom()) { |
| ... | ... | @@ -84,15 +88,18 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
| 84 | 88 | } |
| 85 | 89 | |
| 86 | 90 | device.setOnline(1); |
| 87 | - Device deviceInstore = storager.queryVideoDevice(device.getDeviceId()); | |
| 88 | - if (deviceInstore != null && deviceInstore.getOnline() == 0) { | |
| 91 | + Device deviceInStore = storager.queryVideoDevice(device.getDeviceId()); | |
| 92 | + if (deviceInStore != null && deviceInStore.getOnline() == 0) { | |
| 89 | 93 | List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(device.getDeviceId()); |
| 90 | 94 | eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON); |
| 91 | 95 | } |
| 92 | 96 | // 处理上线监听 |
| 93 | 97 | storager.updateDevice(device); |
| 94 | 98 | |
| 95 | - // TODO 上线添加订阅 | |
| 99 | + // 上线添加订阅 | |
| 100 | + if (device.getSubscribeCycleForCatalog() > 0) { | |
| 101 | + deviceService.addCatalogSubscribe(device); | |
| 102 | + } | |
| 96 | 103 | |
| 97 | 104 | } |
| 98 | 105 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
| ... | ... | @@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory; |
| 18 | 18 | import org.springframework.beans.factory.annotation.Autowired; |
| 19 | 19 | import org.springframework.context.ApplicationListener; |
| 20 | 20 | import org.springframework.stereotype.Component; |
| 21 | +import org.springframework.util.StringUtils; | |
| 21 | 22 | |
| 22 | 23 | import java.util.*; |
| 23 | 24 | |
| ... | ... | @@ -76,12 +77,12 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 76 | 77 | }else if (event.getGbStreams() != null) { |
| 77 | 78 | if (platforms.size() > 0) { |
| 78 | 79 | for (GbStream gbStream : event.getGbStreams()) { |
| 80 | + if (gbStream == null || StringUtils.isEmpty(gbStream.getGbId())) continue; | |
| 79 | 81 | List<ParentPlatform> parentPlatformsForGB = storager.queryPlatFormListForStreamWithGBId(gbStream.getApp(),gbStream.getStream(), platforms); |
| 80 | 82 | parentPlatformMap.put(gbStream.getGbId(), parentPlatformsForGB); |
| 81 | 83 | } |
| 82 | 84 | } |
| 83 | 85 | } |
| 84 | - | |
| 85 | 86 | } |
| 86 | 87 | switch (event.getType()) { |
| 87 | 88 | case CatalogEvent.ON: | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
| ... | ... | @@ -41,6 +41,8 @@ public class DeferredResultHolder { |
| 41 | 41 | |
| 42 | 42 | public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; |
| 43 | 43 | |
| 44 | + public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; | |
| 45 | + | |
| 44 | 46 | public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION"; |
| 45 | 47 | |
| 46 | 48 | public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
| ... | ... | @@ -80,17 +80,14 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 80 | 80 | Element rootElement = getRootElement(evt); |
| 81 | 81 | String cmd = XmlUtil.getText(rootElement, "CmdType"); |
| 82 | 82 | if (CmdType.MOBILE_POSITION.equals(cmd)) { |
| 83 | - logger.info("接收到MobilePosition订阅"); | |
| 84 | 83 | processNotifyMobilePosition(evt, rootElement); |
| 85 | 84 | // } else if (CmdType.ALARM.equals(cmd)) { |
| 86 | 85 | // logger.info("接收到Alarm订阅"); |
| 87 | 86 | // processNotifyAlarm(evt, rootElement); |
| 88 | 87 | } else if (CmdType.CATALOG.equals(cmd)) { |
| 89 | - logger.info("接收到Catalog订阅"); | |
| 90 | 88 | processNotifyCatalogList(evt, rootElement); |
| 91 | 89 | } else { |
| 92 | 90 | logger.info("接收到消息:" + cmd); |
| 93 | -// responseAck(evt, Response.OK); | |
| 94 | 91 | |
| 95 | 92 | Response response = null; |
| 96 | 93 | response = getMessageFactory().createResponse(200, request); |
| ... | ... | @@ -132,7 +129,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 132 | 129 | SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId); |
| 133 | 130 | String sn = XmlUtil.getText(rootElement, "SN"); |
| 134 | 131 | String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_MobilePosition_" + platformId; |
| 135 | - | |
| 132 | + logger.info("接收到{}的MobilePosition订阅", platformId); | |
| 136 | 133 | StringBuilder resultXml = new StringBuilder(200); |
| 137 | 134 | resultXml.append("<?xml version=\"1.0\" ?>\r\n") |
| 138 | 135 | .append("<Response>\r\n") |
| ... | ... | @@ -182,7 +179,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 182 | 179 | SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId); |
| 183 | 180 | String sn = XmlUtil.getText(rootElement, "SN"); |
| 184 | 181 | String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platformId; |
| 185 | - | |
| 182 | + logger.info("接收到{}的Catalog订阅", platformId); | |
| 186 | 183 | StringBuilder resultXml = new StringBuilder(200); |
| 187 | 184 | resultXml.append("<?xml version=\"1.0\" ?>\r\n") |
| 188 | 185 | .append("<Response>\r\n") | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| ... | ... | @@ -30,11 +30,15 @@ public class DeviceServiceImpl implements IDeviceService { |
| 30 | 30 | if (device == null || device.getSubscribeCycleForCatalog() < 0) { |
| 31 | 31 | return false; |
| 32 | 32 | } |
| 33 | + if (dynamicTask.contains(device.getDeviceId())) { | |
| 34 | + logger.info("[添加目录订阅] 设备{}的目录订阅以存在", device.getDeviceId()); | |
| 35 | + return false; | |
| 36 | + } | |
| 37 | + logger.info("[添加目录订阅] 设备{}", device.getDeviceId()); | |
| 33 | 38 | // 添加目录订阅 |
| 34 | 39 | CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander); |
| 35 | 40 | catalogSubscribeTask.run(); |
| 36 | 41 | // 提前开始刷新订阅 |
| 37 | - // TODO 使用jain sip的当时刷新订阅 | |
| 38 | 42 | int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); |
| 39 | 43 | // 设置最小值为30 |
| 40 | 44 | subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
| ... | ... | @@ -14,15 +14,23 @@ import java.util.Set; |
| 14 | 14 | |
| 15 | 15 | public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPushExcelDto> { |
| 16 | 16 | |
| 17 | + private ErrorDataHandler errorDataHandler; | |
| 17 | 18 | private IStreamPushService pushService; |
| 18 | 19 | private String defaultMediaServerId; |
| 19 | 20 | private List<StreamPushItem> streamPushItems = new ArrayList<>(); |
| 20 | 21 | private Set<String> streamPushStreamSet = new HashSet<>(); |
| 21 | 22 | private Set<String> streamPushGBSet = new HashSet<>(); |
| 23 | + private List<String> errorStreamList = new ArrayList<>(); | |
| 24 | + private List<String> errorGBList = new ArrayList<>(); | |
| 22 | 25 | |
| 23 | - public StreamPushUploadFileHandler(IStreamPushService pushService, String defaultMediaServerId) { | |
| 26 | + public StreamPushUploadFileHandler(IStreamPushService pushService, String defaultMediaServerId, ErrorDataHandler errorDataHandler) { | |
| 24 | 27 | this.pushService = pushService; |
| 25 | 28 | this.defaultMediaServerId = defaultMediaServerId; |
| 29 | + this.errorDataHandler = errorDataHandler; | |
| 30 | + } | |
| 31 | + | |
| 32 | + public interface ErrorDataHandler{ | |
| 33 | + void handle(List<String> streams, List<String> gbId); | |
| 26 | 34 | } |
| 27 | 35 | |
| 28 | 36 | @Override |
| ... | ... | @@ -32,9 +40,16 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPus |
| 32 | 40 | || StringUtils.isEmpty(streamPushExcelDto.getGbId())) { |
| 33 | 41 | return; |
| 34 | 42 | } |
| 43 | + if (streamPushGBSet.contains(streamPushExcelDto.getGbId())) { | |
| 44 | + errorGBList.add(streamPushExcelDto.getGbId()); | |
| 45 | + } | |
| 46 | + if (streamPushStreamSet.contains(streamPushExcelDto.getApp() + streamPushExcelDto.getStream())) { | |
| 47 | + errorStreamList.add(streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream()); | |
| 48 | + } | |
| 35 | 49 | if (streamPushGBSet.contains(streamPushExcelDto.getGbId()) || streamPushStreamSet.contains(streamPushExcelDto.getApp() + streamPushExcelDto.getStream())) { |
| 36 | 50 | return; |
| 37 | 51 | } |
| 52 | + | |
| 38 | 53 | StreamPushItem streamPushItem = new StreamPushItem(); |
| 39 | 54 | streamPushItem.setApp(streamPushExcelDto.getApp()); |
| 40 | 55 | streamPushItem.setStream(streamPushExcelDto.getStream()); |
| ... | ... | @@ -60,8 +75,11 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPus |
| 60 | 75 | @Override |
| 61 | 76 | public void doAfterAllAnalysed(AnalysisContext analysisContext) { |
| 62 | 77 | // 这里也要保存数据,确保最后遗留的数据也存储到数据库 |
| 63 | - pushService.batchAdd(streamPushItems); | |
| 78 | + if (streamPushItems.size() > 0) { | |
| 79 | + pushService.batchAdd(streamPushItems); | |
| 80 | + } | |
| 64 | 81 | streamPushGBSet.clear(); |
| 65 | 82 | streamPushStreamSet.clear(); |
| 83 | + errorDataHandler.handle(errorStreamList, errorGBList); | |
| 66 | 84 | } |
| 67 | 85 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
| ... | ... | @@ -50,7 +50,7 @@ public interface StreamPushMapper { |
| 50 | 50 | StreamPushItem selectOne(String app, String stream); |
| 51 | 51 | |
| 52 | 52 | @Insert("<script>" + |
| 53 | - "INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " + | |
| 53 | + "REPLACE INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " + | |
| 54 | 54 | "createStamp, aliveSecond, mediaServerId) " + |
| 55 | 55 | "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" + |
| 56 | 56 | "( '${item.app}', '${item.stream}', '${item.totalReaderCount}', '${item.originType}', " + | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
| ... | ... | @@ -4,11 +4,14 @@ import com.alibaba.excel.EasyExcel; |
| 4 | 4 | import com.alibaba.excel.ExcelReader; |
| 5 | 5 | import com.alibaba.excel.read.metadata.ReadSheet; |
| 6 | 6 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 7 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | |
| 7 | 9 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 8 | 10 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 9 | 11 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| 10 | 12 | import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler; |
| 11 | 13 | import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto; |
| 14 | +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | |
| 12 | 15 | import com.github.pagehelper.PageInfo; |
| 13 | 16 | import io.swagger.annotations.Api; |
| 14 | 17 | import io.swagger.annotations.ApiImplicitParam; |
| ... | ... | @@ -18,12 +21,19 @@ import org.apache.poi.sl.usermodel.Sheet; |
| 18 | 21 | import org.slf4j.Logger; |
| 19 | 22 | import org.slf4j.LoggerFactory; |
| 20 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
| 24 | +import org.springframework.http.HttpStatus; | |
| 25 | +import org.springframework.http.ResponseEntity; | |
| 21 | 26 | import org.springframework.stereotype.Controller; |
| 22 | 27 | import org.springframework.web.bind.annotation.*; |
| 28 | +import org.springframework.web.context.request.async.DeferredResult; | |
| 23 | 29 | import org.springframework.web.multipart.MultipartFile; |
| 24 | 30 | |
| 25 | 31 | import java.io.IOException; |
| 26 | 32 | import java.io.InputStream; |
| 33 | +import java.util.HashMap; | |
| 34 | +import java.util.List; | |
| 35 | +import java.util.Map; | |
| 36 | +import java.util.UUID; | |
| 27 | 37 | |
| 28 | 38 | @Api(tags = "推流信息管理") |
| 29 | 39 | @Controller |
| ... | ... | @@ -39,6 +49,9 @@ public class StreamPushController { |
| 39 | 49 | @Autowired |
| 40 | 50 | private IMediaServerService mediaServerService; |
| 41 | 51 | |
| 52 | + @Autowired | |
| 53 | + private DeferredResultHolder resultHolder; | |
| 54 | + | |
| 42 | 55 | @ApiOperation("推流列表查询") |
| 43 | 56 | @ApiImplicitParams({ |
| 44 | 57 | @ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class), |
| ... | ... | @@ -103,10 +116,44 @@ public class StreamPushController { |
| 103 | 116 | } |
| 104 | 117 | @PostMapping(value = "upload") |
| 105 | 118 | @ResponseBody |
| 106 | - public String uploadChannelFile(@RequestParam(value = "file") MultipartFile file){ | |
| 119 | + public DeferredResult<ResponseEntity<WVPResult<Object>>> uploadChannelFile(@RequestParam(value = "file") MultipartFile file){ | |
| 120 | + | |
| 121 | + | |
| 122 | + // 最多处理文件一个小时 | |
| 123 | + DeferredResult<ResponseEntity<WVPResult<Object>>> result = new DeferredResult<>(60*60*1000L); | |
| 124 | + // 录像查询以channelId作为deviceId查询 | |
| 125 | + String key = DeferredResultHolder.UPLOAD_FILE_CHANNEL; | |
| 126 | + String uuid = UUID.randomUUID().toString(); | |
| 127 | + | |
| 107 | 128 | if (file.isEmpty()) { |
| 108 | - return "fail"; | |
| 129 | + logger.warn("通道导入文件为空"); | |
| 130 | + WVPResult<Object> wvpResult = new WVPResult<>(); | |
| 131 | + wvpResult.setCode(-1); | |
| 132 | + wvpResult.setMsg("文件为空"); | |
| 133 | + result.setResult(ResponseEntity.status(HttpStatus.BAD_REQUEST).body(wvpResult)); | |
| 134 | + return result; | |
| 109 | 135 | } |
| 136 | + // 同时只处理一个文件 | |
| 137 | + if (resultHolder.exist(key, null)) { | |
| 138 | + logger.warn("已有导入任务正在执行"); | |
| 139 | + WVPResult<Object> wvpResult = new WVPResult<>(); | |
| 140 | + wvpResult.setCode(-1); | |
| 141 | + wvpResult.setMsg("已有导入任务正在执行"); | |
| 142 | + result.setResult(ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(wvpResult)); | |
| 143 | + return result; | |
| 144 | + } | |
| 145 | + | |
| 146 | + resultHolder.put(key, uuid, result); | |
| 147 | + result.onTimeout(()->{ | |
| 148 | + logger.warn("通道导入超时,可能文件过大"); | |
| 149 | + RequestMessage msg = new RequestMessage(); | |
| 150 | + msg.setKey(key); | |
| 151 | + WVPResult<Object> wvpResult = new WVPResult<>(); | |
| 152 | + wvpResult.setCode(-1); | |
| 153 | + wvpResult.setMsg("导入超时,可能文件过大"); | |
| 154 | + msg.setData(wvpResult); | |
| 155 | + resultHolder.invokeAllResult(msg); | |
| 156 | + }); | |
| 110 | 157 | //获取文件流 |
| 111 | 158 | InputStream inputStream = null; |
| 112 | 159 | try { |
| ... | ... | @@ -117,11 +164,29 @@ public class StreamPushController { |
| 117 | 164 | } |
| 118 | 165 | //传入参数 |
| 119 | 166 | ExcelReader excelReader = EasyExcel.read(inputStream, StreamPushExcelDto.class, |
| 120 | - new StreamPushUploadFileHandler(streamPushService, mediaServerService.getDefaultMediaServer().getId())).build(); | |
| 167 | + new StreamPushUploadFileHandler(streamPushService, mediaServerService.getDefaultMediaServer().getId(), (errorStreams, errorGBs)->{ | |
| 168 | + logger.info("通道导入成功,存在重复App+Stream为{}个,存在国标ID为{}个", errorStreams.size(), errorGBs.size()); | |
| 169 | + RequestMessage msg = new RequestMessage(); | |
| 170 | + msg.setKey(key); | |
| 171 | + WVPResult<Map<String, List<String>>> wvpResult = new WVPResult<>(); | |
| 172 | + if (errorStreams.size() == 0 && errorGBs.size() == 0) { | |
| 173 | + wvpResult.setCode(0); | |
| 174 | + wvpResult.setMsg("成功"); | |
| 175 | + }else { | |
| 176 | + wvpResult.setCode(1); | |
| 177 | + wvpResult.setMsg("导入成功。但是存在重复数据"); | |
| 178 | + Map<String, List<String>> errorData = new HashMap<>(); | |
| 179 | + errorData.put("gbId", errorGBs); | |
| 180 | + errorData.put("stream", errorStreams); | |
| 181 | + wvpResult.setData(errorData); | |
| 182 | + } | |
| 183 | + msg.setData(wvpResult); | |
| 184 | + resultHolder.invokeAllResult(msg); | |
| 185 | + })).build(); | |
| 121 | 186 | ReadSheet readSheet = EasyExcel.readSheet(0).build(); |
| 122 | 187 | excelReader.read(readSheet); |
| 123 | 188 | excelReader.finish(); |
| 124 | - return "success"; | |
| 189 | + return result; | |
| 125 | 190 | } |
| 126 | 191 | |
| 127 | 192 | ... | ... |
web_src/src/components/PushVideoList.vue
web_src/src/components/dialog/importChannel.vue
| ... | ... | @@ -16,6 +16,8 @@ |
| 16 | 16 | drag |
| 17 | 17 | :action="uploadUrl" |
| 18 | 18 | name="file" |
| 19 | + :on-success="successHook" | |
| 20 | + :on-error="errorHook" | |
| 19 | 21 | > |
| 20 | 22 | <i class="el-icon-upload"></i> |
| 21 | 23 | <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> |
| ... | ... | @@ -23,14 +25,19 @@ |
| 23 | 25 | </el-upload> |
| 24 | 26 | </div> |
| 25 | 27 | </el-dialog> |
| 28 | + <ShowErrorData ref="showErrorData" :gbIds="errorGBIds" :streams="errorStreams" ></ShowErrorData> | |
| 26 | 29 | </div> |
| 27 | 30 | </template> |
| 28 | 31 | |
| 29 | 32 | <script> |
| 30 | 33 | |
| 34 | +import ShowErrorData from './importChannelShowErrorData.vue' | |
| 35 | + | |
| 31 | 36 | export default { |
| 32 | 37 | name: "importChannel", |
| 33 | - computed: {}, | |
| 38 | + components: { | |
| 39 | + ShowErrorData, | |
| 40 | + }, | |
| 34 | 41 | created() {}, |
| 35 | 42 | data() { |
| 36 | 43 | return { |
| ... | ... | @@ -38,6 +45,8 @@ export default { |
| 38 | 45 | showDialog: false, |
| 39 | 46 | isLoging: false, |
| 40 | 47 | isEdit: false, |
| 48 | + errorStreams: null, | |
| 49 | + errorGBIds: null, | |
| 41 | 50 | uploadUrl: process.env.NODE_ENV === 'development'?`debug/api/push/upload`:`api/push/upload`, |
| 42 | 51 | }; |
| 43 | 52 | }, |
| ... | ... | @@ -73,8 +82,35 @@ export default { |
| 73 | 82 | }, |
| 74 | 83 | close: function () { |
| 75 | 84 | this.showDialog = false; |
| 76 | - this.$refs.form.resetFields(); | |
| 77 | 85 | }, |
| 86 | + successHook: function(response, file, fileList){ | |
| 87 | + if (response.code === 0) { | |
| 88 | + this.$message({ | |
| 89 | + showClose: true, | |
| 90 | + message: response.msg, | |
| 91 | + type: "success", | |
| 92 | + }); | |
| 93 | + }else if (response.code === 1) { | |
| 94 | + this.errorGBIds = response.data.gbId | |
| 95 | + this.errorStreams = response.data.stream | |
| 96 | + console.log(this.$refs) | |
| 97 | + console.log(this.$refs.showErrorData) | |
| 98 | + this.$refs.showErrorData.openDialog() | |
| 99 | + }else { | |
| 100 | + this.$message({ | |
| 101 | + showClose: true, | |
| 102 | + message: response.msg, | |
| 103 | + type: "error", | |
| 104 | + }); | |
| 105 | + } | |
| 106 | + }, | |
| 107 | + errorHook: function (err, file, fileList) { | |
| 108 | + this.$message({ | |
| 109 | + showClose: true, | |
| 110 | + message: err, | |
| 111 | + type: "error", | |
| 112 | + }); | |
| 113 | + } | |
| 78 | 114 | }, |
| 79 | 115 | }; |
| 80 | 116 | </script> |
| ... | ... | @@ -82,4 +118,8 @@ export default { |
| 82 | 118 | .upload-box{ |
| 83 | 119 | text-align: center; |
| 84 | 120 | } |
| 121 | +.errDataBox{ | |
| 122 | + max-height: 15rem; | |
| 123 | + overflow: auto; | |
| 124 | +} | |
| 85 | 125 | </style> | ... | ... |
web_src/src/components/dialog/importChannelShowErrorData.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div id="importChannelShowErrorData" v-loading="isLoging"> | |
| 3 | + <el-dialog | |
| 4 | + title="导入通道数据成功,但数据存在重复" | |
| 5 | + width="30rem" | |
| 6 | + top="2rem" | |
| 7 | + :append-to-body="true" | |
| 8 | + :close-on-click-modal="false" | |
| 9 | + :visible.sync="showDialog" | |
| 10 | + :destroy-on-close="true" | |
| 11 | + @close="close()" | |
| 12 | + > | |
| 13 | + <div > | |
| 14 | + 重复国标ID: | |
| 15 | + <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="gbIds.join(',')" @success="$message({type:'success', message:'成功拷贝到粘贴板'})">复制</el-button> | |
| 16 | + <ul class="errDataBox"> | |
| 17 | + <li v-for="id in gbIds" > | |
| 18 | + {{ id }} | |
| 19 | + </li> | |
| 20 | + </ul> | |
| 21 | + </div> | |
| 22 | + | |
| 23 | + <div > | |
| 24 | + 重复App/stream: | |
| 25 | + <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="streams.join(',')" @success="$message({type:'success', message:'成功拷贝到粘贴板'})">复制</el-button> | |
| 26 | + <ul class="errDataBox"> | |
| 27 | + <li v-for="id in streams" > | |
| 28 | + {{ id }} | |
| 29 | + </li> | |
| 30 | + </ul> | |
| 31 | + </div> | |
| 32 | + </el-dialog> | |
| 33 | + </div> | |
| 34 | +</template> | |
| 35 | + | |
| 36 | +<script> | |
| 37 | + | |
| 38 | +export default { | |
| 39 | + name: "importChannelShowErrorData", | |
| 40 | + computed: {}, | |
| 41 | + created() {}, | |
| 42 | + props: ['gbIds', 'streams'], | |
| 43 | + data() { | |
| 44 | + return { | |
| 45 | + isLoging: false, | |
| 46 | + showDialog: false, | |
| 47 | + }; | |
| 48 | + }, | |
| 49 | + methods: { | |
| 50 | + openDialog: function () { | |
| 51 | + this.showDialog = true; | |
| 52 | + }, | |
| 53 | + close: function () { | |
| 54 | + this.showDialog = false; | |
| 55 | + }, | |
| 56 | + }, | |
| 57 | +}; | |
| 58 | +</script> | |
| 59 | +<style> | |
| 60 | +.errDataBox{ | |
| 61 | + max-height: 15rem; | |
| 62 | + overflow: auto; | |
| 63 | +} | |
| 64 | +</style> | ... | ... |
web_src/src/components/dialog/jessibuca.vue
| ... | ... | @@ -78,7 +78,7 @@ export default { |
| 78 | 78 | this.jessibuca = new window.Jessibuca(Object.assign( |
| 79 | 79 | { |
| 80 | 80 | container: this.$refs.container, |
| 81 | - videoBuffer: 0.5, // 最大缓冲时长,单位秒 | |
| 81 | + videoBuffer: 0.2, // 最大缓冲时长,单位秒 | |
| 82 | 82 | isResize: true, |
| 83 | 83 | isFlv: true, |
| 84 | 84 | decoder: "./static/js/jessibuca/index.js", | ... | ... |