doum
2025-12-25 b3adc414c51e229f10172985911373ed90b1334f
最新版本541200007最新版本541200007
已修改14个文件
482 ■■■■ 文件已修改
admin/src/components/business/OperaDeviceDataListWindow.vue 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaDeviceDuanluqiWindow.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/deviceDuanluqi.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/doc/新增断路器设备功能(2025-12-24).sql 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/pom.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/core/utils/Constants.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_timer/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/admin_timer/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/device_service/pom.xml 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Device.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/DeviceData.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/DeviceServiceImpl.java 326 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaDeviceDataListWindow.vue
@@ -1,7 +1,7 @@
<template>
  <GlobalWindow
      :title="title"
      width="100%"
      width="85%"
      :visible.sync="visible"
  >
    <TableLayout >
@@ -19,30 +19,20 @@
          <div style="display: flex;margin-top: 20px;">
            <div style="flex: 1"><span  class="label">MQTT IP:</span>{{model.doorNameObj.mqttIp ||''}}</div>
            <div style="flex: 1"><span  class="label">MQTT端口:</span>{{model.doorNameObj.mqttPort||''}}</div>
            <div style="flex: 3">
              <span class="label">最近控制操作:</span>
              <span class="orange" >{{model.remark||''}}</span>
            </div>
            <div style="flex: 3"> <span class="label">最近控制操作:</span>{{model.remark||''}}</div>
          </div>
        </div>
        <div class="platgroup_tabs">
          <div class="tab" :class="{ active: activeGroup === item.id }" @click="groupClick(item)"
               v-for="(item, i) in groupList" :key="i">
            {{ item.name }}
          </div>
        </div>
        <el-form-item label="开关序号" v-if="activeGroup==0" prop="val1">
        <el-form-item label="开关序号" prop="val1">
          <el-input v-model="searchForm.val1" placeholder="请输入开关序号" @keypress.enter.native="search"></el-input>
        </el-form-item>
        <section v-if="activeGroup==0">
        <section>
          <el-button type="primary" @click="search">搜索</el-button>
          <el-button @click="reset">重置</el-button>
        </section>
      </el-form>
      <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
      <template  v-slot:table-wrap>
      <template v-slot:table-wrap>
        <el-table
            v-if="activeGroup===0"
            :height="tableHeightNew"
            v-loading="isWorking.search"
            :data="tableData.list"
@@ -60,24 +50,6 @@
          <el-table-column prop="val3" label="电圧(V)" min-width="120px"></el-table-column>
          <el-table-column prop="val4" label="温度(℃)" min-width="180px" ></el-table-column>
          <el-table-column prop="val5" label="有功功率值(kW)" min-width="120px"></el-table-column>
        </el-table>
        <el-table
            v-if="activeGroup===1"
            :height="tableHeightNew"
            v-loading="isWorking.search"
            :data="tableData.list"
            stripe>
          <el-table-column prop="createDate" label="操作时间" min-width="150px"></el-table-column>
          <el-table-column prop="val4" label="操作人" min-width="100px" ></el-table-column>
          <el-table-column prop="val3" label="操作内容" min-width="100px">
            <template slot-scope="{row}">
                <span v-if=" row.val3 === '【合闸】'" class="green">{{row.val3||''}}</span>
                <span  v-else-if=" row.val3 === '【分闸】'" class="red">{{row.val3||''}}</span>
                <span v-else>{{row.val3||''}}</span>
            </template>
          </el-table-column>
          <el-table-column prop="val5" label="开关序号" min-width="120px"></el-table-column>
          <el-table-column prop="val2" label="内容" min-width="300px" show-overflow-tooltip></el-table-column>
        </el-table>
        <pagination
            @size-change="handleSizeChange"
@@ -107,13 +79,10 @@
      // è¡¨å•数据
      visible: false,
      title: '',
      activeGroup:0,
      model:{},
      groupList: [{ id: 0, name: '数据上报记录', type: 0 }, { id: 1, name: '远程控制记录', type: 1 }],
      searchForm: {
        deviceId:  null,
        val1: '',
        dataType:0
        val1:''
      }
    }
  },
@@ -127,12 +96,6 @@
    this.search()
  },
  methods: {
    groupClick (item) {
      this.activeGroup = item.id
      this.searchForm.val1 = ''
      this.searchForm.dataType = item.type
      this.search()
    },
    open (title, row) {
      this.title = title +' ã€'+ (row.name)+'】'
      this.searchForm.deviceId = row.id
@@ -155,33 +118,12 @@
          total: 0
        }
      }
      this.groupClick(this.groupList[0])
      this.search()
    }
  }
}
</script>
<style>
.platgroup_tabs {
  flex: 1;
  display: flex;
  border-bottom: 1px solid #dfe2e8;
  margin-bottom:30px;
  .tab {
    color: #666666;
    margin-right: 40px;
    cursor: pointer;
    padding-bottom: 18px;
    border-bottom: 2px solid #fff;
  }
  .active {
    font-weight: 500;
    font-size: 15px;
    color: #2080f7;
    border-bottom: 2px solid $primary-color;
  }
}
.label{
/*  width: 80px;
  text-align: right;*/
admin/src/components/business/OperaDeviceDuanluqiWindow.vue
@@ -34,9 +34,8 @@
            1.全部开关序号:参考设备实际配置,多个用英文逗号隔开,如 1,2,3;<br>
            2.控制开关序号:系统根据配置规则,判断开关当前空闲中进行【自动分闸】,多个用英文逗号隔开,如 1,2;<br>
            3.自动分闸规则:针对控制开关序号的配置,定时检测【空闲时长】内满足开关电流值都在【空闲电流阈值】范围内,则进行自动分闸控制;<br>
            4.空闲时长: è¯·è®¾ç½®è‡³å°‘空闲时长大于等于300秒(5分钟)。<br>
            5.修改重启: ä¿®æ”¹é…ç½®å‚数后,返回列表页,点击重启【启用】,是参数生效!<br>
            6.如需远程控制开关,请正确填写下述全部参数信息。
            4.空闲时长: è¯·è®¾ç½®è‡³å°‘空闲时长大于等于300秒(5分钟)。
            5.如需远程控制开关,请正确填写下述全部参数信息。
          </p>
          <div style="display: flex">
            <el-form-item label="全部开关序号" prop="channelNo" style="display: inline-block;width:300px;">
@@ -119,7 +118,7 @@
        name: [
          { required: true, message: '请输入设备名称' }
        ],
        /*max: [
      /*  max: [
          { required: true, message: '请输入设备空闲电流阈值' }
        ],*/
        doorId: [
admin/src/views/business/deviceDuanluqi.vue
@@ -133,9 +133,10 @@
    return {
      // æœç´¢
      searchForm: {
        doorName: '',
        doorNo: '',
        no: '',
        name: '',
        regionPathName: '',
        type: 5
      },
      isWorkSending: false,
server/doc/ÐÂÔö¶Ï·Æ÷É豸¹¦ÄÜ£¨2025-12-24£©.sql
@@ -1,13 +1,7 @@
ALTER TABLE `device`
ALTER TABLE `wuhuyancao`.`device`
MODIFY COLUMN `door_no` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '门禁点编号' AFTER `install_location`;
INSERT INTO `quartz_job` (`id`, `bean_name`, `params`, `cron_expres`, `state`, `remark`, `create_time`, `module`) VALUES (NULL, 'visitServiceJob', '{}', '0 0/5 * * * ? *', 1, '【断路器】开启定时远程控制断路器分闸', '2023-07-26 13:17:17', 'autoCloseCmd');
INSERT INTO `system_dict_data` (`ID`, `DICT_ID`, `CODE`, `LABEL`, `SORT`, `DISABLED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `REMARK`) VALUES (314, 18, 'yKSKuO0LoFf06jWGrwwuGudK', 'JDY_SECRET', 0, 0, 1, '2025-12-29 10:32:54', NULL, '2025-12-29 10:31:45', 0, '数据推送秘钥');
INSERT INTO `system_dict_data` (`ID`, `DICT_ID`, `CODE`, `LABEL`, `SORT`, `DISABLED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `REMARK`) VALUES (315, 18, 'https://api.jiandaoyun.com/api/v1/automation/tenant/6909b792324dc197821895d1/hooks/6909d0fbdb93695219faa27eb068192dc4a9532972993159', 'JDY_MEMBER_PUSH_STATUS_URL', 0, 0, 1, '2025-12-29 14:06:56', NULL, '2025-12-29 14:05:46', 0, '简道云人员推送处理结果通知地址');
INSERT INTO `system_dict_data` (`ID`, `DICT_ID`, `CODE`, `LABEL`, `SORT`, `DISABLED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `REMARK`) VALUES (316, 1, '芜湖烟草公司', 'SYSTEM_TITLE', 0, 0, 1, '2025-12-30 14:49:57', NULL, '2025-12-30 14:48:47', 0, '系统主标题');
INSERT INTO `system_dict_data` (`ID`, `DICT_ID`, `CODE`, `LABEL`, `SORT`, `DISABLED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `REMARK`) VALUES (317, 1, '智慧物流园区安消一体化平台', 'SYSTEM_SUBTITLE', 0, 0, 1, '2025-12-30 14:50:40', NULL, '2025-12-30 14:49:30', 0, '系统副标题');
INSERT INTO `wuhuyancao`.`quartz_job` (`id`, `bean_name`, `params`, `cron_expres`, `state`, `remark`, `create_time`, `module`) VALUES (NULL, 'visitServiceJob', '{}', '0 0/5 * * * ? *', 1, '【断路器】开启定时远程控制断路器分闸', '2023-07-26 13:17:17', 'autoCloseCmd');
CREATE TABLE `device_data` (
server/pom.xml
@@ -18,8 +18,6 @@
      <module>system_gateway</module>
      <module>emaysms</module>
    <module>visits/device_service</module>
      <module>jiandaoyun_service</module>
      <module>base_serivce</module>
  </modules>
  <parent>
    <groupId>org.springframework.boot</groupId>
server/system_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -218,6 +218,7 @@
    public static  boolean DEALING_HK_NOTICE_LIST = false;
    public static  boolean DEALING_FROM_HK_VISIT = false;
    public static  boolean DEALING_HK_EMPOWER = false;
    public static  boolean DEALING_DUANLUQI_CLOSE = false;
    public static  boolean DEALING_HK_EMPOWER_DETAIL = false;
    public static  boolean DEALING_HK_EMPOWER_RESULT = false;
    public static  boolean DEALING_HK_PARKBOOK = false;
@@ -288,6 +289,15 @@
        public static final  int depart = 3;
        public static final  int custom = 4;
        public static final  int self = -1;
    }
    //类型 0门禁 1车库 2LED 3广播点 4广播设备 5断路器空开
    public interface DEVICE_TYPE{
        public static final  int door = 0;
        public static final  int park = 1;
        public static final  int led = 2;
        public static final  int broadcaset = 3;
        public static final  int broadcasetChannel = 4;
        public static final  int duanluqi = 5;
    }
    /**
@@ -1529,6 +1539,14 @@
        return JSONObject.toJSONString(map);
    }
    public  interface MqttTopic{
        String mts_attr = "/dev/+/+/attr/json";//属性topic
        String mts_status = "/dev/+/+/status/json";//状态topic
        String mts_event= "/dev/+/+/event/json";//事件topic
        String mts_echo= "/dev/+/+/echo/json";//消息回复topic
        String mts_cmd= "/dev/$CATE/$DEVID/cmd/json";//命令topic
        String mts_resp= "/dev/+/+/resp/json";//命令响应topic
    }
    public  enum WarningConfig {
server/system_timer/src/main/resources/bootstrap.yml
@@ -1,6 +1,6 @@
spring:
  profiles:
    active: test
    active: dev
  application:
    name: systemTimer
    # å®‰å…¨é…ç½®
server/visits/admin_timer/src/main/resources/bootstrap.yml
@@ -1,6 +1,6 @@
spring:
  profiles:
    active: pro
    active: dev
  application:
    name: visitsTimer
    # å®‰å…¨é…ç½®
server/visits/device_service/pom.xml
@@ -9,13 +9,13 @@
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <artifactId>device_service</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <fastjson.version>1.2.70</fastjson.version>
    </properties>
    <dependencies>
@@ -27,11 +27,6 @@
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>
</project>
server/visits/dmvisit_service/pom.xml
@@ -24,11 +24,6 @@
        </dependency>
        <dependency>
            <groupId>com.doumee</groupId>
            <artifactId>jiandaoyun_service</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.doumee</groupId>
            <artifactId>device_service</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Device.java
@@ -1,5 +1,6 @@
package com.doumee.dao.business.model;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.service.business.third.model.LoginUserModel;
@@ -10,6 +11,7 @@
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
@@ -71,8 +73,8 @@
    @ExcelColumn(name="排序码")
    private Integer sortnum;
    @ApiModelProperty(value = "类型 0门禁 1车库 2LED 3广播点 4广播设备", example = "1")
    @ExcelColumn(name="类型 0门禁 1车库 2LED 3广播点 4广播设备")
    @ApiModelProperty(value = "类型 0门禁 1车库 2LED 3广播点 4广播设备 5断路器空开", example = "1")
    @ExcelColumn(name="类型 0门禁 1车库 2LED 3广播点 4广播设备 5断路器空开")
    private Integer type;
    @ApiModelProperty(value = "是否园区出入口 0不是 1是", example = "1")
    @ExcelColumn(name="是否园区出入口 0不是 1是")
@@ -154,12 +156,12 @@
    @ApiModelProperty(value = "门禁点名称")
    @ExcelColumn(name="门禁点名称")
    private String doorName;
    @ApiModelProperty(value = "播报内容")
    @TableField(exist = false)
    private String sendInfo;
    @ApiModelProperty(value = "配置参数")
    @TableField(exist = false)
    private JSONObject doorNameObj;
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/DeviceData.java
@@ -31,6 +31,7 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -39,6 +40,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
@@ -88,8 +90,8 @@
    @ExcelColumn(name="属性值7")
    private String val7;
    @ApiModelProperty(value = "数据来源 0mqtt上报综合状态 1远程控制 ", example = "1")
    @ExcelColumn(name="数据来源 0mqtt上报综合状态 1远程控制")
    @ApiModelProperty(value = "数据来源 0mqtt上报 1其他", example = "1")
    @ExcelColumn(name="数据来源 0mqtt上报 1其他")
    private Integer dataType;
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceService.java
@@ -5,6 +5,8 @@
import com.doumee.service.business.third.model.PageData;
import com.doumee.service.business.third.model.PageWrap;
import com.doumee.dao.business.model.Device;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.List;
/**
@@ -13,6 +15,7 @@
 * @date 2023/11/30 15:33
 */
public interface DeviceService {
    /**
     * åˆ›å»º
@@ -109,4 +112,11 @@
    void setBroadcaseBobao(Device body);
    String setBroadcaseBobaoHttp(Device body);
    void duanluqiCmd(Device param);
    void updateUsedById(Device d);
    void autoCloseCmdTimer();
    void startCheckDuanluqiSubjob();
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/DeviceServiceImpl.java
@@ -11,14 +11,15 @@
import com.doumee.core.haikang.model.param.request.CustomBroadcastRequest;
import com.doumee.core.haikang.model.param.request.TransparentChannelSingleRequest;
import com.doumee.core.haikang.service.HKService;
import com.doumee.core.utils.HttpsUtil;
import com.doumee.core.utils.*;
import com.doumee.dao.business.*;
import com.doumee.dao.business.model.*;
import com.doumee.mqtt.config.MqttConfig;
import com.doumee.mqtt.service.MqttBizService;
import com.doumee.service.business.impl.mqtt.MqttClientCache;
import com.doumee.service.business.third.model.LoginUserInfo;
import com.doumee.service.business.third.model.PageData;
import com.doumee.service.business.third.model.PageWrap;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.Utils;
import com.doumee.service.business.DeviceService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
@@ -28,11 +29,14 @@
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.Date;
import java.util.stream.Collectors;
/**
@@ -45,7 +49,11 @@
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private MqttBizService mqttBizService;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Autowired
    private PlatformMapper platformMapper;
    @Autowired
@@ -65,6 +73,14 @@
        model.setIsdeleted(Constants.ZERO);
        model.setEditDate(new Date());
        model.setCreateDate(model.getEditDate());
        if(model.getDoorNameObj()!=null && Constants.equalsInteger(model.getType(),Constants.DEVICE_TYPE.duanluqi)){
            model.setDoorName(JSONObject.toJSONString(model.getDoorNameObj()));
            if(StringUtils.isNotBlank(model.getLevel())){
                if(getNumberByStr(model.getLevel()) <300){
                    throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,控制时长必须大于等于300秒");
                }
            }
        }
        deviceMapper.insert(model);
        return model.getId();
    }
@@ -99,6 +115,9 @@
    public void updateById(Device device) {
        device.setEdirot(device.getLoginUserInfo().getId()+"");
        device.setEditDate(new Date());
        if(device.getDoorNameObj()!=null && Constants.equalsInteger(device.getType(),Constants.DEVICE_TYPE.duanluqi)){
            device.setDoorName(JSONObject.toJSONString(device.getDoorNameObj()));
        }
        deviceMapper.updateById(device);
    }
@@ -114,7 +133,16 @@
    @Override
    public Device findById(Integer id) {
        return deviceMapper.selectById(id);
        Device d = deviceMapper.selectById(id);
        if(StringUtils.isNotBlank(d.getDoorName()) &&Constants.equalsInteger(d.getType(),Constants.DEVICE_TYPE.duanluqi)){
            try {
                //断路器设备参数
                d.setDoorNameObj(JSONObject.parseObject(d.getDoorName()));
            }catch (Exception e){
            }
        }
        return d;
    }
    @Override
@@ -138,7 +166,20 @@
               .eq(null !=param.getIsdeleted(),Device::getIsdeleted,param.getIsdeleted())
               .eq(Objects.isNull(param.getIsdeleted()),Device::getIsdeleted,Constants.ZERO)
               .eq(null != param.getHkStatus(),Device::getHkStatus,param.getHkStatus());
        return deviceMapper.selectList(wrapper);
        List<Device> list = deviceMapper.selectList(wrapper);
        if(list!=null){
            for(Device d : list){
                if(StringUtils.isNotBlank(d.getDoorName()) &&Constants.equalsInteger(d.getType(),Constants.DEVICE_TYPE.duanluqi)){
                    try {
                        //断路器设备参数
                        d.setDoorNameObj(JSONObject.parseObject(d.getDoorName()));
                    }catch (Exception e){
                    }
                }
            }
        }
        return list;
    }
  
    @Override
@@ -247,7 +288,20 @@
                queryWrapper.orderByAsc(sortData.getProperty());
            }
        }
        return PageData.from(deviceMapper.selectPage(page, queryWrapper));
        IPage<Device> result = deviceMapper.selectPage(page, queryWrapper);
        if(result!=null){
            for(Device d : result.getRecords()){
                if(StringUtils.isNotBlank(d.getDoorName()) &&Constants.equalsInteger(d.getType(),Constants.DEVICE_TYPE.duanluqi)){
                    try {
                        //断路器设备参数
                        d.setDoorNameObj(JSONObject.parseObject(d.getDoorName()));
                    }catch (Exception e){
                    }
                }
            }
        }
        return PageData.from(result);
    }
    @Override
@@ -271,6 +325,125 @@
        if(response == null || !StringUtils.equals(response.getCode(), HKConstants.RESPONSE_SUCCEE)){
          throw  new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"发送失败:"+ JSONObject.toJSONString(response));
        }
    }
    @Override
    public   void updateUsedById(Device param){
        Device model = deviceMapper.selectById(param.getId());
        if(model ==null && Constants.equalsInteger(param.getType(),Constants.DEVICE_TYPE.duanluqi)){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        MqttConfig config = getMqttConfigByParam(model,"device_");
        MqttClient mqttClient = MqttClientCache.clientMapCache.get("device"+param.getId());
        String[] topics =new String[]{Constants.MqttTopic.mts_status,
                Constants.MqttTopic.mts_attr,
                Constants.MqttTopic.mts_resp};
        if(Constants.equalsInteger(param.getIsUsed(),Constants.ONE)){
            //如果系统不用了,端口mqtt连接
            try {
                mqttClient = mqttBizService.unsubscribe(mqttClient,config  ,topics);
                if(mqttClient ==null){
                    throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"建立连接失败!");
                }
                if(mqttClient.isConnected()){
                    mqttClient.disconnect();
                }
            }catch (Exception e){
                log.error("==============端口mqtt链接失败:"+model.getName()+e.getMessage());
            }
        }else{
            //如果开始使用,开始订阅
            mqttClient = mqttBizService.subscribe(mqttClient,config ,topics);
            if(mqttClient ==null){
                throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"建立连接失败!");
            }
            MqttClientCache.clientMapCache.put("device"+param.getId(),mqttClient);
        }
        this.updateById(param);
    }
    @Override
    public  void duanluqiCmd(Device param){
        Device model = deviceMapper.selectById(param.getId());
        if(model ==null && Constants.equalsInteger(param.getType(),Constants.DEVICE_TYPE.duanluqi)){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        dealDuanluqiCmd(model,param,"device_");
    }
    private void dealDuanluqiCmd(Device model, Device param,String clientIndex) {
        MqttConfig config = getMqttConfigByParam(model,clientIndex);
        MqttClient mqttClient = MqttClientCache.clientMapCache.get("device"+param.getId());
        String cmdTopic = Constants.MqttTopic.mts_cmd.replace("$CATE",model.getNo()).replace("$DEVID",model.getDoorNo());
        if(Constants.equalsInteger(param.getStatus(),Constants.ONE)){
            //如果是开闸,先解锁
            String cmdParamAction = CmdContants.T30A.cmdParam.replace("$DEVID", model.getDoorNo())
                    .replace("$CMD",  CmdContants.T30ACmd.do_err_clear)//异常解锁
                    .replace("$BUSADDR",model.getChannelNo());
            mqttClient = mqttBizService.publish(mqttClient,config,cmdTopic, cmdParamAction);//解锁命令
            if(mqttClient ==null){
                throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"指令发送失败!");
            }
        }
        String cmdParamAction =CmdContants.T30A.cmdParam.replace("$DEVID", model.getDoorNo())
                .replace("$CMD",(Constants.equalsInteger(param.getStatus(),Constants.ONE)?CmdContants.T30ACmd.do_turn_on:CmdContants.T30ACmd.do_turn_off))
                .replace("$BUSADDR", param.getChannelNo());
        mqttClient = mqttBizService.publish(mqttClient,config,cmdTopic, cmdParamAction);//开关闸命令
        if(mqttClient ==null){
            throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"指令发送失败!");
        }
        MqttClientCache.clientMapCache.put("device"+param.getId(),mqttClient);
        String curremak = "【"+param.getLoginUserInfo().getRealname()
                +"】于"+ DateUtil.getPlusTime2(new Date()) +"进行了"+(Constants.equalsInteger(param.getStatus(),Constants.ONE)?"【开闸】":"【关闸】")+"操作,开关【"+param.getChannelNo()+"】;";
        deviceMapper.update(null,new UpdateWrapper<Device>().lambda()
//                        .setSql("remark = concat(ifnull(remark,''),'"+curremak+"','\n')")
                .set(Device::getRemark,curremak)
                .set(Device::getEditDate,new Date())
                .set(Device::getEdirot,param.getLoginUserInfo().getId())
                .eq(Device::getId,param.getId()));
    }
    private MqttConfig getMqttConfigByParam(Device model,String index) {
        MqttConfig config = new MqttConfig();
        JSONObject mqtt = new JSONObject();
        if(StringUtils.isBlank(model.getNo())
                ||StringUtils.isBlank(model.getDoorNo()) ){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,设备标识符和设备号未配置!");
        }
        if(StringUtils.isNotBlank(model.getDoorName())){
            try {
                //断路器设备参数
                mqtt = (JSONObject.parseObject(model.getDoorName()));
            }catch (Exception e){
            }
        }
        if(mqtt == null
                ||StringUtils.isBlank(mqtt.getString("mqttUsername"))
                ||StringUtils.isBlank(mqtt.getString("mqttIp"))
                ||StringUtils.isBlank(mqtt.getString("mqttPort"))
                ||StringUtils.isBlank(mqtt.getString("mqttPassword"))){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,设备mqtt服务参数配置不正确!");
        }
        /**
         *   MqttConfig config = (new MqttConfig());
         *         config.setHost("tcp://192.168.0.7:1883");
         *         config.setClientid("doumee1");
         *         config.setPassword("doumee@168");
         *         config.setUsername("doumee");
         *         config.setVersion("003");
         */
        config.setVersion("003");
        config.setUsername( mqtt.getString("mqttUsername"));
        config.setPassword( mqtt.getString("mqttPassword"));
        config.setHost("tcp://"+ mqtt.getString("mqttIp")+":"+mqtt.getString("mqttPort"));
        config.setClientid(index+model.getId());
        return config;
    }
    public  void mqttCallbackService(String topic, MqttMessage message){
       log.error("mqtt收到消息=====topic:",topic);
       log.error("mqtt收到消息=====message:",JSONObject.toJSONString(message));
    }
    @Override
    public String setBroadcaseBobaoHttp(Device param){
@@ -382,4 +555,145 @@
        }
        log.error( "屏幕内容设置=======================结束========" );
    }
    /**
     * æœåŠ¡å¼€å¯è®¢é˜…ä»»åŠ¡
     */
    @Override
    public   void startCheckDuanluqiSubjob() {
        List<Device> devices = deviceMapper.selectList(new QueryWrapper<Device>().lambda()
                .eq(Device::getType,Constants.DEVICE_TYPE.duanluqi)//断路器
                .eq(Device::getIsUsed,Constants.ZERO)
                .eq(Device::getIsdeleted,Constants.ZERO)
        );
        if(devices!=null && devices.size()>0){
            for (Device model : devices){
                try {
                    MqttConfig config = getMqttConfigByParam(model,"device_");
                    MqttClient mqttClient = MqttClientCache.clientMapCache.get("device"+model.getId());
                    String[] topics =new String[]{Constants.MqttTopic.mts_status,
                            Constants.MqttTopic.mts_attr,
                            Constants.MqttTopic.mts_resp};
                        //如果开始使用,开始订阅
                    mqttClient = mqttBizService.subscribe(mqttClient,config ,topics);
                    if(mqttClient ==null){
                        throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"建立连接失败!");
                    }
                    MqttClientCache.clientMapCache.put("device"+model.getId(),mqttClient);
                    log.error("=======开始自动定于mqtt任务完成:"+model.getName() );
                }catch (Exception e){
                    log.error("=======开始自动定于mqtt任务失败:"+model.getName()+e.getMessage());
                }
            }
        }
    }
    /**
     * æ–­è·¯å™¨åˆ¤æ–­æ˜¯å¦éœ€è¦è¿œç¨‹åˆ†é—¸å®šäººä»»åŠ¡
     */
    @Override
    public   void autoCloseCmdTimer(){
        if(Constants.DEALING_DUANLUQI_CLOSE){
            return;
        }
        log.error("开启定时远程控制断路器开始=========");
        Constants.DEALING_DUANLUQI_CLOSE = true;
        try {
            List<Device> devices = deviceMapper.selectList(new QueryWrapper<Device>().lambda()
                    .eq(Device::getType,Constants.DEVICE_TYPE.duanluqi)//断路器
                    .isNotNull(Device::getLevel)//配置了空闲时长限制
                    .isNotNull(Device::getDoorName)//配置了MQTT参数
                    .isNotNull(Device::getChannelInfo)//配置了控制开关序号
                    .eq(Device::getIsUsed,Constants.ZERO)
                    .eq(Device::getIsdeleted,Constants.ZERO)
            );
            if(devices!=null && devices.size()>0){
                for(Device device : devices){
                    try {
                        long time = (long)getNumberByStr(device.getLevel());//控制时长
                        if(time < 300 ){
                            log.error("开启定时远程控制断路器分闸失败=========空闲时长未正确配置"+time);
                            continue;
                        }
                        double closeDianliu = getCloseDianliuByParam(device);
                        if(closeDianliu < 0 ){
                            log.error("开启定时远程控制断路器分闸失败=========空闲电流阈值设置错误"+closeDianliu);
                            continue;
                        }
                        List<String> closeBtn = new ArrayList<>();
                        String[] btns = device.getChannelInfo().split(",");
                        Date startDate = new Date((System.currentTimeMillis()-time*1000));//查询开始时间
                        List<DeviceData> dataList = deviceDataMapper.selectList(new QueryWrapper<DeviceData>().lambda()
                                .eq(DeviceData::getDeviceId,device.getId())
                                .in(DeviceData::getVal1,btns)
                                .ge(DeviceData::getHappenTime,DateUtil.getPlusTime2(startDate))
                                .orderByDesc(DeviceData::getHappenTime));
                        if(dataList != null && dataList.size()>0 ){
                           for(String b : btns){
                               DeviceData last = getLastDataByVal1(b,dataList,closeDianliu);
                               if(last !=null && StringUtils.equals(last.getVal7(),"1")){
                                   closeBtn.add(b);//需要分闸
                               }
                           }
                           if(StringUtils.equals( dataList.get(0).getVal7(),"0")){
                               log.error("开启定时远程控制断路器分闸结束======分闸状态无需操作==="+device.getName());
                               continue;
                           }
                        }
                        if(closeBtn.size()>0){
                            Device param = new Device();
                            param.setLoginUserInfo(new LoginUserInfo());
                            param.getLoginUserInfo().setRealname("系统自动控制");
                            param.setChannelNo(String.join(",",closeBtn));
                            param.setId(device.getId());
                            param.setStatus(Constants.ZERO);
                            dealDuanluqiCmd(device,param,"deviceTimer_");
                        }
                    }catch (Exception e){
                        log.error("开启定时远程控制断路器分闸失败========="+device.getName()+e.getMessage());
                    }
                }
            }
            log.error("开启定时远程控制断路器分闸数量========="+devices.size());
        }catch (Exception e){
            log.error("开启定时远程控制断路器分闸异常========="+e.getMessage());
        }finally {
            Constants.DEALING_DUANLUQI_CLOSE = false;
        }
        log.error("开启定时远程控制断路器分闸结束=========");
    }
    private double getCloseDianliuByParam(Device device) {
        try {
            JSONObject json = JSONObject.parseObject(device.getDoorName() );
            return json.getDouble("max");
        }catch (Exception e){
        }
        return 0;
    }
    private DeviceData getLastDataByVal1(String b, List<DeviceData> dataList,double limit) {
        List<DeviceData> list = new ArrayList<>();
        for(DeviceData d :dataList){
            if(StringUtils.equals(d.getVal1(),b)){
                if(limit <= getNumberByStr(d.getVal2())){
                    //如果有实时电流值大于空闲阈值,则表示工作中,不做处理
                    return null;
                }
                list.add(d);
            }
        }
        return list.size()>0?list.get(0):null;
    }
    private double getNumberByStr(String level) {
        try {
            return Double.parseDouble(level);
        }catch (Exception e){
        }
        return 0;
    }
}