Compare commits

...

3 Commits

Author SHA1 Message Date
阿斌
c2dad7bb37
Pre Merge pull request !36 from 阿斌/N/A 2026-06-23 12:39:10 +00:00
panlinlin
b7ba8b9cfa 通用通道支持看守位控制 2026-06-23 20:38:53 +08:00
阿斌
da98101aac
update src/main/resources/civilCode.csv.
行政规划错误。江苏南通海门市,修改为海门区,浙江杭州删除下城区、江干区,新增钱塘区,临平区

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

View File

@ -17,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.context.request.async.DeferredResult;
@ -599,6 +600,42 @@ public class ChannelFrontEndController {
return result; return result;
} }
@Operation(summary = "看守位设置", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "enabled", description = "是否开启看守位", required = true)
@Parameter(name = "resetTime", description = "自动归位时间间隔(秒)")
@Parameter(name = "presetIndex", description = "调用预置位编号")
@GetMapping("/home_position")
public DeferredResult<WVPResult<String>> homePosition(Integer channelId, Boolean enabled,
@RequestParam(required = false) Integer resetTime,
@RequestParam(required = false) Integer presetIndex){
if (log.isDebugEnabled()) {
log.debug("[通用通道]看守位设置 API调用channelId{} enabled{} resetTime{} presetIndex{}", channelId, enabled, resetTime, presetIndex);
}
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
result.onTimeout(()->{
WVPResult<String> wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "请求超时");
result.setResult(wvpResult);
});
ErrorCallback<String> callback = (code, msg, data) -> {
WVPResult<String> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
};
channelControlService.homePosition(channel, enabled, resetTime, presetIndex, callback);
return result;
}
@Operation(summary = "拉框放大", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Operation(summary = "拉框放大", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "channelId", description = "通道ID", required = true) @Parameter(name = "channelId", description = "通道ID", required = true)
@Parameter(name = "length", description = "播放窗口长度像素值", required = true) @Parameter(name = "length", description = "播放窗口长度像素值", required = true)

View File

@ -17,4 +17,6 @@ public interface IGbChannelControlService {
void auxiliary(CommonGBChannel channel, FrontEndControlCodeForAuxiliary frontEndControlCode, ErrorCallback<String> callback); void auxiliary(CommonGBChannel channel, FrontEndControlCodeForAuxiliary frontEndControlCode, ErrorCallback<String> callback);
void queryPreset(CommonGBChannel channel, ErrorCallback<List<Preset>> callback); void queryPreset(CommonGBChannel channel, ErrorCallback<List<Preset>> callback);
void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom frontEndControlCode, ErrorCallback<String> callback); void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom frontEndControlCode, ErrorCallback<String> callback);
void homePosition(CommonGBChannel channel, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback);
} }

View File

@ -22,4 +22,5 @@ public interface IPTZService {
void dragZoomOut(CommonGBChannel channel, int length, int width, int midPointX, int midPointY, int lengthX, int lengthY); void dragZoomOut(CommonGBChannel channel, int length, int width, int midPointX, int midPointY, int lengthX, int lengthY);
void homePosition(CommonGBChannel channel, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback);
} }

View File

@ -27,4 +27,6 @@ public interface ISourcePTZService {
void queryPreset(CommonGBChannel channel, ErrorCallback<List<Preset>> callback); void queryPreset(CommonGBChannel channel, ErrorCallback<List<Preset>> callback);
void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom frontEndControlCode, ErrorCallback<String> callback); void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom frontEndControlCode, ErrorCallback<String> callback);
void homePosition(CommonGBChannel channel, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback);
} }

View File

@ -138,4 +138,16 @@ public class GbChannelControlServiceImpl implements IGbChannelControlService {
} }
sourcePTZService.dragZoom(channel, frontEndControlCode, callback); sourcePTZService.dragZoom(channel, frontEndControlCode, callback);
} }
@Override
public void homePosition(CommonGBChannel channel, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback) {
log.info("[通用通道] 看守位设置, 类型: {} 编号:{}", channel.getDataType(), channel.getGbDeviceId());
Integer dataType = channel.getDataType();
ISourcePTZService sourcePTZService = sourcePTZServiceMap.get(ChannelDataType.PTZ_SERVICE + dataType);
if (sourcePTZService == null) {
log.error("[通用通道] 类型: {} 不支持看守位设置", dataType);
throw new PlayException(Response.BUSY_HERE, "channel not support");
}
sourcePTZService.homePosition(channel, enabled, resetTime, presetIndex, callback);
}
} }

View File

@ -119,6 +119,23 @@ public class PTZServiceImpl implements IPTZService {
deviceService.dragZoomOut(device, deviceChannel.getDeviceId(), length, width, midPointX, midPointY, lengthX, lengthY); deviceService.dragZoomOut(device, deviceChannel.getDeviceId(), length, width, midPointX, midPointY, lengthX, lengthY);
} }
@Override
public void homePosition(CommonGBChannel channel, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback) {
if (channel.getDataType() != ChannelDataType.GB28181) {
log.warn("[INFO 消息] 只有国标通道支持看守位通道ID{}", channel.getGbId());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持");
}
Device device = deviceService.getDevice(channel.getDataDeviceId());
if (device == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到设备");
}
DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId());
if (deviceChannel == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到通道");
}
deviceService.homePosition(device, deviceChannel.getDeviceId(), enabled, resetTime, presetIndex, callback);
}
@Override @Override
public void queryPresetList(CommonGBChannel channel, ErrorCallback<List<Preset>> callback) { public void queryPresetList(CommonGBChannel channel, ErrorCallback<List<Preset>> callback) {
if (channel.getDataType() != ChannelDataType.GB28181) { if (channel.getDataType() != ChannelDataType.GB28181) {

View File

@ -349,6 +349,11 @@ public class SourcePTZServiceForGbImpl implements ISourcePTZService {
ptzService.queryPresetList(channel, callback); ptzService.queryPresetList(channel, callback);
} }
@Override
public void homePosition(CommonGBChannel channel, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback) {
ptzService.homePosition(channel, enabled, resetTime, presetIndex, callback);
}
@Override @Override
public void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom controlCode, ErrorCallback<String> callback) { public void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom controlCode, ErrorCallback<String> callback) {
if (controlCode.getCode() == 1) { if (controlCode.getCode() == 1) {

View File

@ -156,6 +156,11 @@ public class SourcePTZServiceForJTImpl implements ISourcePTZService {
callback.run(ErrorCode.ERROR486.getCode(), ErrorCode.ERROR486.getMsg(), null); callback.run(ErrorCode.ERROR486.getCode(), ErrorCode.ERROR486.getMsg(), null);
} }
@Override
public void homePosition(CommonGBChannel channel, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback) {
callback.run(ErrorCode.ERROR486.getCode(), ErrorCode.ERROR486.getMsg(), null);
}
@Override @Override
public void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom frontEndControlCode, ErrorCallback<String> callback) { public void dragZoom(CommonGBChannel channel, FrontEndControlCodeForDragZoom frontEndControlCode, ErrorCallback<String> callback) {
callback.run(ErrorCode.ERROR486.getCode(), ErrorCode.ERROR486.getMsg(), null); callback.run(ErrorCode.ERROR486.getCode(), ErrorCode.ERROR486.getMsg(), null);

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

@ -691,6 +691,14 @@ export function drawThin(data) {
data: data data: data
}) })
} }
export function homePosition(params) {
return request({
method: 'get',
url: '/api/common/channel/front-end/home_position',
params
})
}
export function test() { export function test() {
return request({ return request({
method: 'get', method: 'get',

View File

@ -50,7 +50,8 @@ import {
resumePlayback, resumePlayback,
seekPlayback, speedPlayback, getAllForMap, test, saveLevel, resetLevel, clearThin, thinProgress, drawThin, saveThin, seekPlayback, speedPlayback, getAllForMap, test, saveLevel, resetLevel, clearThin, thinProgress, drawThin, saveThin,
dragZoomIn, dragZoomOut, dragZoomIn, dragZoomOut,
talkStart, talkStop, broadcastStart, broadcastStop talkStart, talkStop, broadcastStart, broadcastStop,
homePosition
} from '@/api/commonChannel' } from '@/api/commonChannel'
const actions = { const actions = {
@ -695,6 +696,17 @@ const actions = {
}) })
}, },
homePosition({ commit }, params) {
return new Promise((resolve, reject) => {
homePosition(params).then(response => {
const { data } = response
resolve(data)
}).catch(error => {
reject(error)
})
})
},
test({ commit }) { test({ commit }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
test().then(response => { test().then(response => {

View File

@ -1,6 +1,6 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 1291092 */ font-family: "iconfont"; /* Project id 1291092 */
src: url('iconfont.woff2?t=1780559263294') format('woff2'); src: url('iconfont.woff2?t=1782216793622') format('woff2');
} }
.iconfont { .iconfont {
@ -11,6 +11,58 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-yuzhidian:before {
content: "\e808";
}
.icon-xunhuan:before {
content: "\e809";
}
.icon-kanshouwei:before {
content: "\e80a";
}
.icon-yushua:before {
content: "\e80b";
}
.icon-mubiaogenzong1:before {
content: "\e80c";
}
.icon-fangkuang:before {
content: "\e807";
}
.icon-jingxiang:before {
content: "\e806";
}
.icon-zuoyoujingxiang:before {
content: "\ea5d";
}
.icon-shangxiajingxiang:before {
content: "\ea5e";
}
.icon-a-18_baojingluxiang:before {
content: "\e805";
}
.icon-mubiaogenzong:before {
content: "\e804";
}
.icon-yuntaijiaodu:before {
content: "\e803";
}
.icon-tubiao_yuntaikongzhi:before {
content: "\e802";
}
.icon-dingshirenwuguanli:before { .icon-dingshirenwuguanli:before {
content: "\e800"; content: "\e800";
} }

Binary file not shown.

View File

@ -0,0 +1,100 @@
<template>
<div>
<el-form label-width="120px" class="guard-form">
<el-form-item label="启用">
<el-switch v-model="enabled" />
</el-form-item>
<el-form-item label="预置位">
<el-select v-model="presetIndex" style="width: 180px" placeholder="选择预置位">
<el-option v-for="p in allPresetList" :key="p.presetId"
:label="p.presetId + '-' + (p.presetName || ('预置点' + p.presetId))"
:value="Number(p.presetId)" />
</el-select>
</el-form-item>
<el-form-item label="自动归位(秒)">
<el-input-number v-model="resetTime" :min="1" :max="999999" controls-position="right" style="width: 180px" />
</el-form-item>
<el-form-item>
<div class="guard-actions">
<el-button @click="loadPresets">刷新</el-button>
<el-button type="primary" :loading="submitting" :disabled="submitting" @click="confirmSave">保存</el-button>
</div>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'ChPtzGuardConfig',
props: {
channelId: { type: String, default: null }
},
data() {
return {
enabled: false,
presetIndex: null,
resetTime: 10,
allPresetList: [],
submitting: false
}
},
created() {
this.loadPresets()
},
methods: {
loadPresets() {
this.$store.dispatch('commonChanel/queryPreset', this.channelId)
.then(data => {
this.allPresetList = data || []
})
.catch(error => {
console.log('[看守位] 加载预置点列表失败', error)
})
},
confirmSave() {
if (!this.enabled && !this.presetIndex) {
this.$message({ showClose: true, message: '请选择预置位编号', type: 'warning' })
return
}
if (this.resetTime == null || this.resetTime < 1) {
this.$message({ showClose: true, message: '请输入有效的归位时间', type: 'warning' })
return
}
this.submitting = true
const params = {
channelId: this.channelId,
enabled: this.enabled
}
if (this.presetIndex != null) {
params.presetIndex = this.presetIndex
}
if (this.resetTime != null) {
params.resetTime = this.resetTime
}
this.$store.dispatch('commonChanel/homePosition', params)
.then(() => {
this.$message({ showClose: true, message: '保存成功', type: 'success' })
})
.catch(error => {
this.$message({ showClose: true, message: error || '保存失败', type: 'error' })
})
.finally(() => {
this.submitting = false
})
}
}
}
</script>
<style scoped>
.guard-form {
padding: 16px 12px;
max-width: 420px;
}
.guard-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
</style>

View File

@ -5,19 +5,23 @@
<div class="config-sidebar"> <div class="config-sidebar">
<el-menu :default-active="activeTab" @select="handleMenuSelect"> <el-menu :default-active="activeTab" @select="handleMenuSelect">
<el-menu-item index="preset"> <el-menu-item index="preset">
<i class="el-icon-map-location" style="margin-right: 6px" /> <i class="iconfont icon-yuzhidian" style="margin-right: 8px" />
<span>预置点</span> <span>预置点</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="cruise"> <el-menu-item index="cruise">
<i class="el-icon-s-order" style="margin-right: 6px" /> <i class="iconfont icon-xunhuan" style="margin-right: 8px" />
<span>巡航组</span> <span>巡航组</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="scan"> <el-menu-item index="scan">
<i class="iconfont icon-slider-right" style="margin-right: 6px" /> <i class="iconfont icon-slider-right" style="margin-right: 8px" />
<span>线性扫描</span> <span>线性扫描</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="guard">
<i class="iconfont icon-kanshouwei" style="margin-right: 8px" />
<span>看守位</span>
</el-menu-item>
<el-menu-item index="switch"> <el-menu-item index="switch">
<i class="el-icon-s-tools" style="margin-right: 6px" /> <i class="iconfont icon-yushua" style="margin-right: 8px" />
<span>辅助开关</span> <span>辅助开关</span>
</el-menu-item> </el-menu-item>
</el-menu> </el-menu>
@ -31,6 +35,7 @@
<ptzCruiseConfig v-if="activeTab === 'cruise'" :channel-id="channelId" /> <ptzCruiseConfig v-if="activeTab === 'cruise'" :channel-id="channelId" />
<ptzScanConfig v-if="activeTab === 'scan'" :channel-id="channelId" /> <ptzScanConfig v-if="activeTab === 'scan'" :channel-id="channelId" />
<ptzSwitchConfig v-if="activeTab === 'switch'" :channel-id="channelId" /> <ptzSwitchConfig v-if="activeTab === 'switch'" :channel-id="channelId" />
<ptzGuardConfig v-if="activeTab === 'guard'" :channel-id="channelId" />
</div> </div>
</div> </div>
</div> </div>
@ -43,10 +48,11 @@ import ptzPresetConfig from './common/ptzPresetConfig.vue'
import ptzCruiseConfig from './common/ptzCruiseConfig.vue' import ptzCruiseConfig from './common/ptzCruiseConfig.vue'
import ptzScanConfig from './common/ptzScanConfig.vue' import ptzScanConfig from './common/ptzScanConfig.vue'
import ptzSwitchConfig from './common/ptzSwitchConfig.vue' import ptzSwitchConfig from './common/ptzSwitchConfig.vue'
import ptzGuardConfig from './common/ptzGuardConfig.vue'
export default { export default {
name: 'ChPtzConfig', name: 'ChPtzConfig',
components: { playerPtzPanel, ptzPresetConfig, ptzCruiseConfig, ptzScanConfig, ptzSwitchConfig }, components: { playerPtzPanel, ptzPresetConfig, ptzCruiseConfig, ptzScanConfig, ptzSwitchConfig, ptzGuardConfig },
props: { props: {
channelId: { type: String, default: null } channelId: { type: String, default: null }
}, },

View File

@ -5,23 +5,23 @@
<div class="config-sidebar"> <div class="config-sidebar">
<el-menu :default-active="activeTab" @select="handleMenuSelect"> <el-menu :default-active="activeTab" @select="handleMenuSelect">
<el-menu-item index="preset"> <el-menu-item index="preset">
<i class="el-icon-map-location" style="margin-right: 6px" /> <i class="iconfont icon-yuzhidian" style="margin-right: 8px" />
<span>预置点</span> <span>预置点</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="cruise"> <el-menu-item index="cruise">
<i class="el-icon-s-order" style="margin-right: 6px" /> <i class="iconfont icon-xunhuan" style="margin-right: 8px" />
<span>巡航组</span> <span>巡航组</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="scan"> <el-menu-item index="scan">
<i class="iconfont icon-slider-right" style="margin-right: 6px" /> <i class="iconfont icon-slider-right" style="margin-right: 8px" />
<span>线性扫描</span> <span>线性扫描</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="guard"> <el-menu-item index="guard">
<i class="el-icon-s-home" style="margin-right: 6px" /> <i class="iconfont icon-kanshouwei" style="margin-right: 8px" />
<span>看守位</span> <span>看守位</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="switch"> <el-menu-item index="switch">
<i class="el-icon-s-tools" style="margin-right: 6px" /> <i class="iconfont icon-yushua" style="margin-right: 8px" />
<span>辅助开关</span> <span>辅助开关</span>
</el-menu-item> </el-menu-item>
</el-menu> </el-menu>