2022-06-16 14:33:15 +08:00

1086 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="fullHeight page">
<img src="@/assets/images/inoutBigScreen/leftLine.png" class="leftLine" />
<img src="@/assets/images/inoutBigScreen/leftLine.png" class="rightLine" />
<img
src="@/assets/images/inoutBigScreen/bottomLine.png"
class="bottomLine"
/>
<div class="topHeader">
<div class="left">
<p class="date">{{ curDate }}</p>
<p>
<span>{{ curTime }}</span
><span>{{ curWeek }}</span>
</p>
</div>
<div class="projectName">
{{ $store.state.currentProDetail.projectName }}
</div>
<div class="tempBox">
<span>{{ weatherInfo.temperature }}</span
><span>{{ weatherInfo.weather }}</span>
</div>
</div>
<div class="pageBottom">
<div class="left fullHeight">
<div class="leftTop">
<div class="blockBox perNumBox">
<img
src="@/assets/images/inoutBigScreen/blockLine.png"
class="blockLine-top"
/>
<img
src="@/assets/images/inoutBigScreen/blockLine.png"
class="blockLine-bottom"
/>
<div class="perNumInner">
<p>
{{ $t('message.laborMange.workersOnSite') }}<span
class="num1"
>{{ statictisData.presencePerson.totalPerson }}</span
>{{ $t('message.laborMange.person') }}
</p>
<p>
{{ $t('message.laborMange.peopleWhoPunchInToday') }}<span
class="num1"
>{{ statictisData.todayNum }}</span
>{{ $t('message.laborMange.person') }}
</p>
<p>
{{
$t('message.laborMange.peopleWhoClockedInYesterday')
}}<span class="num1">{{ statictisData.yesterdayNum }}</span
>{{ $t('message.laborMange.person') }}
</p>
</div>
</div>
<div class="blockBox">
<img
src="@/assets/images/inoutBigScreen/blockLine.png"
class="blockLine-top"
/>
<img
src="@/assets/images/inoutBigScreen/blockLine.png"
class="blockLine-bottom"
/>
<div class="currentPersonInfoBox">
<div
class="imgBox"
v-if="
currentPersonDetail.imageUrl != '' &&
currentPersonDetail.imageUrl != null
"
>
<img
:src="$store.state.FILEURL + currentPersonDetail.imageUrl"
/>
<img
:src="
$store.state.FILEURL +
currentPersonDetail.fieldAcquisitionUrl
"
/>
</div>
<div class="imgBox" v-else>
<img src="@/assets/images/profile_photo.png" />
<img src="@/assets/images/profile_photo.png" />
</div>
<div class="personName">
<span>
{{ currentPersonDetail.workerName }}
<b
class="codeResult"
v-show="currentPersonDetail.codeState === 0"
style="color: rgb(168, 168, 168)"
>
无码
</b>
<b
class="codeResult"
v-show="currentPersonDetail.codeState === 1"
style="color: red"
>
红码
</b>
<b
class="codeResult"
v-show="currentPersonDetail.codeState === 2"
style="color: yellow"
>
黄码
</b>
<b
class="codeResult"
v-show="currentPersonDetail.codeState === 3"
style="color: green"
>
绿码
</b>
</span>
<span class="inoutType">{{
currentPersonDetail.passType == 1
? $t('message.laborMange.enter')
: $t('message.laborMange.leave')
}}</span>
</div>
<p>体温:{{ currentPersonDetail.temperature }}°</p>
<p>
{{ $t('message.laborMange.inOutTime') }}{{
currentPersonDetail.createTime
}}
</p>
<p v-if="currentPersonDetail.teamName">
{{ $t('message.laborMange.team') }}{{
currentPersonDetail.teamName
}}
</p>
<p v-else>
{{ $t('message.laborMange.section') }}{{
currentPersonDetail.departmentName
}}
</p>
<p>
{{ $t('message.laborMange.companies') }}{{
currentPersonDetail.enterpriseName
}}
</p>
</div>
</div>
</div>
<div class="leftBottom blockBox">
<img
src="@/assets/images/inoutBigScreen/blockLine_b.png"
class="blockLine-top"
/>
<img
src="@/assets/images/inoutBigScreen/blockLine_b.png"
class="blockLine-bottom"
/>
<div class="inListBox itemList">
<div class="typeTxt">
{{ $t('message.laborMange.up') }}<br />{{
$t('message.laborMange.shift')
}}
</div>
<div class="personInner">
<div
class="personBox"
v-for="(item, index) in inList"
:key="index"
>
<div class="personBoxItem">
<div class="urseLogo">
<div class="stateLabel" v-if="item.nadTime&&item.workerClassify">
{{overtimeEve(item.nadTime,item.workerClassify)}}
</div>
<img
:src="$store.state.FILEURL + item.imageUrl"
:preview="$store.state.FILEURL + item.imageUrl"
/>
</div>
<div class="detail">
<p class="name">{{ item.workerName }}</p>
<p>
{{
item.departmentName
? item.departmentName
: item.teamName
}}
</p>
<p>{{ item.createTime.split(' ')[1] }}</p>
<p>体温:{{ item.temperature }}°</p>
<p>
<b
v-show="item.codeState == 0"
style="
color: rgb(168, 168, 168);
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
无码
</b>
<b
v-show="item.codeState == 1"
style="
color: red;
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
红码
</b>
<b
v-show="item.codeState == 2"
style="
color: yellow;
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
黄码
</b>
<b
v-show="item.codeState == 3"
style="
color: green;
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
绿码
</b>
</p>
</div>
</div>
</div>
</div>
</div>
<div class="outListBox itemList">
<div class="typeTxt">
{{ $t('message.laborMange.down') }}<br />{{
$t('message.laborMange.shift')
}}
</div>
<div class="personInner">
<div
class="personBox"
v-for="(item, index) in outList"
:key="index"
>
<div class="personBoxItem">
<div class="urseLogo">
<div class="stateLabel" v-if="item.nadTime&&item.workerClassify">
{{overtimeEve(item.nadTime,item.workerClassify)}}
</div>
<img
:src="$store.state.FILEURL + item.imageUrl"
:preview="$store.state.FILEURL + item.imageUrl"
/>
</div>
<div class="detail">
<p class="name">{{ item.workerName }}</p>
<p>
{{
item.departmentName
? item.departmentName
: item.teamName
}}
</p>
<p>{{ item.createTime.split(' ')[1] }}</p>
<p>体温:{{ item.temperature }}°</p>
<p>
<b
v-show="item.codeState == 0"
style="
color: rgb(168, 168, 168);
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
无码
</b>
<b
v-show="item.codeState == 1"
style="
color: red;
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
红码
</b>
<b
v-show="item.codeState == 2"
style="
color: yellow;
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
黄码
</b>
<b
v-show="item.codeState == 3"
style="
color: green;
width: 40px;
height: 25px;
line-height: 25px;
font-size: 20px;
margin: 0;
"
class="codeResult"
>
绿码
</b>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="right fullHeight">
<img
src="@/assets/images/inoutBigScreen/companyLine.png"
class="blockLine-top"
/>
<img
src="@/assets/images/inoutBigScreen/companyLine.png"
class="blockLine-bottom"
/>
<div class="title">
{{ $t('message.laborMange.enterprisesEnteringMarket') }}
</div>
<div
id="detetion-box2"
class="companyListBox"
@mouseover="clearTimer"
@mouseout="ScrollUp2"
>
<div id="detetion-con1">
<div
class="companyInner"
v-for="(item, index) in statictisData.list"
:key="index"
>
<div class="companyName">{{ item.enterpriseName }}</div>
<div class="groupBox groupBox1">
<p v-for="(data, i) in item.list" :key="i + 'child'">
<span>{{ data.name }}</span
><span
>{{ $t('message.laborMange.today') }}{{
data.todayNum
}}</span
><span
>{{ $t('message.laborMange.yesterday') }}{{
data.yesterdayNum
}}</span
>
</p>
</div>
<div class="groupBox">
<p class="groupTotal">
<span>{{ $t('message.laborMange.total') }}</span
><span
>{{ $t('message.laborMange.today') }}{{
item.totaltodayNum
}}</span
><span
>{{ $t('message.laborMange.yesterday') }}{{
item.totalyesterdayNum
}}</span
>
</p>
</div>
</div>
</div>
<div id="detetion-con2"></div>
<div
class="placeholderBox placeholderBox2"
v-if="statictisData.list.length == 0"
>
<img src="@/assets/images/noData3.png" alt="" srcset="" />
<p>{{ $t('message.laborMange.noData') }}</p>
</div>
</div>
</div>
</div>
<!-- <p class="bottomDesc">佳信捷智慧工地 您的工地管理好帮手</p> -->
</div>
</template>
<script>
// import vueSeamlessScroll from 'vue-seamless-scroll'
import {
selectEnterpriseAttendanceCountApi,
selectWorkNewAttendanceListApi,
} from "@/assets/js/api/laborPerson.js";
import { GetTimeDiff, GetTimeStr } from "@/assets/js/util";
import mqtt from "mqtt";
const options = {
connectTimeout: 40000,
clientId: "mqttjs_" + Math.random().toString(16).substr(2, 8),
username: "root",
password: "123456",
clean: true,
};
import tool from "@/util/nowDate/index";
var client2 = null;
export default {
// components:{vueSeamlessScroll},
// computed: {
// classOption () {
// return {
// step: 0.2, // 数值越大速度滚动越快
// limitMoveNum: 2, // 开始无缝滚动的数据量 this.dataList.length
// hoverStop: true, // 是否开启鼠标悬停stop
// direction: 1, // 0向下 1向上 2向左 3向右
// openWatch: true, // 开启数据实时监控刷新dom
// singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
// singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
// waitTime: 1000 // 单步运动停止的时间(默认值1000ms)
// }
// }
// },
data() {
return {
timer1: null,
timer2: null,
statictisData: {
todayNum: 0,
yesterdayNum: 0,
list: [],
presencePerson: {
totalPerson: 0,
},
},
inList: [],
outList: [],
curTime: "",
curDate: "",
curWeek: "",
weatherInfo: {
city: "--",
weather: "--",
temperature: "--",
winddirection: "--",
windpower: "-",
humidity: "--",
},
topicName: "attendance",
currentPersonDetail: {
teamName: "",
createTime: "",
workerName: "",
passType: 1, //1 进 2 出
departmentName: "",
enterpriseName: "",
imageUrl: "",
fieldAcquisitionUrl: "",
},
};
},
created() {
if (COMPANY == 'nanchang') {
document.title = '疫情防控LED大屏';
}
},
mounted() {
this.getTime();
this.getCompanyData();
this.getInoutData(1, 2);
this.getInoutData(2, 2);
this.getNewestData(1);
this.loadWeather();
console.log(mqttUrl);
// client2 = mqtt.connect("ws://139.159.226.224:8083/mqtt", options);
client2 = mqtt.connect(mqttUrl, options);
this.mqttMSG();
},
beforeDestroy() {
clearInterval(this.timer1);
clearInterval(this.timer2);
if (client2) {
client2.unsubscribe(this.topicName + this.$store.state.projectSn);
}
},
filters:{
},
methods: {
overtimeEve(data, workerClass) {
// console.log(time,'=============')
if (data && workerClass) {
let timestamp = new Date().getTime();
let codeTime = new Date(data).getTime();
let timeDifference = Number(timestamp) - Number(codeTime);
if(isNaN(timeDifference)){
return "核酸超时"
}
let hour = Math.floor(timeDifference / 3600000);
let res='';
switch (workerClass) {
case 1:
if(hour>168){
res="核酸超时"
}else{
res=hour.toString()+'小时'
}
break;
case 2:
if(hour>24){
res="核酸超时"
}else{
res=hour.toString()+'小时'
}
break;
case 3:
if(hour>72){
res="核酸超时"
}else{
res=hour.toString()+'小时'
}
break;
default:
res=''
}
return res;
} else {
return ""
}
},
mqttMSG() {
// mqtt连接 +"/#" +workerId
client2.on("connect", (e) => {
console.log("连接成功:", this.topicName + this.$store.state.projectSn);
client2.subscribe(
this.topicName + this.$store.state.projectSn,
{ qos: 0 },
(error) => {
if (!error) {
console.log("订阅成功");
} else {
console.log("订阅失败");
}
}
);
});
// 接收消息处理
client2.on("message", (topic, message) => {
console.log("收到来自", topic, "的消息", message.toString());
console.log(JSON.parse(message));
// console.log(message.content.toString());
// console.log(JSON.parse(message.content.toString()));
this.currentPersonDetail = JSON.parse(JSON.parse(message).content);
let arr = [this.currentPersonDetail];
if (this.currentPersonDetail.passType == 1) {
this.inList = arr.concat(this.inList);
} else if (this.currentPersonDetail.passType == 2) {
this.outList = arr.concat(this.outList);
}
this.getCompanyData();
});
// 断开发起重连
// client2.on("reconnect", (error) => {
// console.log("正在重连:", error);
// });
// 链接异常处理
client2.on("error", (error) => {
console.log("连接失败:", error);
});
},
getTime() {
let a = GetTimeStr(0, "-");
this.curDate = a.split(" ")[0];
this.curTime = a.split(" ")[1];
this.timer2 = setTimeout(() => {
this.getTime();
this.getDateWeek(this.curDate);
}, 1000);
},
getDateWeek(date) {
var day = new Date(Date.parse(date));
var today = this.$t("message.laborMange.dayArr");
this.curWeek = today[day.getDay()];
},
loadWeather() {
if (
localStorage.getItem("weatherInfo") &&
localStorage.getItem("weatherInfo") != "undefined"
) {
this.weatherInfo = JSON.parse(localStorage.getItem("weatherInfo"));
var diff = GetTimeDiff(this.weatherInfo.reporttime, GetTimeStr(0, "-"));
if (diff < 2) {
//2小时请求一次
return;
}
}
let url = "http://restapi.amap.com/v3/weather/weatherInfo";
let that = this;
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
ajax.open(
"get",
url +
"?key=a3217cf9335d333c307abee2fce600b5&extensions=base&output=json&city=" +
this.$store.state.currentProDetail.cityCode
);
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
// console.log(ajax.responseText);//输入相应的内容
let data = JSON.parse(ajax.responseText);
that.weatherInfo = data.lives[0];
localStorage.setItem("weatherInfo", JSON.stringify(that.weatherInfo));
}
};
// this.$http
// .get(url, {
// params: {
// key: "a3217cf9335d333c307abee2fce600b5",
// city: this.$store.state.currentProDetail.cityCode,
// extensions: "base",
// output: "JSON"
// }
// })
// .then(res => {
// if (res.data.status == "1") {
// this.weatherInfo = res.data.lives[0];
// localStorage.setItem(
// "weatherInfo",
// JSON.stringify(this.weatherInfo)
// );
// }
// });
},
//获取进出列表
getInoutData(passType, limitType) {
let json = {
projectSn: this.$store.state.projectSn,
passType: passType,
limitType: limitType,
userEnterpriseId: this.$store.state.userInfo.userEnterpriseId,
};
selectWorkNewAttendanceListApi(json).then((res) => {
if (passType == 1) {
this.inList = res.result;
} else if (passType == 2) {
this.outList = res.result;
}
this.$nextTick(() => {
this.$previewRefresh();
});
});
},
// 获取最新进出场的一名员工
getNewestData(limitType) {
let json = {
projectSn: this.$store.state.projectSn,
limitType: limitType,
userEnterpriseId: this.$store.state.userInfo.userEnterpriseId,
};
selectWorkNewAttendanceListApi(json).then((res) => {
this.currentPersonDetail = res.result[0];
console.log(this.currentPersonDetail);
});
},
//获取企业进场人数
getCompanyData() {
selectEnterpriseAttendanceCountApi({
projectSn: this.$store.state.projectSn,
}).then((res) => {
this.statictisData = res.result;
if (res.result.list.length > 0) {
this.$nextTick(() => {
this.ScrollUp2();
});
}
});
},
clearTimer() {
clearInterval(this.timer1);
},
ScrollUp2() {
var box = document.getElementById("detetion-box2");
var con1 = document.getElementById("detetion-con1");
var con2 = document.getElementById("detetion-con2");
if (con1.offsetHeight >= box.offsetHeight) {
con2.innerHTML = con1.innerHTML;
this.timer1 = setInterval(scrol, 50);
function scrol() {
/*判断滚动内容是否已经滚完滚完了则滚动的值重新设置到0否则就每个30默秒向上滚动1px */
if (box.scrollTop >= con1.scrollHeight) {
box.scrollTop = 0;
} else {
box.scrollTop++;
}
/*判断滚动的距离刚好为一条公告的高度时停掉定时器隔1s之后重新启动计时器即可实现公告滚动停留效果 */
// if (box.scrollTop % 25 == 0) {
// clearInterval(timer1);
// setTimeout(() => {
// timer1 = setInterval(scrol, 30);
// }, 2000);
// }
}
}
},
},
};
</script>
<style lang="less" scoped>
.page {
background-color: #142739;
color: white;
font-size: 30px;
position: relative;
width: 100%;
}
.leftLine {
position: absolute;
top: 50px;
left: 6px;
height: calc(100% - 70px);
}
.rightLine {
position: absolute;
top: 50px;
right: 6px;
height: calc(100% - 70px);
transform: rotateY(180deg);
}
.bottomLine {
position: absolute;
bottom: 10px;
left: 40px;
width: calc(100% - 80px);
}
.topHeader {
height: 100px;
padding: 0 70px;
display: flex;
align-items: center;
justify-content: space-between;
background: url('../../../assets/images/inoutBigScreen/headerBG.png')
no-repeat 100% 100%;
.left {
flex: 1;
.date {
font-size: 25px;
}
span {
margin-right: 28px;
}
}
}
.projectName {
font-size: 46px;
color: #00ecd5;
text-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
flex: 1;
text-align: center;
margin-top: -15px;
flex: 4;
}
.tempBox {
flex: 1;
text-align: right;
font-size: 40px;
span:first-child {
margin-right: 42px;
}
}
.blockBox {
background-color: rgba(19, 50, 66, 1);
position: relative;
}
.perNumBox {
.perNumInner {
padding: 20px 0;
height: calc(100% - 40px);
}
p {
height: 33.33%;
display: flex;
align-items: center;
justify-content: center;
}
.num1 {
margin-right: 23px;
font-size: 50px;
color: #00ecd5;
width: 168px;
height: 70px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 34px;
// border-bottom: 1px dashed rgba(0, 236, 213, 1);
background: url('../../../assets/images/inoutBigScreen/numBG.png') no-repeat
100% 100%;
}
}
.pageBottom {
padding: 40px 40px 60px;
overflow: hidden;
height: calc(100% - 100px - 60px - 40px);
.left {
width: calc(65% - 20px);
float: left;
margin-right: 20px;
}
.right {
width: 35%;
float: left;
background-color: rgba(19, 50, 66, 1);
position: relative;
.title {
background: linear-gradient(
to right,
#133242,
rgba(2, 211, 193, 0.4),
#133242
);
width: 80%;
margin: 0 10%;
font-size: 39px;
text-align: center;
height: 65px;
line-height: 65px;
}
}
.leftTop {
height: calc(100% - 330px - 45px);
margin-bottom: 45px;
.blockBox {
width: calc(50% - 10px);
float: left;
height: 100%;
&:first-child {
margin-right: 20px;
}
}
}
}
.currentPersonInfoBox {
padding: 6px 40px 0;
.imgBox {
text-align: center;
img {
width: 217px;
height: 229px;
display: inline-block;
&:first-child {
margin-right: 40px;
}
}
}
.personName {
font-size: 40px;
position: relative;
margin: 10px 0 0;
.inoutType {
position: absolute;
right: 0;
top: 0;
border-radius: 23px;
background-color: rgba(0, 236, 213, 0.6);
width: 80px;
height: 46px;
line-height: 46px;
font-size: 35px;
text-align: center;
}
}
p {
color: #f2f2f2;
margin-top: 5px;
}
}
.companyListBox {
padding: 0 20px 0;
height: calc(100% - 65px - 40px);
overflow: hidden;
margin: 20px 0;
.companyName {
color: #02fbe2;
margin: 0px 0 5px;
}
// .companyInner{
// padding-top: 10px;
// }
.groupBox {
background-color: rgba(20, 43, 60, 1);
font-size: 24px;
color: rgba(242, 242, 242, 100);
margin-bottom: 20px;
p {
display: flex;
align-items: center;
height: 54px;
span {
flex: 1;
padding-left: 30px;
}
}
.groupTotal {
background: linear-gradient(
rgba(34, 115, 131, 0.58),
rgba(15, 63, 76, 0.58)
);
}
}
.groupBox1 {
margin-bottom: 0;
}
}
.typeTxt {
background: linear-gradient(#152739, #097c7d, #152739);
color: #f2f2f2;
width: 62px;
height: 100%;
display: inline-flex;
justify-content: center;
align-items: center;
margin-right: 28px;
float: left;
}
.inListBox {
border-bottom: 1px solid rgba(255, 255, 255, 0.09);
}
.itemList {
height: 165px;
overflow: hidden;
}
.personInner {
width: calc(100% - 90px);
float: left;
padding-top: 20px;
white-space: nowrap;
}
.personBox {
.personBoxItem {
display: flex;
.urseLogo {
position: relative;
.stateLabel {
font-size: 14px;
position: absolute;
left: 10px;
top: 10px;
padding: 0 6px;
height: 24px;
line-height: 24px;
text-align: center;
background-color: #3662d6;
color: #fff;
}
}
}
display: inline-block;
// margin-right: 5px;
min-width: 240px;
img {
width: 110px;
height: 126px;
display: inline-block;
margin-right: 10px;
}
.detail {
display: inline-block;
vertical-align: top;
font-size: 20px;
.name {
font-size: 26px;
margin-bottom: 9px;
// padding-top: 6px;
}
p {
// margin-bottom: 12px;
width: 153px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
.codeResult {
font-weight: normal;
display: inline-block;
width: 60px;
height: 45px;
font-size: 30px;
margin-left: 10px;
background: rgba(233, 255, 220, 0.2);
padding: 0 10px;
border-radius: 6px;
line-height: 45px;
}
.bottomDesc {
font-size: 25px;
color: #f2f2f2;
position: absolute;
left: 50%;
bottom: 5px;
transform: translateX(-50%);
}
.blockLine-top {
position: absolute;
top: -18px;
left: 0;
width: 100%;
}
.blockLine-bottom {
position: absolute;
bottom: -12px;
left: 0;
width: 100%;
transform: rotateX(180deg);
opacity: 0.2;
}
// @media screen and (max-height: 1050px) {
// .currentPersonInfoBox{
// font-size: 20px;
// .personName{
// font-size: 35px;
// }
// .imgBox{
// transform: scale(0.6);
// height: 180px;
// }
// }
// }
</style>