doum
2026-03-10 92cd2a4474d33cee339f5da9d2ea51fd32b3f74a
新增智能电表、空调管理
已添加10个文件
已修改25个文件
2094 ■■■■■ 文件已修改
admin/.env.development 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/device.js 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/deviceData.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaDeviceDianbiaoWindow.vue 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaDianbiaoDataListWindow.vue 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/deviceDianbiao.vue 211 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/roomStatus/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_gateway/src/main/resources/application-dev.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_gateway/src/main/resources/application-test.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_gateway/src/main/resources/bootstrap-dev.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_gateway/src/main/resources/bootstrap-test.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/core/utils/Constants.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_timer/src/main/resources/application-dev.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_timer/src/main/resources/application-pro.yml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_timer/src/main/resources/application-test.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_timer/src/main/resources/bootstrap-dev.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_timer/src/main/resources/bootstrap-test.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_timer/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/admin_timer/src/main/resources/bootstrap-dev.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/admin_timer/src/main/resources/bootstrap-test.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/DeviceCloudController.java 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/DeviceDataCloudController.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/resources/bootstrap-dev.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/resources/bootstrap-test.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/core/device/WaterElectricityUtil.java 600 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/DeviceDataMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Device.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/DeviceData.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceDataService.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceService.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/DeviceDataServiceImpl.java 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/DeviceServiceImpl.java 293 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/resources/application-dev.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/resources/application-test.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/.env.development
@@ -3,13 +3,6 @@
# é¡¹ç›®ä¸Šä¸‹æ–‡è·¯å¾„
VUE_APP_CONTEXT_PATH = './'
#VUE_APP_API_URL  = 'http://localhost:10010'
VUE_APP_API_URL  = 'http://localhost:10010'
# VUE_APP_API_URL  = 'http://192.168.0.143:10010'
# VUE_APP_API_URL  = 'https://dmtest.ahapp.net/fn_admin'
# VUE_APP_API_URL  = 'http://10.50.250.253:8088/gateway_interface'
VUE_APP_API_URL  = 'https://zhcg.fnwtzx.com/gateway_interface'
#VUE_APP_API_URL  = 'https://zhcg.fnwtzx.com/gateway_interface'
admin/src/api/business/device.js
@@ -12,9 +12,13 @@
  return request.post('/visitsAdmin/cloudService/business/hksync/syncDevices', data)
}
// èŽ·å–é—¨ç¦é›†åˆ-提供给门禁组
export function getList (data) {
  return request.post('/visitsAdmin/cloudService/business/device/getList', data)
}
export function allList (data) {
  return request.post('/visitsAdmin/cloudService/business/device/list', data)
}
export function getDeviceRoleList (data) {
  return request.post('/visitsAdmin/cloudService/business/deviceRole/list', data)
@@ -24,12 +28,44 @@
export function updateById (data) {
  return request.post('/visitsAdmin/cloudService/business/device/updateById', data)
}
export function create (data) {
  return request.post('/visitsAdmin/cloudService/business/device/create', data)
}
export function dianbiaoData(data) {
  return request.post('/visitsAdmin/cloudService/business/device/dianbiaoData', data)
}
// ä¿®æ”¹æ˜¯å¦é—¨ç¦å…¥å£
export function updateEntranceById (data) {
  return request.post('/visitsAdmin/cloudService/business/device/updateEntranceById', data)
}
export function updateUsedById (data) {
  return request.post('/visitsAdmin/cloudService/business/device/updateUsedById', data)
}
export function duanluqiCmd (data) {
  return request.post('/visitsAdmin/cloudService/business/device/duanluqiCmd', data)
}
export function dianbaoCmd (data) {
  return request.post('/visitsAdmin/cloudService/business/device/dianbaoCmd', data)
}
// å‘生led屏内容
export function setLedContent (data) {
  return request.post('/visitsAdmin/cloudService/business/hksync/setLedContent', data)
}
export function sendBobao (data) {
  return request.post('/visitsAdmin/cloudService/business/hksync/sendBobao', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/visitsAdmin/cloudService/business/device/delete/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/visitsAdmin/cloudService/business/device/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/api/business/deviceData.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/visitsAdmin/cloudService/business/deviceData/page', data, {
    trim: true
  })
}
admin/src/components/business/OperaDeviceDianbiaoWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,147 @@
<template>
    <GlobalWindow
        :title="title"
        :visible.sync="visible"
        width="65%"
        :confirm-working="isWorking"
        @confirm="confirm"
    >
        <el-form :model="form" ref="form" :rules="rules">
          <p class="tip-header" >基本信息</p>
          <el-form-item label="设备名称" prop="name">
            <el-input v-model="form.name" placeholder="请输入名称" v-trim/>
          </el-form-item>
          <el-form-item label="设备地址域" prop="no">
            <el-input v-model="form.no" placeholder="请输入设备标识符" v-trim/>
          </el-form-item>
          <el-form-item label="设备号" prop="doorNo">
            <el-input v-model="form.doorNo" placeholder="请输入序列号" v-trim/>
          </el-form-item>
          <el-form-item label="厂商" prop="manufature">
            <el-input v-model="form.manufature" placeholder="请输入厂商" v-trim/>
          </el-form-item>
          <el-form-item label="安装位置" prop="regionPathName">
            <el-input v-model="form.regionPathName" 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="channelNo">
            <el-input v-model="form.channelNo" type="number" placeholder="请输入电流比" v-trim>
              <template slot="append">/5A</template>
            </el-input>
          </el-form-item>
          <el-form-item label="密码等级" prop="pwdLevel">
            <el-input v-model="form.doorNameObj.pwdLevel" placeholder="请输入密码等级" v-trim/>
          </el-form-item>
          <el-form-item label="密码" prop="pwd">
            <el-input v-model="form.doorNameObj.pwd" placeholder="请输入连接密码" v-trim/>
          </el-form-item>
          <el-form-item label="操作者代码" prop="userCode">
            <el-input v-model="form.doorNameObj.userCode" placeholder="请输入设备操作者代码" v-trim/>
          </el-form-item>
        </el-form>
    </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  name: 'OperaDeviceDuanluqiWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        name: '',
        regionPathName: '',
        doorNo: '',
        no: '',
        type: 6,
        ip: '',
        port: '',
        level: '',
        doorName: '',
        doorId: '',
        doorNameObj: {
          pwdLevel: '',
          pwd: '',
          userCode: ''
        },
        channelInfo: '',
        manufature: '',
        channelNo: ''
      },
      // éªŒè¯è§„则
      rules: {
        name: [
          { required: true, message: '请输入设备名称' }
        ],
        doorName: [
          { required: true, message: '请输入设备连接密码' }
        ],
        channelNo: [
          { required: true, message: '请输入开关序号' }
        ],
        doorNo: [
          { required: true, message: '请输入设备号' }
        ],
        no: [
          { required: true, message: '请输入设备标识符' }
        ]
      }
    }
  },
  created () {
    this.config({
      api: '/business/device',
      'field.id': 'id'
    })
  },
  methods: {
    open (title, target) {
      this.title = title
      this.visible = true
      this.form.doorName = ''
      this.form.doorNameObj = {
        userCode: '',
        pwd: '',
        pwdLevel: ''
      }
      // debugger
      // æ–°å»º
      if (target == null) {
        this.$nextTick(() => {
          this.$refs.form.resetFields()
          this.form[this.configData['field.id']] = null
        })
        if(!this.form.doorNameObj){
          this.form.doorNameObj = {
            pwdLevel: '',
            pwd: '',
            userCode: ''
          }
        }
        return
      }
      // ç¼–辑
      this.$nextTick(async () => {
        if(!target.doorNameObj){
          target.doorNameObj={
            pwdLevel: '',
            pwd: '',
            userCode: ''}
        }
        for (const key in this.form) {
          this.form[key] = target[key]
        }
      })
    }
  }
}
</script>
admin/src/components/business/OperaDianbiaoDataListWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,177 @@
<template>
  <GlobalWindow
      :title="title"
      width="100%"
      :visible.sync="visible"
  >
    <TableLayout >
      <!-- æœç´¢è¡¨å• -->
      <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
        <div  style="display: block;margin-bottom: 60px;padding: 20px; border: 1px solid #f2f2f2;">
          <div style="display: block;font-size: 16px;font-weight: 600;margin-bottom: 20px;">设备信息</div>
          <div style="display: flex;">
            <div style="flex: 1"><span class="label">名称:</span>{{model.name ||''}}</div>
            <div style="flex: 1"><span  class="label">地址域:</span>{{model.no ||''}}</div>
            <div style="flex: 1"><span  class="label">设备号:</span>{{model.doorNo ||'-'}}</div>
          </div>
          <div style="display: flex;margin-top: 20px;">
            <div style="flex: 1"><span  class="label">IP:</span>{{ model.ip ||'' }}</div>
            <div style="flex: 1"><span  class="label">端口:</span>{{ model.port ||''}}</div>
            <div style="flex: 3">
              <span class="label">最近控制操作:</span>
              <span class="orange" >{{model.remark||''}}</span>
            </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>
      <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
      <template  v-slot:table-wrap>
        <el-table
            v-if="activeGroup===0"
            v-loading="isWorking.search"
            :data="tableData.list"
            stripe>
          <el-table-column prop="happenTime" label="读取时间" min-width="150px"></el-table-column>
          <el-table-column prop="val1" label="电能(KWH)" min-width="120px"></el-table-column>
          <el-table-column prop="val2" label="状态" min-width="120px">
            <template slot-scope="{row}">
              <span v-if=" row.val2 === '0000'" class="green">合闸</span>
              <span  v-else-if=" row.val2 === '0050'" class="red">分闸</span>
              <span v-else>-</span>
            </template>
          </el-table-column>
          <el-table-column prop="val3" label="电表时间" min-width="120px"></el-table-column>
        </el-table>
        <el-table
            v-if="activeGroup===1"
            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="val2" label="内容" min-width="300px" show-overflow-tooltip></el-table-column>
        </el-table>
        <pagination
            @size-change="handleSizeChange"
            @current-change="handlePageChange"
            :pagination="tableData.pagination"
        >
        </pagination>
      </template>
    </TableLayout>
    <template   v-slot:footer>
      <el-button @click="visible=false">返回</el-button>
    </template>
  </GlobalWindow>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  name: 'OperaJkSketchCustomerWindow',
  extends: BaseTable,
  components: { GlobalWindow, TableLayout, Pagination },
  data () {
    return {
      // è¡¨å•数据
      visible: false,
      title: '',
      activeGroup:0,
      model:{doorNameObj:{}},
      groupList: [{ id: 0, name: '数据上报记录', type: 0 }, { id: 1, name: '远程控制记录', type: 1 }],
      searchForm: {
        deviceId:  null,
        val1: '',
        dataType:0
      }
    }
  },
  created () {
    this.config({
      module: '设备数据信息表',
      api: '/business/deviceData',
      'field.id': 'id',
      'field.main': 'id'
    })
    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
      if(!row.doorNameObj) {
        row.doorNameObj = {}
      }
      this.model=row
      this.visible = true
      this.tableData = {
        // å·²é€‰ä¸­çš„æ•°æ®
        selectedRows: [],
        // æŽ’序的字段
        sorts: [],
        // å½“前页数据
        list: [],
        // åˆ†é¡µ
        pagination: {
          pageIndex: 1,
          pageSize: 10,
          total: 0
        }
      }
      this.groupClick(this.groupList[0])
    }
  }
}
</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;*/
  color: rgb(102, 102, 102);
  display: inline-block;
}
</style>
admin/src/views/business/deviceDianbiao.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,211 @@
<template>
    <TableLayout :permissions="['business:device:query']">
        <!-- æœç´¢è¡¨å• -->
        <el-form ref="searchForm"  slot="search-form" :model="searchForm" label-width="100px" inline>
            <el-form-item title="名称" prop="name">
                <el-input v-model="searchForm.name" placeholder="请输入名称" @keypress.enter.native="search"></el-input>
            </el-form-item>
            <el-form-item title="标识符" prop="no">
                <el-input v-model="searchForm.no" placeholder="请输入设备标识符" @keypress.enter.native="search"></el-input>
            </el-form-item>
            <el-form-item title="设备号" prop="doorNo">
                <el-input v-model="searchForm.doorNo" placeholder="请输入设备号" @keypress.enter.native="search"></el-input>
            </el-form-item>
            <section>
                <el-button type="primary" @click="search">搜索</el-button>
                <el-button @click="reset">重置</el-button>
            </section>
        </el-form>
        <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
        <template v-slot:table-wrap>
          <ul class="toolbar" v-permissions="['business:device:create', 'business:device:delete']">
            <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
                v-loading="isWorking.search"
                :data="tableData.list"
                stripe >
              <el-table-column type="selection" width="55"></el-table-column>
              <el-table-column prop="name" label="名称" fixed min-width="150" align="center"></el-table-column>
              <el-table-column prop="no" label="电表地址域" min-width="100" align="center" ></el-table-column>
              <el-table-column prop="doorNo" label="设备号"  min-width="120" align="center" show-overflow-tooltip></el-table-column>
<!--
              <el-table-column prop="channelNo" label="开关序号" align="center" min-width="100"></el-table-column>
-->
              <el-table-column prop="manufature" label="厂商" align="center" min-width="100" show-overflow-tooltip></el-table-column>
              <el-table-column prop="regionPathName" align="center"  min-width="100" label="所在位置"></el-table-column>
              <el-table-column prop="ip" label="IP"  min-width="150" align="center" show-overflow-tooltip ></el-table-column>
              <el-table-column prop="port" label="端口" align="center"  ></el-table-column>
              <el-table-column prop="isUsed" label="是否使用">
                <template slot-scope="{row}">
                  <el-switch @change="changeUsed($event, row)" v-model="row.isUsed" active-color="#13ce66"
                             inactive-color="#ff4949" :active-value="0" :inactive-value="1">
                  </el-switch>
                </template>
              </el-table-column>
              <el-table-column prop="doorNameObj.pwdLevel" label="密码等级" align="center" min-width="150"></el-table-column>
              <el-table-column prop="doorNameObj.pwd" label="密码" align="center">
                <template slot-scope="{row}">
                  <span :class=" 'blue'">{{row.showPwd?row.doorNameObj.pwd:'******'}}</span>
                  <el-button  style="margin-left: 10px" v-if="row.doorNameObj.pwd!=null"
                              @click.native.p.prevent="showPassward(row)" type="text">
                    <i class="el-icon-view" :class="row.showPwd?'red':'blue'" :title="row.showPwd?'隐藏':'显示'"></i>
                  </el-button>
                </template>
              </el-table-column>
              <el-table-column prop="doorNameObj.userCode" label="操作者代码" align="center" min-width="150"></el-table-column>
              <el-table-column prop="editDate" label="最近更新时间" align="center" min-width="150"></el-table-column>
              <el-table-column
                  label="操作"
                  align="center"
                  min-width="280"
                  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="$refs.operaDeviceDataWindow.open('查看电表数据', row)" icon="el-icon-view" v-permissions="['business:device:update']">数据</el-button>
                    <el-button type="text" @click="send(row,1)" icon="el-icon-circle-check"  v-permissions="['business:device:update']">开闸</el-button>
                    <el-button type="text" class="red" @click="send(row,0)" icon="el-icon-circle-close"  v-permissions="['business:device:update']">关闸</el-button>
                    <el-button type="text" class="red" @click="readData(row)" icon="el-icon-circle-close"  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"
                @current-change="handlePageChange"
                :pagination="tableData.pagination"  >
            </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"  :rules="rules">
          <el-form-item label="执行操作:"  >
            <b class="green" v-if="form.status ===1">开闸</b>
            <b class="red" v-else>关闸</b>
          </el-form-item>
          <el-form-item label="有效时间" prop="cmdDate">
            <el-date-picker type="datetime" v-model="form.cmdDate" value-format="yyyy-MM-dd HH:mm:ss"
                            placeholder="请选择有效时间"   />
          </el-form-item>
<!--
          <p class="tip-warn" style="width: 100%;"><i class="el-icon-warning"></i></p>
-->
        </el-form>
        <template  v-slot:footer  >
          <el-button @click="sendAction(0)" type="primary" v-if="form.status === 1" :loading="isWorkSending">确认开闸</el-button>
          <el-button @click="sendAction(1)" type="danger" v-if="form.status !== 1" :loading="isWorkSending">确认关闸</el-button>
          <el-button @click="sendClose()">返回</el-button>
        </template>
      </el-dialog>
        <!-- æ–°å»º/修改 -->
    <OperaDeviceDianbiaoWindow ref="operaDeviceWindow" @success="handlePageChange"/>
    <OperaDeviceDataListWindow ref="operaDeviceDataWindow" @success="handlePageChange"/>
    </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaDeviceDataListWindow from '@/components/business/OperaDianbiaoDataListWindow'
import OperaDeviceDianbiaoWindow from '@/components/business/OperaDeviceDianbiaoWindow'
export default {
  name: 'DeviceDuanluqi',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaDeviceDianbiaoWindow, OperaDeviceDataListWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        doorNo: '',
        no: '',
        name: '',
        type: 6
      },
      isWorkSending: false,
      form: {
        id: '',
        status: null,
        name:null,
        cmdDate: null
      },
      visibleSend: false,
      options: [],
      rules: {
        cmdDate: [{ required: true, message: '请选择操作有效时间' }]
      }
    }
  },
  created () {
    this.config({
      module: '设备信息表',
      api: '/business/device',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  },
  methods: {
    changeUsed (e, row) {
      this.api.updateUsedById({
        id: row.id,
        isUsed: e
      })
    },
    showPassward (row) {
      if (!row.showPwd) {
        this.$set(row, 'showPwd', true)
      } else {
        this.$set(row, 'showPwd', false)
      }
    },
    sendAction (status) {
      this.form.status = status
      this.$dialog.actionConfirm('确认进行电表【' + (this.form.status === 1 ? '开闸' : '关闸') + '】操作吗?', '操作确认提醒')
        .then(() => {
          console.log(this.form)
          this.isWorkSending = true
          this.api.dianbaoCmd(this.form)
            .then(res => {
              this.$tip.apiSuccess(res || '请求成功')
              this.handlePageChange()
            })
            .catch(e => {
            })
            .finally(() => {
              this.isWorkSending = false
            })
        })
        .catch(() => {})
    },
    readData (row) {
      this.api.dianbiaoData({ id: row.id })
        .then(res => {
          this.$tip.apiSuccess(res || '请求成功')
          this.handlePageChange()
        })
        .catch(e => {
        })
        .finally(() => {
          this.isWorkSending = false
        })
    },
    send (row, type) {
      this.visibleSend = true
      this.form = { id: row.id, name: row.name, cmdDate: null, status: type}
    },
    sendClose () {
      this.visibleSend = false
      this.isWorkSending = false
      this.form = { id: '', name: '', status: '', cmdDate: '' }
    }
  }
}
</script>
admin/src/views/roomStatus/index.vue
@@ -288,7 +288,7 @@
                                            </div>
                                        </div>
                                        <div class="xm_house_list_right">
                                            <template v-for="(child, i) in item.roomsList" :key="i">
                                            <template v-for="(child, i) in item.roomsList" >
                                                <div class="xm_house_list_right_row" v-for="(childThree, a) in child" :key="a" :style="{ width: childThree.width + 'px', backgroundColor: ifBackground(childThree.roomStatus) }">
                                                    <div class="ft">
                                                        <span>{{childThree.roomCode}}</span>
@@ -305,7 +305,6 @@
                                                    <div class="xm_house_list_right_row_day" v-if="childThree.roomStatus === 0">未出租|空置{{childThree.freeDayAmount}}天</div>
                                                </div>
                                            </template>
                                        </div>
                                    </div>
                                </div>
@@ -498,7 +497,7 @@
                                        <el-table
                                            :data="tableData"
                                            border
                                            v-lading="loading"
                                            v-loading="loading"
                                            style="width: 100%">
                                            <el-table-column
                                                prop="categoryName"
@@ -687,6 +686,7 @@
          label: '黄金糕'
        }],
        value: '',
        ids:[],
        form: {
          name: '',
          status: '',
server/system_gateway/src/main/resources/application-dev.yml
@@ -1,9 +1,9 @@
spring:
  # æ•°æ®æºé…ç½®
  datasource:
    url: jdbc:mysql://112.26.66.25:3306/funingyunwei?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8
    url: jdbc:mysql://192.168.0.211:3306/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Doumee@168&QWERT
    password: Doumee@168
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
server/system_gateway/src/main/resources/application-test.yml
@@ -1,9 +1,9 @@
spring:
  # æ•°æ®æºé…ç½®
  datasource:
    url: jdbc:mysql://sh-cdb-aiskr3vy.sql.tencentcdb.com:62443/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: doumee
    password: rtjgfEr@&0c0m
    url: jdbc:mysql://192.168.0.211:3306/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Doumee@168
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
server/system_gateway/src/main/resources/bootstrap-dev.yml
@@ -1,13 +1,13 @@
spring:
  cloud:
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
#        namespace: dmvisit
        namespace: dev_renkang
        namespace: funingyunwei_dev
        username: nacos
        password: nacos
    gateway:
server/system_gateway/src/main/resources/bootstrap-test.yml
@@ -1,12 +1,12 @@
spring:
  cloud:
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: funing_test
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
        namespace: funingyunwei_test
#        namespace: dev_renkang
        username: nacos
        password: nacos
server/system_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -50,6 +50,8 @@
    public static final String HK_HOST ="HK_HOST" ;
    public static final String HK_APPKEY ="HK_APPKEY" ;
    public static final String LOGIN_OUT_URL ="LOGIN_OUT" ;
    public static  boolean DEALING_DUANLUQI_CLOSE = false;
    public static final String HK_APPSECRET ="HK_APPSECRET" ;
    public static final String HK_HTTPS ="HK_HTTPS" ;
    public static final String HK_PUSH_URL = "HK_PUSH_URL";
@@ -108,7 +110,16 @@
    public static final String INTERVAL = "INTERVAL";
    public static final String USE_CAR_TAKE_CARE = "USE_CAR_TAKE_CARE";
    //类型 0门禁 1车库 2LED 3广播点 4广播设备 5断路器空开 6电表
    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;
        public static final  int dianbiao = 6;
    }
    // åŠ³åŠ¡æ¥è®¿é…ç½®
server/system_timer/src/main/resources/application-dev.yml
@@ -1,9 +1,9 @@
spring:
  # æ•°æ®æºé…ç½®
  datasource:
    url: jdbc:mysql://sh-cdb-aiskr3vy.sql.tencentcdb.com:62443/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: doumee
    password: rtjgfEr@&0c0m
    url: jdbc:mysql://192.168.0.211:3306/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Doumee@168
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  redis:
server/system_timer/src/main/resources/application-pro.yml
@@ -11,10 +11,7 @@
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
debug_model: false
captcha_check: true
# Swagger配置
server/system_timer/src/main/resources/application-test.yml
@@ -1,9 +1,9 @@
spring:
  # æ•°æ®æºé…ç½®
  datasource:
    url: jdbc:mysql://sh-cdb-aiskr3vy.sql.tencentcdb.com:62443/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: doumee
    password: rtjgfEr@&0c0m
    url: jdbc:mysql://192.168.0.211:3306/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Doumee@168
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  redis:
server/system_timer/src/main/resources/bootstrap-dev.yml
@@ -10,7 +10,7 @@
        # æš‚时关闭缓存
        enabled: false
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
      #      config:
@@ -22,7 +22,7 @@
      #        group: dev
      #        data-id: com.doumee.meeting.admin
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: dev_renkang
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
        namespace: funingyunwei_dev
        username: nacos
        password: nacos
server/system_timer/src/main/resources/bootstrap-test.yml
@@ -10,7 +10,7 @@
        # æš‚时关闭缓存
        enabled: false
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
      #      config:
@@ -22,7 +22,7 @@
      #        group: dev
      #        data-id: com.doumee.meeting.admin
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: funing_test
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
        namespace: funingyunwei_test
        username: nacos
        password: nacos
server/system_timer/src/main/resources/bootstrap.yml
@@ -1,6 +1,6 @@
spring:
  profiles:
    active: pro
    active: dev
  application:
    name: systemTimer
    # å®‰å…¨é…ç½®
server/visits/admin_timer/src/main/resources/bootstrap-dev.yml
@@ -10,7 +10,7 @@
        # æš‚时关闭缓存
        enabled: false
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
#      config:
@@ -22,7 +22,7 @@
#        group: dev
#        data-id: com.doumee.meeting.admin
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: dev_renkang
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
        namespace: funingyunwei_dev
        username: nacos
        password: nacos
server/visits/admin_timer/src/main/resources/bootstrap-test.yml
@@ -10,7 +10,7 @@
        # æš‚时关闭缓存
        enabled: false
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
#      config:
@@ -22,7 +22,7 @@
#        group: dev
#        data-id: com.doumee.meeting.admin
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: funing_test
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
        namespace: funingyunwei_test
        username: nacos
        password: nacos
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/DeviceCloudController.java
@@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * @author æ±Ÿè¹„蹄
 * @date 2023/11/30 15:33
@@ -36,25 +37,55 @@
    @PostMapping("/create")
    @CloudRequiredPermission("business:device:create")
    public ApiResponse create(@RequestBody Device device,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        device.setLoginUserInfo(this.getLoginUser(token));
        return ApiResponse.success(deviceService.create(device));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @CloudRequiredPermission("business:device:delete")
    public ApiResponse deleteById(@PathVariable Integer id,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        deviceService.deleteById(id);
    public ApiResponse deleteById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        deviceService.deleteById(id,this.getLoginUser(token));
        return ApiResponse.success(null);
    }
    @ApiOperation("修改是否门禁入口")
    @PostMapping("/updateEntranceById")
    @CloudRequiredPermission("business:company:update")
    @CloudRequiredPermission("business:device:update")
    public ApiResponse updateStatusById(@RequestBody Device param,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        Device d = new Device();
        d.setId(param.getId());
        d.setEditDate(new Date());
        d.setIsEntrance(Constants.formatIntegerNum(param.getIsEntrance()));
        d.setLoginUserInfo(this.getLoginUser(token));
        deviceService.updateById(d);
        return ApiResponse.success(null);
    }
    @ApiOperation("修改是否系统使用")
    @PostMapping("/updateUsedById")
    @CloudRequiredPermission("business:device:update")
    public ApiResponse updateUsedById(@RequestBody Device param,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        Device d = new Device();
        d.setId(param.getId());
        d.setEditDate(new Date());
        d.setLoginUserInfo(this.getLoginUser(token));
        d.setIsUsed(Constants.formatIntegerNum(param.getIsUsed()));
        deviceService.updateUsedById(d);
        return ApiResponse.success(null);
    }
    @ApiOperation("执行电表开关闸操作")
    @PostMapping("/dianbaoCmd")
    @CloudRequiredPermission("business:device:update")
    public ApiResponse dianbaoCmd(@RequestBody Device param,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        param.setLoginUserInfo(this.getLoginUser(token));
        deviceService.dianbaoCmd(param);
        return ApiResponse.success(null);
    }
    @ApiOperation("读取电表数据(电能、时间和状态)")
    @PostMapping("/dianbiaoData")
    @CloudRequiredPermission("business:device:update")
    public ApiResponse dianbiaoData(@RequestBody Device param,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        param.setLoginUserInfo(this.getLoginUser(token));
        deviceService.dianbiaoData(param);
        return ApiResponse.success(null);
    }
@@ -67,7 +98,7 @@
        for (String id : idArray) {
            idList.add(Integer.valueOf(id));
        }
        deviceService.deleteByIdInBatch(idList);
        deviceService.deleteByIdInBatch(idList,this.getLoginUser(token));
        return ApiResponse.success(null);
    }
@@ -75,6 +106,8 @@
    @PostMapping("/updateById")
    @CloudRequiredPermission("business:device:update")
    public ApiResponse updateById(@RequestBody Device device,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        device.setLoginUserInfo(this.getLoginUser(token));
        deviceService.updateById(device);
        return ApiResponse.success(null);
    }
@@ -82,9 +115,15 @@
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @CloudRequiredPermission("business:device:query")
    public ApiResponse<PageData<Device>> findPage (@RequestBody PageWrap<Device> pageWrap,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
    public ApiResponse<PageData<Device>> findPage (@RequestBody PageWrap<Device> pageWrap, @RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        return ApiResponse.success(deviceService.findPage(pageWrap));
    }
    @ApiOperation("查询全部")
    @PostMapping("/list")
    @CloudRequiredPermission("business:device:query")
    public ApiResponse<List<Device>> findPage (@RequestBody   Device model,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        return ApiResponse.success(deviceService.findList(model));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/DeviceDataCloudController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package com.doumee.cloud.admin;
import com.doumee.api.BaseController;
import com.doumee.config.annotation.CloudRequiredPermission;
import com.doumee.core.annotation.excel.ExcelExporter;
import com.doumee.core.utils.Constants;
import com.doumee.dao.business.model.DeviceData;
import com.doumee.service.business.DeviceDataService;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
/**
 * @author æ±Ÿè¹„蹄
 * @date 2023/11/30 15:33
 */
@Api(tags = "设备数据信息表")
@RestController
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/business/deviceData")
public class DeviceDataCloudController extends BaseController {
    @Autowired
    private DeviceDataService deviceDataService;
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @CloudRequiredPermission("business:device:query")
    public ApiResponse<PageData<DeviceData>> findPage (@RequestBody PageWrap<DeviceData> pageWrap,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        return ApiResponse.success(deviceDataService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @CloudRequiredPermission("business:device:exportExcel")
    public void exportExcel (@RequestBody PageWrap<DeviceData> pageWrap, HttpServletResponse response, @RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        ExcelExporter.build(DeviceData.class).export(deviceDataService.findPage(pageWrap).getRecords(), "设备信息表", response);
    }
}
server/visits/dmvisit_admin/src/main/resources/bootstrap-dev.yml
@@ -10,7 +10,7 @@
        # æš‚时关闭缓存
        enabled: false
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
#      config:
@@ -22,9 +22,9 @@
#        group: dev
#        data-id: com.doumee.meeting.admin
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
#        namespace: dmvisit
        namespace: dev_renkang
        namespace: funingyunwei_dev
        username: nacos
        password: nacos
# swagger配置
server/visits/dmvisit_admin/src/main/resources/bootstrap-test.yml
@@ -10,7 +10,7 @@
        # æš‚时关闭缓存
        enabled: false
    nacos:
      server-addr: http://175.27.187.84:8848 #配置Nacos地址
      server-addr: http://192.168.0.7:8848 #配置Nacos地址
      username: nacos
      password: nacos
#      config:
@@ -22,7 +22,7 @@
#        group: dev
#        data-id: com.doumee.meeting.admin
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: funing_test
        server-addr: http://192.168.0.7:8848 #配置Nacos地址
        namespace: funingyunwei_test
        username: nacos
        password: nacos
server/visits/dmvisit_admin/src/main/resources/bootstrap.yml
@@ -1,6 +1,6 @@
spring:
  profiles:
    active: pro
    active: dev
  application:
    name: visitsAdmin
    # å®‰å…¨é…ç½®
server/visits/dmvisit_service/src/main/java/com/doumee/core/device/WaterElectricityUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,600 @@
package com.doumee.core.device;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class WaterElectricityUtil {
    private static double parseBcdToDouble(byte[] bcdBytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bcdBytes) {
            sb.append(String.format("%02X", b));
        }
        try {
            return Double.parseDouble(sb.toString());
        } catch (NumberFormatException e) {
            return 0.0;
        }
    }
    private static byte[] reverseAddress(String address) {
        byte[] result = new byte[6];
        for (int i = 0; i < 6; i++) {
            if (i * 2 + 1 < address.length()) {
                String hex = address.substring(i * 2, Math.min((i + 1) * 2, address.length()));
                result[i] = (byte) Integer.parseInt(hex, 16);
            }
        }
        return result;
    }
    private static byte calculateChecksum(byte[] data, int offset, int length) {
        int sum = 0;
        for (int i = offset; i < offset + length; i++) {
            sum += data[i] & 0xFF;
        }
        return (byte) (sum & 0xFF);
    }
    private static byte[] hexStringToByteArray(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }
    public static byte calcCS(byte[] data) {
        int sum = 0;
        for (byte b : data) {
            sum += b & 0xFF;
        }
        return (byte) (sum & 0xFF);
    }
    public static byte[] getRequestParam(int feCount, byte[] address, byte control, byte[] data) throws IOException {
        ///FEFEFE    68  999999999999    68  01  02  65  F3C1  16
//        byte b = (byte) 0xFE;
//        byte[] msg = {(byte) 0xFE,0x68};
        ByteArrayOutputStream frame = new ByteArrayOutputStream();
        for (int i = 0; i < feCount; i++) {
            frame.write(0xFE);
        }
        // 2. å¸§èµ·å§‹ç¬¦
        frame.write(0x68);
        // 3. åœ°å€åŸŸ
        frame.write(address);
        // 4. å†æ¬¡å¸§èµ·å§‹ç¬¦
        frame.write(0x68);
        // 5. æŽ§åˆ¶ç 
        frame.write(control);
        // 6. æ•°æ®é•¿åº¦
        frame.write(data.length);
        // 7. æ•°æ®åŸŸ
        frame.write(data);
        // 8. è®¡ç®— CS(从第一个 68 å¼€å§‹ï¼‰
        byte[] csData = frame.toByteArray();
        int start = feCount; // ç¬¬ä¸€ä¸ª 68 çš„位置
        byte cs = calcCS(Arrays.copyOfRange(csData, start, csData.length));
        frame.write(cs);
        // 9. ç»“束符
        frame.write(0x16);
        return frame.toByteArray();
    }
    private static byte[] readDeviceData(String ip, int port, byte[] data) {
        Socket socket = null;
        try {
            socket = new Socket(ip, port);
            socket.setSoTimeout(5000);
            java.io.OutputStream out = socket.getOutputStream();
            java.io.InputStream in = socket.getInputStream();
            out.write(data);
            out.flush();
            // è¯»å–响应
            byte[] buffer = new byte[2048];
            int bytesRead = in.read(buffer);
            byte[] response = Arrays.copyOf(buffer, bytesRead);
            // è§£æžå“åº”数据
            return response;
        } catch (Exception e) {
//            e.printStackTrace();
            throw new RuntimeException("Failed to read from device", e);
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                }
            }
        }
    }
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = String.format("%02X", b & 0xFF);
            hexString.append(hex);
        }
        return hexString.toString();
    }
    /**
     * å°†12位十进制地址转换为6字节BCD小端序地址
     *
     * @param decimalAddress 12位十进制地址字符串
     * @return 6字节的BCD地址(小端序)
     */
    private static byte[] convertToBCDAddress(String decimalAddress) {
        // 1. éªŒè¯è¾“å…¥
        if (decimalAddress == null || decimalAddress.length() != 12) {
            throw new IllegalArgumentException("地址必须是12位十进制数");
        }
        if (!decimalAddress.matches("\\d{12}")) {
            throw new IllegalArgumentException("地址必须全部是数字");
        }
        // 2. å‡†å¤‡ç»“果数组(6字节)
        byte[] result = new byte[6];
        // 3. ä»Žå³å‘左每2位一组处理(小端序)
        for (int i = 0; i < 6; i++) {
            // è®¡ç®—在字符串中的位置(从右向左)
            int strIndex = 10 - (i * 2);  // å› ä¸ºè¦å–两位,所以是10,8,6,4,2,0
            String twoDigits = decimalAddress.substring(strIndex, strIndex + 2);
            // å°†ä¸¤ä½åè¿›åˆ¶æ•°è½¬æ¢ä¸ºBCD字节
            // ä¾‹å¦‚:"25" -> 0x25
            result[i] = (byte) Integer.parseInt(twoDigits, 16);
        }
        // æ³¨æ„ï¼šä¸Šé¢çš„循环顺序已经是小端序,result[0]存的是最低两位
        return result;
    }
    private static String subByte(String value, byte sub) {
        byte b = (byte) Integer.parseInt(value, 16);
        int result = (b & 0xFF) - (sub & 0xFF);
        // ç¡®ä¿ç»“果在0-255范围内(处理负数)
        if (result < 0) {
            result += 256;
        }
        String hexResult = String.format("%02X", result & 0xFF);
        return hexResult;
    }
    private static String addByte(String value, byte add) {
        byte b = (byte) Integer.parseInt(value, 16);
        int result = (b & 0xFF) + (add & 0xFF);
        // ç¡®ä¿ç»“果在0-255范围内(处理负数)
        if (result < 0) {
            result += 256;
        }
        String hexResult = String.format("%02X", result & 0xFF);
        return hexResult;
    }
    private static String[] parseSub33Reverse(String msg, int n) {
        //33333333  3333
        String[] nArr = new String[n];
        byte _33 = 0x33;
        for (int i = 0; i < n; i++) {
            int index = i * 2;
            String twoDigits = msg.substring(index, index + 2);
            String hexResult = subByte(twoDigits, _33);
            // åå‘存储:nArr[n - i - 1] å®žçŽ°åè½¬
            nArr[n - i - 1] = hexResult;
        }
        return nArr;
    }
    public static Map<String, Object> water(String ip, int port, String address) throws IOException {
        byte[] address_buf = convertToBCDAddress(address);
        byte control = 0x01;
        byte[] data = {0x43, (byte) 0xC3};
        byte[] bufReq = getRequestParam(3, address_buf, control, data);
        byte[] resp = readDeviceData(ip, port, bufReq);
        String hex = bytesToHex(resp);
        //FEFEFE6899254652010068810843C3333433333333E916
//        System.out.println(hex);
        String msg = hex.substring(30, 30 + 8 + 4);
        String[] nArr = parseSub33Reverse(msg, 4);
        Double total = strArrNum(nArr);
        Map<String, Object> r = new HashMap<>();
        r.put("total", total);
        msg = hex.substring(40, 40 + 2);
        byte sub = 0x33;
        String hexResult = subByte(msg, sub);
        String v = hexToBinary(hexResult);
        /**
         * Y0.B0 存储器状态 (1:故障,0:正常);
         * Y0.B1 阀门状态 (1:故障,0:正常);
         * Y0.B2 信号状态 (1:故障,0:正常);
         * Y0.B3 电池状态 (1:故障,0:正常);
         * Y0.B4 保留;
         * Y0.B5 保留;
         * Y0.B6 水表通讯状态( 1:故障,0:正常);
         * Y0.B7 阀门开关状态 (1: åˆ,0:开);
         * æ³¨æ„ï¼šçŠ¶æ€ä½æ— æ—¶ä¸º 0(正常)
         * çº¢è‰²ï¼šæ— è®°å¿†ç›´è¯»è¡¨çš„状态
         */
        r.put("status", v);
        return r;
    }
    private static void electricityTotal(String ip, int port, byte[] addressBuf, Map<String, Object> map) throws IOException {
        byte control = 0x11;
        byte[] data = {0x33, 0x33, 0x33, 0x33};
        byte[] bufReq = getRequestParam(4, addressBuf, control, data);
        byte[] respBuf = readDeviceData(ip, port, bufReq);
        String resp = bytesToHex(respBuf);
        String msg = resp.substring(28 + 8, 28 + 8 + 8);
        String[] nArr = parseSub33Reverse(msg, 4);
        Double total = strArrNum(nArr);
        map.put("total", total);
    }
    /**
     * ç”µè¡¨è·³é—¸ã€åˆé—¸
     * @param ip
     * @param port
     * @param addressBuf
     * @param type ï¼ˆ0跳闸 1合闸)
     * @param date æœ‰æ•ˆæˆªæ­¢æ—¶é—´
     * @throws IOException
     */
    private static boolean electricityControl(String ip, int port, byte[] addressBuf,int type,  String date)   {
        /**
         * N1为控制命令类型,N1=1AH代表跳闸4D,N1=1BH代表合闸4F允许N2保留
         * æƒé™å¯†ç æ“ä½œä»£ç ï¼šPAP2P1P0C3C2C1C0(02/223203/111111H)
         * 4F
         * TCP/IP直接合闸指令[2026å¹´03月09日 10:57:39]
         * Tx ->FEFEFEFE68615121010000681C1035366555776655444F33568843433659E016
         * TCP/IP直接合闸指令[2026å¹´03月09日 10:57:40]
         * Rx <-FEFEFEFE68615121010000689C004016
         * ç›´æŽ¥åˆé—¸æ‰§è¡ŒæˆåŠŸï¼ 9C
         */
        try {
            byte control = 0x1C;
            byte n1 =  0x4D;
            if(type==1){
                n1 =  0x4F;
            }
//        byte[] data0 = {0x02, 0x03, 0x32, 0x22,0x44,0x33,0x22,0x11};
            byte[] data = {0x35, 0x36, 0x65, 0x55,0x77,0x66,0x55,0x44,n1,0x33,0,0,0,0,0,0};
            byte[] data2 = getDateBytes(date);
            for (int i = 0; i < data2.length; i++) {
                data[10+i]=data2[i];
            }
            byte[] bufReq = getRequestParam(4, addressBuf, control, data);
            String reqt = bytesToHex(bufReq);
            System.out.println(reqt);
            byte[] respBuf = readDeviceData(ip, port, bufReq);
            String resp = bytesToHex(respBuf);
            System.out.println(resp);
            //FEFEFEFE68379707010000689C004216
             String msg = resp.substring(24, 26);
             return msg.equals("9C");
        }catch (Exception e){
        }
        return  false;
    }
    private static byte[] getDateBytes(String dateStr) {
//        String dateStr = new SimpleDateFormat("yyyyMMddHHmmss").format(date);
        dateStr = dateStr.substring(2);
        // 1. éªŒè¯è¾“å…¥
        if (dateStr == null || dateStr.length() != 12) {
            throw new IllegalArgumentException("时间必须是12位十进制数");
        }
        if (!dateStr.matches("\\d{12}")) {
            throw new IllegalArgumentException("时间必须全部是数字");
        }
        // 2. å‡†å¤‡ç»“果数组(6字节)
        byte[] result = new byte[6];
        // 3. ä»Žå³å‘左每2位一组处理(小端序)
        byte add = 0x33;
        for (int i = 0; i < 6; i++) {
            // è®¡ç®—在字符串中的位置(从右向左)
            int strIndex = 10 - (i * 2);  // å› ä¸ºè¦å–两位,所以是10,8,6,4,2,0
            String twoDigits = dateStr.substring(strIndex, strIndex + 2);
            // å°†ä¸¤ä½åè¿›åˆ¶æ•°è½¬æ¢ä¸ºBCD字节
            // ä¾‹å¦‚:"25" -> 0x25
            int t = Integer.parseInt(twoDigits, 16);
            int t1 =   ( t& 0xFF) + (add & 0xFF);
            System.out.println(t1+":");
            result[i] =(byte) t1 ;
        }
        // æ³¨æ„ï¼šä¸Šé¢çš„循环顺序已经是小端序,result[0]存的是最低两位
        return result;
    }
    private static void electricityStatus(String ip, int port, byte[] addressBuf, Map<String, Object> map) throws IOException {
        byte control = 0x11;
        byte[] data = {0x36, 0x38, 0x33, 0x37};
        byte[] bufReq = getRequestParam(4, addressBuf, control, data);
        byte[] respBuf = readDeviceData(ip, port, bufReq);
        String resp = bytesToHex(respBuf);
        String msg = resp.substring(36, 36 + 4);
        System.out.println(resp);
        String[] nArr = parseSub33Reverse(msg, 2);
        String status = hexToBinary1(nArr);
//        String resp = "FEFEFEFE   68  615121010000    68  91  06  36383337    3333    7916";
        map.put("status", status);
    }
    private static void electricityTime(String ip, int port, byte[] addressBuf, Map<String, Object> map) throws IOException {
        byte control = 0x11;
        byte[] data = {0x3F, 0x34, 0x33, 0x37};
        byte[] bufReq = getRequestParam(4, addressBuf, control, data);
        byte[] respBuf = readDeviceData(ip, port, bufReq);
        String resp = bytesToHex(respBuf);
        String msg = resp.substring(36, 36 + 14);
//        System.out.println(msg);
        String[] nArr = parseSub33Reverse(msg, 7);
        String ts = hexToBinary1(nArr);
        String time = "20"+ts.substring(0,6)+ts.substring(8);
        Date date = getDateByStr(time);
        System.out.println( formatData(date));
//        String resp = "FEFEFEFE   68  615121010000    68  91  06  36383337    3333    7916";
        map.put("time", date);
//        map.put("currentTime", formatData(date));
    }
    public static Date getDateByStr(String date)  {
        TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
        if(date!=null ){
            int i = date.indexOf("+");
            if(i >0){
                date = date.substring(0,i);
            }
        }
        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        df.setTimeZone(tz);
        Date dates = null;
        try {
            dates = df.parse(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dates;
    }
    public static String formatData(Date date)  {
        DateFormat df = new SimpleDateFormat("yyyyå¹´MM月dd日HH时mm分ss秒");
        try {
            return  df.format(date);
        } catch (Exception e) {
        }
        return null;
    }
    public static Map<String, Object> electricityData(String ip, int port, String address) throws IOException {
        Map<String, Object> r = new HashMap<>();
        byte[] addressBuf = convertToBCDAddress(address);
        electricityTotal(ip, port, addressBuf, r);
        electricityStatus(ip, port, addressBuf, r);
        electricityTime(ip, port, addressBuf, r);
        return r;
    }
    public static boolean electricityAct(String ip, int port, String address,int type,String dateStr) {
        Map<String, Object> r = new HashMap<>();
        byte[] addressBuf = convertToBCDAddress(address);
       return electricityControl(ip,port,addressBuf,type,dateStr);
    }
    private static String hexToBinary(String hex) {
        StringBuilder sb = new StringBuilder();
        for (char c : hex.toCharArray()) {
            int val = Integer.parseInt(String.valueOf(c), 16);
            sb.append(String.format("%4s", Integer.toBinaryString(val)).replace(' ', '0'));
        }
        return sb.toString();
    }
    private static String hexToBinary(String[] hexArr) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hexArr.length; i++) {
            sb.append(hexToBinary(hexArr[i]));
        }
        return sb.toString();
    }
    private static String hexToBinary1(String[] hexArr) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hexArr.length; i++) {
            sb.append(hexArr[i]);
        }
        return sb.toString();
    }
    private static String addHex(String hex1, String hex2) {
        int num1 = Integer.parseInt(hex1.replace("0x", ""), 16);
        int num2 = Integer.parseInt(hex2.replace("0x", ""), 16);
        int sum = num1 + num2;
        return "0x" + Integer.toHexString(sum).toUpperCase();
    }
    private static void testWater() throws IOException {
        //"00000152462599"; 000152462599
        //FEFEFE    68  999999999999    68  01(C)  02(L)  65(DI0) F3(DI1)  C1(CS校验码)  16(结束符)
        //FEFEFE6899254652010068010243C33016
        //FEFEFE6899254652010068810843C3333333333333E816
//        FEFEFE6899254652010068810843C3333333333333E816
        String ip = "192.168.1.78";
        int port = 1030;
//        DeviceData d = readDeviceData(ip, port, "00000152462599");
//        System.out.println(d);
//        String address = "000152462599";
        String address = "000152462599";
        //00000152462599
        byte[] address_buf = convertToBCDAddress(address);
//        byte[] address_buf = hexStringToByteArray(address);
//        System.out.println(buf);
        /**
         *
         * FEFEFE   68  000152462599  68010243C33016
         * FEFEFE   68  992546520100  68010243C33016
         */
        byte control = 0x01;
        byte[] data = {0x43, (byte) 0xC3};
        byte[] datas = getRequestParam(3, address_buf, control, data);
        System.out.println(bytesToHex(datas));
        System.out.println("FEFEFE6899254652010068010243C33016");
//         datas = hexStringToByteArray("FEFEFE6899254652010068010243C33016");
        byte[] resp = readDeviceData(ip, port, datas);
        String r = bytesToHex(resp);
        System.out.println(r);
        /**
         *
         * FEFEFE   68  992546520100    68  01  02  43C3    30  16
         * FEFEFE   68  992546520100    68  81  08  43C3    33333333    3333    E8  16
         */
//        String r = "FEFEFE6899254652010068810843C3333333333333E816";
        String msg = r.substring(30, 30 + 8 + 4);
        System.out.println(msg);
        String[] nArr = parseSub33Reverse(msg, 4);
        System.out.println(strArrNum(nArr));
//        byte d10 = 0x10;
//        byte add = 0x33;
//        String hex = String.format("%02X", (d10 + add) & 0xFF);
//        System.out.println(hex);
//        r = addHex("0x10", "0x33");
//        System.out.println(r);
//
//        r = addHex("0x90", "0x33");
//        System.out.println(r);
        msg = r.substring(40, 40 + 2);
        System.out.println(msg);
        byte sub = 0x33;
        String hexResult = subByte(msg, sub);
        String v = hexToBinary(hexResult);
        System.out.println(v);
    }
    /**
     * æœ€åŽä¸€ä½æ˜¯å°æ•°ç‚¹
     *
     * @param nArr
     * @return
     */
    private static Double strArrNum(String[] nArr) {
        if (nArr == null || nArr.length == 0) {
            return 0.0;
        }
        // å°†æ‰€æœ‰éƒ¨åˆ†æ‹¼æŽ¥èµ·æ¥
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < nArr.length; i++) {
            sb.append(nArr[i]);
        }
        // åœ¨é€‚当位置插入小数点
        String combined = sb.toString();
        int totalLength = combined.length();
        int decimalLength = nArr[nArr.length - 1].length();
        // æ’入小数点
        String numberStr = combined.substring(0, totalLength - decimalLength) + "." + combined.substring(totalLength - decimalLength);
        return Double.parseDouble(numberStr);
    }
    public static void electricityTest() throws IOException {
        //000001215161
//        FEFEFEFE  68  615121010000    68  11  04  33333333    8516
//        FEFEFEFE6861512101000068910833333333A93333334B16
//        FEFEFEFE6861512101000068910833333333AC3333334E16
        String ip = "192.168.1.78";
        int port = 1030;
        String address = "000001215161";
        byte[] addressBuf = convertToBCDAddress(address);
//        byte control = 0x11;
//        byte[] data = {0x33, 0x33, 0x33, 0x33};
////
//        byte[] bufReq = getRequestParam(4, addressBuf, control, data);
////        String req = bytesToHex(bufReq);
//////        String param = "FEFEFE68615121010000681104333333338516";
////        System.out.println(req);
//////        System.out.println(param);
////        byte[] buf = hexStringToByteArray(param);
//        byte[] respBuf = readDeviceData(ip, port, bufReq);
//        String hex = bytesToHex(respBuf);
////        System.out.println(hex);
//        String resp = "FEFEFEFE6861512101000068910833333333AC3333334E16";
////                     FEFEFEFE68615121010000   68  91  08 33333333 A9  333333    4B16
//
//        String msg = resp.substring(28, 28 + 8);
//        System.out.println(msg);
//
//        String[] nArr = parseSub33Reverse(msg, 4);
//        System.out.println(strArrNum(nArr));
//        msg = resp.substring(28 + 8, 28 + 8 + 8);
//        System.out.println(msg);
//
//        nArr = parseSub33Reverse(msg, 4);
////        parseSub33Reverse
//        System.out.println(strArrNum(nArr));
//        String msgStatus = "FEFEFEFE 68 379707010000 68 11 04 36383337 9316";
//        String msgStatus = "FEFEFEFE68379707010000681104363833379316";
//        byte control = 0x11;
//        byte[] data = {0x36, 0x38, 0x33, 0x37};
//        byte[] bufReq = getRequestParam(4, addressBuf, control, data);
//        String req = bytesToHex(bufReq);
//        System.out.println(req);
//        System.out.println(msgStatus);
//        byte[] respBuf = readDeviceData(ip, port, bufReq);
//        String resp = bytesToHex(respBuf);
//        System.out.println(resp);
//        FEFEFEFE  68  615121010000  68  91  06  36383337  3333  79  16
//        FEFEFEFE  68  615121010000    68  91  06  36383337    3333    79  16
        String resp = "FEFEFEFE686151210100006891063638333733337916";
        String msg = resp.substring(36, 36 + 4);
        System.out.println(msg);
        String[] nArr = parseSub33Reverse(msg, 2);
//        System.out.println(strArrNum(nArr));
        String v = hexToBinary(nArr);
        v="0000000000010000";
        System.out.println(v);
        System.out.println(v.charAt(11));
    }
    public static void main(String[] args) throws IOException {
//        testWater();
//        electricityTest();
//        water("192.168.1.78",1030,"000152462599");
//        Map<String, Object> map = electricityData("192.168.1.78", 1030, "000001215161");
//        System.out.println(JSONObject.toJSONString(map));
        electricityAct("192.168.1.78", 1030, "000001215161",0,"20260309162655");
//        FEFEFE6899254652010068810 843C3333433333333   E9 16
//        FEFEFE6899254652010068810 84  3C3333433333333E916
//        Map<String, Object> map1 = water("192.168.1.78", 1030, "000152462599");
//        System.out.println(JSONObject.toJSONString(map1));
    }
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/DeviceDataMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.doumee.dao.business;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.doumee.dao.business.model.DeviceData;
/**
 * @author æ±Ÿè¹„蹄
 * @date 2025/12/25 10:04
 */
public interface DeviceDataMapper extends BaseMapper<DeviceData> {
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Device.java
@@ -1,5 +1,7 @@
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.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
@@ -8,9 +10,9 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
import java.math.BigDecimal;
import java.util.Date;
/**
 * è®¾å¤‡ä¿¡æ¯è¡¨
@@ -71,8 +73,8 @@
    @ExcelColumn(name="排序码")
    private Integer sortnum;
    @ApiModelProperty(value = "类型 0门禁 1车库 2LED 3广播", example = "1")
    @ExcelColumn(name="类型 0门禁 1车库 2LED 3广播")
    @ApiModelProperty(value = "类型 0门禁 1车库 2LED 3广播点 4广播设备 5断路器空开 6海康电表", example = "1")
    @ExcelColumn(name="类型 0门禁 1车库 2LED 3广播点 4广播设备 5断路器空开 6海康电表")
    private Integer type;
    @ApiModelProperty(value = "是否园区出入口 0不是 1是", example = "1")
    @ExcelColumn(name="是否园区出入口 0不是 1是")
@@ -154,12 +156,14 @@
    @ApiModelProperty(value = "门禁点名称")
    @ExcelColumn(name="门禁点名称")
    private String doorName;
    @ApiModelProperty(value = "播报内容")
    @TableField(exist = false)
    private String sendInfo;
    @ApiModelProperty(value = "远程操作时间参数")
    @TableField(exist = false)
    private Date cmdDate;
    @ApiModelProperty(value = "配置参数")
    @TableField(exist = false)
    private JSONObject doorNameObj;
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/DeviceData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,95 @@
package com.doumee.dao.business.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
 * é—¨ç¦äº‹ä»¶æŽ¨é€è®°å½•表
 * @author æ±Ÿè¹„蹄
 * @date 2025/12/25 10:04
 */
@Data
@ApiModel("门禁事件推送记录表")
@TableName("`device_data`")
public class DeviceData {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
    @ExcelColumn(name="主键")
    private Integer id;
    @ApiModelProperty(value = "创建人编码", example = "1")
    @ExcelColumn(name="创建人编码")
    private Integer creator;
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
    @ExcelColumn(name="更新人编码")
    private Integer editor;
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
    private Integer isdeleted;
    @ApiModelProperty(value = "备注")
    @ExcelColumn(name="备注")
    private String remark;
    @ApiModelProperty(value = "数据json对象", example = "1")
    @ExcelColumn(name="数据json对象")
    private String dataJson;
    @ApiModelProperty(value = "设备编码(关联device)")
    @ExcelColumn(name="设备编码(关联device)")
    private String deviceId;
    @ApiModelProperty(value = "发生时间")
    @ExcelColumn(name="发生时间")
    private String happenTime;
    @ApiModelProperty(value = "属性值1")
    @ExcelColumn(name="属性值1")
    private String val1;
    @ApiModelProperty(value = "属性值2")
    @ExcelColumn(name="属性值2")
    private String val2;
    @ApiModelProperty(value = "属性值3")
    @ExcelColumn(name="属性值3")
    private String val3;
    @ApiModelProperty(value = "属性值4")
    @ExcelColumn(name="属性值4")
    private String val4;
    @ApiModelProperty(value = "属性值5")
    @ExcelColumn(name="属性值5")
    private String val5;
    @ApiModelProperty(value = "属性值6")
    @ExcelColumn(name="属性值6")
    private String val6;
    @ApiModelProperty(value = "属性值7")
    @ExcelColumn(name="属性值7")
    private String val7;
    @ApiModelProperty(value = "数据来源 0mqtt上报综合状态 1远程控制 2TCP读取数据 ", example = "1")
    @ExcelColumn(name="数据来源 0mqtt上报综合状态 1远程控制 2TCP读取数据")
    private Integer dataType;
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceDataService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
package com.doumee.service.business;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.DeviceData;
import java.util.List;
/**
 * é—¨ç¦äº‹ä»¶æŽ¨é€è®°å½•表Service定义
 * @author æ±Ÿè¹„蹄
 * @date 2025/12/25 10:04
 */
public interface DeviceDataService {
    /**
     * åˆ›å»º
     *
     * @param deviceData å®žä½“对象
     * @return Integer
     */
    Integer create(DeviceData deviceData);
    /**
     * ä¸»é”®åˆ é™¤
     *
     * @param id ä¸»é”®
     */
    void deleteById(Integer id);
    /**
     * åˆ é™¤
     *
     * @param deviceData å®žä½“对象
     */
    void delete(DeviceData deviceData);
    /**
     * æ‰¹é‡ä¸»é”®åˆ é™¤
     *
     * @param ids ä¸»é”®é›†
     */
    void deleteByIdInBatch(List<Integer> ids);
    /**
     * ä¸»é”®æ›´æ–°
     *
     * @param deviceData å®žä½“对象
     */
    void updateById(DeviceData deviceData);
    /**
     * æ‰¹é‡ä¸»é”®æ›´æ–°
     *
     * @param deviceDatas å®žä½“集
     */
    void updateByIdInBatch(List<DeviceData> deviceDatas);
    /**
     * ä¸»é”®æŸ¥è¯¢
     *
     * @param id ä¸»é”®
     * @return DeviceData
     */
    DeviceData findById(Integer id);
    /**
     * æ¡ä»¶æŸ¥è¯¢å•条记录
     *
     * @param deviceData å®žä½“对象
     * @return DeviceData
     */
    DeviceData findOne(DeviceData deviceData);
    /**
     * æ¡ä»¶æŸ¥è¯¢
     *
     * @param deviceData å®žä½“对象
     * @return List<DeviceData>
     */
    List<DeviceData> findList(DeviceData deviceData);
    /**
     * åˆ†é¡µæŸ¥è¯¢
     *
     * @param pageWrap åˆ†é¡µå¯¹è±¡
     * @return PageData<DeviceData>
     */
    PageData<DeviceData> findPage(PageWrap<DeviceData> pageWrap);
    /**
     * æ¡ä»¶ç»Ÿè®¡
     *
     * @param deviceData å®žä½“对象
     * @return long
     */
    long count(DeviceData deviceData);
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/DeviceService.java
@@ -1,11 +1,12 @@
package com.doumee.service.business;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.doumee.core.haikang.model.param.request.AcsDeviceListRequest;
import com.doumee.core.haikang.model.param.request.TransparentChannelSingleRequest;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.Device;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.List;
/**
@@ -15,9 +16,10 @@
 */
public interface DeviceService {
    /**
     * åˆ›å»º
     *
     *
     * @param device å®žä½“对象
     * @return Integer
     */
@@ -28,7 +30,7 @@
     *
     * @param id ä¸»é”®
     */
    void deleteById(Integer id);
    void deleteById(Integer id, LoginUserInfo userInfo);
    /**
     * åˆ é™¤
@@ -42,7 +44,7 @@
     *
     * @param ids ä¸»é”®é›†
     */
    void deleteByIdInBatch(List<Integer> ids);
    void deleteByIdInBatch(List<Integer> ids, LoginUserInfo userInfo);
    /**
     * ä¸»é”®æ›´æ–°
@@ -106,4 +108,11 @@
    long count(Device device);
    void setLedContent(TransparentChannelSingleRequest body);
    void setBroadcaseBobao(Device body);
    void updateUsedById(Device d);
    void dianbaoCmd(Device param);
    void dianbiaoData(Device param);
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/DeviceDataServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,161 @@
package com.doumee.service.business.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.DeviceDataMapper;
import com.doumee.dao.business.model.DeviceData;
import com.doumee.service.business.DeviceDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
/**
 * é—¨ç¦äº‹ä»¶æŽ¨é€è®°å½•表Service实现
 * @author æ±Ÿè¹„蹄
 * @date 2025/12/25 10:04
 */
@Service
public class DeviceDataServiceImpl implements DeviceDataService {
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Override
    public Integer create(DeviceData deviceData) {
        deviceDataMapper.insert(deviceData);
        return deviceData.getId();
    }
    @Override
    public void deleteById(Integer id) {
        deviceDataMapper.deleteById(id);
    }
    @Override
    public void delete(DeviceData deviceData) {
        UpdateWrapper<DeviceData> deleteWrapper = new UpdateWrapper<>(deviceData);
        deviceDataMapper.delete(deleteWrapper);
    }
    @Override
    public void deleteByIdInBatch(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        deviceDataMapper.deleteBatchIds(ids);
    }
    @Override
    public void updateById(DeviceData deviceData) {
        deviceDataMapper.updateById(deviceData);
    }
    @Override
    public void updateByIdInBatch(List<DeviceData> deviceDatas) {
        if (CollectionUtils.isEmpty(deviceDatas)) {
            return;
        }
        for (DeviceData deviceData: deviceDatas) {
            this.updateById(deviceData);
        }
    }
    @Override
    public DeviceData findById(Integer id) {
        return deviceDataMapper.selectById(id);
    }
    @Override
    public DeviceData findOne(DeviceData deviceData) {
        QueryWrapper<DeviceData> wrapper = new QueryWrapper<>(deviceData);
        return deviceDataMapper.selectOne(wrapper);
    }
    @Override
    public List<DeviceData> findList(DeviceData deviceData) {
        QueryWrapper<DeviceData> wrapper = new QueryWrapper<>(deviceData);
        return deviceDataMapper.selectList(wrapper);
    }
    @Override
    public PageData<DeviceData> findPage(PageWrap<DeviceData> pageWrap) {
        IPage<DeviceData> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
        QueryWrapper<DeviceData> queryWrapper = new QueryWrapper<>();
        Utils.MP.blankToNull(pageWrap.getModel());
        if (pageWrap.getModel().getId() != null) {
            queryWrapper.lambda().eq(DeviceData::getId, pageWrap.getModel().getId());
        }
        if (pageWrap.getModel().getCreator() != null) {
            queryWrapper.lambda().eq(DeviceData::getCreator, pageWrap.getModel().getCreator());
        }
        if (pageWrap.getModel().getCreateDate() != null) {
            queryWrapper.lambda().ge(DeviceData::getCreateDate, Utils.Date.getStart(pageWrap.getModel().getCreateDate()));
            queryWrapper.lambda().le(DeviceData::getCreateDate, Utils.Date.getEnd(pageWrap.getModel().getCreateDate()));
        }
        if (pageWrap.getModel().getEditor() != null) {
            queryWrapper.lambda().eq(DeviceData::getEditor, pageWrap.getModel().getEditor());
        }
        if (pageWrap.getModel().getEditDate() != null) {
            queryWrapper.lambda().ge(DeviceData::getEditDate, Utils.Date.getStart(pageWrap.getModel().getEditDate()));
            queryWrapper.lambda().le(DeviceData::getEditDate, Utils.Date.getEnd(pageWrap.getModel().getEditDate()));
        }
        if (pageWrap.getModel().getIsdeleted() != null) {
            queryWrapper.lambda().eq(DeviceData::getIsdeleted, pageWrap.getModel().getIsdeleted());
        }
        if (pageWrap.getModel().getRemark() != null) {
            queryWrapper.lambda().eq(DeviceData::getRemark, pageWrap.getModel().getRemark());
        }
        if (pageWrap.getModel().getDataJson() != null) {
            queryWrapper.lambda().eq(DeviceData::getDataJson, pageWrap.getModel().getDataJson());
        }
        if (pageWrap.getModel().getDeviceId() != null) {
            queryWrapper.lambda().eq(DeviceData::getDeviceId, pageWrap.getModel().getDeviceId());
        }
        if (pageWrap.getModel().getHappenTime() != null) {
            queryWrapper.lambda().eq(DeviceData::getHappenTime, pageWrap.getModel().getHappenTime());
        }
        if (pageWrap.getModel().getVal1() != null) {
            queryWrapper.lambda().eq(DeviceData::getVal1, pageWrap.getModel().getVal1());
        }
        if (pageWrap.getModel().getVal2() != null) {
            queryWrapper.lambda().eq(DeviceData::getVal2, pageWrap.getModel().getVal2());
        }
        if (pageWrap.getModel().getVal3() != null) {
            queryWrapper.lambda().eq(DeviceData::getVal3, pageWrap.getModel().getVal3());
        }
        if (pageWrap.getModel().getVal4() != null) {
            queryWrapper.lambda().eq(DeviceData::getVal4, pageWrap.getModel().getVal4());
        }
        if (pageWrap.getModel().getVal5() != null) {
            queryWrapper.lambda().eq(DeviceData::getVal5, pageWrap.getModel().getVal5());
        }
        if (pageWrap.getModel().getVal6() != null) {
            queryWrapper.lambda().eq(DeviceData::getVal6, pageWrap.getModel().getVal6());
        }
        if (pageWrap.getModel().getDataType() != null) {
            queryWrapper.lambda().eq(DeviceData::getDataType, pageWrap.getModel().getDataType());
        }
        queryWrapper.lambda().orderByDesc(DeviceData::getHappenTime);
        for(PageWrap.SortData sortData: pageWrap.getSorts()) {
            if (sortData.getDirection().equalsIgnoreCase(PageWrap.DESC)) {
                queryWrapper.orderByDesc(sortData.getProperty());
            } else {
                queryWrapper.orderByAsc(sortData.getProperty());
            }
        }
        return PageData.from(deviceDataMapper.selectPage(page, queryWrapper));
    }
    @Override
    public long count(DeviceData deviceData) {
        QueryWrapper<DeviceData> wrapper = new QueryWrapper<>(deviceData);
        return deviceDataMapper.selectCount(wrapper);
    }
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/DeviceServiceImpl.java
@@ -2,29 +2,36 @@
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.haikang.model.HKConstants;
import com.doumee.core.haikang.model.param.BaseResponse;
import com.doumee.core.haikang.model.param.request.*;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.DeviceMapper;
import com.doumee.dao.business.PlatformBroadcastLogMapper;
import com.doumee.dao.business.model.Device;
import com.doumee.dao.business.model.PlatformBroadcastLog;
import com.doumee.service.business.DeviceService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.device.WaterElectricityUtil;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.haikang.model.HKConstants;
import com.doumee.core.haikang.model.param.BaseResponse;
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.model.LoginUserInfo;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.DateUtil;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.*;
import com.doumee.dao.business.model.Device;
import com.doumee.dao.business.model.DeviceData;
import com.doumee.dao.business.model.PlatformBroadcastLog;
import com.doumee.service.business.DeviceService;
import com.doumee.service.business.impl.hksync.HkSyncPushServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.*;
@@ -35,25 +42,54 @@
 * @date 2023/11/30 15:33
 */
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Autowired
    private PlatformMapper platformMapper;
    @Autowired
    private PlatformDeviceMapper platformDeviceMapper;
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private PlatformBroadcastLogMapper platformBroadcastLogMapper;
    @Autowired
    private InterfaceLogMapper interfaceLogMapper;
    @Override
    public Integer create(Device device) {
        deviceMapper.insert(device);
        return device.getId();
    public Integer create(Device model) {
        model.setCreator(model.getLoginUserInfo().getId()+"");
        model.setEdirot(model.getCreator());
        model.setIsdeleted(Constants.ZERO);
        model.setEditDate(new Date());
        model.setCreateDate(model.getEditDate());
        if(model.getDoorNameObj()!=null &&
                (Constants.equalsInteger(model.getType(),Constants.DEVICE_TYPE.duanluqi)
                        ||Constants.equalsInteger(model.getType(),Constants.DEVICE_TYPE.dianbiao))){
            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();
    }
    @Override
    public void deleteById(Integer id) {
        deviceMapper.deleteById(id);
    public void deleteById(Integer id, LoginUserInfo userInfo) {
        Device update = new Device();
        update.setEdirot(userInfo.getId()+"");
        update.setEditDate(new Date());
        update.setIsdeleted(Constants.ONE);
        update.setId(id);
        deviceMapper.updateById(update);
    }
    @Override
@@ -63,16 +99,30 @@
    }
    @Override
    public void deleteByIdInBatch(List<Integer> ids) {
    public void deleteByIdInBatch(List<Integer> ids, LoginUserInfo userInfo) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        deviceMapper.deleteBatchIds(ids);
        for(Integer id :ids){
            deleteById(id,userInfo);
        }
    }
    @Override
    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)
                        ||Constants.equalsInteger(device.getType(),Constants.DEVICE_TYPE.dianbiao))){
            device.setDoorName(JSONObject.toJSONString(device.getDoorNameObj()));
        }
        Device model = deviceMapper.selectById(device.getId());
        if(model ==null){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        deviceMapper.updateById(device);
    }
    @Override
@@ -87,7 +137,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
@@ -98,6 +157,7 @@
    @Override
    public List<Device> findList(Device device) {
        device.setIsdeleted(Constants.ZERO);
        QueryWrapper<Device> wrapper = new QueryWrapper<>(device);
        return deviceMapper.selectList(wrapper);
    }
@@ -107,12 +167,25 @@
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>(param);
        wrapper.select(Device::getId, Device::getName, Device::getDoorName,Device::getRegionPathName, Device::getRegionName);
        wrapper.eq(null != param.getType(),Device::getType,param.getType())
               .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);
                .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;
    }
    @Override
    public PageData<Device> findPage(PageWrap<Device> pageWrap) {
        IPage<Device> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
@@ -147,6 +220,12 @@
        }
        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());
@@ -219,7 +298,22 @@
                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)||
                        Constants.equalsInteger(d.getType(),Constants.DEVICE_TYPE.dianbiao))){
                    try {
                        //断路器设备参数
                        d.setDoorNameObj(JSONObject.parseObject(d.getDoorName()));
                    }catch (Exception e){
                    }
                }
            }
        }
        return PageData.from(result);
    }
    @Override
@@ -227,6 +321,123 @@
        QueryWrapper<Device> wrapper = new QueryWrapper<>(device);
        return deviceMapper.selectCount(wrapper);
    }
    @Override
    public void setBroadcaseBobao(Device model){
        List<String> ids = new ArrayList<>();
        ids.add(model.getHkId());
        CustomBroadcastRequest request = new CustomBroadcastRequest();
        request.setAudioPointIndexCode(ids);
        request.setPlayDuration(15);//单位秒
        request.setBroadCastMode("tts");
        request.setPriority(1);
        request.setState(1);//播放/停止标识 1-播放,0-停止
        request.setPlayTtsContent(model.getSendInfo());
        BaseResponse response =  HKService.customBroadcast(request);
        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);
        }
        this.updateById(param);
    }
    @Override
    public  void dianbaoCmd(Device param){
        Device model = deviceMapper.selectById(param.getId());
        if(model ==null && Constants.equalsInteger(param.getType(),Constants.DEVICE_TYPE.dianbiao)){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        if (param.getStatus() == null || param.getCmdDate() == null
                ||param.getCmdDate().getTime() <= System.currentTimeMillis()) {
            //如果是开闸
            throw  new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        boolean r ;
        String date = DateUtil.formatDate(new Date(),"yyyyMMddHHmmss");
        if(Constants.equalsInteger(param.getStatus(),Constants.ONE)) {
            //如果是开闸
            r = WaterElectricityUtil.electricityAct(param.getIp(),Integer.parseInt(param.getPort()),param.getNo(),0,date);
        }else {
            //如果是合闸
            r = WaterElectricityUtil.electricityAct(param.getIp(),Integer.parseInt(param.getPort()),param.getNo(),1,date);
        }
        if(!r){
            throw  new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"远程控制电表失败,请稍后重试!");
        }
        String curremak = "【"+param.getLoginUserInfo().getRealname()
                +"】于"+ DateUtil.getPlusTime2(new Date()) +"进行了"+(Constants.equalsInteger(param.getStatus(),Constants.ONE)?"【合闸】":"【分闸】")+"操作,开关【"+param.getChannelNo()+"】;";
        deviceMapper.update(null,new UpdateWrapper<Device>().lambda()
                .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);
    }
    @Override
    @Transactional
    public  void dianbiaoData(Device param){
        Device model = deviceMapper.selectById(param.getId());
        if(model ==null && Constants.equalsInteger(param.getType(),Constants.DEVICE_TYPE.dianbiao)){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        try {
            Map<String, Object>  readData=  WaterElectricityUtil.electricityData(model.getIp(),Integer.parseInt(model.getPort()),model.getNo());
            if(readData!=null){
                String curremak = "【"+param.getLoginUserInfo().getRealname()
                        +"】于"+ DateUtil.getPlusTime2(new Date()) +"进行了数据读取操作";
                Date time =(Date) readData.get("time");
                String total = (Double) readData.get("total")+"";
                String status =  (String) readData.get("status");
                model.setHkDate(new Date());//最近同步时间
                model.setOnline(Constants.ONE);//标识设备在线
                model.setRemark(curremak);
                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.ZERO);//
                data.setVal1(total);
                data.setVal2(status);
                data.setHappenTime(DateUtil.getPlusTime2(data.getCreateDate()));
                data.setVal3(DateUtil.getPlusTime2(time));
                data.setVal4(param.getLoginUserInfo().getRealname());
                data.setVal5(param.getNo());//地址域
                deviceDataMapper.insert(data);
                deviceMapper.updateById(model);
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("电表数据读取失败,"+e.getMessage());
            throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"读取电表数据失败!");
        }
    }
    @Override
    public void setLedContent(TransparentChannelSingleRequest model) {
@@ -250,4 +461,28 @@
            throw  new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), "对不起,屏幕内容设置失败"+(log!=null?log.getHkInfo():""));
        }
    }
    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;
    }
}
server/visits/dmvisit_service/src/main/resources/application-dev.yml
@@ -1,9 +1,9 @@
spring:
  # æ•°æ®æºé…ç½®
  datasource:
    url: jdbc:mysql://112.26.66.25:3306/funingyunwei?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8
    url: jdbc:mysql://192.168.0.211:3306/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Doumee@168&QWERT
    password: Doumee@168
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  redis:
server/visits/dmvisit_service/src/main/resources/application-test.yml
@@ -1,9 +1,9 @@
spring:
  # æ•°æ®æºé…ç½®
  datasource:
    url: jdbc:mysql://sh-cdb-aiskr3vy.sql.tencentcdb.com:62443/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: doumee
    password: rtjgfEr@&0c0m
    url: jdbc:mysql://192.168.0.211:3306/funingyunwei?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Doumee@168
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  redis: