Browse Source

Merge remote-tracking branch 'origin/develop' into develop

develop
wangsixiang 11 months ago
parent
commit
4134c85c91
  1. 10
      ruoyi-admin/src/main/resources/application-druid.yml
  2. 12
      ruoyi-admin/src/main/resources/application.yml
  3. 2
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
  4. 2
      zc-business/src/main/java/com/zc/business/constant/StakeMarkConstant.java
  5. 2
      zc-business/src/main/java/com/zc/business/controller/DcDeviceController.java
  6. 8
      zc-business/src/main/java/com/zc/business/controller/DcEmergencyPlansController.java
  7. 2
      zc-business/src/main/java/com/zc/business/controller/DcEventController.java
  8. 16
      zc-business/src/main/java/com/zc/business/controller/DcTrafficStatisticsController.java
  9. 21
      zc-business/src/main/java/com/zc/business/controller/VideoController.java
  10. 31
      zc-business/src/main/java/com/zc/business/domain/DcCongestedSectionData.java
  11. 6
      zc-business/src/main/java/com/zc/business/domain/DcEmergencyPlans.java
  12. 3
      zc-business/src/main/java/com/zc/business/domain/DcEvent.java
  13. 18
      zc-business/src/main/java/com/zc/business/domain/DcExecuteAction.java
  14. 2
      zc-business/src/main/java/com/zc/business/domain/DcTrafficMetricsData.java
  15. 6
      zc-business/src/main/java/com/zc/business/domain/DcTrafficSectionData.java
  16. 71
      zc-business/src/main/java/com/zc/business/enums/ChannelCongestionLevelEnum.java
  17. 3
      zc-business/src/main/java/com/zc/business/request/DcTrafficMetricsDataRequest.java
  18. 3
      zc-business/src/main/java/com/zc/business/request/DcTrafficSectionDataRequest.java
  19. 9
      zc-business/src/main/java/com/zc/business/service/DcTrafficStatisticsService.java
  20. 210
      zc-business/src/main/java/com/zc/business/service/impl/DcEmergencyPlansServiceImpl.java
  21. 2
      zc-business/src/main/java/com/zc/business/service/impl/DcEventServiceImpl.java
  22. 80
      zc-business/src/main/java/com/zc/business/service/impl/DcTrafficStatisticsServiceImpl.java
  23. 151
      zc-business/src/main/java/com/zc/business/statistics/handler/TrafficAnalysis.java
  24. 24
      zc-business/src/main/resources/mapper/business/DcEmergencyPlansMapper.xml
  25. 28
      zc-business/src/main/resources/mapper/business/DcExecuteActionMapper.xml

10
ruoyi-admin/src/main/resources/application-druid.yml

@ -8,10 +8,12 @@ spring:
master: master:
# 公司数据库地址 # 公司数据库地址
# url: jdbc:mysql://10.168.3.169:3306/athena?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8 # url: jdbc:mysql://10.168.3.169:3306/athena?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
url: jdbc:mysql://10.168.56.204:3306/jihe-dc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true # url: jdbc:mysql://127.0.0.1:3308/event_iot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root # url: jdbc:mysql://127.0.0.1:3308/jihe-dc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
# password: Platform123!@# url: jdbc:mysql://10.168.56.204:3306/jihe-dc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
password: Platform123!@# username: root
# password: root
password: Platform123!@#
# 从库数据源 # 从库数据源
slave: slave:
# 从数据源开关/默认关闭 # 从数据源开关/默认关闭

12
ruoyi-admin/src/main/resources/application.yml

@ -67,9 +67,9 @@ spring:
# 端口,默认为6379 # 端口,默认为6379
port: 6379 port: 6379
# 数据库索引 # 数据库索引
database: 0 database: 1
# 密码 # 密码
password: Redis123!@# password:
# 连接超时时间 # 连接超时时间
timeout: 10s timeout: 10s
lettuce: lettuce:
@ -156,7 +156,7 @@ aj:
iot: iot:
# 物联平台地址 # 物联平台地址
address: http://127.0.0.1:8080 address: https://10.0.81.202:8081
# redis 配置 # redis 配置
redis: redis:
# 地址 # 地址
@ -164,9 +164,9 @@ iot:
# 端口,默认为6379 # 端口,默认为6379
port: 6379 port: 6379
# 数据库索引 # 数据库索引
database: 10 database: 0
# 密码 # 密码
password: Redis123!@# password:
# 连接超时时间 # 连接超时时间
timeout: 10s timeout: 10s
lettuce: lettuce:
@ -183,4 +183,4 @@ iot:
# 允许访问的ip地址 # 允许访问的ip地址
allowed: allowed:
ips: 10.0.81.202,10.168.73.54,10.168.71.194 ips: 10.0.81.202,10.168.73.54,10.168.71.194,

2
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@ -126,7 +126,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
"/**/*.js", "/**/*.js",
"/profile/**" "/profile/**"
).permitAll() ).permitAll()
// .antMatchers("/swagger-ui.html").anonymous() // .antMatchers("/swagger-ui.html").anonymous()
// .antMatchers("/swagger-resources/**").anonymous() // .antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous() .antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous() .antMatchers("/*/api-docs").anonymous()

2
zc-business/src/main/java/com/zc/business/constant/StakeMarkConstant.java

@ -13,7 +13,7 @@ public class StakeMarkConstant {
// 定义最小桩号常量 // 定义最小桩号常量
public static final int MIN_STAKE_MARK = 54394; public static final int MIN_STAKE_MARK = 54394;
// 定义毫米波雷达最大测量间隔 // 定义毫米波雷达最大间隔
public static final int MAX_INTERVAL_MILLIMETER_WAVE_RADAR = 12030; public static final int MAX_INTERVAL_MILLIMETER_WAVE_RADAR = 12030;
/** /**

2
zc-business/src/main/java/com/zc/business/controller/DcDeviceController.java

@ -248,7 +248,7 @@ public class DcDeviceController extends BaseController {
JSONObject formatValue = JSON.parseObject(jsonObject.get("formatValue").toString()); JSONObject formatValue = JSON.parseObject(jsonObject.get("formatValue").toString());
map.put("1", formatValue.get("1")); map.put("1", formatValue.get("1"));
map.put("3", formatValue.get("3")); map.put("3", formatValue.get("3"));
map.put("timestamp", formatValue.get("equipmentReportingTime") == null? "":formatValue.get("equipmentReportingTime")); map.put("timestamp", formatValue.get("equipmentReportingTime") == null? "":Long.valueOf(formatValue.get("equipmentReportingTime").toString()));
list.add(map); list.add(map);
}); });
List<Map<String, Object>> newList = list.stream() List<Map<String, Object>> newList = list.stream()

8
zc-business/src/main/java/com/zc/business/controller/DcEmergencyPlansController.java

@ -34,7 +34,7 @@ public class DcEmergencyPlansController extends BaseController {
* 查询事件预案列表 * 查询事件预案列表
*/ */
@ApiOperation("查询事件预案列表") @ApiOperation("查询事件预案列表")
@PreAuthorize("@ss.hasPermi('business:plans:list')") // @PreAuthorize("@ss.hasPermi('business:plans:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(DcEmergencyPlans dcEmergencyPlans) { public TableDataInfo list(DcEmergencyPlans dcEmergencyPlans) {
startPage(); startPage();
@ -46,7 +46,7 @@ public class DcEmergencyPlansController extends BaseController {
* 根据事件预案id查询事件预案列表 * 根据事件预案id查询事件预案列表
*/ */
@ApiOperation("根据事件预案id查询事件预案列表") @ApiOperation("根据事件预案id查询事件预案列表")
@PreAuthorize("@ss.hasPermi('business:plans:list')") // @PreAuthorize("@ss.hasPermi('business:plans:list')")
@GetMapping("/list/{id}") @GetMapping("/list/{id}")
public AjaxResult list(@PathVariable @ApiParam(name = "id", value = "事件预案id", required = true) Integer id) { public AjaxResult list(@PathVariable @ApiParam(name = "id", value = "事件预案id", required = true) Integer id) {
@ -149,7 +149,7 @@ public class DcEmergencyPlansController extends BaseController {
* 新增事件预案 * 新增事件预案
*/ */
@ApiOperation("新增预案") @ApiOperation("新增预案")
@PreAuthorize("@ss.hasPermi('business:plans:add')") // @PreAuthorize("@ss.hasPermi('business:plans:add')")
@PostMapping @PostMapping
public AjaxResult add(@RequestBody DcEmergencyPlans dcEmergencyPlans) { public AjaxResult add(@RequestBody DcEmergencyPlans dcEmergencyPlans) {
return toAjax(dcEmergencyPlansService.insertDcEmergencyPlans(dcEmergencyPlans)); return toAjax(dcEmergencyPlansService.insertDcEmergencyPlans(dcEmergencyPlans));
@ -159,7 +159,7 @@ public class DcEmergencyPlansController extends BaseController {
* 修改事件预案 * 修改事件预案
*/ */
@ApiOperation("修改预案") @ApiOperation("修改预案")
@PreAuthorize("@ss.hasPermi('business:plans:edit')") // @PreAuthorize("@ss.hasPermi('business:plans:edit')")
@PutMapping @PutMapping
public AjaxResult update(@RequestBody DcEmergencyPlans dcEmergencyPlans) { public AjaxResult update(@RequestBody DcEmergencyPlans dcEmergencyPlans) {
return toAjax(dcEmergencyPlansService.updateDcEmergencyPlans(dcEmergencyPlans)); return toAjax(dcEmergencyPlansService.updateDcEmergencyPlans(dcEmergencyPlans));

2
zc-business/src/main/java/com/zc/business/controller/DcEventController.java

@ -46,10 +46,8 @@ public class DcEventController extends BaseController
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(DcEvent dcEvent) public TableDataInfo list(DcEvent dcEvent)
{ {
startPage(); startPage();
List<DcEvent> list = dcEventService.selectDcEventList(dcEvent); List<DcEvent> list = dcEventService.selectDcEventList(dcEvent);
return getDataTable(list); return getDataTable(list);
} }

16
zc-business/src/main/java/com/zc/business/controller/DcTrafficStatisticsController.java

@ -1,6 +1,7 @@
package com.zc.business.controller; package com.zc.business.controller;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.zc.business.domain.DcCongestedSectionData;
import com.zc.business.domain.DcTrafficMetricsData; import com.zc.business.domain.DcTrafficMetricsData;
import com.zc.business.domain.DcTrafficSectionData; import com.zc.business.domain.DcTrafficSectionData;
import com.zc.business.request.DcTrafficMetricsDataRequest; import com.zc.business.request.DcTrafficMetricsDataRequest;
@ -88,4 +89,19 @@ public class DcTrafficStatisticsController {
return AjaxResult.success(dcTrafficMetricsDataList); return AjaxResult.success(dcTrafficMetricsDataList);
} }
/**
* 获取当前拥堵路段
*
* @param direction 交通方向指定查询哪个方向的拥堵路段具体方向的定义根据实际业务而定
* @return 返回一个AjaxResult对象其中包含了查询结果如果查询成功则结果中封装了当前拥堵路段的数据列表
*/
@ApiOperation("获取当前拥堵路段")
@GetMapping("/current/congested")
public AjaxResult currentCongestedSection(Byte direction){
// 调用服务层方法,获取当前交通指标数据
List<DcCongestedSectionData> dcTrafficMetricsData = dcTrafficStatisticsService.currentCongestedSection(direction);
// 将获取到的交通指标数据封装为成功的结果并返回
return AjaxResult.success(dcTrafficMetricsData);
}
} }

21
zc-business/src/main/java/com/zc/business/controller/VideoController.java

@ -412,35 +412,30 @@ public class VideoController extends BaseController {
Integer pileNumDistance = pileNumTransformMetre(pileNum); Integer pileNumDistance = pileNumTransformMetre(pileNum);
Map<String,Object> result = new HashMap<>(); Map<String,Object> result = new HashMap<>();
//上行列表 //上行列表(包含双向)
List<Map<String,Object>> upCameraList = datalist.stream() List<Map<String,Object>> upCameraList = datalist.stream()
.filter(item -> "0".equals(item.get("camOrientation")))
.map(item->{ .map(item->{
item.put("distance",Math.abs(pileNumTransformMetre(item.get("pileNum").toString()) - pileNumDistance)); item.put("distance",Math.abs(pileNumTransformMetre(item.get("pileNum").toString()) - pileNumDistance));
return item; return item;
}) })
.filter(item ->
("0".equals(item.get("camOrientation")) || "2".equals(item.get("camOrientation")))
&& Integer.parseInt(item.get("distance").toString()) < 2000)
.sorted(comparing(item -> Integer.parseInt(item.get("distance").toString()))) .sorted(comparing(item -> Integer.parseInt(item.get("distance").toString())))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (upCameraList.size() > 0 && Integer.parseInt(upCameraList.get(0).get("distance").toString()) < 2000){ result.put("upCamera",upCameraList);
result.put("upCamera",upCameraList.get(0));
} else {
result.put("upCamera",new HashMap<>());
}
//下行列表 //下行列表
List<Map<String,Object>> downCameraList = datalist.stream() List<Map<String,Object>> downCameraList = datalist.stream()
.filter(item -> "1".equals(item.get("camOrientation")))
.map(item->{ .map(item->{
item.put("distance",Math.abs(pileNumTransformMetre(item.get("pileNum").toString()) - pileNumDistance)); item.put("distance",Math.abs(pileNumTransformMetre(item.get("pileNum").toString()) - pileNumDistance));
return item; return item;
}) })
.filter(item -> "1".equals(item.get("camOrientation")) && Integer.parseInt(item.get("distance").toString()) < 2000)
.sorted(comparing(item -> Integer.parseInt(item.get("distance").toString()))) .sorted(comparing(item -> Integer.parseInt(item.get("distance").toString())))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (downCameraList.size() > 0 && Integer.parseInt(downCameraList.get(0).get("distance").toString()) < 2000){ result.put("downCamera",downCameraList);
result.put("downCamera",downCameraList.get(0));
} else {
result.put("downCamera",new HashMap<>());
}
return AjaxResult.success(result); return AjaxResult.success(result);

31
zc-business/src/main/java/com/zc/business/domain/DcCongestedSectionData.java

@ -0,0 +1,31 @@
package com.zc.business.domain;
import lombok.Data;
/**
* 交通拥堵路段数据定义
* @author xiepufeng
*/
@Data
public class DcCongestedSectionData {
/**
* 开始桩号
*/
private Integer startStakeMark;
/**
* 结束桩号
*/
private Integer endStakeMark;
/**
* 道路方向
*/
private Byte direction;
/**
* 平均车速
*/
private Integer averageSpeed;
}

6
zc-business/src/main/java/com/zc/business/domain/DcEmergencyPlans.java

@ -81,12 +81,6 @@ public class DcEmergencyPlans {
@ApiModelProperty("控制指令") @ApiModelProperty("控制指令")
private String controlCommand; private String controlCommand;
/**
* 事件分类
*/
@ApiModelProperty("事件分类")
private int eventCategory;
/** /**
* 执行操作列表 * 执行操作列表
*/ */

3
zc-business/src/main/java/com/zc/business/domain/DcEvent.java

@ -279,6 +279,9 @@ public class DcEvent {
@ApiModelProperty("事件类型名称") @ApiModelProperty("事件类型名称")
@TableField(exist = false) @TableField(exist = false)
private String eventName; private String eventName;
@ApiModelProperty("流程节点")
@TableField(exist = false)
private String processNode;

18
zc-business/src/main/java/com/zc/business/domain/DcExecuteAction.java

@ -39,12 +39,6 @@ public class DcExecuteAction{
@ApiModelProperty("设备类型") @ApiModelProperty("设备类型")
private int deviceType; private int deviceType;
/**
* 操作类型
*/
@ApiModelProperty("操作类型")
private int actionType;
@ApiModelProperty("创建时间") @ApiModelProperty("创建时间")
private Date createTime; private Date createTime;
@ApiModelProperty("修改时间") @ApiModelProperty("修改时间")
@ -69,10 +63,16 @@ public class DcExecuteAction{
private String deviceList; private String deviceList;
/** /**
* 其他配置 * 执行操作配置
*/
@ApiModelProperty("执行操作配置")
private String executeConfig;
/**
* 恢复操作配置
*/ */
@ApiModelProperty("其他配置") @ApiModelProperty("恢复操作配置")
private String otherConfig; private String recoverConfig;

2
zc-business/src/main/java/com/zc/business/domain/DcTrafficMetricsData.java

@ -1,5 +1,6 @@
package com.zc.business.domain; package com.zc.business.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import java.util.Date; import java.util.Date;
@ -39,6 +40,7 @@ public class DcTrafficMetricsData {
/** /**
* 统计时间 * 统计时间
*/ */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date statisticalDate; private Date statisticalDate;
/** /**

6
zc-business/src/main/java/com/zc/business/domain/DcTrafficSectionData.java

@ -47,12 +47,14 @@ public class DcTrafficSectionData {
/** /**
* 统计时间 * 统计时间
*/ */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date statisticalDate; private Date statisticalDate;
/** /**
* 上报时间 * 上报时间
*/ */
@TableField(exist = false) @TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date reportTime; private Date reportTime;
/** /**
@ -87,6 +89,10 @@ public class DcTrafficSectionData {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date updateTime; private Date updateTime;
public void setPeriodType(Byte periodType) {
this.periodType = periodType;
}
/** /**
* 设置交通数据的统计周期类型 * 设置交通数据的统计周期类型
* @param periodType 统计周期类型的枚举值 * @param periodType 统计周期类型的枚举值

71
zc-business/src/main/java/com/zc/business/enums/ChannelCongestionLevelEnum.java

@ -69,7 +69,28 @@ public enum ChannelCongestionLevelEnum {
*/ */
public static ChannelCongestionLevelEnum fromSpeed(int speed) { public static ChannelCongestionLevelEnum fromSpeed(int speed) {
for (ChannelCongestionLevelEnum level : values()) { for (ChannelCongestionLevelEnum level : values()) {
if (speed > level.speedThreshold) { if (speed >= level.speedThreshold) {
return level;
}
}
return SEVERE_CONGESTION; // 若速度小于等于所有等级阈值,则视为严重拥堵
}
/**
* 根据给定速度返回对应的通道拥挤度等级
*
* @param speed 速度单位km/h
* @param trafficVolume 车流量
* @return 对应的通道拥挤度等级
*/
public static ChannelCongestionLevelEnum fromSpeed(int speed, int trafficVolume) {
if (trafficVolume == 0) {
return FLOWING;
}
for (ChannelCongestionLevelEnum level : values()) {
if (speed >= level.speedThreshold) {
return level; return level;
} }
} }
@ -84,6 +105,53 @@ public enum ChannelCongestionLevelEnum {
return level == MEDIUM_CONGESTION || level == SEVERE_CONGESTION; return level == MEDIUM_CONGESTION || level == SEVERE_CONGESTION;
} }
/**
* 判断当前交通状况是否为中度或严重拥堵
*
* @param speed 当前道路的车速单位为任意测量单位取决于具体应用
* @param trafficVolume 当前道路的交通流量单位为任意测量单位取决于具体应用
* @return boolean 返回 true 如果当前交通状况被判断为中度或严重拥堵否则返回 false
*/
public static boolean isMediumOrSevereCongestion(int speed, int trafficVolume) {
// 当交通流量为0时,不考虑拥堵问题,直接返回false
if (trafficVolume == 0) {
return false;
}
// 根据车速判断拥堵级别
ChannelCongestionLevelEnum level = fromSpeed(speed);
// 判断拥堵级别是否为中度或严重拥堵
return level == MEDIUM_CONGESTION || level == SEVERE_CONGESTION;
}
/**
* 判断给定速度是否属于拥堵状态
*
* @param speed 速度单位km/h
* @param trafficVolume 车流量
* @return 如果速度小于等于基本畅通的阈值则返回true否则返回false
*/
public static boolean isCongestion(int speed, int trafficVolume) {
if (trafficVolume == 0) {
return false;
}
return speed < BASIC_FLOWING.getSpeedThreshold();
}
/**
* 判断给定速度是否属于拥堵状态
*
* @param speed 速度单位km/h
* @return 如果速度小于等于基本畅通的阈值则返回true否则返回false
*/
public static boolean isCongestion(int speed) {
return speed < BASIC_FLOWING.getSpeedThreshold();
}
/** /**
* 判断给定速度是否属于指定的拥挤度等级 * 判断给定速度是否属于指定的拥挤度等级
* *
@ -92,6 +160,7 @@ public enum ChannelCongestionLevelEnum {
* @return 如果速度属于该等级返回true否则返回false * @return 如果速度属于该等级返回true否则返回false
*/ */
public static boolean isWithinLevel(int speed, ChannelCongestionLevelEnum level) { public static boolean isWithinLevel(int speed, ChannelCongestionLevelEnum level) {
if (level == null) return false;
ChannelCongestionLevelEnum currentLevel = fromSpeed(speed); ChannelCongestionLevelEnum currentLevel = fromSpeed(speed);
return currentLevel == level; return currentLevel == level;
} }

3
zc-business/src/main/java/com/zc/business/request/DcTrafficMetricsDataRequest.java

@ -1,6 +1,7 @@
package com.zc.business.request; package com.zc.business.request;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date; import java.util.Date;
@ -30,11 +31,13 @@ public class DcTrafficMetricsDataRequest {
/** /**
* 开始时间 * 开始时间
*/ */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime; private Date startTime;
/** /**
* 结束时间 * 结束时间
*/ */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime; private Date endTime;
/** /**

3
zc-business/src/main/java/com/zc/business/request/DcTrafficSectionDataRequest.java

@ -1,6 +1,7 @@
package com.zc.business.request; package com.zc.business.request;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date; import java.util.Date;
@ -25,11 +26,13 @@ public class DcTrafficSectionDataRequest {
/** /**
* 开始时间 * 开始时间
*/ */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime; private Date startTime;
/** /**
* 结束时间 * 结束时间
*/ */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime; private Date endTime;
/** /**

9
zc-business/src/main/java/com/zc/business/service/DcTrafficStatisticsService.java

@ -2,6 +2,7 @@ package com.zc.business.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.zc.business.domain.DcCongestedSectionData;
import com.zc.business.domain.DcTrafficMetricsData; import com.zc.business.domain.DcTrafficMetricsData;
import com.zc.business.domain.DcTrafficSectionData; import com.zc.business.domain.DcTrafficSectionData;
import com.zc.business.request.DcTrafficMetricsDataRequest; import com.zc.business.request.DcTrafficMetricsDataRequest;
@ -50,4 +51,12 @@ public interface DcTrafficStatisticsService extends IService<DcTrafficSectionDat
* @return 返回符合查询条件的历史交通指标数据列表 * @return 返回符合查询条件的历史交通指标数据列表
*/ */
List<DcTrafficMetricsData> historyTrafficMetrics(DcTrafficMetricsDataRequest request); List<DcTrafficMetricsData> historyTrafficMetrics(DcTrafficMetricsDataRequest request);
/**
* 获取当前拥堵路段列表
*
* @param direction 交通方向指定查询哪个方向的拥堵路段具体方向的定义根据实际业务而定
* @return 返回当前拥堵路段列表
*/
List<DcCongestedSectionData> currentCongestedSection(Byte direction);
} }

210
zc-business/src/main/java/com/zc/business/service/impl/DcEmergencyPlansServiceImpl.java

@ -196,7 +196,8 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
markArray[1] = String.format("%0" + 3 + "d", markArray[1]); markArray[1] = String.format("%0" + 3 + "d", markArray[1]);
} }
DcExecuteAction executeAction = dcEventAnDcEmergencyPlans.getDcEmergencyPlans().getExecuteAction(); DcExecuteAction executeAction = dcEventAnDcEmergencyPlans.getDcEmergencyPlans().getExecuteAction();
List<DcDevice> dcDevices = ruleFiltering(executeAction, markArray, direction); Integer operationType = dcEventAnDcEmergencyPlans.getOperationType();
List<DcDevice> dcDevices = ruleFiltering(executeAction, markArray, direction, operationType);
return getBoardTemplate(dcDevices); return getBoardTemplate(dcDevices);
} }
@ -217,7 +218,8 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
markArray[1] = String.format("%0" + 3 + "d", markArray[1]); markArray[1] = String.format("%0" + 3 + "d", markArray[1]);
} }
DcExecuteAction executeAction = dcEventAnDcEmergencyPlans.getDcEmergencyPlans().getExecuteAction(); DcExecuteAction executeAction = dcEventAnDcEmergencyPlans.getDcEmergencyPlans().getExecuteAction();
List<DcDevice> dcDevices = ruleFiltering(executeAction, markArray, direction); Integer operationType = dcEventAnDcEmergencyPlans.getOperationType();
List<DcDevice> dcDevices = ruleFiltering(executeAction, markArray, direction, operationType);
return getBoardTemplate(dcDevices); return getBoardTemplate(dcDevices);
} }
@ -287,9 +289,12 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
* @param direction * @param direction
* @return * @return
*/ */
public List<DcDevice> ruleFiltering(DcExecuteAction dcExecuteAction, String[] markArray, String direction) { public List<DcDevice> ruleFiltering(DcExecuteAction dcExecuteAction, String[] markArray, String direction, Integer operationType) {
Integer searchRule = dcExecuteAction.getSearchRule(); Integer searchRule = dcExecuteAction.getSearchRule();
// 区分执行操作还是恢复操作
JSONObject otherConfig = operationType.equals(1)?
JSON.parseObject(dcExecuteAction.getExecuteConfig()): JSON.parseObject(dcExecuteAction.getRecoverConfig());
List<String> start = new ArrayList<>(); List<String> start = new ArrayList<>();
List<String> end = new ArrayList<>(); List<String> end = new ArrayList<>();
// 设备列表 // 设备列表
@ -301,7 +306,6 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
// 指定设备资源 // 指定设备资源
// 根据设备id,获取设备集合 // 根据设备id,获取设备集合
LambdaQueryWrapper<DcDevice> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DcDevice> queryWrapper = new LambdaQueryWrapper<>();
JSONObject otherConfig = JSON.parseObject(dcExecuteAction.getOtherConfig());
List<String> deviceList = (List<String>) otherConfig.get("deviceList"); List<String> deviceList = (List<String>) otherConfig.get("deviceList");
queryWrapper.in(DcDevice::getIotDeviceId, deviceList); queryWrapper.in(DcDevice::getIotDeviceId, deviceList);
dcDevices = dcDeviceService.list(queryWrapper); dcDevices = dcDeviceService.list(queryWrapper);
@ -564,19 +568,21 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
// 获取事件预案数据 // 获取事件预案数据
DcEmergencyPlans dcEmergencyPlans = dcEventAnDcEmergencyPlans.getDcEmergencyPlans(); DcEmergencyPlans dcEmergencyPlans = dcEventAnDcEmergencyPlans.getDcEmergencyPlans();
Integer operationType = dcEventAnDcEmergencyPlans.getOperationType();
//获取事件预案中的 执行操作配置 //获取事件预案中的操作配置
dcEmergencyPlans.getDcExecuteAction() dcEmergencyPlans.getDcExecuteAction()
.forEach(dcExecuteAction -> { .forEach(dcExecuteAction -> {
List<DcDevice> dcDevices = ruleFiltering(dcExecuteAction, markArray, direction); List<DcDevice> dcDevices = ruleFiltering(dcExecuteAction, markArray, direction, operationType);
JSONObject otherConfig = operationType.equals(1)?
JSON.parseObject(dcExecuteAction.getExecuteConfig()): JSON.parseObject(dcExecuteAction.getRecoverConfig());
try { try {
// 根据不通设备类型,执行不通的功能操作 // 根据不通设备类型,执行不通的功能操作
invokedFunction( invokedFunction(
dcEventAnDcEmergencyPlans.getOperationType(), dcEventAnDcEmergencyPlans.getOperationType(),
dcDevices, dcDevices,
JSON.parseObject(dcExecuteAction.getOtherConfig()), otherConfig,
resultArray); resultArray);
// 记录操作过的设备id // 记录操作过的设备id
@ -666,81 +672,31 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
} }
else if (device.getDeviceType().equals(DeviceTypeConstants.VARIABLE_INFORMATION_FLAG.toString())) { else if (device.getDeviceType().equals(DeviceTypeConstants.VARIABLE_INFORMATION_FLAG.toString())) {
if (operationType == 1) { if (operationType == 1) {
// 情报板发布全流程
// 执行操作 boardReleaseProcess(props, iotDeviceId, otherConfig, device, resultArray);
// 可变信息标志 分三步
// 1:执行11功能码
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_11;
props.put("fileName", "play011.lst");
props.put("size", "65535");
AjaxResult ajaxResult11;
ajaxResult11 = dcDeviceController.invokedFunction(iotDeviceId, functionId, props);
if (ajaxResult11.get("code").equals(200)) {
// 2:执行13功能码
HashMap<String, Object> props11 = new HashMap<>();
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_13;
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> parameters = new HashMap<>();
DcInfoBoardTemplate dcInfoBoardTemplate = JSON.parseObject(
JSON.toJSONString(otherConfig.get("dcInfoBoardTemplate")),
DcInfoBoardTemplate.class);
// stopTime
parameters.put("STAY", dcInfoBoardTemplate.getStopTime());
// inScreenMode
parameters.put("ACTION", dcInfoBoardTemplate.getInScreenMode());
// fontSpacing
parameters.put("SPEED", dcInfoBoardTemplate.getFontSpacing());
// fontColor
parameters.put("COLOR", dcInfoBoardTemplate.getFontColor());
// fontType
parameters.put("FONT", dcInfoBoardTemplate.getFontType());
// fontSize
parameters.put("FONT_SIZE", dcInfoBoardTemplate.getFontSize());
// content
parameters.put("CONTENT", dcInfoBoardTemplate.getContent());
// screenSize 768*64 宽度和高度
parameters.put("width", dcInfoBoardTemplate.getScreenSize().split("\\*")[0]);
parameters.put("height", dcInfoBoardTemplate.getScreenSize().split("\\*")[1]);
// formatStyle
parameters.put("formatStyle", dcInfoBoardTemplate.getFormatStyle());
list.add(parameters);
props11.put("parameters", list);
AjaxResult ajaxResult13 = null;
ajaxResult13 = dcDeviceController.invokedFunction(iotDeviceId, functionId, props11);
JSONObject result = new JSONObject();
if (ajaxResult13.get("code").equals(200)) {
HashMap<String, Object> props1B = new HashMap<>();
// 3: 执行1B功能码
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_1B;
props1B.put("fileId", "11");
AjaxResult ajaxResult1B = dcDeviceController.invokedFunction(iotDeviceId, functionId, props1B);
result.put("device", device.getId());
result.put("result", ajaxResult1B);
resultArray.add(result);
} else {
result.put("device", device.getId());
result.put("result", ajaxResult13);
resultArray.add(result);
}
}
} else { } else {
// 恢复操作 // 恢复操作
props.put("fileId", "10"); if (otherConfig.get("operationType").equals("2")) {
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_1B; // 还原上次
AjaxResult ajaxResult1B; props.put("fileId", "10");
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_1B;
AjaxResult ajaxResult1B;
ajaxResult1B = dcDeviceController.invokedFunction(iotDeviceId, functionId, props); ajaxResult1B = dcDeviceController.invokedFunction(iotDeviceId, functionId, props);
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
result.put("device", device.getId()); result.put("device", device.getId());
result.put("result", ajaxResult1B); result.put("result", ajaxResult1B);
resultArray.add(result); resultArray.add(result);
}else {
// 播放自定义
boardReleaseProcess(props, iotDeviceId, otherConfig, device, resultArray);
}
} }
} }
else if (device.getDeviceType().equals(DeviceTypeConstants.ROAD_SECTION_VOICE_BROADCASTING.toString())) { else if (device.getDeviceType().equals(DeviceTypeConstants.ROAD_SECTION_VOICE_BROADCASTING.toString())
&& operationType.equals(1)) {
// 路段广播 // 路段广播
JSONObject params = new JSONObject(); JSONObject params = new JSONObject();
params.put("name", "task-event"); params.put("name", "task-event");
@ -793,6 +749,75 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
} }
/**
* 情报板发布全流程
*/
public void boardReleaseProcess(HashMap<String, Object> props,
String iotDeviceId,
JSONObject otherConfig,
DcDevice device,
JSONArray resultArray
) throws HttpException, IOException {
String functionId = "";
// 执行操作
// 可变信息标志 分三步
// 1:执行11功能码
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_11;
props.put("fileName", "play011.lst");
props.put("size", "65535");
AjaxResult ajaxResult11;
ajaxResult11 = dcDeviceController.invokedFunction(iotDeviceId, functionId, props);
if (ajaxResult11.get("code").equals(200)) {
// 2:执行13功能码
HashMap<String, Object> props11 = new HashMap<>();
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_13;
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> parameters = new HashMap<>();
DcInfoBoardTemplate dcInfoBoardTemplate = JSON.parseObject(
JSON.toJSONString(otherConfig.get("dcInfoBoardTemplate")),
DcInfoBoardTemplate.class);
// stopTime
parameters.put("STAY", dcInfoBoardTemplate.getStopTime());
// inScreenMode
parameters.put("ACTION", dcInfoBoardTemplate.getInScreenMode());
// fontSpacing
parameters.put("SPEED", dcInfoBoardTemplate.getFontSpacing());
// fontColor
parameters.put("COLOR", dcInfoBoardTemplate.getFontColor());
// fontType
parameters.put("FONT", dcInfoBoardTemplate.getFontType());
// fontSize
parameters.put("FONT_SIZE", dcInfoBoardTemplate.getFontSize());
// content
parameters.put("CONTENT", dcInfoBoardTemplate.getContent());
// screenSize 768*64 宽度和高度
parameters.put("width", dcInfoBoardTemplate.getScreenSize().split("\\*")[0]);
parameters.put("height", dcInfoBoardTemplate.getScreenSize().split("\\*")[1]);
// formatStyle
parameters.put("formatStyle", dcInfoBoardTemplate.getFormatStyle());
list.add(parameters);
props11.put("parameters", list);
AjaxResult ajaxResult13 = null;
ajaxResult13 = dcDeviceController.invokedFunction(iotDeviceId, functionId, props11);
JSONObject result = new JSONObject();
if (ajaxResult13.get("code").equals(200)) {
HashMap<String, Object> props1B = new HashMap<>();
// 3: 执行1B功能码
functionId = DeviceFunctionIdConstants.VARIABLE_INFORMATION_FLAG_1B;
props1B.put("fileId", "11");
AjaxResult ajaxResult1B = dcDeviceController.invokedFunction(iotDeviceId, functionId, props1B);
result.put("device", device.getId());
result.put("result", ajaxResult1B);
resultArray.add(result);
} else {
result.put("device", device.getId());
result.put("result", ajaxResult13);
resultArray.add(result);
}
}
}
/** /**
* 新增事件预案 * 新增事件预案
@ -828,7 +853,7 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
dcEmergencyPlansMapper.updateDcEmergencyPlans(dcEmergencyPlans); dcEmergencyPlansMapper.updateDcEmergencyPlans(dcEmergencyPlans);
// 修改执行操作表数据 // 修改执行操作表数据
dcExecuteActionList.forEach(dcExecuteAction -> dcExecuteAction.setUpdateTime(DateUtils.getNowDate())); dcExecuteActionList.forEach(dcExecuteAction -> dcExecuteAction.setUpdateTime(DateUtils.getNowDate()));
// 过滤出删除掉的执行操作和恢复操作 // 过滤出删除掉的操作
String dcExecuteActionId = dcExecuteActionList.stream() String dcExecuteActionId = dcExecuteActionList.stream()
.filter(dcExecuteAction -> dcExecuteAction.getId() != null) .filter(dcExecuteAction -> dcExecuteAction.getId() != null)
.map(DcExecuteAction::getEmergencyPlansId) .map(DcExecuteAction::getEmergencyPlansId)
@ -839,17 +864,16 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
.filter(dcExecuteAction -> dcExecuteAction.getId() != null) .filter(dcExecuteAction -> dcExecuteAction.getId() != null)
.map(DcExecuteAction::getId) .map(DcExecuteAction::getId)
.collect(Collectors.toList()); .collect(Collectors.toList());
// 查询出事件预案关联的执行操作和恢复操作 // 查询出事件预案关联的操作
List<String> dcExecuteActionIdList = dcExecuteActionService.selectDcExecuteActionByEmergencyPlansId(dcExecuteActionId); List<String> dcExecuteActionIdList = dcExecuteActionService.selectDcExecuteActionByEmergencyPlansId(dcExecuteActionId);
List<String> commonIds = new ArrayList<>(ids); List<String> commonIds = new ArrayList<>(ids);
commonIds.retainAll(dcExecuteActionIdList); commonIds.retainAll(dcExecuteActionIdList);
// 删除后的执行操作id和恢复操作id // 删除后的操作id
List<String> idsNotInDcExecuteActionIdList = new ArrayList<>(dcExecuteActionIdList); List<String> idsNotInDcExecuteActionIdList = new ArrayList<>(dcExecuteActionIdList);
idsNotInDcExecuteActionIdList.removeAll(commonIds); idsNotInDcExecuteActionIdList.removeAll(commonIds);
// 根据执行操作id和恢复操作id,进行删除操作 // 根据操作id,进行删除操作
if (idsNotInDcExecuteActionIdList.size() > 0) { if (idsNotInDcExecuteActionIdList.size() > 0) {
System.out.println("存在需要删除的数据");
dcExecuteActionService.deleteDcExecuteAction(idsNotInDcExecuteActionIdList); dcExecuteActionService.deleteDcExecuteAction(idsNotInDcExecuteActionIdList);
} }
@ -907,14 +931,10 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
* 数据处理 * 数据处理
*/ */
public static List<DcExecuteAction> dataProcessing(DcEmergencyPlans dcEmergencyPlans) { public static List<DcExecuteAction> dataProcessing(DcEmergencyPlans dcEmergencyPlans) {
// 过滤出执行操作数据
List<DcExecuteAction> dcExecuteActionOperationList = dcEmergencyPlans.getDcExecuteAction()
.stream()
.filter(dcExecuteAction -> dcExecuteAction.getActionType() == 1)
.collect(Collectors.toList());
List<DcExecuteAction> dcExecuteActionList = dcEmergencyPlans.getDcExecuteAction(); List<DcExecuteAction> dcExecuteActionList = dcEmergencyPlans.getDcExecuteAction();
// 设备类型 数据处理 // 设备类型 数据处理
String deviceType = dcExecuteActionOperationList.stream() String deviceType = dcExecuteActionList.stream()
.map(DcExecuteAction::getDeviceType) .map(DcExecuteAction::getDeviceType)
.distinct() .distinct()
.map(type -> Arrays.stream(DeviceTypeEnum.values()) .map(type -> Arrays.stream(DeviceTypeEnum.values())
@ -926,7 +946,7 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
.collect(Collectors.joining(",")); .collect(Collectors.joining(","));
dcEmergencyPlans.setDeviceType(deviceType); dcEmergencyPlans.setDeviceType(deviceType);
// 可控设备 数据处理 // 可控设备 数据处理
List<DcExecuteAction> dcExecuteActionNewList = dcExecuteActionOperationList.stream() List<DcExecuteAction> dcExecuteActionNewList = dcExecuteActionList.stream()
.filter(dcExecuteAction -> dcExecuteAction.getSearchRule() == 1) .filter(dcExecuteAction -> dcExecuteAction.getSearchRule() == 1)
.collect(Collectors.toList()); .collect(Collectors.toList());
String controllableDevice = dcExecuteActionNewList.stream() String controllableDevice = dcExecuteActionNewList.stream()
@ -934,11 +954,12 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
.collect(Collectors.joining("、")); .collect(Collectors.joining("、"));
dcEmergencyPlans.setControllableDevice(controllableDevice); dcEmergencyPlans.setControllableDevice(controllableDevice);
// 控制指令 数据处理 // 控制指令 数据处理
List<String> otherConfigList = dcExecuteActionOperationList.stream() List<String> otherConfigList = dcExecuteActionList.stream()
.map(dcExecuteAction -> { .map(dcExecuteAction -> {
JSONObject config = new JSONObject(); JSONObject config = new JSONObject();
String otherConfig = dcExecuteAction.getOtherConfig(); // 执行操作配置
JSONObject jsonObject = JSON.parseObject(otherConfig); String executeConfig = dcExecuteAction.getExecuteConfig();
JSONObject jsonObject = JSON.parseObject(executeConfig);
if (dcExecuteAction.getDeviceType() == DeviceTypeConstants.DRIVING_GUIDANCE) { if (dcExecuteAction.getDeviceType() == DeviceTypeConstants.DRIVING_GUIDANCE) {
// 行车诱导 // 行车诱导
config.put("controlModelName",jsonObject.get("controlModelName")); config.put("controlModelName",jsonObject.get("controlModelName"));
@ -950,7 +971,12 @@ public class DcEmergencyPlansServiceImpl implements DcEmergencyPlansService {
}else if (dcExecuteAction.getDeviceType() == DeviceTypeConstants.VARIABLE_INFORMATION_FLAG || }else if (dcExecuteAction.getDeviceType() == DeviceTypeConstants.VARIABLE_INFORMATION_FLAG ||
dcExecuteAction.getDeviceType() == DeviceTypeConstants.ROAD_SECTION_VOICE_BROADCASTING) { dcExecuteAction.getDeviceType() == DeviceTypeConstants.ROAD_SECTION_VOICE_BROADCASTING) {
// 情报板/语音广播 // 情报板/语音广播
config.put("content",jsonObject.get("content")); if (jsonObject.get("operationType").equals("1")) {
config.put("content",jsonObject.get("content"));
}else {
config.put("operationType","智能发布");
}
} }
else if (dcExecuteAction.getDeviceType() == DeviceTypeConstants.LASER_FATIGUE_AWAKENING) { else if (dcExecuteAction.getDeviceType() == DeviceTypeConstants.LASER_FATIGUE_AWAKENING) {
// 激光疲劳唤醒 // 激光疲劳唤醒

2
zc-business/src/main/java/com/zc/business/service/impl/DcEventServiceImpl.java

@ -603,6 +603,8 @@ public class DcEventServiceImpl extends ServiceImpl<DcEventMapper, DcEvent> impl
public DcEvent selectEventSubclassById(int eventType, String id) { public DcEvent selectEventSubclassById(int eventType, String id) {
//todo //todo
DcEvent dcEvent = dcEventMapper.selectDcEventById(id); DcEvent dcEvent = dcEventMapper.selectDcEventById(id);
List<DcProcessConfig> processConfigList = dcProcessConfigMapper.selectDcProcessConfigByEventType(Math.toIntExact(dcEvent.getEventType()));
dcEvent.setProcessConfigList(processConfigList);
switch (eventType) { switch (eventType) {
//交通事故 //交通事故
case 1: case 1:

80
zc-business/src/main/java/com/zc/business/service/impl/DcTrafficStatisticsServiceImpl.java

@ -10,6 +10,7 @@ import com.ruoyi.common.exception.ServiceException;
import com.zc.business.constant.DeviceTypeConstants; import com.zc.business.constant.DeviceTypeConstants;
import com.zc.business.constant.RedisKeyConstants; import com.zc.business.constant.RedisKeyConstants;
import com.zc.business.controller.DcDeviceController; import com.zc.business.controller.DcDeviceController;
import com.zc.business.domain.DcCongestedSectionData;
import com.zc.business.domain.DcRoadSection; import com.zc.business.domain.DcRoadSection;
import com.zc.business.domain.DcTrafficMetricsData; import com.zc.business.domain.DcTrafficMetricsData;
import com.zc.business.domain.DcTrafficSectionData; import com.zc.business.domain.DcTrafficSectionData;
@ -30,6 +31,8 @@ import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -123,9 +126,18 @@ public class DcTrafficStatisticsServiceImpl
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime()); queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime());
queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType()); queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType());
queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection());
queryWrapper.eq(DcTrafficSectionData::getDeviceType, request.getDeviceType()); if (request.getDirection() != null) {
queryWrapper.eq(DcTrafficSectionData::getDeviceId, request.getDeviceId()); queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection());
}
if (request.getDeviceType() != null) {
queryWrapper.eq(DcTrafficSectionData::getDeviceType, request.getDeviceType());
}
if (request.getDeviceId() != null) {
queryWrapper.eq(DcTrafficSectionData::getDeviceId, request.getDeviceId());
}
return list(queryWrapper); return list(queryWrapper);
} }
@ -143,6 +155,9 @@ public class DcTrafficStatisticsServiceImpl
// 从Redis缓存中获取指定方向的交通路段数据列表 // 从Redis缓存中获取指定方向的交通路段数据列表
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(request.getDirection()); List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(request.getDirection());
// 过滤掉时间错误的交通数据
processStaleTrafficSectionData(dcTrafficSectionDataCaches);
// 根据请求过滤交通数据 // 根据请求过滤交通数据
List<DcTrafficSectionData> trafficSectionDataList = filterTrafficDataByRequest(request, dcTrafficSectionDataCaches); List<DcTrafficSectionData> trafficSectionDataList = filterTrafficDataByRequest(request, dcTrafficSectionDataCaches);
@ -180,7 +195,10 @@ public class DcTrafficStatisticsServiceImpl
LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DcTrafficSectionData> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime()); queryWrapper.between(DcTrafficSectionData::getStatisticalDate, request.getStartTime(), request.getEndTime());
queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType()); queryWrapper.eq(DcTrafficSectionData::getPeriodType, request.getPeriodType());
queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection());
if (request.getDirection() != null) {
queryWrapper.eq(DcTrafficSectionData::getDirection, request.getDirection());
}
// 根据请求获取所属路段ID,并进一步筛选路段范围内的数据 // 根据请求获取所属路段ID,并进一步筛选路段范围内的数据
Long roadSectionId = request.getRoadSectionId(); Long roadSectionId = request.getRoadSectionId();
@ -211,6 +229,30 @@ public class DcTrafficStatisticsServiceImpl
} }
/**
* 获取当前拥堵的路段数据列表
*
* @param direction 指定的方向用于筛选交通数据
* @return 返回一个包含当前拥堵路段数据的列表
*/
@Override
public List<DcCongestedSectionData> currentCongestedSection(Byte direction) {
// 从Redis缓存中获取指定方向的交通路段数据列表
List<DcTrafficSectionData> dcTrafficSectionDataCaches = getDcTrafficSectionDataRedisCache(direction);
// 过滤掉时间错误的交通数据
processStaleTrafficSectionData(dcTrafficSectionDataCaches);
// 移除非毫米波雷达设备类型的交通数据
dcTrafficSectionDataCaches.removeIf(data -> !Objects.equals(data.getDeviceType(), DeviceTypeConstants.MILLIMETER_WAVE_RADAR));
// 分析交通数据,计算出当前拥堵的路段列表并返回
return trafficAnalysis.calculateCongestedSection(dcTrafficSectionDataCaches);
}
/** /**
* 恢复每日缓存的函数 * 恢复每日缓存的函数
* 该方法尝试从物联平台获取所有设备信息并对这些信息进行处理 * 该方法尝试从物联平台获取所有设备信息并对这些信息进行处理
@ -320,6 +362,36 @@ public class DcTrafficStatisticsServiceImpl
return new ArrayList<>(dcTrafficSectionDataMap.values()); return new ArrayList<>(dcTrafficSectionDataMap.values());
} }
/**
* 过滤掉时间错误的交通路段数据并更新数据的统计时间为当前时间
* 该方法会遍历交通路段数据列表移除统计时间早于20分钟前的数据并将其它数据的统计时间更新为当前时间
*
* @param dcTrafficSectionDataList 交通路段数据列表列表中每一项包含一个交通路段的统计数据
*/
public void processStaleTrafficSectionData(List<DcTrafficSectionData> dcTrafficSectionDataList) {
// 计算20分钟前的时间戳
Instant twentyMinutesAgo = Instant.now().minus(20, ChronoUnit.MINUTES);
// 获取当前时间
Instant currentTime = Instant.now();
// 遍历交通路段数据列表
dcTrafficSectionDataList.removeIf(data -> {
// 获取数据的统计时间
Instant dataStatisticalTime = data.getStatisticalDate().toInstant();
// 如果数据的统计时间早于20分钟前,则移除该数据,并记录日志
if (dataStatisticalTime.isBefore(twentyMinutesAgo)) {
logger.error("过滤掉时间错误的交通路段数据,已移除:" + data);
return true; // 移除该元素
}
// 更新数据的统计时间为当前时间
data.setStatisticalDate(Date.from(currentTime)); // 直接使用Instant对象
return false; // 保留该元素
});
}
/** /**
* 根据方向获取交通数据 * 根据方向获取交通数据
* *

151
zc-business/src/main/java/com/zc/business/statistics/handler/TrafficAnalysis.java

@ -5,10 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.zc.business.constant.RedisKeyConstants; import com.zc.business.constant.RedisKeyConstants;
import com.zc.business.constant.StakeMarkConstant; import com.zc.business.constant.StakeMarkConstant;
import com.zc.business.domain.DcRoadSection; import com.zc.business.domain.*;
import com.zc.business.domain.DcTrafficMetricsData;
import com.zc.business.domain.DcTrafficSectionData;
import com.zc.business.domain.DcTrafficVolumeForecast;
import com.zc.business.enums.*; import com.zc.business.enums.*;
import com.zc.business.request.DcTrafficMetricsDataRequest; import com.zc.business.request.DcTrafficMetricsDataRequest;
import com.zc.business.service.DcTrafficVolumeForecastService; import com.zc.business.service.DcTrafficVolumeForecastService;
@ -303,9 +300,6 @@ public class TrafficAnalysis {
return (int) Math.round(averageSaturationDegree); return (int) Math.round(averageSaturationDegree);
} }
/** /**
* 计算路段饱和度 * 计算路段饱和度
* *
@ -423,14 +417,17 @@ public class TrafficAnalysis {
// 遍历排序后的路段数据,计算每个路段的拥堵里程,并累加到总拥堵里程中 // 遍历排序后的路段数据,计算每个路段的拥堵里程,并累加到总拥堵里程中
for (DcTrafficSectionData dcTrafficSectionData : sortedList) { for (DcTrafficSectionData dcTrafficSectionData : sortedList) {
int averageSpeed = dcTrafficSectionData.getAverageSpeed(); int averageSpeed = dcTrafficSectionData.getAverageSpeed();
int stakeMark = dcTrafficSectionData.getStakeMark(); int stakeMark = dcTrafficSectionData.getStakeMark();
// 对于不拥堵的路段,累加之前计算的默认拥堵距离 // 对于不拥堵的路段,累加之前计算的默认拥堵距离
if (!ChannelCongestionLevelEnum.isMediumOrSevereCongestion(averageSpeed)) { if (!ChannelCongestionLevelEnum.isMediumOrSevereCongestion(averageSpeed, dcTrafficSectionData.getTrafficVolume())) {
totalCongestionDistance.addAndGet(defaultCongestionDistance); int congestionDistance = Math.abs(stakeMark - previousStakeMark);
totalCongestionDistance.addAndGet(Math.min(congestionDistance, defaultCongestionDistance));
previousStakeMark = stakeMark; previousStakeMark = stakeMark;
defaultCongestionDistance = 0; defaultCongestionDistance = 0;
previousAverageSpeed = 0;
continue; continue;
} }
@ -442,17 +439,26 @@ public class TrafficAnalysis {
int congestionDistance = Math.abs(stakeMark - previousStakeMark); int congestionDistance = Math.abs(stakeMark - previousStakeMark);
if (congestionDistance > StakeMarkConstant.MAX_INTERVAL_MILLIMETER_WAVE_RADAR) { if (congestionDistance > StakeMarkConstant.MAX_INTERVAL_MILLIMETER_WAVE_RADAR) {
totalCongestionDistance.addAndGet(defaultCongestionDistance); totalCongestionDistance.addAndGet(defaultCongestionDistance);
defaultCongestionDistance = 0;
} else { } else {
totalCongestionDistance.addAndGet(congestionDistance); totalCongestionDistance.addAndGet(congestionDistance);
// 如果当前路段被计算过,则累加拥堵路段数量 // 如果当前路段被计算过,则累加拥堵路段数量
congestedSectionQuantity.addAndGet(1); congestedSectionQuantity.addAndGet(1);
} }
} else {
// 累加拥堵路段数量
congestedSectionQuantity.addAndGet(1);
} }
// 更新辅助变量以备后续计算 // 更新辅助变量以备后续计算
previousStakeMark = stakeMark; previousStakeMark = stakeMark;
previousAverageSpeed = averageSpeed; previousAverageSpeed = averageSpeed;
} }
if (defaultCongestionDistance != 0) {
totalCongestionDistance.addAndGet(defaultCongestionDistance);
}
}); });
// 计算并返回路网整体的拥堵指数 // 计算并返回路网整体的拥堵指数
@ -465,8 +471,6 @@ public class TrafficAnalysis {
return metricsData; return metricsData;
} }
/** /**
* 计算路段交通量 * 计算路段交通量
* *
@ -624,7 +628,7 @@ public class TrafficAnalysis {
// 如果找到对应的路段,则将交通数据添加到该路段的数据列表中。 // 如果找到对应的路段,则将交通数据添加到该路段的数据列表中。
if (index > -1) { if (index > -1) {
DcRoadSection dcRoadSection = sortedRoadSections.get(index); DcRoadSection dcRoadSection = sortedRoadSections.get(index);
List<DcTrafficSectionData> dcTrafficSectionList = sectionDataMap.putIfAbsent(dcRoadSection.getId(), new ArrayList<>()); List<DcTrafficSectionData> dcTrafficSectionList = sectionDataMap.computeIfAbsent(dcRoadSection.getId(), k -> new ArrayList<>());
dcTrafficSectionList.add(trafficSectionData); dcTrafficSectionList.add(trafficSectionData);
} }
} }
@ -633,4 +637,127 @@ public class TrafficAnalysis {
} }
/**
* 计算拥堵路段数据
*
* @param trafficSectionDataList 交通路段数据列表包含各个路段的平均速度交通量和行驶方向等信息
* @return 拥堵路段数据列表详细记录了每个拥堵路段的起始桩号结束桩号平均速度和行驶方向等信息
*/
public List<DcCongestedSectionData> calculateCongestedSection(List<DcTrafficSectionData> trafficSectionDataList) {
if (trafficSectionDataList == null || trafficSectionDataList.isEmpty()) {
return Collections.emptyList();
}
// 根据行驶方向对交通数据进行分组
Map<Byte, List<DcTrafficSectionData>> groupedByDirection = trafficSectionDataList.stream()
.collect(Collectors.groupingBy(DcTrafficSectionData::getDirection));
List<DcCongestedSectionData> dcCongestedSectionDataList = new ArrayList<>();
groupedByDirection.forEach((directionData, trafficSectionList) -> {
List<DcTrafficSectionData> sortedList;
// 根据行驶方向,对交通路段数据进行排序,上行方向逆序,下行方向正序
if (directionData.equals(LaneDirectionEnum.UPWARD.getValue())) {
sortedList = trafficSectionList.stream()
.sorted(Comparator.comparing(DcTrafficSectionData::getStakeMark).reversed())
.collect(Collectors.toList());
} else {
sortedList = trafficSectionList.stream()
.sorted(Comparator.comparing(DcTrafficSectionData::getStakeMark))
.collect(Collectors.toList());
}
int previousStakeMark = 0;
int previousAverageSpeed = 0;
int defaultCongestionDistance = 0;
int trafficVolume = 0;
ChannelCongestionLevelEnum previousCongestionLevel = null;
DcCongestedSectionData congestedSectionData = null;
// 遍历排序后的路段数据,计算每个路段的拥堵里程,并累加到总拥堵里程中
for (DcTrafficSectionData dcTrafficSectionData : sortedList) {
int averageSpeed = dcTrafficSectionData.getAverageSpeed();
int stakeMark = dcTrafficSectionData.getStakeMark();
trafficVolume = dcTrafficSectionData.getTrafficVolume();
boolean isCongestion = ChannelCongestionLevelEnum.isCongestion(averageSpeed, trafficVolume);
// 判断当前路段是否拥堵,如果不是拥堵路段且前一个路段是拥堵的,则更新拥堵里程并创建新的拥堵路段数据
if (!isCongestion && previousAverageSpeed != 0) {
int congestionDistance = Math.abs(stakeMark - previousStakeMark);
if (congestionDistance > defaultCongestionDistance) {
if (directionData.equals(LaneDirectionEnum.UPWARD.getValue())) {
previousStakeMark -= defaultCongestionDistance;
} else {
previousStakeMark += defaultCongestionDistance;
}
congestedSectionData.setEndStakeMark(previousStakeMark);
} else {
previousStakeMark = stakeMark;
congestedSectionData.setEndStakeMark(stakeMark);
}
congestedSectionData.setEndStakeMark(previousStakeMark);
previousCongestionLevel = ChannelCongestionLevelEnum.fromSpeed(averageSpeed, trafficVolume);
previousAverageSpeed = 0;
defaultCongestionDistance = 0;
continue;
}
if (!isCongestion) {
continue;
}
// 处理同等级别拥堵的路段,计算拥堵距离,更新拥堵路段的结束桩号
if (ChannelCongestionLevelEnum.isWithinLevel(averageSpeed, previousCongestionLevel)) {
int congestionDistance = Math.abs(stakeMark - previousStakeMark);
// 对于超出最大间隔的拥堵路段,更新拥堵里程
if (congestionDistance > StakeMarkConstant.MAX_INTERVAL_MILLIMETER_WAVE_RADAR) {
if (directionData.equals(LaneDirectionEnum.UPWARD.getValue())) {
previousStakeMark -= defaultCongestionDistance;
} else {
previousStakeMark += defaultCongestionDistance;
}
congestedSectionData.setEndStakeMark(previousStakeMark);
} else {
previousStakeMark = stakeMark;
congestedSectionData.setEndStakeMark(stakeMark);
}
} else {
// 如果当前路段拥堵级别改变,创建新的拥堵路段数据,并更新起始桩号和默认拥堵距离
congestedSectionData = new DcCongestedSectionData();
congestedSectionData.setAverageSpeed(averageSpeed);
congestedSectionData.setDirection(directionData);
congestedSectionData.setStartStakeMark(stakeMark);
dcCongestedSectionDataList.add(congestedSectionData);
previousStakeMark = stakeMark;
defaultCongestionDistance = ChannelCongestionLevelEnum.fromSpeed(averageSpeed).getDefaultCongestionDistance();
}
previousAverageSpeed = averageSpeed;
previousCongestionLevel = ChannelCongestionLevelEnum.fromSpeed(averageSpeed);
}
// 处理遍历完所有路段后的拥堵状态,确保最后一个拥堵路段也被记录
boolean isCongestion = ChannelCongestionLevelEnum.isCongestion(previousAverageSpeed, trafficVolume);
if (isCongestion && congestedSectionData != null) {
// 根据行驶方向更新拥堵里程
if (directionData.equals(LaneDirectionEnum.UPWARD.getValue())) {
previousStakeMark -= defaultCongestionDistance;
} else {
previousStakeMark += defaultCongestionDistance;
}
congestedSectionData.setEndStakeMark(previousStakeMark);
}
});
return dcCongestedSectionDataList;
}
} }

24
zc-business/src/main/resources/mapper/business/DcEmergencyPlansMapper.xml

@ -15,18 +15,17 @@
<result property="triggeringCondition" column="triggering_condition"/> <result property="triggeringCondition" column="triggering_condition"/>
<result property="controllableDevice" column="controllable_device"/> <result property="controllableDevice" column="controllable_device"/>
<result property="controlCommand" column="control_command"/> <result property="controlCommand" column="control_command"/>
<result property="eventCategory" column="event_category"/>
<collection property="dcExecuteAction" ofType="DcExecuteAction"> <collection property="dcExecuteAction" ofType="DcExecuteAction">
<result property="id" column="action_id"/> <result property="id" column="action_id"/>
<result property="emergencyPlansId" column="action_emergency_plans_id"/> <result property="emergencyPlansId" column="action_emergency_plans_id"/>
<result property="deviceType" column="action_device_type"/> <result property="deviceType" column="action_device_type"/>
<result property="actionType" column="action_action_type"/>
<result property="createTime" column="action_create_time"/> <result property="createTime" column="action_create_time"/>
<result property="updateTime" column="action_update_time"/> <result property="updateTime" column="action_update_time"/>
<result property="searchRule" column="action_search_rule"/> <result property="searchRule" column="action_search_rule"/>
<result property="number" column="action_number"/> <result property="number" column="action_number"/>
<result property="deviceList" column="action_device_list"/> <result property="deviceList" column="action_device_list"/>
<result property="otherConfig" column="action_other_config"/> <result property="executeConfig" column="action_execute_config"/>
<result property="recoverConfig" column="action_recover_config"/>
</collection> </collection>
</resultMap> </resultMap>
@ -43,7 +42,6 @@
<if test="triggeringCondition != null and triggeringCondition != ''">triggering_condition,</if> <if test="triggeringCondition != null and triggeringCondition != ''">triggering_condition,</if>
<if test="controllableDevice != null and controllableDevice != ''">controllable_device,</if> <if test="controllableDevice != null and controllableDevice != ''">controllable_device,</if>
<if test="controlCommand != null and controlCommand != ''">control_command,</if> <if test="controlCommand != null and controlCommand != ''">control_command,</if>
<if test="eventCategory != null">event_category,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="planName != null and planName != ''">#{planName},</if> <if test="planName != null and planName != ''">#{planName},</if>
@ -55,7 +53,6 @@
<if test="triggeringCondition != null and triggeringCondition != ''">#{triggeringCondition},</if> <if test="triggeringCondition != null and triggeringCondition != ''">#{triggeringCondition},</if>
<if test="controllableDevice != null and controllableDevice != ''">#{controllableDevice},</if> <if test="controllableDevice != null and controllableDevice != ''">#{controllableDevice},</if>
<if test="controlCommand != null and controlCommand != ''">#{controlCommand},</if> <if test="controlCommand != null and controlCommand != ''">#{controlCommand},</if>
<if test="eventCategory != null">#{eventCategory},</if>
</trim> </trim>
</insert> </insert>
@ -68,8 +65,7 @@
device_type = #{deviceType}, device_type = #{deviceType},
triggering_condition = #{triggeringCondition}, triggering_condition = #{triggeringCondition},
controllable_device = #{controllableDevice}, controllable_device = #{controllableDevice},
control_command = #{controlCommand}, control_command = #{controlCommand}
event_category = #{eventCategory}
where id = #{id} where id = #{id}
</update> </update>
@ -90,16 +86,16 @@
t1.triggering_condition, t1.triggering_condition,
t1.controllable_device, t1.controllable_device,
t1.control_command, t1.control_command,
t1.event_category,
t2.id as action_id, t2.id as action_id,
t2.emergency_plans_id as action_emergency_plans_id, t2.emergency_plans_id as action_emergency_plans_id,
t2.device_type as action_device_type, t2.device_type as action_device_type,
t2.action_type as action_action_type,
t2.create_time as action_create_time, t2.create_time as action_create_time,
t2.update_time as action_update_time,
t2.search_rule as action_search_rule, t2.search_rule as action_search_rule,
t2.`number` as action_number, t2.`number` as action_number,
t2.device_list as action_device_list, t2.device_list as action_device_list,
t2.other_config as action_other_config t2.execute_config as action_execute_config,
t2.recover_config as action_recover_config
from dc_emergency_plans t1 from dc_emergency_plans t1
left join dc_execute_action t2 left join dc_execute_action t2
on t1.id = t2.emergency_plans_id on t1.id = t2.emergency_plans_id
@ -115,13 +111,11 @@
t1.device_type, t1.device_type,
t1.triggering_condition, t1.triggering_condition,
t1.controllable_device, t1.controllable_device,
t1.control_command, t1.control_command
t1.event_category
from dc_emergency_plans t1 from dc_emergency_plans t1
<where> <where>
<if test="planName != null and planName != ''"> and plan_name like concat('%', #{planName}, '%')</if> <if test="planName != null and planName != ''"> and plan_name like concat('%', #{planName}, '%')</if>
<if test="eventType != 0 "> and event_type = #{eventType}</if> <if test="eventType != 0 "> and event_type = #{eventType}</if>
<if test="eventCategory != 0"> and event_category = #{eventCategory}</if>
</where> </where>
order by t1.id desc order by t1.id desc
</select> </select>
@ -133,12 +127,12 @@
<select id="selectDcEmergencyPlansByEventType" parameterType="dcEvent" resultMap="DcEmergencyPlansResult"> <select id="selectDcEmergencyPlansByEventType" parameterType="dcEvent" resultMap="DcEmergencyPlansResult">
<include refid="selectDcEmergencyPlansListAll"/> <include refid="selectDcEmergencyPlansListAll"/>
where t1.event_type = #{eventType} and t1.event_category = 1 where t1.event_type = #{eventType}
</select> </select>
<select id="selectDcEmergencyPlansByWarningType" parameterType="int" resultMap="DcEmergencyPlansResult"> <select id="selectDcEmergencyPlansByWarningType" parameterType="int" resultMap="DcEmergencyPlansResult">
<include refid="selectDcEmergencyPlansListAll"/> <include refid="selectDcEmergencyPlansListAll"/>
where t1.event_type = #{eventType} and t1.event_category = 2 where t1.event_type = #{eventType}
</select> </select>

28
zc-business/src/main/resources/mapper/business/DcExecuteActionMapper.xml

@ -10,24 +10,26 @@
(emergency_plans_id, (emergency_plans_id,
device_type, device_type,
action_type,
create_time, create_time,
search_rule, search_rule,
`number`, `number`,
device_list, device_list,
other_config execute_config,
recover_config
) )
values values
<foreach collection="list" item="item" separator=","> <foreach collection="list" item="item" separator=",">
(#{item.emergencyPlansId}, (
#{item.emergencyPlansId},
#{item.deviceType}, #{item.deviceType},
#{item.actionType},
#{item.createTime}, #{item.createTime},
#{item.searchRule}, #{item.searchRule},
#{item.number}, #{item.number},
#{item.deviceList}, #{item.deviceList},
#{item.otherConfig}) #{item.executeConfig},
#{item.recoverConfig}
)
</foreach> </foreach>
</insert> </insert>
@ -47,12 +49,6 @@
then #{item.deviceType} then #{item.deviceType}
</foreach> </foreach>
</trim> </trim>
<trim prefix="action_type =case" suffix="end,">
<foreach collection="list" item="item" index="index">
when id=#{item.id}
then #{item.actionType}
</foreach>
</trim>
<trim prefix="update_time =case" suffix="end,"> <trim prefix="update_time =case" suffix="end,">
<foreach collection="list" item="item" index="index"> <foreach collection="list" item="item" index="index">
when id=#{item.id} when id=#{item.id}
@ -77,10 +73,16 @@
then #{item.deviceList} then #{item.deviceList}
</foreach> </foreach>
</trim> </trim>
<trim prefix="other_config =case" suffix="end,"> <trim prefix="execute_config =case" suffix="end,">
<foreach collection="list" item="item" index="index">
when id=#{item.id}
then #{item.executeConfig}
</foreach>
</trim>
<trim prefix="recover_config =case" suffix="end,">
<foreach collection="list" item="item" index="index"> <foreach collection="list" item="item" index="index">
when id=#{item.id} when id=#{item.id}
then #{item.otherConfig} then #{item.recoverConfig}
</foreach> </foreach>
</trim> </trim>
</trim> </trim>

Loading…
Cancel
Save