1.相机查询

2.取消流的日志
3.首页修改
4.相机控制
master
LAPTOP-S9HJSOEB\昊天 8 months ago
parent ea2fa52f8e
commit a0252bb5d5

@ -4,7 +4,7 @@ NODE_ENV=production
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://192.168.0.10:48080'
VITE_BASE_URL='http://192.168.2.162:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server
@ -33,4 +33,4 @@ VITE_OUT_DIR=dist
VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn'
# 验证码的开关
VITE_APP_CAPTCHA_ENABLE=true
VITE_APP_CAPTCHA_ENABLE=false

@ -4,7 +4,7 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://192.168.0.10:48080'
VITE_BASE_URL='http://192.168.0.162:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server
@ -31,3 +31,6 @@ VITE_OUT_DIR=dist-prod
# 商城H5会员端域名
VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn'
# 验证码的开关
VITE_APP_CAPTCHA_ENABLE=false

@ -4,7 +4,7 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://192.168.0.10:48080'
VITE_BASE_URL='http://192.168.0.162:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server

@ -4,7 +4,7 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://192.168.0.10:48080'
VITE_BASE_URL='http://192.168.0.162:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

@ -41,8 +41,8 @@ export const CameraApi = {
return request.get({ url: `/logistics/camera/list` })
},
// 查询相机详情
getCamera: async (id: number) => {
return await request.get({ url: `/logistics/camera/get?id=` + id })
getCamera: (id: number) => {
return request.get({ url: `/logistics/camera/get?id=` + id })
},
// 新增相机

@ -80,5 +80,10 @@ export const StockApi = {
//请求卡片信息接口
getStockStatus: async (data: any) => {
return await request.post({ url: `/logistics/stock/getStockStatus`, data })
},
//请求卡片信息接口
artificial: async (data: any) => {
return await request.post({ url: `/logistics/stock/artificial`, data })
}
}

@ -18,6 +18,9 @@ export const getSimpleDictDataList = () => {
return request.get({ url: '/system/dict-data/simple-list' })
}
export const getTypeList = (type: string) => {
return request.get({ url: '/system/dict-data/type?type='+type })
}
// 查询字典数据列表
export const getDictDataPage = (params: PageParam) => {
return request.get({ url: '/system/dict-data/page', params })

@ -22,11 +22,12 @@ const props = defineProps({
type: Object as PropType<EChartsOption>,
required: true
},
dark: propTypes.bool.def(false),
width: propTypes.oneOfType([Number, String]).def(''),
height: propTypes.oneOfType([Number, String]).def('500px')
})
const isDark = computed(() => appStore.getIsDark)
const isDark = computed(() => props.dark|| appStore.getIsDark)
const theme = computed(() => {
const echartTheme: boolean | string = unref(isDark) ? true : 'auto'
@ -58,7 +59,7 @@ const styles = computed(() => {
const initChart = () => {
if (unref(elRef) && props.options) {
echartRef = echarts.init(unref(elRef) as HTMLElement)
echartRef = echarts.init(unref(elRef) as HTMLElement, props.dark?'dark':'')
echartRef?.setOption(unref(options))
}
}

@ -46,7 +46,7 @@ export default {
setup(props) {
console.log(props.ptzShow)
// console.log(props.ptzShow)
const video = ref(null)
const selfVideo = ref(null)
const url = ref(null)
@ -59,27 +59,37 @@ export default {
const msgrecv = ref(null)
// const streamUrl = ref(document.location.protocol + "//" + window.location.host + "/index/api/webrtc?app=live&stream=test&type=play");
const streamUrl = ref(
document.location.protocol +
'//' +
window.location.host +
':8096/index/api/webrtc?app=live&stream=camera' +
props.cameraId +
'&type=play'
)
const player = ref(null)
const recvOnly = ref(true)
const resolutions = ref([])
const resolution = ref('')
// cameraId
watch(() => props.cameraId, (newCameraId, oldCameraId) => {
console.log(newCameraId);
// console.log(newCameraId);
if (newCameraId !== oldCameraId) {
ZLMRTCClient.GetAllScanResolution().forEach((r, i) => {
let text = r.label + '(' + r.width + 'x' + r.height + ')'
resolutions.value.push({
text: text,
value: r
})
})
resolution.value = resolutions.value[0].text
stopVideo()
startVideo()
// console.log(newCameraId);
//
console.log(newCameraId+"54651561");
// console.log(newCameraId+"54651561");
}
}),
onMounted(() => {
// formData.value = CameraApi.getCamera(props.cameraId)
// console.log(formData.value);
ZLMRTCClient.GetAllScanResolution().forEach((r, i) => {
let text = r.label + '(' + r.width + 'x' + r.height + ')'
resolutions.value.push({
@ -89,32 +99,48 @@ export default {
})
resolution.value = resolutions.value[0].text
formData.value = CameraApi.getCamera(props.cameraId)
stopVideo()
startVideo()
})
//
onUnmounted(() => {
stopVideo()
})
const radioChange = (value) => {
let urlObj = new URL(streamUrl.value)
urlObj.searchParams.set('type', value)
streamUrl.value = urlObj.href
if (value == 'play') {
recvOnly.value = true
} else if (value == 'echo') {
recvOnly.value = false
} else {
recvOnly.value = false
}
}
// const radioChange = (value) => {
// let urlObj = new URL(streamUrl.value)
// urlObj.searchParams.set('type', value)
// streamUrl.value = urlObj.href
// if (value == 'play') {
// recvOnly.value = true
// } else if (value == 'echo') {
// recvOnly.value = false
// } else {
// recvOnly.value = false
// }
// }
const changeResolution = (e) => {
resolution.value = e.target.options[e.target.selectedIndex].text
}
const start_play = () => {
const start_play =async () => {
// const urlIp = ref("")
const resCamera = await CameraApi.getCamera(props.cameraId)
const urlIp = resCamera
console.log(urlIp);
const streamUrl = ref(
document.location.protocol +
'//' +
urlIp.rtcServer +
':'+urlIp.rtcServerPort+'/index/api/webrtc?app=live&stream=camera' +
props.cameraId +
'&type=play'
)
console.log(streamUrl.value);
let res = resolution.value.match(/\d+/g)
let h = parseInt(res.pop())
let w = parseInt(res.pop())
@ -137,15 +163,15 @@ export default {
})
player.value.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, function (e) {
console.log('ICE 协商出错')
// console.log('ICE ')
})
player.value.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, function (e) {
console.log('播放成功', e.streams)
// console.log('', e.streams)
})
player.value.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, function (e) {
console.log('offer anwser 交换失败', e)
// console.log('offer anwser ', e)
stopVideo()
})
@ -155,42 +181,42 @@ export default {
})
player.value.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, function (s) {
console.log('获取本地流失败')
// console.log('')
})
player.value.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, function (state) {
console.log('当前状态==>', state)
// console.log('==>', state)
})
player.value.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN, function (event) {
console.log('rtc datachannel 打开 :', event)
// // console.log('rtc datachannel :', event)
})
player.value.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG, function (event) {
console.log('rtc datachannel 消息 :', event.data)
// console.log('rtc datachannel :', event.data)
msgrecv.value.value = event.data
})
player.value.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR, function (event) {
console.log('rtc datachannel 错误 :', event)
// console.log('rtc datachannel :', event)
})
player.value.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE, function (event) {
console.log('rtc datachannel 关闭 :', event)
// console.log('rtc datachannel :', event)
})
}
const startVideo = () => {
console.log('开始')
// console.log('')
stopVideo()
let res = resolution.value.match(/\d+/g)
let h = '50%'
let w = '50%'
console.log(h, w)
console.log(video.value)
// console.log(h, w)
// console.log(video.value)
start_play()
}
const stopVideo = () => {
console.log('停止')
// console.log('')
if (player.value) {
player.value.close()
player.value = null
@ -221,12 +247,12 @@ export default {
datachannel,
msgsend,
msgrecv,
streamUrl,
// streamUrl,
player,
recvOnly,
resolutions,
resolution,
radioChange,
// radioChange,
changeResolution,
startVideo,
stopVideo,

@ -105,6 +105,7 @@ export enum DICT_TYPE {
SHELVES_TYPE = 'shelves_type',
LIGHT_TYPE = 'light_type',
CAMERA_TYPE = 'camera_type',
CAMERA_CONF = 'camera_conf',
CHECK_STATUS = 'check_status',
ORDER_STATUS = 'order_status',//camera_type
SIDE = 'side',
@ -112,7 +113,8 @@ export enum DICT_TYPE {
TCP_CLIENT_STATUS = 'tcp_client_status',//tcp连接状态
TCP_PROCESSOR = 'tcp_processor',//tcp处理器类型
TCP_LOG_STATUS= 'tcp_log_status',//tcp日志类型
SCANGUN_TYPE = 'scangun_type',
TCP_LOG_STATUS= 'tcp_log_status',//tcp日志类型
TERMINAL = 'terminal', // 终端
DATE_INTERVAL = 'date_interval', // 数据间隔

@ -1,43 +1,39 @@
<template>
<ContentWrap>
<ContentWrap class="body" >
<el-row :gutter="20">
<!-- 左侧区域 -->
<el-col :span="7">
<el-col :span="7" >
<!-- 左上统计信息 -->
<el-card style="height: 250px" shadow="always" class="mb-20px">
<el-card class="box-card" style="height: 250px" shadow="always" >
<template #header>
<div class="card-header">
<div class="card-header" :body-style="{ borderTop: 'none' }">
<span>统计信息</span>
</div>
</template>
<div>
<p>总盘点数: {{ statistics.checkLogCount }}</p>
<p>总随行数: {{ statistics.orderCount }}</p>
<p>月盘点数: {{ statistics.checkLogMonthCount }}</p>
<p>月随行数: {{ statistics.orderMonthCount }}</p>
<p class="colour-text">总盘点数: {{ statistics.checkLogCount }}</p>
<p class="colour-text">总随行数: {{ statistics.orderCount }}</p>
<p class="colour-text">月盘点数: {{ statistics.checkLogMonthCount }}</p>
<p class="colour-text">月随行数: {{ statistics.orderMonthCount }}</p>
</div>
</el-card>
<!-- 左中条状图 -->
<el-card shadow="always">
<el-card class="box-card" shadow="always">
<template #header>
<div class="card-header">
<span>盘点状态</span>
</div>
</template>
<Echart style="width: 100%; height: 200px" :options="deviceStatusChartOption" />
<Echart dark="true" style="width: 100%; height: 200px" :options="deviceStatusChartOption" />
</el-card>
</el-col>
<!-- 中间区域 -->
<el-col :span="10">
<!-- 中上和中中选择相机直播 -->
<el-card shadow="always">
<template #header>
<div class="card-header">
<span>选择相机</span>
</div>
</template>
<el-card class="box-card" shadow="always" style="height: 590px">
<el-select v-model="selectedCamera" placeholder="请选择相机" style="width: 100%">
<el-option
v-for="camera in cameraList"
@ -46,7 +42,7 @@
:value="camera.id"
/>
</el-select>
<div style="height: 420px; background-color: #555555" class="mt-20px">
<div style="height: 500px; background-color: #555555" class="mt-20px">
<Camera v-if="selectedCamera" :cameraId="selectedCamera" />
</div>
</el-card>
@ -55,7 +51,7 @@
<!-- 右侧区域 -->
<el-col :span="7">
<!-- 右上快捷方式 -->
<el-card style="height: 250px" shadow="always" class="mb-20px">
<el-card class="box-card" style="height: 250px" shadow="always">
<template #header>
<div class="card-header">
<span>快捷方式</span>
@ -69,10 +65,9 @@
<el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-50px">
<div class="flex items-center">
<Icon :icon="item.icon" size="30" class="mr-3px" />
<router-link :to="item.url">
<el-link type="default" :underline="false">
{{ item.name }}
<span class='white-text-icon'>{{ item.name }}</span>
</el-link>
</router-link>
</div>
@ -81,13 +76,13 @@
</el-card>
<!-- 右中另一个条状图 -->
<el-card shadow="always">
<el-card class="box-card" shadow="always">
<template #header>
<div class="card-header">
<span>本月随行情况</span>
</div>
</template>
<Echart style="width: 100%; height: 200px" :options="orderChartOption" />
<Echart dark="true" style="width: 100%; height: 200px" :options="orderChartOption" />
</el-card>
</el-col>
</el-row>
@ -96,28 +91,28 @@
<el-row :gutter="20" class="mt-20px">
<el-col :span="7">
<!-- 左下实时滚动信息 -->
<el-card shadow="always">
<el-card class="box-card" shadow="always">
<template #header>
<div class="card-header">
<span>盘点饼状图</span>
</div>
</template>
<Echart style="width: 100%; height: 200px" :options="stockPieOptions" />
<Echart dark="true" style="width: 100%; height: 200px" :options="stockPieOptions" />
</el-card>
</el-col>
<el-col :span="10">
<el-card shadow="always">
<el-card class="box-card" shadow="always">
<template #header>
<div class="card-header">
<span>随行折线图</span>
</div>
</template>
<Echart style="width: 100%; height: 200px" :options="laneInventoryLineOptions" />
<Echart dark="true" style="width: 100%; height: 200px" :options="laneInventoryLineOptions" />
</el-card>
</el-col>
<el-col :span="7">
<!-- 左下实时滚动信息 -->
<el-card shadow="always">
<el-card class="box-card" shadow="always">
<template #header>
<div class="card-header">
<span>实时滚动信息</span>
@ -129,7 +124,10 @@
:key="index"
class="log-item"
>
<p class="colour-text">
{{ item }}
</p>
</div>
</el-scrollbar>
</el-card>
@ -286,32 +284,32 @@ const getShortcut = async () => {
{
name: '随行记录',
icon: 'ep:data-analysis',
url: 'logistics/order'
url: 'logistics/order',
},
{
name: '盘点管理',
icon: 'ep:coin',
url: 'logistics/check-log'
url: 'logistics/check-log',
},
{
name: '盘点信息',
icon: 'ep:pointer',
url: 'logistics/stock'
url: 'logistics/stock',
},
{
name: '实时视频',
icon: 'ep:magic-stick',
url: 'cameraTree/cameraStreet'
url: 'cameraTree/cameraStreet',
},
{
name: '巷道管理',
icon: 'fa-solid:rainbow',
url: 'system/street'
url: 'system/street',
},
{
name: '相机管理',
icon: 'ep:camera-filled',
url: 'system/camera'
url: 'system/camera',
}
]
shortcut = Object.assign(shortcut, data)
@ -337,13 +335,13 @@ let eventSource: any = null
const sseUid = ref(`${Date.now()}-${Math.floor(Math.random() * 10000)}`)
const sse = ()=>{
// EventSource SSE
eventSource = new EventSource('http://192.168.0.10:48080/app-api/sse/createSse?uid=' + sseUid.value );
eventSource = new EventSource(import.meta.env.VITE_BASE_URL+'/app-api/sse/createSse?uid=' + sseUid.value );
//
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(data);
const data = JSON.parse(event.data);
console.log(data);
realTimeLogs.value.push(data.message)
};
//
@ -467,12 +465,34 @@ onUnmounted(() => {
})
</script>
<style scoped>
.body{
background-image:url(/public/pic02.jpg) ;
background-size:cover;
}
.card-header {
display: flex;
justify-content: space-between;
justify-content: center;
align-items: center;
padding: 10px;
color: white;
background: url('/public/pic01.png') no-repeat center;
background-size: cover;
}
.colour-text {
color: white;
}
.card-header::v-deep .el-card__header {
border-bottom: none !important;
}
.el-card {
border-color: rgba(5, 2, 53, 0.87); /* 深蓝色透明边框 */
background-color: rgba(5, 2, 53, 0.87); /* 深蓝色透明背景 */
}
.log-item {
padding: 5px 0;
border-bottom: 1px solid #ebeef5;
@ -487,6 +507,29 @@ onUnmounted(() => {
}
.mb-20px {
margin-bottom: 20px;
margin-bottom: 30px;
}
.box-card {
margin-bottom: 20px;
}
.box-card ::v-deep .el-card__header {
border-bottom: none !important;
}
.box-card ::v-deep .el-card__body {
background-color: #070225;
color: #7d6ea3ee; /* 接近黑色*/
}
.white-text-icon, .el-icon {
color: white !important;
}
/*.box-card { box-shadow: 0 0 10px rgba(0, 0, 255, 0.5); } */
.box-card { border-radius: 10px; } /* 加圆角*/
</style>

@ -70,6 +70,7 @@ import * as authUtil from '@/utils/auth'
import { usePermissionStore } from '@/store/modules/permission'
import * as LoginApi from '@/api/login'
import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
import { count } from 'console'
defineOptions({ name: 'LoginForm' })
@ -107,14 +108,15 @@ const loginData = reactive({
//
const getCode = async () => {
//
if (loginData.captchaEnable === 'false') {
await handleLogin({})
} else {
//
//
verify.value.show()
}
await handleLogin({})
// //
// if (loginData.captchaEnable === 'false') {
// } else {
// //
// //
// verify.value.show()
// }
}
//
const getLoginFormCache = () => {
@ -160,12 +162,16 @@ const handleLogin = async (params) => {
// SSO
if (redirect.value.indexOf('sso') !== -1) {
console.log('SSO登录');
window.location.href = window.location.href.replace('/login?redirect=', '')
} else {
console.log(redirect.value);
console.log(permissionStore.addRouters[0].path);
console.log('普通登录');
// console.log(redirect.value);
// console.log(permissionStore.addRouters[0].path);
push({ path: redirect.value || permissionStore.addRouters[0].path })
// push({ path: redirect.value})

@ -56,7 +56,9 @@
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import {getTypeList} from '@/api/system/dict/dict.data'
import { CameraApi, CameraVO } from '@/api/logistics/camera'
import { number } from 'vue-types'
/** 相机 表单 */
defineOptions({ name: 'CameraForm' })
@ -68,7 +70,20 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
const formData = ref<{
id?: number
name?: string
type?: number
ip?: string
port?: number
user?: string
password?: string
rtcServer?: string
rtcServerPort?: number
rtspPort?: number // number | undefined
channel?: string
recorderIp?: string
}>({
id: undefined,
name: undefined,
type: undefined,
@ -78,7 +93,7 @@ const formData = ref({
password: undefined,
rtcServer: undefined,
rtcServerPort: undefined,
rtspPort: undefined,
rtspPort: undefined, // undefined number
channel: undefined,
recorderIp: undefined,
})
@ -100,6 +115,29 @@ const open = async (type: string, id?: number) => {
} finally {
formLoading.value = false
}
}else{
const cameraConf = await getTypeList(DICT_TYPE.CAMERA_CONF)
for(let i = 0; i < cameraConf.length; i++){
if(cameraConf[i].label == 'camera_password'){
formData.value.password = cameraConf[i].value
}else if(cameraConf[i].label == 'camera_type'){
formData.value.type = Number(cameraConf[i].value)
}else if(cameraConf[i].label == 'camera_user'){
formData.value.user = cameraConf[i].value
}else if(cameraConf[i].label == 'camera_port'){
formData.value.port = cameraConf[i].value
}else if(cameraConf[i].label == 'rtc_server_ip'){
formData.value.rtcServer = cameraConf[i].value
}else if(cameraConf[i].label == 'rtc_server_port'){
formData.value.rtcServerPort = cameraConf[i].value
}else if(cameraConf[i].label == 'rtsp_port'){
formData.value.rtspPort = cameraConf[i].value
}else if(cameraConf[i].label == 'camera_cannel'){
formData.value.channel = cameraConf[i].value
}
}
console.log(cameraConf);
}
}
defineExpose({ open }) // open

@ -108,6 +108,17 @@ const addRouters = (id: number) => {
getList()
}
// cameraId
watch(
() => props.cameraId,
(newVal, oldVal) => {
if (newVal !== oldVal) {
formData.value.cameraId = newVal // formData cameraId
getList() //
}
}
)
//
const showModelDel = async (id: number) => {
try {
@ -131,6 +142,9 @@ onMounted(() => {
onUnmounted(() => {
//
console.log('组件销毁时执行清理逻辑');
list.value = [] //
})
</script>

@ -11,7 +11,7 @@
highlight-current
class="camera-tree"
/>
<ptz :cameraId="cameraId" />
<ptz v-if="cameraId" :cameraId="cameraId" />
</el-col>
<el-col :span="19">
<div class="container">
@ -25,7 +25,7 @@
<el-button type="primary" @click="updateTopNum(3)">
<Icon :size="20" icon="fa-solid:th"
/></el-button>
</el-button-group>
</el-button-group>
</div>
<el-row v-for="rowIndex in topNum" :key="rowIndex">
@ -38,8 +38,9 @@
@click="clickCameraFun((rowIndex-1)*topNum +colIndex)"
>
<div v-if="((rowIndex-1)*topNum +colIndex)==cameraIndex" class="floating-text"><Icon :size="15" icon="ep:circle-close"
/></div>
<div v-if="((rowIndex-1)*topNum +colIndex)==cameraIndex" class="floating-text">
<Icon :size="15" icon="ep:circle-close" @click="deleteCameraFun((rowIndex-1)*topNum +colIndex)"/>
</div>
<Camera v-if="getCameraId((rowIndex - 1) * topNum + colIndex)!== 0"
:cameraId="getCameraId((rowIndex-1)*topNum +colIndex)" :ptzShow="false" />
@ -80,6 +81,15 @@ const getTree = async () => {
}
}
const selectedNodeId = ref<string | null>(null)
//
const deleteCameraFun = (index)=>{
console.log("删除摄像头 index:",index );
clickCamera.value = true
CameraMap.value?.delete(index)
cameraIndex.value = index
cameraId.value = null
}
//
const clickCameraFun = (index)=>{
@ -97,6 +107,7 @@ const handleNodeClick = (data: any) => {
if (data.id != null) {
//
if(clickCamera.value){
deleteCameraFun(cameraIndex.value)
CameraMap.value?.set(cameraIndex.value, data.id)
}else{
// cameraId

@ -193,6 +193,16 @@
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="success"
@click="getDialogVisible(scope.row.streetName,scope.row.direction,scope.row.row, scope.row.column,scope.row.id)"
v-hasPermi="['logistics:check-log:success']"
>
操作
</el-button>
<el-button
link
type="danger"

@ -139,10 +139,11 @@
<space >{{ scope.row.srmNumber+"-"+ (scope.row.toDirection?"左侧-":"右侧-")+ scope.row.toRow+'层-'+scope.row.toColumn+'列' }}</space>
</template>
</el-table-column>
<el-table-column label="图片" align="center" prop="pics" >
<el-table-column label="图片" align="center" prop="pics" min-width="150">
<template #default="scope">
<div v-if="scope.row.pics">
<div v-if="scope.row.pics" class="image-cell-container">
<el-image
v-for="(pic, index) in scope.row.pics.split(';')"
:key="index"
@ -152,6 +153,7 @@
:initial-index="0"
:preview-teleported="true"
fit="cover"
:disabled="true"
/>
</div>
<div v-else>
@ -162,10 +164,11 @@
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
v-if="scope.row.videoPath1!=null"
v-if="scope.row.videoPath1 && scope.row.videoPath1.trim() !== '' &&
scope.row.videoPath2 && scope.row.videoPath2.trim() !== ''"
link
type="primary"
@click="videoPlay(scope.row.videoPath2,scope.row.videoPath2)"
@click="videoPlay(scope.row.videoPath1,scope.row.videoPath2)"
v-hasPermi="['logistics:order:delete']"
>
视频
@ -190,28 +193,17 @@
@pagination="getList"
/>
<el-dialog
v-model="dialogVisible"
title="视频"
width="500"
>
<video ref="videoPlayer" width="100%" controls autoplay muted>
<source :src="video1Src" type="video/mp4" />
您的浏览器不支持 video 标签
</video>
<video ref="videoPlayer" width="100%" controls autoplay muted>
<source :src="video2Src" type="video/mp4" />
您的浏览器不支持 video 标签
</video>
<!--
<video muted autoplay="true" >
<source
:src="video2Src.value"
type="video/mp4"
>
</video> -->
</el-dialog>
<el-dialog v-model="dialogVisible" title="视频" width="500">
<video ref="videoPlayer1" width="100%" controls autoplay muted>
<source :src="video1Src" type="video/mp4" />
您的浏览器不支持 video 标签
</video>
<video ref="videoPlayer2" width="100%" controls autoplay muted>
<source :src="video2Src" type="video/mp4" />
您的浏览器不支持 video 标签
</video>
</el-dialog>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
@ -266,13 +258,29 @@ const exportLoading = ref(false) // 导出的加载中
const video1Src = ref("") //
const video2Src = ref("") //
const videoPlay = ((video1,video2) =>{
console.log(video1,video2);
dialogVisible.value = true
video1Src.value = video1
video2Src.value = video2
})
const videoPlayer1 = ref<HTMLVideoElement | null>(null)
const videoPlayer2 = ref<HTMLVideoElement | null>(null)
const videoPlay = (video1: string, video2: string) => {
//
dialogVisible.value = false
nextTick(() => {
dialogVisible.value = true
//
video1Src.value = video1
video2Src.value = video2
// DOM load()
nextTick(() => {
if (videoPlayer1.value) {
videoPlayer1.value.load()
}
if (videoPlayer2.value) {
videoPlayer2.value.load()
}
})
})
}
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -354,4 +362,20 @@ onMounted(() => {
getList()
getStringList()
})
</script>
</script>
<style scoped>
.image-cell-container {
display: flex;
overflow-x: auto;
white-space: nowrap;
}
.image-cell-container::-webkit-scrollbar {
height: 6px;
}
.image-cell-container::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 3px;
}
</style>

@ -14,6 +14,7 @@
placeholder="请选择巷道"
clearable
@keyup.enter="handleQuery"
@change="handleQuery"
class="!w-240px"
>
<el-option
@ -29,6 +30,7 @@
v-model="queryParams.direction"
clearable
@keyup.enter="handleQuery"
@change="handleQuery"
class="!w-240px"
>
<el-option
@ -40,7 +42,14 @@
</el-select>
</el-form-item>
<el-form-item ><el-button @click="handleQuery" type="primary">搜索</el-button></el-form-item>
<!-- <el-form-item ><el-button @click="handleQuery" type="primary">搜索</el-button></el-form-item> -->
<el-form-item >
<el-button
v-for="(button, index) in colorList"
:type="colorList[index]"
:key="index">{{statusList[index]}}</el-button>
</el-form-item>
</el-form>
</ContentWrap>
@ -144,6 +153,9 @@ import Cookies from 'js-cookie';
const message = useMessage() //
const { t } = useI18n() // ist
const statusList = ['未盘点', '盘点异常', '盘点正确', '人工盘点正常'];
const colorList = ['warning', 'danger', 'success', 'success'];
const colorListHex = {'未盘点':'#ebc26e','盘点异常':'#ed6d6d','盘点正确':'#6cc238','人工盘点正常':'#b1c238'};
let rows = ref(12);
let columns = ref(48);
//
@ -230,12 +242,20 @@ const saveQueryParamsToCookie = () => {
/** 搜索按钮操作 */
const handleQuery = async () => {
columnMap.value = []
const data = await StockApi.getStreetList(queryParams)
saveQueryParamsToCookie()
getStreetStatus()
if(queryParams.streetId == null ||queryParams.streetId ==undefined){
queryParams.streetId = 0
}
if(queryParams.direction == null ||queryParams.direction ==undefined){
queryParams.direction = 0
}
const data = await StockApi.getStreetList(queryParams)
buttons.value = data.buttons
rows = ref(data.rows)
columns =ref(data.columns)
saveQueryParamsToCookie()
getStreetStatus()
const page = columns.value/columnMax.value
for(var i = 0; i <= page; i++){
@ -365,7 +385,7 @@ const option = reactive({
trigger: 'item'
},
legend: {
top: '5%',
top: '5%',
left: 'center'
},
series: [
@ -376,7 +396,14 @@ const option = reactive({
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
borderWidth: 2,
color: function (params) {
console.log(params.name);
// var status = buttonByStatusMap.value.get(params.name);
// 使 params.dataIndex
return colorListHex[params.name];
}
},
label: {
show: false,
@ -392,13 +419,12 @@ const option = reactive({
labelLine: {
show: false
}, //
normal: {
color: function(params) {
// params.name
const colorList = ['#87cefa', '#da70d6', '#32cd32', '#ff6347'];
return colorList[params.dataIndex]; // index
}
},
// normal: {
// color: function(params) {
// // params.name
// return colorList[params.dataIndex]; // index
// }
// },
data: echartData()
}
]

@ -34,6 +34,9 @@
</div>
</div>
</div>
<div class="mt-4">
<el-button type="success" size="20" style="width: 50%;" @click="artificial()" >人工盘点</el-button>
</div>
</div>
</div>
<!-- </div>
@ -43,7 +46,7 @@
<script>
import { ref, onMounted } from 'vue';
import { StockApi } from '@/api/logistics/stock';
import { ElMessage } from 'element-plus'
export default {
props: {
stockId: {
@ -63,8 +66,9 @@ export default {
const stockInfo = ref([]);
const showEnlarged = ref(false);
const enlargedImageUrl = ref('');
const resStatus = ref(true);
//
//
const fetchStockInfo = async () => {
try {
const response = await StockApi.getStockStatus({
@ -72,6 +76,8 @@ export default {
checkLogId: props.checkLogId
});
let statusString = "盘点正确";
resStatus.value = response.status ==="2" || response.status ==="3" || response.status ===2 || response.status ===3;
console.log(resStatus);
const scanData = response.scan || [];
//
// const hasInconsistent = scanData.some(item =>
@ -147,6 +153,14 @@ export default {
enlargedImageUrl.value = url;
showEnlarged.value = true;
};
const artificial = async () => {
const response = await StockApi.artificial({
stockId: props.stockId,
checkLogId: props.checkLogId
});
resStatus.value = true;
ElMessage.status('人工识别成功')
};
const closeBoxCard = () => {
emit('close-box-card');
@ -158,6 +172,7 @@ export default {
stockInfo,
showEnlarged,
enlargedImageUrl,
artificial,
showEnlargedImage,
closeBoxCard
};

@ -23,6 +23,21 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="类型" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.type`" :rules="formRules.type" class="mb-0px!">
<el-select v-model="row.type" placeholder="请选择类型">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SCANGUN_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="ip" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.ip`" :rules="formRules.ip" class="mb-0px!">
@ -60,7 +75,6 @@ const formData = ref([])
const formRules = reactive({
})
const formRef = ref() // Ref
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.streetId,
@ -87,6 +101,7 @@ const handleAdd = () => {
id: undefined,
streetId: undefined,
direction: undefined,
type: undefined,
ip: undefined,
port: undefined,
}

Loading…
Cancel
Save