Compare commits

...

4 Commits

Author SHA1 Message Date
阿斌
81e3e58479
Pre Merge pull request !36 from 阿斌/N/A 2026-06-22 09:57:41 +00:00
lin
015441bbb2 整合功能入口 2026-06-22 17:57:24 +08:00
lin
3b25da45b3 移除没有业务的空处理 2026-06-22 16:48:26 +08:00
阿斌
da98101aac
update src/main/resources/civilCode.csv.
行政规划错误。江苏南通海门市,修改为海门区,浙江杭州删除下城区、江干区,新增钱塘区,临平区

Signed-off-by: 阿斌 <38912748@qq.com>
2024-12-15 08:58:42 +00:00
10 changed files with 293 additions and 168 deletions

View File

@ -1,60 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.Platform;
import com.genersoft.iot.vmp.gb28181.service.IDeviceService;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import gov.nist.javax.sip.message.SIPRequest;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Element;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
@Slf4j
@Component
public class DeviceControlResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private final String cmdType = "DeviceControl";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private IDeviceService deviceService;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
log.info("[DeviceControl Response] \n {}", element.asXML());
// 检查设备是否存在 不存在则不回复
if (device == null) {
return;
}
// 回复200 OK
try {
responseAckAsync((SIPRequest) evt.getRequest(), Response.OK);
} catch (SipException | InvalidArgumentException | ParseException e) {
log.error("[命令发送失败] 国标级联 设备状态应答回复200OK: {}", e.getMessage());
}
}
@Override
public void handForPlatform(RequestEvent evt, Platform parentPlatform, Element rootElement) {
}
}

View File

@ -861,7 +861,7 @@
320623,如东县,3206 320623,如东县,3206
320681,启东市,3206 320681,启东市,3206
320682,如皋市,3206 320682,如皋市,3206
320684,海门,3206 320684,海门,3206
320685,海安市,3206 320685,海安市,3206
3207,连云港市,32 3207,连云港市,32
320703,连云区,3207 320703,连云区,3207
@ -918,8 +918,6 @@
33,浙江省, 33,浙江省,
3301,杭州市,33 3301,杭州市,33
330102,上城区,3301 330102,上城区,3301
330103,下城区,3301
330104,江干区,3301
330105,拱墅区,3301 330105,拱墅区,3301
330106,西湖区,3301 330106,西湖区,3301
330108,滨江区,3301 330108,滨江区,3301
@ -927,6 +925,8 @@
330110,余杭区,3301 330110,余杭区,3301
330111,富阳区,3301 330111,富阳区,3301
330112,临安区,3301 330112,临安区,3301
330113,临平区,3301
330114,钱塘区,3301
330122,桐庐县,3301 330122,桐庐县,3301
330127,淳安县,3301 330127,淳安县,3301
330182,建德市,3301 330182,建德市,3301

1 编号 名称 上级
861 320623 如东县 3206
862 320681 启东市 3206
863 320682 如皋市 3206
864 320684 海门市 海门区 3206
865 320685 海安市 3206
866 3207 连云港市 32
867 320703 连云区 3207
918 33 浙江省
919 3301 杭州市 33
920 330102 上城区 3301
330103 下城区 3301
330104 江干区 3301
921 330105 拱墅区 3301
922 330106 西湖区 3301
923 330108 滨江区 3301
925 330110 余杭区 3301
926 330111 富阳区 3301
927 330112 临安区 3301
928 330113 临平区 3301
929 330114 钱塘区 3301
930 330122 桐庐县 3301
931 330127 淳安县 3301
932 330182 建德市 3301

View File

@ -69,6 +69,14 @@ export function resetGuard(deviceId) {
}) })
} }
export function resetAlarm(data) {
return request({
method: 'get',
url: '/api/device/control/reset_alarm',
params: data
})
}
export function homePosition(params) { export function homePosition(params) {
return request({ return request({
method: 'get', method: 'get',
@ -316,3 +324,10 @@ export function dragZoomOut(params) {
}) })
} }
export function teleboot(deviceId) {
return request({
method: 'get',
url: `/api/device/control/teleboot/${deviceId}`
})
}

View File

@ -13,13 +13,14 @@ import {
queryDeviceSyncStatus, queryDeviceSyncStatus,
queryDeviceTree, queryDeviceTree,
queryHasStreamChannels, queryHasStreamChannels,
resetAlarm,
resetGuard, resetGuard,
setBasicParam, setBasicParam,
setGuard, setGuard,
setVideoParamOpt, setVideoParamOpt,
subscribeCatalog, subscribeForAlarm, subscribeCatalog, subscribeForAlarm,
subscribeMobilePosition, subscribeMobilePosition,
sync, sync, teleboot,
update, update,
updateChannelStreamIdentification, updateChannelStreamIdentification,
updateDeviceTransport updateDeviceTransport
@ -86,6 +87,16 @@ const actions = {
}) })
}) })
}, },
resetAlarm({ commit }, data) {
return new Promise((resolve, reject) => {
resetAlarm(data).then(response => {
const { data: result } = response
resolve(result)
}).catch(error => {
reject(error)
})
})
},
homePosition({ commit }, params) { homePosition({ commit }, params) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
homePosition(params).then(response => { homePosition(params).then(response => {
@ -305,6 +316,16 @@ const actions = {
reject(error) reject(error)
}) })
}) })
},
teleboot({ commit }, deviceId) {
return new Promise((resolve, reject) => {
teleboot(deviceId).then(response => {
const { data } = response
resolve(data)
}).catch(error => {
reject(error)
})
})
} }
} }

View File

@ -0,0 +1,113 @@
<template>
<div id="dhAlarmConfigPage">
<div class="alarm-config-body">
<div class="card-list">
<div class="alarm-section">
<div class="section-header">报警设置</div>
<el-form ref="alarmSettingForm">
<el-form-item>
<el-button type="primary" @click="handleSetGuard">布防</el-button>
<el-button type="warning" @click="handleResetGuard">撤防</el-button>
<el-button type="danger" @click="handleResetAlarm">复位</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'AlarmConfigPage',
props: {
deviceId: { type: String, default: null },
channelDeviceId: { type: String, default: null }
},
data() {
return {
}
},
mounted() {},
methods: {
handleSetGuard() {
this.$confirm('确认对该通道执行布防操作?', '提示', {
confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning'
}).then(() => {
this.$store.dispatch('device/setGuard', this.deviceId).then(() => {
this.$message.success('布防成功')
})
}).catch(() => {})
},
handleResetGuard() {
this.$confirm('确认对该通道执行撤防操作?', '提示', {
confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning'
}).then(() => {
this.$store.dispatch('device/resetGuard', this.deviceId).then(() => {
this.$message.success('撤防成功')
})
}).catch(() => {})
},
handleResetAlarm() {
this.$confirm('确认对该通道执行复位操作?', '提示', {
confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning'
}).then(() => {
this.$store.dispatch('device/resetAlarm', {
deviceId: this.deviceId,
channelId: this.channelDeviceId
}).then(() => {
this.$message.success('复位成功')
})
}).catch(() => {})
}
}
}
</script>
<style scoped>
#dhAlarmConfigPage {
height: 100%;
display: flex;
flex-direction: column;
}
.alarm-config-body {
flex: 1;
padding-top: 16px;
overflow: auto;
}
.card-list {
display: flex;
flex-wrap: wrap;
gap: 16px;
align-content: flex-start;
}
.alarm-section {
width: 380px;
flex-shrink: 0;
border: 1px solid #e6e6e6;
border-radius: 6px;
padding: 16px;
}
.section-header {
font-weight: 600;
font-size: 15px;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.alarm-section .el-select,
.alarm-section .el-input-number {
width: 100%;
}
.alarm-section .el-button + .el-button {
margin-left: 12px;
}
</style>

View File

@ -8,10 +8,25 @@
<i class="iconfont icon-wxbzhuye" style="margin-right: 10px" /> <i class="iconfont icon-wxbzhuye" style="margin-right: 10px" />
<span>基础属性</span> <span>基础属性</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="alarm">
<i class="iconfont icon-baojing" style="margin-right: 10px" />
<span>报警配置</span>
</el-menu-item>
<el-menu-item index="recordControl">
<i class="iconfont icon-record1" style="margin-right: 10px" />
<span>录像控制</span>
</el-menu-item>
<el-menu-item index="upgrade">
<i class="iconfont icon-shangchuan" style="margin-right: 10px" />
<span>设备运维</span>
</el-menu-item>
</el-menu> </el-menu>
</div> </div>
<div class="config-content"> <div class="config-content">
<basicPropertyConfig v-if="activeTab === 'base'" :device-id="deviceId" :channel-device-id="channelDeviceId" /> <basicPropertyConfig v-if="activeTab === 'base'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
<alarmConfig v-if="activeTab === 'alarm'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
<upgradeConfig v-if="activeTab === 'upgrade'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
<recordControlConfig v-if="activeTab === 'recordControl'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
</div> </div>
</div> </div>
</div> </div>
@ -19,10 +34,13 @@
<script> <script>
import basicPropertyConfig from './basicPropertyConfig.vue' import basicPropertyConfig from './basicPropertyConfig.vue'
import alarmConfig from './alarmConfig.vue'
import upgradeConfig from './upgradeConfig.vue'
import recordControlConfig from './recordControlConfig.vue'
export default { export default {
name: 'CameraConfigPage', name: 'CameraConfigPage',
components: { basicPropertyConfig }, components: { basicPropertyConfig, alarmConfig, upgradeConfig, recordControlConfig },
props: { props: {
deviceId: { type: String, default: null }, deviceId: { type: String, default: null },
channelDeviceId: { type: String, default: null } channelDeviceId: { type: String, default: null }

View File

@ -181,20 +181,16 @@
更多<i class="el-icon-arrow-down el-icon--right" /> 更多<i class="el-icon-arrow-down el-icon--right" />
</el-button> </el-button>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="records" :disabled="device == null || device.online === 0">
设备录像</el-dropdown-item>
<el-dropdown-item command="cloudRecords" :disabled="device == null || device.online === 0">
云端录像</el-dropdown-item>
<el-dropdown-item command="record" :disabled="device == null || device.online === 0">
设备录像控制-开始</el-dropdown-item>
<el-dropdown-item command="stopRecord" :disabled="device == null || device.online === 0">
设备录像控制-停止</el-dropdown-item>
<el-dropdown-item command="ptzConfig" :disabled="device == null || device.online === 0">
云台配置</el-dropdown-item>
<el-dropdown-item command="audioTalk" :disabled="device == null || device.online === 0"> <el-dropdown-item command="audioTalk" :disabled="device == null || device.online === 0">
语音对讲</el-dropdown-item> 语音对讲</el-dropdown-item>
<el-dropdown-item command="cameraConfig" :disabled="device == null || device.online === 0" divided> <el-dropdown-item command="records" :disabled="device == null || device.online === 0">
设备录像</el-dropdown-item>
<el-dropdown-item command="ptzConfig" :disabled="device == null || device.online === 0">
云台配置</el-dropdown-item>
<el-dropdown-item command="cameraConfig" :disabled="device == null || device.online === 0">
相机配置</el-dropdown-item> 相机配置</el-dropdown-item>
<el-dropdown-item command="cloudRecords" :disabled="device == null || device.online === 0">
云端录像</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
@ -398,10 +394,6 @@ export default {
this.queryRecords(itemData) this.queryRecords(itemData)
} else if (command === 'cloudRecords') { } else if (command === 'cloudRecords') {
this.queryCloudRecords(itemData) this.queryCloudRecords(itemData)
} else if (command === 'record') {
this.startRecord(itemData)
} else if (command === 'stopRecord') {
this.stopRecord(itemData)
} else if (command === 'ptzConfig') { } else if (command === 'ptzConfig') {
console.log(itemData.channelId) console.log(itemData.channelId)
this.ptzConfigDeviceId = this.deviceId this.ptzConfigDeviceId = this.deviceId
@ -424,40 +416,6 @@ export default {
this.$router.push(`/cloudRecord/detail/rtp/${deviceId}_${channelId}`) this.$router.push(`/cloudRecord/detail/rtp/${deviceId}_${channelId}`)
}, },
startRecord: function(itemData) {
this.$store.dispatch('device/deviceRecord', {
deviceId: this.deviceId,
channelId: itemData.deviceId,
recordCmdStr: 'Record'
}).then(data => {
this.$message.success({
showClose: true,
message: '开始录像成功'
})
}).catch((error) => {
this.$message.error({
showClose: true,
message: error.message
})
})
},
stopRecord: function(itemData) {
this.$store.dispatch('device/deviceRecord', {
deviceId: this.deviceId,
channelId: itemData.deviceId,
recordCmdStr: 'StopRecord'
}).then(data => {
this.$message.success({
showClose: true,
message: '停止录像成功'
})
}).catch((error) => {
this.$message.error({
showClose: true,
message: error.message
})
})
},
stopDevicePush: function(itemData) { stopDevicePush: function(itemData) {
this.$store.dispatch('play/stop', { this.$store.dispatch('play/stop', {
deviceId: this.deviceId, deviceId: this.deviceId,

View File

@ -0,0 +1,47 @@
<template>
<div class="record-control-form">
<el-alert title="对当前通道下发录像控制指令" type="info" :closable="false" show-icon style="margin-bottom: 16px" />
<el-button type="primary" :loading="startLoading" @click="handleRecord('Record')">开始录像</el-button>
<el-button type="danger" :loading="stopLoading" @click="handleRecord('StopRecord')" style="margin-left: 12px">停止录像</el-button>
</div>
</template>
<script>
export default {
name: 'RecordControlConfig',
props: {
deviceId: { type: String, default: null },
channelDeviceId: { type: String, default: null }
},
data() {
return {
startLoading: false,
stopLoading: false
}
},
methods: {
handleRecord(recordCmdStr) {
const loadingKey = recordCmdStr === 'Record' ? 'startLoading' : 'stopLoading'
this[loadingKey] = true
const msg = recordCmdStr === 'Record' ? '开始录像' : '停止录像'
this.$store.dispatch('device/deviceRecord', {
deviceId: this.deviceId,
channelId: this.channelDeviceId,
recordCmdStr: recordCmdStr
}).then(() => {
this.$message({ showClose: true, message: msg + '成功', type: 'success' })
}).catch((error) => {
this.$message({ showClose: true, message: error.message || msg + '失败', type: 'error' })
}).finally(() => {
this[loadingKey] = false
})
}
}
}
</script>
<style scoped>
.record-control-form {
padding: 16px 0;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<div class="upgrade-form">
<div class="reboot-section">
<h4>远程启动</h4>
<el-button type="warning" @click="handleReboot">设备重启</el-button>
</div>
</div>
</template>
<script>
export default {
name: 'UpgradeConfig',
props: {
deviceId: { type: String, default: null },
channelDeviceId: { type: String, default: null }
},
data() {
return {
firmware: '',
fileName: '',
headers: {
'access-token': this.$store.getters.token
}
}
},
methods: {
handleReboot() {
this.$confirm('确定远程重启该设备?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$store.dispatch('device/teleboot', this.deviceId).then(() => {
this.$message({ showClose: true, message: '远程启动命令已发送', type: 'success' })
}).catch(error => {
this.$message({ showClose: true, message: error.message, type: 'error' })
})
}).catch(() => {})
}
}
}
</script>
<style scoped>
.upgrade-form {
padding: 16px 0;
}
.upgrade-form >>> .upgrade-input {
width: 360px;
}
.upload-row {
display: flex;
align-items: center;
}
.reboot-section {
padding: 8px 0;
}
.reboot-section h4 {
margin: 0 0 12px;
font-weight: 600;
font-size: 14px;
color: #303133;
}
</style>

View File

@ -132,7 +132,7 @@
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" min-width="300" fixed="right"> <el-table-column label="操作" min-width="200" fixed="right">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button <el-button
type="text" type="text"
@ -154,22 +154,7 @@
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">编辑</el-button> <el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">编辑</el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-dropdown @command="(command)=>{moreClick(command, scope.row)}"> <el-button size="medium" type="text" style="color: #f56c6c" @click="deleteDevice(scope.row)">删除</el-button>
<el-button size="medium" type="text">
操作<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu>
<el-dropdown-item command="delete" style="color: #f56c6c">
删除
</el-dropdown-item>
<el-dropdown-item command="setGuard" :disabled="!scope.row.onLine">
布防
</el-dropdown-item>
<el-dropdown-item command="resetGuard" :disabled="!scope.row.onLine">
撤防
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -381,43 +366,7 @@ export default {
this.$refs.configInfo.openDialog(data) this.$refs.configInfo.openDialog(data)
}) })
}, },
moreClick: function(command, itemData) {
if (command === 'setGuard') {
this.setGuard(itemData)
} else if (command === 'resetGuard') {
this.resetGuard(itemData)
} else if (command === 'delete') {
this.deleteDevice(itemData)
}
},
setGuard: function(itemData) {
this.$store.dispatch('device/setGuard', itemData.deviceId)
.then((data) => {
this.$message.success({
showClose: true,
message: '布防成功'
})
}).catch((error) => {
this.$message.error({
showClose: true,
message: error.message
})
})
},
resetGuard: function(itemData) {
this.$store.dispatch('device/resetGuard', itemData.deviceId)
.then((data) => {
this.$message.success({
showClose: true,
message: '撤防成功'
})
}).catch((error) => {
this.$message.error({
showClose: true,
message: error.message
})
})
},
subscribeForCatalog: function(data, value) { subscribeForCatalog: function(data, value) {
this.$store.dispatch('device/subscribeCatalog', { this.$store.dispatch('device/subscribeCatalog', {
id: data, id: data,