添加视频录制按钮

This commit is contained in:
cwchen 2026-01-19 15:00:56 +08:00
parent e2daa18de9
commit b75e4d381b
2 changed files with 250 additions and 2 deletions

View File

@ -27,3 +27,21 @@ export function getVideoStreamAPI(params) {
})
}
// 设备管理->视频监控->操作设备
export function operDeviceAPI(data) {
return request({
url: '/smartCar/data/line/operDevice',
method: 'POST',
data
})
}
// 设备管理->视频监控->开始录制视频 和 结束录制视频
export function recordingVideoAPI(data) {
return request({
url: '/smartCar/data/line/recordingVideo',
method: 'POST',
data
})
}

View File

@ -34,6 +34,35 @@
</el-button>
</template>
</div>
<div class="device-control-buttons">
<!-- <el-button type="warning" class="lock-position-btn" @click="handleLockPosition"
icon="el-icon-lock" :loading="locking">
位置锁定
</el-button>
<el-button type="success" class="unlock-position-btn" @click="handleUnlockPosition"
icon="el-icon-unlock" :loading="unlocking">
位置解锁
</el-button> -->
<el-button v-if="!isRecording" type="primary" plain icon="el-icon-video-camera"
:loading="recordingLoading" @click="handleStartRecord">
开始录制
</el-button>
<el-button v-else type="danger" plain class="recording-btn" icon="el-icon-video-pause"
:loading="recordingLoading" @click="handleStopRecord">
<span class="recording-dot"></span>
结束录制
</el-button>
<el-button type="danger" class="shutdown-device-btn" @click="handleShutdownDevice"
icon="el-icon-switch-button" :loading="shuttingDown">
设备关机
</el-button>
<el-button type="info" class="clear-alarm-btn" @click="handleClearAlarm" icon="el-icon-bell"
:loading="clearingAlarm">
解除告警
</el-button>
</div>
</div>
</div>
</el-card>
@ -62,7 +91,7 @@
</template>
<script>
import { getLineDetailAPI, updateLineAPI, getVideoStreamAPI } from '@/api/device/video'
import { getLineDetailAPI, updateLineAPI, getVideoStreamAPI, operDeviceAPI,recordingVideoAPI } from '@/api/device/video'
export default {
name: 'VideoMonitor',
@ -86,6 +115,11 @@ export default {
videoErrorShown: false,
//
isFullscreen: false,
// loading
locking: false,
unlocking: false,
shuttingDown: false,
clearingAlarm: false,
//
lastContainerWidth: 0,
lastContainerHeight: 0,
@ -97,7 +131,10 @@ export default {
startY: '',
endX: '',
endY: '',
}
},
//
isRecording: false, //
recordingLoading: false, // loading
}
},
computed: {
@ -515,6 +552,161 @@ export default {
} catch (error) {
console.error('获取视频流失败:', error)
}
},
/** 位置锁定 */
async handleLockPosition() {
this.$confirm('确定要锁定设备位置吗?', '位置锁定', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
this.locking = true
try {
// TODO: API
// const res = await lockPositionAPI()
// if (res.code === 200) {
// this.$message.success('')
// } else {
// this.$message.error(res.msg || '')
// }
this.$message.success('位置锁定成功')
} catch (error) {
console.error('位置锁定失败:', error)
this.$message.error('位置锁定失败,请稍后重试')
} finally {
this.locking = false
}
}).catch(() => { })
},
/** 位置解锁 */
async handleUnlockPosition() {
this.$confirm('确定要解锁设备位置吗?', '位置解锁', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
this.unlocking = true
try {
// TODO: API
// const res = await unlockPositionAPI()
// if (res.code === 200) {
// this.$message.success('')
// } else {
// this.$message.error(res.msg || '')
// }
this.$message.success('位置解锁成功')
} catch (error) {
console.error('位置解锁失败:', error)
this.$message.error('位置解锁失败,请稍后重试')
} finally {
this.unlocking = false
}
}).catch(() => { })
},
/* *开始录制视频 */
async handleStartRecord() {
this.recordingLoading = true
try {
//
// ID { deviceId: this.lineInfo.deviceId }
const res = await recordingVideoAPI({recordingType:1})
if (res.code === 200) {
this.isRecording = true
this.$message.success('已下发开始录制指令')
} else {
this.$message.error(res.msg || '开启录制失败')
}
} catch (error) {
console.error('录制请求异常:', error)
this.$message.error('请求失败')
} finally {
this.recordingLoading = false
}
},
/** 结束录制 */
async handleStopRecord() {
this.$confirm('确定要结束当前的视频录制吗?', '提示', {
confirmButtonText: '结束录制',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
this.recordingLoading = true
try {
//
const res = await recordingVideoAPI({recordingType:2})
if (res.code === 200) {
this.isRecording = false
this.$message.success('录制已结束,视频保存中')
} else {
this.$message.error(res.msg || '结束录制失败')
}
} catch (error) {
console.error('停止录制请求异常:', error)
this.$message.error('请求失败')
} finally {
this.recordingLoading = false
}
}).catch(() => { })
},
/** 设备关机 */
async handleShutdownDevice() {
this.$confirm('确定要关闭设备吗?设备将停止运行', '设备关机', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
this.shuttingDown = true
try {
// API
const res = await operDeviceAPI({ mode: 2 })
if (res.code === 200) {
this.$message.success('设备关机成功')
} else {
this.$message.error(res.msg || '设备关机失败')
}
this.$message.success('设备关机成功')
} catch (error) {
console.error('设备关机失败:', error)
this.$message.error('设备关机失败,请稍后重试')
} finally {
this.shuttingDown = false
}
}).catch(() => { })
},
/** 解除告警 */
async handleClearAlarm() {
this.$confirm('确定要解除设备告警吗?', '解除告警', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}).then(async () => {
this.clearingAlarm = true
try {
// API
const res = await operDeviceAPI({
alarm: false
})
if (res.code === 200) {
this.$message.success('解除告警成功')
} else {
this.$message.error(res.msg || '解除告警失败')
}
this.$message.success('解除告警成功')
} catch (error) {
console.error('解除告警失败:', error)
this.$message.error('解除告警失败,请稍后重试')
} finally {
this.clearingAlarm = false
}
}).catch(() => { })
}
}
}
@ -617,6 +809,15 @@ export default {
align-items: center;
gap: 12px;
}
.device-control-buttons {
display: flex;
align-items: center;
gap: 12px;
margin-left: 12px;
padding-left: 12px;
border-left: 1px solid #e4e7ed;
}
}
}
@ -761,4 +962,33 @@ video::-webkit-media-controls-enclosure {
video::-internal-media-controls-download-button {
display: none;
}
/* 录制中状态的样式 */
.recording-btn {
position: relative;
.recording-dot {
display: inline-block;
width: 8px;
height: 8px;
background-color: red;
border-radius: 50%;
margin-right: 5px;
animation: recording-flash 1.5s infinite ease-in-out;
}
}
@keyframes recording-flash {
0% {
opacity: 1;
}
50% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
</style>