doum
2025-11-27 0631137a90901f2e09a971fbf422ef476edb1c4e
最新版本541200007
已修改8个文件
653 ■■■■ 文件已修改
admin/.env.development 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaDeviceBroadcastWindow.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/deviceBroadcast.vue 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_gateway/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/HkSyncCloudController.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Device.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/DeviceServiceImpl.java 429 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/.env.development
@@ -3,9 +3,9 @@
# VUE_APP_API_URL  = 'https://atwl.ahzyssl.com/zhyq_interface'
VUE_APP_API_URL  = 'http://192.168.1.45:10010'
VUE_APP_API_URL  = 'http://localhost:10010'
# VUE_APP_API_URL  = 'http://192.168.0.7/system_gateway'
#VUE_APP_API_URL  = 'http://192.168.0.7/system_gateway'
# VUE_APP_API_URL  = 'http://localhost:10010'
admin/src/components/business/OperaDeviceBroadcastWindow.vue
@@ -15,18 +15,6 @@
          <el-form-item label="设备序列号" prop="no">
            <el-input v-model="form.no" placeholder="请输入序列号" v-trim/>
          </el-form-item>
          <el-form-item label="连接IP" prop="ip">
            <el-input v-model="form.ip" placeholder="请输入设备连接IP地址" v-trim/>
          </el-form-item>
          <el-form-item label="连接端口" prop="port">
            <el-input v-model="form.port" placeholder="请输入连接端口" v-trim/>
          </el-form-item>
          <el-form-item label="连接账号" prop="doorId">
            <el-input v-model="form.doorId" placeholder="请输入设备连接账号" v-trim/>
          </el-form-item>
          <el-form-item label="连接密码" prop="doorName">
            <el-input v-model="form.doorName" type="password"  maxlength="30" show-password></el-input>
          </el-form-item>
          <el-form-item label="所在位置" prop="regionPathName">
            <el-input v-model="form.regionPathName" placeholder="请输入所在位置" v-trim/>
          </el-form-item>
@@ -50,28 +38,12 @@
        name: '',
        regionPathName: '',
        no: '',
        type: 4,
        ip: '',
        port: '',
        doorId: '',
        doorName:''
        type: 4
      },
      // 验证规则
      rules: {
        name: [
          { required: true, message: '请输入设备名称' }
        ],
        ip: [
          { required: true, message: '请输入设备连接IP地址' }
        ],
        port: [
          { required: true, message: '请输入设备连接端口号' }
        ],
        doorId: [
          { required: true, message: '请输入设备连接账号' }
        ],
        doorName: [
          { required: true, message: '请输入设备连接密码' }
        ],
        hkId: [
          { required: true, message: '请输入设备唯一码' }
admin/src/views/business/deviceBroadcast.vue
@@ -12,22 +12,37 @@
        </el-form>
        <!-- 表格和分页 -->
        <template v-slot:table-wrap>
            <ul class="toolbar">
                <li><el-button type="primary" @click="synchronousData">同步</el-button></li>
            </ul>
          <ul class="toolbar" v-permissions="['business:device:create', 'business:device:delete']">
            <li><el-button type="primary" :loading="isWorking.delete" @click="synchronousData">同步</el-button></li>
            <li><el-button type="primary" @click="$refs.operaDeviceWindow.open('新建广播')" icon="el-icon-plus" v-permissions="['business:device:create']">新建</el-button></li>
            <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:device:delete']">删除</el-button></li>
          </ul>
            <el-table
                :height="tableHeightNew"
                v-loading="isWorking.search"
                :data="tableData.list"
                stripe
            >
              <el-table-column type="selection" width="55"></el-table-column>
              <el-table-column label="序号"  width="55" fixed><template slot-scope="scope" >{{scope.$index+1}}</template></el-table-column>
                <el-table-column prop="name" label="名称"></el-table-column>
                <el-table-column prop="hkId" label="唯一标识" min-width="200"></el-table-column>
                <el-table-column prop="channelInfo" label="类型"></el-table-column>
                <el-table-column prop="channelNo" label="设备号"></el-table-column>
                <el-table-column prop="regionName" label="区域编码"></el-table-column>
                <el-table-column prop="hkDate" label="同步时间"></el-table-column>
                <el-table-column prop="hkId" label="唯一标识"  ></el-table-column>
                <el-table-column prop="no" label="序列号"  ></el-table-column>
                <el-table-column prop="regionPathName" label="所在位置"></el-table-column>
                <el-table-column prop="editDate" label="最近更新时间"></el-table-column>
                <el-table-column
                    v-if="containPermissions(['business:devicerole:update', 'business:devicerole:delete'])"
                    label="操作"
                    align="center"
                    min-width="120"
                    fixed="right"
                >
                  <template slot-scope="{row}">
                    <el-button type="text" @click="$refs.operaDeviceWindow.open('编辑广播', row)" icon="el-icon-edit" v-permissions="['business:device:update']">编辑</el-button>
                    <el-button type="text" @click="send(row)" icon="el-icon-edit"  v-permissions="['business:device:update']">发送播报</el-button>
                    <el-button type="text" class="red" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:device:delete']">删除</el-button>
                  </template>
                </el-table-column>
            </el-table>
            <pagination
                @size-change="handleSizeChange"
@@ -36,8 +51,26 @@
            >
            </pagination>
        </template>
      <el-dialog
          :visible.sync="visibleSend"
          style="z-index: 100000"
          append-to-body
          width="50%"
          height="50%"
          :title="'发送播报-'+ form.name"
      >
        <el-form :model="form" ref="form" >
          <el-form-item label="播报内容" prop="name" required>
            <el-input v-model="form.sendInfo" type="textarea" placeholder="请输入播报内容" v-trim/>
          </el-form-item>
        </el-form>
        <template  v-slot:footer  >
          <el-button @click="sendBobao()" type="primary" :loading="isWorkSending">确认</el-button>
          <el-button @click="sendClose()">返回</el-button>
        </template>
      </el-dialog>
        <!-- 新建/修改 -->
    <OperaDeviceWindow ref="operaDeviceWindow" @success="handlePageChange"/>
    <OperaDeviceBroadcastWindow ref="operaDeviceWindow" @success="handlePageChange"/>
    </TableLayout>
</template>
@@ -45,12 +78,11 @@
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaDeviceWindow from '@/components/business/OperaDeviceWindow'
import { syncDevices, updateEntranceById } from '@/api/business/device'
import OperaDeviceBroadcastWindow from '@/components/business/OperaDeviceBroadcastWindow'
export default {
  name: 'Device',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaDeviceWindow },
  components: { TableLayout, Pagination, OperaDeviceBroadcastWindow },
  data () {
    return {
      // 搜索
@@ -61,6 +93,14 @@
        online: '',
        type: 4
      },
      isWorkSending: false,
      form: {
        sendInfo: '',
        id: '',
        hkId: '',
        name: ''
      },
      visibleSend: false,
      options: []
    }
  },
@@ -74,17 +114,40 @@
    this.search()
  },
  methods: {
    changeManufature(e, row) {
      updateEntranceById({
        id: row.id,
        isEntrance: e
      })
    sendBobao () {
      if(!this.form.sendInfo){
        return
      }
      this.$dialog.actionConfirm('确认进行广播播报吗?','操作确认提醒')
        .then(() => {
          this.isWorkSending = true
          this.api.sendBobao(this.form)
            .then(res => {
              this.$tip.apiSuccess(res || '播报请求成功')
              this.sendClose()
            })
            .catch(e => {
            })
            .finally(() => {
              this.isWorkSending = false
            })
        })
        .catch(() => {})
    },
    synchronousData () {
    send (row) {
      this.visibleSend = true
      this.form = { sendInfo: '', id: row.id, hkId: row.hkId, name: row.name }
    },
    sendClose () {
      this.visibleSend = false
      this.isWorkSending = false
      this.form = { sendInfo: '', id: '', hkId: '', name: '' }
    },
     synchronousData () {
      this.$dialog.actionConfirm('操作确认提醒', '您确认同步全部信息吗?')
        .then(() => {
          this.isWorking.delete = true
          syncDevices({type: 3})
          syncDevices({type: 4})
            .then(res => {
              this.$tip.apiSuccess(res || '同步成功')
              this.search()
server/system_gateway/src/main/resources/bootstrap.yml
@@ -1,6 +1,6 @@
spring:
  profiles:
    active: pro
    active: dev
  application:
    name: system_gateway
  # 安全配置
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/HkSyncCloudController.java
@@ -116,7 +116,7 @@
            //同步LED
            result = hkSyncDeviceService.syncHkLed(param);
        }else if(Constants.equalsInteger(param.getType(),Constants.THREE)){
            //同步广播点
            //同步广播
            result = hkSyncDeviceService.syncHkBroadcast(param);
        }else if(Constants.equalsInteger(param.getType(),Constants.FOUR)){
            //同步广播
@@ -320,83 +320,30 @@
    @PostMapping("/regionList")
    public ApiResponse<List<PageRegionInfoResponse> > getRegionList(HttpServletResponse response, @RequestHeader(Constants.HEADER_USER_TOKEN) String token ){
        CarmeraListVO param  =new CarmeraListVO();
        param.setWithCameras(2);
        param.setWithCameras(0);
        List<PageRegionInfoResponse>  result = new ArrayList<>();
        try {
            result = boardService.getRegionTree( param);
        }catch (Exception e){
        }
        boolean debug =false;
         if(debug && result.size()==0){
//            result = boardService.getRegionTree( param);
            //------TODO---------测试模拟数据----start-----
            for (int i = 0; i < 5; i++) {
                PageRegionInfoResponse t = new PageRegionInfoResponse();
                t.setName("总区域_"+i);
                t.setIndexCode(i+"_code");
                t.setChildList(new ArrayList<>());
                t.setCarmeraList(new ArrayList<>());
                CarmeraListVO c= new CarmeraListVO();
                c.setName("监控点11"+i);
                c.setIndexCode("jkd11"+i);
                t.getCarmeraList().add(c);
                c= new CarmeraListVO();
                c.setName("监控点12"+i);
                c.setIndexCode("jkd12"+i);
                t.getCarmeraList().add(c);
                for (int j = 0; j < 5; j++) {
                    PageRegionInfoResponse t1 = new PageRegionInfoResponse();
                    t1.setName("子区域_"+i+"_"+j);
                    t1.setIndexCode(i+"_"+j+"_ChildCode");
                    t1.setParentIndexCode(t.getIndexCode());
                    t1.setCarmeraList(new ArrayList<>());
                    t1.setDeviceList(new ArrayList<>());
                    t1.setSensorList(new ArrayList<>());
                    CarmeraListVO c1= new CarmeraListVO();
                    c1.setName(i+"监控点111"+j);
                    c1.setIndexCode(i+"jkd111"+j);
                    t1.getCarmeraList().add(c1);
                    c1= new CarmeraListVO();
                    c1.setName(i+"监控点112"+j);
                    c1.setIndexCode(i+"jkd112"+j);
                    t1.getCarmeraList().add(c1);
                    c1= new CarmeraListVO();
                    c1.setName(i+"传感器111"+j);
                    c1.setIndexCode(i+"cgq111"+j);
                    t1.getSensorList().add(c1);
                    c1= new CarmeraListVO();
                    c1.setName(i+"传感器111112"+j);
                    c1.setIndexCode(i+"cgq112"+j);
                    t1.getSensorList().add(c1);
                    c1= new CarmeraListVO();
                    c1.setName(i+"消防设备111"+j);
                    c1.setIndexCode(i+"xf111"+j);
                    t1.getDeviceList().add(c1);
                    c1= new CarmeraListVO();
                    c1.setName(i+"消防设备111112"+j);
                    c1.setIndexCode(i+"xf112"+j);
                    t1.getDeviceList().add(c1);
                    t.getChildList().add(t1);
                }
                result.add(t);
            }
            //------TODO---------测试模拟数据----end-----
        }catch (Exception e){
        }
        return ApiResponse.success(result);
    }
    @ApiOperation("【海康】强制刷新区域、监控、消防设备缓存")
    @PostMapping("/refreshRegionData")
    public ApiResponse<String > refreshRegionData(HttpServletResponse response, @RequestHeader(Constants.HEADER_USER_TOKEN) String token ){
        boardService.cacheRegionAndDeviceData( );
        return ApiResponse.success(null);
    }
@@ -409,12 +356,7 @@
    }
    @ApiOperation("【海康】广播播报")
    @PostMapping("/sendBobao")
    public ApiResponse<String> setBroadcaseBobao(@RequestBody Device body  , HttpServletResponse response) {
        return ApiResponse.success( deviceService.setBroadcaseBobaoHttp(body));
    }
    @ApiOperation("【海康】广播播报")
    @PostMapping("/sendBobaoOpenApi")
    public ApiResponse<List<Map<String,Object>>> sendBobaoOpenapi(@RequestBody Device body  , HttpServletResponse response) {
    public ApiResponse<List<Map<String,Object>>> setBroadcaseBobao(@RequestBody Device body  , HttpServletResponse response) {
        deviceService.setBroadcaseBobao(body);
        return ApiResponse.success(null);
    }
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.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.service.business.third.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
@@ -155,8 +156,9 @@
    private String doorName;
    @ApiModelProperty(value = "播报内容")
    @TableField(exist = false)
    private String sendInfo;
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceService.java
@@ -5,8 +5,6 @@
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;
/**
@@ -15,7 +13,6 @@
 * @date 2023/11/30 15:33
 */
public interface DeviceService {
    /**
     * 创建
@@ -111,12 +108,4 @@
    void allLedDefualtContent();
    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
@@ -1,6 +1,5 @@
package com.doumee.service.business.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.doumee.biz.system.SystemDictDataBiz;
@@ -11,15 +10,13 @@
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.*;
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;
@@ -29,14 +26,11 @@
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;
/**
@@ -49,11 +43,7 @@
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private MqttBizService mqttBizService;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Autowired
    private PlatformMapper platformMapper;
    @Autowired
@@ -62,8 +52,6 @@
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private PlatformBroadcastLogMapper platformBroadcastLogMapper;
    @Autowired
    private InterfaceLogMapper interfaceLogMapper;
    @Override
@@ -73,14 +61,6 @@
        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();
    }
@@ -115,35 +95,7 @@
    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()));
        }
        Device model = deviceMapper.selectById(device.getId());
        if(model ==null){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        if(Constants.equalsInteger(model.getType(),Constants.DEVICE_TYPE.duanluqi)){
            //如果是斷路器
            if( Constants.equalsInteger(model.getIsUsed(),Constants.ZERO)
                    && StringUtils.equals(device.getDoorName(),model.getDoorName())){
                //如果配置参数发生了变化,设置状态未启用
                device.setIsUsed(Constants.ONE);
                try {
                    MqttClient mqttClient = MqttClientCache.clientMapCache.get("device"+device.getId());
                    if(mqttClient !=null){
                        if(mqttClient.isConnected()){
                            mqttClient.disconnect();
                        }
                        mqttClient.close();
                        MqttClientCache.clientMapCache.remove("device"+device.getId());
                    }
                }catch (Exception e){
                    log.error("==============端口mqtt链接失败:"+model.getName()+e.getMessage());
                }
            }
        }
        deviceMapper.updateById(device);
    }
    @Override
@@ -158,16 +110,7 @@
    @Override
    public Device findById(Integer 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;
        return deviceMapper.selectById(id);
    }
    @Override
@@ -178,7 +121,6 @@
    @Override
    public List<Device> findList(Device device) {
        device.setIsdeleted(Constants.ZERO);
        QueryWrapper<Device> wrapper = new QueryWrapper<>(device);
        return deviceMapper.selectList(wrapper);
    }
@@ -191,20 +133,7 @@
               .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());
        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;
        return deviceMapper.selectList(wrapper);
    }
  
    @Override
@@ -241,12 +170,6 @@
        }
        if (pageWrap.getModel().getName() != null) {
            queryWrapper.lambda().like(Device::getName, pageWrap.getModel().getName());
        }
        if (pageWrap.getModel().getDoorNo() != null) {
            queryWrapper.lambda().like(Device::getDoorNo, pageWrap.getModel().getDoorNo());
        }
        if (pageWrap.getModel().getNo() != null) {
            queryWrapper.lambda().like(Device::getNo, pageWrap.getModel().getNo());
        }
        if (pageWrap.getModel().getDoorName() != null) {
            queryWrapper.lambda().like(Device::getDoorName, pageWrap.getModel().getDoorName());
@@ -319,20 +242,7 @@
                queryWrapper.orderByAsc(sortData.getProperty());
            }
        }
        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);
        return PageData.from(deviceMapper.selectPage(page, queryWrapper));
    }
    @Override
@@ -356,192 +266,6 @@
        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){
                    if(mqttClient.isConnected()){
                        mqttClient.disconnect();
                    }
                    mqttClient.close();
                    MqttClientCache.clientMapCache.remove("device"+param.getId());
                }
            }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()));
        DeviceData data = new DeviceData();
        data.setCreateDate(new Date());
        data.setEditDate(new Date());
        data.setCreator(param.getLoginUserInfo().getId());
        data.setEditor(param.getLoginUserInfo().getId());
        data.setDeviceId(param.getId()+"");
        data.setDataType(Constants.ONE);//
        data.setVal1("远程控制");
        data.setVal2(curremak);
        data.setHappenTime(DateUtil.getPlusTime2(data.getCreateDate()));
        data.setVal3((Constants.equalsInteger(param.getStatus(),Constants.ONE)?"【合闸】":"【分闸】"));
        data.setVal4(param.getLoginUserInfo().getRealname());
        data.setVal5(param.getChannelNo());
        deviceDataMapper.insert(data);
    }
    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){
        Device model = deviceMapper.selectById(param.getId());
        if(model ==null && Constants.equalsInteger(param.getType(),Constants.FOUR)){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        String input = "";
        model.setSendInfo(param.getSendInfo());
        return  sendBroadcaseBobaoHttpBiz(model,interfaceLogMapper);
    }
    public static String sendBroadcaseBobaoHttpBiz(Device model,InterfaceLogMapper interfaceLogMapper){
        //重新下发计划
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("command","start");
        jsonObject.put("TTSContent",model.getSendInfo());
        jsonObject.put("audioLevel",6);
        jsonObject.put("audioVolume",100);
        jsonObject.put("TTSLanguageType","chinese");
        jsonObject.put("voiceType","female");
        jsonObject.put("pace",50);
        JSONArray a = new JSONArray();
        a.add(1);
        jsonObject.put("audioOutID",a);
        String params =jsonObject.toJSONString();
        log.error("========海康广播播放入参内容 : " + params);
        String result = HttpsUtil.doPutHk(model.getIp(),Integer.parseInt(StringUtils.defaultString(model.getPort(),"80")),model.getDoorId(), model.getDoorName()
                ,"/ISAPI/AccessControl/EventCardLinkageCfg/TTSAudio?format=json",params);
        log.error("========海康广播播放返回内容 : " + result);
        JSONObject resultJson = JSONObject.parseObject(result);
        Boolean success = false;
        if(Constants.equalsInteger(resultJson.getInteger("statusCode"),Constants.ONE)){
            success = true;
        }
        InterfaceLog log = new InterfaceLog();
        log.setCreateDate(new Date());
        log.setUrl("/ISAPI/AccessControl/EventCardLinkageCfg/TTSAudio?format=json");
        log.setEditDate(log.getCreateDate());
        log.setPlat(Constants.ZERO);
        log.setName("海康广播播放");
        log.setIsdeleted(Constants.ZERO);
        log.setRequest(params);
        log.setType(Constants.ZERO);
        log.setSuccess(success?Constants.ZERO:Constants.ONE);
        log.setRepose(result);
        interfaceLogMapper.insert(log);
        return result;
    }
    @Override
    public void setLedContent(TransparentChannelSingleRequest model) {
@@ -599,149 +323,8 @@
            }catch (Exception e){
                log.error( "对不起,屏幕内容设置异常"+ device.getName());
            }
        }
        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::getDataType,Constants.ZERO)
                                .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;
    }
}