@@ -71,37 +71,13 @@
<!-- 右侧信息 -- >
< div class = "right-section" >
< div class = "camera-section" >
<!-- 相机1 - WebSocket视频流 -- >
< div class = "video-contain er square-image" >
< canvas
ref = "camera1Canvas "
style = "width: 100%; height: 100%; "
> < / canvas >
<!-- 加载状态 -- >
< div v-if = "camera1Status === 'connecting'" class="video-overlay" >
< a -spin / >
< span style = "margin-left: 8px;" > 加载中 ... < / span >
< / div >
<!-- 错误状态 -- >
< div v-if = "camera1Status === 'error'" class="video-overlay error" >
< icon -close -circle -fill style = "color: #ff4d4f; font-size: 24px;" / >
< span > 连接失败 < / span >
< a-button size = "small" type = "primary" @click ="reconnectCamera1" > 重试 < / a -button >
< / div >
<!-- 未连接状态 -- >
< div v-if = "camera1Status === 'disconnected'" class="video-overlay" >
< icon -pause -circle -fill style = "color: #999; font-size: 24px;" / >
< span > 未连接 < / span >
< a-button size = "small" type = "primary" @click ="initCamera1" > 连接 < / a -button >
< / div >
<!-- 摄像头状态标识 -- >
< div v-if = "camera1Status === 'connected'" class="camera-badge" >
< span class = "live-badge" > LIVE < / span >
< / div >
<!-- 图片展示 -- >
< div class = "image-placehold er square-image" >
< img
:src = "imgData.imgUrl "
alt = "图片展示 "
style = "width: 100%; height: 100%; object-fit: cover; border-radius: 4px;"
/ >
< / div >
< / div >
@@ -298,8 +274,7 @@
< script setup lang = "ts" >
import { nextTick , onBeforeUnmount , onMounted , onUnmounted , reactive , ref } from 'vue'
import { Message , Modal , Notification } from '@arco-design/web-vue'
import { getMaterialDetail , validateWeighing , vmSend } from '@/apis/weightManage/weightManage'
import { getImg , getMaterialDetail , validateWeighing , vmSend } from '@/apis/weightManage/weightManage'
import { type WorkOrderResp , addWorkOrder , getWorkOrder } from '@/apis/workOrder/workOrder'
import { catchPhoto } from '@/apis/material/materialInfo'
@@ -322,21 +297,31 @@ const formData = reactive({
photoUrl : '' , // 样图URL
} )
const imgData = reactive ( {
imgUrl : '' , // 样图URL
} )
// 定时器引用
let pollingInterval = null
// 获取图片的方法
const getImage = ( ) => {
getImg ( ) . then ( ( res ) => {
if ( res . code === '0' ) {
imgData . imgUrl = res . data ? . imgUrl || ''
}
} )
}
//比对结果
const compareMatchResult = ref ( '' )
// 摄像头状态
const cameraStatus = ref < 'connected' | 'connecting' | 'disconnected' | 'error' > ( 'disconnected' )
const camera1Status = ref < 'connected' | 'connecting' | 'disconnected' | 'error' > ( 'disconnected' )
// 视频元素引用
const cameraVideo = ref < HTMLVideoElement | null > ( null )
// 相机1使用canvas元素
const camera1Canvas = ref < HTMLCanvasElement | null > ( null )
// 相机1 WebSocket连接
const camera1Ws = ref < WebSocket | null > ( null )
const camera1WsConnected = ref ( false )
// FLV播放器实例
let player : any = null
@@ -554,14 +539,10 @@ const stopCamera = () => {
reconnectCount . value = 1
}
// 监听步骤变化
watch ( activeStep , ( newVal ) => {
if ( newVal === 1 ) {
// 进入扫码核验页面, 启动相机1
nextTick ( ( ) => {
initCamera1 ( )
} )
} else if ( newVal === 2 ) {
if ( newVal === 2 ) {
// 进入称重登记页面,启动摄像头
nextTick ( ( ) => {
initCamera ( )
@@ -569,17 +550,13 @@ watch(activeStep, (newVal) => {
} else {
// 离开相关页面,停止摄像头
stopCamera ( )
closeCamera1WebSocket ( )
}
} )
// 组件挂载时
onMounted ( async ( ) => {
await loadFlvJs ( )
// 如果当前是扫码核验页面, 初始化相机1
if ( activeStep . value === 1 ) {
initCamera1 ( )
}
pollingInterval = setInterval ( getImg , 1000 )
} )
// 组件卸载时
@@ -803,7 +780,7 @@ const handleNext = async () => {
Message . error ( '请先扫描物料编码' )
return
}
// 调用后端接口获取比对结果
vmSend ( materialCode ) . then ( ( res ) => {
if ( res . code === '0' ) {
@@ -832,120 +809,7 @@ const handleNext = async () => {
}
}
// 初始化相机1 WebSocket连接
const initCamera1 = ( ) => {
camera1Status . value = 'connecting'
try {
const wsUrl = 'ws://localhost:6609/ws/camera'
camera1Ws . value = new WebSocket ( wsUrl )
camera1Ws . value . onopen = ( ) => {
camera1Status . value = 'connected'
camera1WsConnected . value = true
Message . success ( '已和相机1建立连接' )
}
// 修改前端代码,处理黑白相机的视频流数据
// 修改前端代码, 处理压缩后的JPEG图像数据
camera1Ws . value . onmessage = ( event ) => {
try {
if ( camera1Canvas . value && event . data instanceof Blob ) {
// 处理二进制图像数据
const reader = new FileReader ( ) ;
reader . onload = ( e ) => {
if ( e . target && e . target . result ) {
const arrayBuffer = e . target . result ;
const uint8Array = new Uint8Array ( arrayBuffer ) ;
// 解析消息格式: [width(4 bytes)][height(4 bytes)][image data]
if ( uint8Array . length < 8 ) {
console . error ( '相机1 WebSocket消息格式错误: 数据长度不足' ) ;
return ;
}
// 读取宽度和高度(小端序)
const width = uint8Array [ 0 ] | ( uint8Array [ 1 ] << 8 ) | ( uint8Array [ 2 ] << 16 ) | ( uint8Array [ 3 ] << 24 ) ;
const height = uint8Array [ 4 ] | ( uint8Array [ 5 ] << 8 ) | ( uint8Array [ 6 ] << 16 ) | ( uint8Array [ 7 ] << 24 ) ;
// 检查宽度和高度是否合理
if ( width <= 0 || height <= 0 || width > 4096 || height > 4096 ) {
console . error ( '相机1 WebSocket消息格式错误: 无效的图像尺寸' ) ;
return ;
}
// 提取压缩的图像数据
const imageDataStart = 8 ;
const imageData = uint8Array . subarray ( imageDataStart ) ;
// 创建Blob对象并转换为URL
const blob = new Blob ( [ imageData ] , { type : 'image/jpeg' } ) ;
const imageUrl = URL . createObjectURL ( blob ) ;
// 创建Image对象并显示
const img = new Image ( ) ;
img . onload = ( ) => {
// 设置canvas尺寸
camera1Canvas . value . width = width ;
camera1Canvas . value . height = height ;
// 获取canvas上下文
const ctx = camera1Canvas . value . getContext ( '2d' ) ;
if ( ctx ) {
// 绘制图像
ctx . drawImage ( img , 0 , 0 , width , height ) ;
}
// 释放URL对象
URL . revokeObjectURL ( imageUrl ) ;
} ;
img . onerror = ( ) => {
console . error ( '图像加载失败' ) ;
URL . revokeObjectURL ( imageUrl ) ;
} ;
img . src = imageUrl ;
}
} ;
reader . readAsArrayBuffer ( event . data ) ;
}
} catch ( error ) {
console . error ( '相机1 WebSocket消息解析失败:' , error )
}
}
camera1Ws . value . onclose = ( ) => {
camera1Status . value = 'disconnected'
camera1WsConnected . value = false
}
camera1Ws . value . onerror = ( error ) => {
console . error ( '相机1 WebSocket错误:' , error )
camera1Status . value = 'error'
Message . error ( '相机1连接失败' )
}
} catch ( error ) {
console . error ( '建立相机1 WebSocket连接失败:' , error )
camera1Status . value = 'error'
Message . error ( '无法建立相机1连接' )
}
}
// 重新连接相机1
const reconnectCamera1 = ( ) => {
closeCamera1WebSocket ( )
setTimeout ( ( ) => initCamera1 ( ) , 1000 )
}
// 关闭相机1 WebSocket连接
const closeCamera1WebSocket = ( ) => {
if ( camera1Ws . value ) {
camera1Ws . value . close ( )
camera1Ws . value = null
camera1WsConnected . value = false
camera1Status . value = 'disconnected'
}
}
// 处理上一步
const handlePrevious = ( ) => {
@@ -1198,7 +1062,9 @@ const closeWebSocket = () => {
// 组件卸载时关闭WebSocket连接
onUnmounted ( ( ) => {
closeWebSocket ( )
closeCamera1WebSocket ( )
if ( pollingInterval ) {
clearInterval ( pollingInterval )
}
} )
< / script >
@@ -1283,7 +1149,6 @@ onUnmounted(() => {
/* 主内容区域 */
. main - content {
display : flex ;
align - items : flex - start ;
margin - bottom : 30 px ;
}
@@ -1336,7 +1201,7 @@ onUnmounted(() => {
background : # 000 ;
border - radius : 4 px ;
overflow : hidden ;
margin - bottom : 20 px ;
margin : 20 px 0 ;
}
. video - container video {