Compare commits

...

53 Commits

Author SHA1 Message Date
LAPTOP-S9HJSOEB\昊天 960ca2c322 使用zlm作为新的流服务器 2 years ago
yiming 7c8cb04802 库区设置 3 years ago
yiming 06d7eb0bff 巷道球机选择 3 years ago
yiming 2550475eb0 md修改 图片 3 years ago
yiming 46dba190f2 基础版修正 3 years ago
yiming a2e5281780 盘点图片 3 years ago
yiming 1de3950a23 盘点管理去掉货架号 4 years ago
yiming c0f69dde93 去掉货架号 4 years ago
wang.yiming 65d123c406 Merge branch 'liuzhou-yancao' into 'master'
Liuzhou yancao

See merge request duoji/duoji-frontend!3
4 years ago
qiushui ba5ce7492a 柳州烟草 4 years ago
yiming 738882cd08 每个巷道的光源单独可开关 4 years ago
yiming fd57ca6dd5 球机转动的问题 4 years ago
yiming 1cc53e254d 球机预制点配置 4 years ago
yiming 4113c831d7 球机调试 4 years ago
yiming f2791d53db 删除货物条码 4 years ago
yiming 8245eb379f 到处全部盘点 4 years ago
yiming c44fa4ea64 导出盘点数据 4 years ago
yiming 5c9c2b57fb 盘点历史 4 years ago
yiming 576e9d0cda 增加球机的连接状态 4 years ago
yiming b96a17149c 菜单图片 4 years ago
yiming 270521f552 增加库存历史照片 4 years ago
yiming 7408c87193 盘点操作去掉选择 4 years ago
yiming 8e7773b222 盘点缓存 4 years ago
yiming 0048c3d1e2 盘点历史批次号 4 years ago
yiming 4c04774d5d 增加显示盘点批次号 4 years ago
yiming 36f5c24e00 盘点界面航道选择的bug 4 years ago
yiming bfb09d1a6e 盘点行列tab的显示bug 4 years ago
yiming cb38466400 行列号只允许输入数字 4 years ago
yiming 18cabf2ebd 盘点历史 图片选中放大 4 years ago
yiming dd0f85c81c 盘点历史界面 4 years ago
yiming c1d3065ba0 盘点界面,行号排列修改 4 years ago
yiming 4fd6b21329 修复盘点页面不刷新的问题 4 years ago
yiming 0af7ffa8e8 Merge branch 'master' of https://gitlab.hzleaper.com:81/duoji/duoji-frontend 4 years ago
yiming 934a3a35ae 修复切换页面,盘点接口让然请求的问题 4 years ago
yiming 35840fc12e 盘点界面巷道长度 4 years ago
yiming 3797af24da Merge branch 'master' of https://gitlab.hzleaper.com:81/duoji/duoji-frontend 4 years ago
yiming 19e7291eb1 增加RFID配置 4 years ago
Your Name b741bcd3de w
Merge branch 'master' of https://gitlab.hzleaper.com:81/duoji/duoji-frontend
4 years ago
Your Name 6b3cf9fa77 color 4 years ago
yiming 4f09b64b4c 增加扫码枪配置 4 years ago
yiming 575d95545d 实时视频流操作 4 years ago
Your Name 9bef504cb7 盘点问题 4 years ago
Your Name 660de42bdc 盘点行列的bug 4 years ago
yiming 23f9c4e514 删除视频流服务器接口 4 years ago
yiming 6dc6e3d7d4 视频流多服务器配置 4 years ago
yiming 14a5bd738c 一键生成视频流配置文件 4 years ago
yiming a5072f4d6a 巷道增加光源配置 4 years ago
yiming 573c303157 重复播放 4 years ago
wang.yiming 2d7e36eef6 Merge branch 'feature/light-source' into 'master'
增加光源控制

See merge request duoji/duoji-frontend!2
4 years ago
yiming 2c89634ad4 增加光源控制 4 years ago
wang a98d220aec Merge branch 'dev' into 'master'
历史数据翻页bug

See merge request duoji/duoji-frontend!1
4 years ago
yiming d878bf6dc7 历史数据翻页bug 4 years ago
qiushui 03beee4a1d 视频墙 4 years ago

@ -28,7 +28,7 @@ See [Configuration Reference](https://cli.vuejs.org/config/).
#### 1、项目git地址https://gitlab.hzleaper.com:81/duoji/duoji-frontend.git
#### 2、简介
垛机监控系统是一款TOB的项目由哲合科技有限公司承担研发主要为甲方在仓储方面的出入库过程中提供拍照取证实时录像盘点管理等功能。项目主要涵盖实时视频流、历史数据、盘点管理、巷道管理、球机管理、个人中心等。基于vue-cli3.x + Ant Design Vue搭建,rtsp视频流采用VLC插件结合Firefox火狐浏览器运行的方式播放因VLC支持性问题需回退Firefox火狐浏览器版本至51版之前详情请见 [VLC开发文档](https://wiki.videolan.org/Documentation:WebPlugin/#Introduction:_Building_Web_pages_with_Video)
出入库过程中提供拍照取证实时录像盘点管理等功能。项目主要涵盖实时视频流、历史数据、盘点管理、巷道管理、球机管理、个人中心等。基于vue-cli3.x + Ant Design Vue搭建,rtsp视频流采用VLC插件结合Firefox火狐浏览器运行的方式播放因VLC支持性问题需回退Firefox火狐浏览器版本至51版之前详情请见 [VLC开发文档](https://wiki.videolan.org/Documentation:WebPlugin/#Introduction:_Building_Web_pages_with_Video)
#### 3、测试环境地址

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -4,7 +4,7 @@ server {
client_max_body_size 90m;
location /api {
proxy_pass http://localhost:8099/api;
proxy_pass http://192.168.77.91:8099/api;
}
location /{

5
package-lock.json generated

@ -3714,6 +3714,11 @@
"hoek": "2.x.x"
}
},
"bootstrap": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz",
"integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",

@ -12,6 +12,7 @@
"ant-design-vue": "^1.6.3",
"antd-theme-generator": "^1.2.8",
"axios": "^0.19.2",
"bootstrap": "^5.1.3",
"core-js": "^3.6.5",
"element-ui": "^2.15.6",
"path-to-regexp": "^6.2.0",

@ -7,16 +7,16 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- 加快视频的响应速度-->
<link href="/video_play_plugins/video-js-cdn.min.css" rel="stylesheet">
<script src="/video_play_plugins/video.js"></script>
<script src="/video_play_plugins/videojs-contrib-hls.min.js"></script>
<script src="/video_play_plugins/videojs-contrib-hls.min.js"></script>
<title>垛机视觉系统</title>
<!-- <script src="/video_play_plugins/video.js"></script> -->
<script src="/video_play_plugins/webrtcplayer.js"></script>
<script src="webrtc/ZLMRTCClient.js"></script>
<title>垛机视觉系统</title>
</head>
<body>
<noscript>
<strong>We're sorry but 垛机视觉系统 doesn't work properly without JavaScript enabled. Please enable it to
<strong>We're sorry but 垛机视觉系统 doesn't work properly without JavaScript enabled. Please enable it to
continue.</strong>
</noscript>

@ -0,0 +1,120 @@
class WebRtcPlayer {
webrtc = null;
video = null;
server = null;
codecLink = null;
rsdpLink = null;
stream = new MediaStream();
uuid = null;
options={
onStatusChange:null
};
constructor(server,video1, uuid, options={}) {
console.log("new uuid:"+uuid)
this.server = server;
//this.video = document.getElementById(id);
this.video = video1
this.uuid = uuid;
Object.assign(this.options, options);
this.createLinks();
this.play();
}
createLinks() {
this.codecLink = "//" + this.server + "/stream/codec/" + this.uuid
this.rsdpLink = "//" + this.server + "/stream/receiver/" + this.uuid
}
play() {
this.webrtc = new RTCPeerConnection({
iceServers: [{
urls: ["stun:stun.l.google.com:19302"]
}]
});
if(this.webrtc){
}else{
console.log("no")
}
this.webrtc.onnegotiationneeded = this.handleNegotiationNeeded.bind(this);
this.webrtc.ontrack = this.onTrack.bind(this);
fetch(this.codecLink)
.then((response) => {
response.json().then((data) => {
data.forEach((item, i) => {
this.webrtc.addTransceiver(item.Type, {
'direction': 'sendrecv'
});
});
});
})
.catch((error) => {
console.log(error);
});
this.webrtc.onconnectionstatechange = () => {
if(this.webrtc.connectionState == 'connected' || this.webrtc.connectionState == 'connecting'){
console.log("uuid:"+this.uuid+" status:" + this.webrtc.connectionState)
}else{
console.log(this.webrtc.connectionState)
this.load(this.uuid);
}
}
}
async handleNegotiationNeeded() {
let offer = await this.webrtc.createOffer();
await this.webrtc.setLocalDescription(offer);
let formData = new FormData();
formData.append('suuid', this.uuid);
formData.append('data', btoa(this.webrtc.localDescription.sdp));
fetch(this.rsdpLink, {
method: 'POST',
body: formData
})
.then((response) => {
response.text().then((data) => {
this.webrtc.setRemoteDescription(new RTCSessionDescription({
type: 'answer',
sdp: atob(data)
}))
});
})
.catch((err) => {})
}
onTrack(event) {
this.stream.addTrack(event.track);
this.video.srcObject = this.stream;
this.video.play();
}
load(uuid) {
this.destroy();
this.uuid = uuid;
this.createLinks();
this.play();
}
destroy() {
console.log("destroy uuid:"+this.uuid)
this.webrtc.close();
this.webrtc = null;
this.video.srcObject = null;
this.stream = new MediaStream();
}
getImageUrl() {
let canvas = document.createElement("canvas");
canvas.width = this.video.videoWidth;
canvas.height = this.video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
let dataURL = canvas.toDataURL();
canvas.remove();
return dataURL;
}
}
export default WebRtcPlayer;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

@ -1,12 +0,0 @@
{
"program": {
"portable": {
"pnacl-translate": {
"url": "media_player.pexe"
},
"pnacl-debug": {
"url": "media_player_unstripped.bc"
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -0,0 +1,336 @@
<html>
<meta charset="utf-8">
<head>
<title>ZLM RTC demo</title>
<script src="./ZLMRTCClient.js"></script>
</head>
<body>
<div style="text-align: center;">
<div>
<video id='video' controls autoplay style="text-align:left;">
Your browser is too old which doesn't support HTML5 video.
</video>
<video id='selfVideo' controls autoplay style="text-align:right;">
Your browser is too old which doesn't support HTML5 video.
</video>
</div>
<div style="float: left; width:30%;">
<span>已存在的流列表,点击自动播放:</span>
<ol id="olstreamlist">
<li>初始演示</li>
<li>每秒自动刷新</li>
</ol>
</div>
<div style="float: right; width: 70%">
<p>
<label for="streamUrl">url:</label>
<input type="text" style="co; width:70%" id='streamUrl' value="http://192.168.1.101/index/api/webrtc?app=live&stream=xiong&type=play">
</p>
<p>
<label for="simulcast">simulcast:</label>
<input type="checkbox" id='simulcast'>
</p>
<p>
<label for="useCamera">useCamera:</label>
<input type="checkbox" id='useCamera' checked="checked">
</p>
<p>
<label for="audioEnable">audioEnable:</label>
<input type="checkbox" id='audioEnable' checked="checked">
</p>
<p>
<label for="videoEnable">videoEnable:</label>
<input type="checkbox" id='videoEnable' checked="checked">
</p>
<p>
<label for="method">method(play or push or echo):</label>
<input type="radio" name="method" value="echo" >echo
<input type="radio" name="method" value="push" >push
<input type="radio" name="method" value="play" checked = true>play
</p>
<p>
<label for="resolution">resolution:</label>
<select id="resolution">
</select>
</p>
<p>
<label for="datachannel">datachannel:</label>
<input id='datachannel' name="datachannel" type="checkbox" value="0">
</p>
<button onclick="start()">开始(start)</button>
<button onclick="stop()">停止(stop)</button>
<p>
<label for="msgsend">msgsend:</label>
<input type="text" id='msgsend' value="hello word !">
</p>
<p>
<label for="msgrecv">msgrecv:</label>
<input type="text" id='msgrecv' disabled>
</p>
<button onclick="send()">发送(send by datachannel)</button>
<button onclick="close()">关闭(close datachannel)</button>
</div>
</div>
<script>
var player = null;
var recvOnly = true;
var resArr = [];
var ishttps = 'https:' == document.location.protocol ? true : false;
var isLocal = "file:" == document.location.protocol ? true : false;
const searchParams = new URL(document.location.href).searchParams;
let type = searchParams.get('type');
if (!['echo','push','play'].includes(type)) {
type = 'play';
}
recvOnly = type === 'play';
const apiPath = `/index/api/webrtc?app=${searchParams.get('app') ?? 'live'}&stream=${searchParams.get('stream') ?? 'test'}&type=${type}`;
if(!ishttps && !isLocal){
alert('本demo需要在https的网站访问 ,如果你要推流的话(this demo must access in site of https if you want push stream)');
}
const apiHost = isLocal ? "http://127.0.0.1" : `${document.location.protocol}//${window.location.host}`;
var url = apiHost + apiPath;
document.getElementById('streamUrl').value = url;
document.getElementsByName("method").forEach((el,idx) => {
el.checked = el.value === type;
el.onclick = function(e) {
let url = new URL(document.getElementById('streamUrl').value);
url.searchParams.set("type",el.value);
document.getElementById('streamUrl').value = url.toString();
if(el.value == "play"){
recvOnly = true;
}else if(el.value == "echo"){
recvOnly = false;
}else{
recvOnly = false;
}
};
});
ZLMRTCClient.GetAllScanResolution().forEach((r,i) => {
opt = document.createElement('option');
opt.text = `${r.label}(${r.width}x${r.height})`;
opt.value = r;
if (1080*720 <= r.width * r.height && r.width * r.height <= 1280*720) {
opt.selected = true;
}
document.getElementById("resolution").add(opt,null);
});
function start_play(){
let elr = document.getElementById("resolution");
let res = elr.options[elr.selectedIndex].text.match(/\d+/g);
let h = parseInt(res.pop());
let w = parseInt(res.pop());
player = new ZLMRTCClient.Endpoint(
{
element: document.getElementById('video'),// video 标签
debug: true,// 是否打印日志
zlmsdpUrl:document.getElementById('streamUrl').value,//流地址
simulcast:document.getElementById('simulcast').checked,
useCamera:document.getElementById('useCamera').checked,
audioEnable:document.getElementById('audioEnable').checked,
videoEnable:document.getElementById('videoEnable').checked,
recvOnly:recvOnly,
resolution:{w:w,h:h},
usedatachannel:document.getElementById('datachannel').checked,
}
);
player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,function(e)
{// ICE 协商出错
console.log('ICE 协商出错');
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,function(e)
{//获取到了远端流,可以播放
console.log('播放成功',e.streams);
});
player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,function(e)
{// offer anwser 交换失败
console.log('offer anwser 交换失败',e);
stop();
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,function(s)
{// 获取到了本地流
document.getElementById('selfVideo').srcObject=s;
document.getElementById('selfVideo').muted = true;
//console.log('offer anwser 交换失败',e)
});
player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED,function(s)
{// 获取本地流失败
console.log('获取本地流失败');
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE,function(state)
{// RTC 状态变化 ,详情参考 https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionState
console.log('当前状态==>',state);
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN,function(event)
{
console.log('rtc datachannel 打开 :',event);
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG,function(event)
{
console.log('rtc datachannel 消息 :',event.data);
document.getElementById('msgrecv').value = event.data;
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR,function(event)
{
console.log('rtc datachannel 错误 :',event);
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE,function(event)
{
console.log('rtc datachannel 关闭 :',event);
});
}
function start()
{
stop();
let elr = document.getElementById("resolution");
let res = elr.options[elr.selectedIndex].text.match(/\d+/g);
let h = parseInt(res.pop());
let w = parseInt(res.pop());
if(document.getElementById('useCamera').checked && !recvOnly)
{
ZLMRTCClient.isSupportResolution(w,h).then(e=>{
start_play();
}).catch(e=>{
alert("not support resolution");
});
}else{
start_play();
}
}
function stop()
{
if(player)
{
player.close();
player = null;
var remote = document.getElementById('video');
if(remote)
{
remote.srcObject = null;
remote.load();
}
var local = document.getElementById('selfVideo');
local.srcObject = null;
local.load();
}
}
function send(){
if(player){
//send msg refernece https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/send
player.sendMsg(document.getElementById('msgsend').value);
}
}
function close(){
if(player){
player.closeDataChannel();
}
}
function on_click_to_play(app, stream) {
console.log(`on_click_to_play: ${app}/${stream}`);
var url = `${document.location.protocol}//${window.location.host}/index/api/webrtc?app=${app}&stream=${stream}&type=play`;
document.getElementById('streamUrl').value = url;
start();
}
function clearStreamList() {
let content = document.getElementById("olstreamlist");
while (content.hasChildNodes()) {
content.removeChild(content.firstChild);
}
}
function fillStreamList(json) {
clearStreamList();
if (json.code != 0 || !json.data) {
return;
}
let ss = {};
for (let o of json.data) {
if (ss[o.app]) {
ss[o.app].add(o.stream);
} else {
let set = new Set();
set.add(o.stream);
ss[o.app] = set;
}
}
for (let o in ss) {
let app = o;
for (let s of ss[o]) {
if (s) {
//console.log(app, s);
let content = document.getElementById("olstreamlist");
let child = `<li app="${app}" stream="${s}" onmouseover="this.style.color='blue';" onclick="on_click_to_play('${app}', '${s}')">${app}/${s}</li>`;
content.insertAdjacentHTML("beforeend", child);
}
}
}
}
async function getData(url) {
const response = await fetch(url, {
method: 'GET'
});
const data = await response.json();
//console.log(data);
return data;
}
function get_media_list() {
let url = document.location.protocol+"//"+window.location.host+"/index/api/getMediaList?secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc";
let json = getData(url);
json.then((json)=> fillStreamList(json));
}
setInterval(() => {
// get_media_list();
}, 5000);
</script>
</body>
<script>
</script>
</html>

@ -0,0 +1,2 @@
感谢[big panda](<2381267071@qq.com>) 开发并贡献此webrtc js测试客户端,
其开源项目地址为https://gitee.com/xiongguangjie/zlmrtcclient.js

@ -0,0 +1,138 @@
<template>
<!-- webrtc播放器 -->
<video :id="videoId"
ref="jswebrtc"
:controls="controls"
style="width: 100%; height: 100%;margin: 5px;"
muted></video>
</template>
<script>
export default {
name: 'webrtcPlayer',
props: {
videoId: {
type: String,
default: 'jswebrtc'
},
videoSrc: {
type: String,
default: ''
},
controls: {
type: Boolean,
default: true
}
},
data () {
return {
player: null
}
},
mounted () {
this.$watch('videoSrc', () => {
//console.log('videoSrc', this.videoSrc)
if (this.videoSrc) {
this.initVideo(this.videoSrc);
} else {
this.stop()
}
}, { immediate: true, deep: true })
},
methods: {
initVideo (url) {
// console.log('', this.player)
//
if (this.player) {
this.player.pc.close()
this.player = null;
}
let videoDom = document.getElementById(this.videoId);
this.player = new ZLMRTCClient.Endpoint({
element: videoDom, // video
debug: true, //
zlmsdpUrl: url, //
simulcast: true,
useCamera: true,
audioEnable: true,
videoEnable: true,
recvOnly: true,
resolution: {
w: 600,
h: 340
},
usedatachannel: true,
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, function (e) { // ICE
console.log('ICE 协商出错')
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, function (e) { //
console.log('播放成功', e.streams)
videoDom.addEventListener('canplay', function (e) {
videoDom.play();
})
});
this.player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, function (e) { // offer anwser
console.log('offer anwser 交换失败', e)
// this.player.destroy();
// this.player = null;
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, function (s) { //
console.log('offer anwser 交换失败', e)
});
this.player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, function (s) { //
console.log('获取本地流失败')
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, function (
state
) { // RTC , https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionState
console.log('当前状态==>', state)
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN, function (event) {
console.log('rtc datachannel 打开 :', event)
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG, function (event) {
console.log('rtc datachannel 消息 :', event.data)
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR, function (event) {
console.log('rtc datachannel 错误 :', event)
});
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE, function (event) {
console.log('rtc datachannel 关闭 :', event)
});
},
stop () {
let videoDom = document.getElementById(this.videoId);
videoDom.pause()
//
this.player.pc.close()
this.player = null
}
},
beforeDestroy () {
if (this.player) {
//
this.player.pc.close()
this.player = null;
}
}
}
</script>
<style>
</style>

@ -14,16 +14,22 @@ export default {
url: "/order/list",
name: "获取历史监控列表"
},
realTimeLychee: {
method: "GET",
url: "/realTime/lychee",
name: "获取荔枝的ip"
},
getStreetList: {
method: "POST",
url: "/street/page",
name: "获取巷道列表"
},
getAllStreet: {
method: "GET",
url: "/street/list",
name: "获取全部巷道列表"
},
cameraRecord: {
method: "POST",
url: "/cameraRecord/record",
name: "球机回放信息"
},
addStreet: {
method: "POST",
url: "/street",
@ -34,6 +40,21 @@ export default {
url: "/street",
name: "编辑巷道"
},
openLight:{
method: "GET",
url: "/street/lightSource/open",
name: "打开光源"
},
closeLight:{
method: "GET",
url: "/street/lightSource/close",
name: "关闭光源"
},
statusLight:{
method: "GET",
url: "/street/lightSource/status",
name: "获取光源状态"
},
// deleteStreet: {
// method: "DELETE",
// url: "/street",
@ -45,10 +66,25 @@ export default {
url: "/camera/page",
name: "获取球机列表"
},
getVideoServer:{
getAllCameras:{
method: "GET",
url: "/realTime/allCameras",
name: "获取全部球机"
},
allCamerasByArea:{
method: "GET",
url: "/realTime/videoServer",
name: "获取视频服务器"
url: "/realTime/allCamerasByArea",
name: "根据库区查询球机"
},
getAllAreas:{
method: "GET",
url: "/realTime/allAreas",
name: "获取全部库区"
},
getWallStyle:{
method: "GET",
url: "/realTime/wallStyle",
name: "获取视频墙样式"
},
addCamera: {
method: "POST",
@ -60,6 +96,11 @@ export default {
url: "/camera",
name: "编辑球机"
},
videoConfig:{
method: "GET",
url: "/camera/downloadConfig",
name: "直播流配置"
},
getChannel: {
method: "POST",
url: "/lychee/stream/push",
@ -142,6 +183,11 @@ export default {
name: '复核页面的核对信息',
method: 'POST'
},
getStockPage: {
url: '/stockLog',
name: '获取随性历史',
method: 'POST'
},
getStatusByRowColumn: {
url: '/stock/statusByRowColumn',
name: '行列的库存状态',
@ -149,6 +195,11 @@ export default {
},
exportStock: {
url: '/stock/export',
name: '导出单个巷道',
method: 'GET'
},
exportAllStock: {
url: '/stock/exportAll',
name: '导出所有巷道',
method: 'GET'
},
@ -162,6 +213,16 @@ export default {
name: '人工复核',
method: 'POST'
},
checkLog: {
url: '/checkLog',
name: '盘点历史',
method: 'POST'
},
stockLog: {
url: '/stockLog',
name: '库存历史',
method: 'POST'
},
getStockpage: {
url: '/stock/page',
name: '库存列表',

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

@ -92,7 +92,7 @@ export default {
recursionRoute(parents);
}else {
parents = this.$router.options.routes[0].children.filter(item => {
return !item.name.startsWith("center") && !item.name.startsWith("ioTable") && !item.name.startsWith("realTimeMonitoringModel") && !item.name.startsWith("plcStatus") && !item.name.startsWith("cameraManageModel") && !item.name.startsWith("checkOperation");
return !item.name.startsWith("center") && !item.name.startsWith("ioTable") && !item.name.startsWith("realTimeMonitoringModel") && !item.name.startsWith("plcStatus") && !item.name.startsWith("cameraManageModel") && !item.name.startsWith("checkOperation") && !item.name.startsWith("stockLog") ;
});
}
this.routes = parents;

@ -1,9 +1,10 @@
<template>
<div class="wrap">
<!-- 面包屑下标题 -->
<keep-alive>
<router-view :exclude="['checkManage']" class="table"></router-view>
</keep-alive>
<keep-alive include="checkManage" exclude="realTimeMonitoring,videoWall,cameraManage,cameraManageModel">
<router-view class="table" />
</keep-alive>
<!-- footer -->
<div class="wrap-footer bg-white">

@ -15,21 +15,10 @@
<a-badge :count="count" @click="openPlc">
<a-icon type="bell" style="font-size:20px;cursor:pointer"/>
</a-badge>
<a-popover id="popover" v-model="visible" placement="bottom" trigger="click">
<a href="javascript:;" style="margin:0 10px">
{{
userInfo.name ? userInfo.name : "userName"
}}
</a>
<div class="flex flex-column" :style="{ 'min-width': '78px' }" slot="content">
<a
class="block mb16"
href="javascript:;"
@click="visible = false;$router.push({name: 'center'})"
>个人中心</a>
<a href="javascript:;" @click="logout">退</a>
</div>
</a-popover>
<div style="width:20px"/>
<div >
<img width="120" :src="logo" alt/>
</div>
</div>
</div>
</template>
@ -56,7 +45,8 @@ export default {
visible: false,
collapsed: false,
count: 0,
title: ""
title: "",
logo:require('@/assets/indexlogo.png'),
};
},
mounted() {

@ -30,47 +30,39 @@ const routes = [{
component: () => import('@/views/index'),
children: [
{
path: 'realTimeMonitoring',
name: 'realTimeMonitoring',
path: 'videoWall',
name: 'videoWall',
meta: {
icon: 'desktop',
name: '实时视频流'
name: '视频墙'
},
component: () => import('@/views/realTimeMonitoring/index'),
component: () => import('@/views/videoWall/index'),
},
{
path: 'realTimeMonitoring/model',
name: 'realTimeMonitoringModel',
path: 'realTimeMonitoring',
name: 'realTimeMonitoring',
meta: {
name: '实时视频流(全屏)'
icon: 'video-camera',
name: '实时视频流'
},
component: () => import('@/views/realTimeMonitoring/model'),
component: () => import('@/views/realTimeMonitoring/index'),
},
{
path: 'historyMonitoring',
name: 'historyMonitoring',
meta: {
icon: 'line-chart',
icon: 'book',
name: '历史数据'
},
component: () => import('@/views/historyMonitoring/index')
},
// {
// path: 'alarmVideos',
// name: 'alarmVideos',
// meta: {
// icon: 'alert',
// name: '告警视频'
// },
// component: () => import('@/views/alarmVideos/index')
// },
{
path: 'alarmLog',
name: 'alarmLog',
meta: {
icon: 'exception',
icon: 'eye',
name: '告警日志'
},
component: () => import('@/views/alarmVideos/alarmLog')
@ -92,6 +84,41 @@ const routes = [{
},
component: () => import('@/views/checkManage/checkOperation'),
},
{
path: 'checkHistory',
name: 'checkHistory',
meta: {
icon: 'tag',
name: '盘点历史',
},
component: () => import('@/views/historyCheck/index'),
},
{
path: 'videoPlayback',
name: 'videoPlayback',
meta: {
icon: 'tag',
name: '记录回放',
},
component: () => import('@/views/videoPlayback/index'),
},
// {
// path: 'stockHistory',
// name: 'stockHistory',
// meta: {
// icon: 'file-excel',
// name: '库位历史',
// },
// component: () => import('@/views/stockLog/index'),
// },
// {
// path: 'stockLogDetail',
// name: 'stockLogDetail',
// meta: {
// name: '库位历史详情',
// },
// component: () => import('@/views/stockLog/logPage'),
// },
{
path: 'roadwayManage',
name: 'roadwayManage',
@ -105,7 +132,7 @@ const routes = [{
path: 'cameraManage',
name: 'cameraManage',
meta: {
icon: 'video-camera',
icon: 'camera',
name: '球机管理'
},
component: () => import('@/views/cameraManage/index')
@ -118,24 +145,25 @@ const routes = [{
},
component: () => import('@/views/cameraManage/model')
},
{
path: 'productSpecManage',
name: 'productSpecManage',
meta: {
icon: 'pushpin',
name: '品规管理'
},
component: () => import('@/views/productSpecManage/index')
},
{
path: 'repertoryManage',
name: 'repertoryManage',
meta: {
icon: 'wallet',
name: '库存管理'
},
component: () => import('@/views/repertoryManage/index')
},
// {
// path: 'productSpecManage',
// name: 'productSpecManage',
// meta: {
// icon: 'pushpin',
// name: '品规管理'
// },
// component: () => import('@/views/productSpecManage/index')
// },
// {
// path: 'repertoryManage',
// name: 'repertoryManage',
// meta: {
// icon: 'wallet',
// name: '库存管理'
// },
// component: () => import('@/views/repertoryManage/index')
// },
{
path: 'cameraManage/ioTable',
name: 'ioTable',

@ -11,7 +11,7 @@ const store = {
"primary-color":"rgba(184, 68, 13, 1)"
},
"title":{
"text":"昆船垛机视觉系统",
"text":"昆船垛机智能视觉系统",
"style":{
"color":"rgba(255, 255, 255, 1)",
"background-color":"rgba(163, 60, 12, 1)",

@ -143,6 +143,16 @@ export default {
document.body.removeChild(elink)
}
},
downloadFileUrl(fileName, fileUrl) {
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = fileUrl
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href) // 释放URL 对象
document.body.removeChild(elink)
},
/*
* 根据文件名的尾缀 返回文件类型
* @param {any} fileName 文件名

@ -7,6 +7,9 @@
<a-button type="primary" class="plc" @click="goIo">
PLC IO表配置
</a-button>
<a-button type="primary" class="add" @click="videoConfig">
视频流配置
</a-button>
</div>
<a-table
style="margin-top:40px"
@ -59,6 +62,14 @@ const columns = [
title: '球机IP',
dataIndex: 'ip',
},
{
title: '视频流IP',
dataIndex: 'rtcServer',
},
{
title: '连接状态',
dataIndex: 'status',
},
{
title: '修改时间',
dataIndex: 'updateTime',
@ -95,13 +106,13 @@ export default {
},
methods: {
handleGetCameraList(pagination) {
console.log(pagination)
if(pagination){
this.pagination.current = pagination.current;
this.pagination.pageSize = pagination.pageSize;
this.pageNum = pagination.current;
this.pageSize = pagination.pageSize;
}
this.request();
},
request(){
@ -161,7 +172,32 @@ export default {
},
goIo(){
this.$router.push({ name: "ioTable"});
}
},
videoConfig(){
const that = this
this.$confirm({
title: "生成全部视频流",
content: "确认生成全部视频流?",
okText: '确认',
onOk() {
return new Promise((resolve, reject) => {
that.downConfig();
setTimeout(resolve, 1000);
}).catch(() => console.log('Oops errors!'));
},
cancelText: '取消',
});
},
downConfig(){
this.$api.httpApi.videoConfig({
}).then(res => {
}).catch(err => {
});
},
},
components:{
Model
@ -179,5 +215,8 @@ export default {
.add{
margin-right: 20px;
}
.plc{
margin-right: 20px;
}
}
</style>

@ -25,6 +25,11 @@
v-decorator="['ip', { rules: [{ required: true, message: '请输入球机ip!' }] }]"
/>
</a-form-item>
<a-form-item label="视频流IP" :label-col="formItemVerticalLayout.labelCol">
<a-input
v-decorator="['rtcServer']"
/>
</a-form-item>
</a-form>
</a-modal>
</template>
@ -97,48 +102,55 @@
:centered="true"
class="config-model"
>
<video width="900"
<WebrtcPlayer
autoplay class="video-window"
:videoSrc="'http://127.0.0.1/index/api/webrtc?app=live&stream='+id+'&type=play'"
:videoId="'videoId'+colIndex+'-'+rowIndex"
ref="videoWindow"
:key="colIndex+'-'+rowIndex"
muted :style="{ width:'900px'}">
</WebrtcPlayer>
<!-- <video width="900"
height="600"
:id="`config-camera${id}`"
autoplay muted ></video>
autoplay muted ></video> -->
<div class="operation-list">
<div class="operation-item">
<img :src="zoomSubUrl" alt="" @mousedown="zoomDecStart"
@mouseup="zoomDecStop">
@mouseup="zoomDecStop" @mouseleave="zoomDecStop">
<span>变倍</span>
<img :src="zoomAddUrl" alt="" @mousedown="zoomAddStart"
@mouseup="zoomAddStop">
@mouseup="zoomAddStop" @mouseleave="zoomAddStop">
</div>
<div class="operation-item">
<img :src="focusSubUrl" alt="" @mousedown="focusDecStart"
@mouseup="focusDecStop">
@mouseup="focusDecStop" @mouseleave="focusDecStop">
<span>变焦</span>
<img :src="focusAddUrl" alt="" @mousedown="focusAddStart"
@mouseup="focusAddStop">
@mouseup="focusAddStop" @mouseleave="focusAddStop">
</div>
<div class="operation-item">
<img :src="irisSubUrl" alt="" @mousedown="irisDecStart" @mouseup="irisDecStop">
<img :src="irisSubUrl" alt="" @mousedown="irisDecStart" @mouseup="irisDecStop" @mouseleave="irisDecStop">
<span>光圈</span>
<img :src="irisAddUrl" alt="" @mousedown="irisAddStart" @mouseup="irisAddStop">
<img :src="irisAddUrl" alt="" @mousedown="irisAddStart" @mouseup="irisAddStop" @mouseleave="irisAddStop">
</div>
</div>
<div class="direction-list">
<div class="direction-item">
<img :src="leftUpUrl" alt="" @mousedown="leftUpStart" @mouseup="leftUpStop">
<img :src="upUrl" alt="" @mousedown="upStart" @mouseup="upStop">
<img :src="rightUpUrl" alt="" @mousedown="rightUpStart" @mouseup="rightUpStop">
<img :src="leftUpUrl" alt="" @mousedown="leftUpStart" @mouseup="leftUpStop" @mouseleave="leftUpStop">
<img :src="upUrl" alt="" @mousedown="upStart" @mouseup="upStop" @mouseleave="upStop">
<img :src="rightUpUrl" alt="" @mousedown="rightUpStart" @mouseup="rightUpStop" @mouseleave="rightUpStop">
</div>
<div class="direction-item">
<img :src="leftUrl" alt="" @mousedown="leftStart" @mouseup="leftStop">
<img :src="rightUrl" alt="" @mousedown="rightStart" @mouseup="rightStop">
<img :src="leftUrl" alt="" @mousedown="leftStart" @mouseup="leftStop" @mouseleave="leftStop">
<img :src="rightUrl" alt="" @mousedown="rightStart" @mouseup="rightStop" @mouseleave="rightStop">
</div>
<div class="direction-item">
<img :src="leftDownUrl" alt="" @mousedown="leftDownStart"
@mouseup="leftDownStop">
<img :src="downUrl" alt="" @mousedown="downStart" @mouseup="downStop">
@mouseup="leftDownStop" @mouseleave="leftDownStop">
<img :src="downUrl" alt="" @mousedown="downStart" @mouseup="downStop" @mouseleave="downStop">
<img :src="rightDownUrl" alt="" @mousedown="rightDownStart"
@mouseup="rightDownStop">
@mouseup="rightDownStop" @mouseleave="rightDownStop">
</div>
</div>
<div class="config-table">
@ -197,9 +209,12 @@ const columns = [
scopedSlots: { customRender: 'position' }
}
];
import WebRtcPlayer from "./webrtcplayer"
import WebrtcPlayer from '../../../public/webrtc/webrtcPlayer.vue'
//import WebRtcPlayer from "../../../public/static/webrtcplayer"
export default {
props:[ 'visible', 'modelType', 'modelData'],
components: {WebrtcPlayer},
watch: {
//visibleisShowprops
visible: function(newVal){
@ -220,15 +235,15 @@ export default {
this.form.setFieldsValue({ //setFieldsValue form
name:newVal.name,
ip:newVal.ip,
rtsp:newVal.rtsp
rtsp:newVal.rtsp,
rtcServer:newVal.rtcServer,
rtcServerPort:newVal.rtcServerPort
})
})
}else if (newVal.id && this.type=='config'){
this.id = newVal.id
this.mdata = newVal
console.log(newVal)
}
},
@ -266,8 +281,6 @@ export default {
};
},
mounted() {
this.setVideoServer()
if (this.$route.query.modelType == 'test') {
this.isShow = true
this.id = this.$route.query.modelData.id
@ -290,7 +303,10 @@ export default {
}
},
destroy(){
//this.player.destroy()
if(this.player != null){
this.player.destroy()
}
},
methods: {
handleOk() {
@ -346,26 +362,15 @@ export default {
autoPlay(id){
let video = document.getElementById('config-camera'+id);
if(video){
let player = new WebRtcPlayer(video,'camera'+id);
let server = this.mdata.rtcServer+":"+this.mdata.rtcServerPort
console.log("server:"+server)
let player = new WebRtcPlayer(server,video,'camera'+id);
console.log("okkkkkk")
player.load('camera'+id);
//player.load('camera'+id);
this.player = player
}
},
setVideoServer(){
this.$api.httpApi.getVideoServer({
data: {}
}).then(res => {
if(res.code == 200) {
WebRtcPlayer.setServer(res.data.toString());
}
}).catch(err => {
console.log(err)
})
},
getConfigIoList(){
this.$axios.post('/camera/'+this.id+'/io/list', {
data: {
@ -773,6 +778,10 @@ export default {
.operation-item{
img{
width: 42px;
-webkit-user-select: none;
-ms-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
span{
padding: 5px 10px;
@ -795,6 +804,10 @@ export default {
justify-content: space-between;
img{
width: 42px;
-webkit-user-select: none;
-ms-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
}
}
@ -816,6 +829,10 @@ export default {
.operation-item{
img{
width: 32px;
-webkit-user-select: none;
-ms-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
span{
padding: 3px 6px;
@ -838,6 +855,10 @@ export default {
justify-content: space-between;
img{
width: 32px;
-webkit-user-select: none;
-ms-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
}
}
@ -846,7 +867,7 @@ export default {
}
.config-table {
width: 800px;
height: 600px;
height: 500px;
overflow: hidden;
h2 {

@ -1,123 +0,0 @@
class WebRtcPlayer {
static server = '127.0.0.1:8083';
webrtc = null;
video = null;
server = null;
codecLink = null;
rsdpLink = null;
stream = new MediaStream();
uuid = null;
options={
onStatusChange:null
};
constructor(video1, uuid, options={}) {
console.log("new uuid:"+uuid)
this.server = WebRtcPlayer.server;
//this.video = document.getElementById(id);
this.video = video1
this.uuid = uuid;
Object.assign(this.options, options);
this.createLinks();
this.play();
}
createLinks() {
this.codecLink = "//" + this.server + "/stream/codec/" + this.uuid
this.rsdpLink = "//" + this.server + "/stream/receiver/" + this.uuid
}
play() {
this.webrtc = new RTCPeerConnection({
iceServers: [{
urls: ["stun:stun.l.google.com:19302"]
}]
});
if(this.webrtc){
}else{
console.log("no")
}
this.webrtc.onnegotiationneeded = this.handleNegotiationNeeded.bind(this);
this.webrtc.ontrack = this.onTrack.bind(this);
fetch(this.codecLink)
.then((response) => {
response.json().then((data) => {
data.forEach((item, i) => {
this.webrtc.addTransceiver(item.Type, {
'direction': 'sendrecv'
});
});
});
})
.catch((error) => {
console.log(error);
});
this.webrtc.onconnectionstatechange = () => {
if(this.webrtc.connectionState == 'connected' || this.webrtc.connectionState == 'connecting'){
console.log("uuid:"+this.uuid+" status:" + this.webrtc.connectionState)
}else{
console.log(this.webrtc.connectionState)
this.load(this.uuid);
}
}
}
async handleNegotiationNeeded() {
let offer = await this.webrtc.createOffer();
await this.webrtc.setLocalDescription(offer);
let formData = new FormData();
formData.append('suuid', this.uuid);
formData.append('data', btoa(this.webrtc.localDescription.sdp));
fetch(this.rsdpLink, {
method: 'POST',
body: formData
})
.then((response) => {
response.text().then((data) => {
this.webrtc.setRemoteDescription(new RTCSessionDescription({
type: 'answer',
sdp: atob(data)
}))
});
})
.catch((err) => {})
}
onTrack(event) {
this.stream.addTrack(event.track);
this.video.srcObject = this.stream;
this.video.play();
}
load(uuid) {
this.destroy();
this.uuid = uuid;
this.createLinks();
this.play();
}
destroy() {
console.log("destroy uuid:"+this.uuid)
this.webrtc.close();
this.webrtc = null;
this.video.srcObject = null;
this.stream = new MediaStream();
}
getImageUrl() {
let canvas = document.createElement("canvas");
canvas.width = this.video.videoWidth;
canvas.height = this.video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
let dataURL = canvas.toDataURL();
canvas.remove();
return dataURL;
}
static setServer(serv) {
this.server = serv;
}
}
export default WebRtcPlayer;

@ -1,17 +1,17 @@
<template>
<div class="subsection">
<a-layout style="width: 900px">
<a-layout style="width: 1500px">
<a-layout style="width: 100%;height: 310px">
<a-layout-sider width="110px">
<a-tabs default-active-key="1" tab-position="left" @change="changeTabLeft" v-if="total.column > nums.column">
<a-tabs default-active-key="1" tab-position="left" @change="changeTabLeft" v-if="total.row > nums.row">
<a-tab-pane
v-for="index in latticeColumn"
v-for="index in latticeRow"
:key="index"
>
<span slot="tab" >
{{ getRandom(index, latticeColumn, nums.column, total.column) }}
<a-icon type="close-circle" v-if="status.column[index] === 1" style="color: #d81e06"/>
<a-icon type="check-circle" v-else-if="status.column[index] === 2" style="color: #1afa29" />
{{ getRandom(latticeRow + 1 -index, latticeRow, nums.row, total.row) }}
<a-icon type="close-circle" v-if="status.row[index] === 1" style="color: #d81e06"/>
<a-icon type="check-circle" v-else-if="status.row[index] === 2" style="color: #1afa29" />
<a-icon type="exclamation-circle" v-else style="color: #909399" />
</span>
</a-tab-pane>
@ -21,15 +21,16 @@
<!-- <slot :data="{select, nums, random}"></slot> -->
<div class="roadway-buttom">
<div class="roadway-box">
<div class="line" v-for="(column,index) in total.column" :key="index" v-if="column >= random.column[0] && column <= random.column[1]">
<div v-for="(row,index) in total.row" :key="index" class="el" v-if="row >= random.row[0] && row <= random.row[1]">
<div class="line" v-for="(row,rowIndex) in total.row" :key="rowIndex" v-if="row >= random.row[0] && row <= random.row[1]">
<div v-for="(column,index) in total.column" :key="index" class="el" v-if="column >= random.column[0] && column <= random.column[1]">
<!--渲染默认巷道框架规格 定位浮在 已有巷道上做对应-->
<span
<span
class="default"
:id="`${shelveId}-${row}-${column}`"
@click="tocheckPage(row,column)">
{{row}}-{{column}}
:id="`${direction}-${side}-${random.row[0] + random.row[1] - rowIndex - 1}-${column}`"
@click="tocheckPage(random.row[0] + random.row[1] - rowIndex - 1,column)">
{{ random.row[0] + random.row[1] - rowIndex - 1}}-{{column}}
</span>
</div>
</div>
@ -39,16 +40,16 @@
</a-layout>
<a-layout-footer>
<!-- <a-tabs default-active-key="1" tab-position="bottom" @change="value => select.row = value" v-if="total.row > nums.row"> -->
<a-tabs default-active-key="1" tab-position="bottom" @change="changeTab" v-if="total.row > nums.row">
<a-tabs default-active-key="1" tab-position="bottom" @change="changeTab" v-if="total.column > nums.column">
<a-tab-pane
v-for="index in latticeRow"
v-for="index in latticeColumn"
:key="index"
>
<span slot="tab">
{{ getRandom(index, latticeRow, nums.row, total.row) }}
{{ getRandom(index, latticeColumn, nums.column, total.column) }}
<!-- <a-icon :id="`${shelveId}-row-${getRandom(index,latticeRow,nums.row,total.row)}`"/> -->
<a-icon type="close-circle" v-if="status.row[index] === 1" style="color: #d81e06" />
<a-icon type="check-circle" v-else-if="status.row[index] === 2" style="color: #1afa29" />
<a-icon type="close-circle" v-if="status.column[index] === 1" style="color: #d81e06" />
<a-icon type="check-circle" v-else-if="status.column[index] === 2" style="color: #1afa29" />
<a-icon type="exclamation-circle" v-else style="color: #909399" />
</span>
</a-tab-pane>
@ -81,46 +82,41 @@ export default {
}
},
nums: {
// 20 10
type: Object,
default: () => {
return {
row: 15,
column: 10
row: 10,
column: 15
}
}
},
shelveId: {
type: String,
default: () => {
return {}
}
},
streetId: {
direction: {
type: Number,
default: () => {
return {}
}
},
streetName: {
type: String,
side: {
type: Number,
default: () => {
return {}
}
},
type: {
type: String,
streetId: {
type: Number,
default: () => {
return {}
}
},
inOut: {
streetName: {
type: String,
default: () => {
return {}
}
},
},
computed: {
//
@ -138,16 +134,22 @@ export default {
column: this.getRandomColumn(this.select.column),
}
},
watchShelveIdInfo(){
return this.shelveId;
},
watchDirection(){
return this.direction;
},
watchSide(){
return this.side;
},
},
watch: {
watchShelveIdInfo() {
watchDirection() {
this.getStatus();
},
watchSide() {
this.getStatus();
},
immediate: true
immediate: true,
},
data() {
return {
@ -156,23 +158,23 @@ export default {
column: {}
},
timer: null
}
},
mounted() {
this.$nextTick(() => {
this.getStatus();
})
this.timer = window.setInterval(this.getStatus, 5000);
this.$once('hook:beforeDestroy', () => {//
console.log('hook:beforeDestroy')
window.clearInterval(this.timer);//
this.timer = null;
});
this.$on('hook:activated', () => {
this.timer = window.setInterval(this.getStatus, 3000);
})
this.timer = window.setInterval(this.getStatus, 3000);
this.$on('hook:deactivated', () => {
clearInterval(this.timer)
this.timer = null
})
},
beforeDestroy() {
console.log("beforeDestroy")
window.clearInterval(this.timer);
@ -182,15 +184,17 @@ export default {
},
destroyed() {
clearInterval(this.timer);
window.clearInterval(this.timer);
this.timer = null;
},
methods: {
changeTab(value){
this.select.row = value
this.select.column = value
this.getStatus()
},
changeTabLeft(value){
this.select.column = value
this.select.row = value
this.getStatus()
},
@ -204,32 +208,21 @@ export default {
},
//
getRandomRow(val) {
return this.getRandom(val, this.latticeRow, this.nums.row, this.total.row).split(' - ').map(item => Number(item));
console.log(this.latticeRow + 1 - val, this.latticeRow, this.nums.row, this.total.row)
return this.getRandom(this.latticeRow + 1 - val, this.latticeRow, this.nums.row, this.total.row).split(' - ').map(item => Number(item));
},
getRandomColumn(val) {
return this.getRandom(val, this.latticeColumn, this.nums.column, this.total.column).split(' - ').map(item => Number(item));
},
getStatusBg(row,column,status) {
var dom = document.getElementById(this.shelveId+"-"+row+'-'+column);
var color = status == 1 ?'#d81e06': status == 2 ? '#1afa29': '#bfbfbf';
var dom = document.getElementById(this.direction+"-"+this.side+"-"+row+'-'+column);
var color = status == 1 ?'#d81e06': (status == 2|| status == 3) ? '#1afa29': '#bfbfbf';
dom.style.background = color
},
getStatusTab(tab,status,rowColumn){
var dom = document.getElementById(this.shelveId+'-'+rowColumn+'-'+tab);
console.log(dom)
console.log(this.shelveId+'-'+rowColumn+'-'+tab)
dom.style.type ="close-circle"
var color = status == 1 ?'#d81e06': status == 2 ? '#1afa29': '#bfbfbf';
dom.style.color = color
console.log(dom)
},
getStatus(){
if(JSON.stringify(this.shelveId) == "{}"){
return;
}
var columnTab = []
for(let c = 1; c <= this.latticeColumn ;c++){
let tab = this.getRandom(c,this.latticeColumn,this.nums.column,this.total.column)
@ -246,7 +239,9 @@ export default {
columnEnd: this.random.column[1],
rowStart: this.random.row[0],
rowEnd: this.random.row[1],
shelveId: this.shelveId,
streetId: this.streetId,
direction: this.direction,
side: this.side,
rowTabs: rowTab,
columnTabs: columnTab
}
@ -261,16 +256,20 @@ export default {
var i = 1;
for(let a in res.data.columnTabStatus){
this.$set(this.status.column, i, res.data.columnTabStatus[a]);
// this.status.column[i] = res.data.columnTabStatus[a]
i++;
}
var j = 1;
var j = 0;
for(let a in res.data.rowTabStatus){
this.$set(this.status.row, j, res.data.rowTabStatus[a]);
// this.status.row[j] = res.data.rowTabStatus[a]
j++;
}
for(let a in res.data.rowTabStatus){
this.$set(this.status.row, j, res.data.rowTabStatus[a]);
j--;
}
}
}).catch(err => {
@ -279,7 +278,7 @@ export default {
tocheckPage(row,column){
this.$router.push({
name: 'checkOperation',
query: {row: row, column: column, shelveId: this.shelveId, id: this.streetId, name:this.streetName, type: this.type, type2: this.inOut}
query: {row: row, column: column, direction: this.direction,side:this.side, streetId: this.streetId, name:this.streetName}
})
}
}

@ -1,131 +1,86 @@
<template>
<div class="checkOperation">
<div class="topMenu">
<a-select v-if="listData[0]"
:default-value="selectName"
style="width:160px;margin-right:25px"
@change="handleChange"
class="select-roadway">
<a-select-option v-for="i in listData" :key="i.name" :value="i.id">
{{i.name}}
</a-select-option>
</a-select>
<a-select
@change="handleTypeChange"
style="width: 160px;margin-right:25px"
:value="selectType">
<a-select-option value="left">
左货架
</a-select-option>
<a-select-option value="right">
右货架
</a-select-option>
</a-select>
<a-select
@change="sideStreetChange"
style="width: 160px"
:value="selectType2"
v-if="selectType2 !== 'none' && selectType2 !== '' "
>
<a-select-option value="out">
</a-select-option>
<a-select-option value="inside">
</a-select-option>
</a-select>
<span>
货架号 : {{ shelveId }} {{rowCount}} {{columnCount}}
</span>
</div>
<div>
<div class="carousel-page"
>
<div class="carousel-page-content">
<div class="img-box">
<ul>
<li>
<span class="img-box-title">
核对状态:
</span>
<span class="img-box-value">
{{ statusMap[checkObj.status] }}
</span>
</li>
<li v-for="item in params" :key="item.label">
<span class="img-box-title">
{{ item.label }}:
</span>
<span class="img-box-value">
{{ checkObj[item.key] }}
</span>
</li>
<li>
<span class="img-box-title">
盘点图:
</span>
</li>
<template>
<span v-if="checkObj.checkPic">
<happy-scroll color="rgba(100,100,100,0.5)" size="1" class="scroll-box" style="width:50;height:90px;">
<viewer>
<img class="historyImg" :src="imgUrl+checkObj.checkPic"/>
</viewer>
</happy-scroll>
</span>
<span v-else>
暂无盘点图
</span>
</template>
</ul>
</div>
<div class="img-box">
<img
v-if="checkObj.preoperationPic"
:src="imgUrl+checkObj.preoperationPic"
style="width: 100%;height: 358px"
alt=""/>
<div
v-else
style="display: flex;align-items: center;justify-content: center;width:600px;height:400px;background:#eaeaea">
暂无图片
<div class="carousel-page">
<div class="carousel-page-content">
<div class="img-box">
<ul>
<li>
<span >
{{streetName}}-{{this.direction == 1?"左":"右"}}-{{this.side == 1?"浅":"深"}}-{{row}}-{{column}}
</span>
</li>
<li>
<span class="img-box-title">
核对状态:
</span>
<span class="img-box-value">
{{ statusMap[checkObj.status] }}
</span>
</li>
<li v-for="item in params" :key="item.label">
<span class="img-box-title">
{{ item.label }}:
</span>
<span class="img-box-value">
{{ checkObj[item.key] }}
</span>
</li>
</ul>
</div>
<p>操作前照片</p>
</div>
<div class="img-box">
<img
v-if="checkObj.overoperationPic"
:src="imgUrl+checkObj.overoperationPic"
style="width: 100%;height: 358px"
alt=""/>
<div
v-else
style="display: flex;align-items: center;justify-content: center;width:600px;height:400px;background:#eaeaea">
暂无图片
<div class="img-box">
<viewer v-if="checkObj.checkPic" style="height: 300px">
<img :src="imgUrl+checkObj.checkPic"/>
</viewer>
<div
v-else
style="display: flex;align-items: center;justify-content: center;width:100px;height:300px;">
暂无图片
</div>
<p>盘点图</p>
</div>
<div class="img-box">
<viewer v-if="checkObj.preoperationPic" style="height:300px;">
<img :src="imgUrl+checkObj.preoperationPic"/>
</viewer>
<div v-else style="display: flex;align-items: center;justify-content: center;width:100px;height:300px;">
暂无图片
</div>
<p>操作前照片</p>
</div>
<div class="img-box">
<viewer v-if="checkObj.overoperationPic" style="width:100%;height:300px;">
<img :src="imgUrl+checkObj.overoperationPic"/>
</viewer>
<div
v-else
style="display: flex;align-items: center;justify-content: center;width:100px;height:300px;">
暂无图片
</div>
<p>操作后照片</p>
</div>
<p>操作后照片</p>
</div>
</div>
</div>
<div class="bottom-btn" >
<a-button class="btn"
type="primary"
style="background:#29c12b;border-color:#29c12b;"
@click="checkSure(checkObj.row,checkObj.column,checkObj.shelveId,index)"
>核对
</a-button>
</div>
<div class="bottom-btn"
>
<a-button class="btn" @click="prev()"></a-button>
<p>{{checkObj.row}}{{checkObj.column}}</p>
<a-button class="btn" @click="next()">
</a-button>
</div>
<div class="bottom-btn" >
<a-button class="btn"
type="primary"
style="background:#29c12b;border-color:#29c12b;"
@click="checkSure(checkObj.row,checkObj.column,checkObj.shelveId,index)"
>核对正确
</a-button>
<a-button class="btn"
type="primary"
style="background:#ff0000;border-color:#ff0000;"
@click="checkfalse(checkObj.row,checkObj.column,checkObj.shelveId,index)"
>核对错误
</a-button>
</div>
</div>
@ -144,23 +99,11 @@ import {imgUrl} from "@/api/importExcel";
export default {
data() {
return {
listData: [],
scanAndCheck: {},
checkObj: {},
streetDetail: {},
checkList: {},
id: 0,
row: 1,
column: 1,
//
rowCount: 0,
columnCount: 0,
selectName: '',
shelveId: '',
//
selectType: 'left',
//
selectType2: '',
streetName: '',
visible: false,
category: '',
count: 0,
@ -168,93 +111,73 @@ export default {
index: 0,
imgUrl: '',
params:[
{
label:'工单号',
key: 'orderNum'
label:'盘点批次号',
key: 'lotnum'
},
{
label:'系统条码号',
key: 'wmsCode'
label:'盘点任务号',
key: 'checkNum'
},
{
label:'扫描条码号',
key: 'code'
label:'盘点时间',
key: 'exportTime'
},
],
statusMap: {0:"未盘点",1:"盘点异常",2:"核对正确",3:"核对正确"}
statusMap: {0:"未盘点",1:"盘点异常",2:"核对正确",3:"人工核对正确"}
}
},
beforeRouteLeave(to ,form, next) {
// created
this.$destroy();
//next();
if (to.name == 'checkManage') {
to.meta.isUseCache = true;
}else{
to.meta.isUseCache = false;
}
next();
},
created() {
this.imgUrl = imgUrl
console.log(this.$route.query.id)
this.getStreetList();
if (this.$route.query.row && this.$route.query.column && this.$route.query.shelveId && this.$route.query.id && this.$route.query.name) {
//this.getStreetList();
if (this.$route.query.row && this.$route.query.column && this.$route.query.direction && this.$route.query.side && this.$route.query.streetId) {
this.id = this.$route.query.id
this.row = this.$route.query.row
this.column = this.$route.query.column
this.shelveId = this.$route.query.shelveId
this.selectName = this.$route.query.name
this.selectType = this.$route.query.type
this.selectType2 = this.$route.query.type2
this.getStockInfo(this.row, this.column, this.shelveId);
this.direction = this.$route.query.direction
this.side = this.$route.query.side
this.streetId = this.$route.query.streetId
this.streetName = this.$route.query.name
this.getStockInfo(this.row, this.column);
}
},
mounted() {
//this.getStreetList();
},
destroyed () {
},
components: {
Model
},
methods: {
//
getStreetList() {
this.$api.httpApi.getStreetList({
data: {
pageNum: 1,
pageSize: 50,
}
}).then(res => {
this.listData = res.data.list;
this.select = this.id
this.getStreetDetail(this.id)
//this.getStockInfo(this.row,this.column,this.id)
//this.getStockList(this.id)
}).catch(err => {
console.error(err);
});
},
//
getStreetDetail(id) {
this.$axios.get('/street/' + id, {
data: {}
}).then(res => {
this.streetDetail = res.data
this.getRowColumnCounts()
}).catch(err => {
})
},
//
getRowColumnCounts(){
this.updateShleveAndRowColumnCount(this.selectType)
if(this.streetDetail){}
},
//
getStockInfo(row, column, shelveId) {
getStockInfo(row, column) {
this.$api.httpApi.getStockInfo({
data: {
row: Number(row),
column: Number(column),
shelveId: shelveId,
direction: this.direction,
side: this.side,
streetId: this.streetId,
}
}).then(res => {
if (res.data) {
@ -272,156 +195,43 @@ export default {
this.id = value
this.row = 1
this.column = 1
this.getStreetList()
for (var i = 0; i < this.listData.length; i++) {
if (this.listData[i].id == value) {
if (this.listData[i].leftShelveId) {
this.shelveId = this.listData[i].leftShelveId
this.selectType = 'left'
this.selectType2 = 'none'
this.rowCount = this.listData[i].leftRow
this.columnCount = this.listData[i].leftColumn
} else if (this.listData[i].leftInsideShelveId) {
this.shelveId = this.listData[i].leftInsideShelveId
this.selectType = 'left'
this.selectType2 = 'inside'
this.rowCount = this.listData[i].leftRow
this.columnCount = this.listData[i].leftColumn
} else if (this.listData[i].leftOutsideShelveId) {
this.shelveId = this.listData[i].leftOutsideShelveId
this.selectType = 'left'
this.selectType2 = 'out'
this.rowCount = this.listData[i].leftRow
this.columnCount = this.listData[i].leftColumn
}
}
}
this.getStockInfo(1, 1, this.shelveId)
this.getStockInfo(1, 1)
},
//
handleTypeChange(value) {
this.selectType = value
this.updateShleveAndRowColumnCount(value)
this.row = 1
this.column = 1
this.getStockInfo(this.row, this.column, this.shelveId)
},
//streetDetail
//direction : left right
updateShleveAndRowColumnCount(direction){
if (direction == 'left') {
this.rowCount = this.streetDetail.leftRow
this.columnCount = this.streetDetail.leftColumn
if(this.streetDetail.leftType == 0){
this.shelveId = this.streetDetail.leftShelveId
this.selectType2 = ''
}else{
if(this.selectType2 == 'inside'){
this.shelveId = this.streetDetail.leftInsideShelveId
}else if(this.selectType2 == 'outside'){
this.shelveId = this.streetDetail.leftOutsideShelveId
}else{
this.selectType2 = 'inside'
this.shelveId = this.streetDetail.leftInsideShelveId
}
checkSure(row, column, shelveId, index) {
this.$api.httpApi.stockCheckCorrect({
data: {
row: Number(row),
column: Number(column),
side: Number(this.side),
streetId: Number(this.streetId),
direction: Number(this.direction),
ok: 1
}
} else if (direction == 'right') {
this.rowCount = this.streetDetail.rightRow
this.columnCount = this.streetDetail.rightColumn
if(this.streetDetail.rightType == 0){
this.shelveId = this.streetDetail.rightShelveId
this.selectType2 = ''
}else{
if(this.selectType2 == 'inside'){
this.shelveId = this.streetDetail.rightInsideShelveId
}else if(this.selectType2 == 'outside'){
this.shelveId = this.streetDetail.rightOutsideShelveId
}else{
this.selectType2 = 'inside'
this.shelveId = this.streetDetail.rightInsideShelveId
}
}).then(res => {
if (res.code == 200) {
this.$message.success('操作成功');
this.getStockInfo(this.row,this.column)
}
}
},
//
sideStreetChange(value) {
this.selectType2 = value
if (this.selectType == 'left' && value == 'none') {
this.shelveId = this.streetDetail.leftShelveId
this.rowCount = this.streetDetail.leftRow
this.columnCount = this.streetDetail.leftColumn
} else if (this.selectType == 'right' && value == 'none') {
this.rowCount = this.streetDetail.rightRow
this.columnCount = this.streetDetail.rightColumn
this.shelveId = this.streetDetail.rightShelveId
} else if (this.selectType == 'left' && value == 'inside') {
this.rowCount = this.streetDetail.leftRow
this.columnCount = this.streetDetail.leftColumn
this.shelveId = this.streetDetail.leftInsideShelveId
} else if (this.selectType == 'left' && value == 'out') {
this.rowCount = this.streetDetail.leftRow
this.columnCount = this.streetDetail.leftColumn
this.shelveId = this.streetDetail.leftOutsideShelveId
} else if (this.selectType == 'right' && value == 'inside') {
this.rowCount = this.streetDetail.rightRow
this.columnCount = this.streetDetail.rightColumn
this.shelveId = this.streetDetail.rightInsideShelveId
} else if (this.selectType == 'right' && value == 'out') {
this.rowCount = this.streetDetail.rightRow
this.columnCount = this.streetDetail.rightColumn
this.shelveId = this.streetDetail.rightOutsideShelveId
}
//this.getStockInfo(this.row, this.column, this.shelveId)
}).catch(err => {
});
},
prev() {
if(this.column > 1){
this.column = this.column - 1
}else{
if(this.row > 1){
this.row = this.row - 1
this.column = this.columnCount
}else{
this.row = this.rowCount
this.column = this.columnCount
}
}
this.getStockInfo(this.row,this.column,this.shelveId)
},
next() {
if(this.column < this.columnCount){
this.column = this.column + 1
}else{
// row+1
if(this.row < this.rowCount){
this.row = this.row + 1
this.column = 1
}else{
this.row = 1
this.column = 1
}
}
this.getStockInfo(this.row,this.column,this.shelveId)
},
checkSure(row, column, shelveId, index) {
checkfalse(row, column, shelveId, index) {
this.$api.httpApi.stockCheckCorrect({
data: {
row: Number(row),
column: Number(column),
shelveId: shelveId,
side: Number(this.side),
streetId: Number(this.streetId),
direction: Number(this.direction),
ok: 0
}
}).then(res => {
if (res.code == 200) {
this.$message.success('操作成功');
this.getStockInfo(this.row,this.column,this.shelveId)
this.getStockInfo(this.row,this.column)
}
}).catch(err => {
@ -486,7 +296,7 @@ export default {
height: 25px;
}
ul {
width: 320px;
width: 100% / 4;
height: 100%;
margin-bottom: 0;
padding-inline-start: 0;
@ -498,12 +308,12 @@ export default {
font-weight: 600;
color: #494e52;
.img-box-title {
width: 90px;
width: 130px;
display: inline-block;
}
.img-box-value {
display: inline-block;
width: calc(100% - 90px);
width: calc(100% - 130px);
overflow: hidden;
position: relative;
top: 5px;

@ -1,8 +1,13 @@
<template>
<div class="check-page">
<div class="button-box">
<a-button type="primary" @click="exportStock" class="export-all">
导出全部巷道
导出巷道盘点数据
</a-button>
<a-button type="primary" @click="exportAllStock" class="export-all">
导出全部巷道盘点数据
</a-button>
</div>
<div class="title-info">
<span class="explain">颜色说明</span>
<span class="info-text">
@ -20,8 +25,7 @@
</div>
<div style="margin-top: 10px">
<a-select :default-value="data[0].name"
@change="handleChange" class="select-roadway">
<a-select @change="handleChange" style="width:200px" v-model="select">
<a-select-option v-for="i in data" :key="i.name" :value="i.id">
{{i.name}}
</a-select-option>
@ -32,23 +36,24 @@
<!--左货架DOM-->
<div class="center-box">
<span class="shelf-number">
货架: {{leftShelveId.shelveId}}
货架
</span>
<a-radio-group v-model="size" style="margin:10px 0" @change="getStockRowColumn"
v-if="streetDetail.leftInsideShelveId && streetDetail.leftOutsideShelveId">
<a-radio-button value="leftOutsideShelveId">
<a-radio-group v-model="leftSide" style="margin:10px 0"
v-if="streetDetail.leftType == 1">
<a-radio-button :value=1>
浅侧货架
</a-radio-button>
<a-radio-button value="leftInsideShelveId">
<a-radio-button :value=2>
深侧货架
</a-radio-button>
</a-radio-group>
</div>
<div class="check-content" v-for="item in data" :key="item.id">
<subsection v-if="item.id == select" :total="{row: item.leftColumn, column: item.leftRow}" :shelveId="leftShelveId.shelveId" :streetId="item.id" :streetName="item.name" type="left" :inOut="leftShelveId.shelveType" >
<subsection v-if="item.id == select" :total="{row: item.leftRow, column: item.leftColumn}" :side="leftSide" :direction=1 :streetId="item.id" :streetName="item.name">
</subsection>
</div>
@ -56,24 +61,26 @@
<!--单伸类型右货架DOM-->
<div class="center-box">
<span class="shelf-number">
货架: {{rightShelveId.shelveId}}
货架
</span>
<a-radio-group v-model="size2" style="margin:10px 0" @change="getStockRowColumn"
v-if="streetDetail.rightInsideShelveId && streetDetail.rightOutsideShelveId">
<a-radio-button value="rightOutsideShelveId">
<a-radio-group v-model="rightSide" style="margin:10px 0"
v-if="streetDetail.rightType == 1">
<a-radio-button :value=1>
浅侧货架
</a-radio-button>
<a-radio-button value="rightInsideShelveId">
<a-radio-button :value=2>
深测货架
</a-radio-button>
</a-radio-group>
</div>
<div class="check-content" v-for="item in data" :key="item.name">
<subsection v-if="item.id == select" :total="{row:item.rightColumn, column: item.rightRow}" :shelveId="rightShelveId.shelveId" :streetId="item.id" :streetName="item.name" type="right" :inOut="rightShelveId.shelveType">
<subsection v-if="item.id == select" :total="{row:item.rightRow, column: item.rightColumn}" :side="rightSide" :direction=2 :streetId="item.id" :streetName="item.name">
</subsection>
</div>
</div>
@ -84,21 +91,12 @@ export default {
name:'checkManage',
data() {
return {
size: 'leftOutsideShelveId',
size2: 'rightOutsideShelveId',
leftSide: 1,
rightSide: 1,
data: [],
select: '',
streetId: 0,
streetDetail: {},
checkList: [],
stockInfo: {
left: {},
right: {}
},
timer: null,
leftShelveId:{},
rightShelveId:{}
}
},
computed: {
@ -111,88 +109,43 @@ export default {
created(){
},
// activated() {
// this.request();
// },
// beforeRouteLeave(to, form, next) {
// this.timer && clearInterval(this.timer);
// next();
// },
activated() {
if(!this.$route.meta.isUseCache){
console.log("$route.meta.isUseCache false")
//
this.request();//
}else{
console.log("$route.meta.isUseCache true")
//this.request();
}
},
methods: {
//
request() {
this.$api.httpApi.getStreetList({
data: {
pageNum: 1,
pageSize: 50,
}
this.$api.httpApi.getAllStreet({
}).then(res => {
console.log("update data")
for(let i = 0;i<res.data.list.length;i++){
console.log(res.data.list[i])
this.$set(this.data,i,res.data.list[i])
for(let i = 0;i<res.data.length;i++){
this.$set(this.data,i,res.data[i])
}
console.log(this.data)
this.select = res.data.list[0].id
this.select = res.data[0].id
this.selectName = res.data[0].name
//this.$set(this.select,res.data.list[0].id,0)
this.getStreetDetail(this.select);
}).catch(err => {
});
},
//
async getStockRowColumn() {
this.rightShelveChange();
this.leftShelveChange();
},
rightShelveChange() {
let shelveId;
let shelveType = 'none';
if(this.streetDetail.rightShelveId) {
shelveId = this.streetDetail.rightShelveId;
}else if(this.streetDetail.rightInsideShelveId && this.size2 =='rightInsideShelveId'){
shelveId = this.streetDetail.rightInsideShelveId;
shelveType = 'inside';
}else if(this.streetDetail.rightOutsideShelveId && this.size2 == 'rightOutsideShelveId'){
shelveId = this.streetDetail.rightOutsideShelveId;
shelveType = 'out';
};
this.rightShelveId.shelveId = shelveId;
this.rightShelveId.shelveType = shelveType;
},
leftShelveChange() {
let shelveId;
let shelveType = 'none';
if(this.streetDetail.leftShelveId) {
shelveId = this.streetDetail.leftShelveId;
}else if(this.streetDetail.leftInsideShelveId && this.size =='leftInsideShelveId'){
shelveId = this.streetDetail.leftInsideShelveId;
shelveType = 'inside';
}else if(this.streetDetail.leftOutsideShelveId && this.size== 'leftOutsideShelveId'){
shelveId = this.streetDetail.leftOutsideShelveId;
shelveType = 'out';
};
this.leftShelveId.shelveId = shelveId;
this.leftShelveId.shelveType = shelveType;
},
getStatus(data, rowCol) {
return (data[rowCol] || {}).status;
},
//
getStatusBg(data, rowCol) {
let status = this.getStatus(data, rowCol);
return status == 1 ?'#d81e06': status == 2 ? '#1afa29': '#bfbfbf';
},
//
getStreetDetail(id) {
this.$axios.get('/street/' + id, {
data: {}
}).then(res => {
this.streetDetail = res.data
this.getStockRowColumn()
//this.getStockRowColumn()
}).catch(err => {
})
@ -201,17 +154,8 @@ export default {
handleChange(value) {
this.select = value
console.log("1654asdfasf"+value);
this.getStreetDetail(value)
//this.getStockList(value);
//this.getStockRowColumn()
this.leftShelveChange();
this.rightShelveChange();
},
tocheckOperation(checkObj, item) {
console.log(checkObj)
console.log(item)
this.$router.push({name: 'checkOperation', query: {checkObj: checkObj, item: item}})
},
exportStock() {
@ -221,11 +165,15 @@ export default {
}
}).then(res => {
let blob = new Blob([res], {type: "application/vnd.ms-excel"})
this.$utils.downloadFile('巷道列表.xls', blob)
this.$utils.downloadFile(this.streetDetail.name+'-盘点列表.xls', blob)
}).catch(err => {
});
},
exportAllStock() {
this.$utils.downloadFileUrl('盘点列表.xls', '/api/stock/exportAll');
},
},
components: {Subsection}
};
@ -233,7 +181,7 @@ export default {
<style lang="scss" scoped>
.check-page {
position: relative;
.title-info {
display: flex;
align-items: center;
@ -301,9 +249,21 @@ export default {
width: 200px;
}
}
.export-all {
}
.button-box{
position: absolute;
right: 20px;
top:20px;
right: 40px;
display: flex;
align-items: center;
justify-content: center;
.export-all {
margin-right: 20px;
}
}
}
</style>

@ -0,0 +1,318 @@
<template>
<div class="history bg-white">
<div class="ant-advanced-search-form">
<a-form layout="inline" :form="queryParam">
<a-row :gutter="24">
<a-col :span="4">
<a-form-item label="巷道">
<a-select @change="handleChange" v-model="select" style="width:100px">
<a-select-option v-for="i in listData" :key="i.name" :value="i.id">
{{i.name}}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="2">
<a-form-item label="左右">
<a-select v-model="queryParam.leftRight" @change="leftRightChange" >
<a-select-option :value=0>
未选择
</a-select-option>
<a-select-option :value=1>
左侧
</a-select-option>
<a-select-option :value=2>
右侧
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="2">
<a-form-item label="深浅" v-if="queryParam.side >= 0">
<a-select style="width: 50px" :key="queryParam.side" >
<a-select-option :key=0>
未选择
</a-select-option>
<a-select-option :key=1>
</a-select-option>
<a-select-option :key=2>
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="2" style="text-align: left">
<a-form-item label="行号">
<a-input v-model="queryParam.row" placeholder="请输入" style="width:50px;" type="number"/>
</a-form-item>
</a-col>
<a-col :span="2" style="text-align: left">
<a-form-item label="列号">
<a-input v-model="queryParam.column" placeholder="请输入" style="width:50px;" type="number"/>
</a-form-item>
</a-col>
<a-col :span="4" style="text-align: left">
<a-form-item label="盘点号">
<a-input v-model="queryParam.lotnum" placeholder="请输入" />
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item label="时间">
<a-range-picker
@change="onTimeChange"
v-model="time"
format="YYYY-MM-DD HH:mm"
:show-time="{
defaultValue: [moment('00:00', 'HH:mm'), moment('23:59', 'HH:mm')],
//defaultValue: [moment('00:00', 'YYYY-MM-DD HH:mm'), moment('23:59', 'YYYY-MM-DD HH:mm')],
}">
<a-icon slot="suffixIcon" type="calendar"/>
</a-range-picker>
</a-form-item>
</a-col>
<a-col :span="4" style="text-align: right">
<a-button type="primary" @click="handleSearch"></a-button>
<a-button style="margin-left: 15px" @click="reset"></a-button>
</a-col>
</a-row>
</a-form>
</div>
<a-table
:columns="columns"
:row-key="record => record.id"
:data-source="data"
:pagination="pagination"
@change="handleGetHistoryList"
>
<span slot="checkNum" slot-scope="text">
{{ text }}
</span>
<span slot="goodsLocation" slot-scope="text">
{{ text.direction == 1 ?"左":"右"}}-{{ text.side == 1 ?"浅":"深"}}-{{ text.row}}-{{ text.column}}
</span>
<span slot="status" slot-scope="text">
{{ statusMap[text.status] }}
</span>
<span slot="pic" slot-scope="text" style="width:auto">
<template>
<span style="height:100%;">
<happy-scroll color="rgba(100,100,100,0.5)" size="8" class="scroll-box" style="width:320px;height:90px;">
<viewer><img class="historyImg" :src="imgUrl+text.pic"/></viewer>
</happy-scroll>
</span>
</template>
</span>
</a-table>
</div>
</template>
<script>
import {imgUrl} from "@/api/importExcel";
import moment from 'moment';
export default {
name: "historyCheck",
data() {
return {
statusMap: {0:"未盘点",1:"盘点异常",2:"核对正确",3:"人工核对正确"},
queryParam: {
lotnum: '',
side : '',
leftRight : ''
},
listData:[],
time:[],
pageNum: 1,
pageSize: 10,
data: [],
select: '',
pagination:{
total: 0,
defaultPageSize: 10, //
showTotal: total => `${total} 条数据`,//
showSizeChanger: true, //
pageSizeOptions: ['10', '20', '30'],
onShowSizeChange: (current, pageSize) => this.pageSize = pageSize //
},
imgUrl: imgUrl,
columns: [
{
title: "盘点批次号",
dataIndex: "lotnum",
},
{
title: "巷道名称",
dataIndex: "streetName",
},
{
title: "货位({左右}-{深浅}-{行}-{列})",
scopedSlots: {customRender: 'goodsLocation'},
},
{
title: "盘点状态",
scopedSlots: {customRender: 'status'},
},
{
title: "照片",
scopedSlots: {customRender: 'pic'},
width:320,
},
{
title: "更新时间",
dataIndex: "createTime",
},
],
}
},
mounted() {
this.getStreetList();
this.handleSearch();
},
methods: {
moment,
//
getStreetList() {
this.$api.httpApi.getAllStreet({
}).then(res => {
this.listData = res.data;
}).catch(err => {
console.error(err);
});
},
//
getStreetDetail(id) {
this.$axios.get('/street/' + id, {
data: {}
}).then(res => {
this.streetDetail = res.data
this.select = this.streetDetail.name;
this.queryParam.streetId = this.streetDetail.id;
}).catch(err => {
})
},
handleChange(value) {
this.getStreetDetail(value)
this.queryParam.leftRight = ''
this.queryParam.side = ''
},
//
leftRightChange(value) {
if (value == 1) {
//
if(this.streetDetail.leftType == 0){
this.queryParam.side = ''
}else{
this.queryParam.side = 0
}
} else if (value == 2) {
if(this.streetDetail.rightType == 0){
this.queryParam.side = ''
}else{
this.queryParam.side = 0
}
} else{
this.queryParam.side = ''
}
},
handleSearch() {
console.log(this.queryParam)
this.pageNum = 1
this.request()
},
handleGetHistoryList(pagination) {
console.log(pagination)
if(pagination){
this.pagination.current = pagination.current;
this.pagination.pageSize = pagination.pageSize;
this.pageNum = pagination.current;
this.pageSize = pagination.pageSize;
}
this.request();
},
request() {
this.$api.httpApi.checkLog({
data: {
pageNum: this.pageNum,
pageSize: this.pageSize,
...this.queryParam
}
}).then(res => {
console.log(res.data)
const pagination = {...this.pagination};
pagination.total = res.data.total;
this.pagination = pagination;
this.data = res.data.list
}).catch(err => {
});
},
onTimeChange(date, dateString) {
this.handleReset()
console.log(date)
console.log(dateString)
console.log(date[0].format('YYYY-MM-DD HH:mm'))
this.pageNum = 1
this.queryParam.startTimestamp = date[0].format('YYYY-MM-DD HH:mm:ss')
this.queryParam.endTimestamp = date[1].format('YYYY-MM-DD HH:mm:ss')
},
handleReset() {
this.queryParam.startTimestamp = ""
this.queryParam.endTimestamp = ""
this.pageNum = 1
},
reset() {
this.queryParam.startTimestamp = ""
this.queryParam.endTimestamp = ""
this.queryParam.lotnum = ""
this.queryParam.side = ''
this.queryParam.leftRight = ''
this.queryParam.streetId = 0
this.select = null;
this.time = []
this.pageNum = 1
this.pageSize = 10
this.queryParam.row = null
this.queryParam.column = null
this.request()
},
},
};
</script>
<style lang="scss" scoped>
.history {
padding: 24px;
}
.ant-drawer-content-wrapper {
height: auto !important;
}
.ant-drawer-body {
text-align: center;
}
.ant-advanced-search-form .ant-form-item {
display: flex;
width: 100%;
}
.historyImg {
width: 80px;
height:auto;
margin: 5px;
}
</style>

@ -3,6 +3,16 @@
<div class="ant-advanced-search-form">
<a-form layout="inline" :form="queryParam">
<a-row :gutter="24">
<a-col :span="4">
<a-form-item label="巷道">
<a-select @change="handleChange" style="width:150px" v-model="streetName">
<a-select-option v-for="i in listData" :key="i.name" :value="i.id">
{{i.name}}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="6" style="text-align: left">
<a-form-item label="工单号">
<a-input v-model="queryParam.orderNum" placeholder="请输入" style="width:270px;"/>
@ -23,7 +33,7 @@
</a-range-picker>
</a-form-item>
</a-col>
<a-col :span="10" style="text-align: right">
<a-col :span="5" style="text-align: right">
<a-button type="primary" @click="handleSearch"></a-button>
<a-button style="margin-left: 15px" @click="reset"></a-button>
</a-col>
@ -43,27 +53,27 @@
</span>
<span slot="pics" slot-scope="text" style="width:auto">
<template>
<span v-if="text.pics" style="height:100%;">
<happy-scroll color="rgba(100,100,100,0.5)" size="8" class="scroll-box" style="width:320px;height:90px;">
<viewer :images="text.pics">
<img class="historyImg" v-for="(src,index) in text.pics" :src="imgUrl+src"
:key="index"/>
</viewer>
</happy-scroll>
</span>
<span v-else>
暂无图片
</span>
</template>
<template>
<span v-if="text.pics" style="height:100%;">
<happy-scroll color="rgba(100,100,100,0.5)" size="8" class="scroll-box" style="width:320px;height:90px;">
<viewer :images="text.pics">
<img class="historyImg" v-for="(src,index) in text.pics" :src="imgUrl+src"
:key="index"/>
</viewer>
</happy-scroll>
</span>
<span v-else>
暂无图片
</span>
</template>
</span>
<span slot="status" slot-scope="text">
<span :style="text.status == 1 ?' color:red': ''">
{{ text.status == null ? ' ' : text.status == 0 ? '正常' : '告警' }}
</span>
<span slot="status" slot-scope="text">
<span :style="text.status == 1 ?' color:red': ''">
{{ text.status == null ? ' ' : text.status == 0 ? '正常' : '告警' }}
</span>
</span>
<span slot="videoPath1" slot-scope="text">
<span slot="videoPath1" slot-scope="text">
<a-button type="link" @click="showModel(text)">
查看视频
</a-button>
@ -95,9 +105,12 @@ export default {
data() {
return {
queryParam: {
streetId: '',
orderNum: ''
},
streetName: '',
time:[],
listData:[],
pageNum: 1,
pageSize: 10,
data: [],
@ -163,6 +176,8 @@ export default {
}
},
mounted() {
this.getStreetList();
this.handleGetHistoryList()
console.log(this.imgUrl)
if (this.$route.params.orderNum) {
@ -172,6 +187,23 @@ export default {
},
methods: {
moment,
//
getStreetList() {
this.$api.httpApi.getAllStreet({
}).then(res => {
this.listData = res.data;
}).catch(err => {
console.error(err);
});
},
handleChange(value) {
this.queryParam.streetId = value
this.streetName = value
this.getStreetDetail(value)
},
range(start, end) {
const result = [];
for (let i = start; i < end; i++) {
@ -181,7 +213,8 @@ export default {
},
handleSearch() {
console.log(this.queryParam)
this.handleGetHistoryList()
this.pageNum = 1
this.request()
},
handleGetHistoryList(pagination) {
@ -216,12 +249,17 @@ export default {
console.log(date)
console.log(dateString)
console.log(date[0].format('YYYY-MM-DD HH:mm'))
this.pageNum = 1
this.queryParam.startTimestamp = date[0].format('YYYY-MM-DD HH:mm:ss')
this.queryParam.endTimestamp = date[1].format('YYYY-MM-DD HH:mm:ss')
},
handleReset() {
this.queryParam.startTimestamp = ""
this.queryParam.endTimestamp = ""
this.pageNum = 1
this.pageSize = 10
},
showModel(record) {
this.visible = true
@ -239,6 +277,8 @@ export default {
this.queryParam.endTimestamp = ""
this.queryParam.orderNum = ""
this.time = []
this.pageNum = 1
this.pageSize = 10
this.handleGetHistoryList()
},
},

@ -114,5 +114,7 @@ export default {
.ant-table td {
white-space: nowrap;
}
}
</style>

@ -1,40 +1,88 @@
<template>
<div class="realTime bg-white">
<a-tabs default-active-key="1" slot="headerContent" v-model="tabKey" @change="tabsChange" padding:10px>
<a-tab-pane :key="item.streetId.toString()" :tab="item.streetName" v-for="item in realTimeListData"></a-tab-pane>
<div class="realTime bg-white" style="width: 81.5VW">
<a-tabs default-active-key="1" slot="headerContent" v-model="tabKey"
@change="tabsChange" padding:10px>
<a-tab-pane :key="item.streetId.toString()" :tab="item.streetName" v-for="item in realTimeListData">
</a-tab-pane>
</a-tabs>
<!-- {{cameras.length}} {{ selectTab.videoStyleRow }} * {{ selectTab.videoStyleColumn }}-->
<a-row :gutter="20">
<a-col
v-for="(item, index) in cameras.slice(0, selectTab.videoStyleRow * selectTab.videoStyleColumn)"
:span="24 / selectTab.videoStyleColumn"
:key="index"
:style="{
height: videoHeight,
<a-col
v-for="(item, index) in cameras.slice(0, selectTab.videoStyleRow * selectTab.videoStyleColumn)"
:span="24 / selectTab.videoStyleColumn"
:key="index"
:style="{
height: videoHeight,
marginBottom: ((selectTab.videoStyleRow * selectTab.videoStyleColumn - index - 1) >= selectTab.videoStyleColumn) ? '20px': 0
}"
>
<div style="position: relative;width: 100%;">
<WebrtcPlayer
autoplay class="video-window"
:videoSrc="'http://127.0.0.1/index/api/webrtc?app=live&stream='+item.id+'&type=play'"
:videoId="'videoId'+colIndex+'-'+rowIndex"
ref="videoWindow"
:key="colIndex+'-'+rowIndex"
muted :style="{ height: videoHeight,}">
</WebrtcPlayer>
<!-- <video :style="{ height: videoHeight,}" :id="`camera${item.id}`" autoplay muted controls>
</video> -->
<div class="operation-list">
<div class="operation-item">
<img :src="zoomSubUrl" alt="" @mousedown=zoomDecStart($event,item.id) @mouseleave=zoomDecStop($event,item.id)
>
<span>变倍</span>
<img :src="zoomAddUrl" alt="" @mousedown=zoomAddStart($event,item.id) @mouseleave=zoomAddStop($event,item.id)
>
</div>
<div class="operation-item">
<img :src="focusSubUrl" alt="" @mousedown=focusDecStart($event,item.id) @mouseleave=focusDecStop($event,item.id)
@mouseup=focusDecStop($event,item.id)>
<span>变焦</span>
<img :src="focusAddUrl" alt="" @mousedown=focusAddStart($event,item.id) @mouseleave=focusAddStop($event,item.id)
@mouseup=focusAddStop($event,item.id)>
</div>
<div class="operation-item">
<img :src="irisSubUrl" alt="" @mousedown=irisDecStart($event,item.id) @mouseup=irisDecStop($event,item.id) @mouseleave=irisDecStop($event,item.id)>
<span>光圈</span>
<img :src="irisAddUrl" alt="" @mousedown=irisAddStart($event,item.id) @mouseup=irisAddStop($event,item.id) @mouseleave=irisAddStop($event,item.id)>
</div>
</div>
<div class="direction-list">
<div class="direction-item">
<img :src="leftUpUrl" alt="" @mousedown=leftUpStart($event,item.id) @mouseup=leftUpStop($event,item.id) @mouseleave=leftUpStop($event,item.id)>
<img :src="upUrl" alt="" @mousedown=upStart($event,item.id) @mouseup=upStop($event,item.id) @mouseleave=upStop($event,item.id) >
<img :src="rightUpUrl" alt="" @mousedown=rightUpStart($event,item.id) @mouseup=rightUpStop($event,item.id) @mouseleave=rightUpStop($event,item.id) >
</div>
<div class="direction-item">
<img :src="leftUrl" alt="" @mousedown=leftStart($event,item.id) @mouseup=leftStop($event,item.id) @mouseleave=leftStop($event,item.id)>
<img :src="rightUrl" alt="" @mousedown=rightStart($event,item.id) @mouseup=rightStop($event,item.id) @mouseleave=rightStop($event,item.id)>
</div>
<div class="direction-item">
<img :src="leftDownUrl" alt="" @mousedown=leftDownStart($event,item.id)
@mouseup=leftDownStop($event,item.id) @mouseleave=leftDownStop($event,item.id)>
<img :src="downUrl" alt="" @mousedown=downStart($event,item.id) @mouseup=downStop($event,item.id) @mouseleave=downStop($event,item.id)>
<img :src="rightDownUrl" alt="" @mousedown=rightDownStart($event,item.id)
@mouseup=rightDownStop($event,item.id) @mouseleave=rightDownStop($event,item.id)>
</div>
</div>
</div>
marginBottom: ((selectTab.videoStyleRow * selectTab.videoStyleColumn - index - 1) >= selectTab.videoStyleColumn) ? '20px': 0
}"
>
<video
:style="{
height: videoHeight,
}"
:id="`camera${item.id}`"
autoplay muted ></video>
</a-col>
</a-col>
</a-row>
</div>
</template>
<script>
import WebRtcPlayer from "./webrtcplayer"
//import WebRtcPlayer from "../../../public/static/webrtcplayer"
import WebrtcPlayer from '../../../public/webrtc/webrtcPlayer.vue'
export default {
name: "historyMonitoring",
components: {
//VideoPlayer
},
name: "realTimeMonitoring",
components: {WebrtcPlayer},
data() {
return {
realTimeListData: [],
@ -45,8 +93,22 @@ export default {
visible: false,
modelData: [],
clientHeight: 0,
showVideo: false,
players: []
players: [],
zoomSubUrl:require('@/assets/sub-icon.png'),
zoomAddUrl:require('@/assets/add-icon.png'),
focusSubUrl:require('@/assets/sub-icon.png'),
focusAddUrl:require('@/assets/add-icon.png'),
irisSubUrl:require('@/assets/sub-icon.png'),
irisAddUrl:require('@/assets/add-icon.png'),
leftUpUrl:require('@/assets/left-up-icon.png'),
upUrl:require('@/assets/up-icon.png'),
rightUpUrl:require('@/assets/right-up-icon.png'),
leftUrl:require('@/assets/left-icon.png'),
rightUrl:require('@/assets/right-icon.png'),
leftDownUrl:require('@/assets/left-down-icon.png'),
downUrl:require('@/assets/down-icon.png'),
rightDownUrl:require('@/assets/right-down-icon.png'),
};
},
computed: {
@ -54,21 +116,20 @@ export default {
return (this.realTimeListData.filter(item=> item.streetId == this.tabKey)[0] || {})
},
cameras() {
console.log("cameras" +this.selectTab);
return this.selectTab.cameras || [];
},
videoHeight() {
return (( this.clientHeight - this.selectTab.videoStyleRow * 20 )/ this.selectTab.videoStyleRow ) + 'px'
return (( this.clientHeight)/ this.selectTab.videoStyleRow ) + 'px'
},
},
inject: ['reload'],
//inject: ['reload'],
mounted() {
this.setVideoServer()
this.getClientHeight()
this.getRealTimeList()
if (sessionStorage.getItem('tabKey') == null) {
sessionStorage.setItem('tabKey', 0)
}
this.tabKey = sessionStorage.getItem('tabKey');
this.getClientHeight();
},
destroyed() {
this.destory()
@ -78,13 +139,17 @@ export default {
this.clientHeight = this.$el.clientHeight - 80;
},
getRealTimeList(){
this.showVideo = false;
this.$api.httpApi.getRealTimeList({
data: {}
}).then(res => {
if(res.code == 200) {
this.realTimeListData = res.data.reverse();
this.showVideo = true;
if (sessionStorage.getItem('tabKey') == null) {
console.log("tabKey"+this.realTimeListData[0].id)
sessionStorage.setItem('tabKey', this.realTimeListData[0].streetId)
this.tabKey = sessionStorage.getItem('tabKey');
}
this.$nextTick(() => {
this.autoPlay()
})
@ -97,24 +162,22 @@ export default {
tabsChange(key) {
sessionStorage.setItem('tabKey', key)
this.destory()
this.$nextTick(() => {
this.autoPlay()
})
},
showModel(item) {
this.$nextTick(() => {
this.$router.push({name: "realTimeMonitoringModel", query: {modelData: item}});
})
},
autoPlay(){
this.players = []
for(var a of this.realTimeListData){
for (let b of a.cameras){
let video = document.getElementById('camera'+b.id);
if(video){
let player = new WebRtcPlayer(video,'camera'+b.id);
player.load('camera'+b.id);
console.log("play:"+b.id)
let server = b.rtcServer+":"+b.rtcServerPort;
let player = new WebRtcPlayer(server,video,'camera'+b.id);
this.players.push(player)
}
@ -129,18 +192,317 @@ export default {
player.destroy()
}
},
setVideoServer(){
this.$api.httpApi.getVideoServer({
zoomDecStart(event,id){
console.log('变倍-按下')
console.log(id)
this.zoomSubUrl=require('@/assets/sub-active-icon.png')
this.$axios.post('/camera/control/zoomDec/start/'+id, {
data: {}
}).then(res => {
if(res.code == 200) {
WebRtcPlayer.setServer(res.data.toString());
}
}).catch(err => {
console.log(err)
})
}
},
zoomDecStop(event,id){
console.log('变倍-抬起')
console.log(id)
this.zoomSubUrl=require('@/assets/sub-icon.png')
this.$axios.post('/camera/control/zoomDec/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
zoomAddStart(event,id){
console.log('变倍+按下')
this.zoomAddUrl=require('@/assets/add-active-icon.png')
this.$axios.post('/camera/control/zoomAdd/start/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
zoomAddStop(event,id){
console.log('变倍+抬起')
this.zoomAddUrl=require('@/assets/add-icon.png')
this.$axios.post('/camera/control/zoomAdd/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
focusDecStart(event,id){
console.log('变焦-按下')
this.focusSubUrl=require('@/assets/sub-active-icon.png')
this.$axios.post('/camera/control/focusDec/start/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
focusDecStop(event,id){
console.log('变焦-抬起')
this.focusSubUrl=require('@/assets/sub-icon.png')
this.$axios.post('/camera/control/focusDec/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
focusAddStart(event,id){
console.log('变焦+按下')
this.focusAddUrl=require('@/assets/add-active-icon.png')
this.$axios.post('/camera/control/focusAdd/start/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
focusAddStop(event,id){
console.log('变焦+抬起')
this.focusAddUrl=require('@/assets/add-icon.png')
this.$axios.post('/camera/control/focusAdd/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
irisDecStart(event,id){
console.log('光圈-按下')
this.irisSubUrl=require('@/assets/sub-active-icon.png')
this.$axios.post('/camera/control/irisDec/start/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
irisDecStop(event,id){
console.log('光圈-抬起')
this.irisSubUrl=require('@/assets/sub-icon.png')
this.$axios.post('/camera/control/irisDec/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
irisAddStart(event,id){
console.log('光圈+按下')
this.irisAddUrl=require('@/assets/add-active-icon.png')
this.$axios.post('/camera/control/irisAdd/start/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
irisAddStop(event,id){
console.log('光圈+抬起')
this.irisAddUrl=require('@/assets/add-icon.png')
this.$axios.post('/camera/control/irisAdd/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
leftUpStart(event,id){
console.log('左上鼠标按下')
this.leftUpUrl=require('@/assets/left-up-active-icon.png')
this.$axios.post('/camera/control/leftUp/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
leftUpStop(event,id){
console.log('左上鼠标抬起')
this.leftUpUrl=require('@/assets/left-up-icon.png')
this.$axios.post('/camera/control/leftUp/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
upStart(event,id){
console.log('上鼠标按下')
this.upUrl=require('@/assets/up-active-icon.png')
this.$axios.post('/camera/control/up/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
upStop(event,id){
console.log('上鼠标抬起')
this.upUrl=require('@/assets/up-icon.png')
this.$axios.post('/camera/control/up/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
rightUpStart(event,id){
console.log('右上鼠标按下')
this.rightUpUrl=require('@/assets/right-up-active-icon.png')
this.$axios.post('/camera/control/rightUp/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
rightUpStop(event,id){
console.log('右上鼠标抬起')
this.rightUpUrl=require('@/assets/right-up-icon.png')
this.$axios.post('/camera/control/rightUp/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
leftStart(event,id){
// console.log(this.id)
console.log('左转鼠标按下')
this.leftUrl=require('@/assets/left-active-icon.png')
this.$axios.post('/camera/control/left/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
leftStop(event,id){
this.leftUrl=require('@/assets/left-icon.png')
console.log('左转鼠标抬起')
this.$axios.post('/camera/control/left/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
rightStart(event,id){
console.log('右转鼠标按下')
this.rightUrl=require('@/assets/right-active-icon.png')
this.$axios.post('/camera/control/right/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
rightStop(event,id){
console.log('右转鼠标抬起')
this.rightUrl=require('@/assets/right-icon.png')
this.$axios.post('/camera/control/right/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
leftDownStart(event,id){
console.log('左下鼠标按下')
this.leftDownUrl=require('@/assets/left-down-active-icon.png')
this.$axios.post('/camera/control/leftDown/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
leftDownStop(event,id){
console.log('左下鼠标抬起')
this.leftDownUrl=require('@/assets/left-down-icon.png')
this.$axios.post('/camera/control/leftDown/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
downStart(event,id){
console.log('下鼠标按下')
this.downUrl=require('@/assets/down-active-icon.png')
this.$axios.post('/camera/control/down/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
downStop(event,id){
console.log('下鼠标抬起')
this.downUrl=require('@/assets/down-icon.png')
this.$axios.post('/camera/control/down/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
rightDownStart(event,id){
console.log('右下鼠标按下')
this.rightDownUrl=require('@/assets/right-down-active-icon.png')
this.$axios.post('/camera/control/rightDown/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
rightDownStop(event,id){
console.log('右下鼠标抬起')
this.rightDownUrl=require('@/assets/right-down-icon.png')
this.$axios.post('/camera/control/rightDown/stop/'+id, {
data: {}
}).then(res => {
}).catch(err => {
})
},
},
};
@ -150,4 +512,80 @@ export default {
.realTime {
padding: 10px;
}
//
//
video::-webkit-media-controls-play-button {
display: none;
}
//
video::-webkit-media-controls-timeline {
display: none;
}
//
video::-webkit-media-controls-current-time-display{
display: none;
}
//
video::-webkit-media-controls-time-remaining-display {
display: none;
}
//
video::-webkit-media-controls-mute-button {
display: none;
}
video::-webkit-media-controls-toggle-closed-captions-button {
display: none;
}
//
video::-webkit-media-controls-volume-slider {
display: none;
}
//
video::-webkit-media-controls-enclosure{
display: none;
}
.operation-list {
position: absolute;
right: 200px;
bottom: 20px;
/*width: 150px;*/
/*border: solid 1px blue;*/
z-index: 10;
.operation-item{
img{
width: 32px;
-webkit-user-select: none;
-ms-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
span{
padding: 3px 6px;
background: rgba(0,0,0,0.5);
font-size: 16px;
color: #ffffff;
}
}
}
.direction-list{
position: absolute;
right: 30px;
bottom: 20px;
width: 150px;
z-index: 10;
/*border: solid 1px blue;*/
.direction-item{
display: flex;
align-items: center;
justify-content: space-between;
img{
width: 32px;
-webkit-user-select: none;
-ms-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
}
}
</style>

@ -15,39 +15,39 @@
</div>
<div class="operation-list">
<div class="operation-item">
<img :src="zoomSubUrl" alt="" @mousedown="zoomDecStart" @mouseup="zoomDecStop">
<img :src="zoomSubUrl" alt="" @mousedown="zoomDecStart" @mouseup="zoomDecStop" @mousemove="zoomDecStop">
<span>变倍</span>
<img :src="zoomAddUrl" alt="" @mousedown="zoomAddStart" @mouseup="zoomAddStop">
<img :src="zoomAddUrl" alt="" @mousedown="zoomAddStart" @mouseup="zoomAddStop" @mousemove="zoomAddStop">
</div>
<div class="operation-item">
<img :src="focusSubUrl" alt="" @mousedown="focusDecStart" @mouseup="focusDecStop">
<img :src="focusSubUrl" alt="" @mousedown="focusDecStart" @mouseup="focusDecStop" @mousemove="focusDecStop">
<span>变焦</span>
<img :src="focusAddUrl" alt="" @mousedown="focusAddStart" @mouseup="focusAddStop">
<img :src="focusAddUrl" alt="" @mousedown="focusAddStart" @mouseup="focusAddStop" @mousemove="focusAddStop">
</div>
<div class="operation-item">
<img :src="irisSubUrl" alt="" @mousedown="irisDecStart" @mouseup="irisDecStop">
<img :src="irisSubUrl" alt="" @mousedown="irisDecStart" @mouseup="irisDecStop" @mousemove="irisDecStop">
<span>光圈</span>
<img :src="irisAddUrl" alt="" @mousedown="irisAddStart" @mouseup="irisAddStop">
<img :src="irisAddUrl" alt="" @mousedown="irisAddStart" @mouseup="irisAddStop" @mousemove="irisAddStop">
</div>
</div>
<div class="direction-list">
<div class="direction-item">
<img :src="leftUpUrl" alt="" @mousedown="leftUpStart" @mouseup="leftUpStop">
<img :src="upUrl" alt="" @mousedown="upStart" @mouseup="upStop">
<img :src="rightUpUrl" alt="" @mousedown="rightUpStart" @mouseup="rightUpStop">
<img :src="leftUpUrl" alt="" @mousedown="leftUpStart" @mouseup="leftUpStop" @mousemove="leftUpStop">
<img :src="upUrl" alt="" @mousedown="upStart" @mouseup="upStop" @mousemove="upStop">
<img :src="rightUpUrl" alt="" @mousedown="rightUpStart" @mouseup="rightUpStop" @mousemove="rightUpStop">
</div>
<div class="direction-item">
<img :src="leftUrl" alt="" @mousedown="leftStart" @mouseup="leftStop">
<img :src="rightUrl" alt="" @mousedown="rightStart" @mouseup="rightStop">
</div>
<img :src="leftUrl" ondragstart="return false;" @mousedown="leftStart" @mouseup="leftStop" @mousemove="leftStop">
<img :src="rightUrl" ondragstart="return false;" @mousedown="rightStart" @mouseup="rightStop" @mousemove="rightStop">
</div>
<div class="direction-item">
<img :src="leftDownUrl" alt="" @mousedown="leftDownStart" @mouseup="leftDownStop">
<img :src="downUrl" alt="" @mousedown="downStart" @mouseup="downStop">
<img :src="rightDownUrl" alt="" @mousedown="rightDownStart" @mouseup="rightDownStop">
<img :src="leftDownUrl" alt="" @mousedown="leftDownStart" @mouseup="leftDownStop" @mousemove="leftDownStop">
<img :src="downUrl" alt="" @mousedown="downStart" @mouseup="downStop" @mousemove="downStop">
<img :src="rightDownUrl" alt="" @mousedown="rightDownStart" @mouseup="rightDownStop" @mousemove="rightDownStop">
</div>
</div>
</div>
</template>
</template>
<script>
export default {
data() {
@ -486,6 +486,10 @@ export default {
img {
width: 42px;
-webkit-user-select: none;
-ms-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
}
}

@ -1,123 +0,0 @@
class WebRtcPlayer {
static server = '127.0.0.1:8083';
webrtc = null;
video = null;
server = null;
codecLink = null;
rsdpLink = null;
stream = new MediaStream();
uuid = null;
options={
onStatusChange:null
};
constructor(video1, uuid, options={}) {
console.log("new uuid:"+uuid)
this.server = WebRtcPlayer.server;
//this.video = document.getElementById(id);
this.video = video1
this.uuid = uuid;
Object.assign(this.options, options);
this.createLinks();
this.play();
}
createLinks() {
this.codecLink = "//" + this.server + "/stream/codec/" + this.uuid
this.rsdpLink = "//" + this.server + "/stream/receiver/" + this.uuid
}
play() {
this.webrtc = new RTCPeerConnection({
iceServers: [{
urls: ["stun:stun.l.google.com:19302"]
}]
});
if(this.webrtc){
}else{
console.log("no")
}
this.webrtc.onnegotiationneeded = this.handleNegotiationNeeded.bind(this);
this.webrtc.ontrack = this.onTrack.bind(this);
fetch(this.codecLink)
.then((response) => {
response.json().then((data) => {
data.forEach((item, i) => {
this.webrtc.addTransceiver(item.Type, {
'direction': 'sendrecv'
});
});
});
})
.catch((error) => {
console.log(error);
});
this.webrtc.onconnectionstatechange = () => {
if(this.webrtc.connectionState == 'connected' || this.webrtc.connectionState == 'connecting'){
console.log("uuid:"+this.uuid+" status:" + this.webrtc.connectionState)
}else{
console.log(this.webrtc.connectionState)
this.load(this.uuid);
}
}
}
async handleNegotiationNeeded() {
let offer = await this.webrtc.createOffer();
await this.webrtc.setLocalDescription(offer);
let formData = new FormData();
formData.append('suuid', this.uuid);
formData.append('data', btoa(this.webrtc.localDescription.sdp));
fetch(this.rsdpLink, {
method: 'POST',
body: formData
})
.then((response) => {
response.text().then((data) => {
this.webrtc.setRemoteDescription(new RTCSessionDescription({
type: 'answer',
sdp: atob(data)
}))
});
})
.catch((err) => {})
}
onTrack(event) {
this.stream.addTrack(event.track);
this.video.srcObject = this.stream;
this.video.play();
}
load(uuid) {
this.destroy();
this.uuid = uuid;
this.createLinks();
this.play();
}
destroy() {
console.log("destroy uuid:"+this.uuid)
this.webrtc.close();
this.webrtc = null;
this.video.srcObject = null;
this.stream = new MediaStream();
}
getImageUrl() {
let canvas = document.createElement("canvas");
canvas.width = this.video.videoWidth;
canvas.height = this.video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
let dataURL = canvas.toDataURL();
canvas.remove();
return dataURL;
}
static setServer(serv) {
this.server = serv;
}
}
export default WebRtcPlayer;

@ -50,7 +50,7 @@ const columns = [
},
{
title: '条码',
dataIndex: 'code',
dataIndex: 'trayCode',
},
{

@ -1,8 +1,18 @@
<template>
<div>
<a-button type="primary" class="add" @click="showModel('add','')">
新增巷道
</a-button>
<div class="button-box">
<a-button type="primary" class="open" @click="confirmLight('open')">
打开全部光源
</a-button>
<a-button type="primary" class="close" @click="confirmLight('close')">
关闭全部光源
</a-button>
<a-button type="primary" @click="showModel('add','')">
新增巷道
</a-button>
</div>
<a-table
style="margin-top:40px"
:columns="columns"
@ -17,6 +27,24 @@
<span slot="rightType" slot-scope="text">
{{ text === null ? '-' : text === 0 ? '单伸' : '双伸' }}
</span>
<span slot="plc" slot-scope="text" v-if="text.plcIp">
{{ text.plcIp }}:{{text.plcPort}}
</span>
<span slot="lightSourceIp" slot-scope="text" v-if="text.lightSourceIp">
{{ text.lightSourceIp }}:{{text.lightSourcePort}}
</span>
<span slot="RFID" slot-scope="text" v-if="text.RFIDIp">
{{ text.RFIDIp }}:{{text.RFIDPort}}
</span>
<span slot="sensorGun" slot-scope="text">
<template>
<span v-if="text.rightSensorGunIp && text.leftSensorGunIp">{{text.leftSensorGunIp}}:{{text.leftSensorGunPort}} {{text.rightSensorGunIp}}:{{text.rightSensorGunPort}}</span>
<span v-else>
<span v-if="text.leftSensorGunIp">{{text.leftSensorGunIp}}:{{text.leftSensorGunPort}}</span>
<span v-if="text.rightSensorGunIp">{{text.rightSensorGunIp}}:{{text.rightSensorGunPort}}</span>
</span>
</template>
</span>
<span slot="actions" slot-scope="text">
<template>
<span v-if="text.camera1Name && text.camera2Name">{{text.camera1Name}} {{text.camera2Name}}</span>
@ -27,6 +55,14 @@
</template>
</span>
<span slot="action" slot-scope="text, record">
<a @click="openOneLight(record.id)">
打开光源
</a>
<a-divider type="vertical"/>
<a @click="closeOneLight(record.id)">
关闭光源
</a>
<a-divider type="vertical"/>
<a @click="showModel('edit',record)">
编辑
</a>
@ -46,6 +82,7 @@
@sure="submit"
@close="closeModel"
/>
</div>
</template>
@ -58,9 +95,29 @@ const columns = [
dataIndex: 'name',
},
{
title: 'PLC-ID',
title: '巷道标识',
dataIndex: 'plcId',
},
{
title: '库区',
dataIndex: 'area',
},
{
title: '光源IP',
scopedSlots: { customRender: 'lightSourceIp' }
},
{
title: 'plc',
scopedSlots: { customRender: 'plc' }
},
{
title: 'RFID',
scopedSlots: { customRender: 'RFID' }
},
{
title: '扫码枪',
scopedSlots: { customRender: 'sensorGun' }
},
{
title: '左货架类型',
dataIndex: 'leftType',
@ -103,11 +160,13 @@ export default {
columns,
visible:false,
modelTitle:'',
modelData:[]
modelData:[],
};
},
mounted() {
this.handleGetStreetList()
},
methods: {
handleGetStreetList(pagination) {
@ -145,10 +204,12 @@ export default {
this.modelData = data
}
},
submit(visible){
this.visible = visible
this.handleGetStreetList()
},
closeModel(visible,data){
this.visible = visible
this.modelData=data
@ -166,6 +227,80 @@ export default {
}).catch(err => {
})
},
confirmLight(type) {
const that = this
if(type == "open"){
this.$confirm({
title: "打开光源",
content: "确认打开光源?",
okText: '确认',
onOk() {
return new Promise((resolve, reject) => {
that.openLight();
setTimeout(resolve, 1000);
}).catch(() => console.log('Oops errors!'));
},
cancelText: '取消',
});
}else{
this.$confirm({
title: "关闭光源",
content: "确认关闭光源?",
okText: '确认',
onOk() {
return new Promise((resolve, reject) => {
that.closeLight();
setTimeout(resolve, 1000);
this.$message.success('已关闭光源');
}).catch(() => console.log('Oops errors!'));
},
cancelText: '取消',
});
}
},
openOneLight(streetId){
console.log("openOneLight"+streetId)
this.$axios.get('/street/lightSource/open/' + streetId, {
}).then(res => {
if(res.code==200){
this.$message.success('已打开光源');
}
}).catch(err => {
})
},
closeOneLight(streetId){
console.log("closeOneLight"+streetId)
this.$axios.get('/street/lightSource/close/' + streetId, {
}).then(res => {
if(res.code==200){
this.$message.success('已关闭光源');
}
}).catch(err => {
})
},
openLight(){
console.log("openLight")
this.$api.httpApi.openLight().then(res => {
}).catch(err => {
});
},
closeLight(){
this.$api.httpApi.closeLight().then(res => {
}).catch(err => {
});
}
},
components:{
@ -179,4 +314,18 @@ export default {
top:20px;
right: 40px;
}
.button-box{
position: absolute;
top:20px;
right: 40px;
display: flex;
align-items: center;
justify-content: center;
.open{
margin-right: 15px;
}
.close{
margin-right: 15px;
}
}
</style>

@ -25,16 +25,49 @@
v-decorator="['plcId', { rules: [{ required: true, message: '请输入巷道标识!' }] }]"
/>
</a-form-item>
</div>
<div class="across-layout">
<a-form-item label="库区" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['area']"
/>
</a-form-item>
</div>
<div class="across-layout">
<a-form-item label="PLC IP" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['plcIp', { rules: [{ message: '请输入PLC IP地址!' }] }]"
v-decorator="['plcIp']"
/>
</a-form-item>
<a-form-item label="PLC PORT" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['plcPort', { rules: [{ message: '请输入端口!' }] }]"
v-decorator="['plcPort']"
/>
</a-form-item>
</div>
<div class="across-layout">
<a-form-item label="光源IP" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['lightSourceIp']"
/>
</a-form-item>
<a-form-item label="光源 PORT" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['lightSourcePort']"
/>
</a-form-item>
</div>
<div class="across-layout">
<a-form-item label="RFID IP" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['RFIDIp']"
/>
</a-form-item>
<a-form-item label="RFID PORT" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['RFIDPort']"
/>
</a-form-item>
</div>
@ -42,6 +75,7 @@
<div class="leftType">
<h3>左货架</h3>
<a-form-item label="类型" :label-col="formItemVerticalLayout.labelCol">
<a-select
v-decorator="[
@ -73,22 +107,16 @@
/>
</a-form-item>
</div>
<div class="across-layout" v-if="leftType =='0'">
<a-form-item label="货架号" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['leftShelveId', { rules: [{ required: true, message: '请输入货架号!' }] }]"
/>
</a-form-item>
</div>
<div class="across-layout" v-if="leftType =='1'">
<a-form-item label="内货架号" :label-col="formItemAcrossLayout.labelCol">
<div class="across-layout">
<a-form-item label="扫码枪IP" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['leftInsideShelveId', { rules: [{ required: true, message: '请输入内货架号!' }] }]"
v-decorator="['leftSensorGunIp']"
/>
</a-form-item>
<a-form-item label="外货架号" :label-col="formItemAcrossLayout.labelCol">
<a-form-item label="扫码枪PORT" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['leftOutsideShelveId', { rules: [{ required: true, message: '请输入外货架号!' }] }]"
v-decorator="['leftSensorGunPort']"
/>
</a-form-item>
</div>
@ -128,29 +156,22 @@
/>
</a-form-item>
</div>
<div class="across-layout" v-if="rightType =='0'">
<a-form-item label="货架号" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['rightShelveId', { rules: [{ required: true, message: '请输入货架号!' }] }]"
/>
</a-form-item>
</div>
<div class="across-layout" v-if="rightType =='1'">
<a-form-item label="内货架号" :label-col="formItemAcrossLayout.labelCol">
<div class="across-layout">
<a-form-item label="扫码枪IP" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['rightInsideShelveId', { rules: [{ required: true, message: '请输入内货架号!' }] }]"
v-decorator="['rightSensorGunIp']"
/>
</a-form-item>
<a-form-item label="外货架号" :label-col="formItemAcrossLayout.labelCol">
<a-form-item label="扫码枪PORT" :label-col="formItemAcrossLayout.labelCol">
<a-input
v-decorator="['rightOutsideShelveId', { rules: [{ required: true, message: '请输入外货架号!' }] }]"
v-decorator="['rightSensorGunPort']"
/>
</a-form-item>
</div>
<a-divider></a-divider>
</div>
<div v-if="cameraList.length>0">
<a-form-item label="球机1" :label-col="formItemVerticalLayout.labelCol">
<a-form-item label="左侧球机" :label-col="formItemVerticalLayout.labelCol">
<a-select
v-decorator="[
'camera1Id',
@ -163,7 +184,7 @@
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="球机2" :label-col="formItemVerticalLayout.labelCol">
<a-form-item label="右侧球机" :label-col="formItemVerticalLayout.labelCol">
<a-select
v-decorator="[
'camera2Id',
@ -177,7 +198,7 @@
</a-form-item>
</div>
<div v-else>
<a-form-item label="球机1" :label-col="formItemVerticalLayout.labelCol">
<a-form-item label="左侧球机" :label-col="formItemVerticalLayout.labelCol">
<a-select
v-decorator="[
'camera1Name',
@ -190,7 +211,7 @@
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="球机2" :label-col="formItemVerticalLayout.labelCol">
<a-form-item label="右侧球机" :label-col="formItemVerticalLayout.labelCol">
<a-select
v-decorator="[
'camera2Name',
@ -242,6 +263,10 @@ export default {
plcId: newVal.plcId,
plcIp: newVal.plcIp,
plcPort: newVal.plcPort,
lightSourceIp: newVal.lightSourceIp,
lightSourcePort: newVal.lightSourcePort,
RFIDIp: newVal.RFIDIp,
RFIDPort: newVal.RFIDPort,
leftType: newVal.leftType === null ? '' : newVal.leftType === 0 ? '单伸' : '双伸',
leftRow: newVal.leftRow,
leftColumn: newVal.leftColumn,
@ -254,10 +279,15 @@ export default {
rightShelveId: newVal.rightShelveId,
rightInsideShelveId:newVal.rightInsideShelveId,
rightOutsideShelveId:newVal.rightOutsideShelveId,
camera1Id:newVal.camera1Name,
camera2Id:newVal.camera2Name,
leftSensorGunIp:newVal.leftSensorGunIp,
rightSensorGunIp:newVal.rightSensorGunIp,
leftSensorGunPort:newVal.leftSensorGunPort,
rightSensorGunPort:newVal.rightSensorGunPort,
camera1Id:newVal.camera1Id,
camera2Id:newVal.camera2Id,
camera1Name:newVal.camera1Name,
camera2Name:newVal.camera2Name
camera2Name:newVal.camera2Name,
area:newVal.area
})
})
}
@ -372,13 +402,10 @@ export default {
this.rightType = value //data
},
handleSelectCamera(){
this.$api.httpApi.getCameraList({
data: {
pageNum:0,
pageSize:0,
}
this.$api.httpApi.getAllCameras({
}).then(res => {
this.cameraList = res.data.list;
this.cameraList = res.data;
}).catch(err => {
});

@ -0,0 +1,276 @@
<template>
<div class="subsection">
<a-layout style="width: 1500px">
<a-layout style="width: 100%;height: 310px">
<a-layout-sider width="110px">
<a-tabs default-active-key="1" tab-position="left" @change="changeTabLeft" v-if="total.row > nums.row">
<a-tab-pane
v-for="index in latticeRow"
:key="index"
>
<span slot="tab" >
{{ getRandom(latticeRow + 1 -index, latticeRow, nums.row, total.row) }}
</span>
</a-tab-pane>
</a-tabs>
</a-layout-sider>
<a-layout-content>
<!-- <slot :data="{select, nums, random}"></slot> -->
<div class="roadway-buttom">
<div class="roadway-box">
<div class="line" v-for="(row,rowIndex) in total.row" :key="rowIndex" v-if="row >= random.row[0] && row <= random.row[1]">
<div v-for="(column,index) in total.column" :key="index" class="el" v-if="column >= random.column[0] && column <= random.column[1]">
<!--渲染默认巷道框架规格 定位浮在 已有巷道上做对应-->
<span style="background:#bfbfbf;"
class="default"
:id="`${direction}-${side}-${random.row[0] + random.row[1] - rowIndex - 1}-${column}`"
@click="toStockPage(random.row[0] + random.row[1] - rowIndex - 1,column)">
{{ random.row[0] + random.row[1] - rowIndex - 1}}-{{column}}
</span>
</div>
</div>
</div>
</div>
</a-layout-content>
</a-layout>
<a-layout-footer>
<!-- <a-tabs default-active-key="1" tab-position="bottom" @change="value => select.row = value" v-if="total.row > nums.row"> -->
<a-tabs default-active-key="1" tab-position="bottom" @change="changeTab" v-if="total.column > nums.column">
<a-tab-pane
v-for="index in latticeColumn"
:key="index"
>
<span slot="tab">
{{ getRandom(index, latticeColumn, nums.column, total.column) }}
</span>
</a-tab-pane>
</a-tabs>
</a-layout-footer>
</a-layout>
</div>
</template>
<script>
export default {
name: "Subsection",
components: {},
props: {
//
select: {
type: Object,
default: () => {
return {
row: 1,
column: 1
}
}
},
//
total:{
type: Object,
default:()=>{
return {}
}
},
nums: {
type: Object,
default: () => {
return {
row: 10,
column: 15
}
}
},
//
direction:{
type: Number,
default: () => {
return {}
}
},
//
side:{
type: Number,
default: () => {
return {}
}
},
streetId: {
type: Number,
default: () => {
return {}
}
},
streetName: {
type: String,
default: () => {
return {}
}
},
},
computed: {
//
latticeRow() {
return parseInt(this.total.row / this.nums.row) + (this.total.row % this.nums.row > 0 ? 1 : 0);
},
latticeColumn() {
return parseInt(this.total.column / this.nums.column) + (this.total.column % this.nums.column > 0 ? 1 : 0);
},
random() {
return {
row: this.getRandomRow(this.select.row),
column: this.getRandomColumn(this.select.column),
}
},
},
data() {
return {
status: {
row: {},
column: {}
},
}
},
mounted() {
},
beforeDestroy() {
},
created() {
},
destroyed() {
},
methods: {
changeTab(value){
this.select.column = value
},
changeTabLeft(value){
this.select.row = value
},
//
getRandom(index, lattice, num, total) {
if(index !== lattice) {
return `${(index - 1) * num + 1} - ${index * num}`;
}else {
return `${(index - 1) * num + 1} - ${total}`;
}
},
//
getRandomRow(val) {
console.log(this.latticeRow + 1 - val, this.latticeRow, this.nums.row, this.total.row)
return this.getRandom(this.latticeRow + 1 - val, this.latticeRow, this.nums.row, this.total.row).split(' - ').map(item => Number(item));
},
getRandomColumn(val) {
return this.getRandom(val, this.latticeColumn, this.nums.column, this.total.column).split(' - ').map(item => Number(item));
},
toStockPage(row,column){
this.$router.push({
name: 'stockLogDetail',
query: {row: row, column: column, direction: this.direction,side:this.side,streetId:this.streetId}
})
}
}
}
</script>
<style scoped lang="scss">
.subsection /deep/{
width: 100%;
height: 360px;
overflow: hidden;
.ant-tabs-nav .ant-tabs-tab {
// padding: 0;
margin-right: 0;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
&:hover{
background: #40a9ff;
border-color: #40a9ff;
}
background: #40a9ff;
border-color: #40a9ff;
box-shadow: -1px 0 0 0 #40a9ff;
}
.ant-radio-button-wrapper-checked {
box-shadow: -1px 0 0 0 #40a9ff;
}
.radio-button-cell {
width: 100px;
text-align: center;
}
.ant-layout-sider {
height: 100%;
.ant-tabs {
height: 300px;
}
.ant-tabs-tab {
padding: 8px;
margin-bottom: 5px;
width: 104px;
}
}
.ant-layout-footer {
// width: 500px;
padding: 0 0 0 110px;
.ant-tabs {
// width: 735px;
}
.ant-tabs-bottom-bar {
margin-top: 0;
}
}
.ant-layout, .ant-layout-sider, .ant-layout-footer {
background-color: #ffffff;
}
roadway-buttom {
padding: 5px 0;
width: 100%;
}
.roadway-box {
//transform: rotateX(180deg);
padding: 10px 10px 0 0;
.line {
display: flex;
//transform: rotateX(180deg); //div
.el {
width: 46px;
height: 25px;
line-height: 25px;
margin: 2px;
font-size: 12px;
text-align: center;
border-radius: 4px;
cursor: pointer;
position: relative;
.default {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
}
}
}
</style>

@ -0,0 +1,215 @@
<template>
<div class="check-page">
<div style="margin-top: 10px">
<a-select @change="handleChange" style="width:200px" v-model="select">
<a-select-option v-for="i in data" :key="i.name" :value="i.id">
{{i.name}}
</a-select-option>
</a-select>
</div>
<!--左货架DOM-->
<div class="center-box">
<span class="shelf-number">
左侧货架
</span>
<a-radio-group v-model="leftSide" style="margin:10px 0"
v-if="streetDetail.leftType==1">
<a-radio-button :value=1>
浅货架
</a-radio-button>
<a-radio-button :value=2>
深货架
</a-radio-button>
</a-radio-group>
</div>
<div class="check-content" v-for="item in data" :key="item.id">
<subsection v-if="item.id == select" :total="{row: item.leftRow, column: item.leftColumn}" :direction=1 :side="leftSide" :streetId="item.id" :streetName="item.name">
</subsection>
</div>
<!--单伸类型右货架DOM-->
<div class="center-box">
<span class="shelf-number">
右侧货架
</span>
<a-radio-group v-model="rightSide" style="margin:10px 0"
v-if="streetDetail.rightType==1">
<a-radio-button :value=1>
浅货架
</a-radio-button>
<a-radio-button :value=2>
深货架
</a-radio-button>
</a-radio-group>
</div>
<div class="check-content" v-for="item in data" :key="item.name">
<subsection v-if="item.id == select" :total="{row:item.rightRow, column: item.rightColumn}" :direction=2 :side="rightSide" :streetId="item.id" :streetName="item.name" >
</subsection>
</div>
</div>
</template>
<script>
import Subsection from "./Subsection";
export default {
name:'checkManage',
data() {
return {
leftSide: 1,
rightSide: 1,
data: [],
select: '',
streetId: 0,
streetDetail: {},
}
},
computed: {
},
mounted() {
this.request();
},
created(){
},
activated() {
if(!this.$route.meta.isUseCache){
console.log("$route.meta.isUseCache false")
//
this.request();//
}else{
console.log("$route.meta.isUseCache true")
//this.request();
}
},
methods: {
//
request() {
this.$api.httpApi.getAllStreet({
}).then(res => {
console.log("update data")
for(let i = 0;i<res.data.length;i++){
this.$set(this.data,i,res.data[i])
}
this.select = res.data[0].id
//this.$set(this.select,res.data.list[0].id,0)
this.getStreetDetail(this.select);
}).catch(err => {
});
},
//
getStreetDetail(id) {
this.$axios.get('/street/' + id, {
data: {}
}).then(res => {
this.streetDetail = res.data
}).catch(err => {
})
},
handleChange(value) {
this.select = value
this.getStreetDetail(value)
},
},
components: {Subsection}
};
</script>
<style lang="scss" scoped>
.check-page {
position: relative;
.title-info {
display: flex;
align-items: center;
justify-content: start;
.explain {
font-weight: 600;
}
.info-text {
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
}
}
.ant-tag {
margin-right: 0;
display: block;
line-height: 25px;
text-align: center;
cursor: pointer;
}
.roadway-top, roadway-buttom {
padding: 5px 0;
width: 100%;
}
.roadway-box {
transform: rotateX(180deg);
padding: 10px 10px 0 0;
.line {
display: flex;
transform: rotateX(180deg); //div
.el {
width: 46px;
height: 25px;
line-height: 25px;
margin: 2px;
font-size: 12px;
text-align: center;
border-radius: 4px;
cursor: pointer;
position: relative;
.default {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
}
}
.center-box {
width: 500px;
height: 52px;
line-height: 52px;
.shelf-number {
display: inline-block;
width: 200px;
}
}
.export-all {
position: absolute;
right: 20px;
}
}
</style>

@ -0,0 +1,272 @@
<template>
<div >
<a-table
style="margin-top:40px"
:columns="columns"
:row-key="record => record.id"
:data-source="data"
:pagination="pagination"
@change="getStockPageInfo"
>
<span slot="type" slot-scope="record">
{{ statusMap[record.type] }}
</span>
<span slot="pic" slot-scope="text" style="width:auto">
<template>
<span style="height:100%;">
<happy-scroll color="rgba(100,100,100,0.5)" size="8" class="scroll-box" style="width:320px;height:90px;">
<viewer><img class="historyImg" :src="imgUrl+text.pic"/></viewer>
</happy-scroll>
</span>
</template>
</span>
</a-table>
</div>
</template>
<script>
import {imgUrl} from "@/api/importExcel";
const columns=[
{
title:'随行工单号',
dataIndex: 'orderNum'
},
{
title:'货架号',
dataIndex: 'shelveId'
},
{
title:'行',
dataIndex: 'row'
},
{
title:'列',
dataIndex: 'column'
},
{
title:'类型',
scopedSlots: {customRender: 'type'},
},
{
title:'图片',
scopedSlots: {customRender: 'pic'},
},
{
title:'时间',
dataIndex: 'createTime'
},
]
export default {
data() {
return {
pageNum:1,
pageSize:10,
data: [],
pagination:{
total:0,
defaultPageSize:10, //
showTotal: total => `${total} 条数据`, //
showSizeChanger:true, //
pageSizeOptions: ['10', '20', '30'],
onShowSizeChange:(current, pageSize)=>this.pageSize = pageSize //
},
row: 0,
column: 0,
direction:0,
side:0,
columns,
statusMap: {0:"未知",1:"取货到位",2:"取货完成",3:"放货到位",4:"放货完成"},
}
},
beforeRouteLeave(to ,form, next) {
// created
this.$destroy();
// if (to.name == 'checkManage') {
// to.meta.isUseCache = true;
// }else{
// to.meta.isUseCache = false;
// }
next();
},
created() {
this.imgUrl = imgUrl
if (this.$route.query.row && this.$route.query.column && this.$route.query.side && this.$route.query.direction && this.$route.query.streetId) {
this.row = this.$route.query.row
this.column = this.$route.query.column
this.side = this.$route.query.side
this.direction = this.$route.query.direction
this.streetId = this.$route.query.streetId
}
},
mounted() {
this.getStockPageInfo()
},
destroyed () {
},
methods: {
getStockPageInfo(pagination) {
if(pagination){
this.pagination.current = pagination.current;
this.pagination.pageSize = pagination.pageSize;
this.pageNum = pagination.current;
this.pageSize = pagination.pageSize;
}
this.request();
},
request(){
this.$api.httpApi.getStockPage({
data: {
pageNum:this.pageNum,
pageSize:this.pageSize,
row:this.row,
column:this.column,
side:this.side,
direction:this.direction,
streetId:this.streetId
}
}).then(res => {
const pagination = { ...this.pagination };
pagination.total = res.data.total;
this.data = res.data.list;
this.pagination = pagination;
}).catch(err => {
});
},
}
}
</script>
<style lang="scss">
.ant-carousel .slick-slide {
color: #000000;
}
.checkOperation {
.carousel-page {
width: 100%;
/*border: solid 1px blue;*/
&-title {
color: #009FE3;
font-size: 16px;
margin: 0;
padding: 15px 0 10px 25px;
}
&-content {
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 25px;
.img-box {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 17px;
height: 400px;
margin-right: 10px;
img {
height: 100%
}
p {
height: 25px;
}
ul {
width: 100% / 4;
height: 100%;
margin-bottom: 0;
padding-inline-start: 0;
li {
background-color: #ffaf11;
margin: 10px 0;
padding: 5px;
font-size: 16px;
font-weight: 600;
color: #494e52;
.img-box-title {
width: 130px;
display: inline-block;
}
.img-box-value {
display: inline-block;
width: calc(100% - 130px);
overflow: hidden;
position: relative;
top: 5px;
}
}
}
}
}
&-footer {
width: calc(100% - 380px);
.info-box {
color: #000000;
display: flex;
align-items: center;
justify-content: center;
p {
padding: 0 20px;
font-size: 18px;
}
}
.status {
text-align: center;
font-size: 21px;
}
.status-btn {
display: flex;
align-items: flex-start;
justify-content: flex-start;
.btn {
padding: 50px;
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
line-height: 0;
margin: 15px 45px;
}
}
}
}
.bottom-btn {
width: 100%;
display: flex;
align-items: right;
justify-content: center;
p {
font-size: 18px;
padding: 0;
margin: 0;
}
.btn {
margin: 25px;
}
}
}
.historyImg {
width: 180px;
height:auto;
}
</style>

@ -0,0 +1,409 @@
<template>
<a-row type="flex" :gutter="30">
<a-col :flex="1">
时间<a-date-picker v-model="date" format="YYYY-MM-DD" placeholder="请选择时间" @change="cameraRecord"/>
<section style="height: 80vh;overflow: hidden;
overflow-y: scroll;">
<a-tree
:tree-data="treeData"
:check-strictly="true"
@select="handleCheck">
</a-tree>
</section>
</a-col>
<a-col :flex="13">
<div>
<div class="time-display">
<!-- 视频 -->
<video ref="videoPlayer" muted style=" display: flex;" width="100%" >
<source :src="currentVideoUrl" type="video/mp4" />
</video>
</div>
<!-- 滑动轴 -->
<div class="zoom-buttons" width="100%" >
<a-button-group>
<a-button icon="arrows-alt" :disabled="zoom" @click="handleZoomIn"></a-button>
<a-button icon="shrink" :disabled="shrink" @click="handleZoomOut"></a-button>
</a-button-group>
</div>
<a-slider
ref="slider"
:marks="marks"
class="progress-bar"
:max="totalDuration"
:tip-formatter="formatter"
:value="currentTime"
:disabled="Object.keys(urls).length === 0"
@change="onSliderChange"
/>
<div class="time-display">
<a-button-group>
<a-button icon="step-backward" :disabled="Object.keys(urls).length === 0" @click="moveForward(-5)" />
<a-button v-if="isPlaying" :disabled="Object.keys(urls).length === 0" icon="pause" @click="pauseVideo" />
<a-button v-else icon="play-circle" :disabled="Object.keys(urls).length === 0" @click="playVideo" />
<a-button icon="step-forward" :disabled="Object.keys(urls).length === 0" @click="moveForward(5)" />
</a-button-group>
</div>
</div>
</a-col>
</a-row>
</template>
<script>
import { Slider, Button, ButtonGroup } from 'ant-design-vue';
import moment from 'moment'
import { message } from 'ant-design-vue';
export default {
components: {
ASlider: Slider,
AButton: Button,
AButtonGroup: ButtonGroup,
},
data() {
return {
totalDuration: 24*60*60, // 60s
//
currentTime: 0,
//
startTimeLong: 0,
//
endTimeLong: 24*60*60,
//
maxTimeLong:24*60*60,
//
minTimeLong: 0*60*60,
date: this.getYesterday() ,
currentVideoUrl: '', // URL
value1: '2023-10-11',
urls:{
},
URLStartTime: 0,
isPlaying: false, //
marks:{},
zoom:false,
shrink:true,
treeData: [],
cameraId:'',
};
},
mounted() {
const video = this.$refs.videoPlayer;
video.addEventListener('timeupdate', this.onVideoTimeUpdate);
video.addEventListener('ended', this.playNextVideo);
console.log(this.getTimeMap());
this.totalDuration = this.endTimeLong -this.startTimeLong;
this.marks = this.getTimeMap();
console.log(this.date);
this.getTree()
this.cameraRecord()
},
beforeDestroy() {
const video = this.$refs.videoPlayer;
video.removeEventListener('timeupdate', this.onVideoTimeUpdate);
video.removeEventListener('ended', this.playNextVideo);
},
methods: {
getYesterday(){
const now = moment();
return now.subtract(1, 'days')
},
scaleTime(rate) {
const middle = this.startTimeLong +this.currentTime;
//
const startToMiddleMs = middle - this.startTimeLong;
//
const endToMiddleMs = this.endTimeLong - middle;
//
const scaledStart = middle -Math.floor( startToMiddleMs * rate);
console.log("开始缩小时间"+ scaledStart);
//
const scaledEnd =middle +Math.floor( endToMiddleMs * rate);
console.log("结束缩小时间"+ scaledEnd);
//
this.startTimeLong = this.minTimeLong>scaledStart?this.minTimeLong : scaledStart;
this.endTimeLong = this.maxTimeLong<scaledEnd?this.maxTimeLong : scaledEnd;
//
if(this.minTimeLong<scaledStart || this.maxTimeLong>scaledEnd){
this.shrink=false;
}else{
this.shrink=true;
}
console.log("zhou"+middle);
this.updateslider(middle)
},
formatTime(seconds) {
seconds = seconds%(60*60*24);
const hour = Math.floor(seconds / 3600);
const minute = Math.floor((seconds % 3600) / 60);
const second = seconds % 60;
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}`;
},
//
handleZoomIn() {
this.scaleTime(0.5)
},
//
handleZoomOut() {
this.scaleTime(2)
},
//
updateslider(middle){
this.totalDuration = this.endTimeLong - this.startTimeLong;
console.log("轴上数值为:"+(middle-this.startTimeLong));
this.currentTime = (middle-this.startTimeLong);
this.marks = this.getTimeMap();
},
getTree(){
this.$api.httpApi.getAllStreet({
}).then(res => {
console.log("update data")
for(let i = 0;i<res.data.length;i++){
//
const obj = {};
//
obj["title"] = res.data[i].name;
obj["key"] = res.data[i].id;
obj["type"] = 0
obj["children"] =[];
if( res.data[i].camera1Id !=""){
const obj1 = {};
obj1["title"] = res.data[i].camera1Name
obj1["key"] = res.data[i].camera1Id
obj1["type"] = 1
obj["children"].push(obj1)
}
if( res.data[i].camera2Id !=""){
const obj1 = {};
obj1["title"] = res.data[i].camera2Name
obj1["key"] = res.data[i].camera2Id
obj1["type"] = 1
obj["children"].push(obj1)
}
this.treeData.push(obj)
}
console.log(this.treeData);
}).catch(err => {
});
},
getTimeMap() {
const diff = this.endTimeLong - this.startTimeLong; //
console.log(diff + " qqq");
const map = {};
if (diff >= 60 * 60 * 3) {
this.TimeMapErgodic(60*60,map);
} else if (diff >= 60 * 60) {
// 1315
this.TimeMapErgodic(15*60,map);
} else if (diff >= 60*20) {
this.zoom = false;
// 2015
this.TimeMapErgodic(5*60,map);
} else if (diff >= 5* 60) {
this.zoom = false;
// 520
this.TimeMapErgodic(60,map);
} else if (diff >= 30) {
this.zoom = false;
// 51m30s
console.log("如果小于5分钟大于1m每30s一个标识");
console.log(startTime +" "+endTime)
this.TimeMapErgodic(30,map);
} else if (diff >= 10) {
this.zoom = true;
// 1m10s 5s
this.TimeMapErgodic(5,map);
} else {
this.zoom = true;
// 10s 1s
this.TimeMapErgodic(1,map);
}
return map;
},
//time
TimeMapErgodic(interval,map){
const startTime =Math.ceil(this.startTimeLong/(interval)) *interval;
const endTime =Math.floor(this.endTimeLong/(interval))*interval;
for (let i = startTime ; i<= endTime; i+=interval) {
const minuteDiff = (i - this.startTimeLong) ;
map[minuteDiff] = `${String(Math.floor(i/(60*60))).padStart(2, '0')}:${String(Math.floor((i%(60*60))/(60))).padStart(2, '0')}:${String((i%(60))).padStart(2, '0')}`;
}
return map;
},
//
formatter(value) {
const i = this.startTimeLong + value
//
const hours = String(Math.floor(i/(60*60))).padStart(2, '0');
const minutes = String(Math.floor((i%(60*60))/(60))).padStart(2, '0');
const seconds = String(Math.floor((i%(60)))).padStart(2, '0');
return `${hours}:${minutes}:${seconds}`;
},
//
binarySearchMax(arr, target) {
let left = 0;
let right = arr.length - 1;
let max = -Infinity;
console.log(arr);
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] <= target) {
max = Math.max(max, arr[mid]);
left = mid + 1;
} else {
right = mid - 1;
}
}
return max;
},
//
onSliderChange(value) {
console.log(value);
this.URLStartTime = this.binarySearchMax(Object.keys(this.urls),value+this.minTimeLong);
this.currentVideoUrl = this.urls[this.URLStartTime]
this.currentTime = value;
const video = this.$refs.videoPlayer;
video.currentTime = value +this.startTimeLong-this.URLStartTime ;
},
//
onVideoTimeUpdate() {
const video = this.$refs.videoPlayer;
console.log("视频时间"+(this.URLStartTime + video.currentTime));
this.currentTime =this.URLStartTime + video.currentTime-this.startTimeLong;
},
//
moveForward(duration) {
console.log("111");
const newTime = this.currentTime + duration;
if (newTime >= 0 ||newTime <= this.totalDuration) {
this.currentTime = newTime;
const video = this.$refs.videoPlayer;
video.currentTime = newTime;
}
},
playVideo() {
const video = this.$refs.videoPlayer;
this.isPlaying = true;
console.log( this.currentTime +this.startTimeLong - this.URLStartTime);
video.currentTime = this.currentTime +this.startTimeLong - this.URLStartTime
video.play();
},
pauseVideo() {
const video = this.$refs.videoPlayer;
this.isPlaying = false;
video.pause();
},
playNextVideo() {
let nextKey =this.URLStartTime;
const keys = Object.keys(this.urls);
//
const currentIndex = keys.indexOf(this.URLStartTime.toString());
console.log(keys);
if (currentIndex !== -1 && currentIndex < keys.length - 1) {
nextKey = Number(keys[currentIndex + 1]);
const video = this.$refs.videoPlayer;
this.URLStartTime = nextKey;
this.currentVideoUrl = this.urls[nextKey] ;
this.currentTime =this.URLStartTime;
video.currentTime =0;
video.play();
}
},
handleCheck(selectedKeys, e){
if(e.selectedNodes[0].data.props.type == 1){
this.cameraId = e.selectedNodes[0].data.key;
console.log(e.selectedNodes[0].data);
this.cameraRecord()
}
console.log(e.selectedNodes[0].data.props);
},
cameraRecord(){
this.$api.httpApi.cameraRecord({
data: {
date: this.date._d.getFullYear() + '-' + (this.date._d.getMonth() + 1) + '-' + this.date._d.getDate(),
cameraId: this.cameraId,
}
}).then(res => {
console.log("update data")
if( (res.data.startTimeLong !== null && res.data.startTimeLong !== undefined && res.data.startTimeLong !== "")
||( res.data.endTimeLong !== null && res.data.endTimeLong!== undefined &&res.data.endTimeLong !== '')){
}
if(res.data.urls !== null && res.data.urls !== undefined && Object.keys(res.data.urls).length >0){
this.startTimeLong = res.data.startTimeLong
this.endTimeLong = res.data.endTimeLong
this.minTimeLong = res.data.startTimeLong
this.maxTimeLong = res.data.endTimeLong
this.currentTime = 0
this.totalDuration = res.data.endTimeLong - res.data.startTimeLong
this.currentVideoUrl = res.data.urls[0].url
const video = this.$refs.videoPlayer;
video.currentTime = 0 ;
const map = {};
for(let i = 0;i<res.data.urls.length;i++){
map[res.data.urls[i].startTimeLong] = res.data.urls[i].url
}
this.urls = map
this.marks = this.getTimeMap();
}else{
if(this.cameraId !== null && this.cameraId !== undefined && this.cameraId !== ""){
message.info('此摄像头该日期未录像');
}
}
}).catch(err => {
console.log(err);
});
}
},
};
</script>
<style>
.progress-bar .ant-slider-rail {
background-color: lightgray;
}
.progress-bar .ant-slider-track {
background-color: dodgerblue;
}
.time-display {
margin-top: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.zoom-buttons {
text-align: right;
margin-bottom: 16px;
}
</style>

@ -0,0 +1,321 @@
<template>
<div id="videos">
<a-tree-select
v-model="value"
show-search
style="width: 80%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="Please select"
allow-clear
multiple
tree-default-expand-all
>
<a-tree-node key="0-1" value="parent 1" title="parent 1">
<a-tree-node key="0-1-1" :selectable="false" value="parent 1-0" title="parent 1-0">
<a-tree-node key="random" value="leaf1" title="my leaf" />
<a-tree-node key="random1" value="leaf2" title="your leaf" />
</a-tree-node>
<a-tree-node key="random2" value="parent 1-1" title="parent 1-1">
<a-tree-node key="random3" value="sss">
<b slot="title" style="color: #08c">sss</b>
</a-tree-node>
</a-tree-node>
</a-tree-node>
<a-tree-node key="random2" value="leaqf1" title="my 1leaf" />
<a-tree-node key="random13" value="leawf2" title="your2 leaf" />
<a-tree-node key="random4" value="leaef1" title="my l3eaf" />
<a-tree-node key="random15" value="learf2" title="your4 leaf" />
<a-tree-node key="random6" value="leatf1" title="my 6leaf" />
<a-tree-node key="random17" value="leayuf2" title="you5r leaf" />
<a-tree-node key="random8" value="leauf1" title="my 7leaf" />
<a-tree-node key="random19" value="loeaf2" title="yousr leaf" />
<a-tree-node key="random0" value="lieaf1" title="myf leaf" />
<a-tree-node key="randoma1" value="lexaf2" title="yodur leaf" />
<a-tree-node key="randoms" value="leacf1" title="my cleaf" />
<a-tree-node key="randoms1" value="leavf2" title="yobur leaf" />
<a-tree-node key="randomd" value="lnaf1" title="mvy leaf" />
<a-tree-node key="random1f" value="lebaf2" title="y our leaf" />
<a-tree-node key="randomg" value="leamf1" title="myx leaf" />
<a-tree-node key="random1h" value="leaff2" title="your leaf" />
<a-tree-node key="randomz" value="wleaf2" title="your leaf" />
<a-tree-node key="randomc" value="wleaf1" title="my cleaf" />
<a-tree-node key="random1v" value="eleaf2" title="your levaf" />
</a-tree-select>
<a-button type="primary" @click="full" v-if="!isFullscreen"> <a-icon type="right" /> </a-button>
<a-button type="primary" @click="full" v-if="isFullscreen"><a-icon type="left" /> 退出全屏 </a-button>
<!-- @change="tabsChange" v-model="tabKey"-->
<a-row v-for='rowIndex in row' :key='rowIndex'>
<a-col v-for='colIndex in column' :key='colIndex' :span="24/column" :style="{height: videoHeight}" >
<WebrtcPlayer
v-if=" webrtcPlayers[rowIndex-1] !==undefined && webrtcPlayers[rowIndex-1] != null && webrtcPlayers[rowIndex-1].length > 0 && webrtcPlayers[rowIndex-1][colIndex-1] !==undefined && webrtcPlayers[rowIndex-1][colIndex-1] != null "
autoplay class="video-window"
:videoSrc="'http://127.0.0.1/index/api/webrtc?app=live&stream='+webrtcPlayers[rowIndex-1][colIndex-1].id+'&type=play'"
:videoId="'videoId'+colIndex+'-'+rowIndex"
ref="videoWindow"
:key="colIndex+'-'+rowIndex"
muted
:style="{'height': '100%',width:'100%','object-fit':'fill'}">
</WebrtcPlayer>
<!-- <video class="camera" :id="rowIndex+'-'+colIndex" autoplay muted :style="{'height': '100%',width:'100%','object-fit':'fill'}" ></video> -->
</a-col>
</a-row>
</div>
</template>
<script>
//import ATreeSelect from "../../../public/static/webrtcplayer"
import { TreeSelect } from 'ant-design-vue';
import { defineComponent, ref, watch } from 'vue';
import WebrtcPlayer from '../../../public/webrtc/webrtcPlayer.vue'
export default {
name: 'top',
components: {
WebrtcPlayer,
ATreeSelect: TreeSelect
},
props: {
id: {
type: String,
default () {
return ''
}
}
},
data () {
return {
row : 0,
column : 0,
value: undefined,
treeExpandedKeys: [],
a: 0,
clientHeight: 0,
videoH: 0,
isFullscreen: false,
originHeight: 0,
fullHeight: 0,
players: [],
areas:[],
webrtcPlayers: [],
activeKey: ''
}
},
//watch: {},
computed: {
videoHeight() {
return( this.clientHeight/ this.row ) + 'px';
}
},
destroyed() {
this.destory()
},
mounted () {
this.getWallStyle();
this.$nextTick(() => {
this.getAllCameras()
});
let isFullscreen =
document.fullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement ||
document.fullScreen ||
document.mozFullScreen ||
document.webkitIsFullScreen;
this.isFullscreen = !!isFullscreen;
let that = this;
document.addEventListener("fullscreenchange", () => {
that.isFullscreen = !that.isFullscreen;
});
document.addEventListener("mozfullscreenchange", () => {
that.isFullscreen = !that.isFullscreen;
});
document.addEventListener("webkitfullscreenchange", () => {
that.isFullscreen = !that.isFullscreen;
});
document.addEventListener("msfullscreenchange", () => {
that.isFullscreen = !that.isFullscreen;
});
},
methods: {
getWallStyle(){
this.$api.httpApi.getWallStyle({
data: {}
}).then(res => {
if(res.code == 200) {
this.row = res.data[0];
this.column = res.data[1];
this.getClientHeight();
sessionStorage.setItem('originHeight', this.clientHeight)
}
}).catch(err => {
console.log(err)
})
},
getClientHeight() {
this.clientHeight = this.$el.clientHeight-40;
console.log("clientHeight:"+this.clientHeight)
},
getAllCameras(){
this.$api.httpApi.getAllCameras({
data: {}
}).then(res => {
if(res.code == 200) {
let cameras = res.data;
this.webrtcPlayers = Array.from({ length: this.row }, () => []);
for(let i = 1;i<=cameras.length;i++){
let rowIndex = Math.floor((i-1) / this.column) + 1;
if(rowIndex > this.row){
return
}
let columnIndex = i % this.column;
if(columnIndex == 0){
columnIndex = this.column;
}
this.webrtcPlayers[rowIndex-1].push(cameras[i-1]);
let idName = rowIndex + "-" + columnIndex;
console.log("idName:"+idName);
//console.log(this.webrtcPlayers);
//let server = cameras[i-1].rtcServer+":"+ cameras[i-1].rtcServerPort
//let video = document.getElementById(idName);
//let player = new WebRtcPlayer(server,video,"camera"+cameras[i-1].id);
//this.players.push(player);
}
}
}).catch(err => {
console.log(err)
})
},
getAllAreas(){
this.$api.httpApi.getAllAreas({
data: {}
}).then(res => {
if(res.code == 200) {
this.areas = res.data;
if(this.areas.length == 0){
this.getAllCameras()
}else{
this.activeKey = this.areas[0]
this.tabChange();
}
}
}).catch(err => {
console.log(err)
})
},
destory(){
for(let player of this.players){
console.log("stop")
player.destroy()
}
this.players = []
},
tabChange(){
this.destory();
this.$api.httpApi.allCamerasByArea({
params:{
area:this.activeKey
}
}).then(res => {
if(res.code == 200) {
let cameras = res.data;
for(let i = 1;i<=cameras.length;i++){
let rowIndex = Math.floor((i-1) / this.column) + 1;
if(rowIndex > this.row){
return
}
let columnIndex = i % this.column;
if(columnIndex == 0){
columnIndex = this.column;
}
let idName = rowIndex + "-" + columnIndex;
console.log("idName:"+idName);
let server = cameras[i-1].rtcServer+":"+ cameras[i-1].rtcServerPort
let video = document.getElementById(idName);
let player = new WebRtcPlayer(server,video,"camera"+cameras[i-1].id);
this.players.push(player);
}
}
}).catch(err => {
console.log(err)
})
},
full () {
if(this.isFullscreen){
this.exitfullscreen()
}else{
this.enterfullscreen()
}
},
//
enterfullscreen () { //
var docElm = document.getElementById('videos') // id
//W3C
if (docElm.requestFullscreen) {
docElm.requestFullscreen()
}
//FireFox
else if (docElm.mozRequestFullScreen) {
docElm.mozRequestFullScreen()
}
//Chrome
else if (docElm.webkitRequestFullScreen) {
docElm.webkitRequestFullScreen()
}
//IE11
else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen()
}
this.$nextTick(() => {
this.clientHeight = document.body.clientHeight;
console.log("full:"+document.body.clientHeight)
})
},
//退
exitfullscreen () {
console.log("tuichu");
if (document.exitFullscreen) {
document.exitFullscreen()
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen()
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen()
} else if (document.msExitFullscreen) {
document.msExitFullscreen()
}
this.$nextTick(() => {
let origin = sessionStorage.getItem('originHeight');
if(origin){
this.clientHeight = origin;
}else{
this.getClientHeight();
}
})
}
}
}
</script>
<style>
/* #videos > .ant-row {
height: calc(100% / 8);
}
#videos > .ant-row > .ant-col{
height: calc(100% / 8);
} */
</style>

@ -32,14 +32,14 @@ module.exports = {
}
},
'/api/pic': {
target: 'http://127.0.0.1:9007/api/pic',
target: 'http://192.168.77.91:9007/api/pic',
logLevel:'debug',
pathRewrite:{
'/api/pic':''
}
},
'/api/mp4': {
target: 'http://127.0.0.1:9007/api/mp4',
target: 'http://192.168.77.91:9007/api/mp4',
logLevel:'debug',
pathRewrite:{
'/api/mp4':''

Loading…
Cancel
Save