2024-06-03 19:11:33 +08:00

706 lines
21 KiB
Vue

<template>
<div class="leftBottom">
<div class="header">
<div class="hLeft">项目人员考勤</div>
</div>
<div class="content">
<div class="contentTop">
<div class="line1">
<span>出勤人员总数:</span>
<!-- <div class="numberCard" v-for="(item,i) in '0234'" :key="i">{{item}}</div> -->
<div class="numberCard" v-for="(item,i) in totalPerson" :key="i">{{item}}</div>
<span style="margin-left:15px">考勤日环比</span>
<div style="display:flex" v-if="typeof totalPersonRhbRatio == 'undefined'">
<div class="dayRadio">0%</div>
</div>
<!-- <div style="display:flex" v-if="!totalPersonRhbRatio">
<div class="dayRadio">0%</div>
</div> -->
<div style="display:flex" v-if="totalPersonRhbRatio > 0">
<div class="dayRadio">{{totalPersonRhbRatio}}%</div>
<div class="iconCenter"><el-icon size="20" color="#1E90FF"><Top/></el-icon></div>
</div>
<div style="display:flex" v-if="totalPersonRhbRatio == 0">
<!-- <div class="dayRadio">{{totalPersonRhbRatio}}%</div> -->
<div class="dayRadio">0%</div>
</div>
<div style="display:flex" v-if="totalPersonRhbRatio < 0">
<div class="dayRadio">{{Math.abs(totalPersonRhbRatio)}}%</div>
<div class="iconCenter"><el-icon size="20" color="#8B0000"><Bottom/></el-icon></div>
</div>
</div>
<div class="line2">
<div :class="['line2Item',activeIndex === '0' ? 'activeTab' : '']" @click="handleTab('0')">总包出勤情况分析</div>
<div :class="['line2Item',activeIndex === '1' ? 'activeTab' : '']" @click="handleTab('1')">人员风险趋势分析</div>
</div>
<div class="barContent" v-if="isFlag">
<div id="bar" style="width:98%;height:100%" ref="bar"></div>
</div>
<div class="cbProcess" v-if="!isFlag">
<div class="notoDta" v-if="projectCompanyWorkTotalList.length == 0">
<img src="@/assets/images/noData.png" style="margin-top:100px" alt="" />
<p>暂无数据</p>
</div>
</div>
</div>
<div class="centerBottom">
<div class="cbTop">
<div class="header"><div class="hLeft">进度情况分析</div></div>
<div class="content" style="backgound:black">
<div class="cbLine1">
<div style="display:flex">
<span>项目总进度:</span>
<div class="numberCard" v-for="(item,i) in projectTotalProgress" :key="i">{{item}}</div>
<span style="margin-left:5px">%</span>
</div>
<div style="display:flex">
<span style="margin-left:15px">项目剩余天数</span>
<div class="numberCard" v-for="(item,i) in projectSurplusDayNum" :key="i">{{item}}</div>
<span style="margin-left:5px">天</span>
</div>
</div>
<div class="cbProcess" v-if="processList.length >= 5">
<!-- v-if="listData.length>0" :list="listData" -->
<vue3-seamless-scroll
v-if="processList.length>0" :list="processList"
:speed="1" :limitScrollNum="5" :step="0.3" :hover="true" class="scroll">
<div class="pItem" v-for="(item,i) in processList" :key="i">
<div class="pLeft">
<span :class="['plInner','plBgc'+(i+1)%12]">
<span style="margin-left:10px">Top{{i+1}}</span>
</span>
</div>
<div class="pRight">
<div class="prTop">
<div class="prtLeft">{{item.enterpriseName}}</div>
<div class="prtRight">{{item.changeAfter}}%</div>
</div>
<div class="prBottom">
<div class="processLineBg">
<div :class="['processLine','plBtnBgc'+(i+1)%12]" :style="{width:item.changeAfter+'%'}">
<div class="processLineBtn"></div>
</div>
</div>
</div>
</div>
</div>
</vue3-seamless-scroll>
</div>
<div class="cbProcess" v-else-if="processList.length == 0">
<div class="notoDta" v-if="processList.length == 0">
<img src="@/assets/images/noData.png" alt="" />
<p>暂无数据</p>
</div>
</div>
<div class="cbProcess" v-else>
<!-- v-if="listData.length>0" :list="listData" -->
<!-- <vue3-seamless-scroll
v-if="processList.length>0" :list="processList"
:speed="1" :limitScrollNum="5" :step="0.3" :hover="true" class="scroll"> -->
<div class="pItem" v-for="(item,i) in processList" :key="i">
<div class="pLeft">
<span :class="['plInner','plBgc'+(i+1)%12]">
<span style="margin-left:10px">Top{{i+1}}</span>
</span>
</div>
<div class="pRight">
<div class="prTop">
<div class="prtLeft">{{item.enterpriseName}}</div>
<div class="prtRight">{{item.changeAfter}}%</div>
</div>
<div class="prBottom">
<div class="processLineBg">
<div :class="['processLine','plBtnBgc'+(i+1)%12]" :style="{width:item.changeAfter+'%'}">
<div class="processLineBtn"></div>
</div>
</div>
</div>
</div>
</div>
<!-- </vue3-seamless-scroll> -->
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import * as echarts from "echarts";
import ECharts from 'vue-echarts';
import { selectQualityStatisticsApi } from "@/api/modules/projectOverview";
import {
getPersonTypeAndEduStatisticsApi,
queryAttendanceOfEachCompanyApi,
getCountTaskProgressApi,
queryCountEnterpriseApi,
} from "@/api/modules/agjtCommandApi";
import type { TabsPaneContext, ElMessageBox } from "element-plus";
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { GlobalStore } from "@/stores";
import { Vue3SeamlessScroll } from "vue3-seamless-scroll";
const store = GlobalStore();
const activeName = ref("总包出勤情况分析");
const activeIndex = ref("0" as any);
//出勤人员数据
let totalPerson = ref(""as any)
//考勤日环比
let totalPersonRhbRatio = ref("" as any)
//获取出勤人员数据/考勤日环比
const getPersonTypeAndEduStatistics = async () => {
const res: any = await getPersonTypeAndEduStatisticsApi({
projectSn: store.sn
});
if (res.result) {
console.log("出勤人员数据/考勤日环比", res);
totalPerson.value = res.result.personType.attendancePerson.totalPerson
// if(totalPerson.value.length < 4){
// let temp = 4-totalPerson.value.length
// for(let i = 0;i<temp;i++){
// totalPerson.value = "0" + totalPerson.value
// }
// }
totalPersonRhbRatio.value = res.result.personType.attendancePerson.totalPersonRhbRatio
}
};
//总包出勤情况分析数据列表
let projectCompanyWorkTotalList = ref([] as any)
let xData = ref([] as any)
let yData = ref([] as any)
//获取总包出勤情况分析数据
let isFlag = ref(true as any)
const queryAttendanceOfEachCompany = async () => {
const res: any = await queryAttendanceOfEachCompanyApi({
projectSn: store.sn,
isCountMainEnterprise: 1
});
if (res.result) {
console.log("获取总包出勤情况分析数据", res);
projectCompanyWorkTotalList.value = res.result.projectCompanyWorkTotalList
xData.value = projectCompanyWorkTotalList.value.map(item => item.enterpriseName.substring(0,4))
yData.value = projectCompanyWorkTotalList.value.map(item => item.attendancePersonNum)
if(projectCompanyWorkTotalList.value.length > 0){
isFlag = true
drawBar()
}else{
isFlag = false
}
}
};
//切换tab
const handleTab = (val:string) => {
activeIndex.value = val
}
//绘画柱状图
function drawBar() {
console.log("---------------------bar--------")
type EChartsOption = echarts.EChartsOption;
var chartDom = document.getElementById('bar')!;
var myChart = echarts.init(chartDom);
var option: EChartsOption;
option = {
xAxis: {
type: 'category',
// data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
data: xData.value,
axisLabel: {
fontSize: 12, // 设置字体大小为12px
// rotate: 45,
interval: 0, // 显示所有标签
},
axisLine: {
lineStyle: {
// color: 'white' // 设置X轴刻度线的颜色为白色
color: 'rgba(200,200,200,1)'
}
},
},
yAxis: {
type: 'value',
axisLabel: {
fontSize: 12, // 设置字体大小为12px
},
axisLine: {
lineStyle: {
// color: 'white' // 设置Y轴刻度线的颜色为白色
color: 'rgba(200,200,200,1)'
}
},
// show:false
splitLine: {
show: true,
lineStyle: {
// type: 'dashed', //y轴分割线类型
type: 'solid', //y轴实线类型
color: 'rgba(102,102,102,0.25)',
width: 2.5,
},
},
},
dataZoom: [{
type: 'slider',
start: 0,
end: 40,
width:"98%",
height:5,
left:"center",
bottom:3
}],
grid: {
top: "8%",
right: "0",
left:"8%",
bottom: "10%",
},
series: [{
// data: [120, 200, 150, 80, 70, 110, 130],
data: yData.value,
type: 'bar',
barWidth: 20,
itemStyle: {
color: '#3398DB' // 设置柱状图颜色为蓝色
},
emphasis: {
itemStyle: {
// color: '#8B0000' // 设置鼠标悬浮时的颜色为深红色
// color: '#ff6b70' // 设置鼠标悬浮时的颜色为水红色
color: '#00008B' // 设置鼠标悬浮时的颜色为深蓝色
}
}
}],
tooltip: {
borderColor: 'rgba(50,50,50, 0.5)',
backgroundColor: 'rgba(50,50,50, 0.5)',
textStyle: { color: '#fff',fontSize:'15'},
formatter: function(params) {
// 出勤率
let attendanceRate = projectCompanyWorkTotalList.value[params.dataIndex].attendancePersonRate
if(!attendanceRate){
attendanceRate = "--"
}else{
attendanceRate = attendanceRate + "%"
}
// 出勤率日环比
let attendanceRhbRate = projectCompanyWorkTotalList.value[params.dataIndex].attendancePersonRhbRate
if(!attendanceRhbRate){
attendanceRhbRate = "--"
}else{
attendanceRhbRate = attendanceRhbRate + "%"
}
console.log(params)
console.log(123123,projectCompanyWorkTotalList.value[params.dataIndex].attendancePersonRate)
return '<div style="font-weight:bold">'+params.name+'</div>' +
'<div style="line-height:23px"><span style="font-size:16px;margin-right:5px;color:#1E90FF">●</span>在册人员:'+projectCompanyWorkTotalList.value[params.dataIndex].totalPersonNum+'</div>' +
'<div style="line-height:23px"><span style="font-size:16px;margin-right:5px;color:#4682B4">●</span>出勤人员总数:'+projectCompanyWorkTotalList.value[params.dataIndex].attendancePersonNum+'</div>' +
'<div style="line-height:23px"><span style="font-size:16px;margin-right:5px;color:#87CEFA">●</span>出勤率:'+attendanceRate+'</div>' +
'<div style="line-height:23px"><span style="font-size:16px;margin-right:5px;color:#00BFFF">●</span>出勤率日环比:'+attendanceRhbRate+'</div>';
// '<div style="line-height:23px"><span style="font-size:16px;margin-right:5px;color:#87CEFA">●</span>出勤率:'+projectCompanyWorkTotalList.value[params.dataIndex].attendancePersonRate+'%</div>' +
}
}
};
// window.addEventListener('resize',function(){
// myChart.resize()
// })
option && myChart.setOption(option);
}
//进度数据
let listData = ref([
{a:'新地能源工程技术有限公司',b:'54'},{a:'中冶沈勘秦皇岛工程设计研究总院有限公司',b:'23'},{a:'鞍山电力实业有限公司',b:'49'},{a:'鞍钢矿业资源利用(鞍山)有限公司',b:'35'},
{a:'上海建工五建集团有限公司',b:'34'},{a:'辽宁普凡建设有限公司',b:'67'},{a:'沈阳隆基电磁科技股份有限公司',b:'56'},{a:'中国科学院过程工程研究所',b:'78'},
{a:'宏大爆破工程集团有限责任公司',b:'45'},{a:'鞍钢集团矿业设计研究院有限公司',b:'23'},{a:'辽宁电力能源发展集团监理有限公司鞍山分公司',b:'69'},{a:'辽宁五寰特种材料与智能装备产业技术研究院有限公司',b:'27'},
{a:'中铝山东工程技术有限公司',b:'59'},{a:'中国华冶科工集团有限公司',b:'14'},{a:'沈阳岩土工程技术测试开发有限公司',b:'38'},{a:'永明项目管理有限公司',b:'41'},
] as any)
// 进度情况分析
// 项目总进度
let projectTotalProgress = ref("" as any)
// 项目剩余天数
let projectSurplusDayNum = ref({} as any)
// 获取项目总进度/项目剩余天数
const getCountTaskProgress = async () => {
const res: any = await getCountTaskProgressApi({
projectSn: store.sn
});
if (res.result) {
console.log("项目总进度/项目剩余天数", res);
projectTotalProgress.value = res.result.projectTotalProgress + ""
projectSurplusDayNum.value = res.result.projectSurplusDayNum + ""
}
};
// 总包进度列表
let processList = ref([] as any)
// 获取总包进度列表
const queryCountEnterprise = async () => {
const res: any = await queryCountEnterpriseApi({
projectSn: store.sn,
isCountMainEnterprise: 1
});
if (res.result) {
console.log("总包进度列表", res);
processList.value = res.result
}
};
onMounted(async () => {
// drawBar()
getPersonTypeAndEduStatistics()
queryAttendanceOfEachCompany()
getCountTaskProgress()
queryCountEnterprise()
});
</script>
<style lang="scss" scoped>
.leftBottom {
background: url("@/assets/images/commandScreen/card-left-bottom.png") no-repeat;
background-size: 100% 100%;
height: 100%;
.header {
display: flex;
justify-content: space-between;
padding: 10px 20px;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 1px solid #0059ff;
.hLeft {
width: 50%;
font-size: 20px;
font-weight: bold;
background-image: linear-gradient(to bottom left, #c8e3ff, #007aff);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
}
.content {
// background-color: darkred;
height: 92.5%;
.contentTop {
padding: 0 10px;
height: 50%;
// background-color: #fff;
font-size: 13px;
.line1{
color: #fff;
padding-top: 5px;
display: flex;
justify-content: flex-start;
align-items: center;
line-height: 30px;
height: 30px;
font-size: 15px;
.numberCard{
font-size: 15px;
padding: 0 8px;
margin-left: 3px;
font-weight: bold;
color: #47bcec;
background: url("@/assets/images/commandScreen/number-bg.png") no-repeat;
background-size: 100% 100%;
}
.dayRadio{
font-size: 15px;
margin-left: 15px;
font-weight: bold;
color: #47bcec;
}
.iconCenter{
display:flex;
justify-content:center;
align-items:center
}
}
.line2{
padding-top: 5px;
display:flex;
justify-content:flex-start;
align-items:center;
line-height:25px;
height: 25px;
.line2Item{
color: #fff;
width: 140px;
text-align: center;
cursor: pointer;
// background-color: #fff;
background: rgb(0,33,116);
background: linear-gradient(270deg, rgba(0,33,116,0.8) 0%, rgba(40,88,184,0.3) 96%);
}
.activeTab{
background: rgb(0,33,116);
background: linear-gradient(270deg, rgba(0,33,116,1) 0%, rgba(40,88,184,1) 96%);
}
}
.barContent{
height: calc(100% - 65px);
}
}
.centerBottom {
height: 50%;
position: relative;
.cbTop {
width: 100%;
height: 100%;
.header {
display: flex;
align-items: center;
justify-content: space-between;
// padding: 20px 20px;
border-bottom: 1px solid #0059ff;
.hLeft {
width: 50%;
font-size: 20px;
font-weight: bold;
background-image: linear-gradient(to bottom left, #c8e3ff, #007aff);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
}
.content {
padding: 0 10px;
height: 90%;
// background-color: rgba($color: #fff, $alpha: 0.1);
.cbLine1{
color: #fff;
padding-top: 5px;
display: flex;
justify-content: space-between;
align-items: center;
line-height: 30px;
height: 30px;
font-size: 15px;
.numberCard{
font-size: 15px;
padding: 0 8px;
margin-left: 3px;
font-weight: bold;
color: #47bcec;
background: url("@/assets/images/commandScreen/number-bg.png") no-repeat;
background-size: 100% 100%;
}
}
.cbProcess{
padding-top: 5px;
height: calc(100% - 55px);
overflow: hidden;
// background-color: #fff;
.pItem{
width: 100%;
height: 55px;
display: flex;
// background-color: #fff;
font-size: 13px;
color: #fff;
.pLeft{
width: 20%;
height: 55px;
display: flex;
justify-content: center;
align-items: center;
.plInner{
width: 80px;
// text-align: center;
line-height: 30px;
// background-color: darkred;
border-radius: 100px;
}
}
.pRight{
width: 80%;
height: 55px;
.prTop{
// background-color: darkblue;
display: flex;
justify-content: space-between;
height: 30px;
.prtLeft{
display: flex;
justify-content: center;
align-items: flex-end;
}
.prtRight{
display: flex;
justify-content: center;
align-items: flex-end;
}
}
.prBottom{
// background-color: purple;
height: 15px;
.processLineBg{
background-color: rgba(50,50,50,0.5);
// transform: scaleX(-1);
.processLine{
margin-top: 10px;
// padding-top: 10px;
height: 5px;
display: flex;
justify-content: flex-end;
.processLineBtn{
width:3px;
height:9px;
background:#fff;
transform: translateY(-2px);
}
}
// .plBgc1{
// background: rgb(150,0,0);
// background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(150,0,0,1) 100%);
// }
}
}
}
}
}
}
}
}
}
}
.scroll {
height: 100%;
width: 100%;
overflow: hidden;
}
.notoDta {
top: 35%;
width: 50%;
// left: 40%;
position: absolute;
text-align: center;
left: 50%;
transform: translateX(-50%);
img {
width: 40%;
margin: 5% 30%;
}
p {
color: #fff;
font-size: calc(100vw * 14 / 1920);
margin: -6% 30%;
}
}
.plBgc1{
background: rgb(139,0,0);
background: linear-gradient(90deg, rgba(139,0,0,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc1{
background: rgb(139,0,0);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(139,0,0,1) 100%);
}
.plBgc2{
background: rgb(155,155,0);
background: linear-gradient(90deg, rgba(155,155,0,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc2{
background: rgb(155,155,0);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(155,155,0,1) 100%);
}
.plBgc3{
background: rgb(0,0,139);
background: linear-gradient(90deg, rgba(0,0,139,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc3{
background: rgb(0,0,139);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(0,0,139,1) 100%);
}
.plBgc4{
background: rgb(139,0,139);
background: linear-gradient(90deg, rgba(139,0,139,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc4{
background: rgb(139,0,139);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(139,0,139,1) 100%);
}
.plBgc5{
background: rgb(72,61,139);
background: linear-gradient(90deg, rgba(72,61,139,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc5{
background: rgb(72,61,139);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(72,61,139,1) 100%);
}
.plBgc6{
background: rgb(0,206,209);
background: linear-gradient(90deg, rgba(0,206,209,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc6{
background: rgb(0,206,209);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(0,206,209,1) 100%);
}
.plBgc7{
background: rgb(47,79,79);
background: linear-gradient(90deg, rgba(47,79,79,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc7{
background: rgb(47,79,79);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(47,79,79,1) 100%);
}
.plBgc8{
background: rgb(0,100,0);
background: linear-gradient(90deg, rgba(0,100,0,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc8{
background: rgb(0,100,0);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(0,100,0,1) 100%);
}
.plBgc9{
background: rgb(189,183,107);
background: linear-gradient(90deg, rgba(189,183,107,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc9{
background: rgb(189,183,107);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(189,183,107,1) 100%);
}
.plBgc10{
background: rgb(255,140,0);
background: linear-gradient(90deg, rgba(255,140,0,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc10{
background: rgb(255,140,0);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(255,140,0,1) 100%);
}
.plBgc11{
background: rgb(233,150,122);
background: linear-gradient(90deg, rgba(233,150,122,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc11{
background: rgb(233,150,122);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(233,150,122,1) 100%);
}
.plBgc0{
background: rgb(0,139,139);
background: linear-gradient(90deg, rgba(0,139,139,1) 35%, rgba(0,0,0,0.5) 100%);
}
.plBtnBgc0{
background: rgb(0,139,139);
background: linear-gradient(90deg, rgba(50,50,50,0.5) 10%, rgba(0,139,139,1) 100%);
}
</style>