YZProjectCloud/yanzhu-bigscreen/src/views/projectLabor.vue

517 lines
19 KiB
Vue

<template>
<div class="project-labor main-page">
<el-col :span="6" class="h100">
<module-one-1-1 label="劳务人员概况">
<div class="attendance-info warning-info">
<div class="attendance-info-title warning-info-title">
<div :class="attendanceNav == 0 ? 'active' : ''" @click="doAttendanceNav(0, '在岗人员')">在岗人员</div>
<div :class="attendanceNav == 1 ? 'active' : ''" @click="doAttendanceNav(1, '今日出勤')">今日出勤</div>
</div>
<el-row>
<el-col :span="8" class="attendance-tag">
<div class="survey_content">
<div class="survey_content_img">
<img
:src="
attendanceNav == 0
? 'images/survey_icon_4.png'
: 'images/survey_icon_5.png'
"
/>
</div>
</div>
<div class="survey_content_number labour-survey_content_number">
<div class="survey_content_value">
<span>{{ attendanceTotal }}</span>
</div>
<p>{{ attendanceNav == 0 ? "在岗人员" : "今日出勤" }}</p>
</div>
</el-col>
<el-col :span="16">
<staffSurveyChart :key="chartKey" :height="$dpi() == '1K' ? '220px' : $dpi() == '2K' ? '330px' : '550px'" :data="attendanceData" :width="140"></staffSurveyChart>
</el-col>
</el-row>
</div>
</module-one-1-1>
<module-one-1-1 label="劳务人员七天出勤趋势">
<my-chart :key="chartKey" id="prj_labor_chart2" width="100%" height="100%" :render="renderChart2"></my-chart>
</module-one-1-1>
<module-one-1-1 label="劳务人员年龄分布">
<my-chart :key="chartKey" id="prj_labor_chart3" width="100%" height="100%" :render="renderChart3"></my-chart>
</module-one-1-1>
</el-col>
<el-col :span="12" class="h100">
<module-one-2-2 label class="no-title no-border">
<my-chart :key="chartKey" id="prj-labor-map" width="100%" height="100%" :render="renderMap"></my-chart>
</module-one-2-2>
<module-one-1-2 label="实时进出" class="prj-plan"></module-one-1-2>
</el-col>
<el-col :span="6" class="h100">
<module-one-1-1 label="工种占比分布"></module-one-1-1>
<module-one-1-1 label="人员地区分布">
<my-chart :key="chartKey" id="prj_labor_chart5" width="100%" height="100%" :render="renderChart5"></my-chart>
</module-one-1-1>
<module-one-1-1 label="人员预期"></module-one-1-1>
</el-col>
</div>
</template>
<script>
import debounce from 'lodash.debounce'
import staffSurveyChart from '@/components/staffSurveyChart.vue'
export default {
components: { staffSurveyChart },
data() {
return {
dpi: '',
chartKey: 0,
selProject: null,
attendanceNav: 0,
attendanceTotal: 0,
attendanceData: [
{ text: '普通工种', value: 0, id: 0 },
{ text: '特殊工种', value: 0, id: 0 },
{ text: '管理人员', value: 0, id: 0 },
],
nativeList: [],
ageList: [],
weekData: [],
}
},
methods: {
init() {
if (!this.selProject) {
return
}
this.loadAttendanceData()
this.getGroupByWorker()
this.groupAttendanceLastWeek()
},
groupAttendanceLastWeek() {
this.$api.labor.groupAttendanceLastWeek(this.selProject.vendorsCode, this.selProject.id).then((d) => {
this.weekData = d.data.map((it) => {
return {
name: it.dt.substring(5).replace('-', '.'),
value: it.cnt,
//value: it.cnt + parseInt(Math.random() * 100),
}
})
})
},
getGroupByWorker() {
this.$api.labor.groupByWorker(this.selProject.vendorsCode, this.selProject.id).then((d) => {
this.nativeList = (d.data.native || []).map((it) => {
it.name = it.nativePlace
it.value = it.count
return it
})
this.ageList = (d.data.age || []).map((it) => {
it.name = ['', '18~30', '30~40', '40~55', '55岁以上'][it.age]
it.value = it.count
return it
})
this.chartKey++
})
},
renderChart2(opt) {
const areaOption = {
grid: {
left: '5%',
right: '5%',
bottom: '0%',
top: '15%',
containLabel: true,
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
backgroundColor: '#6a7985',
},
},
},
xAxis: {
type: 'category',
data: this.weekData.map((item) => item.name),
axisLabel: {
textStyle: {
color: '#0df2c8',
},
},
},
yAxis: {
type: 'value',
minInterval: 1,
axisLabel: {
textStyle: {
color: '#0df2c8',
},
},
},
series: [
{
name: '出勤人数',
type: 'line',
areaStyle: {
color: 'rgba(13, 204, 242,0.5)', // 设置面积背景颜色为红色
},
label: {
show: true,
position: 'top', // 值标签显示在折线点上方
textStyle: {
color: '#0df2c8', // 设置标签文字颜色为红色
},
},
data: this.weekData.map((item) => item.value),
},
],
}
return areaOption
},
renderChart3(opt) {
let pieOption = {
tooltip: {
trigger: 'item',
formatter: '{b} 岁 <br/> {c} 人 ({d}%)',
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center',
data: this.ageList.map((it) => it.name),
textStyle: {
color: '#19c0e6',
},
},
series: [
{
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: this.ageList,
label: {
normal: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
emphasis: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
},
},
},
],
}
return pieOption
},
renderChart5(opt) {
const pieOption = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)',
},
series: [
{
type: 'pie',
radius: ['50%', '70%'], // 设置为圆环图
avoidLabelOverlap: false,
label: {
normal: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
emphasis: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
},
emphasis: {
label: {
show: true,
fontSize: '30',
fontWeight: 'bold',
},
},
data: this.nativeList,
},
],
}
return pieOption
},
doAttendanceNav(n) {
this.attendanceNav = n
this.loadAttendanceData()
},
loadJhAttendanceData() {
let data = {
id: this.attendanceNav,
projectId: this.selProject.id,
attendanceTime: this.$dt(new Date()).format('YYYY-MM-DD'),
}
let ajax = this.$api.detail.groupByComany
if (this.attendanceNav != 1) {
ajax = this.$api.detail.groupAllByComany
}
ajax(data).then((d) => {
let tmps = d.data || []
const func = (ids) => {
let sum = 0
tmps.filter((it) => ids.includes(it.companyTypeId))
.map((it) => it.id)
.forEach((it) => {
sum += it * 1
})
return sum
}
this.attendanceTotal = 0
this.attendanceData = [
{ text: '劳务人员', value: func(['0', '2', '3', '4', '5']) },
{ text: '监理人员', value: func(['8']) },
{ text: '总包人员', value: func(['1', '6']) },
]
this.attendanceData.forEach((it) => {
this.attendanceTotal += it.value
})
})
},
loadUniAttendanceData() {
let ajax = this.$api.detail.groupByCraftType
let posData = {
comId: this.selProject.comId,
projectId: this.selProject.id,
}
if (this.attendanceNav == 1) {
ajax = this.$api.detail.groupByCraftTypeByAttendance
posData.createTime = this.$dt(new Date()).format('YYYY-MM-DD')
//posData.createTime = '2024-10-13'
}
ajax(posData).then((d) => {
this.attendanceData = (d.data || []).map((it) => {
return {
text: it.createBy,
value: it.id || 0,
id: it.craftType,
}
})
let count = 0
this.attendanceData.forEach((it) => {
count += it.value
})
this.attendanceTotal = count
})
},
renderMap(opt, myChart) {
let mapName = 'china'
let data = this.nativeList
let geoCoordMap = {}
/*获取地图数据*/
let mapFeatures = echarts.getMap(mapName).geoJson.features
let allData = []
mapFeatures.forEach(function (v) {
// 地区名称
var name = v.properties.name
// 地区经纬度
geoCoordMap[name] = v.properties.cp
allData.push({
name: name,
value: 0,
})
})
let max = 880,
min = 3 // todo
let maxSize4Pin = 80,
minSize4Pin = 20
let convertData = function (data, lbl) {
let res = []
if (lbl == 1) {
data = allData
}
for (let i = 0; i < data.length; i++) {
let geoCoord = geoCoordMap[data[i].name]
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(data[i].value),
})
}
}
if (lbl == 1) {
return res
}
return res.filter((d) => d.value[2] > 0)
}
let option = {
visualMap: {
show: false,
min: 0,
max: 200,
left: 'left',
top: 'bottom',
text: ['高', '低'], // 文本,默认为数值文本
calculable: true,
seriesIndex: [1],
inRange: {
color: ['#00e1ff00', '#3da2ffFF'],
//color: ['#3B5077', '#031525'], // 蓝黑
// color: ['#ffc0cb', '#800080'] // 红紫
// color: ['#3C3B3F', '#605C3C'] // 黑绿
// color: ['#0f0c29', '#302b63', '#24243e'] // 黑紫黑
// color: ['#23074d', '#cc5333'] // 紫红
//color: ['#00467F', '#A5CC82'], // 蓝绿
// color: ['#1488CC', '#2B32B2'] // 浅蓝
// color: ['#00467F', '#A5CC82'] // 蓝绿
// color: ['#00467F', '#A5CC82'] // 蓝绿
// color: ['#00467F', '#A5CC82'] // 蓝绿
// color: ['#00467F', '#A5CC82'] // 蓝绿
},
},
geo: {
show: true,
map: mapName,
label: {
normal: {
show: false,
},
emphasis: {
show: false,
},
},
roam: true,
itemStyle: {
normal: {
areaColor: '#031525',
borderColor: '#3B5077',
},
emphasis: {
areaColor: '#2B91B7',
},
},
},
series: [
{
name: '散点',
type: 'scatter',
coordinateSystem: 'geo',
data: convertData(data, 1),
symbolSize: function (val) {
return val[2] / 10
},
label: {
normal: {
formatter: '{b}',
position: 'right',
show: true,
},
emphasis: {
show: true,
},
},
itemStyle: {
normal: {
color: '#05C3F9',
},
},
},
{
type: 'map',
map: mapName,
geoIndex: 0,
aspectScale: 0.75, //长宽比
showLegendSymbol: false, // 存在legend时显示
select: {
disabled: true,
label: {
show: false,
},
},
data: data,
},
{
name: '点',
type: 'scatter',
coordinateSystem: 'geo',
symbol: 'pin', //气泡
symbolSize: function (val) {
var a = (maxSize4Pin - minSize4Pin) / (max - min)
var b = minSize4Pin - a * min
b = maxSize4Pin - a * max
return a * val[2] + b
},
label: {
normal: {
formatter: (a) => {
return a.value[2]
},
show: true,
textStyle: {
color: '#fff',
fontSize: 9,
},
},
},
itemStyle: {
normal: {
color: '#F62157', //标志颜色
},
},
zlevel: 6,
data: convertData(data, 2),
},
],
}
return option
},
loadAttendanceData() {
if (this.selProject.vendorsCode != 'uni') {
this.loadJhAttendanceData()
} else {
this.loadUniAttendanceData()
}
},
},
mounted() {
window.plApp = this
this.$store.dispatch('ChangeNav', 102)
this.$bus.$on(
'projectChange',
debounce((prj) => {
this.selProject = prj
this.init()
})
)
this.selProject = this.$store.getters.selProject
this.init()
this.dpi = this.$dpi()
window.addEventListener('resize', () => {
if (this.dpi != this.$dpi()) {
this.dpi = this.$dpi()
this.chartKey++
}
})
},
}
</script>
<style>
</style>