Commit 7083f30fc4ffd7af893e612c9c8cb1bf612faa6c

Authored by liujun001
1 parent ca1719da

康宝

src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
... ... @@ -26,7 +26,9 @@ import io.swagger.v3.oas.annotations.Operation;
26 26 import io.swagger.v3.oas.annotations.Parameter;
27 27 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
28 28 import io.swagger.v3.oas.annotations.tags.Tag;
  29 +import org.apache.commons.collections4.CollectionUtils;
29 30 import org.apache.commons.compress.utils.IOUtils;
  31 +import org.apache.commons.lang3.StringUtils;
30 32 import org.apache.ibatis.annotations.Options;
31 33 import org.slf4j.Logger;
32 34 import org.slf4j.LoggerFactory;
... ... @@ -48,539 +50,568 @@ import java.io.InputStream;
48 50 import java.nio.file.Files;
49 51 import java.text.ParseException;
50 52 import java.util.*;
  53 +import java.util.stream.Collectors;
51 54  
52   -@Tag(name = "国标设备查询", description = "国标设备查询")
  55 +@Tag(name = "国标设备查询", description = "国标设备查询")
53 56 @SuppressWarnings("rawtypes")
54 57  
55 58 @RestController
56 59 @RequestMapping("/api/device/query")
57 60 public class DeviceQuery {
58   -
59   - private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class);
60   -
61   - @Autowired
62   - private IVideoManagerStorage storager;
63   -
64   - @Autowired
65   - private IDeviceChannelService deviceChannelService;
66   -
67   - @Autowired
68   - private IRedisCatchStorage redisCatchStorage;
69   -
70   - @Autowired
71   - private IInviteStreamService inviteStreamService;
72   -
73   - @Autowired
74   - private SIPCommander cmder;
75   -
76   - @Autowired
77   - private DeferredResultHolder resultHolder;
78   -
79   - @Autowired
80   - private IDeviceService deviceService;
81   -
82   - @Autowired
83   - private DynamicTask dynamicTask;
84   -
85   - /**
86   - * 使用ID查询国标设备
87   - * @param deviceId 国标ID
88   - * @return 国标设备
89   - */
90   - @Operation(summary = "查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER))
91   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
92   - @GetMapping("/devices/{deviceId}")
93   - public Device devices(@PathVariable String deviceId){
94   -
95   - return storager.queryVideoDevice(deviceId);
96   - }
97   -
98   - /**
99   - * 分页查询国标设备
100   - * @param page 当前页
101   - * @param count 每页查询数量
102   - * @return 分页国标列表
103   - */
104   - @Operation(summary = "分页查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER))
105   - @Parameter(name = "page", description = "当前页", required = true)
106   - @Parameter(name = "count", description = "每页查询数量", required = true)
107   - @GetMapping("/devices")
108   - @Options()
109   - public PageInfo<Device> devices(int page, int count){
  61 +
  62 + private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class);
  63 +
  64 + @Autowired
  65 + private IVideoManagerStorage storager;
  66 +
  67 + @Autowired
  68 + private IDeviceChannelService deviceChannelService;
  69 +
  70 + @Autowired
  71 + private IRedisCatchStorage redisCatchStorage;
  72 +
  73 + @Autowired
  74 + private IInviteStreamService inviteStreamService;
  75 +
  76 + @Autowired
  77 + private SIPCommander cmder;
  78 +
  79 + @Autowired
  80 + private DeferredResultHolder resultHolder;
  81 +
  82 + @Autowired
  83 + private IDeviceService deviceService;
  84 +
  85 + @Autowired
  86 + private DynamicTask dynamicTask;
  87 +
  88 + /**
  89 + * 使用ID查询国标设备
  90 + *
  91 + * @param deviceId 国标ID
  92 + * @return 国标设备
  93 + */
  94 + @Operation(summary = "查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER))
  95 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  96 + @GetMapping("/devices/{deviceId}")
  97 + public Device devices(@PathVariable String deviceId) {
  98 +
  99 + return storager.queryVideoDevice(deviceId);
  100 + }
  101 +
  102 + /**
  103 + * 分页查询国标设备
  104 + *
  105 + * @param page 当前页
  106 + * @param count 每页查询数量
  107 + * @return 分页国标列表
  108 + */
  109 + @Operation(summary = "分页查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER))
  110 + @Parameter(name = "page", description = "当前页", required = true)
  111 + @Parameter(name = "count", description = "每页查询数量", required = true)
  112 + @GetMapping("/devices")
  113 + @Options()
  114 + public PageInfo<Device> devices(int page, int count) {
110 115 // if (page == null) page = 0;
111 116 // if (count == null) count = 20;
112   - return storager.queryVideoDeviceList(page, count,null);
113   - }
114   -
115   - /**
116   - * 分页查询通道数
117   - *
118   - * @param deviceId 设备id
119   - * @param page 当前页
120   - * @param count 每页条数
121   - * @param query 查询内容
122   - * @param online 是否在线 在线 true / 离线 false
123   - * @param channelType 设备 false/子目录 true
124   - * @param catalogUnderDevice 是否直属与设备的目录
125   - * @return 通道列表
126   - */
127   - @GetMapping("/devices/{deviceId}/channels")
128   - @Operation(summary = "分页查询通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
129   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
130   - @Parameter(name = "page", description = "当前页", required = true)
131   - @Parameter(name = "count", description = "每页查询数量", required = true)
132   - @Parameter(name = "query", description = "查询内容")
133   - @Parameter(name = "online", description = "是否在线")
134   - @Parameter(name = "channelType", description = "设备/子目录-> false/true")
135   - @Parameter(name = "catalogUnderDevice", description = "是否直属与设备的目录")
136   - public PageInfo<DeviceChannel> channels(@PathVariable String deviceId,
137   - int page, int count,
138   - @RequestParam(required = false) String query,
139   - @RequestParam(required = false) Boolean online,
140   - @RequestParam(required = false) Boolean channelType,
141   - @RequestParam(required = false) Boolean catalogUnderDevice) {
142   - if (ObjectUtils.isEmpty(query)) {
143   - query = null;
144   - }
145   -
146   - return storager.queryChannelsByDeviceId(deviceId, query, channelType, online, catalogUnderDevice, page, count);
147   - }
148   -
149   - /**
150   - * 同步设备通道
151   - * @param deviceId 设备id
152   - * @return
153   - */
154   - @Operation(summary = "同步设备通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
155   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
156   - @GetMapping("/devices/{deviceId}/sync")
157   - public WVPResult<SyncStatus> devicesSync(@PathVariable String deviceId){
158   -
159   - if (logger.isDebugEnabled()) {
160   - logger.debug("设备通道信息同步API调用,deviceId:" + deviceId);
161   - }
162   - Device device = storager.queryVideoDevice(deviceId);
163   - boolean status = deviceService.isSyncRunning(deviceId);
164   - // 已存在则返回进度
165   - if (status) {
166   - SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId);
167   - return WVPResult.success(channelSyncStatus);
168   - }
169   - deviceService.sync(device);
170   -
171   - WVPResult<SyncStatus> wvpResult = new WVPResult<>();
172   - wvpResult.setCode(0);
173   - wvpResult.setMsg("开始同步");
174   - return wvpResult;
175   - }
176   -
177   - /**
178   - * 移除设备
179   - * @param deviceId 设备id
180   - * @return
181   - */
182   - @Operation(summary = "移除设备", security = @SecurityRequirement(name = JwtUtils.HEADER))
183   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
184   - @DeleteMapping("/devices/{deviceId}/delete")
185   - public String delete(@PathVariable String deviceId){
186   -
187   - if (logger.isDebugEnabled()) {
188   - logger.debug("设备信息删除API调用,deviceId:" + deviceId);
189   - }
190   -
191   - // 清除redis记录
192   - boolean isSuccess = deviceService.delete(deviceId);
193   - if (isSuccess) {
194   - inviteStreamService.clearInviteInfo(deviceId);
195   - // 停止此设备的订阅更新
196   - Set<String> allKeys = dynamicTask.getAllKeys();
197   - for (String key : allKeys) {
198   - if (key.startsWith(deviceId)) {
199   - Runnable runnable = dynamicTask.get(key);
200   - if (runnable instanceof ISubscribeTask) {
201   - ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
202   - subscribeTask.stop(null);
203   - }
204   - dynamicTask.stop(key);
205   - }
206   - }
207   - JSONObject json = new JSONObject();
208   - json.put("deviceId", deviceId);
209   - return json.toString();
210   - } else {
211   - logger.warn("设备信息删除API调用失败!");
212   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备信息删除API调用失败!");
213   - }
214   - }
215   -
216   - /**
217   - * 分页查询子目录通道
218   - * @param deviceId 通道id
219   - * @param channelId 通道id
220   - * @param page 当前页
221   - * @param count 每页条数
222   - * @param query 查询内容
223   - * @param online 是否在线
224   - * @param channelType 通道类型
225   - * @return 子通道列表
226   - */
227   - @Operation(summary = "分页查询子目录通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
228   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
229   - @Parameter(name = "channelId", description = "通道国标编号", required = true)
230   - @Parameter(name = "page", description = "当前页", required = true)
231   - @Parameter(name = "count", description = "每页查询数量", required = true)
232   - @Parameter(name = "query", description = "查询内容")
233   - @Parameter(name = "online", description = "是否在线")
234   - @Parameter(name = "channelType", description = "设备/子目录-> false/true")
235   - @GetMapping("/sub_channels/{deviceId}/{channelId}/channels")
236   - public PageInfo<DeviceChannel> subChannels(@PathVariable String deviceId,
237   - @PathVariable String channelId,
238   - int page,
239   - int count,
240   - @RequestParam(required = false) String query,
241   - @RequestParam(required = false) Boolean online,
242   - @RequestParam(required = false) Boolean channelType){
243   -
244   - DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId);
245   - if (deviceChannel == null) {
246   - PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>();
247   - return deviceChannelPageResult;
248   - }
249   -
250   - return storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
251   - }
252   -
253   - /**
254   - * 更新通道信息
255   - * @param deviceId 设备id
256   - * @param channel 通道
257   - * @return
258   - */
259   - @Operation(summary = "更新通道信息", security = @SecurityRequirement(name = JwtUtils.HEADER))
260   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
261   - @Parameter(name = "channel", description = "通道信息", required = true)
262   - @PostMapping("/channel/update/{deviceId}")
263   - public void updateChannel(@PathVariable String deviceId,DeviceChannel channel){
264   - deviceChannelService.updateChannel(deviceId, channel);
265   - }
266   -
267   - @Operation(summary = "修改通道的码流类型", security = @SecurityRequirement(name = JwtUtils.HEADER))
268   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
269   - @Parameter(name = "channel", description = "通道信息", required = true)
270   - @PostMapping("/channel/stream/identification/update/")
271   - public void updateChannelStreamIdentification(DeviceChannel channel){
272   - deviceChannelService.updateChannelStreamIdentification(channel);
273   - }
274   -
275   - /**
276   - * 修改数据流传输模式
277   - * @param deviceId 设备id
278   - * @param streamMode 数据流传输模式
279   - * @return
280   - */
281   - @Operation(summary = "修改数据流传输模式", security = @SecurityRequirement(name = JwtUtils.HEADER))
282   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
283   - @Parameter(name = "streamMode", description = "数据流传输模式, 取值:" +
284   - "UDP(udp传输),TCP-ACTIVE(tcp主动模式,暂不支持),TCP-PASSIVE(tcp被动模式)", required = true)
285   - @PostMapping("/transport/{deviceId}/{streamMode}")
286   - public void updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){
287   - Device device = deviceService.getDevice(deviceId);
288   - device.setStreamMode(streamMode);
289   - deviceService.updateCustomDevice(device);
290   - }
291   -
292   - /**
293   - * 添加设备信息
294   - * @param device 设备信息
295   - * @return
296   - */
297   - @Operation(summary = "添加设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER))
298   - @Parameter(name = "device", description = "设备", required = true)
299   - @PostMapping("/device/add/")
300   - public void addDevice(Device device){
301   -
302   - if (device == null || device.getDeviceId() == null) {
303   - throw new ControllerException(ErrorCode.ERROR400);
304   - }
305   -
306   - // 查看deviceId是否存在
307   - boolean exist = deviceService.isExist(device.getDeviceId());
308   - if (exist) {
309   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备编号已存在");
310   - }
311   - deviceService.addDevice(device);
312   - }
313   -
314   - /**
315   - * 更新设备信息
316   - * @param device 设备信息
317   - * @return
318   - */
319   - @Operation(summary = "更新设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER))
320   - @Parameter(name = "device", description = "设备", required = true)
321   - @PostMapping("/device/update/")
322   - public void updateDevice(Device device){
323   -
324   - if (device != null && device.getDeviceId() != null) {
325   - deviceService.updateCustomDevice(device);
326   - }
327   - }
328   -
329   - /**
330   - * 设备状态查询请求API接口
331   - *
332   - * @param deviceId 设备id
333   - */
334   - @Operation(summary = "设备状态查询", security = @SecurityRequirement(name = JwtUtils.HEADER))
335   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
336   - @GetMapping("/devices/{deviceId}/status")
337   - public DeferredResult<ResponseEntity<String>> deviceStatusApi(@PathVariable String deviceId) {
338   - if (logger.isDebugEnabled()) {
339   - logger.debug("设备状态查询API调用");
340   - }
341   - Device device = storager.queryVideoDevice(deviceId);
342   - String uuid = UUID.randomUUID().toString();
343   - String key = DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId;
344   - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(2*1000L);
345   - if(device == null) {
346   - result.setResult(new ResponseEntity(String.format("设备%s不存在", deviceId),HttpStatus.OK));
347   - return result;
348   - }
349   - try {
350   - cmder.deviceStatusQuery(device, event -> {
351   - RequestMessage msg = new RequestMessage();
352   - msg.setId(uuid);
353   - msg.setKey(key);
354   - msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg));
355   - resultHolder.invokeResult(msg);
356   - });
357   - } catch (InvalidArgumentException | SipException | ParseException e) {
358   - logger.error("[命令发送失败] 获取设备状态: {}", e.getMessage());
359   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
360   - }
361   - result.onTimeout(()->{
362   - logger.warn(String.format("获取设备状态超时"));
363   - // 释放rtpserver
364   - RequestMessage msg = new RequestMessage();
365   - msg.setId(uuid);
366   - msg.setKey(key);
367   - msg.setData("Timeout. Device did not response to this command.");
368   - resultHolder.invokeResult(msg);
369   - });
370   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId, uuid, result);
371   - return result;
372   - }
373   -
374   - /**
375   - * 设备报警查询请求API接口
376   - * @param deviceId 设备id
377   - * @param startPriority 报警起始级别(可选)
378   - * @param endPriority 报警终止级别(可选)
379   - * @param alarmMethod 报警方式条件(可选)
380   - * @param alarmType 报警类型
381   - * @param startTime 报警发生起始时间(可选)
382   - * @param endTime 报警发生终止时间(可选)
383   - * @return true = 命令发送成功
384   - */
385   - @Operation(summary = "设备报警查询", security = @SecurityRequirement(name = JwtUtils.HEADER))
386   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
387   - @Parameter(name = "startPriority", description = "报警起始级别")
388   - @Parameter(name = "endPriority", description = "报警终止级别")
389   - @Parameter(name = "alarmMethod", description = "报警方式条件")
390   - @Parameter(name = "alarmType", description = "报警类型")
391   - @Parameter(name = "startTime", description = "报警发生起始时间")
392   - @Parameter(name = "endTime", description = "报警发生终止时间")
393   - @GetMapping("/alarm/{deviceId}")
394   - public DeferredResult<ResponseEntity<String>> alarmApi(@PathVariable String deviceId,
395   - @RequestParam(required = false) String startPriority,
396   - @RequestParam(required = false) String endPriority,
397   - @RequestParam(required = false) String alarmMethod,
398   - @RequestParam(required = false) String alarmType,
399   - @RequestParam(required = false) String startTime,
400   - @RequestParam(required = false) String endTime) {
401   - if (logger.isDebugEnabled()) {
402   - logger.debug("设备报警查询API调用");
403   - }
404   - Device device = storager.queryVideoDevice(deviceId);
405   - String key = DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId;
406   - String uuid = UUID.randomUUID().toString();
407   - try {
408   - cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> {
409   - RequestMessage msg = new RequestMessage();
410   - msg.setId(uuid);
411   - msg.setKey(key);
412   - msg.setData(String.format("设备报警查询失败,错误码: %s, %s",event.statusCode, event.msg));
413   - resultHolder.invokeResult(msg);
414   - });
415   - } catch (InvalidArgumentException | SipException | ParseException e) {
416   - logger.error("[命令发送失败] 设备报警查询: {}", e.getMessage());
417   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
418   - }
419   - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L);
420   - result.onTimeout(()->{
421   - logger.warn(String.format("设备报警查询超时"));
422   - // 释放rtpserver
423   - RequestMessage msg = new RequestMessage();
424   - msg.setId(uuid);
425   - msg.setKey(key);
426   - msg.setData("设备报警查询超时");
427   - resultHolder.invokeResult(msg);
428   - });
429   - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId, uuid, result);
430   - return result;
431   - }
432   -
433   -
434   - @GetMapping("/{deviceId}/sync_status")
435   - @Operation(summary = "获取通道同步进度", security = @SecurityRequirement(name = JwtUtils.HEADER))
436   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
437   - public WVPResult<SyncStatus> getSyncStatus(@PathVariable String deviceId) {
438   - SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId);
439   - WVPResult<SyncStatus> wvpResult = new WVPResult<>();
440   - if (channelSyncStatus == null) {
441   - wvpResult.setCode(-1);
442   - wvpResult.setMsg("同步尚未开始");
443   - }else {
444   - wvpResult.setCode(ErrorCode.SUCCESS.getCode());
445   - wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
446   - wvpResult.setData(channelSyncStatus);
447   - if (channelSyncStatus.getErrorMsg() != null) {
448   - wvpResult.setMsg(channelSyncStatus.getErrorMsg());
449   - }
450   - }
451   - return wvpResult;
452   - }
453   -
454   - @GetMapping("/{deviceId}/subscribe_info")
455   - @Operation(summary = "获取设备的订阅状态", security = @SecurityRequirement(name = JwtUtils.HEADER))
456   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
457   - public WVPResult<Map<String, Integer>> getSubscribeInfo(@PathVariable String deviceId) {
458   - Set<String> allKeys = dynamicTask.getAllKeys();
459   - Map<String, Integer> dialogStateMap = new HashMap<>();
460   - for (String key : allKeys) {
461   - if (key.startsWith(deviceId)) {
462   - ISubscribeTask subscribeTask = (ISubscribeTask)dynamicTask.get(key);
463   - if (subscribeTask instanceof CatalogSubscribeTask) {
464   - dialogStateMap.put("catalog", 1);
465   - }else if (subscribeTask instanceof MobilePositionSubscribeTask) {
466   - dialogStateMap.put("mobilePosition", 1);
467   - }
468   - }
469   - }
470   - WVPResult<Map<String, Integer>> wvpResult = new WVPResult<>();
471   - wvpResult.setCode(0);
472   - wvpResult.setData(dialogStateMap);
473   - return wvpResult;
474   - }
475   -
476   - @GetMapping("/snap/{deviceId}/{channelId}")
477   - @Operation(summary = "请求截图")
478   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
479   - @Parameter(name = "channelId", description = "通道国标编号", required = true)
480   - @Parameter(name = "mark", description = "标识", required = false)
481   - public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId, @RequestParam(required = false) String mark) {
482   -
483   - try {
484   - final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + (mark == null? ".jpg": ("_" + mark + ".jpg"))).toPath());
485   - resp.setContentType(MediaType.IMAGE_PNG_VALUE);
486   - ServletOutputStream outputStream = resp.getOutputStream();
487   - IOUtils.copy(in, resp.getOutputStream());
488   - in.close();
489   - outputStream.close();
490   - } catch (IOException e) {
491   - resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
492   - }
493   - }
494   -
495   - /**
496   - * 查询国标树
497   - * @param deviceId 设备ID
498   - * @param parentId 父ID
499   - * @param page 当前页
500   - * @param count 每页条数
501   - * @return 国标设备
502   - */
503   - @Operation(summary = "查询国标树")
504   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
505   - @Parameter(name = "parentId", description = "父级国标编号")
506   - @Parameter(name = "onlyCatalog", description = "只获取目录")
507   - @Parameter(name = "page", description = "当前页", required = true)
508   - @Parameter(name = "count", description = "每页条数", required = true)
509   - @GetMapping("/tree/{deviceId}")
510   - public ResponseEntity<PageInfo> getTree(@PathVariable String deviceId,
511   - @RequestParam(required = false) String parentId,
512   - @RequestParam(required = false) Boolean onlyCatalog,
513   - int page, int count){
514   -
515   -
516   - if (page <= 0) {
517   - page = 1;
518   - }
519   - if (onlyCatalog == null) {
520   - onlyCatalog = false;
521   - }
522   -
523   - List<BaseTree<DeviceChannel>> treeData = deviceService.queryVideoDeviceTree(deviceId, parentId, onlyCatalog);
524   - if (treeData == null || (page - 1) * count > treeData.size()) {
525   - PageInfo<BaseTree<DeviceChannel>> pageInfo = new PageInfo<>();
526   - pageInfo.setPageNum(page);
527   - pageInfo.setTotal(treeData == null? 0 : treeData.size());
528   - pageInfo.setSize(0);
529   - pageInfo.setList(new ArrayList<>());
530   - return new ResponseEntity<>(pageInfo,HttpStatus.OK);
531   - }
532   -
533   - int toIndex = Math.min(page * count, treeData.size());
534   - // 处理分页
535   - List<BaseTree<DeviceChannel>> trees = treeData.subList((page - 1) * count, toIndex);
536   - PageInfo<BaseTree<DeviceChannel>> pageInfo = new PageInfo<>();
537   - pageInfo.setPageNum(page);
538   - pageInfo.setTotal(treeData.size());
539   - pageInfo.setSize(trees.size());
540   - pageInfo.setList(trees);
541   -
542   - return new ResponseEntity<>(pageInfo,HttpStatus.OK);
543   - }
544   -
545   - /**
546   - * 查询国标树下的通道
547   - * @param deviceId 设备ID
548   - * @param parentId 父ID
549   - * @param page 当前页
550   - * @param count 每页条数
551   - * @return 国标设备
552   - */
553   - @Operation(summary = "查询国标树下的通道")
554   - @Parameter(name = "deviceId", description = "设备国标编号", required = true)
555   - @Parameter(name = "parentId", description = "父级国标编号")
556   - @Parameter(name = "page", description = "当前页", required = true)
557   - @Parameter(name = "count", description = "每页条数", required = true)
558   - @GetMapping("/tree/channel/{deviceId}")
559   - public ResponseEntity<PageInfo> getChannelInTreeNode(@PathVariable String deviceId, @RequestParam(required = false) String parentId, int page, int count){
560   -
561   - if (page <= 0) {
562   - page = 1;
563   - }
564   -
565   - List<DeviceChannel> treeData = deviceService.queryVideoDeviceInTreeNode(deviceId, parentId);
566   - if (treeData == null || (page - 1) * count > treeData.size()) {
567   - PageInfo<BaseTree<DeviceChannel>> pageInfo = new PageInfo<>();
568   - pageInfo.setPageNum(page);
569   - pageInfo.setTotal(treeData == null? 0 : treeData.size());
570   - pageInfo.setSize(0);
571   - pageInfo.setList(new ArrayList<>());
572   - return new ResponseEntity<>(pageInfo,HttpStatus.OK);
573   - }
574   -
575   - int toIndex = Math.min(page * count, treeData.size());
576   - // 处理分页
577   - List<DeviceChannel> trees = treeData.subList((page - 1) * count, toIndex);
578   - PageInfo<DeviceChannel> pageInfo = new PageInfo<>();
579   - pageInfo.setPageNum(page);
580   - pageInfo.setTotal(treeData.size());
581   - pageInfo.setSize(trees.size());
582   - pageInfo.setList(trees);
583   -
584   - return new ResponseEntity<>(pageInfo,HttpStatus.OK);
585   - }
  117 + return storager.queryVideoDeviceList(page, count, null);
  118 + }
  119 +
  120 + /**
  121 + * 分页查询通道数
  122 + *
  123 + * @param deviceId 设备id
  124 + * @param page 当前页
  125 + * @param count 每页条数
  126 + * @param query 查询内容
  127 + * @param online 是否在线 在线 true / 离线 false
  128 + * @param channelType 设备 false/子目录 true
  129 + * @param catalogUnderDevice 是否直属与设备的目录
  130 + * @return 通道列表
  131 + */
  132 + @GetMapping("/devices/{deviceId}/channels")
  133 + @Operation(summary = "分页查询通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
  134 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  135 + @Parameter(name = "page", description = "当前页", required = true)
  136 + @Parameter(name = "count", description = "每页查询数量", required = true)
  137 + @Parameter(name = "query", description = "查询内容")
  138 + @Parameter(name = "online", description = "是否在线")
  139 + @Parameter(name = "channelType", description = "设备/子目录-> false/true")
  140 + @Parameter(name = "catalogUnderDevice", description = "是否直属与设备的目录")
  141 + public PageInfo<DeviceChannel> channels(@PathVariable String deviceId,
  142 + int page, int count,
  143 + @RequestParam(required = false) String query,
  144 + @RequestParam(required = false) String online,
  145 + @RequestParam(required = false) Boolean channelType,
  146 + @RequestParam(required = false) Boolean catalogUnderDevice) {
  147 + if (ObjectUtils.isEmpty(query)) {
  148 + query = null;
  149 + }
  150 +
  151 + Boolean onlineBoolean = null;
  152 + if (StringUtils.equalsAnyIgnoreCase("true", online)) {
  153 + onlineBoolean = true;
  154 + } else if (StringUtils.equalsAnyIgnoreCase("false", online)) {
  155 + onlineBoolean = false;
  156 + } else if (StringUtils.equalsAnyIgnoreCase("the", online)) {
  157 + page = 1;
  158 + count = 10000;
  159 + }
  160 +
  161 + PageInfo<DeviceChannel> pageInfo = storager.queryChannelsByDeviceId(deviceId, query, channelType, onlineBoolean, catalogUnderDevice, page, count);
  162 + if (StringUtils.equalsAnyIgnoreCase("the", online) && Objects.nonNull(pageInfo) && CollectionUtils.isNotEmpty(pageInfo.getList())) {
  163 + List<DeviceChannel> channels = pageInfo.getList().stream().filter(ch -> Objects.equals(ch.getChannelId(), "34020000001310000001")
  164 + || Objects.equals(ch.getChannelId(), "34020000001310000002")).collect(Collectors.toList());
  165 + pageInfo.setList(channels);
  166 + }
  167 + return pageInfo;
  168 + }
  169 +
  170 + /**
  171 + * 同步设备通道
  172 + *
  173 + * @param deviceId 设备id
  174 + * @return
  175 + */
  176 + @Operation(summary = "同步设备通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
  177 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  178 + @GetMapping("/devices/{deviceId}/sync")
  179 + public WVPResult<SyncStatus> devicesSync(@PathVariable String deviceId) {
  180 +
  181 + if (logger.isDebugEnabled()) {
  182 + logger.debug("设备通道信息同步API调用,deviceId:" + deviceId);
  183 + }
  184 + Device device = storager.queryVideoDevice(deviceId);
  185 + boolean status = deviceService.isSyncRunning(deviceId);
  186 + // 已存在则返回进度
  187 + if (status) {
  188 + SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId);
  189 + return WVPResult.success(channelSyncStatus);
  190 + }
  191 + deviceService.sync(device);
  192 +
  193 + WVPResult<SyncStatus> wvpResult = new WVPResult<>();
  194 + wvpResult.setCode(0);
  195 + wvpResult.setMsg("开始同步");
  196 + return wvpResult;
  197 + }
  198 +
  199 + /**
  200 + * 移除设备
  201 + *
  202 + * @param deviceId 设备id
  203 + * @return
  204 + */
  205 + @Operation(summary = "移除设备", security = @SecurityRequirement(name = JwtUtils.HEADER))
  206 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  207 + @DeleteMapping("/devices/{deviceId}/delete")
  208 + public String delete(@PathVariable String deviceId) {
  209 +
  210 + if (logger.isDebugEnabled()) {
  211 + logger.debug("设备信息删除API调用,deviceId:" + deviceId);
  212 + }
  213 +
  214 + // 清除redis记录
  215 + boolean isSuccess = deviceService.delete(deviceId);
  216 + if (isSuccess) {
  217 + inviteStreamService.clearInviteInfo(deviceId);
  218 + // 停止此设备的订阅更新
  219 + Set<String> allKeys = dynamicTask.getAllKeys();
  220 + for (String key : allKeys) {
  221 + if (key.startsWith(deviceId)) {
  222 + Runnable runnable = dynamicTask.get(key);
  223 + if (runnable instanceof ISubscribeTask) {
  224 + ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
  225 + subscribeTask.stop(null);
  226 + }
  227 + dynamicTask.stop(key);
  228 + }
  229 + }
  230 + JSONObject json = new JSONObject();
  231 + json.put("deviceId", deviceId);
  232 + return json.toString();
  233 + } else {
  234 + logger.warn("设备信息删除API调用失败!");
  235 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备信息删除API调用失败!");
  236 + }
  237 + }
  238 +
  239 + /**
  240 + * 分页查询子目录通道
  241 + *
  242 + * @param deviceId 通道id
  243 + * @param channelId 通道id
  244 + * @param page 当前页
  245 + * @param count 每页条数
  246 + * @param query 查询内容
  247 + * @param online 是否在线
  248 + * @param channelType 通道类型
  249 + * @return 子通道列表
  250 + */
  251 + @Operation(summary = "分页查询子目录通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
  252 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  253 + @Parameter(name = "channelId", description = "通道国标编号", required = true)
  254 + @Parameter(name = "page", description = "当前页", required = true)
  255 + @Parameter(name = "count", description = "每页查询数量", required = true)
  256 + @Parameter(name = "query", description = "查询内容")
  257 + @Parameter(name = "online", description = "是否在线")
  258 + @Parameter(name = "channelType", description = "设备/子目录-> false/true")
  259 + @GetMapping("/sub_channels/{deviceId}/{channelId}/channels")
  260 + public PageInfo<DeviceChannel> subChannels(@PathVariable String deviceId,
  261 + @PathVariable String channelId,
  262 + int page,
  263 + int count,
  264 + @RequestParam(required = false) String query,
  265 + @RequestParam(required = false) Boolean online,
  266 + @RequestParam(required = false) Boolean channelType) {
  267 +
  268 + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  269 + if (deviceChannel == null) {
  270 + PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>();
  271 + return deviceChannelPageResult;
  272 + }
  273 +
  274 + return storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
  275 + }
  276 +
  277 + /**
  278 + * 更新通道信息
  279 + *
  280 + * @param deviceId 设备id
  281 + * @param channel 通道
  282 + * @return
  283 + */
  284 + @Operation(summary = "更新通道信息", security = @SecurityRequirement(name = JwtUtils.HEADER))
  285 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  286 + @Parameter(name = "channel", description = "通道信息", required = true)
  287 + @PostMapping("/channel/update/{deviceId}")
  288 + public void updateChannel(@PathVariable String deviceId, DeviceChannel channel) {
  289 + deviceChannelService.updateChannel(deviceId, channel);
  290 + }
  291 +
  292 + @Operation(summary = "修改通道的码流类型", security = @SecurityRequirement(name = JwtUtils.HEADER))
  293 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  294 + @Parameter(name = "channel", description = "通道信息", required = true)
  295 + @PostMapping("/channel/stream/identification/update/")
  296 + public void updateChannelStreamIdentification(DeviceChannel channel) {
  297 + deviceChannelService.updateChannelStreamIdentification(channel);
  298 + }
  299 +
  300 + /**
  301 + * 修改数据流传输模式
  302 + *
  303 + * @param deviceId 设备id
  304 + * @param streamMode 数据流传输模式
  305 + * @return
  306 + */
  307 + @Operation(summary = "修改数据流传输模式", security = @SecurityRequirement(name = JwtUtils.HEADER))
  308 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  309 + @Parameter(name = "streamMode", description = "数据流传输模式, 取值:" +
  310 + "UDP(udp传输),TCP-ACTIVE(tcp主动模式,暂不支持),TCP-PASSIVE(tcp被动模式)", required = true)
  311 + @PostMapping("/transport/{deviceId}/{streamMode}")
  312 + public void updateTransport(@PathVariable String deviceId, @PathVariable String streamMode) {
  313 + Device device = deviceService.getDevice(deviceId);
  314 + device.setStreamMode(streamMode);
  315 + deviceService.updateCustomDevice(device);
  316 + }
  317 +
  318 + /**
  319 + * 添加设备信息
  320 + *
  321 + * @param device 设备信息
  322 + * @return
  323 + */
  324 + @Operation(summary = "添加设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER))
  325 + @Parameter(name = "device", description = "设备", required = true)
  326 + @PostMapping("/device/add/")
  327 + public void addDevice(Device device) {
  328 +
  329 + if (device == null || device.getDeviceId() == null) {
  330 + throw new ControllerException(ErrorCode.ERROR400);
  331 + }
  332 +
  333 + // 查看deviceId是否存在
  334 + boolean exist = deviceService.isExist(device.getDeviceId());
  335 + if (exist) {
  336 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备编号已存在");
  337 + }
  338 + deviceService.addDevice(device);
  339 + }
  340 +
  341 + /**
  342 + * 更新设备信息
  343 + *
  344 + * @param device 设备信息
  345 + * @return
  346 + */
  347 + @Operation(summary = "更新设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER))
  348 + @Parameter(name = "device", description = "设备", required = true)
  349 + @PostMapping("/device/update/")
  350 + public void updateDevice(Device device) {
  351 +
  352 + if (device != null && device.getDeviceId() != null) {
  353 + deviceService.updateCustomDevice(device);
  354 + }
  355 + }
  356 +
  357 + /**
  358 + * 设备状态查询请求API接口
  359 + *
  360 + * @param deviceId 设备id
  361 + */
  362 + @Operation(summary = "设备状态查询", security = @SecurityRequirement(name = JwtUtils.HEADER))
  363 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  364 + @GetMapping("/devices/{deviceId}/status")
  365 + public DeferredResult<ResponseEntity<String>> deviceStatusApi(@PathVariable String deviceId) {
  366 + if (logger.isDebugEnabled()) {
  367 + logger.debug("设备状态查询API调用");
  368 + }
  369 + Device device = storager.queryVideoDevice(deviceId);
  370 + String uuid = UUID.randomUUID().toString();
  371 + String key = DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId;
  372 + DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(2 * 1000L);
  373 + if (device == null) {
  374 + result.setResult(new ResponseEntity(String.format("设备%s不存在", deviceId), HttpStatus.OK));
  375 + return result;
  376 + }
  377 + try {
  378 + cmder.deviceStatusQuery(device, event -> {
  379 + RequestMessage msg = new RequestMessage();
  380 + msg.setId(uuid);
  381 + msg.setKey(key);
  382 + msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg));
  383 + resultHolder.invokeResult(msg);
  384 + });
  385 + } catch (InvalidArgumentException | SipException | ParseException e) {
  386 + logger.error("[命令发送失败] 获取设备状态: {}", e.getMessage());
  387 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  388 + }
  389 + result.onTimeout(() -> {
  390 + logger.warn(String.format("获取设备状态超时"));
  391 + // 释放rtpserver
  392 + RequestMessage msg = new RequestMessage();
  393 + msg.setId(uuid);
  394 + msg.setKey(key);
  395 + msg.setData("Timeout. Device did not response to this command.");
  396 + resultHolder.invokeResult(msg);
  397 + });
  398 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId, uuid, result);
  399 + return result;
  400 + }
  401 +
  402 + /**
  403 + * 设备报警查询请求API接口
  404 + *
  405 + * @param deviceId 设备id
  406 + * @param startPriority 报警起始级别(可选)
  407 + * @param endPriority 报警终止级别(可选)
  408 + * @param alarmMethod 报警方式条件(可选)
  409 + * @param alarmType 报警类型
  410 + * @param startTime 报警发生起始时间(可选)
  411 + * @param endTime 报警发生终止时间(可选)
  412 + * @return true = 命令发送成功
  413 + */
  414 + @Operation(summary = "设备报警查询", security = @SecurityRequirement(name = JwtUtils.HEADER))
  415 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  416 + @Parameter(name = "startPriority", description = "报警起始级别")
  417 + @Parameter(name = "endPriority", description = "报警终止级别")
  418 + @Parameter(name = "alarmMethod", description = "报警方式条件")
  419 + @Parameter(name = "alarmType", description = "报警类型")
  420 + @Parameter(name = "startTime", description = "报警发生起始时间")
  421 + @Parameter(name = "endTime", description = "报警发生终止时间")
  422 + @GetMapping("/alarm/{deviceId}")
  423 + public DeferredResult<ResponseEntity<String>> alarmApi(@PathVariable String deviceId,
  424 + @RequestParam(required = false) String startPriority,
  425 + @RequestParam(required = false) String endPriority,
  426 + @RequestParam(required = false) String alarmMethod,
  427 + @RequestParam(required = false) String alarmType,
  428 + @RequestParam(required = false) String startTime,
  429 + @RequestParam(required = false) String endTime) {
  430 + if (logger.isDebugEnabled()) {
  431 + logger.debug("设备报警查询API调用");
  432 + }
  433 + Device device = storager.queryVideoDevice(deviceId);
  434 + String key = DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId;
  435 + String uuid = UUID.randomUUID().toString();
  436 + try {
  437 + cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> {
  438 + RequestMessage msg = new RequestMessage();
  439 + msg.setId(uuid);
  440 + msg.setKey(key);
  441 + msg.setData(String.format("设备报警查询失败,错误码: %s, %s", event.statusCode, event.msg));
  442 + resultHolder.invokeResult(msg);
  443 + });
  444 + } catch (InvalidArgumentException | SipException | ParseException e) {
  445 + logger.error("[命令发送失败] 设备报警查询: {}", e.getMessage());
  446 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  447 + }
  448 + DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L);
  449 + result.onTimeout(() -> {
  450 + logger.warn(String.format("设备报警查询超时"));
  451 + // 释放rtpserver
  452 + RequestMessage msg = new RequestMessage();
  453 + msg.setId(uuid);
  454 + msg.setKey(key);
  455 + msg.setData("设备报警查询超时");
  456 + resultHolder.invokeResult(msg);
  457 + });
  458 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId, uuid, result);
  459 + return result;
  460 + }
  461 +
  462 +
  463 + @GetMapping("/{deviceId}/sync_status")
  464 + @Operation(summary = "获取通道同步进度", security = @SecurityRequirement(name = JwtUtils.HEADER))
  465 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  466 + public WVPResult<SyncStatus> getSyncStatus(@PathVariable String deviceId) {
  467 + SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId);
  468 + WVPResult<SyncStatus> wvpResult = new WVPResult<>();
  469 + if (channelSyncStatus == null) {
  470 + wvpResult.setCode(-1);
  471 + wvpResult.setMsg("同步尚未开始");
  472 + } else {
  473 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  474 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  475 + wvpResult.setData(channelSyncStatus);
  476 + if (channelSyncStatus.getErrorMsg() != null) {
  477 + wvpResult.setMsg(channelSyncStatus.getErrorMsg());
  478 + }
  479 + }
  480 + return wvpResult;
  481 + }
  482 +
  483 + @GetMapping("/{deviceId}/subscribe_info")
  484 + @Operation(summary = "获取设备的订阅状态", security = @SecurityRequirement(name = JwtUtils.HEADER))
  485 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  486 + public WVPResult<Map<String, Integer>> getSubscribeInfo(@PathVariable String deviceId) {
  487 + Set<String> allKeys = dynamicTask.getAllKeys();
  488 + Map<String, Integer> dialogStateMap = new HashMap<>();
  489 + for (String key : allKeys) {
  490 + if (key.startsWith(deviceId)) {
  491 + ISubscribeTask subscribeTask = (ISubscribeTask) dynamicTask.get(key);
  492 + if (subscribeTask instanceof CatalogSubscribeTask) {
  493 + dialogStateMap.put("catalog", 1);
  494 + } else if (subscribeTask instanceof MobilePositionSubscribeTask) {
  495 + dialogStateMap.put("mobilePosition", 1);
  496 + }
  497 + }
  498 + }
  499 + WVPResult<Map<String, Integer>> wvpResult = new WVPResult<>();
  500 + wvpResult.setCode(0);
  501 + wvpResult.setData(dialogStateMap);
  502 + return wvpResult;
  503 + }
  504 +
  505 + @GetMapping("/snap/{deviceId}/{channelId}")
  506 + @Operation(summary = "请求截图")
  507 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  508 + @Parameter(name = "channelId", description = "通道国标编号", required = true)
  509 + @Parameter(name = "mark", description = "标识", required = false)
  510 + public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId, @RequestParam(required = false) String mark) {
  511 +
  512 + try {
  513 + final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + (mark == null ? ".jpg" : ("_" + mark + ".jpg"))).toPath());
  514 + resp.setContentType(MediaType.IMAGE_PNG_VALUE);
  515 + ServletOutputStream outputStream = resp.getOutputStream();
  516 + IOUtils.copy(in, resp.getOutputStream());
  517 + in.close();
  518 + outputStream.close();
  519 + } catch (IOException e) {
  520 + resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
  521 + }
  522 + }
  523 +
  524 + /**
  525 + * 查询国标树
  526 + *
  527 + * @param deviceId 设备ID
  528 + * @param parentId 父ID
  529 + * @param page 当前页
  530 + * @param count 每页条数
  531 + * @return 国标设备
  532 + */
  533 + @Operation(summary = "查询国标树")
  534 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  535 + @Parameter(name = "parentId", description = "父级国标编号")
  536 + @Parameter(name = "onlyCatalog", description = "只获取目录")
  537 + @Parameter(name = "page", description = "当前页", required = true)
  538 + @Parameter(name = "count", description = "每页条数", required = true)
  539 + @GetMapping("/tree/{deviceId}")
  540 + public ResponseEntity<PageInfo> getTree(@PathVariable String deviceId,
  541 + @RequestParam(required = false) String parentId,
  542 + @RequestParam(required = false) Boolean onlyCatalog,
  543 + int page, int count) {
  544 +
  545 +
  546 + if (page <= 0) {
  547 + page = 1;
  548 + }
  549 + if (onlyCatalog == null) {
  550 + onlyCatalog = false;
  551 + }
  552 +
  553 + List<BaseTree<DeviceChannel>> treeData = deviceService.queryVideoDeviceTree(deviceId, parentId, onlyCatalog);
  554 + if (treeData == null || (page - 1) * count > treeData.size()) {
  555 + PageInfo<BaseTree<DeviceChannel>> pageInfo = new PageInfo<>();
  556 + pageInfo.setPageNum(page);
  557 + pageInfo.setTotal(treeData == null ? 0 : treeData.size());
  558 + pageInfo.setSize(0);
  559 + pageInfo.setList(new ArrayList<>());
  560 + return new ResponseEntity<>(pageInfo, HttpStatus.OK);
  561 + }
  562 +
  563 + int toIndex = Math.min(page * count, treeData.size());
  564 + // 处理分页
  565 + List<BaseTree<DeviceChannel>> trees = treeData.subList((page - 1) * count, toIndex);
  566 + PageInfo<BaseTree<DeviceChannel>> pageInfo = new PageInfo<>();
  567 + pageInfo.setPageNum(page);
  568 + pageInfo.setTotal(treeData.size());
  569 + pageInfo.setSize(trees.size());
  570 + pageInfo.setList(trees);
  571 +
  572 + return new ResponseEntity<>(pageInfo, HttpStatus.OK);
  573 + }
  574 +
  575 + /**
  576 + * 查询国标树下的通道
  577 + *
  578 + * @param deviceId 设备ID
  579 + * @param parentId 父ID
  580 + * @param page 当前页
  581 + * @param count 每页条数
  582 + * @return 国标设备
  583 + */
  584 + @Operation(summary = "查询国标树下的通道")
  585 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  586 + @Parameter(name = "parentId", description = "父级国标编号")
  587 + @Parameter(name = "page", description = "当前页", required = true)
  588 + @Parameter(name = "count", description = "每页条数", required = true)
  589 + @GetMapping("/tree/channel/{deviceId}")
  590 + public ResponseEntity<PageInfo> getChannelInTreeNode(@PathVariable String deviceId, @RequestParam(required = false) String parentId, int page, int count) {
  591 +
  592 + if (page <= 0) {
  593 + page = 1;
  594 + }
  595 +
  596 + List<DeviceChannel> treeData = deviceService.queryVideoDeviceInTreeNode(deviceId, parentId);
  597 + if (treeData == null || (page - 1) * count > treeData.size()) {
  598 + PageInfo<BaseTree<DeviceChannel>> pageInfo = new PageInfo<>();
  599 + pageInfo.setPageNum(page);
  600 + pageInfo.setTotal(treeData == null ? 0 : treeData.size());
  601 + pageInfo.setSize(0);
  602 + pageInfo.setList(new ArrayList<>());
  603 + return new ResponseEntity<>(pageInfo, HttpStatus.OK);
  604 + }
  605 +
  606 + int toIndex = Math.min(page * count, treeData.size());
  607 + // 处理分页
  608 + List<DeviceChannel> trees = treeData.subList((page - 1) * count, toIndex);
  609 + PageInfo<DeviceChannel> pageInfo = new PageInfo<>();
  610 + pageInfo.setPageNum(page);
  611 + pageInfo.setTotal(treeData.size());
  612 + pageInfo.setSize(trees.size());
  613 + pageInfo.setList(trees);
  614 +
  615 + return new ResponseEntity<>(pageInfo, HttpStatus.OK);
  616 + }
586 617 }
... ...
src/main/resources/application-local.yml
... ... @@ -17,9 +17,9 @@ spring:
17 17 # [必须修改] 端口号
18 18 port: 6379
19 19 # [可选] 数据库 DB
20   - database: 7
  20 + database: 8
21 21 # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
22   -# password: guzijian
  22 + # password: guzijian
23 23 # [可选] 超时时间
24 24 timeout: 10000
25 25 # mysql数据源
... ... @@ -30,7 +30,7 @@ spring:
30 30 master:
31 31 type: com.zaxxer.hikari.HikariDataSource
32 32 driver-class-name: com.mysql.cj.jdbc.Driver
33   - url: jdbc:mysql://127.0.0.1:3306/latest_wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
  33 + url: jdbc:mysql://192.168.169.100:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
34 34 username: root
35 35 password: guzijian
36 36 hikari:
... ... @@ -60,9 +60,10 @@ sip:
60 60 # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4
61 61 # 如果不明白,就使用0.0.0.0,大部分情况都是可以的
62 62 # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。
63   - ip: 192.169.1.31
  63 + ip: 0.0.0.0
64 64 # [可选] 28181服务监听的端口
65 65 port: 5060
  66 +
66 67 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
67 68 # 后两位为行业编码,定义参照附录D.3
68 69 # 3701020049标识山东济南历下区 信息行业接入
... ... @@ -77,29 +78,29 @@ sip:
77 78  
78 79 #zlm 默认服务器配置
79 80 media:
80   - id: cQ5byeSBKP2INt6l
  81 + id: guzijian1
81 82 # [必须修改] zlm服务器的内网IP
82   - ip: 192.169.1.31
  83 + ip: 192.168.169.100
83 84 # [必须修改] zlm服务器的http.port
84   - http-port: 80
  85 + http-port: 1091
85 86 # [可选] 返回流地址时的ip,置空使用 media.ip
86   - stream-ip: 192.169.1.31
  87 + stream-ip: 192.168.169.100
87 88 # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip
88   - sdp-ip: 192.169.1.31
  89 + sdp-ip: 192.168.169.100
89 90 # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
90   - hook-ip: 192.169.1.31
  91 + hook-ip: 192.168.169.100
91 92 # [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置
92 93 http-ssl-port: 443
93 94 # [可选] zlm服务器的hook.admin_params=secret
94   - secret: ZLh24VioqaKqxiihBJ80ny60NuWpVe62
  95 + secret: RPorcBlIw26uHGnEHYGesIYyFDXpgjkP1
95 96 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
96 97 rtp:
97 98 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
98 99 enable: true
99 100 # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功
100   - port-range: 50000,50300 # 端口范围
  101 + port-range: 60000,60300 # 端口范围
101 102 # [可选] 国标级联在此范围内选择端口发送媒体流,
102   - send-port-range: 50000,50300 # 端口范围
  103 + send-port-range: 60000,60300 # 端口范围
103 104 # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用
104 105 record-assist-port: 18081
105 106 # [根据业务需求配置]
... ... @@ -111,17 +112,13 @@ user-settings:
111 112 # 设备/通道状态变化时发送消息
112 113 device-status-notify: true
113 114 # 推流直播是否录制
114   -# record-push-live: true
  115 + # record-push-live: true
115 116 # 是否开启接口鉴权
116   -# interface-authentication: false
  117 + # interface-authentication: false
117 118 # 国标是否录制
118   -# record-sip: true
  119 + # record-sip: true
119 120 # 等待音视频编码信息再返回, true: 可以根据编码选择合适的播放器,false: 可以更快点播
120 121 # wait-track: true
121 122 # [可选] 日志配置, 一般不需要改
122 123 logging:
123   - config: classpath:logback-spring.xml
124   -#mybatis:
125   -# configuration:
126   -# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
127   -
  124 + config: classpath:logback-spring.xml
128 125 \ No newline at end of file
... ...
web_src/config/index.js
... ... @@ -11,7 +11,7 @@ module.exports = {
11 11 assetsPublicPath: "/",
12 12 proxyTable: {
13 13 "/debug": {
14   - target: "http://61.169.120.202:18089",
  14 + target: "http://127.0.0.1:18080",
15 15 changeOrigin: true,
16 16 pathRewrite: {
17 17 "^/debug": "/",
... ...
web_src/src/components/channelList.vue
... ... @@ -25,6 +25,7 @@
25 25 <el-option label="全部" value=""></el-option>
26 26 <el-option label="在线" value="true"></el-option>
27 27 <el-option label="离线" value="false"></el-option>
  28 + <el-option label="特定通道" value="the"></el-option>
28 29 </el-select>
29 30 码流类型重置:
30 31 <el-select size="mini" style="width: 16rem; margin-right: 1rem;" @change="subStreamChange" v-model="subStream"
... ... @@ -242,7 +243,7 @@ export default {
242 243 updateLooper: 0, //数据刷新轮训标志
243 244 searchSrt: "",
244 245 channelType: "",
245   - online: "",
  246 + online: "the",
246 247 subStream: "",
247 248 winHeight: window.innerHeight - 200,
248 249 currentPage: 1,
... ...
web_src/static/js/config.js
1   -window.baseUrl = "http://192.168.20.215:18089";
  1 +window.baseUrl = "http://127.0.0.1:18080";
2 2  
3 3 // map组件全局参数, 注释此内容可以关闭地图功能
4 4 window.mapParam = {
... ...