diff --git a/Jenkinsfile b/Jenkinsfile index 8a26772a371f27a6d2adb97cbb7e81945628659e..b1b8b39ddb47b2755b013cd98dfd09ed5101e121 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -63,6 +63,7 @@ pipeline { sh 'tar -zcvf Configdist.tar.gz dist' sh 'cp -r ../../openatc-doc/configserver/UserManual dist' sh 'tar -zcvf ConfigWithUserManual.tar.gz dist' + archiveArtifacts artifacts: "Configdist.tar.gz", fingerprint: true } } } @@ -85,6 +86,7 @@ pipeline { sh 'cp -r dist ../../OpenATC-Admin-server/agent/src/main/resources/static' // sh 'cp -r ../../openatc-doc/UserManual ../../OpenATC-Admin-server/agent/src/main/resources/static' sh 'tar -zcvf admindist.tar.gz dist' + archiveArtifacts artifacts: "admindist.tar.gz", fingerprint: true } } } @@ -100,14 +102,18 @@ pipeline { steps { dir("${env.WORKSPACE}/OpenATC-Admin-server") { sh 'mvn clean install' + sh 'ls' + sh 'cp -r target/agent.jar ./' + sh 'ls' + //archiveArtifacts artifacts: "agent.jar", fingerprint: true } } } - stage('Publish') { - steps { - archiveArtifacts artifacts: 'OpenATC-Admin-server/target/agent.jar, OpenATC-Admin-ui/OpenATC-Configer-web/Configdist.tar.gz,OpenATC-Admin-ui/OpenATC-Configer-web/ConfigWithUserManual.tar.gz, OpenATC-Admin-ui/OpenATC-Admin-web/admindist.tar.gz', followSymlinks: false, onlyIfSuccessful: true - } - } + // stage('Publish') { + // steps { + // archiveArtifacts artifacts: 'OpenATC-Admin-server/target/agent.jar, OpenATC-Admin-ui/OpenATC-Configer-web/Configdist.tar.gz,OpenATC-Admin-ui/OpenATC-Configer-web/ConfigWithUserManual.tar.gz, OpenATC-Admin-ui/OpenATC-Admin-web/admindist.tar.gz', followSymlinks: false, onlyIfSuccessful: true + // } + // } stage('Building image & push') { steps { @@ -116,6 +122,9 @@ pipeline { echo "building img for branch: ${env.BRANCH_NAME} and tag: ${env.TAG_NAME}" if ( env.TAG_NAME != null ){ sh "docker buildx build --platform linux/amd64,linux/arm64/v8 -t a.watchword.space:55000/openatc/openatc-admin:${env.TAG_NAME} --push ." + // sh label:"pull image",script:"docker pull a.watchword.space:55000/openatc/openatc-admin:${env.TAG_NAME}" + // sh label:'Artifacts image',script: "docker save -o openatc-admin:${env.TAG_NAME}.tar a.watchword.space:55000/openatc/openatc-admin:${env.TAG_NAME}" + // archiveArtifacts artifacts: "openatc-admin:${env.TAG_NAME}.tar", fingerprint: true } else if (env.BRANCH_NAME == 'master') { sh "docker buildx build --platform linux/amd64,linux/arm64/v8 -t a.watchword.space:55000/openatc/openatc-admin:latest --push ." } else { diff --git a/OpenATC-Admin-server/agent/Dockerfile b/OpenATC-Admin-server/agent/Dockerfile index 5035c59e70145cff945aa82ac6fedf4b6edefafc..527927e38354252619562bd1ee60669c065cd60b 100644 --- a/OpenATC-Admin-server/agent/Dockerfile +++ b/OpenATC-Admin-server/agent/Dockerfile @@ -33,6 +33,7 @@ ENV QY_DEVICE_STATUS_REPORT_ENABLE=false ENV SSLKEY_PATH=classpath:kdstore.p12 ENV SSLKEY_PWD=kedacom123 ENV DATE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiIsImFkbWluIjp0cnVlLCJleHAiOjQxMDIzMjk2MDAsIm5iZiI6MTczMjk4MjQwMCwiaWF0IjoxNzM0NTkzOTc1fQ.vuYB10NuZiwVYhHHNrBGtTmTUuk0s_kYkQwZSysT4I0 +ENV CYCLE_FACTOR=2 RUN ln -sf /usr/share/zoneinfo/{TZ} /etc/localtime && echo "{TZ}" > /etc/timezone diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/RestTemplateConfig.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/RestTemplateConfig.java index ac400e16f72939f65a9a79090ce22d5ef22e85fc..998e2fa6767e13af1404e849fe63b40b37347f87 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/RestTemplateConfig.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/RestTemplateConfig.java @@ -35,6 +35,7 @@ public class RestTemplateConfig { return factory; } + // 忽略HTTPS证书认证 public static HttpComponentsClientHttpRequestFactory generateHttpRequestFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/ShiroConfig.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/ShiroConfig.java index 4213760b6c040ba14b40473bee7ec218f2077bc8..fffe7a246a9b8c138f173801b16468e5a07c9efe 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/ShiroConfig.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/config/ShiroConfig.java @@ -76,6 +76,7 @@ public class ShiroConfig { filterChainDefinitionMap.put("/servConfig.json", "anon"); filterChainDefinitionMap.put("/LRRoadConfig.json","anon"); filterChainDefinitionMap.put("/favicon.ico", "anon"); + filterChainDefinitionMap.put("/CrossRoadsSvg.svg", "anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); @@ -84,10 +85,12 @@ public class ShiroConfig { filterChainDefinitionMap.put("/auth/login", "anon"); filterChainDefinitionMap.put("/auth/user/modifypassword", "anon"); filterChainDefinitionMap.put("/auth/user/modifystatus", "anon"); + filterChainDefinitionMap.put("/devs/siteid/**", "anon"); filterChainDefinitionMap.put("/swagger-ui/**", "anon"); filterChainDefinitionMap.put("/swagger-resources/**", "anon"); filterChainDefinitionMap.put("/v3/api-docs", "anon"); filterChainDefinitionMap.put("/ws","anon"); + filterChainDefinitionMap.put("/ws/subs","anon"); filterChainDefinitionMap.put("/oauth2/**", "anon"); filterChainDefinitionMap.put("/**", "jwt"); } diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/DevController.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/DevController.java index 65f1888ebc34934126abfa60d26fb0bcbe89f83a..93fa499d5dd607278c51eb9fea5c47fab4a2e413 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/DevController.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/DevController.java @@ -23,7 +23,6 @@ import com.openatc.agent.service.impl.WebOperationCollector; import com.openatc.agent.service.impl.WebOperationRecordExtractor; import com.openatc.comm.data.MessageData; import com.openatc.core.common.IErrorEnumImplOuter; -import com.openatc.core.model.InnerError; import com.openatc.core.model.RESTRet; import com.openatc.core.model.RESTRetBase; import com.openatc.core.util.MyHttpUtil; @@ -131,6 +130,34 @@ public class DevController { return RESTRetUtils.successObj(mDao.getAscsByType(type)); } + // 保存路口有效方向 + @PostMapping(value = "/devs/validdirections/{agentid}") + public RESTRetBase saveValidDirection(@PathVariable String agentid, @RequestBody DeviceCommonData commonData) { + int count = featureService.saveDeviceCommonData(agentid, commonData); + return RESTRetUtils.successObj(count); + } + + // 查询路口的有效方向 + @GetMapping(value = "/devs/validdirections/{agentid}") + public RESTRetBase getDeviceCommonData(@PathVariable String agentid) { + DeviceCommonData commonData = featureService.getDeviceCommonData(agentid); + return RESTRetUtils.successObj(commonData); + } + + // 保存路口并线方向 + @PostMapping(value = "/devs/mergedirections/{agentid}") + public RESTRetBase saveMergeDirection(@PathVariable String agentid, @RequestBody DeviceCommonData commonData) { + int count = featureService.saveMergeDirections(agentid, commonData); + return RESTRetUtils.successObj(count); + } + + // 获取路口并线 + @GetMapping(value = "/devs/mergedirections/{agentid}") + public RESTRetBase saveMergeDirection(@PathVariable String agentid) { + DeviceCommonData commonData = featureService.getDeviceMergeDirection(agentid); + return RESTRetUtils.successObj(commonData); + } + @PostMapping(value = "/devs/range") public RESTRetBase getDevsRange(@RequestBody JsonObject jsonObject) { // return devService.getRangeDevs(jsonObject); @@ -221,6 +248,7 @@ public class DevController { }else if (temp == -2) { return RESTRetUtils.errorObj(IErrorEnumImplOuter.E_8012); }else { + deviceCache.updateCache(); return RESTRetUtils.successObj(ascs); } } diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/FixedTimePlanController.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/FixedTimePlanController.java index 86fafc3b270f7b2b9c9aa8290ef8ce4012a3e997..059422add0b81906ab03331796f7e5ba876a9c11 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/FixedTimePlanController.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/FixedTimePlanController.java @@ -1,13 +1,15 @@ package com.openatc.agent.controller; -import com.alibaba.fastjson.JSON; +import com.google.gson.Gson; import com.openatc.core.model.RESTRetBase; +import com.openatc.core.util.GsonUtil; import com.openatc.core.util.RESTRetUtils; import com.openatc.optimize.fixedtimeplan.config.cross.CrossConfig; import com.openatc.optimize.fixedtimeplan.model.control.Cross; import com.openatc.optimize.fixedtimeplan.model.control.FixedtimePlan; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -24,26 +26,14 @@ import java.util.HashMap; @RequestMapping("/fixedtimeplan") @Slf4j public class FixedTimePlanController { + @Value("${agent.optimize.cycle.factor}") + private double cFactor; + private Gson gson = GsonUtil.getInstance(); @PostMapping("") - /* - @ApiOperation(value = "post 根据流量计算最优固定配时方案",notes = "根据流量计算最优固定配时方案") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "路口名称", dataType = "String", paramType = "path", required = false), - @ApiImplicitParam(name = "agentid", value = "信号机编号", dataType = "String", paramType = "path", required = false), - @ApiImplicitParam(name = "red", value = "红灯时间, 默认2秒", dataType = "int", paramType = "path", defaultValue = "2", required = true), - @ApiImplicitParam(name = "yellow", value = "黄灯时间, 默认3秒", dataType = "int", paramType = "path", defaultValue = "3", required = true), - @ApiImplicitParam(name = "loss", value = "车辆启动损失时间, 默认3秒", dataType = "int", paramType = "path", defaultValue = "3", required = false), - @ApiImplicitParam(name = "rings", value = "环描述 num: 1 sequence: [1, 2, 5, 6], 环编号和相序", dataType = "String", paramType = "path", required = true), - @ApiImplicitParam(name = "barrier", value = "屏障描述,id: 1 phases: [[1, 2], [3, 4]], 屏障编号和所属相位" , dataType = "String", paramType = "path", required = true), - @ApiImplicitParam(name = "phases", value = "相位描述 id: 5 flowperhour: 200 saturation: 1650 相位编号, 小时流量, 饱和流量", dataType = "String", paramType = "path", required = true), - - - }) - - */ public RESTRetBase calcFixedTimePlan(@RequestBody CrossConfig crossConfig){ - log.info("CrossConfig:{}", crossConfig); + log.info("CrossConfig:{}", gson.toJson(crossConfig) ); + crossConfig.init(); Cross cross = Cross.builder() .agentid(crossConfig.getAgentid()) @@ -51,14 +41,8 @@ public class FixedTimePlanController { .phaseMap(new HashMap<>()) .build(); cross.updatePhaseMap(); - - - - FixedtimePlan fixedtimePlan = cross.optimize(); - log.info("cross:{}", JSON.toJSONString(cross)); - log.info("fixedtimeplan:{}", JSON.toJSONString(fixedtimePlan)); + FixedtimePlan fixedtimePlan = cross.optimize(cFactor); return RESTRetUtils.successObj(fixedtimePlan); - } @PostMapping("/assigncycleequally") @@ -71,10 +55,7 @@ public class FixedTimePlanController { .build(); cross.updatePhaseMap(); cross.adjustPhaseDurationAssignEqually(crossConfig.getOptcycle()); - - return RESTRetUtils.successObj(cross.createFixedtimePlan()); - } @PostMapping("/assigncycletocophase") @@ -87,13 +68,6 @@ public class FixedTimePlanController { .build(); cross.updatePhaseMap(); cross.adjustPhaseDurationAssignToCophsae(crossConfig.getOptcycle()); - - return RESTRetUtils.successObj(cross.calcFixedtimePlan()); - } - - - - } diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/ServerController.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/ServerController.java index f0f9f8a9d96e061cc5f382f631170a2ac9e39c88..f4329b963b10762a3bf8665dc28b241a07c9e1b7 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/ServerController.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/ServerController.java @@ -220,65 +220,115 @@ public class ServerController { */ @Scheduled(fixedRate = 1000) private void updatePatternCountDown(){ - try{ - for(MessageData md : ascDao.getStatusPatternMap().values() ){ - + try { + for (MessageData md : ascDao.getStatusPatternMap().values()){ JsonObject mdo = md.getData().getAsJsonObject(); - if(mdo.get("current_stage") == null) - return; - - int control = mdo.get("control").getAsInt(); - int patternid = 0; - if( mdo.get("patternid") != null ) patternid = mdo.get("patternid").getAsInt(); - int current_stage = mdo.get("current_stage").getAsInt(); - -// int curTime = mdo.get("curTime").getAsInt(); - + StatusPattern statusPattern = gson.fromJson(mdo, StatusPattern.class); + if (statusPattern == null) return; + if (statusPattern.getCurrent_stage() == null) return; + Integer patternid = statusPattern.getPatternid(); + // 特殊控制不存在控制方案 + if (patternid == null) return; CountDownPattern cdPattern = ascDao.cdPatternMap.get(md.getAgentid()); - if( cdPattern == null ) { - // 初始化 - cdPattern = new CountDownPattern(); + if (cdPattern == null) { + List> stages = statusPattern.getStages(); + cdPattern = new CountDownPattern(stages.size()); + cdPattern.setPatternid(patternid); ascDao.cdPatternMap.put(md.getAgentid(), cdPattern); - }else{ - // 方案发生变化,清空阶段信息 - if( patternid != cdPattern.getPatternid()){ - cdPattern.getStages().clear(); - cdPattern.setControl(control); + } else { + // 方案发生变化时,如果阶段数不一致,重置阶段信息,避免多次重置 + // 方案发生变化,重置阶段信息 + if (patternid != cdPattern.getPatternid()) { + cdPattern.initStages(statusPattern.getStages().size()); cdPattern.setPatternid(patternid); } + // 当前运行的阶段数和保存的阶段数不一致时,重置阶段信息 + int savedSize = cdPattern.getStages().size(); + int currentSize = statusPattern.getStages().size(); + if (savedSize != currentSize) { + cdPattern.initStages(statusPattern.getStages().size()); + } } - // - CountDownStage cdStage = cdPattern.getStages().get(current_stage); - if( cdStage == null ){ - cdStage = new CountDownStage(); - cdStage.setStageNum( current_stage ); - cdPattern.getStages().put(current_stage,cdStage ); - } - - int lastSecStageNum = cdPattern.getCurStageNum(); - + int control = statusPattern.getControl(); + cdPattern.setControl(control); + // 实时运行方案的当前阶段 + Integer currentStage = statusPattern.getCurrent_stage(); + CountDownStage currentCountDownStage = cdPattern.getStages().get(currentStage); + // 上次保存的运行阶段 + int curStageNum = cdPattern.getCurStageNum(); // 判断阶段是否切换 - if( lastSecStageNum != current_stage){ - cdPattern.setCurStageNum( current_stage ); - cdStage.setLaststageNum(lastSecStageNum); - cdStage.setCurDuration(0); -// int split = cdStage.getSplit(); - // 更新上个阶段的绿信比 - CountDownStage lastcdStage = cdPattern.getStages().get(lastSecStageNum); - lastcdStage.setNeststageNum( current_stage ); - lastcdStage.setSplit( lastcdStage.getCurDuration() ); + if (curStageNum != currentStage) { + cdPattern.setCurStageNum(currentStage); + currentCountDownStage.setCurDuration(0); + // 更新上个阶段绿信比 + CountDownStage lastStage = cdPattern.getStages().get(curStageNum); + lastStage.setSplit(lastStage.getCurDuration()); } - - // 定时控制计算倒计时 - // 持续时间加1 - int curDuration = cdStage.getCurDuration()+1; - cdStage.setCurDuration( curDuration ); + // 定时控制计算倒计时,持续时间加1 + int curDuration = currentCountDownStage.getCurDuration() + 1; + currentCountDownStage.setCurDuration(curDuration); if( control == 5 || control == 10 || control == 11 || control == 13){ - int current_stagecd = Math.max( cdStage.getSplit() - curDuration, 0 ); + int current_stagecd = Math.max(currentCountDownStage.getSplit() - curDuration, 0); cdPattern.setCurStageCd( current_stagecd ); mdo.addProperty("current_stagecd",current_stagecd); } + // ########################################################## +// if(mdo.get("current_stage") == null) +// return; +// +// int control = mdo.get("control").getAsInt(); +// int patternid = 0; +// if( mdo.get("patternid") != null ) patternid = mdo.get("patternid").getAsInt(); +// int current_stage = mdo.get("current_stage").getAsInt(); +// +//// int curTime = mdo.get("curTime").getAsInt(); +// +// CountDownPattern cdPattern = ascDao.cdPatternMap.get(md.getAgentid()); +// if( cdPattern == null ) { +// // 初始化 +// cdPattern = new CountDownPattern(); +// ascDao.cdPatternMap.put(md.getAgentid(), cdPattern); +// }else{ +// // 方案发生变化,清空阶段信息 +// if( patternid != cdPattern.getPatternid()){ +// cdPattern.getStages().clear(); +// cdPattern.setControl(control); +// cdPattern.setPatternid(patternid); +// } +// } +// // +// CountDownStage cdStage = cdPattern.getStages().get(current_stage); +// if( cdStage == null ){ +// cdStage = new CountDownStage(); +// cdStage.setStageNum( current_stage ); +// cdPattern.getStages().put(current_stage,cdStage ); +// } +// +// int lastSecStageNum = cdPattern.getCurStageNum(); +// +// // 判断阶段是否切换 +// if( lastSecStageNum != current_stage){ +// cdPattern.setCurStageNum( current_stage ); +// cdStage.setLaststageNum(lastSecStageNum); +// cdStage.setCurDuration(0); +//// int split = cdStage.getSplit(); +// // 更新上个阶段的绿信比 +// CountDownStage lastcdStage = cdPattern.getStages().get(lastSecStageNum); +// lastcdStage.setNeststageNum( current_stage ); +// lastcdStage.setSplit( lastcdStage.getCurDuration() ); +// } +// +// // 定时控制计算倒计时 +// // 持续时间加1 +// int curDuration = cdStage.getCurDuration()+1; +// cdStage.setCurDuration( curDuration ); +// +// if( control == 5 || control == 10 || control == 11 || control == 13){ +// int current_stagecd = Math.max( cdStage.getSplit() - curDuration, 0 ); +// cdPattern.setCurStageCd( current_stagecd ); +// mdo.addProperty("current_stagecd",current_stagecd); +// } // logger.info( cdPattern.toString() ); @@ -292,23 +342,23 @@ public class ServerController { /** * 定时把方案保存进数据库,30秒 */ - @Scheduled(fixedRate = 30*1000) - private void savePattern2DB(){ - logger.warning("savePattern2DB Schedule Start!"); - - try { - List strs = new ArrayList<>(); - int size = patternsqlqueue.size(); - for(int i=0; i< size; i++){ - strs.add( patternsqlqueue.poll() ); - } - ascDao.batchUpdate(strs); - }catch (Exception e){ - logger.warning("savePattern2DB Error! " + e.getMessage()); - } - logger.warning("savePattern2DB Schedule Finish!"); - - } +// @Scheduled(fixedRate = 30*1000) +// private void savePattern2DB(){ +// logger.warning("savePattern2DB Schedule Start!"); +// +// try { +// List strs = new ArrayList<>(); +// int size = patternsqlqueue.size(); +// for(int i=0; i< size; i++){ +// strs.add( patternsqlqueue.poll() ); +// } +// ascDao.batchUpdate(strs); +// }catch (Exception e){ +// logger.warning("savePattern2DB Error! " + e.getMessage()); +// } +// logger.warning("savePattern2DB Schedule Finish!"); +// +// } // 更新数据库表dev中mode和control字段,同时更新信号机注册消息 @Scheduled(cron = "*/31 * * * * ?") @@ -358,7 +408,7 @@ public class ServerController { // 保证每次更新设备在线状态能正常完成 // loginMap中保存了所有在线的设备,可以当作在线设备的缓存 private void UpdateModeAndControl() { - int fiveMinuteFlag = 10; + int fiveMinuteFlag = 20; Map loginMap = AscsDao.getLoginMap(); logger.warning("Start Update Login Msg!" + " Dev Size:" + loginMap.size() + " ID: " + loginMap.keySet() ); @@ -393,7 +443,7 @@ public class ServerController { // 5分钟保存一次关键周期 if (savePatternIndex == fiveMinuteFlag) { - String savePatternSql = getSavePatternSql(messageDatas.get(agentid)); + String savePatternSql = getSavePatternRealtimeSql(messageDatas.get(agentid)); if (StringUtils.hasLength(savePatternSql)) { sqls.add(savePatternSql); } @@ -539,7 +589,7 @@ public class ServerController { private void updateFaultRenewTime(Set onLineDevs) { String inCond = AscsDao.getInCond(new ArrayList<>(onLineDevs)); String selectOfflineFault = String.format("select agentid,m_w_faultid from fault " + - " where agentid in %s and m_w_fault_type=901 and m_un_fault_renew_time isnull", inCond); + " where agentid in %s and m_w_fault_type=901 and m_un_fault_renew_time=0", inCond); List> unProceedFault = jdbcTemplate.queryForList(selectOfflineFault); if (!CollectionUtils.isEmpty(unProceedFault)) { Set faultIds = new HashSet<>(); @@ -606,6 +656,39 @@ public class ServerController { } + /** + * 拼接保存实时方案的sql + * @param msg + * @return + */ + private String getSavePatternRealtimeSql(MessageData msg) { + JsonObject msgdata = new JsonObject(); +// JsonArray msgphase = new JsonArray(); + + try { + // 删除不需要保存的数据 + JsonObject mdo = msg.getData().getAsJsonObject(); + + msgdata.add("mode",mdo.get("mode")); + msgdata.add("control",mdo.get("control")); + msgdata.add("patternid",mdo.get("patternid")); + msgdata.add("cycle",mdo.get("cycle")); + msgdata.add("patternoffset",mdo.get("patternoffset")); + msgdata.add("current_stage",mdo.get("current_stage")); + msgdata.add("current_phase",mdo.get("current_phase")); + + } catch (Exception e){ + logger.warning("Deal Pattern Data error!:" + e.getMessage()); + return null; + } + + String sql = String.format("INSERT INTO pattern_realtime (agentid,time,data) VALUES " + + "('%s','%s','%s')", + msg.getAgentid(),msg.getCreatetime(),msgdata.toString()); + return sql; + } + + /** * 拼接保存方案的sql * @param msg @@ -643,7 +726,7 @@ public class ServerController { cycle = msgdata.get("cycle").getAsInt(); } catch (Exception e){ - logger.warning("Deal Pattern Data error!:" + e.getMessage()); + logger.warning("Get Pattern Data error!:" + e.getMessage()); return null; } @@ -856,6 +939,10 @@ public class ServerController { jdbcTemplate.execute(sql); logger.warning("Rest Estimate Data Valid "); + sql = "delete from static_route_intersection d where d.route_id is null"; + jdbcTemplate.execute(sql); + logger.warning("Rest route_intersection Data"); + // 统计昨日设备在线数 List ascsBaseModels = ascDao.getAscs(); int online = 0; diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/TemplateController.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/TemplateController.java index e286c3f220cfbe4c1aad7b638b7b697fd9451730..2c0e89a110f2ffe53d2d10327de3873510ec27fc 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/TemplateController.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/TemplateController.java @@ -77,8 +77,28 @@ public class TemplateController { * @Description: 根据设备id获取路口类型和相位 */ @GetMapping(value = "/intersection/info/{agentid}") - public RESTRetBase getTemplate(@PathVariable String agentid) throws SocketException, ParseException { - + public RESTRetBase getTemplate(@PathVariable String agentid) { +// // 调用通信接口获取参数,设备在线,会返回最新数据,设备不在线,会尝试从数据库获取 +// MessageData mdsend = new MessageData(agentid, CosntDataDefine.getrequest, CosntDataDefine.allfeature); +// RESTRet retBase = messageService.postDevsMessage(mdsend); +// if (!retBase.isSuccess()) { +// return retBase; +// } else { +// MessageData responseData = retBase.getData(); +// // 从设备中也获取不到参数,应答参数为空 +// if (responseData == null) { +// return RESTRetUtils.errorDetialObj(E_4005, new InnerError()); +// } +// if (responseData.getData() == null) { +// return RESTRetUtils.errorDetialObj(E_4009, new InnerError()); +// } +// //返回获取路口类型和相位 +// JsonObject intersectionInfo = templateService.getIntersectionInfo(responseData.getData().getAsJsonObject()); +// return RESTRetUtils.successObj(intersectionInfo); +// } + +// 2 如果设备不在线,从数据库获取参数 +// ################################################################ // 尝试从数据库中获取 MessageData responseData = featureService.getFeatures(agentid); diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/VipRouteController.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/VipRouteController.java index 9320506cc85dd51113b207871d49a372bf148727..6575d45e87feef9a667c86cf6ed0c06893c35718 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/VipRouteController.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/controller/VipRouteController.java @@ -486,7 +486,7 @@ public class VipRouteController { private RESTRet backSelfControl(String agentid) { JsonObject selfControl = new JsonObject(); selfControl.addProperty("control", 0); - selfControl.addProperty("terminal", 1); + selfControl.addProperty("terminal", 0); MessageData selfMessage = new MessageData(agentid, CosntDataDefine.setrequest, CosntDataDefine.ControlPattern, selfControl); return messageService.postDevsMessage(selfMessage); diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/gateway/RedisService.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/gateway/RedisService.java index 0e4e1a7427dd99da83b972496b06492fa7d51e9d..b7011b79c2b4134792f27eb71df977df5ca2253a 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/gateway/RedisService.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/gateway/RedisService.java @@ -59,16 +59,6 @@ public class RedisService { return; } -// if (type.contains("asc:status/pattern")) { -// for (Session session : patternWebSocketSet.keySet()) { -// WebSocketServer webSocketServer = patternWebSocketSet.get(session); -// Set agentIds = webSocketServer.patternAgentidSet; -// if (agentIds != null && agentIds.contains(agentId)) { -// webSocketServer.sendMessage(message); -// } -// } -// } - if (type.contains("asc:status/fault")) { for (Session session : faultIncidentWebSocketSet.keySet()) { faultIncidentWebSocketSet.get(session).sendMessage(message); @@ -107,25 +97,6 @@ public class RedisService { log.info("UnSubsMessage: {}", message); } - //发送消息给订阅的客户端 -// public void sendMessageToSubsClients(String type) { -// Map fwss = WebSocketServer.getPatternWebSocketSet(); -// for (Session session : fwss.keySet()) { -// sendValuesMessage(type, fwss.get(session)); -// } -// } - -// public boolean sendValuesMessage(String type, Set deviceIds, WebSocketServer webSock) { -// Collection set = webSock.PatternTypeMap.get(type); -// return sendMessageToClient(set, type, deviceIds, webSock); -// } - - -// private boolean sendValuesMessage(String type, WebSocketServer webSock) { -// Collection set = webSock.PatternTypeMap.get(type); -// return sendMessageToClient(set, type, webSock); -// } - /** * @return 发送消息给socket diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/gateway/WebSocketSubs.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/gateway/WebSocketSubs.java new file mode 100644 index 0000000000000000000000000000000000000000..d2b5a3ecf298734977ff3c547f4ef6a9767dcf36 --- /dev/null +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/gateway/WebSocketSubs.java @@ -0,0 +1,154 @@ +package com.openatc.agent.gateway; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.openatc.agent.model.WebSocketSub; +import com.openatc.core.util.GsonUtil; +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.ReactiveSubscription; +import org.springframework.data.redis.core.ReactiveRedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.stereotype.Component; +import reactor.core.Disposable; + +import javax.annotation.PostConstruct; +import javax.websocket.*; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; + +import static com.openatc.core.common.IErrorEnumImplOuter.E_3015; + +/** + * @author zhangwenchao + * @Date 2025/4/25 + * @Describetion 根据redis中的channel,订阅channel的消息,一个websocket只能订阅一个channel + */ +@ServerEndpoint(value = "/ws/subs") +@Component +@Data +public class WebSocketSubs { + + private Logger log = LoggerFactory.getLogger(WebSocketSubs.class); + + @Autowired + private ReactiveRedisTemplate redisService; + + // 此处存放Spring boot创建的redisService + public static WebSocketSubs webSocketComponent; + + //与客户端的连接会话 + private Session session; + + // 订阅的redis channel + private Disposable subscription = null; + private String channel; + Gson gson = GsonUtil.getInstance(); + + @PostConstruct + public void init() { + WebSocketSubs.webSocketComponent = this; + } + + @OnOpen + public void onOpen(Session session) { + this.session = session; + this.session.setMaxIdleTimeout( 60 * 1000); // 一分钟无消息自动关闭ws + this.session.setMaxTextMessageBufferSize( 1024 * 1024); + + log.info("onOpen URL:{},Session ID:{},OnlineCount:{}", session.getRequestURI(), session.getId()); + + } + + @OnMessage + public void onMessage(String message) { + log.info("onMessage sessionId:{},receive:{}", session.getId(), message); + + WebSocketSub wss = gson.fromJson(message, WebSocketSub.class); + if(wss == null){ + log.info("onMessage error fromJson msg: " + message); + return; + } + + String infoType = wss.getInfotype().trim(); //订阅类型 + String subscribe = wss.getSubscribe(); //开始or结束标 + String[] para = wss.getParam(); //订阅的通道 + String model = wss.getModel().trim(); + + String msg = ""; + + if( ! "redis".equals(model) || ! "channel".equals( infoType ) ){ + log.error("onMessage error:{},Session ID:{}", message, session.getId()); + return; + } + + // 订阅单个频道 + if(subscription == null){ + ChannelTopic topic1 = new ChannelTopic(para[0]); + channel = para[0]; + subscription = webSocketComponent.redisService.listenTo(topic1) + .map(ReactiveSubscription.Message::getMessage) + .subscribe(subsmessage -> { +// log.info("Received reactive message: {}", subsmessage); + // 处理消息 + sendMessage(subsmessage); + }); + }else{ + sendMessage("Already subscribed! Channel: " + channel); + } + } + + public void unsubscribe() { + if (subscription != null && !subscription.isDisposed()) { + subscription.dispose(); + log.info("Unsubscribed successfully"); + } + } + + private String getResMsg(Boolean validateToken, String infoType) { + JsonObject resMsg = new JsonObject(); +// resMsg.addProperty("model",model); + resMsg.addProperty("infotype",infoType); + resMsg.addProperty("success",validateToken); + if (validateToken) { + resMsg.addProperty("code","0"); + resMsg.addProperty("message","success"); + } else { + resMsg.addProperty("code",E_3015.getErrorCode()); + resMsg.addProperty("message",E_3015.getErrorMsg()); + } + return resMsg.toString(); + } + + @OnError + public void onError(Throwable error) throws IOException { + unsubscribe(); + log.error("onError:{},Session ID:{}", error.toString(), session.getId()); + } + + + @OnClose + public void onClose(Session session, CloseReason reason) { + unsubscribe(); + log.warn("onClose: Session ID:{}", session.getId()); + } + + + + /** + * 发送消息 + * + * @param message + */ + public synchronized void sendMessage(String message) { + try { + session.getBasicRemote().sendText(message); + } catch (Exception e) { + log.error("sendMessage Error:{},session ID:{}", e.getMessage(), session.getId()); + } + } + + +} diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/handler/AgentHandler.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/handler/AgentHandler.java index 74a999e928cd3d38b18fd4970902c33b87d420a4..05fdcb171203610dc44869c6bf5d25e6f8c503af 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/handler/AgentHandler.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/handler/AgentHandler.java @@ -17,6 +17,7 @@ import com.openatc.agent.controller.TemplateController; import com.openatc.agent.gateway.WebSocketServer; import com.openatc.agent.model.CountDownPattern; import com.openatc.agent.model.CountDownStage; +import com.openatc.agent.model.DeviceCache; import com.openatc.agent.model.Fault; import com.openatc.agent.service.*; import com.openatc.comm.data.MessageData; @@ -54,7 +55,7 @@ import static com.openatc.model.model.SystemEventDetails.*; * @ClassName AgentHandler * @Auther zhangwenchao * @CreateTime 2019/11/5 16:09 - * @Description + * @Description 收到主动上报消息的处理回调函数 */ @Component public class AgentHandler extends ICommHandler { @@ -90,6 +91,8 @@ public class AgentHandler extends ICommHandler { private TemplateController templateController; @Autowired private FeatureService featureService; + @Autowired + private DeviceCache cache; public static BlockingQueue MdQueue = new LinkedBlockingQueue<>(); private static final Map lightStatusFaultAgent = new HashMap<>(); @@ -133,7 +136,7 @@ public class AgentHandler extends ICommHandler { continue; } - // 检查消息时间 + // 检查消息时间,并设置Sts为系统当前收到的时间 Date curDate = new Date(); String curtime = DateUtil.date2esstr(curDate); msg.setSystime(curtime); @@ -150,15 +153,10 @@ public class AgentHandler extends ICommHandler { continue; } - // 获取操作类型 -// String operation = msg.getOperation(); - String agentid; // 设备的注册消息 if (login.equals(infotype)) { -// logger.info("Recv LoginMsg :" + msg ); - agentid = ascsDao.processLoginMsg(msg); if (agentid == null){ logger.warning("LoginMsg cannot find agentid! msg:" + msg); @@ -171,7 +169,7 @@ public class AgentHandler extends ICommHandler { saveAndPublishMsg(msg,loginKey,40); // 保持全息设备在线 - pushMessageToKafka("openatcstatusheartbeat",msg); + pushMessageToKafka("openatcstatusheartbeat",agentid,gson.toJson(msg)); } else { if (msg.getAgentid() != null) { @@ -186,11 +184,13 @@ public class AgentHandler extends ICommHandler { // ** 以下为消息的特殊处理 ** // 程序运行到此处,agentid仍为null,说明在注册设备完成之前收到了其他上报的消息,丢弃 if (agentid == null) continue; + String key = agenttype + ":" + infotype + ":" + agentid; // 收到方案消息,发布redis订阅,并根据用户权限,发布ws消息 if (infotype.equals("status/pattern")) { // 计算阶段倒计时 calcStageInfo(msg); + JsonElement data = msg.getData(); StatusPattern statusPattern = gson.fromJson(data, StatusPattern.class); int control = statusPattern.getControl(); @@ -220,9 +220,10 @@ public class AgentHandler extends ICommHandler { lightStatusFaultAgent.put(agentid, control); } // 更新缓存 - saveAndPublishMsg(msg,key,0); ascsDao.putMsgToStatusPatternMap(agentid,msg); String value = gson.toJson(msg); + saveAndPublishMsg(value,key,0); + // 发布websocket订阅 for (Session session : patternWebSocketSet.keySet()) { WebSocketServer webSocketServer = patternWebSocketSet.get(session); @@ -234,12 +235,12 @@ public class AgentHandler extends ICommHandler { } } // 消息推送到kafka - pushMessageToKafka(statusPatternPushTopic,msg); + pushMessageToKafka(statusPatternPushTopic,msg.getAgentid(),value); // 保存实时方案状态 - String savePatternSql = getSavePatternSql(msg); - if (StringUtils.hasLength(savePatternSql)) { - patternsqlqueue.offer(savePatternSql); - } +// String savePatternSql = getSavePatternSql(msg); +// if (StringUtils.hasLength(savePatternSql)) { +// patternsqlqueue.offer(savePatternSql); +// } } // 上报的检测器状态 else if ( infotype.equals(detectorstatus) ){ @@ -267,14 +268,16 @@ public class AgentHandler extends ICommHandler { else faultService.processFaultMessage(msg); // 增加name字段 - JsonObject finalMsg = gson.toJsonTree(msg).getAsJsonObject(); - AscsBaseModel ascsFromCache = ascsDao.getAscsFromCache(agentid); - if (ascsFromCache != null) { - String name = ascsFromCache.getName(); - finalMsg.addProperty("name", name); +// AscsBaseModel ascsFromCache = ascsDao.getAscsFromCache(agentid); + String deviceName = cache.getDeviceName(agentid); + if (deviceName != null) { + JsonObject finalMsg = gson.toJsonTree(msg).getAsJsonObject(); +// String name = ascsFromCache.getName(); + finalMsg.addProperty("name", deviceName); + saveAndPublishMsg(finalMsg,key, 0); + } else { + saveAndPublishMsg(msg,key, 0); } - saveAndPublishMsg(msg,key, 0); - } // 收到流量消息,保存到数据库中 else if (infotype.equals("status/currentvolume")) { @@ -287,7 +290,7 @@ public class AgentHandler extends ICommHandler { // 计算获取全息车道ID processCrossTrafficData(msg); // 消息推送到kafka - pushMessageToKafka(laneFlowPushTopic,msg); + pushMessageToKafka(laneFlowPushTopic,msg.getAgentid(), gson.toJson(msg)); // String value = gson.toJson(msg); // if (isPushKafkaEnable) { // kafkaTemplate.send(laneFlowPushTopic,msg.getAgentid(),value); @@ -296,7 +299,8 @@ public class AgentHandler extends ICommHandler { } } catch (Exception e) { - logger.warning("taskExecutor Exception: " + e.getMessage()); + e.printStackTrace(); + logger.warning("taskExecutor Exception: " + e); } } @@ -307,11 +311,10 @@ public class AgentHandler extends ICommHandler { * @param topic * @param msg */ - private void pushMessageToKafka(String topic, MessageData msg) { + private void pushMessageToKafka(String topic, String agentid,String msg) { if (isPushKafkaEnable) { - String value = gson.toJson(msg); try { - kafkaTemplate.send(topic,msg.getAgentid(),value); + kafkaTemplate.send(topic,agentid,msg); } catch (KafkaException e) { logger.warning("Enable push msg to kafka,but kafka config error!"); } @@ -572,6 +575,12 @@ public class AgentHandler extends ICommHandler { String value = gson.toJson(msg); saveAndPublishMsg(value, key, expire); } + + private void saveAndPublishMsg(JsonElement msg, String key, int expire) { + if (msg == null) return; + String value = gson.toJson(msg); + saveAndPublishMsg(value, key, expire); + } /** * 将消息保存到redis,并发布 * @param msg @@ -631,48 +640,5 @@ public class AgentHandler extends ICommHandler { } } - /** - * 拼接保存方案的sql - * @param msg - * @return - */ - private String getSavePatternSql(MessageData msg) { - JsonObject msgdata = new JsonObject(); -// JsonArray msgphase = new JsonArray(); - - try { - // 删除不需要保存的数据 - JsonObject mdo = msg.getData().getAsJsonObject(); - - msgdata.add("mode",mdo.get("mode")); - msgdata.add("control",mdo.get("control")); - msgdata.add("patternid",mdo.get("patternid")); - msgdata.add("cycle",mdo.get("cycle")); - msgdata.add("patternoffset",mdo.get("patternoffset")); - msgdata.add("current_stage",mdo.get("current_stage")); - msgdata.add("current_phase",mdo.get("current_phase")); - - -// JsonArray phases = mdo.get("phase").getAsJsonArray(); -// for (JsonElement phase : phases) { -// JsonObject phosedatanew = new JsonObject(); -// -// JsonObject phosedata = phase.getAsJsonObject(); -// phosedatanew.add("id",phosedata.get("id")); -// phosedatanew.add("type",phosedata.get("type")); -// phosedatanew.add("pedtype",phosedata.get("pedtype")); -// -// msgphase.add(phosedatanew); -// } - } catch (Exception e){ - logger.warning("Deal Pattern Data error!:" + e.getMessage()); - return null; - } - - String sql = String.format("INSERT INTO pattern_realtime (agentid,time,data) VALUES " + - "('%s','%s','%s')", - msg.getAgentid(),msg.getCreatetime(),msgdata.toString()); - return sql; - } } diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/CountDownPattern.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/CountDownPattern.java index b103f7fa60259a084d53296c1d87a23957376364..6f3913e2384e8ed648edbe27175d90472e083add 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/CountDownPattern.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/CountDownPattern.java @@ -3,6 +3,7 @@ package com.openatc.agent.model; import lombok.Data; import java.util.HashMap; +import java.util.List; import java.util.Map; @Data @@ -15,6 +16,32 @@ public class CountDownPattern { int patternid; public CountDownPattern(){ - stages = new HashMap<>(); +// stages = new HashMap<>(); } - } + + public CountDownPattern(int size) { + this.initStages(size); + } + + public void initStages(int size) { + this.curStageNum = 1; + this.stages = new HashMap<>(size); + for (int stageIndex = 1; stageIndex <= size; stageIndex++) { + CountDownStage countDownStage = new CountDownStage(); + countDownStage.setStageNum(stageIndex); + if (stageIndex == 1) { + countDownStage.setLaststageNum(size); + } else { + countDownStage.setLaststageNum(stageIndex - 1); + } + if (stageIndex == size) { + countDownStage.setNeststageNum(1); + } else { + countDownStage.setNeststageNum(stageIndex + 1); + } + countDownStage.setSplit(0); + countDownStage.setCurDuration(0); + this.stages.put(stageIndex, countDownStage); + } + } +} diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/DeviceCache.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/DeviceCache.java index 9af2a4f2e6bde2839d709ae87d7ede4deae9f6d8..f2c4fabcef6eb134d2f0072f53b80114d8c5b0b3 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/DeviceCache.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/model/DeviceCache.java @@ -1,13 +1,10 @@ package com.openatc.agent.model; +import com.openatc.model.model.AscsBaseModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.logging.Logger; /** @@ -20,7 +17,7 @@ import java.util.logging.Logger; @Component public class DeviceCache { private static final Logger logger = Logger.getLogger(DeviceCache.class.getSimpleName()); - private Set deviceIds = new HashSet<>(); + private Map devs = new HashMap<>(); @Autowired private JdbcTemplate jdbcTemplate; @@ -29,18 +26,35 @@ public class DeviceCache { */ public void updateCache() { clearCache(); - String sql = String.format("select agentid from dev"); - List agentIds = jdbcTemplate.queryForList(sql, String.class); - logger.info("update device cache.device size: " + agentIds.size() +".devices: " + agentIds); - if (CollectionUtils.isEmpty(agentIds)) return; - deviceIds.addAll(agentIds); + String sql = String.format("select agentid, thirdplatformid, name, platform from dev"); + List> lvRet = jdbcTemplate.queryForList(sql); + for (Map map : lvRet) { + AscsBaseModel ascsBaseModel = new AscsBaseModel(); + ascsBaseModel.setThirdplatformid((String) map.get("thirdplatformid")); + ascsBaseModel.setPlatform((String) map.get("platform")); + ascsBaseModel.setAgentid((String) map.get("agentid")); + ascsBaseModel.setName((String) map.get("name")); + devs.put(ascsBaseModel.getAgentid(), ascsBaseModel); + } + logger.info("update device cache.device size: " + devs.size() +".devices: " + devs.keySet()); + } + + /** + * 获取设备的名称 + * @param agentId + * @return + */ + public String getDeviceName(String agentId) { + if (!hasDevice(agentId)) return null; + AscsBaseModel ascsBaseModel = devs.get(agentId); + return ascsBaseModel.getName(); } /** * 清空缓存 */ public void clearCache() { - deviceIds.clear(); + devs.clear(); } @@ -51,7 +65,7 @@ public class DeviceCache { */ public boolean hasDevice(String agentId) { if (agentId == null) return false; - return deviceIds.contains(agentId); + return devs.keySet().contains(agentId); } } diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/AscsDao.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/AscsDao.java index 7dfd4b40eb7c5bec582daf5448f27e655e20479b..196a294169aaf31336462977f0dc79a468e470b4 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/AscsDao.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/AscsDao.java @@ -43,6 +43,7 @@ import static com.openatc.comm.common.CommunicationType.OCP_PROTYPE; import static com.openatc.comm.common.CommunicationType.SCP_PROTYPE; import static com.openatc.model.model.SystemEvent.EVENT_LEVEL_URGENT; import static com.openatc.model.model.SystemEvent.TYPE_SYSTEM; +import static com.openatc.model.model.SystemEventDetails.MSG_TYPE_IP_CONFLICT; @Repository public class AscsDao { @@ -842,11 +843,13 @@ public class AscsDao { thridAgentCacheLock.lock(); String agentid = getAgentidFromThirdPartyid(thirdpartyid); - // 判断ip和设备id是否一致 - if (checkDeviceIdConflict(msg, agentid)) return null; + // 缓存中没有agentid,则表明是新的设备 if (agentid == null) { agentid = thirdpartyid; + // 判断ip和设备id是否一致 + if (checkDeviceIdConflict(msg, agentid)) return null; + DevCover devCover = gson.fromJson(msg.getData(),DevCover.class); int ret = insertAscsByReportLogin(devCover,thirdpartyid,thirdpartyid); if(ret == 0) @@ -885,6 +888,11 @@ public class AscsDao { String content = "IP为 " + currentIp + " 的设备上报设备ID冲突: " + devCover.getAgentid(); systemEvent.setContent(content); systemEvent.setType(TYPE_SYSTEM); + SystemEventDetails details = new SystemEventDetails(); + details.setAgentid(agentid); + details.setMsgtype(MSG_TYPE_IP_CONFLICT); + details.setName(cacheAscsBaseModel.getName()); + systemEvent.setDetails(details); webSocketServer.sendSystemEvent(systemEvent); // 丢弃当前消息 logger.warning("device id conflict! device id: " + devCover.getAgentid()); @@ -953,8 +961,14 @@ public class AscsDao { } String search = jsonObject.get("search").getAsString(); if( !search.isEmpty()){ - String temp = String.format("( agentid like '%%%s%%' or name like '%%%s%%' or thirdplatformid like '%%%s%%' or jsonparam::text like '%%%s%%' ) ",search,search,search,search); - whereCondition = addWhereCondition(whereCondition,temp); + if( search.contains(" ") ){//针对包含空格模糊查询的特殊处理 + String[] parts = search.split(" "); + String temp = String.format("( name like '%%%s%%' and name like '%%%s%%' ) ",parts[0],parts[0]); + whereCondition = addWhereCondition(whereCondition,temp); + }else{ + String temp = String.format("( agentid like '%%%s%%' or name like '%%%s%%' or thirdplatformid like '%%%s%%' or jsonparam::text like '%%%s%%' ) ",search,search,search,search); + whereCondition = addWhereCondition(whereCondition,temp); + } } String type = jsonObject.get("type").getAsString(); if( !type.isEmpty()){ diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/FeatureService.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/FeatureService.java index 0b2fa6fa1c943c6ee95063083d2c60d888e2d24c..9657ddae8f2986fdfb846a2ca68c9d835ac58743 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/FeatureService.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/FeatureService.java @@ -36,4 +36,12 @@ public interface FeatureService { int saveRingConfig(RingFromStage ringConfig); RingFromStage getRingConfig(String agentid); + + int saveDeviceCommonData(String agentid, DeviceCommonData commonData); + + DeviceCommonData getDeviceCommonData(String agentid); + + int saveMergeDirections(String agentid, DeviceCommonData commonData); + + DeviceCommonData getDeviceMergeDirection(String agentid); } diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/arterial/AbstractArterialTrafficControl.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/arterial/AbstractArterialTrafficControl.java index a976f771c1725669f5bcf255ca7264eb4d33070f..484e023d1d62af87fd3b4f13cf0899543749006a 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/arterial/AbstractArterialTrafficControl.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/arterial/AbstractArterialTrafficControl.java @@ -12,6 +12,7 @@ import com.openatc.optimize.fixedtimeplan.model.control.Cross; import com.openatc.optimize.fixedtimeplan.model.control.FixedtimePlan; import model.RouteIntsection; import model.RoutePara; +import org.springframework.beans.factory.annotation.Value; import java.util.HashMap; import java.util.List; @@ -26,6 +27,8 @@ import java.util.Objects; */ public abstract class AbstractArterialTrafficControl implements ArterialTrafficControl { protected OptTypeEnum optType; + @Value("${agent.optimize.cycle.factor}") + private double cFactor; /** * 计算关键路口的周期 * @param keyIntersectionId @@ -90,7 +93,7 @@ public abstract class AbstractArterialTrafficControl implements ArterialTrafficC .build(); cross.updatePhaseMap(); - FixedtimePlan fixedtimePlan = cross.optimize(); + FixedtimePlan fixedtimePlan = cross.optimize(cFactor); // 兼容阶段模式 if( pattern.getRings() == null || pattern.getRings().isEmpty() || Objects.equals(pattern.getContrloType(), "stage")) { diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/DirectionLock.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/DirectionLock.java index f401c67e71ec90ea390032f3a2008405c10fdfe1..794b369b3c0ba4eb078385d276eccecf7c9d8860 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/DirectionLock.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/DirectionLock.java @@ -60,18 +60,25 @@ public class DirectionLock extends AbstractControlRequest { // 解析出需要锁定的通道号 Set channelIds = getLockChannelIds(directionLockData, channels); // 转换为通道锁定 - ControlPattern controlPattern = getControlPattern(directionLockData, channelIds); + ControlPattern controlPattern = getControlPattern(directionLockData, channelIds, channels); requestData.setData(gson.toJsonTree(controlPattern)); return super.preProcess(requestData); } - private ControlPattern getControlPattern(LockDirection directionLockData, Set channelIds) { + private ControlPattern getControlPattern(LockDirection directionLockData, Set channelIds, List channels) { // 生成方向锁定通道信息 List channelLocks = new ArrayList<>(); - // 要锁定的通道置为绿灯 - for (Integer channelId : channelIds) { - channelLocks.add(new ChannelLock(channelId, 3)); + // 要锁定的通道置为绿灯/不锁定的置为绿灯 + for (Channel channel : channels) { + if (channelIds.contains(channel.getId())) { + channelLocks.add(new ChannelLock(channel.getId(), 3)); + } else { + channelLocks.add(new ChannelLock(channel.getId(), 1)); + } +// for (Integer channelId : channelIds) { +// channelLocks.add(new ChannelLock(channelId, 3)); +// } } // 设置方向锁定消息 diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/FeatureServiceImpl.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/FeatureServiceImpl.java index 3cbdd44ddbb4e45556d1dfd0a1b64d7e457cf7f8..262c0b5a109e67df9c29f9c0df0a06b87ba7f1fd 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/FeatureServiceImpl.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/FeatureServiceImpl.java @@ -18,6 +18,7 @@ import com.openatc.core.util.GsonUtil; import com.openatc.core.util.RESTRetUtils; import com.openatc.model.model.*; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.jdbc.core.JdbcTemplate; @@ -349,10 +350,15 @@ public class FeatureServiceImpl implements FeatureService { if( messageData ==null ) return null; - JsonElement data = messageData.getData(); - Type type = new TypeToken() {}.getType(); - Feature feature = gson.fromJson(data, type); - return feature.getLaneList(); + try{ + JsonElement data = messageData.getData(); + Type type = new TypeToken() {}.getType(); + Feature feature = gson.fromJson(data, type); + return feature.getLaneList(); + }catch (Exception e){ + logger.warning(e.getMessage() + " @ " + agentid + " data: " + messageData); + return null; + } } // 获取方案 @@ -427,4 +433,50 @@ public class FeatureServiceImpl implements FeatureService { RingFromStage ring = gson.fromJson(ringMap.get("ring").toString(),RingFromStage.class); return ring; } + + @Override + public int saveDeviceCommonData(String agentid, DeviceCommonData commonData) { + String sql = String.format("update featureall set commondata='%s' where agentid='%s'",gson.toJson(commonData), agentid); + return jdbcTemplate.update(sql); + } + + @Override + public DeviceCommonData getDeviceCommonData(String agentid) { + String sql = String.format("select commondata from featureall where agentid = '%s'", agentid); + String commonData; + try { + commonData = jdbcTemplate.queryForObject(sql, String.class); + } catch (DataAccessException e) { + logger.warning("commondata is not exist in DB! AgentId: " + agentid); + return new DeviceCommonData(); + } + if (!StringUtils.hasLength(commonData)) { + return new DeviceCommonData(); + } + DeviceCommonData deviceCommonData = gson.fromJson(commonData, DeviceCommonData.class); + return deviceCommonData; + } + + @Override + public int saveMergeDirections(String agentid, DeviceCommonData commonData) { + String sql = String.format("update featureall set mergedirection='%s' where agentid='%s'",gson.toJson(commonData), agentid); + return jdbcTemplate.update(sql); + } + + @Override + public DeviceCommonData getDeviceMergeDirection(String agentid) { + String sql = String.format("select mergedirection from featureall where agentid = '%s'", agentid); + String commonData; + try { + commonData = jdbcTemplate.queryForObject(sql, String.class); + } catch (DataAccessException e) { + logger.warning("mergedirection is not exist in DB! AgentId: " + agentid); + return new DeviceCommonData(); + } + if (!StringUtils.hasLength(commonData)) { + return new DeviceCommonData(); + } + DeviceCommonData deviceCommonData = gson.fromJson(commonData, DeviceCommonData.class); + return deviceCommonData; + } } diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/MessageServiceImpl.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/MessageServiceImpl.java index 4676abc47d268cbea5aae0cd112133d11f8d00e2..70b25b5610763db09b3838a7d838766f565dcad3 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/MessageServiceImpl.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/MessageServiceImpl.java @@ -216,9 +216,16 @@ public class MessageServiceImpl implements MessageService { } } + boolean logMessage = false; + if (infotype.contains("feature")) { + logMessage = true; + logger.info("pre send message to device: " + requestData); + } // 发送请求,并把应答返回 RESTRet responceData = commClient.devMessage(requestData, ascsBaseModel); - + if (logMessage) { + logger.info("device response message: " + responceData); + } // 处理应答后的请求 RESTRet ret = msgPostHandler.process(requestData, responceData); // 后置处理后,应答处理完后的消息。当消息内容为空,代表无需处理,应答原始消息 diff --git a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/StatusPatternRequest.java b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/StatusPatternRequest.java index dc030299fd0c53c77aa07c0f91a9737b401a7670..457db9e62a034b13be5172cd2b23b2eb4bc5d232 100644 --- a/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/StatusPatternRequest.java +++ b/OpenATC-Admin-server/agent/src/main/java/com/openatc/agent/service/impl/StatusPatternRequest.java @@ -51,6 +51,7 @@ public class StatusPatternRequest extends GenericMsgStrategy { // OpenATC 5.0 - status/pattern 的请求都从缓存中获取 MessageData responseData = null; responseData = ascsDao.getStatusPatternFromMap(msg.getAgentid()); + logger.info("pattern From Map: " + msg.getAgentid() + " data:" + responseData); if(responseData == null){ return RESTRetUtils.errorObj(false,E_2013); diff --git a/OpenATC-Admin-server/agent/src/main/resources/application-docker.properties b/OpenATC-Admin-server/agent/src/main/resources/application-docker.properties index 95f9841e1fabdb86b1a36c62a70d608d62e9ab91..bc7e431ed28ec8e714f344b186c0bed0302965ac 100644 --- a/OpenATC-Admin-server/agent/src/main/resources/application-docker.properties +++ b/OpenATC-Admin-server/agent/src/main/resources/application-docker.properties @@ -25,4 +25,5 @@ agent.comm.pattern.cache=${patterncache} agent.comm.timeout = ${timeout} server.ssl.key-store=${SSLKEY_PATH} server.ssl.key-store-password=${SSLKEY_PWD} -date.token=${DATE_TOKEN} \ No newline at end of file +date.token=${DATE_TOKEN} +agent.optimize.cycle.factor = ${CYCLE_FACTOR} \ No newline at end of file diff --git a/OpenATC-Admin-server/agent/src/main/resources/application-local.properties b/OpenATC-Admin-server/agent/src/main/resources/application-local.properties deleted file mode 100644 index b91e1cc4c0da5291c4dffd716505c4996a812b6d..0000000000000000000000000000000000000000 --- a/OpenATC-Admin-server/agent/src/main/resources/application-local.properties +++ /dev/null @@ -1,18 +0,0 @@ - -spring.datasource.url=jdbc:postgresql://192.168.74.133:5432/openatc1?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai -spring.datasource.username=postgres -spring.datasource.password=123456 - -## Redis -#spring.redis.enable=true -#spring.redis.host=192.168.74.133 -#spring.redis.port=6379 -#spring.redis.database=0 - -# 统一权限配置 -cloud.rbac.authorize=true -cloud.rbac.baseurl=https://rbac.devdolphin.com/cloud-rbac -cloud.rbac.client_id=jt-iss-back -cloud.rbac.client_secret=RTGCXM -cloud.rbac.grant_type=authorization_code -cloud.rbac.redirect_uri=https://192.168.14.182:10003/openatc \ No newline at end of file diff --git a/OpenATC-Admin-server/agent/src/main/resources/application.properties b/OpenATC-Admin-server/agent/src/main/resources/application.properties index aa7f443a364c84c37f9c49a014f68d975e614550..2c9feeded0f99f87698b2f22e93faeda3d16ef74 100644 --- a/OpenATC-Admin-server/agent/src/main/resources/application.properties +++ b/OpenATC-Admin-server/agent/src/main/resources/application.properties @@ -17,7 +17,7 @@ datebasename=openatc schema=public spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/${datebasename}?currentSchema=${schema}&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai spring.datasource.username=postgres -spring.datasource.password=password +spring.datasource.password= spring.datasource.driverClassName=org.postgresql.Driver spring.jpa.properties.hibernate.dialect=com.openatc.extend.common.config.MyDialect spring.jpa.properties.hibernate.hbm2ddl.auto=update @@ -96,20 +96,12 @@ jwt.token.secret=emarf.moc jwt.token.expiration=3600 #default.user.password=123456 -# 统一权限配置 -#cloud.rbac.authorize=true -#cloud.rbac.baseurl=http://10.165.28.85/cloud-rbac -#cloud.rbac.client_id=jt-iss-back -#cloud.rbac.client_secret=RTGCXM -#cloud.rbac.grant_type=authorization_code -#cloud.rbac.redirect_uri=https://192.168.14.182:10003/openatc - cloud.rbac.authorize=true -cloud.rbac.baseurl=https://rbac.devdolphin.com/cloud-rbac/ +cloud.rbac.baseurl=https://127.0.0.1/cloud-rbac/ cloud.rbac.client_id=jt-iss-back cloud.rbac.client_secret=RTGCXM cloud.rbac.grant_type=authorization_code -cloud.rbac.redirect_uri=https://192.168.14.54:10203/openatc +cloud.rbac.redirect_uri=https://127.0.0.1:10203/openatc cloud.rbac.openatc.token=eyJraWQiOiIxNzAxODMyOTQ3MTUwIiwidHlwIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJzdWIiOiJxeXl0aCIsImV4cCI6MTc2OTc4ODgwMCwiaWF0IjoxNzAxMzYwMDAwfQ.RIQpNEkJibL-RYllirDeNLi8G9-t8PecM_m7KlZNQXg agent.version = @project.version@ @@ -128,7 +120,7 @@ statuspattern.pushkafka.enable=false #kafka.topic.push.laneflow=sc1049flow #statuspattern.pushkafka.enable=false #quanyu kafka -quanyu.kafka.servers=10.165.77.67:30198,10.165.77.68:30198,10.165.77.69:30198 +quanyu.kafka.servers=127.0.0.1:9092 quanyu.device.status.report-enable=false # 平台通讯配置 @@ -147,3 +139,4 @@ date.token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiIsImFkbWluIjp0 # 兼容老设备模式时,方案消息直接问设备请求,不从缓存里取,此处配false agent.comm.pattern.cache=true +agent.optimize.cycle.factor = 2 \ No newline at end of file diff --git a/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20230328_0926__KDA.sql b/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20230328_0926__KDA.sql index aa12256195ec68cac41908ff0c5d85426d3fd8be..25d7b6fe1411cd23268458d2237e2a3f9ab02ede 100644 --- a/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20230328_0926__KDA.sql +++ b/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20230328_0926__KDA.sql @@ -49,5 +49,5 @@ CREATE TABLE pattern_realtime ( id serial PRIMARY KEY, "agentid" varchar(255), "time" timestamp(6), - "data" json + "data" VARCHAR ); diff --git a/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20250409_1337__KDA.sql b/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20250409_1337__KDA.sql new file mode 100644 index 0000000000000000000000000000000000000000..34a66dc53790fa04531662fb5b187ae53c0bc29c --- /dev/null +++ b/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20250409_1337__KDA.sql @@ -0,0 +1 @@ +ALTER TABLE "featureall" ADD COLUMN IF NOT EXISTS "commondata" json; \ No newline at end of file diff --git a/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20250421_1401__KDA.sql b/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20250421_1401__KDA.sql new file mode 100644 index 0000000000000000000000000000000000000000..9ae73394b5184346fa93298b519c13012fad2bf5 --- /dev/null +++ b/OpenATC-Admin-server/agent/src/main/resources/db/migration/V20250421_1401__KDA.sql @@ -0,0 +1 @@ +ALTER TABLE "featureall" ADD COLUMN IF NOT EXISTS "mergedirection" json; \ No newline at end of file diff --git a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/common/CosntDataDefine.java b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/common/CosntDataDefine.java index b25b86407a9822dc2c8df984bd6b413240109070..045f3bf636e2c9bc6b24a9b0bb8aeec325042600 100644 --- a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/common/CosntDataDefine.java +++ b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/common/CosntDataDefine.java @@ -69,7 +69,8 @@ public final class CosntDataDefine { public static final byte INFO_TYPE_SYSTEM_CUSTOM = -83; //设备信息 0xAD public static final byte INFO_TYPE_SYSTEM_UPDATE = -81; //设备升级 0xAF public static final byte INFO_TYPE_DETECTOR_STATUS = -80; //检测器状态 0xB0 - public static final byte INFO_TYPE_SECRETKEY = (byte) 0xC0; //检测器状态 0xC0 + public static final byte INFO_TYPE_SECRETKEY = (byte) 0xC0; //密钥 0xC0 + public static final byte INFO_TYPE_CUSTOM = (byte) 0xC1; //自定义消息 0xC1 public static final byte CFG_ACK_ASKSEND = 0x18; //主机回应配置软件请求发送数据 public static final byte CFG_ASK_ASKREAD = 0x19; //配置软件请求读数据 public static final byte CFG_ACK_ASKREAD_OK = 0x20; //主机回应配置软件请求读数据成功 @@ -114,6 +115,7 @@ public final class CosntDataDefine { public static final String systemcustom ="system/custom"; //设备参数 public static final String systemupdate ="system/update"; //设备升级 public static final String secretkeyupdate ="system/secretkey"; //更新密钥 + public static final String custominfo ="system/custominfo"; //自定义信息 // 参数对象 public static final String signalgroup = "feature/channel"; //信号灯组 public static final String phase = "feature/phase"; //相位 diff --git a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationForConfiger.java b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationForConfiger.java index 3f6a0c4addeb352355daa2843621005f318ed05f..0c95f3eb2ca16cb4a0d6c39b05ddd3c963b7aaa7 100644 --- a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationForConfiger.java +++ b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationForConfiger.java @@ -82,7 +82,7 @@ public class UdpCommunicationForConfiger implements Communication { logger.warning(e.getMessage()); } // logger.info("datagramSocket senddata end: " + System.currentTimeMillis()); -// logger.info("============= From Local: " + datagramSocket.getLocalPort() + " send to " + ip + ":" + port + " successfully!"); + System.out.println("From Local Port: " + datagramSocket.getLocalPort() + " send to " + ip + ":" + port + " Length: " + packData.getM_packDataSize()); return 0; } @@ -97,6 +97,8 @@ public class UdpCommunicationForConfiger implements Communication { DatagramPacket recvPacket = new DatagramPacket(dataRecv, dataRecv.length); try { datagramSocket.receive(recvPacket); + System.out.println("Receive From Ip: " + recvPacket.getAddress().getHostAddress() + " port: " + recvPacket.getPort() + " Length: " + recvPacket.getLength()); + md = message.uppack(recvPacket.getData(),recvPacket.getLength()); // logger.info("Recv data: " + BytePrintAsString(recvPacket.getData(),recvPacket.getLength())); } catch (IOException e) { diff --git a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationStaticPort.java b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationStaticPort.java index 17a1c04a917789f9302b5d211a0e60ef01748fee..71dcaaa55882c4633b116c87fb0b280972c85b9d 100644 --- a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationStaticPort.java +++ b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/UdpCommunicationStaticPort.java @@ -11,7 +11,6 @@ **/ package com.openatc.comm.model; -import com.google.gson.JsonElement; import com.openatc.comm.common.LogUtil; import com.openatc.comm.common.PropertiesUtil; import com.openatc.comm.data.MessageData; @@ -284,6 +283,8 @@ public class UdpCommunicationStaticPort implements Communication { // // 收到信号机的注册消息并应答 if (responceData.getInfotype().equals("login")) { +// logger.warning("Receive Login Report. RemoteIP: " + addressStr + " : " + port + " Data:" + responceData); + String protocol = responceData.getData().getAsJsonObject().get("protocol").getAsString(); // ocp设备都要应答联机请求 if (OCP_PROTYPE.equals(protocol)) { diff --git a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/ocpMessage.java b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/ocpMessage.java index 4a072855b97b285916c4bd74718d94d90daf6eef..95e816fbca607a54573e92298b7ff23d9a9b3c06 100644 --- a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/ocpMessage.java +++ b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/model/ocpMessage.java @@ -37,7 +37,7 @@ public class ocpMessage implements Message { byte[] packDataBuff = new byte[RECVBUFFER]; int packBuffLen = 0; // 密钥认证设备的set请求需要开启密钥校验 - if(sendMsg.getAuth() == 3 || sendMsg.getAuth() == 2 && sendMsg.getOperation().equals(setrequest)){ + if(sendMsg.getAuth() == 4 || sendMsg.getAuth() == 3 || sendMsg.getAuth() == 2 && sendMsg.getOperation().equals(setrequest)){ String secretkey = sendMsg.getSecretkey(); byte[] checkdata = addBytes(dataSchedule, secretkey.getBytes()); byte[] md5Bytes = MessageDigest.getInstance("md5").digest( checkdata ); diff --git a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/ocp/OcpDataPackUpPack.java b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/ocp/OcpDataPackUpPack.java index 1cb25d015dfcebb8ab1b03139f3a0526f367273f..81de00060f700c7ccb10606d369527d5d96f912a 100644 --- a/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/ocp/OcpDataPackUpPack.java +++ b/OpenATC-Admin-server/comm/src/main/java/com/openatc/comm/ocp/OcpDataPackUpPack.java @@ -17,11 +17,13 @@ import com.openatc.core.model.InnerError; import com.openatc.core.util.Gzip; import com.openatc.core.util.RESTRetUtils; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.Arrays; import static com.openatc.comm.common.CosntDataDefine.*; +import static com.openatc.comm.common.LogUtil.BytePrintAsString; import static com.openatc.core.common.IErrorEnumImplInner.E_207; import static com.openatc.core.common.IErrorEnumImplInner.E_209; @@ -104,6 +106,7 @@ public class OcpDataPackUpPack { //数据表内容宏定义 case 0x23: case 0x22: case 0x18: + case 0x19: return allfeature; case -94: return paramip; @@ -135,6 +138,8 @@ public class OcpDataPackUpPack { //数据表内容宏定义 return detectorstatus; case INFO_TYPE_SECRETKEY: return secretkeyupdate; + case INFO_TYPE_CUSTOM: + return custominfo; } return null; @@ -258,6 +263,12 @@ public class OcpDataPackUpPack { //数据表内容宏定义 case secretkeyupdate:// 更新密钥 eight = INFO_TYPE_SECRETKEY; break; + case custominfo:// 更新密钥 + eight = INFO_TYPE_CUSTOM; + break; + case detectorstatus:// 检测器状态 + eight = INFO_TYPE_DETECTOR_STATUS; + break; default: } return eight; @@ -409,6 +420,12 @@ public class OcpDataPackUpPack { //数据表内容宏定义 case secretkeyupdate: // 更新密钥 three = DATA_LINK_CONTROL; break; + case custominfo: // 更新密钥 + three = DATA_LINK_CONFIG; + break; + case detectorstatus: // 检测器状态 + three = LINK_OPTIMIZE_CONTROL; + break; default: } return three; @@ -431,15 +448,31 @@ public class OcpDataPackUpPack { //数据表内容宏定义 md5data.setMd5(datamd5value); String dataSetAllParam = gson.toJson(md5data); if (dataSetAllParam != null) { - byte[] dataSend = dataSetAllParam.getBytes("UTF-8"); - dataSendCount = dataSend.length; - dataSchdule = Arrays.copyOf(dataSchdule, dataSendCount + 14); - System.arraycopy(dataSend, 0, dataSchdule, 14, dataSendCount); + byte[] dataSend; + if (needGzip(sendData.getAuth())) { + try { + dataSend = Gzip.compress(dataSetAllParam, Gzip.GZIP_ENCODE_UTF_8); + } catch (IOException e) { + // 抛出异常 + throw new RuntimeException("Gzip compress error"); + } + dataSendCount = dataSend.length; + dataSchdule = Arrays.copyOf(dataSchdule, dataSendCount + 18); + System.arraycopy(dataSend, 0, dataSchdule, 18, dataSendCount); + for (int i = 0; i < 4; i++) { + dataSchdule[i + 14] = (byte) ((dataSendCount >> (i * 8)) & 0xFF); + } + } else { + dataSend = dataSetAllParam.getBytes("UTF-8"); + dataSendCount = dataSend.length; + dataSchdule = Arrays.copyOf(dataSchdule, dataSendCount + 14); + System.arraycopy(dataSend, 0, dataSchdule, 14, dataSendCount); + for (int i = 0; i < 4; i++) { + dataSchdule[i + 10] = (byte) ((dataSendCount >> (i * 8)) & 0xFF); + } + } + break; } - for (int i = 0; i < 4; i++) { - dataSchdule[i + 10] = (byte) ((dataSendCount >> (i * 8)) & 0xFF); - } - break; default: dataSchdule = AddMsgToDatafillwithLength(sendData,dataSchdule); } @@ -475,14 +508,28 @@ public class OcpDataPackUpPack { //数据表内容宏定义 JsonElement messageDataContent = sendData.getData(); if (messageDataContent != null) { String strSend = messageDataContent.toString(); - if (strSend != null) { - byte[] dataSend = strSend.getBytes("UTF-8"); + byte[] dataSend; + if (needGzip(sendData.getAuth())) { + try { + dataSend = Gzip.compress(strSend, Gzip.GZIP_ENCODE_UTF_8); + } catch (IOException e) { + // 抛出异常 + throw new RuntimeException("Gzip compress error"); + } + dataSendCount = dataSend.length; + dataSchdule = Arrays.copyOf(dataSchdule, dataSendCount + 18); + System.arraycopy(dataSend, 0, dataSchdule, 18, dataSendCount); + for (int i = 0; i < 4; i++) { + dataSchdule[i + 14] = (byte) ((dataSendCount >> (i * 8)) & 0xFF); + } + } else { + dataSend = strSend.getBytes("UTF-8"); dataSendCount = dataSend.length; dataSchdule = Arrays.copyOf(dataSchdule, dataSendCount + 14); System.arraycopy(dataSend, 0, dataSchdule, 14, dataSendCount); - } - for (int i = 0; i < 4; i++) { - dataSchdule[i + 10] = (byte) ((dataSendCount >> (i * 8)) & 0xFF); + for (int i = 0; i < 4; i++) { + dataSchdule[i + 10] = (byte) ((dataSendCount >> (i * 8)) & 0xFF); + } } return dataSchdule; } @@ -516,7 +563,13 @@ public class OcpDataPackUpPack { //数据表内容宏定义 dataSchdule[7] = dataScheduleSeven(operationType, infoType);// 操作类型 dataSchdule[8] = dataScheduleEight(operationType, infoType);// 对象标识 dataSchdule[9] = (byte)sendData.getAuth().intValue(); - dataSchdule[10] = 0x00; + boolean needGzip = needGzip(sendData.getAuth()); + // 版本大于4,数据采用gzip压缩 + if (needGzip) { + dataSchdule[10] = 0x01; + } else { + dataSchdule[10] = 0x00; + } dataSchdule[11] = 0x00; dataSchdule[12] = 0x00; dataSchdule[13] = 0x00; @@ -526,6 +579,17 @@ public class OcpDataPackUpPack { //数据表内容宏定义 return PackDataContent(sendData, dataSchdule); // 设置消息需要拼上消息体 } + /** + * 根据信号机的认证版本,确定是否需要对数据进行gzip压缩,从v4版本开始支持gzip压缩 + * @param auth + * @return + */ + private boolean needGzip(Integer auth) { + if (auth == null) return false; + if (auth >= 4) return true; + return false; + } + //应答信号的数据表 public static byte[] AskPackDataSchedule(String operationtype) { byte[] dataSchdule = new byte[MAX_DATA_SCHEDULE]; @@ -570,18 +634,19 @@ public class OcpDataPackUpPack { //数据表内容宏定义 * @Description: 对数据表进行解析,并将解析内容转发配置软件 */ public static int ReadDataSchedule(MessageData recvData, byte[] dataSchedule, int dataScheduleSize) throws UnsupportedEncodingException { - String tempData = ""; - if (dataScheduleSize >= 14) { - // 处理gzip压缩的数据内容 - byte gzip = dataSchedule[10]; - if (gzip == 1) { - byte[] subArray = Arrays.copyOfRange(dataSchedule, 14, dataScheduleSize); - tempData = Gzip.uncompressToString(subArray, Gzip.GZIP_ENCODE_UTF_8); - } else { - tempData = new String(dataSchedule ,14, dataScheduleSize-14, "UTF-8"); - } - }else - return 0; + if (dataScheduleSize < 14) return 0; + + String tempData; + // 部分消息在数据内容前有4个字节表示数据长度,可能以0x01开头,并占据第10位标志位,要结合第10位标志位以及数据部分开头是否为0x1f 0x8b来判断是否是gzip压缩 + byte gzip = dataSchedule[10]; + int gzipFlagPos = getFlagPos(dataSchedule); + // 处理gzip压缩的数据内容 + if (gzip == 1 && gzipFlagPos != 0) { + byte[] subArray = Arrays.copyOfRange(dataSchedule, gzipFlagPos, dataScheduleSize); + tempData = Gzip.uncompressToString(subArray, Gzip.GZIP_ENCODE_UTF_8); + } else { + tempData = new String(dataSchedule ,14, dataScheduleSize-14, "UTF-8"); + } // 解析设备ID String roadID; @@ -603,7 +668,7 @@ public class OcpDataPackUpPack { //数据表内容宏定义 recvData.setData(gson.toJsonTree(innerError)); }else if(chOperateType == OPERATE_TYPE_ERROR_ANSWER){ // 错误应答 InnerError innerError; - if( allfeature.equals(recvData.getInfotype()) ) + if( allfeature.equals(recvData.getInfotype()) && tempData != null && !tempData.contains("success") ) innerError = RESTRetUtils.innerErrorObj(null,E_207,gson.fromJson(tempData, JsonElement.class)); else innerError = RESTRetUtils.innerErrorObj(null,E_209,gson.fromJson(tempData, JsonElement.class)); @@ -623,6 +688,16 @@ public class OcpDataPackUpPack { //数据表内容宏定义 return checkDataLink(chDataLink, chOperateType, chInfoType, tempData, recvData); } + private static int getFlagPos(byte[] dataSchedule) { + // 查找数组中,1f 8b的位置 + for (int i = 0; i < dataSchedule.length; i++) { + if (dataSchedule[i] == 31 && dataSchedule[i + 1] == -117) { + return i; + } + } + return 0; + } + public boolean isZero(byte[] dataSchedule) { for (int i = 0; i < dataSchedule.length; i++) { if (dataSchedule[i] != 0) { diff --git a/OpenATC-Admin-server/core/src/main/java/com/openatc/core/util/FileUtil.java b/OpenATC-Admin-server/core/src/main/java/com/openatc/core/util/FileUtil.java index 1b3749255a847bea7b647590bdf8b99bc85458ed..3884a196d09372128ec5126a287dbd0ed9f27509 100644 --- a/OpenATC-Admin-server/core/src/main/java/com/openatc/core/util/FileUtil.java +++ b/OpenATC-Admin-server/core/src/main/java/com/openatc/core/util/FileUtil.java @@ -25,13 +25,32 @@ public class FileUtil { public static void writeString(String filePath, String data) throws Exception{ - Writer writer = new OutputStreamWriter(new FileOutputStream(filePath), StandardCharsets.UTF_8); + + Writer writer = null; try { + + // 创建 File 对象 + File file = new File(filePath); + + // 检查文件是否存在,若不存在则创建 + if (!file.exists()) { + boolean created = file.createNewFile(); + if (created) { + System.out.println("文件已创建: " + filePath); + } else { + System.out.println("无法创建文件: " + filePath); + return; + } + } + writer = new OutputStreamWriter(new FileOutputStream(filePath), StandardCharsets.UTF_8); + writer.write(data); } catch (Exception e) { - e.printStackTrace(); + throw new RuntimeException(e); } finally { - writer.close(); + if (writer != null) { + writer.close(); + } } } diff --git a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/Detector.java b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/Detector.java index 55aec7a6a80deb2a52bad77424b6ffc1d465596a..ecc64e0c5aa63675c60f600f1b302c214d0bd3e9 100644 --- a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/Detector.java +++ b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/Detector.java @@ -13,4 +13,6 @@ public class Detector { private String createTime; private int id; private int state; + private String ip; + private int port; } diff --git a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/DeviceCommonData.java b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/DeviceCommonData.java new file mode 100644 index 0000000000000000000000000000000000000000..cbe85a3db4504de042d9053fae23e2b71cf44716 --- /dev/null +++ b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/DeviceCommonData.java @@ -0,0 +1,18 @@ +package com.openatc.model.model; + +import lombok.Data; + +import java.util.List; + +/** + * @author :panleilei + * @description 所有特勤路线共用的设备数据 + * @modified By: + * @version: + * @date :Created in 2025/4/9 10:12 + */ +@Data +public class DeviceCommonData { + private List validDirections; + private List mergeDirections; +} diff --git a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/StageForStageMode.java b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/StageForStageMode.java index 69722fb9c13a7ddf55d8b3930a5fa69186aa79a2..a76a38d300b643cb1c3374f8530bfcdd7cf251cb 100644 --- a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/StageForStageMode.java +++ b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/StageForStageMode.java @@ -21,4 +21,5 @@ public class StageForStageMode { private int stageSplit; // 阶段绿性比 private List phases; // 阶段配置模式下该阶段包含的相位 private List stages; // 环模式下该阶段包含的相位 + private boolean isConnected; // 是否与上个阶段搭接 } diff --git a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/SystemEventDetails.java b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/SystemEventDetails.java index 5838fc077e912f7eaae8af43ed5ed39baf3afdca..500ec5d9f3e1917afe5bccc32d07cba051f7b72b 100644 --- a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/SystemEventDetails.java +++ b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/model/SystemEventDetails.java @@ -16,6 +16,7 @@ public class SystemEventDetails { public static final int MSG_TYPE_YELLOW_FLASH = 1; // 黄闪 public static final int MSG_TYPE_ALL_RED = 2; // 黄闪 public static final int MSG_TYPE_LIGHT_OFF = 3; // 关灯 + public static final int MSG_TYPE_IP_CONFLICT = 4; // 设备ip冲突 private int msgtype; // 消息类型 -1-离线,0-上线,1-黄闪 private String agentid; // 路口id private String name; // 路口名称 diff --git a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/service/TemplateService.java b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/service/TemplateService.java index ab3c2dfafa1347335410633d13ec3abb515b0fdd..e2e9d39a003561ef7dccb3e511cdae940a26addc 100644 --- a/OpenATC-Admin-server/model/src/main/java/com/openatc/model/service/TemplateService.java +++ b/OpenATC-Admin-server/model/src/main/java/com/openatc/model/service/TemplateService.java @@ -166,18 +166,22 @@ public class TemplateService { switch (intersectionDirection) { case "001": direction[0] = new int[]{1}; + direction[1] = new int[]{1}; break; case "002": direction[0] = new int[]{13}; + direction[1] = new int[]{13}; break; case "003": direction[0] = new int[]{5}; + direction[1] = new int[]{5}; break; case "004": direction[0] = new int[]{9}; + direction[1] = new int[]{9}; break; } - direction[1] = new int[]{}; +// direction[1] = new int[]{}; } //表示行人过街 diff --git a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/Barrier.java b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/Barrier.java index ce454a44cfda83a658663d8bb1e23076584c2ab5..64bf15c0b7022f58d1060c9e6b3fa91691d6cfa5 100644 --- a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/Barrier.java +++ b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/Barrier.java @@ -113,10 +113,31 @@ public class Barrier { if(items.size() < 2){ return; } - duration = items.get(0).calcDuration(phaseMap); - long offset = items.get(1).calcDuration(phaseMap) - duration; - int targetphaseid = items.get(1).getData().get(0); - phaseMap.get(targetphaseid).setDuration(phaseMap.get(targetphaseid).getDuration() - offset ); + BarrierItem item1 = null; + BarrierItem item2 = null; + BarrierItem item3 = null; + + try{ + item1 = items.get(0); + item2 = items.get(1); + item3 = items.get(2); + }catch (Exception e){ + + } + + + duration = item1.calcDuration(phaseMap); + long offset = duration - item2.calcDuration(phaseMap); + int targetphaseid = item2.getData().get(0); + phaseMap.get(targetphaseid).setDuration(phaseMap.get(targetphaseid).getDuration() + offset ); + + // 存在第三个环 + if( item3 != null ){ + offset = duration - item3.calcDuration(phaseMap); + targetphaseid = item3.getData().get(0); + phaseMap.get(targetphaseid).setDuration(phaseMap.get(targetphaseid).getDuration() + offset ); + + } } diff --git a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/CrossConfig.java b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/CrossConfig.java index 487f36bb001f8ed476511f0ad8281d003f618671..97b2fc4291219854b8c522b38c13e559b1afe099 100644 --- a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/CrossConfig.java +++ b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/CrossConfig.java @@ -5,11 +5,12 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; +import java.util.*; + +import static com.openatc.optimize.fixedtimeplan.enums.OptTypeEnum.CYCLE_OPT; +import static java.lang.Math.*; /** @@ -21,6 +22,7 @@ import java.util.Objects; @NoArgsConstructor @Builder @AllArgsConstructor +@Slf4j public class CrossConfig { private String type; @@ -50,15 +52,10 @@ public class CrossConfig { // 创建优化的相位 - // 兼容阶段模式 + // 兼容阶段模式,阶段模式中phases代表阶段 if( pattern.getRings() == null || pattern.getRings().isEmpty() || "stage".equals(pattern.getContrloType())) { - phases = new ArrayList<>(); - for( StageForStageMode stage : pattern.getStagesList() ){ - PhaseOpt phaseOpt = new PhaseOpt(); - phaseOpt.setId(stage.getKey() + 1); - phaseOpt.setDuration(stage.getStageSplit() ); - phases.add(phaseOpt); - } + // 计算阶段流量 + calcStageOpt(); }else{ if(phases == null) phases = new ArrayList<>(); @@ -78,6 +75,107 @@ public class CrossConfig { } } + private void calcStageOpt() { + if(CYCLE_OPT.getValue().equals(type)){ + phases = new ArrayList<>(); + for( StageForStageMode stage : pattern.getStagesList() ){ + PhaseOpt phaseOpt = new PhaseOpt(); + phaseOpt.setId(stage.getKey() + 1); + phaseOpt.setDuration(stage.getStageSplit() ); + phases.add(phaseOpt); + } + return; + } + List stages = pattern.getStagesList(); + Map phaseOptMap = new HashMap<>(); + Map stagesOpt = new HashMap(); + + if( phases == null ){ + // 更新PhaseOpt + phases = new ArrayList<>(); + for( StageForStageMode stage : stages ){ + PhaseOpt phaseOpt = new PhaseOpt(); + phaseOpt.setId(stage.getKey() + 1); + phaseOpt.setDuration(stage.getStageSplit() ); + phaseOpt.setFlowperhour(1); + phaseOpt.setSaturation(0); + + phases.add(phaseOpt); + } + return ; + } + // 将PhaseOpt 列表转为map + for( PhaseOpt phaseOpt : phases){ + phaseOptMap.put(phaseOpt.getId(),phaseOpt); + } + // 计算阶段优化信息,关键路径算法: + // - 若相位出现在下个阶段,则不在此阶段中判断 + // - 如果下个阶段有搭接相位,减去上个阶段的流量后计算流量 + List StagePhases = new ArrayList<>(); + int remainstageflow = 0; + + for (int i = 0; i < stages.size(); i++) { + StageForStageMode stage = stages.get(i); + + // 到下个阶段中查询有没有搭接相位,存在的话,不在此阶段中判断 + if(i != stages.size() - 1){ + StageForStageMode stageNext = stages.get(i+1); + + for (int j = stage.getPhases().size() - 1; j >= 0; j--) { + for( Integer phaseidnext : stageNext.getPhases() ){ + if( stage.getPhases().get(j) == phaseidnext ){ + stage.getPhases().remove(j); + stageNext.setConnected(true); + break; + } + } + } + } + + int stageflow = 0; + int stageflowmax = 0; + int stageSaturation = 0; + + for( Integer phaseid : stage.getPhases() ){ + PhaseOpt opt = phaseOptMap.get(phaseid); + if( opt == null) continue; + int flow = (int) opt.getFlowperhour(); + if (flow != 0){ + if( flow > stageflowmax){ + stageflowmax = flow; + } + stageSaturation = (int) max(stageSaturation, opt.getSaturation()); + } + } + + if(stage.isConnected()){ + stageflow = max(0,stageflowmax - remainstageflow); + + } + else + stageflow = stageflowmax; + + PhaseOpt stageOpt = new PhaseOpt(); + stageOpt.setId(stage.getKey()); + stageOpt.setFlowperhour(stageflow); + stageOpt.setSaturation(stageSaturation); + stagesOpt.put(stage.getKey(), stageOpt); + + remainstageflow = stageflow; + } + + // 更新PhaseOpt + phases = new ArrayList<>(); + for( StageForStageMode stage : stages ){ + PhaseOpt phaseOpt = new PhaseOpt(); + phaseOpt.setId(stage.getKey() + 1); + phaseOpt.setDuration(stage.getStageSplit() ); + phaseOpt.setFlowperhour( max( stagesOpt.get(stage.getKey()).getFlowperhour(),1) ); + phaseOpt.setSaturation(stagesOpt.get(stage.getKey()).getSaturation() ); + + phases.add(phaseOpt); + } + } private PhaseOpt phasebyid(int id){ @@ -137,6 +235,24 @@ public class CrossConfig { List barrierFeatures = pattern.getBarriers(); if(barrierFeatures == null) return optbarriers; + // 简单处理三个环但是没有把环三放入barrier的情况,只支持环三是两个相位的情况 + try{ + if( pattern.getRings().get(2).size() == 2 && barrierFeatures.get(0).getItems().size() != 3 ){ + for(BarrierFeature barrierFeature : barrierFeatures){ + + BarrierItemFeature itemFeature = new BarrierItemFeature(); + itemFeature.setRing(3); + List phases = new ArrayList<>(); + phases.add(pattern.getRings().get(2).get(barrierFeature.getBarrier()-1).getId()); + itemFeature.setData(phases); + barrierFeature.getItems().add(itemFeature); + } + } + + }catch (Exception e){ + log.warn("不支持的三环方案:" + e + pattern.getRings().toString()); + } + for(BarrierFeature barrierFeature : barrierFeatures){ Barrier barrier = Barrier.createBarrierByBarrierFeature(barrierFeature); optbarriers.add(barrier); diff --git a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/PhaseOpt.java b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/PhaseOpt.java index 1bc10688859d1b5b5d27eaf26ff8e3d676c824ff..f80f4e3bcdb096b1bb6e6abb82fd344053d63c6c 100644 --- a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/PhaseOpt.java +++ b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/config/cross/PhaseOpt.java @@ -25,7 +25,13 @@ public class PhaseOpt { private boolean adjusted; public double Y(){ - return flowperhour/saturation; + if(saturation == 0) + saturation = 1700; + + double y = flowperhour/saturation; + if(y == 0) + y = 0.01; + return y; } diff --git a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/model/control/Cross.java b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/model/control/Cross.java index ac3dc419e71140e6111ddb67a8c383e3fc233f52..7b78946e0dbe8a26c0738d446c0c55f6a6466bb0 100644 --- a/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/model/control/Cross.java +++ b/OpenATC-Admin-server/optimize/fixedtimeplan/src/main/java/com/openatc/optimize/fixedtimeplan/model/control/Cross.java @@ -1,7 +1,7 @@ package com.openatc.optimize.fixedtimeplan.model.control; -import com.alibaba.fastjson.JSON; +//import com.alibaba.fastjson.JSON; import com.openatc.optimize.fixedtimeplan.config.cross.*; import com.openatc.optimize.fixedtimeplan.enums.OptTypeEnum; @@ -12,22 +12,19 @@ import lombok.extern.slf4j.Slf4j; import java.util.*; +import static java.lang.Math.max; + /** * @author mz * @version 1.0 - * @date 2021/10/26 8:52 + * @time 2021/10/26 8:52 */ @Data @AllArgsConstructor @Slf4j @Builder public class Cross { - - - - - - public FixedtimePlan optimize(){ + public FixedtimePlan optimize(double factor){ OptTypeEnum optTypeEnum = OptTypeEnum.getOptTypeEnumByValue(crossConfig.getType()); if(optTypeEnum == OptTypeEnum.CYCLE_OPT){//周期优化,提供周期,各相位绿信比等比例赋值 adjustPhaseDurationAssignEqually(crossConfig.getOptcycle()); @@ -35,6 +32,7 @@ public class Cross { }else{ //1、未提供优化周期,默认0,则算法自己算出优化周期 //2、提供优化周期,则根据优化周期和算法调整 + cFactor = factor; return calcFixedtimePlan(); } } @@ -46,7 +44,7 @@ public class Cross { private double totalY; private long cycle; - + private double cFactor; // 周期修正因子 //路口初始化配置 @@ -87,7 +85,7 @@ public class Cross { if(crossConfig.getBarriers().size() != 0){//双环 for(Barrier barrier:crossConfig.getBarriers()){ calcYofBarrier(barrier); - log.info("y of barrer {} is {}", barrier.getBarrier(), barrier.getY()); +// log.info("y of barrer {} is {}", barrier.getBarrier(), barrier.getY()); y += barrier.getY(); } }else{//单环 @@ -107,7 +105,7 @@ public class Cross { for(Integer id:ids){ tempY += phaseMap.get(id).Y(); } - log.info("temp Y of barrer {} is {}", barrier.getBarrier(), tempY); +// log.info("temp Y of barrer {} is {}", barrier.getBarrier(), tempY); if(tempY > Y){ Y = tempY; } @@ -133,16 +131,32 @@ public class Cross { if(crossConfig.getBarriers().size() != 0){//双环 for(Barrier barrier:crossConfig.getBarriers()){ - barrier.setDuration(Math.round(barrier.getY()/totalY*cycle)); - log.info("duration of barrier {} is {}", barrier.getBarrier(), barrier.getDuration()); + long barrierDuration = Math.round(barrier.getY()/totalY*cycle); + long barrierMinDuration = 0; + + for(Integer id : barrier.getItems().get(0).getData()){ + barrierMinDuration += phaseMap.get(id).getMingreen(); + } + + if( barrierDuration < barrierMinDuration ) barrierDuration = barrierMinDuration; + barrier.setDuration(barrierDuration ); + +// log.info("duration of barrier {} is {}", barrier.getBarrier(), barrier.getDuration()); for(BarrierItem item:barrier.getItems()){ + List ids = item.getData(); - double tempY = 0; + double tempYTotal = 0; + long barrierMinGreen = 0; for(Integer id : ids){ - tempY += phaseMap.get(id).Y(); + tempYTotal += phaseMap.get(id).Y(); + barrierMinGreen += phaseMap.get(id).getMingreen(); } + long duration = barrier.getDuration() - barrierMinGreen; + if( duration < 0) duration = 0; for(Integer id : ids){ - phaseMap.get(id).setDuration(Math.round(barrier.getDuration()*phaseMap.get(id).Y()/tempY)); + double tempY = phaseMap.get(id).Y(); + double pahseDuration = duration * tempY / tempYTotal; + phaseMap.get(id).setDuration(Math.round(pahseDuration) + phaseMap.get(id).getMingreen() ); } } @@ -160,65 +174,67 @@ public class Cross { for(Integer id : ids){ phaseMap.get(id).setDuration(Math.round(barrier.getDuration()*phaseMap.get(id).Y()/tempY)); } - } - */ } - }else{//单环 + } + else{//单环 for(PhaseOpt phase:phaseMap.values()){ - phase.setDuration((Math.round((cycle*phase.Y()/totalY)))); - } + if(phase.getFlowperhour() == 0 ) + phase.setDuration(20); + else{ + double tempy = phase.Y(); + long duration = Math.round((cycle*tempy/totalY)); + if( phase.getMingreen() != null ) + phase.setDuration( max(duration,phase.getMingreen() ) ); + else + phase.setDuration( duration ); + } + } } - - - } public FixedtimePlan calcFixedtimePlan(){ - - totalY = updateTotalY(); - log.info("Y of agent:{} is {}", agentid, totalY); +// log.info("Y of agent:{} is {}", agentid, totalY); double L = (crossConfig.getLoss()+crossConfig.getRed()) * crossConfig.getRings().get(0).getSequence().size(); - log.info("loss time of agentid: {} is {}", agentid, L); - - - totalY = totalY > 0.95 ? 0.95 : totalY; - if(totalY < 0.9){ +// log.info("loss time of agentid: {} is {}", agentid, L); +// totalY = totalY > 0.95 ? 0.95 : totalY; + // 设置周期最大值 + if( totalY > 0.9) + cycle = 216; + else{ //webster模型 - cycle = Math.round((1.5 * L + 5) / (1 - totalY)); + cycle = Math.round((1.5 * L + 5) / (1 - totalY) * cFactor ) ; + if( cycle > 216 ) + cycle = 216; + } - }else{ + cycle = max( cycle, getMinCycle() ); - //ARRB模型 - cycle = Math.round((1.4 * L + 6) / (1- totalY)); - } +// if(totalY < 0.9){ +// //webster模型 +// cycle = Math.round((1.5 * L + 5) / (1 - totalY) ) ; +// } else if (Double.isNaN(totalY) ) { +// } else { +// //ARRB模型 +// cycle = Math.round((1.4 * L + 6) / (1- totalY)); +// } if(crossConfig.getOptcycle() != 0){//如果指定周期,则按照指定的来 cycle = crossConfig.getOptcycle(); } - - - log.info("cycle of {} is {}", agentid, cycle); - - +// log.info("cycle of {} is {}", agentid, cycle); assignDurationOfBarrier(); - - - - log.info("final cycle of {} is {}", agentid, cycle); - - - +// log.info("final cycle of {} is {}", agentid, cycle); fixminoroffset(); - + log.info("final opt pattern of {} is cycle: {} feature: {}", agentid,cycle, crossConfig); return createFixedtimePlan(); } @@ -228,14 +244,12 @@ public class Cross { return FixedtimePlan.builder() .agentid(agentid) .cycle(Math.round(cycle)) - .rings(this.crossConfig.getRings()) + .rings(crossConfig.getRings()) .barriers(crossConfig.getBarriers()) .phase(new ArrayList<>(phaseMap.values())) .build(); } - - - + // 对齐相位最后一秒 public void fixminoroffset(){ if(crossConfig.getBarriers().size() > 0){//双环 for(Barrier barrier:crossConfig.getBarriers()){ @@ -248,9 +262,36 @@ public class Cross { } } }else{//单环 - cycle = 0; + int optcycle = 0; + PhaseOpt optMaxSplit = null; + PhaseOpt optMinSplit = null; for(PhaseOpt phaseOpt:phaseMap.values()){ - cycle += phaseOpt.getDuration(); + long duration = phaseOpt.getDuration(); + + // 获取最大绿信比相位 + if(optMaxSplit == null){ + optMaxSplit = phaseOpt; + }else if ( duration > optMaxSplit.getDuration() ){ + optMaxSplit = phaseOpt; + } + + // 获取最小绿信比相位 + if(optMinSplit == null){ + optMinSplit = phaseOpt; + }else if ( duration < optMinSplit.getDuration() ){ + optMinSplit = phaseOpt; + } + + optcycle += duration; + } + int optoffset = (int) (optcycle - cycle); + // 修正值大于0,最大的相位绿信比减去 + if( optoffset > 0){ + optMaxSplit.setDuration( optMaxSplit.getDuration() - optoffset); + } + // 修正值大于0,最小的相位绿信比加上 + else if( optoffset < 0 ){ + optMinSplit.setDuration( optMinSplit.getDuration() - optoffset); } } @@ -293,7 +334,7 @@ public class Cross { } } } - log.info("adjustPhaseDurationAssignToCophsae phasemap:{}", JSON.toJSONString(phaseMap)); +// log.info("adjustPhaseDurationAssignToCophsae phasemap:{}", JSON.toJSONString(phaseMap)); for(Barrier barrier:crossConfig.getBarriers()){ for(BarrierItem barrierItem:barrier.getItems()){ @@ -304,7 +345,7 @@ public class Cross { } } } - log.info("adjustPhaseDurationAssignToCophsae barriers:{}",JSON.toJSONString(crossConfig.getBarriers())); +// log.info("adjustPhaseDurationAssignToCophsae barriers:{}",JSON.toJSONString(crossConfig.getBarriers())); for(Barrier barrier:crossConfig.getBarriers()){ for(BarrierItem barrierItem:barrier.getItems()){ barrierItem.adjustPhaseDuration(phaseMap, barrier.getDuration()); @@ -322,15 +363,35 @@ public class Cross { } + // 获取最小周期 + public int getMinCycle(){ + + int mincycle = 0; + + try{ + for( int targetid:crossConfig.getRings().get(0).getSequence()){ + if( phaseMap.get(targetid).getMingreen() == null ){ + mincycle = 0; + break; + } + mincycle += phaseMap.get(targetid).getMingreen(); + } + }catch (Exception e){ + log.info("getMinCycle Error " + e.getMessage() + crossConfig ); + } + + return mincycle; + } + /** * 最大最小绿调整后,重新计算周期长 * */ - private void updateCycle(){ - int tempcycle = 0; - for(Barrier barrier:crossConfig.getBarriers()){ - tempcycle += barrier.getDuration(); - } - cycle = tempcycle; - } +// private void updateCycle(){ +// int tempcycle = 0; +// for(Barrier barrier:crossConfig.getBarriers()){ +// tempcycle += barrier.getDuration(); +// } +// cycle = tempcycle; +// } } diff --git a/OpenATC-Admin-ui/OpenATC-Admin-web/.gitignore b/OpenATC-Admin-ui/OpenATC-Admin-web/.gitignore index 8adb0b12a8075cf669ffb549f60cf66756b3462c..3f1e32c6ecf963f73f09e5d5fe03944b5911560c 100644 --- a/OpenATC-Admin-ui/OpenATC-Admin-web/.gitignore +++ b/OpenATC-Admin-ui/OpenATC-Admin-web/.gitignore @@ -1,16 +1,17 @@ -.DS_Store -node_modules/ -dist/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* -package-lock.json - -# Editor directories and files -.idea -.vscode -*.suo -*.ntvs* -*.njsproj -*.sln -.history +.DS_Store +node_modules/ +dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +config/dev.local.js + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +.history diff --git a/OpenATC-Admin-ui/OpenATC-Admin-web/build/webpack.base.conf.js b/OpenATC-Admin-ui/OpenATC-Admin-web/build/webpack.base.conf.js index be379e2c19291c18c430b6ba416f4d52c166d413..d7cf87333e56c5ceda949df2155c6a9304d11315 100644 --- a/OpenATC-Admin-ui/OpenATC-Admin-web/build/webpack.base.conf.js +++ b/OpenATC-Admin-ui/OpenATC-Admin-web/build/webpack.base.conf.js @@ -99,6 +99,10 @@ module.exports = { limit: 100000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } + }, + { + test: /\.json$/, + use: 'json-loader' } ] }, diff --git a/OpenATC-Admin-ui/OpenATC-Admin-web/config/index.js b/OpenATC-Admin-ui/OpenATC-Admin-web/config/index.js index 62a10268c0d5911242fab30c83b16783933e1170..44a2cf5ff2b610352c87fb8f873088e0ed93dd28 100644 --- a/OpenATC-Admin-ui/OpenATC-Admin-web/config/index.js +++ b/OpenATC-Admin-ui/OpenATC-Admin-web/config/index.js @@ -1,144 +1,137 @@ -/** - * Copyright (c) 2020 kedacom - * OpenATC is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - **/ -'use strict' -// Template version: 1.2.6 -// see http://vuejs-templates.github.io/webpack for documentation. - -const path = require('path') -// const DEV_API_HOST = '192.168.13.103:10014' -const DEV_API_HOST = '192.168.13.103:10003' -// const DEV_API_HOST = '10.165.32.135:30003' // 10 -// const DEV_API_HOST = '192.168.13.103:30004'// pro 网关 -// const DEV_API_HOST = '192.168.14.183:10003' - -module.exports = { - dev: { - - // Paths - assetsSubDirectory: 'static', - assetsPublicPath: '/', - proxyTable: { - '/api': { - target: 'http://192.168.13.113:55555', - changeOrigin: true, - ws: true, - secure: false, - pathRewrite: { - '^/api': '/api' - } - }, - '/socket': { - target: `ws://${DEV_API_HOST}`, - changeOrigin: true, - ws: true, - secure: false, - pathRewrite: { - '^/socket': '/' - } - }, - '/': { - // target: 'http://192.168.13.121:8099/kissapi',//'http://172.16.239.139:8080/',//设置你调用的接口域名和端口号 - // target: 'http://192.168.13.103:9999',//'http://172.16.239.139:8080/',//设置你调用的接口域名和端口号 - // target: 'http://192.168.13.103:9999/kissapi',//'http://172.16.239.139:8080/',//设置你调用的接口域名和端口号 - // target: 'http://192.168.14.172:10003/openatc', - target: 'http://192.168.13.103:10003/openatc', - // target: 'http://10.165.32.135:30003/openatc', - // target: 'http://192.168.14.150:10003/openatc', - // target: 'https://kints-dev.devdolphin.com/openatc', - // target: 'http://192.168.14.122:10003/openatc', - // target: 'http://192.168.13.83:10003/openatc', - // target: 'http://192.168.31.139:10003/openatc', - // target: 'http://192.168.14.187:10003/openatc', - // target: 'https://dolphin-test.kedacom.com/openatc', - changeOrigin: true, //跨域 - pathRewrite: { - '^/': '/'//这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://10.1.5.11:8080/xxx/duty?time=2017-07-07 14:57:22',直接写‘/api/xxx/duty?time=2017-07-07 14:57:22’即可 - } - } - }, - - // Various Dev Server settings - // host: '0.0.0.0', - host: 'localhost', // can be overwritten by process.env.HOST - port: 9528, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined - autoOpenBrowser: true, - errorOverlay: true, - notifyOnErrors: false, - poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- - - // Use Eslint Loader? - // If true, your code will be linted during bundling and - // linting errors and warnings will be shown in the console. - useEslint: true, - // If true, eslint errors and warnings will also be shown in the error overlay - // in the browser. - showEslintErrorsInOverlay: true, - - /** - * Source Maps - */ - - // https://webpack.js.org/configuration/devtool/#development - devtool: 'source-map', - - // If you have problems debugging vue-files in devtools, - // set this to false - it *may* help - // https://vue-loader.vuejs.org/en/options.html#cachebusting - cacheBusting: false, - - // CSS Sourcemaps off by default because relative paths are "buggy" - // with this option, according to the CSS-Loader README - // (https://github.com/webpack/css-loader#sourcemaps) - // In our experience, they generally work as expected, - // just be aware of this issue when enabling this option. - cssSourceMap: false, - }, - - build: { - // Template for index.html - index: path.resolve(__dirname, '../dist/index.html'), - - // Paths - assetsRoot: path.resolve(__dirname, '../dist'), - assetsSubDirectory: './', - - /** - * You can set by youself according to actual condition - * You will need to set this if you plan to deploy your site under a sub path, - * for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/, - * then assetsPublicPath should be set to "/bar/". - * In most cases please use '/' !!! - */ - assetsPublicPath: './', // If you are deployed on the root path, please use '/' - - /** - * Source Maps - */ - - productionSourceMap: false, - // https://webpack.js.org/configuration/devtool/#production - devtool: '#source-map', - - // Gzip off by default as many popular static hosts such as - // Surge or Netlify already gzip all static assets for you. - // Before setting to `true`, make sure to: - // npm install --save-dev compression-webpack-plugin - productionGzip: false, - productionGzipExtensions: ['js', 'css'], - - // Run the build command with an extra argument to - // View the bundle analyzer report after build finishes: - // `npm run build --report` - // Set to `true` or `false` to always turn it on or off - bundleAnalyzerReport: process.env.npm_config_report - } -} +/** + * Copyright (c) 2020 kedacom + * OpenATC is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **/ +'use strict' +// Template version: 1.2.6 +// see http://vuejs-templates.github.io/webpack for documentation. +const fs = require('fs'); +const path = require('path') +let VUE_APP_PROXY_API_TARGET = "http://127.0.0.1:8080" +let VUE_APP_PROXY_MAIN_TARGET = "http://127.0.0.1:8080" +let VUE_APP_PROXY_SOCKET_TARGET = "http://127.0.0.1:8080" +const localFile = path.resolve(__dirname, 'dev.local.js'); +if (fs.existsSync(localFile)) { + let local = require(localFile) + if (local) { + VUE_APP_PROXY_API_TARGET = local.VUE_APP_PROXY_API_TARGET + VUE_APP_PROXY_MAIN_TARGET = local.VUE_APP_PROXY_MAIN_TARGET + VUE_APP_PROXY_SOCKET_TARGET = local.VUE_APP_PROXY_SOCKET_TARGET + } +} +module.exports = { + dev: { + // Paths + assetsSubDirectory: 'static', + assetsPublicPath: '/', + proxyTable: { + '/api': { + target: VUE_APP_PROXY_API_TARGET, + changeOrigin: true, + ws: true, + secure: false, + pathRewrite: { + '^/api': '/api' + } + }, + '/socket': { + target: VUE_APP_PROXY_SOCKET_TARGET, + changeOrigin: true, + ws: true, + secure: false, + pathRewrite: { + '^/socket': '/' + } + }, + '/': { + target: VUE_APP_PROXY_MAIN_TARGET, + changeOrigin: true, //跨域 + pathRewrite: { + '^/': '/'//这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://10.1.5.11:8080/xxx/duty?time=2017-07-07 14:57:22',直接写‘/api/xxx/duty?time=2017-07-07 14:57:22’即可 + } + } + }, + + // Various Dev Server settings + // host: '0.0.0.0', + host: 'localhost', // can be overwritten by process.env.HOST + port: 9528, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined + autoOpenBrowser: true, + errorOverlay: true, + notifyOnErrors: false, + poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- + + // Use Eslint Loader? + // If true, your code will be linted during bundling and + // linting errors and warnings will be shown in the console. + useEslint: true, + // If true, eslint errors and warnings will also be shown in the error overlay + // in the browser. + showEslintErrorsInOverlay: true, + + /** + * Source Maps + */ + + // https://webpack.js.org/configuration/devtool/#development + devtool: 'source-map', + + // If you have problems debugging vue-files in devtools, + // set this to false - it *may* help + // https://vue-loader.vuejs.org/en/options.html#cachebusting + cacheBusting: false, + + // CSS Sourcemaps off by default because relative paths are "buggy" + // with this option, according to the CSS-Loader README + // (https://github.com/webpack/css-loader#sourcemaps) + // In our experience, they generally work as expected, + // just be aware of this issue when enabling this option. + cssSourceMap: false, + }, + + build: { + // Template for index.html + index: path.resolve(__dirname, '../dist/index.html'), + + // Paths + assetsRoot: path.resolve(__dirname, '../dist'), + assetsSubDirectory: './', + + /** + * You can set by youself according to actual condition + * You will need to set this if you plan to deploy your site under a sub path, + * for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/, + * then assetsPublicPath should be set to "/bar/". + * In most cases please use '/' !!! + */ + assetsPublicPath: './', // If you are deployed on the root path, please use '/' + + /** + * Source Maps + */ + + productionSourceMap: false, + // https://webpack.js.org/configuration/devtool/#production + devtool: '#source-map', + + // Gzip off by default as many popular static hosts such as + // Surge or Netlify already gzip all static assets for you. + // Before setting to `true`, make sure to: + // npm install --save-dev compression-webpack-plugin + productionGzip: false, + productionGzipExtensions: ['js', 'css'], + + // Run the build command with an extra argument to + // View the bundle analyzer report after build finishes: + // `npm run build --report` + // Set to `true` or `false` to always turn it on or off + bundleAnalyzerReport: process.env.npm_config_report + } +} diff --git a/OpenATC-Admin-ui/OpenATC-Admin-web/package.json b/OpenATC-Admin-ui/OpenATC-Admin-web/package.json index 8f5bdfbe82be2e2cf87ff36c77e7e44ac3d5c0a7..74492b8faa30931425ba7443e52038217bdf335a 100644 --- a/OpenATC-Admin-ui/OpenATC-Admin-web/package.json +++ b/OpenATC-Admin-ui/OpenATC-Admin-web/package.json @@ -53,7 +53,7 @@ "moment": "^2.29.1", "normalize.css": "7.0.0", "nprogress": "0.2.0", - "openatc-components": "0.4.7", + "openatc-components": "0.4.64", "postcss-pxtorem": "^5.0.0", "scss-loader": "0.0.1", "sortablejs": "^1.10.1", @@ -99,6 +99,7 @@ "friendly-errors-webpack-plugin": "1.6.1", "html-webpack-plugin": "2.30.1", "husky": "^3.0.9", + "json-loader": "^0.5.7", "lint-staged": "^9.4.2", "mockjs": "^1.1.0", "node-notifier": "5.1.2", diff --git a/OpenATC-Admin-ui/OpenATC-Admin-web/src/api/device.js b/OpenATC-Admin-ui/OpenATC-Admin-web/src/api/device.js index 107b9df9c3834b8d4ceafcadb82660fc19b113b1..dd636f43b36f60d9d543699fc2a1d1a96a97c1a5 100644 --- a/OpenATC-Admin-ui/OpenATC-Admin-web/src/api/device.js +++ b/OpenATC-Admin-ui/OpenATC-Admin-web/src/api/device.js @@ -117,6 +117,32 @@ export const getYesterdayStatusCollect = () => { return api.Send({}, {}, []) } +export const setValidDirections = (reqData) => { + let api = new Authapi('setValidDirections') + let paramList = [reqData.agentid] + let data = reqData.data + return api.Send({}, data, [paramList]) +} + +export const getValidDirections = (agentid) => { + let api = new Authapi('getValidDirections') + let paramList = [agentid] + return api.Send({}, {}, [paramList]) +} + +export const setMergeDirections = (reqData) => { + let api = new Authapi('setMergeDirections') + let paramList = [reqData.agentid] + let data = reqData.data + return api.Send({}, data, [paramList]) +} + +export const getMergeDirections = (agentid) => { + let api = new Authapi('getMergeDirections') + let paramList = [agentid] + return api.Send({}, {}, [paramList]) +} + export default { GetAllDevice, AddDevice, diff --git a/OpenATC-Admin-ui/OpenATC-Admin-web/src/assets/icon/demo_index.html b/OpenATC-Admin-ui/OpenATC-Admin-web/src/assets/icon/demo_index.html index 25f0d728f7a28ed5a474b2936b99a8a1c429bb3b..1389b554e7be7a8223c2f385487738dcbc78dae2 100644 --- a/OpenATC-Admin-ui/OpenATC-Admin-web/src/assets/icon/demo_index.html +++ b/OpenATC-Admin-ui/OpenATC-Admin-web/src/assets/icon/demo_index.html @@ -54,6 +54,18 @@
    +
  • + +
    检测器
    +
    &#xe76c;
    +
  • + +
  • + +
    感应式自适应
    +
    &#xe76b;
    +
  • +
  • 实时方案
    @@ -2256,9 +2268,9 @@
    @font-face {
       font-family: 'iconfont';
    -  src: url('iconfont.woff2?t=1724752066068') format('woff2'),
    -       url('iconfont.woff?t=1724752066068') format('woff'),
    -       url('iconfont.ttf?t=1724752066068') format('truetype');
    +  src: url('iconfont.woff2?t=1742196033749') format('woff2'),
    +       url('iconfont.woff?t=1742196033749') format('woff'),
    +       url('iconfont.ttf?t=1742196033749') format('truetype');
     }
     

    第二步:定义使用 iconfont 的样式

    @@ -2284,6 +2296,24 @@
      +
    • + +
      + 检测器 +
      +
      .icon-jianceqi +
      +
    • + +
    • + +
      + 感应式自适应 +
      +
      .icon-ganyingshizishiying +
      +
    • +
    • @@ -5587,6 +5617,22 @@
        +
      • + +
        检测器
        +
        #icon-jianceqi
        +
      • + +
      • + +
        感应式自适应
        +
        #icon-ganyingshizishiying
        +
      • +
      • -
        -
        -
        - -
        -
        {{$t('edge.overview.patternstate')}}
        -
        ({{$t('edge.overview.cycle')}}: {{controlData.cycle}} {{$t('edge.overview.patternoffset')}}: {{controlData.patternoffset}} {{$t('edge.overview.coordinationtime')}}: {{controlData.offset}})
        - {{$t('edge.pattern.overLap')}} - - - - - - - - - -
        -
        - -
        - -
        -
        -
        -
        - - - diff --git a/OpenATC-Admin-ui/OpenATC-Admin-web/src/views/Home/crossAbnormal.vue b/OpenATC-Admin-ui/OpenATC-Admin-web/src/views/Home/crossAbnormal.vue index d44c58ba8ca532260ff1ce8a3e4a107f2b5cd875..b0022c1b18bc3d7c5b2f9f886acea51881059d9e 100644 --- a/OpenATC-Admin-ui/OpenATC-Admin-web/src/views/Home/crossAbnormal.vue +++ b/OpenATC-Admin-ui/OpenATC-Admin-web/src/views/Home/crossAbnormal.vue @@ -10,7 +10,7 @@ * See the Mulan PSL v2 for more details. **/