|
|
@ -13,11 +13,23 @@ |
|
|
|
|
|
|
|
|
<main class="playback-workspace"> |
|
|
<main class="playback-workspace"> |
|
|
<div class="query-bar"> |
|
|
<div class="query-bar"> |
|
|
<label><span>日期</span><input v-model="queryDate" type="date"></label> |
|
|
|
|
|
<label><span>开始时间</span><input v-model="startTime" type="time" step="1"></label> |
|
|
|
|
|
|
|
|
<label> |
|
|
|
|
|
<span>日期</span> |
|
|
|
|
|
<el-date-picker v-model="queryDate" type="date" size="small" format="yyyy-MM-dd" value-format="yyyy-MM-dd" :clearable="false" /> |
|
|
|
|
|
</label> |
|
|
|
|
|
<label> |
|
|
|
|
|
<span>开始时间</span> |
|
|
|
|
|
<el-time-picker v-model="startTime" size="small" format="HH:mm:ss" value-format="HH:mm:ss" popper-class="video-time-picker" :clearable="false" /> |
|
|
|
|
|
</label> |
|
|
<em>至</em> |
|
|
<em>至</em> |
|
|
<label><span>结束时间</span><input v-model="endTime" type="time" step="1"></label> |
|
|
|
|
|
<label><span>下载时刻</span><input v-model="clipTime" type="time" step="1" title="留空时使用当前回放时刻"></label> |
|
|
|
|
|
|
|
|
<label> |
|
|
|
|
|
<span>结束时间</span> |
|
|
|
|
|
<el-time-picker v-model="endTime" size="small" format="HH:mm:ss" value-format="HH:mm:ss" popper-class="video-time-picker" :clearable="false" /> |
|
|
|
|
|
</label> |
|
|
|
|
|
<label> |
|
|
|
|
|
<span>下载时刻</span> |
|
|
|
|
|
<el-time-picker v-model="clipTime" size="small" format="HH:mm:ss" value-format="HH:mm:ss" popper-class="video-time-picker" placeholder="留空使用当前时刻" /> |
|
|
|
|
|
</label> |
|
|
<div class="query-actions"> |
|
|
<div class="query-actions"> |
|
|
<button type="button" class="primary" :disabled="busy" @click="queryPlayback"><i class="el-icon-search" />查询录像</button> |
|
|
<button type="button" class="primary" :disabled="busy" @click="queryPlayback"><i class="el-icon-search" />查询录像</button> |
|
|
<button type="button" :disabled="clipDownloading" @click="downloadClip"><i class="el-icon-download" />{{ clipDownloading ? '正在生成' : '下载1分钟' }}</button> |
|
|
<button type="button" :disabled="clipDownloading" @click="downloadClip"><i class="el-icon-download" />{{ clipDownloading ? '正在生成' : '下载1分钟' }}</button> |
|
|
@ -63,11 +75,15 @@ |
|
|
<div class="time-readout"><strong>{{ currentClock }}</strong><span>{{ timelineRangeText }}</span></div> |
|
|
<div class="time-readout"><strong>{{ currentClock }}</strong><span>{{ timelineRangeText }}</span></div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="control-center"> |
|
|
<div class="control-center"> |
|
|
<div class="volume"><i :class="volume ? 'el-icon-microphone' : 'el-icon-turn-off-microphone'" /><input v-model.number="volume" type="range" min="0" max="1" step="0.05" @input="syncVolume"></div> |
|
|
|
|
|
|
|
|
<div class="volume"><i :class="volume ? 'el-icon-microphone' : 'el-icon-turn-off-microphone'" /><input v-model.number="volume" type="range" min="0" max="1" step="0.05" :style="{ background: `linear-gradient(to right, #2787ed 0%, #2787ed ${volume * 100}%, transparent ${volume * 100}%, transparent 100%)` }" @input="syncVolume"></div> |
|
|
<div class="speed-group"> |
|
|
<div class="speed-group"> |
|
|
<button v-for="speed in speeds" :key="speed" type="button" :class="{ active: playbackSpeed === speed }" @click="setSpeed(speed)">{{ speed }}x</button> |
|
|
<button v-for="speed in speeds" :key="speed" type="button" :class="{ active: playbackSpeed === speed }" @click="setSpeed(speed)">{{ speed }}x</button> |
|
|
</div> |
|
|
</div> |
|
|
<div class="jump-control"><span>跳转</span><input v-model="jumpTime" type="time" step="1"><button type="button" @click="jumpToTime">定位</button></div> |
|
|
|
|
|
|
|
|
<div class="jump-control"> |
|
|
|
|
|
<span>跳转</span> |
|
|
|
|
|
<el-time-picker v-model="jumpTime" class="jump-time-picker" size="small" format="HH:mm:ss" value-format="HH:mm:ss" popper-class="video-time-picker" placeholder="选择时间" /> |
|
|
|
|
|
<button type="button" @click="jumpToTime">定位</button> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<button type="button" class="fullscreen" title="全屏" @click="fullscreen"><i class="el-icon-full-screen" /></button> |
|
|
<button type="button" class="fullscreen" title="全屏" @click="fullscreen"><i class="el-icon-full-screen" /></button> |
|
|
</section> |
|
|
</section> |
|
|
@ -347,10 +363,40 @@ export default { |
|
|
<style lang="scss" scoped> |
|
|
<style lang="scss" scoped> |
|
|
.playback-console { height: 100%; min-height: 0; display: flex; flex-direction: column; color: #dcecff; background: #0b1248; } |
|
|
.playback-console { height: 100%; min-height: 0; display: flex; flex-direction: column; color: #dcecff; background: #0b1248; } |
|
|
.playback-body { flex: 1; min-height: 0; display: flex; }.playback-workspace { flex: 1; min-width: 0; min-height: 0; padding: 10px 14px; display: flex; flex-direction: column; gap: 9px; } |
|
|
.playback-body { flex: 1; min-height: 0; display: flex; }.playback-workspace { flex: 1; min-width: 0; min-height: 0; padding: 10px 14px; display: flex; flex-direction: column; gap: 9px; } |
|
|
.query-bar { min-height: 58px; display: flex; align-items: flex-end; gap: 9px; padding: 7px 10px; border: 1px solid rgba(42,133,230,.38); background: rgba(7,30,84,.68); }.query-bar label { display: flex; flex-direction: column; gap: 5px; color: #7fa8d1; font-size: 11px; }.query-bar input { width: 126px; height: 29px; padding: 0 8px; border: 1px solid rgba(55,151,247,.48); color: #d4eaff; background: #09265e; outline: none; }.query-bar label:first-child input { width: 140px; }.query-bar em { height: 29px; line-height: 29px; color: #6c97c2; font-style: normal; }.query-actions { margin-left: auto; display: flex; gap: 6px; }.query-actions button { height: 30px; padding: 0 11px; border: 1px solid rgba(50,147,244,.52); color: #a9d3ff; background: #0a2b67; cursor: pointer; }.query-actions button.primary { color: #fff; background: #176bc2; }.query-actions button i { margin-right: 5px; }.query-actions button:disabled { opacity: .55; cursor: not-allowed; } |
|
|
|
|
|
|
|
|
.query-bar { min-height: 58px; display: flex; align-items: flex-end; gap: 9px; padding: 7px 10px; border: 1px solid rgba(42,133,230,.38); background: rgba(7,30,84,.68); }.query-bar label { display: flex; flex-direction: column; gap: 5px; color: #7fa8d1; font-size: 11px; }.query-bar em { height: 29px; line-height: 29px; color: #6c97c2; font-style: normal; }.query-actions { margin-left: auto; display: flex; gap: 6px; }.query-actions button { height: 30px; padding: 0 11px; border: 1px solid rgba(50,147,244,.52); color: #a9d3ff; background: #0a2b67; cursor: pointer; }.query-actions button.primary { color: #fff; background: #176bc2; }.query-actions button i { margin-right: 5px; }.query-actions button:disabled { opacity: .55; cursor: not-allowed; } |
|
|
|
|
|
::v-deep .query-bar .el-date-editor { width: 126px; }.query-bar label:first-child ::v-deep .el-date-editor { width: 140px; }::v-deep .query-bar .el-input__inner { height: 29px; padding: 0 28px 0 30px; line-height: 29px; } |
|
|
.video-stage { position: relative; flex: 1; min-height: 260px; overflow: hidden; border: 1px solid #176bc2; background: #03081d; }.video-stage video { width: 100%; height: 100%; display: block; object-fit: contain; }.stage-head { position: absolute; z-index: 2; top: 0; left: 0; right: 0; height: 34px; padding: 0 10px; display: flex; align-items: center; gap: 12px; color: #c9e3ff; background: linear-gradient(180deg,rgba(2,9,31,.94),transparent); font-size: 11px; }.stage-head span { display: flex; align-items: center; gap: 6px; }.stage-head span i { width: 7px; height: 7px; border-radius: 50%; background: #d09231; }.stage-head span i.playing { background: #25dfa2; box-shadow: 0 0 8px #25dfa2; }.stage-head small { color: #7da8d4; }.stage-head em { margin-left: auto; color: #5e8dbb; font-style: normal; }.stage-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px; color: #6d9bc8; background: radial-gradient(circle at center,rgba(10,45,96,.65),rgba(3,8,29,.92)); }.stage-overlay i { font-size: 36px; }.stage-overlay strong { color: #b9d8f7; font-size: 14px; }.stage-overlay span { font-size: 11px; }.stage-clock { position: absolute; right: 10px; bottom: 8px; color: #a7caec; font-family: Consolas,monospace; font-size: 12px; } |
|
|
.video-stage { position: relative; flex: 1; min-height: 260px; overflow: hidden; border: 1px solid #176bc2; background: #03081d; }.video-stage video { width: 100%; height: 100%; display: block; object-fit: contain; }.stage-head { position: absolute; z-index: 2; top: 0; left: 0; right: 0; height: 34px; padding: 0 10px; display: flex; align-items: center; gap: 12px; color: #c9e3ff; background: linear-gradient(180deg,rgba(2,9,31,.94),transparent); font-size: 11px; }.stage-head span { display: flex; align-items: center; gap: 6px; }.stage-head span i { width: 7px; height: 7px; border-radius: 50%; background: #d09231; }.stage-head span i.playing { background: #25dfa2; box-shadow: 0 0 8px #25dfa2; }.stage-head small { color: #7da8d4; }.stage-head em { margin-left: auto; color: #5e8dbb; font-style: normal; }.stage-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px; color: #6d9bc8; background: radial-gradient(circle at center,rgba(10,45,96,.65),rgba(3,8,29,.92)); }.stage-overlay i { font-size: 36px; }.stage-overlay strong { color: #b9d8f7; font-size: 14px; }.stage-overlay span { font-size: 11px; }.stage-clock { position: absolute; right: 10px; bottom: 8px; color: #a7caec; font-family: Consolas,monospace; font-size: 12px; } |
|
|
.timeline-panel { padding: 8px 10px 4px; border: 1px solid rgba(43,133,226,.38); background: rgba(7,29,80,.72); }.timeline-head { display: flex; align-items: center; justify-content: space-between; color: #bcd9f7; font-size: 11px; }.timeline-head span { display: flex; align-items: center; gap: 6px; }.timeline-head i { width: 6px; height: 6px; border-radius: 50%; background: #1a8cff; }.timeline-head small { color: #6d98c2; }.timeline { position: relative; height: 46px; margin-top: 4px; cursor: pointer; }.timeline-track { position: absolute; left: 0; right: 0; top: 12px; height: 7px; background: #071b44; border: 1px solid #183f73; }.actual-range { position: absolute; top: -1px; height: 7px; background: #1989ee; box-shadow: 0 0 7px rgba(25,137,238,.6); }.timeline-marker { position: absolute; z-index: 2; top: -5px; width: 1px; height: 17px; background: #54ffff; }.timeline-marker span { position: absolute; left: 50%; top: -17px; transform: translateX(-50%); color: #54ffff; font-size: 9px; white-space: nowrap; }.timeline-empty { position: absolute; top: 3px; left: 50%; transform: translateX(-50%); color: #587fa8; font-size: 10px; }.timeline-labels { position: absolute; left: 0; right: 0; bottom: 0; display: flex; justify-content: space-between; color: #557da7; font-size: 9px; } |
|
|
|
|
|
.playback-controls { height: 48px; min-height: 48px; padding: 0 9px; display: flex; align-items: center; border: 1px solid rgba(43,133,226,.38); background: #081e53; }.transport { display: flex; align-items: center; gap: 5px; }.playback-controls button { border: 1px solid rgba(53,146,238,.5); color: #a8d2fa; background: #0a2b67; cursor: pointer; }.transport>button { width: 29px; height: 29px; }.transport button.play { width: 35px; height: 35px; border-radius: 50%; color: #fff; background: #176bc2; }.time-readout { width: 170px; display: flex; flex-direction: column; margin-left: 6px; }.time-readout strong { color: #54ffff; font: 13px Consolas,monospace; }.time-readout span { color: #638fb9; font-size: 9px; }.control-center { flex: 1; display: flex; align-items: center; justify-content: center; gap: 18px; }.volume { display: flex; align-items: center; gap: 5px; color: #71a7d7; }.volume input { width: 76px; accent-color: #228ef1; }.speed-group { display: flex; }.speed-group button { width: 34px; height: 27px; border-right: 0; }.speed-group button:last-child { border-right: 1px solid rgba(53,146,238,.5); }.speed-group button.active { color: #fff; background: #176bc2; }.jump-control { display: flex; align-items: center; gap: 5px; color: #729dcc; font-size: 10px; }.jump-control input { width: 100px; height: 27px; padding: 0 5px; border: 1px solid rgba(53,146,238,.5); color: #d1e7ff; background: #081f53; }.jump-control button { height: 27px; }.fullscreen { width: 30px; height: 30px; } |
|
|
|
|
|
|
|
|
.timeline-panel { padding: 8px 10px 4px; border: 1px solid rgba(43,133,226,.38); background: rgba(7,29,80,.72); }.timeline-head { display: flex; align-items: center; justify-content: space-between; color: #bcd9f7; font-size: 11px; }.timeline-head span { display: flex; align-items: center; gap: 6px; }.timeline-head i { width: 6px; height: 6px; border-radius: 50%; background: #1a8cff; }.timeline-head small { color: #6d98c2; }.timeline { position: relative; height: 46px; margin-top: 4px; cursor: pointer; }.timeline-track { position: absolute; left: 0; right: 0; top: 12px; height: 7px; background: #071b44; border: 1px solid #2787ed; }.actual-range { position: absolute; top: -1px; height: 7px; background: #1989ee; box-shadow: 0 0 7px rgba(25,137,238,.6); }.timeline-marker { position: absolute; z-index: 2; top: -5px; width: 1px; height: 17px; background: #54ffff; }.timeline-marker span { position: absolute; left: 50%; top: -17px; transform: translateX(-50%); color: #54ffff; font-size: 9px; white-space: nowrap; }.timeline-empty { position: absolute; top: 3px; left: 50%; transform: translateX(-50%); color: #587fa8; font-size: 10px; }.timeline-labels { position: absolute; left: 0; right: 0; bottom: 0; display: flex; justify-content: space-between; color: #557da7; font-size: 9px; } |
|
|
|
|
|
.playback-controls { height: 48px; min-height: 48px; padding: 0 9px; display: flex; align-items: center; border: 1px solid rgba(43,133,226,.38); background: #081e53; }.transport { display: flex; align-items: center; gap: 5px; }.playback-controls button { border: 1px solid rgba(53,146,238,.5); color: #a8d2fa; background: #0a2b67; cursor: pointer; }.transport>button { width: 29px; height: 29px; }.transport button.play { width: 35px; height: 35px; border-radius: 50%; color: #fff; background: #176bc2; }.time-readout { width: 170px; display: flex; flex-direction: column; margin-left: 6px; }.time-readout strong { color: #54ffff; font: 13px Consolas,monospace; }.time-readout span { color: #638fb9; font-size: 9px; }.control-center { flex: 1; display: flex; align-items: center; justify-content: center; gap: 18px; }.volume { display: flex; align-items: center; gap: 5px; color: #71a7d7; }.volume input[type="range"] { width: 76px; height: 8px; box-sizing: border-box; margin: 0; appearance: none; border: 1px solid #2787ed; border-radius: 4px; outline: none; cursor: pointer; }.volume input[type="range"]::-webkit-slider-runnable-track { height: 6px; border: 0; border-radius: 3px; background: transparent; }.volume input[type="range"]::-webkit-slider-thumb { width: 14px; height: 14px; margin-top: -4px; appearance: none; border: 0; border-radius: 50%; background: #2787ed; }.volume input[type="range"]::-moz-range-track { height: 6px; border: 0; border-radius: 3px; background: transparent; }.volume input[type="range"]::-moz-range-progress { background: transparent; }.volume input[type="range"]::-moz-range-thumb { width: 14px; height: 14px; border: 0; border-radius: 50%; background: #2787ed; }.speed-group { display: flex; }.speed-group button { width: 34px; height: 27px; border-right: 0; }.speed-group button:last-child { border-right: 1px solid rgba(53,146,238,.5); }.speed-group button.active { color: #fff; background: #176bc2; }.jump-control { display: flex; align-items: center; gap: 5px; color: #729dcc; font-size: 10px; }.jump-time-picker { width: 112px; }.jump-control button { height: 27px; }.fullscreen { width: 30px; height: 30px; } |
|
|
|
|
|
::v-deep .jump-time-picker .el-input__inner { height: 27px; padding: 0 28px 0 30px; line-height: 27px; } |
|
|
.status-line { min-height: 29px; padding: 0 10px; display: flex; align-items: center; gap: 7px; color: #7fa8d0; border: 1px solid rgba(43,133,226,.25); background: rgba(6,25,70,.6); font-size: 11px; }.status-line i { width: 6px; height: 6px; border-radius: 50%; background: #428fda; }.status-line.success i { background: #2bdb9f; }.status-line.warn i { background: #e5a83d; }.status-line.error i { background: #ff5c72; } |
|
|
.status-line { min-height: 29px; padding: 0 10px; display: flex; align-items: center; gap: 7px; color: #7fa8d0; border: 1px solid rgba(43,133,226,.25); background: rgba(6,25,70,.6); font-size: 11px; }.status-line i { width: 6px; height: 6px; border-radius: 50%; background: #428fda; }.status-line.success i { background: #2bdb9f; }.status-line.warn i { background: #e5a83d; }.status-line.error i { background: #ff5c72; } |
|
|
@media (max-width: 1250px) { .query-bar { flex-wrap: wrap; }.query-actions { margin-left: 0; }.control-center { gap: 8px; }.time-readout { width: 130px; } } |
|
|
@media (max-width: 1250px) { .query-bar { flex-wrap: wrap; }.query-actions { margin-left: 0; }.control-center { gap: 8px; }.time-readout { width: 130px; } } |
|
|
</style> |
|
|
</style> |
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss"> |
|
|
|
|
|
.video-time-picker { |
|
|
|
|
|
.el-time-panel__content::before { |
|
|
|
|
|
left: 0; |
|
|
|
|
|
right: 0; |
|
|
|
|
|
z-index: 0; |
|
|
|
|
|
margin: -15px 0 0; |
|
|
|
|
|
padding: 0; |
|
|
|
|
|
border-color: #2787ed; |
|
|
|
|
|
background: #176b9e; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.el-time-panel__content::after { |
|
|
|
|
|
display: none; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.el-time-spinner__wrapper, |
|
|
|
|
|
.el-time-spinner__list { |
|
|
|
|
|
z-index: 1; |
|
|
|
|
|
background: transparent !important; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.el-time-spinner__item.active:not(.disabled) { |
|
|
|
|
|
background: transparent !important; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
</style> |