662 lines
15 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="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>