Browse Source

修改控制云台和任务详情

inspection_yanyuan
douyage 3 weeks ago
parent
commit
6287672754
13 changed files with 206 additions and 87 deletions
  1. BIN
      src/assets/images/ptz/focus-left.png
  2. BIN
      src/assets/images/ptz/focus-right.png
  3. BIN
      src/assets/images/ptz/iris-left.png
  4. BIN
      src/assets/images/ptz/iris-right.png
  5. BIN
      src/assets/images/ptz/zoom-left.png
  6. BIN
      src/assets/images/ptz/zoom-right.png
  7. +0
    -24
      src/layout/components/TagsView/index.vue
  8. +1
    -1
      src/layout/index.vue
  9. +1
    -4
      src/views/cards/taskSummary/inspectionTask.vue
  10. +13
    -16
      src/views/cards/taskSummary/newInspectionTaskDetail.vue
  11. +1
    -1
      src/views/portal/index.vue
  12. +187
    -40
      src/views/video/LivePreview.vue
  13. +3
    -1
      src/views/video/components/NvrDeviceTree.vue

BIN
src/assets/images/ptz/focus-left.png View File

Before After
Width: 27  |  Height: 24  |  Size: 466 B

BIN
src/assets/images/ptz/focus-right.png View File

Before After
Width: 28  |  Height: 24  |  Size: 488 B

BIN
src/assets/images/ptz/iris-left.png View File

Before After
Width: 27  |  Height: 24  |  Size: 426 B

BIN
src/assets/images/ptz/iris-right.png View File

Before After
Width: 28  |  Height: 24  |  Size: 428 B

BIN
src/assets/images/ptz/zoom-left.png View File

Before After
Width: 27  |  Height: 24  |  Size: 256 B

BIN
src/assets/images/ptz/zoom-right.png View File

Before After
Width: 28  |  Height: 24  |  Size: 201 B

+ 0
- 24
src/layout/components/TagsView/index.vue View File

@ -1,29 +1,5 @@
<template>
<div id="tags-view-container" class="tags-view-container">
<div v-if="isVideoLivePreview" class="video-layout-switch" aria-label="画面布局">
<el-tooltip
v-for="item in videoLayouts"
:key="item.value"
:content="item.label"
placement="bottom"
>
<button
type="button"
:aria-label="item.label"
:class="{ active: videoLayout === item.value }"
@click="setVideoLayout(item.value)"
>
<span
class="video-layout-icon"
:class="`video-layout-icon-${item.columns}`"
:style="{ gridTemplateColumns: `repeat(${item.columns}, minmax(0, 1fr))`, gridTemplateRows: `repeat(${item.columns}, minmax(0, 1fr))` }"
aria-hidden="true"
>
<i v-for="cell in item.value" :key="cell" />
</span>
</button>
</el-tooltip>
</div>
<div v-if="isPatrolSchedule" class="schedule-view-switch">
<button
v-for="view in scheduleViews"


+ 1
- 1
src/layout/index.vue View File

@ -124,7 +124,7 @@ export default {
return [
{ key: 'home', label: '首页', path: '/portal' },
{ key: 'patrol', label: '动环巡检', path: '/index' },
{ key: 'system', label: '系统管理', path: '/system/menu' }
// { key: 'system', label: '系统管理', path: '/system/menu' }
]
},
activeModule() {


+ 1
- 4
src/views/cards/taskSummary/inspectionTask.vue View File

@ -701,7 +701,7 @@ export default {
}
this.getList();
// 获取区域
this.getAreaList();
if (process.env.VUE_APP_MODEL_DIALOGUE == "true") {
this.modelDialogIcon = true;
@ -709,9 +709,6 @@ export default {
},
mounted() {
this.setTableHeight();
setTimeout(() => {
this.getAreaList();
}, 1000);
},
activated() {
sessionStorage.removeItem("inspectionTaskState");


+ 13
- 16
src/views/cards/taskSummary/newInspectionTaskDetail.vue View File

@ -1086,24 +1086,21 @@ export default {
}
}
::v-deep .current-row {
background-color: #124451 !important;
td {
background-color: #124451 !important;
border-color: #1a5969 !important;
}
&:hover td {
background-color: #165666 !important;
}
::v-deep .card-table .el-table__body tr.current-row > td.el-table__cell,
::v-deep .card-table .el-table__fixed-body-wrapper tr.current-row > td.el-table__cell {
background-color: #9bb3e2 !important;
color: #303133 !important;
border-color: #d8e2ef !important;
}
::v-deep .card-table {
.el-table__row.current-row {
color: #e1f5fe;
.cell {
color: #e1f5fe;
}
}
::v-deep .card-table .el-table__body tr.current-row:hover > td.el-table__cell,
::v-deep .card-table .el-table__fixed-body-wrapper tr.current-row:hover > td.el-table__cell {
background-color: #8aa6d8 !important;
}
::v-deep .card-table .el-table__row.current-row .cell,
::v-deep .card-table .el-table__row.current-row .cell span {
color: #303133 !important;
}
.detail-reset-btn,


+ 1
- 1
src/views/portal/index.vue View File

@ -395,7 +395,7 @@ export default {
navItems: [
{ key: "home", label: "首页" },
{ key: "patrol", label: "动环巡检" },
{ key: "system", label: "系统管理" }
// { key: "system", label: "系统管理" }
],
stationButtons: STATION_BUTTONS,
defectSlides: DEFECT_SLIDES,


+ 187
- 40
src/views/video/LivePreview.vue View File

@ -5,7 +5,6 @@
v-show="!embed || embedTreeVisible"
class="tree-panel"
:style="embedTreeStyle"
@mousedown="startEmbedPanelDrag('tree', $event)"
>
<nvr-device-tree
v-if="!embed || sessionReady"
@ -98,7 +97,7 @@
@mousedown="startEmbedPanelDrag('control', $event)"
>
<div class="control-panel-body">
<section v-if="embed" class="control-section embed-layout-section">
<section class="control-section embed-layout-section">
<div class="section-title"><span>画面布局</span></div>
<div class="embed-layout-switch" aria-label="画面布局">
<button
@ -122,12 +121,13 @@
</section>
<section class="control-section">
<div class="section-title section-title-stack"><span>云台控制</span><small>{{ selectedChannelName }}</small></div>
<div class="ptz-grid">
<div class="ptz-grid" :class="{ 'is-disabled': !ptzEnabled }">
<button
v-for="button in ptzButtons"
:key="button.action"
type="button"
:title="button.label"
:disabled="!ptzEnabled"
@mousedown.prevent="startPtz(button.action)"
@mouseup.prevent="stopPtz"
@mouseleave="stopPtz"
@ -137,13 +137,15 @@
<i :class="button.icon" />
</button>
</div>
<div class="lens-actions">
<div class="lens-actions" :class="{ 'is-disabled': !ptzEnabled }">
<div v-for="tool in lensTools" :key="tool.label" class="lens-tool" :title="tool.label">
<img :src="tool.icon" :alt="tool.label">
<img class="lens-glyph" :src="tool.leftIcon" :alt="tool.leftLabel">
<img class="lens-glyph" :src="tool.rightIcon" :alt="tool.rightLabel">
<button
type="button"
:aria-label="tool.leftLabel"
:title="tool.leftLabel"
:disabled="!ptzEnabled"
@mousedown.prevent="startPtz(tool.leftAction)"
@mouseup.prevent="stopPtz"
@mouseleave="stopPtz"
@ -154,6 +156,7 @@
type="button"
:aria-label="tool.rightLabel"
:title="tool.rightLabel"
:disabled="!ptzEnabled"
@mousedown.prevent="startPtz(tool.rightAction)"
@mouseup.prevent="stopPtz"
@mouseleave="stopPtz"
@ -162,9 +165,9 @@
/>
</div>
</div>
<div class="speed-row">
<div class="speed-row" :class="{ 'is-disabled': !ptzEnabled }">
<span>速度</span>
<input v-model.number="ptzSpeed" type="range" min="1" max="7" :style="{ background: `linear-gradient(to right, #2787ed 0%, #2787ed ${((ptzSpeed - 1) / 6) * 100}%, transparent ${((ptzSpeed - 1) / 6) * 100}%, transparent 100%)` }">
<input v-model.number="ptzSpeed" type="range" min="1" max="7" :disabled="!ptzEnabled" :style="{ background: `linear-gradient(to right, #2787ed 0%, #2787ed ${((ptzSpeed - 1) / 6) * 100}%, transparent ${((ptzSpeed - 1) / 6) * 100}%, transparent 100%)` }">
<el-input-number
v-model="ptzSpeed"
class="speed-input"
@ -172,37 +175,38 @@
:max="7"
size="mini"
:controls="false"
:disabled="!ptzEnabled"
/>
</div>
<div class="preset-quick-actions">
<button type="button" title="调用预置位" @click="callPreset">
<div class="preset-quick-actions" :class="{ 'is-disabled': !ptzEnabled }">
<button type="button" title="调用预置位" :disabled="!ptzEnabled" @click="callPreset">
<img :src="presetIcons.call" alt="调用预置位">
</button>
<button type="button" title="新增预置位" @click="prepareNewPreset">
<button type="button" title="新增预置位" :disabled="!ptzEnabled" @click="prepareNewPreset">
<img :src="presetIcons.add" alt="新增预置位">
</button>
<button type="button" title="编辑预置位" @click="prepareEditPreset">
<button type="button" title="编辑预置位" :disabled="!ptzEnabled" @click="prepareEditPreset">
<img :src="presetIcons.edit" alt="编辑预置位">
</button>
</div>
</section>
<section class="control-section">
<div class="section-title"><span>预置位</span><button type="button" @click="loadPresets"><i class="el-icon-refresh" /></button></div>
<el-select v-model="presetId" size="small" placeholder="请选择预置位" style="width:100%">
<section class="control-section" :class="{ 'is-disabled': !ptzEnabled }">
<div class="section-title"><span>预置位</span><button type="button" :disabled="!ptzEnabled" @click="loadPresets"><i class="el-icon-refresh" /></button></div>
<el-select v-model="presetId" size="small" placeholder="请选择预置位" style="width:100%" :disabled="!ptzEnabled">
<el-option v-for="item in presets" :key="item.id" :label="`${item.id} · ${item.name}`" :value="item.id" />
</el-select>
<div class="preset-create">
<el-input-number v-model="newPresetId" :min="1" :max="255" size="mini" :controls="false" placeholder="编号" />
<el-input v-model.trim="newPresetName" size="mini" maxlength="32" placeholder="名称" />
<el-input-number v-model="newPresetId" :min="1" :max="255" size="mini" :controls="false" placeholder="编号" :disabled="!ptzEnabled" />
<el-input v-model.trim="newPresetName" size="mini" maxlength="32" placeholder="名称" :disabled="!ptzEnabled" />
</div>
<div class="section-actions">
<button type="button" @click="callPreset">调用</button>
<button type="button" class="primary" @click="savePreset">保存</button>
<button type="button" :disabled="!ptzEnabled" @click="callPreset">调用</button>
<button type="button" class="primary" :disabled="!ptzEnabled" @click="savePreset">保存</button>
</div>
</section>
<section v-if="!embed" class="control-section">
<section class="control-section">
<div class="section-title"><span>操作</span></div>
<div class="operation-grid">
<button type="button" class="wide" @click="capture"><i class="el-icon-camera" />抓图</button>
@ -210,10 +214,10 @@
<button type="button" :class="{ active: !activeMuted }" @click="toggleMuted">
<i :class="activeMuted ? 'el-icon-turn-off-microphone' : 'el-icon-microphone'" />静音
</button>
<button type="button" :disabled="wiperRunning" @click="wipeOnce">
<button type="button" :disabled="wiperRunning || !wiperEnabled" @click="wipeOnce">
<i :class="wiperRunning ? 'el-icon-loading' : 'el-icon-umbrella'" />{{ wiperRunning ? '擦拭中' : '雨刷器' }}
</button>
<button type="button" @click="showPendingOperation('3D定位')"><i class="el-icon-aim" />3D定位</button>
<button type="button" :disabled="!position3dEnabled" @click="showPendingOperation('3D定位')"><i class="el-icon-aim" />3D定位</button>
</div>
</section>
</div>
@ -343,19 +347,19 @@ const PTZ_CODES = {
],
lensTools: [
{
label: '变倍', icon: require('@/assets/images/r1.png'),
leftAction: 'ZOOM_OUT', leftLabel: '变倍缩小',
rightAction: 'ZOOM_IN', rightLabel: '变倍放大'
key: 'zoom', label: '变倍',
leftAction: 'ZOOM_OUT', leftLabel: '变倍缩小', leftIcon: require('@/assets/images/ptz/zoom-left.png'),
rightAction: 'ZOOM_IN', rightLabel: '变倍放大', rightIcon: require('@/assets/images/ptz/zoom-right.png')
},
{
label: '聚焦', icon: require('@/assets/images/r2.png'),
leftAction: 'FOCUS_FAR', leftLabel: '远聚焦',
rightAction: 'FOCUS_NEAR', rightLabel: '近聚焦'
key: 'focus', label: '聚焦',
leftAction: 'FOCUS_FAR', leftLabel: '远聚焦', leftIcon: require('@/assets/images/ptz/focus-left.png'),
rightAction: 'FOCUS_NEAR', rightLabel: '近聚焦', rightIcon: require('@/assets/images/ptz/focus-right.png')
},
{
label: '光圈', icon: require('@/assets/images/r3.png'),
leftAction: 'IRIS_CLOSE', leftLabel: '关闭光圈',
rightAction: 'IRIS_OPEN', rightLabel: '打开光圈'
key: 'iris', label: '光圈',
leftAction: 'IRIS_CLOSE', leftLabel: '关闭光圈', leftIcon: require('@/assets/images/ptz/iris-left.png'),
rightAction: 'IRIS_OPEN', rightLabel: '打开光圈', rightIcon: require('@/assets/images/ptz/iris-right.png')
}
]
}
@ -379,6 +383,10 @@ const PTZ_CODES = {
},
selectedChannel() { return this.controlTarget },
selectedChannelName() { return this.controlTarget ? (this.controlTarget.name || `通道 ${this.controlTarget.channel}`) : '未选择画面' },
// 未选择画面时保持可点;选中后按 capabilities 置灰不支持的功能
ptzEnabled() { return this.hasCapability('ptz') },
wiperEnabled() { return this.hasCapability('wiper') },
position3dEnabled() { return this.hasCapability('position3d') },
embedTreeStyle() {
if (!this.embed) return { width: this.treePanelWidth + 'px' }
const drag = this.embedPanelDrag.tree
@ -468,7 +476,7 @@ const PTZ_CODES = {
},
startEmbedPanelDrag(panel, event) {
if (event.button !== 0) return
if (!this.embed && panel !== 'control') return
if (panel !== 'control') return
if (event.target.closest('button, a, input, textarea, .el-input, .el-select, .el-input-number, .el-tree-node, .tree-content, .embed-toggle')) return
const bounds = event.currentTarget.getBoundingClientRect()
const parent = event.currentTarget.offsetParent
@ -591,6 +599,13 @@ const PTZ_CODES = {
if (status === undefined || status === null || status === '') return true
return String(status) === '1'
},
hasCapability(key) {
const channel = this.controlTarget
if (!channel) return true
const capabilities = channel.capabilities
if (!capabilities || typeof capabilities !== 'object' || !Object.prototype.hasOwnProperty.call(capabilities, key)) return false
return capabilities[key] === true
},
onlineChannels(channels) {
return (channels || []).filter(item => this.isChannelOnline(item))
},
@ -656,6 +671,7 @@ const PTZ_CODES = {
await this.playChannels(channels)
},
openChannel(channel) {
if (channel && !this.isChannelOnline(channel)) return
this.selectChannel(channel)
this.startChannel(channel)
},
@ -676,7 +692,7 @@ const PTZ_CODES = {
}
},
async startChannel(channel, targetIndex = this.activeIndex, attemptedCameraCodes = [], streamType = this.streamType) {
if (!this.pageActive || !channel || !channel.cameraCode) return
if (!this.pageActive || !channel || !channel.cameraCode || !this.isChannelOnline(channel)) return
const index = targetIndex
await this.closeEarlierCopies(channel, index)
if (!this.pageActive) return
@ -992,7 +1008,7 @@ const PTZ_CODES = {
return
}
const code = PTZ_CODES[action]
if (!code || this.ptzActive) return
if (!code || this.ptzActive || !this.ptzEnabled) return
if (!this.controlTarget) { this.$message.warning('请先选择有视频的画面'); return }
this.ptzActive = true
this.ptzCameraCode = this.controlTarget.cameraCode
@ -1014,7 +1030,7 @@ const PTZ_CODES = {
},
async loadPresets(silent = false) {
const cameraCode = this.controlTarget && this.controlTarget.cameraCode
if (!cameraCode) return
if (!cameraCode || !this.ptzEnabled) return
try {
let result
if (this.isAggMode) {
@ -1035,10 +1051,12 @@ const PTZ_CODES = {
} catch (error) { if (!silent) this.$message.error(error.message) }
},
async callPreset() {
if (!this.ptzEnabled) return
if (!this.presetId) { this.$message.warning('请选择预置位'); return }
try { await this.sendPtz(11, String(this.presetId)); this.$message.success('预置位调用成功') } catch (error) { this.$message.error(error.message) }
},
prepareNewPreset() {
if (!this.ptzEnabled) return
const used = new Set(this.presets.map(item => Number(item.id)))
let nextId = 1
while (used.has(nextId) && nextId < 255) nextId += 1
@ -1047,6 +1065,7 @@ const PTZ_CODES = {
this.$message.info(`请填写预置位 ${nextId} 的名称后保存`)
},
prepareEditPreset() {
if (!this.ptzEnabled) return
const preset = this.presets.find(item => item.id === this.presetId)
if (!preset) { this.$message.warning('请先选择需要编辑的预置位'); return }
this.newPresetId = preset.id
@ -1054,6 +1073,7 @@ const PTZ_CODES = {
this.$message.info(`正在编辑预置位 ${preset.id}`)
},
async savePreset() {
if (!this.ptzEnabled) return
const channel = this.selectedChannel
if (!channel) { this.$message.warning('请先选择摄像机'); return }
if (!Number.isInteger(this.newPresetId) || this.newPresetId < 1 || this.newPresetId > 255) {
@ -1141,6 +1161,7 @@ const PTZ_CODES = {
async wipeOnce() {
const cameraCode = this.controlTarget && this.controlTarget.cameraCode
if (!cameraCode) { this.$message.warning('请先选择有视频的画面'); return }
if (!this.wiperEnabled) return
if (this.wiperRunning) return
this.wiperRunning = true
@ -1203,15 +1224,38 @@ const PTZ_CODES = {
.camera-label { position: absolute; left: 0; right: 0; top: 0; height: 28px; padding: 0 8px; display: flex; align-items: center; justify-content: space-between; color: #d8eaff; background: linear-gradient(180deg, rgba(0,10,36,.92), transparent); font-size: 11px; pointer-events: none; user-select: none; }.camera-label i { display: inline-block; width: 6px; height: 6px; margin-right: 5px; border-radius: 50%; background: #24e39f; box-shadow: 0 0 6px #24e39f; }
.camera-actions { position: absolute; right: 5px; bottom: 5px; display: none; gap: 3px; }.camera-card:hover .camera-actions, .camera-card:fullscreen .camera-actions, .camera-card:-webkit-full-screen .camera-actions { display: flex; }.camera-actions button { width: 26px; height: 25px; border: 1px solid rgba(66, 167, 255, .55); color: #bfe0ff; background: rgba(4,28,78,.88); cursor: pointer; }
.empty-slot { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: #466f9c; background: radial-gradient(circle at center, #0b2a61, #050b24 70%); user-select: none; }.empty-slot i { font-size: 28px; }.empty-slot span { font-size: 11px; }
.control-panel { position: absolute; top: 0; right: 0; bottom: 0; z-index: 4; width: 242px; min-width: 242px; height: auto; margin: 0; overflow: visible; border: 1px solid rgba(63,127,216,.72); border-radius: 2px; background: rgba(7, 24, 78, .82); box-sizing: border-box; cursor: move; user-select: none; }
.control-panel { position: absolute; top: 0; right: 0; bottom: 0; z-index: 4; width: 242px; min-width: 242px; height: auto; margin: 0; padding: 0; overflow: visible; border: 1px solid rgba(63,127,216,.72); border-radius: 2px; background: rgba(7, 24, 78, .42); color: #dcecff; font-size: 14px; line-height: normal; box-sizing: border-box; cursor: move; user-select: none; }
.control-panel-body { height: 100%; padding: 10px; overflow-x: hidden; overflow-y: auto; box-sizing: border-box; }
.control-section { padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid rgba(39, 128, 220, .28); }.section-title { height: 30px; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 8px; overflow: hidden; color: #54ffff; }.section-title span { flex: none; white-space: nowrap; }.section-title small { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; color: #719bc8; }.section-title-stack { height: auto; flex-direction: column; align-items: flex-start; gap: 2px; overflow: visible; }.section-title-stack small { width: 100%; white-space: normal; text-align: left; line-height: 1.4; overflow: visible; text-overflow: unset; }.section-title button { border: 0; color: #75bfff; background: transparent; cursor: pointer; }
.video-console:not(.is-embed) .control-panel-body { padding: 8px 10px; overflow-y: hidden; }
.control-section { padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid rgba(39, 128, 220, .28); }
.video-console:not(.is-embed) .control-section { padding-bottom: 8px; margin-bottom: 8px; }
.video-console:not(.is-embed) .control-section:last-child { padding-bottom: 0; margin-bottom: 0; }
.video-console:not(.is-embed) .section-title:not(.section-title-stack) { height: 26px; }
.video-console:not(.is-embed) .section-title-stack { height: auto; margin-bottom: 4px; }
.video-console:not(.is-embed) .ptz-grid { margin: 4px auto 8px; }
.video-console:not(.is-embed) .lens-actions { margin-bottom: 8px; }
.video-console:not(.is-embed) .preset-quick-actions { margin-top: 6px; }
.video-console:not(.is-embed) .preset-create,
.video-console:not(.is-embed) .section-actions,
.video-console:not(.is-embed) .operation-grid { margin-top: 6px; }.section-title { height: 30px; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 8px; overflow: hidden; color: #54ffff; }.section-title span { flex: none; white-space: nowrap; }.section-title small { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; color: #719bc8; }.section-title-stack { height: auto; flex-direction: column; align-items: flex-start; gap: 2px; overflow: visible; }.section-title-stack small { width: 100%; white-space: normal; text-align: left; line-height: 1.4; overflow: visible; text-overflow: unset; }.section-title button { border: 0; color: #75bfff; background: transparent; cursor: pointer; }
.ptz-grid { width: 168px; margin: 6px auto 12px; display: grid; grid-template-columns: repeat(3, 50px); gap: 9px; }.ptz-grid button { width: 50px; height: 50px; border: 1px solid #3988ff; border-radius: 7px; color: #43c0ff; background: #01016b; box-shadow: none; cursor: pointer; transition: color .15s, background .15s, transform .15s; }.ptz-grid button i { font-size: 18px; font-weight: 700; }.ptz-grid button:hover { color: #43c0ff; background: #01016b; }.ptz-grid button:active { color: #ffffff; background: #01016b; transform: scale(.96); }
.speed-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) 48px; align-items: center; gap: 7px; color: #8eb7df; font-size: 12px; }.speed-row > input[type="range"] { min-width: 0; height: 8px; box-sizing: border-box; margin: 0; appearance: none; border: 1px solid #2787ed; border-radius: 4px; outline: none; cursor: pointer; }.speed-row > input[type="range"]::-webkit-slider-runnable-track { height: 6px; border: 0; border-radius: 3px; background: transparent; }.speed-row > input[type="range"]::-webkit-slider-thumb { width: 14px; height: 14px; margin-top: -4px; appearance: none; border: 0; border-radius: 50%; background: #2787ed; }.speed-row > input[type="range"]::-moz-range-track { height: 6px; border: 0; border-radius: 3px; background: transparent; }.speed-row > input[type="range"]::-moz-range-progress { background: transparent; }.speed-row > input[type="range"]::-moz-range-thumb { width: 14px; height: 14px; border: 0; border-radius: 50%; background: #2787ed; }.speed-input { width: 48px; }
.preset-quick-actions { display: flex; align-items: center; gap: 7px; margin: 9px 0 0 1px; }.preset-quick-actions button { display: grid; place-items: center; width: 24px; height: 24px; padding: 0; border: 1px solid rgba(48, 151, 248, .5); color: #58bfff; background: transparent; cursor: pointer; }.preset-quick-actions button:hover { background: rgba(31, 126, 222, .25); }.preset-quick-actions img { width: 18px; height: 18px; object-fit: contain; }
.lens-actions { display: flex; align-items: center; justify-content: center; gap: 11px; min-height: 28px; margin: 0 0 10px; }.lens-tool { position: relative; width: 48px; height: 22px; overflow: hidden; }.lens-tool img { display: block; width: 100%; height: 100%; object-fit: fill; }.lens-tool button { position: absolute; top: 0; bottom: 0; width: 50%; padding: 0; border: 0; background: transparent; cursor: pointer; }.lens-tool button:first-of-type { left: 0; }.lens-tool button:last-of-type { right: 0; }.lens-tool button:active { background: rgba(73, 184, 255, .28); }
.operation-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 9px; }.operation-grid button, .section-actions button { min-height: 29px; border: 1px solid rgba(47, 145, 241, .5); color: #abd4ff; background: #0b2b67; cursor: pointer; }.operation-grid button i { margin-right: 5px; }.operation-grid button.active, .section-actions button.primary { color: #fff; background: #176bc2; }
.lens-actions { display: flex; align-items: center; justify-content: center; gap: 11px; min-height: 28px; margin: 0 0 10px; }.lens-tool { position: relative; width: 55px; height: 24px; display: grid; grid-template-columns: 1fr 1fr; border: 0; background: transparent; }.lens-glyph { display: block; width: 100%; height: 100%; object-fit: fill; pointer-events: none; }.lens-tool button { position: absolute; top: 0; bottom: 0; width: 50%; padding: 0; border: 0; background: transparent; cursor: pointer; }.lens-tool button:first-of-type { left: 0; }.lens-tool button:last-of-type { right: 0; }.lens-tool button:active { background: rgba(65, 187, 250, .18); }
.operation-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 9px; }.operation-grid button, .section-actions button { min-height: 29px; border: 1px solid #4aa6ff; color: #d7eeff; background: transparent; font-weight: 600; cursor: pointer; }.operation-grid button i { margin-right: 5px; }.operation-grid button.active, .section-actions button.primary { color: #ffffff; border-color: #7ec4ff; background: transparent; }
.operation-grid button:disabled { color: #6385aa; background: #081f4d; cursor: not-allowed; }
.ptz-grid.is-disabled,
.lens-actions.is-disabled,
.speed-row.is-disabled,
.preset-quick-actions.is-disabled,
.control-section.is-disabled { opacity: .45; }
.ptz-grid button:disabled,
.lens-tool button:disabled,
.preset-quick-actions button:disabled,
.section-actions button:disabled,
.section-title button:disabled { cursor: not-allowed; }
.ptz-grid button:disabled:hover,
.ptz-grid button:disabled:active { color: inherit; background: transparent; transform: none; }
.operation-grid .wide { grid-column: 1 / -1; }
::v-deep .el-select .el-input__inner, ::v-deep .preset-create .el-input__inner, ::v-deep .speed-input .el-input__inner { color: #cce6ff; border-color: rgba(52, 147, 241, .5); background: #09265e; }
::v-deep .speed-input .el-input__inner { height: 26px; padding: 0 7px; line-height: 26px; text-align: center; }
@ -1224,9 +1268,112 @@ const PTZ_CODES = {
.is-embed .console-body { position: relative; }
.is-embed .monitor-workspace { position: absolute; inset: 0; z-index: 1; }
.is-embed .tree-panel,
.is-embed .control-panel { position: absolute; top: 0; bottom: 0; z-index: 4; overflow: visible; background: rgba(7, 24, 78, .8); }
.is-embed .control-panel {
position: absolute;
top: 0;
bottom: 0;
z-index: 4;
overflow: visible;
background: rgba(7, 24, 78, .42);
border: 1px solid rgba(63, 127, 216, .72);
box-shadow: inset 0 0 18px rgba(36, 110, 200, .14), 0 0 8px rgba(36, 120, 210, .22);
user-select: none;
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.is-embed .tree-panel { left: 0; }
.is-embed .tree-panel .nvr-tree { background: transparent; }
.is-embed .tree-panel ::v-deep .nvr-tree { background: transparent; border: 0 !important; }
.is-embed .tree-panel ::v-deep .el-tree__empty-block { display: none; }
.is-embed .tree-panel ::v-deep .tree-title,
.is-embed .control-panel .control-section { border-color: rgba(90, 186, 255, .22); }
.is-embed .tree-panel,
.is-embed .control-panel,
.is-embed .control-panel .section-title,
.is-embed .tree-panel ::v-deep .tree-title { text-shadow: 0 1px 2px rgba(0, 10, 28, .9); }
.is-embed .tree-panel ::v-deep .el-input__inner,
.is-embed .control-panel ::v-deep .el-input__inner {
color: #f4fbff !important;
-webkit-text-fill-color: #f4fbff;
font-weight: 600;
background-color: transparent !important;
border-color: #4aa6ff !important;
box-shadow: none;
}
.is-embed .tree-panel ::v-deep .el-input__inner::-webkit-input-placeholder,
.is-embed .control-panel ::v-deep .el-input__inner::-webkit-input-placeholder,
.is-embed .tree-panel ::v-deep .el-input__inner::placeholder,
.is-embed .control-panel ::v-deep .el-input__inner::placeholder {
color: rgba(214, 242, 255, .78);
-webkit-text-fill-color: rgba(214, 242, 255, .78);
font-weight: 500;
}
.is-embed .control-panel ::v-deep .el-select .el-input .el-select__caret,
.is-embed .tree-panel ::v-deep .el-select .el-input .el-select__caret {
color: #e7f7ff;
}
.is-embed .tree-panel ::v-deep .tree-filters .el-button {
color: #e7f8ff;
border-color: #4aa6ff;
background: transparent;
box-shadow: none;
}
.control-panel .section-title { color: #7ad4ff; font-weight: 600; }
.control-panel .section-title small { color: #d7eeff; }
.control-panel .ptz-grid button {
color: #7ad4ff;
background: transparent;
border-color: #4aa6ff;
box-shadow: none;
}
.control-panel .ptz-grid button i {
font-weight: 700;
text-shadow: none;
}
.control-panel .ptz-grid button:hover,
.control-panel .ptz-grid button:active {
color: #ffffff;
background: transparent;
border-color: #7ec4ff;
box-shadow: none;
}
.control-panel .speed-row {
color: #f2fbff;
font-weight: 600;
}
.control-panel .speed-row > input[type="range"] {
border-color: #4aa6ff;
}
.control-panel .speed-row > input[type="range"]::-webkit-slider-thumb,
.control-panel .speed-row > input[type="range"]::-moz-range-thumb {
background: #8adfff;
}
.control-panel .lens-tool {
border: 0;
box-shadow: none;
}
.control-panel .preset-quick-actions button {
border-color: #4aa6ff;
}
.control-panel .section-actions button,
.control-panel .embed-layout-switch button {
color: #d7eeff;
border-color: #4aa6ff;
font-weight: 600;
background: transparent;
box-shadow: none;
}
.control-panel .embed-layout-icon i { border-width: 1px; }
.control-panel .embed-layout-switch button:hover,
.control-panel .embed-layout-switch button.active,
.control-panel .section-actions button.primary {
color: #ffffff;
border-color: #7ec4ff;
background: transparent;
box-shadow: none;
}
.is-embed .tree-panel ::v-deep .tree-content { scrollbar-color: rgba(96, 186, 255, .6) transparent; }
.is-embed .tree-panel ::v-deep .tree-content::-webkit-scrollbar-track { background: transparent; }
.is-embed .tree-panel ::v-deep .tree-content::-webkit-scrollbar-thumb { background: rgba(96, 186, 255, .55); border-color: transparent; box-shadow: 0 0 6px rgba(80, 190, 255, .45); }
.is-embed .control-panel { right: 0; }
.is-embed .tree-panel button,
.is-embed .tree-panel input,


+ 3
- 1
src/views/video/components/NvrDeviceTree.vue View File

@ -148,6 +148,7 @@ export default {
},
handleNodeClick(node) {
if (!node.channelFlag) return
if (this.isOffline(node)) return
const channel = this.normalizeChannel(node)
this.$emit('open', channel)
},
@ -195,7 +196,8 @@ export default {
::v-deep .el-tree-node__expand-icon.is-leaf { display: inline-block; width: 12px; }
::v-deep .el-tree-node__content:hover, ::v-deep .el-tree-node:focus > .el-tree-node__content { background: transparent; }
::v-deep .el-tree-node.is-current > .el-tree-node__content { color: #54ffff; background: transparent; }
.custom-tree-node.is-offline { color: #7f8da8; }
.custom-tree-node.is-offline { color: #7f8da8; cursor: not-allowed; }
::v-deep .el-tree-node__content:has(.is-offline) { cursor: not-allowed; }
</style>
<style lang="scss">


Loading…
Cancel
Save