662 lines
15 KiB
Vue
662 lines
15 KiB
Vue
<template>
|
||
<div class="political-outlook">
|
||
<div class="content">
|
||
<div class="dialog-title">
|
||
<div class="title-img"><img src="@/assets/images/titleIcon.png" alt="" /></div>
|
||
<div class="title-text">
|
||
<i>人员类型统计</i>
|
||
</div>
|
||
</div>
|
||
<div class="PersonnelType_wrap">
|
||
<div class="title_wrap" style="margin-bottom: 18px">
|
||
<div>
|
||
<div class="headcount">工地总人数:{{ memberCountData.totalPersonNum }}</div>
|
||
<div class="headcount">今日出勤人数:{{ memberCountData.attendancePersonNum }}</div>
|
||
<div class="headcount">今日在场人数:{{ memberCountData.presencePersonNum }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="echarts" ref="personnelTypeRef"></div>
|
||
</div>
|
||
</div>
|
||
<div class="content">
|
||
<div class="dialog-title">
|
||
<div class="title-img"><img src="@/assets/images/titleIcon.png" alt="" /></div>
|
||
<div class="title-text">
|
||
<i>企业出勤排名</i>
|
||
</div>
|
||
</div>
|
||
<div class="manager_wrap">
|
||
<div class="echarts" ref="ageChartRef" style="width: 100%; height: 100%"></div>
|
||
</div>
|
||
</div>
|
||
<div class="list-content">
|
||
<div class="dialog-title">
|
||
<div class="title-img"><img src="@/assets/images/titleIcon.png" alt="" /></div>
|
||
<div class="title-text">
|
||
<i>人员实时动态</i>
|
||
</div>
|
||
</div>
|
||
<div class="show-more" @click="openPeopleCountDialog({ index: 13, type: 3, title: '人员实时动态' })">
|
||
<span>更多</span>
|
||
</div>
|
||
<div class="tabList">
|
||
<div>类型</div>
|
||
<div>姓名</div>
|
||
<div>班组</div>
|
||
<div>图片</div>
|
||
<div style="width: 25%">通行时间</div>
|
||
</div>
|
||
|
||
<el-scrollbar class="listBox" ref="refScrollbar">
|
||
<div v-for="(item, index) in crewRealTimeList" class="listStyle" :key="item.id">
|
||
<div>{{ item.passType == 1 ? "进" : "出" }}</div>
|
||
<div>{{ item.workerName }}</div>
|
||
<div>{{ item.teamName ? item.teamName : item.departmentName }}</div>
|
||
<div class="list-img">
|
||
<el-image v-if="item.imageUrl" fit="contain" class="el-img" :src="item.imageUrl" :preview-src-list="[item.imageUrl]">
|
||
<template #error>
|
||
<el-image :src="noDataImage" :preview-src-list="[noDataImage]" fit="contain" class="el-no-img" alt="" />
|
||
</template>
|
||
</el-image>
|
||
<el-image v-else :src="noDataImage" :preview-src-list="[noDataImage]" fit="contain" class="el-no-img" alt="" />
|
||
</div>
|
||
<div style="width: 25%">{{ item.createTime }}</div>
|
||
</div>
|
||
<div class="notoDta" v-if="crewRealTimeList.length == 0">
|
||
<img src="@/assets/images/noData.png" alt="" />
|
||
<p>暂无数据</p>
|
||
</div>
|
||
</el-scrollbar>
|
||
</div>
|
||
<div class="list-content">
|
||
<div class="dialog-title">
|
||
<div class="title-img"><img src="@/assets/images/titleIcon.png" alt="" /></div>
|
||
<div class="title-text">
|
||
<i>班组人员统计</i>
|
||
</div>
|
||
</div>
|
||
<div class="tabList">
|
||
<div>序号</div>
|
||
<div>班组名称</div>
|
||
<div>在册人数</div>
|
||
<div>出场人数</div>
|
||
<div>在场人数</div>
|
||
</div>
|
||
<el-scrollbar class="listBox" ref="refScrollbar">
|
||
<div v-for="(item, index) in teamList" class="listStyle" :key="item.id">
|
||
<div>{{ index + 1 }}</div>
|
||
<div>{{ item.teamName }}</div>
|
||
<div>{{ item.totalPerson }}</div>
|
||
<div>{{ item.attendancePersonTotal }}</div>
|
||
<div>{{ item.presencePersonTotal }}</div>
|
||
</div>
|
||
<div class="notoDta" v-if="teamList.length == 0">
|
||
<img src="@/assets/images/noData.png" alt="" />
|
||
<p>暂无数据</p>
|
||
</div>
|
||
</el-scrollbar>
|
||
</div>
|
||
<dataDialog ref="partyBuildRefMore"></dataDialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref, onMounted } from "vue";
|
||
import { GlobalStore } from "@/stores";
|
||
import {
|
||
getPersonTypeAndEduStatisticsApi,
|
||
getComapnyWorkTotalListApi,
|
||
getRealTimeDataApi,
|
||
getWorkerInfoApi
|
||
} from "@/api/modules/labor";
|
||
import * as echarts from "echarts";
|
||
import dataDialog from "./data-dialog.vue";
|
||
import noDataImage from "@/assets/images/vehicleManagement/car.png";
|
||
const store = GlobalStore();
|
||
const props = defineProps(["tip"]);
|
||
const partyBuildRefMore = ref();
|
||
const teamList = ref([] as any);
|
||
const BASEURL = import.meta.env.VITE_API_URL;
|
||
const crewRealTimeList = ref([] as any);
|
||
const ageChartRef = ref();
|
||
const memberCountData = ref({
|
||
totalPersonNum: 0,
|
||
totalEducationPerson: 0,
|
||
attendancePersonNum: 0,
|
||
presencePersonNum: 0
|
||
});
|
||
const personnelTypeRef = ref();
|
||
// 弹窗
|
||
const openPeopleCountDialog = (obj: any) => {
|
||
partyBuildRefMore.value.openDialog(obj);
|
||
// console.log(partyBuildRef.value);
|
||
};
|
||
// 查询项目下按照班组统计
|
||
const selectWorkerTeamStatistics = async () => {
|
||
const res: any = await getWorkerInfoApi({
|
||
projectSn: store.sn,
|
||
userEnterpriseId: store.userInfo?.userEnterpriseId
|
||
});
|
||
teamList.value = res.result;
|
||
};
|
||
//获取人员实时动态
|
||
const getCrewRealTimeData = async () => {
|
||
let data = {
|
||
projectSn: store.sn,
|
||
userEnterpriseId: store.userInfo?.userEnterpriseId
|
||
};
|
||
const res: any = await getRealTimeDataApi(data);
|
||
if (res.code == 200) {
|
||
crewRealTimeList.value = res.result;
|
||
crewRealTimeList.value.map((item: any) => {
|
||
if (item.imageUrl) {
|
||
item.imageUrl = BASEURL + "/image/" + item.imageUrl;
|
||
} else if (item.fieldAcquisitionUrl) {
|
||
item.fieldAcquisitionUrl = BASEURL + "/image/" + item.fieldAcquisitionUrl;
|
||
}
|
||
});
|
||
}
|
||
};
|
||
//获取企业出勤数据
|
||
const getCompanyAttendData = async () => {
|
||
let data = {
|
||
projectSn: store.sn
|
||
};
|
||
const res: any = await getComapnyWorkTotalListApi(data);
|
||
|
||
if (res.code == 200) {
|
||
var Data = res.result;
|
||
var xData: any = [],
|
||
yData1: any = [],
|
||
yData2: any = [],
|
||
yData3: any = [];
|
||
Data.forEach((element: any) => {
|
||
xData.push(element.enterpriseName);
|
||
yData1.push(element.attendancePersonNum);
|
||
yData2.push(element.totalPersonNum);
|
||
yData3.push(element.presencePersonNum);
|
||
});
|
||
createdBarCharts(xData, yData1, yData2, yData3, ageChartRef.value, ["出勤人数", "在册人数", "在场人数"]);
|
||
}
|
||
};
|
||
//企业出勤---图表
|
||
const createdBarCharts = (xData: any, yData1: any, yData2: any, yData3: any, el: any, legendData: any) => {
|
||
let that = this;
|
||
let ageChart = echarts.init(el);
|
||
ageChart.clear();
|
||
let option = {
|
||
grid: {
|
||
width: "92%",
|
||
height: "82%",
|
||
left: 20,
|
||
containLabel: true
|
||
},
|
||
color: ["#5CE2F6", "#5181F6", "#8EBDD2"],
|
||
tooltip: {
|
||
trigger: "axis",
|
||
axisPointer: {
|
||
type: "shadow"
|
||
}
|
||
},
|
||
legend: {
|
||
show: true,
|
||
// align: "left",
|
||
top: 0,
|
||
// left: 0,
|
||
itemWidth: 13,
|
||
itemHeight: 5,
|
||
textStyle: {
|
||
color: "#9fa2ad"
|
||
}
|
||
},
|
||
|
||
xAxis: [
|
||
{
|
||
type: "category",
|
||
data: xData,
|
||
boundaryGap: true,
|
||
axisTick: {
|
||
show: false
|
||
},
|
||
axisLine: {
|
||
show: false
|
||
},
|
||
axisLabel: {
|
||
color: "#9fa2ad",
|
||
fontSize: 12,
|
||
interval: 0, // 强制显示所有标签
|
||
}
|
||
}
|
||
],
|
||
dataZoom: [
|
||
{
|
||
type: "slider", // 使用滑动条形式的数据区域缩放组件
|
||
start: 0, // 数据窗口范围的起始百分比
|
||
end: 50, // 数据窗口范围的结束百分比
|
||
height: 10, // 滑动条组件高度
|
||
bottom: 0, // 距离图表区域下边的距离
|
||
showDetail: false, // 拖拽时是否显示详情
|
||
showDataShadow: false, // 是否在组件中显示数据阴影
|
||
fillerColor: "#2758C0", // 平移条的填充颜色
|
||
borderColor: "transparent", // 边框颜色
|
||
zoomLock: true, // 锁定视图
|
||
},
|
||
],
|
||
yAxis: {
|
||
type: "value",
|
||
axisTick: {
|
||
show: false
|
||
},
|
||
axisLine: {
|
||
show: false
|
||
},
|
||
splitLine: {
|
||
lineStyle: {
|
||
type: "dashed",
|
||
color: "rgba(231, 233, 243, 1)"
|
||
}
|
||
},
|
||
axisLabel: {
|
||
color: "#9fa2ad"
|
||
}
|
||
},
|
||
// dataZoom: [
|
||
// {
|
||
// show: true,
|
||
// start: 50,
|
||
// end: 100,
|
||
// height: 8,
|
||
// borderColor: "transparent",
|
||
// backgroundColor: "#fff",
|
||
// filterColor: "#999999",
|
||
// bottom: 0,
|
||
// },
|
||
// ],
|
||
series: [
|
||
{
|
||
name: legendData[1],
|
||
type: "bar",
|
||
data: yData2,
|
||
// stack: 'product',
|
||
barWidth: 35,
|
||
barGap: 0.1
|
||
},
|
||
{
|
||
name: legendData[0],
|
||
type: "bar",
|
||
// stack: 'product',
|
||
data: yData1,
|
||
barMaxWidth: 35
|
||
},
|
||
{
|
||
name: legendData[2],
|
||
type: "bar",
|
||
data: yData3,
|
||
// stack: 'product',
|
||
barMaxWidth: 35,
|
||
barGap: 0.1
|
||
}
|
||
]
|
||
};
|
||
|
||
ageChart.setOption(option);
|
||
};
|
||
//人员类型统计
|
||
const createdEcharts = (yAxisData1: any, yAxisData2: any, yAxisData3: any) => {
|
||
// let yAxisData1 = [1, 2, 3, 4, 5, 6, 7];
|
||
// let yAxisData2 = [2, 3, 7, 4, 5, 6, 7];
|
||
let personnelType = echarts.init(personnelTypeRef.value);
|
||
let option = {
|
||
color: ["#8FC8FF", "rgba(126,150,232,1)", "#61D2B9"],
|
||
tooltip: {
|
||
show: true,
|
||
trigger: "axis",
|
||
formatter: "{b} <br /> {a0}: {c0}<br /> {a1}: {c1} <br /> {a2}: {c2}",
|
||
axisPointer: {
|
||
lineStyle: {
|
||
color: "transparent"
|
||
}
|
||
},
|
||
textStyle: {
|
||
color: "#000",
|
||
fontSize: 12
|
||
},
|
||
backgroundColor: "rgba(236,236,236,0.75)"
|
||
},
|
||
grid: {
|
||
left: 30,
|
||
right: 30,
|
||
bottom: 15,
|
||
top: 20,
|
||
containLabel: true
|
||
},
|
||
xAxis: {
|
||
type: "category",
|
||
boundaryGap: false,
|
||
axisLine: {
|
||
show: false
|
||
},
|
||
axisTick: { show: false },
|
||
data: ["项目管理人员", "劳务工", "临时工"],
|
||
axisLabel: {
|
||
// rotate: 30,
|
||
textStyle: {
|
||
color: "#9fa2ad",
|
||
fontSize: 10
|
||
}
|
||
}
|
||
},
|
||
yAxis: {
|
||
show: true,
|
||
// type: "time",
|
||
axisTick: { show: false },
|
||
axisLine: {
|
||
show: false
|
||
},
|
||
splitLine: {
|
||
lineStyle: {
|
||
type: "dashed",
|
||
color: "rgba(231, 233, 243, 0.5)"
|
||
}
|
||
},
|
||
axisLabel: {
|
||
// show: false,
|
||
textStyle: {
|
||
color: "#9fa2ad",
|
||
fontSize: 10
|
||
}
|
||
}
|
||
},
|
||
series: [
|
||
{
|
||
name: "在册人数",
|
||
data: yAxisData2,
|
||
type: "line",
|
||
symbolSize: 10,
|
||
// symbol: "circle",
|
||
lineStyle: {
|
||
width: 1
|
||
},
|
||
areaStyle: {
|
||
normal: {
|
||
// opacity: 0.2
|
||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||
{
|
||
offset: 0,
|
||
color: "rgba(126,150,232,0.56)"
|
||
},
|
||
{
|
||
offset: 1,
|
||
color: "rgba(30, 72, 223, 0)"
|
||
}
|
||
])
|
||
}
|
||
}
|
||
},
|
||
{
|
||
name: "出勤人数",
|
||
data: yAxisData3,
|
||
type: "line",
|
||
symbolSize: 10,
|
||
// symbol: "circle",
|
||
lineStyle: {
|
||
width: 1
|
||
},
|
||
areaStyle: {
|
||
normal: {
|
||
// opacity: 0.2
|
||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||
{
|
||
offset: 0,
|
||
color: "rgba(126,150,232,0.56)"
|
||
},
|
||
{
|
||
offset: 1,
|
||
color: "rgba(30, 72, 223, 0)"
|
||
}
|
||
])
|
||
}
|
||
}
|
||
},
|
||
{
|
||
name: "在场人数",
|
||
data: yAxisData1,
|
||
type: "line",
|
||
symbolSize: 10,
|
||
// symbol: "circle",
|
||
lineStyle: {
|
||
width: 1
|
||
},
|
||
areaStyle: {
|
||
normal: {
|
||
// opacity: 0.2
|
||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||
{
|
||
offset: 0,
|
||
color: "rgba(37,82,228,0.56)"
|
||
},
|
||
{
|
||
offset: 1,
|
||
color: "rgba(30, 72, 223, 0)"
|
||
}
|
||
])
|
||
}
|
||
}
|
||
}
|
||
]
|
||
};
|
||
personnelType.setOption(option);
|
||
};
|
||
//查询人员类型和教育统计
|
||
const selectPersonTypeAndEduStatistics = async () => {
|
||
const res: any = await getPersonTypeAndEduStatisticsApi({
|
||
projectSn: store.sn,
|
||
userEnterpriseId: store.userInfo?.userEnterpriseId
|
||
});
|
||
console.log(res);
|
||
memberCountData.value.totalPersonNum = res.result.personType.toaltPerson.totalPerson; //总人数
|
||
memberCountData.value.totalEducationPerson = res.result.totalEducationPerson;
|
||
memberCountData.value.attendancePersonNum = res.result.personType.attendancePerson.totalPerson; //出勤总人数
|
||
memberCountData.value.presencePersonNum = res.result.personType.presencePerson.totalPerson; //在场 总人数
|
||
var personTypeData = res.result.personType;
|
||
var arr1 = [
|
||
personTypeData.presencePerson.glPersonTotal,
|
||
personTypeData.presencePerson.lwPersonTotal,
|
||
personTypeData.presencePerson.lsPersonTotal
|
||
];
|
||
var arr2 = [
|
||
personTypeData.toaltPerson.glPersonTotal,
|
||
personTypeData.toaltPerson.lwPersonTotal,
|
||
personTypeData.toaltPerson.lsPersonTotal
|
||
];
|
||
var attendance = [
|
||
//出勤总人数
|
||
personTypeData.attendancePerson.glPersonTotal,
|
||
personTypeData.attendancePerson.lwPersonTotal,
|
||
personTypeData.attendancePerson.lsPersonTotal
|
||
];
|
||
createdEcharts(arr1, arr2, attendance);
|
||
// createdEcharts3()
|
||
};
|
||
onMounted(async () => {
|
||
await selectPersonTypeAndEduStatistics();
|
||
await getCompanyAttendData();
|
||
await getCrewRealTimeData();
|
||
await selectWorkerTeamStatistics();
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@mixin flex {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.political-outlook {
|
||
width: 100%;
|
||
height: 97% !important;
|
||
@include flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-around;
|
||
margin-top: 1%;
|
||
.content {
|
||
height: 45%;
|
||
width: 45%;
|
||
margin-top: 10px;
|
||
// background: url("@/assets/images/cardImg.png") no-repeat;
|
||
background-size: 100% 100%;
|
||
.dialog-title {
|
||
color: #ffffff;
|
||
font-weight: bold;
|
||
font-size: 18px;
|
||
font-family: "OPPOSans-Bold";
|
||
@include flex;
|
||
.title-img {
|
||
width: 30px;
|
||
height: 30px;
|
||
img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
.title-text {
|
||
margin-bottom: 0.3%;
|
||
margin-left: 0.2%;
|
||
}
|
||
}
|
||
.PersonnelType_wrap {
|
||
width: 100%;
|
||
height: 100%;
|
||
.title_wrap {
|
||
> div {
|
||
@include flex;
|
||
justify-content: flex-end;
|
||
.headcount {
|
||
color: white;
|
||
font-size: 14px;
|
||
padding: 3px 10px;
|
||
// border-radius: 30px;
|
||
background: #2758c0;
|
||
margin-right: 10px;
|
||
}
|
||
}
|
||
margin-top: 12px;
|
||
}
|
||
}
|
||
.manager_wrap {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.echarts {
|
||
width: 100%;
|
||
height: calc(100% - 50px);
|
||
}
|
||
}
|
||
.list-content {
|
||
height: 45%;
|
||
width: 45%;
|
||
margin-top: 10px;
|
||
// background: url("@/assets/images/cardImg.png") no-repeat;
|
||
background-size: 100% 100%;
|
||
.dialog-title {
|
||
color: #ffffff;
|
||
font-weight: bold;
|
||
font-size: 18px;
|
||
font-family: "OPPOSans-Bold";
|
||
@include flex;
|
||
margin-bottom: 20px;
|
||
.title-img {
|
||
width: 30px;
|
||
height: 30px;
|
||
img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
.title-text {
|
||
margin-bottom: 0.3%;
|
||
margin-left: 0.2%;
|
||
}
|
||
}
|
||
.show-more {
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
font-family: Source Han Sans CN-Regular, Source Han Sans CN;
|
||
color: #4ac0f3;
|
||
@include flex;
|
||
justify-content: flex-end;
|
||
margin-bottom: 10px;
|
||
}
|
||
.tabList {
|
||
display: flex;
|
||
width: 100%;
|
||
height: 5%;
|
||
background: url("@/assets/images/vehicleManagement/ListTitleImg.png") no-repeat;
|
||
background-size: 100% 100%;
|
||
// position: absolute;
|
||
left: 75.5%;
|
||
top: 75%;
|
||
color: #ccc;
|
||
font-size: calc(100vw * 14 / 1920);
|
||
line-height: 30px;
|
||
align-items: center;
|
||
div {
|
||
text-align: center;
|
||
width: 20%;
|
||
}
|
||
}
|
||
.listBox {
|
||
height: 78%;
|
||
.listStyle {
|
||
display: flex;
|
||
align-items: center;
|
||
text-align: center;
|
||
color: #fff;
|
||
font-size: 12px;
|
||
margin-bottom: 5px;
|
||
.list-img {
|
||
.el-img {
|
||
width: 30px;
|
||
height: 30px;
|
||
img {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
.el-no-img {
|
||
width: 30px;
|
||
height: 30px;
|
||
}
|
||
}
|
||
div {
|
||
width: 20%;
|
||
white-space: nowrap; //单行
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
}
|
||
.listStyle:hover {
|
||
background: #091f3f;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.notoDta {
|
||
top: 28%;
|
||
width: 50%;
|
||
left: 22%;
|
||
position: absolute;
|
||
text-align: center;
|
||
img {
|
||
width: 40%;
|
||
margin: 5% 30%;
|
||
}
|
||
p {
|
||
color: #fff;
|
||
font-size: calc(100vw * 14 / 1920);
|
||
margin: -6% 37%;
|
||
}
|
||
}
|
||
</style>
|