新增班组人员组件

This commit is contained in:
binbin_pan 2024-09-30 16:02:45 +08:00
parent 9abf12e317
commit b57907cea7
7 changed files with 1067 additions and 5 deletions

View File

@ -52,3 +52,31 @@ export const getProjectAndDeviceById = (data) => {
params: data
})
}
// 施工记录数量
export const getTeamDataAmount = (data) => {
return request.get(`/base/screen/homeTwo/getTeamDataAmount`, {
params: data
})
}
// 岗位工种-下拉
export const getProDepartDataList = (data) => {
return request.get(`/base/tbProDepart/getDataList`, {
params: data
})
}
// 施工班组-列表
export const getTeamDetails = (data) => {
return request.get(`/base/screen/homeTwo/getTeamDetails`, {
params: data
})
}
// 施工人员-列表
export const getTeamPeopleDetails = (data) => {
return request.get(`/base/screen/homeTwo/getTeamPeopleDetails`, {
params: data
})
}

View File

@ -0,0 +1,271 @@
<template>
<div class="edge-device-page">
<div class="inner-tit">
<img src="../../assets/img/lef-badge.png" alt="" />
班组人员
<div class="position" @click="handlePieChart(3)">位置</div>
</div>
<div class="inner-cont">
<div class="device-total" @click="handlePieChart(2)">
<div class="lef">
<img src="../../assets/img/device-total.png" alt="" />
</div>
<div class="rig">
<h4 style="font-size: 18px">施工班组数</h4>
<h4
style="
font-size: 24px;
color: #0983fe;
font-weight: bold;
"
>{{ teamDataAmount.teamNum || 0 }}</h4
>
</div>
</div>
<div class="device-online" @click="handlePieChart(1)">
<div class="lef">
<img src="../../assets/img/device-online.png" alt="" />
</div>
<div class="rig">
<h4 style="font-size: 18px">施工人员数</h4>
<h4
style="
font-size: 24px;
color: #3ec076;
font-weight: bold;
"
>{{ teamDataAmount.peopleNum || 0 }}</h4
>
</div>
</div>
</div>
<!-- 饼图 -->
<div class="bottom-echarts">
<div id="pieChart"></div>
</div>
</div>
</template>
<script>
import { getTeamDataAmount } from '@/api/home/home'
import * as echarts from 'echarts'
export default {
props: {
proId: {
type: Number,
default: undefined,
},
},
name: 'leftEight',
components: {},
data() {
return {
//
teamDataAmount: {},
tableVisible: false, //
}
},
created() {},
mounted() {
// this.initPieChart()
},
watch: {
proId: {
handler: function (val) {
console.log('🚀 ~饼图-- val:', val)
if (val) {
this.getTeamDataAmount()
} else {
}
},
immediate: true,
},
},
methods: {
//
async getTeamDataAmount() {
const params = {
proId: this.proId,
}
const res = await getTeamDataAmount(params)
this.teamDataAmount = res.data
//
let pieData = [
{ value: res.data.teamMaster, name: '班组骨干' },
{ value: res.data.teamSame, name: '一般作业人员' },
{ value: res.data.teamSpecial, name: '特种作业人员' },
]
this.initPieChart(pieData)
console.log('🚀 ~饼图--> getTeamDataAmount ~ res:', res)
},
//
initPieChart(pieData) {
let pieChart = echarts.init(document.getElementById('pieChart'))
let option = {
title: {
left: 'left',
top: 20,
textStyle: {
color: '#000',
fontSize: 16,
},
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c}', // abc
},
legend: {
orient: 'vertical',
left: 0,
top: 20,
data: [
{
name: '班组骨干',
icon: 'circle',
},
{
name: '一般作业人员',
icon: 'circle',
},
{
name: '特种作业人员',
icon: 'circle',
},
],
},
series: [
{
name: '班组人员',
type: 'pie',
avoidLabelOverlap: true,
label: {
show: false,
position: 'inner',
},
emphasis: {
label: {
show: true,
fontSize: '13',
},
},
labelLine: {
show: false,
},
data: pieData,
},
],
}
pieChart.setOption(option)
},
//
handlePieChart(val) {
this.$emit('handlePieDialog', val)
},
},
}
</script>
<style lang="scss" scoped>
@font-face {
font-family: 'YouShe';
src: url('../../assets/iconfont/YouSheBiaoTiHei.ttf');
}
.edge-device-page {
height: 100%;
background-color: #f3f7ff;
box-sizing: border-box;
padding: 15px 20px;
margin-bottom: 20px;
border-radius: 5px;
border: 1px solid #eff2fc;
box-shadow: 2px 2px 2px #d9e0f3;
.inner-tit {
width: 100%;
box-sizing: border-box;
padding: 10px 20px;
background-color: #eff4fe;
display: flex;
align-items: center;
color: #000;
font-size: 20px;
font-family: 'YouShe', sans-serif;
box-shadow: -3px -3px 2px #cbdcf6, 2px 2px 2px #f8f9fe,
-2px -2px 2px #cbdcf6, 2px 2px 2px #f8f9fe;
margin-bottom: 15px;
img {
margin-right: 10px;
}
}
.inner-cont {
width: 100%;
display: flex;
justify-content: space-between;
.device-total,
.device-online {
width: 47%;
height: 100px;
box-sizing: border-box;
padding: 8px;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
.lef {
width: 40%;
height: 100%;
display: flex;
align-items: center;
img {
width: 100%;
height: 80%;
}
}
.rig {
width: 55%;
height: 80%;
display: flex;
flex-direction: column;
justify-content: space-around;
h4 {
color: #000;
}
}
}
.device-total {
background: linear-gradient(90deg, #b7d7fe, #d8e6f8);
border: 1px solid #d1e0f2;
}
.device-online {
background: linear-gradient(90deg, #c1ebde, #e7f7fa);
border: 1px solid #d7e7ea;
}
}
.bottom-echarts {
width: 100%;
height: 100%;
#pieChart {
width: 100%;
height: 52%;
}
}
.position {
margin-left: auto;
color: #0983fe;
cursor: pointer;
}
}
</style>

View File

@ -0,0 +1,410 @@
<template>
<div>
<!-- 位置弹框 -->
<el-dialog
title="人员管控"
style="margin-top: 5vh"
:visible.sync="locationVisible"
width="70%"
append-to-body
:close-on-click-modal="false"
>
<div class="hole-page">
<div class="crew">
<el-input
placeholder="请输入人员名"
suffix-icon="el-icon-search"
v-model="crewIpt"
style="margin-bottom: 20px"
/>
<div class="crew-sel">
<div class="sel-top">班组人员</div>
<el-collapse v-model="activeCrew">
<el-collapse-item
v-for="group in searchCrew"
:key="group.teamId"
:name="group.teamName"
>
<template
#title
style="display: flex; align-items: center"
>
<img
src="../../assets/img/crew-spin.png"
alt=""
style="
width: 20px;
height: 20px;
margin-right: 10px;
"
/>
{{ group.teamName }}
</template>
<div
:class="[
'single-crew',
{
crewActive:
crewName === person.peopleName,
},
]"
v-for="person in group.peopleList"
:key="person.peopleId"
@click="handleCrew(person)"
>
<span
style="
padding-right: 5px;
font-weight: bold;
"
>{{ person.peopleName }}</span
>
{{ person.peoplePhone }}
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
<div class="map" v-if="locationVisible">
<div id="map-container"></div>
</div>
<!-- <div class="key-standby">
<div class="inner-tit">
<div>
<img src="../../assets/img/lef-badge.png" alt="" />
关键人员到岗到位
</div>
<span @click="handleSignUp">签到</span>
</div>
<el-table
:data="keyPersonTable"
stripe
style="width: 100%"
:row-style="rowStyle"
>
<el-table-column
prop="postName"
label="职务"
align="center"
>
</el-table-column>
<el-table-column
prop="relName"
label="姓名"
align="center"
width="80"
>
</el-table-column>
<el-table-column
prop="relPhone"
label="手机号"
align="center"
>
</el-table-column>
<el-table-column
prop="createTime"
label="签到时间"
align="center"
width="180"
>
</el-table-column>
</el-table>
</div> -->
<!-- 新增以及修改时的弹框 -->
<DialogModal
:dialogConfig="dialogConfig"
@closeDialogOuter="closeDialogOuter"
>
<template slot="outerContent">
<!-- 新增以及修改数据的表单组件 -->
<TableSign :send-id="sendId" />
</template>
</DialogModal>
</div>
</el-dialog>
</div>
</template>
<script>
import { dialogConfig } from '@/components/substation/config-sign'
import { commonMixin } from '@/views/mixins/common'
import TableSign from '@/components/substation/subComp/table-sign.vue'
import {
queryKeyArriveApi,
queryCrewInfoApi,
queryCrewCoordinateApi,
} from '@/api/substation/substation'
export default {
props: {
proId: {
type: Number,
default: undefined,
},
},
components: {
TableSign,
},
mixins: [commonMixin],
name: 'locationDialog',
data() {
return {
locationVisible: false,
dialogConfig,
crewIpt: undefined,
crewList: [],
coordList: [],
activeCrew: [],
crewName: undefined,
keyPersonTable: [],
sendId: undefined,
}
},
computed: {
searchCrew() {
if (!this.crewIpt) {
return this.crewList
} else {
return this.crewList.map((item) => ({
teamId: item.teamId,
teamName: item.teamName,
peopleList: item.peopleList.filter((child) =>
child.peopleName.includes(this.crewIpt),
),
}))
}
},
},
created() {},
mounted() {
this.sendId = this.proId
// this.getCrewData()
// this.getKeyData()
// this.getCrewCoordinate()
// this.createMap()
},
methods: {
openDialog() {
this.locationVisible = true
this.getCrewData()
this.getKeyData()
this.getCrewCoordinate()
},
async getCrewData() {
let res = await queryCrewInfoApi({
proId: this.proId,
})
this.crewList = res.data
},
async getKeyData() {
let res = await queryKeyArriveApi({
isAll: 0,
proId: this.proId,
})
res.data.forEach((item) => {
item.relPhone = this.phoneCrypto(item.relPhone)
})
this.keyPersonTable = res.data
},
async getCrewCoordinate() {
this.coordList = []
let res = await queryCrewCoordinateApi({
proId: this.proId,
})
this.coordList = res.data
this.createMap(res.data)
},
closeDialogOuter() {
this.getKeyData()
this.dialogConfig.outerVisible = false
},
rowStyle(scope) {
if (scope.rowIndex % 2 === 0) {
return {
background: '#EAF5FF',
}
} else {
return {
background: '#E1EEFF',
}
}
},
createMap(list) {
console.log(list, 'coord')
let this_ = this
this.$nextTick(() => {
this_.map = new BMapGL.Map('map-container') //
let point = new BMapGL.Point(list[0].lon, list[0].lat) //
this_.map.centerAndZoom(point, 14) //
this_.map.enableScrollWheelZoom(true) //
this_.map.setHeading(0) //
this_.map.setTilt(0) //
var geoc = new BMapGL.Geocoder()
list.forEach((item) => {
let point = new BMapGL.Point(item.lon, item.lat)
let marker = new BMapGL.Marker(point)
this.map.addOverlay(marker)
})
this_.map.addEventListener('click', function (e) {
console.log(e)
var pt = e.latlng
geoc.getLocation(pt, function (res) {
console.log(res, 'res')
})
this_.map.clearOverlays()
point = new BMapGL.Point(e.latlng.lng, e.latlng.lat)
let marker = new BMapGL.Marker(point) //
this_.map.addOverlay(marker)
})
})
},
handleCrew(v) {
this.crewName = v.peopleName
console.log(v, this.coordList)
this.coordList.forEach((item) => {
if (item.relName === v.peopleName) {
this.map.clearOverlays()
let point = new BMapGL.Point(item.lon, item.lat)
let marker = new BMapGL.Marker(point)
this.map.addOverlay(marker)
this.map.centerAndZoom(point, 14)
}
})
},
handleSignUp() {
this.dialogConfig.outerVisible = true
},
},
}
</script>
<style lang="less" scoped>
/deep/ .el-collapse-item__header {
background-color: transparent !important;
box-sizing: border-box;
padding-left: 15px;
font-size: 18px;
font-weight: bold;
border-bottom: 1px solid #bac4cd;
}
/deep/ .el-collapse-item__content {
padding-bottom: 0;
font-size: 16px;
}
/deep/ .el-collapse-item__wrap {
background-color: transparent;
}
/deep/ .el-input__inner {
background-color: #ecf3fe;
border-radius: 20px;
}
@font-face {
font-family: 'YouShe';
src: url('../../assets/iconfont/YouSheBiaoTiHei.ttf');
}
.hole-page {
width: 100%;
height: 70vh;
display: flex;
justify-content: space-between;
.crew {
width: 30%;
height: 100%;
background-color: #f3f7ff;
box-sizing: border-box;
padding: 20px;
border-radius: 5px;
border: 1px solid #eff2fc;
box-shadow: 2px 2px 2px #d9e0f3;
display: flex;
flex-direction: column;
.crew-sel {
flex: 1;
border: 1px solid #c6daf8;
background: linear-gradient(180deg, #e8f2fc, #d6e6f7);
border-radius: 5px;
.sel-top {
width: 100%;
box-sizing: border-box;
padding: 20px 35px;
background-color: #d3e4fa;
font-size: 18px;
font-weight: bold;
color: #000;
}
.single-crew {
box-sizing: border-box;
padding: 15px 30px;
border-top: 1px dashed #cfd8e5;
background-color: transparent;
cursor: pointer;
}
.crewActive {
background-color: #d3e4fa;
}
}
}
.map {
width: 68%;
height: 100%;
#map-container {
width: 100%;
height: 100%;
}
}
.key-standby {
width: 35%;
height: 100%;
background-color: #f3f7ff;
box-sizing: border-box;
padding: 20px;
border-radius: 5px;
border: 1px solid #eff2fc;
box-shadow: 2px 2px 2px #d9e0f3;
display: flex;
flex-direction: column;
.inner-tit {
width: 100%;
box-sizing: border-box;
padding: 10px 20px;
background-color: #eff4fe;
display: flex;
align-items: center;
justify-content: space-between;
color: #000;
font-size: 20px;
font-family: 'YouShe', sans-serif;
box-shadow: -3px -3px 2px #cbdcf6, 2px 2px 2px #f8f9fe,
-2px -2px 2px #cbdcf6, 2px 2px 2px #f8f9fe;
margin-bottom: 15px;
span {
color: #fff;
box-sizing: border-box;
padding: 5px 15px;
background-color: #0297fc;
border-radius: 5px;
cursor: pointer;
}
}
}
}
</style>

View File

@ -0,0 +1,177 @@
<template>
<div>
<!-- 施工人员数弹框 -->
<el-dialog
title=""
style="margin-top: 5vh"
:visible.sync="tableVisible"
width="80%"
append-to-body
:close-on-click-modal="false"
>
<!-- 表单 -->
<el-form inline :model="formData" class="demo-form-inline">
<el-form-item label="姓名" prop="peopleName" size="small">
<el-input
v-model="formData.peopleName"
placeholder="请输入姓名"
></el-input>
</el-form-item>
<el-form-item label="岗位工种" prop="postCode">
<el-select
v-model="formData.postCode"
placeholder="请选择岗位工种"
clearable
>
<el-option
v-for="(item, index) in postTypeOptions"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="handleQuery"
icon="el-icon-search"
>查询</el-button
>
</el-form-item>
</el-form>
<!-- 列表 -->
<el-table
:data="tableData"
style="width: 100%"
height="500"
border
stripe
>
<el-table-column
type="index"
label="序号"
width="80"
align="center"
:index="
indexContinuation(formData.pageNum, formData.pageSize)
"
></el-table-column>
<el-table-column
prop="peopleName"
label="姓名"
></el-table-column>
<el-table-column prop="sexName" label="性别"></el-table-column>
<el-table-column prop="phone" label="手机号"></el-table-column>
<el-table-column
prop="postCodeName"
label="岗位工种"
></el-table-column>
</el-table>
<pagination
v-if="total > 0"
:total="total"
:page.sync="formData.pageNum"
:limit.sync="formData.pageSize"
@pagination="getTableList"
/>
</el-dialog>
</div>
</template>
<script>
import { getProDepartDataList, getTeamPeopleDetails } from '@/api/home/home'
export default {
props: {
proId: {
type: Number,
default: undefined,
},
},
name: 'pieDialog',
data() {
return {
tableVisible: false,
formData: {
pageNum: 1,
pageSize: 10,
peopleName: '',
postCode: '',
},
total: 0,
tableData: [],
//
postTypeOptions: [],
}
},
created() {},
mounted() {},
watch: {},
methods: {
//
async getProDepartDataList() {
this.postTypeOptions = []
const params = {
dictType: 'post_type',
}
const res = await getProDepartDataList(params)
console.log('🚀 ~ 获取岗位下拉 ~ res:', res)
if (res.code === 200 && res.data.length > 0) {
res.data.forEach((item) => {
if (item.dictLabel == '0900101') {
item.label = '班组负责人'
} else if (item.dictLabel == '0900102') {
item.label = '班组安全员'
} else if (item.dictLabel == '0900103') {
item.label = '班组技术员'
} else if (item.dictLabel == '0900104') {
item.label = '一般作业人员'
} else if (item.dictLabel == '0900106') {
item.label = '特种作业人员'
}
this.postTypeOptions.push({
label: item.label,
value: item.dictLabel,
})
})
} else {
this.postTypeOptions = []
}
},
openDialog(proId) {
//
this.formData = {
pageNum: 1,
pageSize: 10,
peopleName: '',
postCode: '',
}
console.log('🚀 ~ openDialog ~ proId:', proId)
this.tableVisible = true
this.getProDepartDataList()
this.getTableList()
},
handleQuery() {
console.log('🚀 ~ handleQuery ~ ', this.formData)
this.getTableList()
},
//
async getTableList() {
const params = {
...this.formData,
proId: this.proId,
}
console.log('🚀 ~ getTableList ~ ', params)
const res = await getTeamPeopleDetails(params)
this.tableData = res.rows
this.total = res.total
console.log('🚀 ~ 列表 ~ res:', res)
},
},
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,146 @@
<template>
<div>
<!-- 班组弹框 -->
<el-dialog
title=""
style="margin-top: 5vh"
:visible.sync="tableVisible"
width="80%"
append-to-body
:close-on-click-modal="false"
>
<!-- 表单 -->
<el-form inline :model="formData" class="demo-form-inline">
<el-form-item label="班组名称" prop="teamName" size="small">
<el-input
v-model="formData.teamName"
placeholder="请输入班组名称"
clearable
></el-input>
</el-form-item>
<el-form-item label="班组长" prop="masterName">
<el-input
v-model="formData.masterName"
placeholder="请输入班组长"
clearable
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="handleQuery"
icon="el-icon-search"
>查询</el-button
>
</el-form-item>
</el-form>
<!-- 列表 -->
<el-table
:data="tableData"
style="width: 100%"
height="500"
border
stripe
>
<el-table-column
type="index"
label="序号"
width="80"
align="center"
:index="
indexContinuation(formData.pageNum, formData.pageSize)
"
></el-table-column>
<el-table-column
prop="teamName"
label="班组名称"
></el-table-column>
<el-table-column
prop="masterName"
label="班组长"
></el-table-column>
<el-table-column
prop="masterPhone"
label="班组长电话"
></el-table-column>
<el-table-column
prop="peopleCount"
label="班组人数"
></el-table-column>
</el-table>
<pagination
v-if="total > 0"
:total="total"
:page.sync="formData.pageNum"
:limit.sync="formData.pageSize"
@pagination="getTableList"
/>
</el-dialog>
</div>
</template>
<script>
import { getTeamDetails } from '@/api/home/home'
export default {
props: {
proId: {
type: Number,
default: undefined,
},
},
name: 'pieDialog',
data() {
return {
tableVisible: false,
formData: {
pageNum: 1,
pageSize: 10,
teamName: '',
masterName: '',
},
total: 0,
tableData: [],
//
postTypeOptions: [],
}
},
created() {},
mounted() {},
watch: {},
methods: {
openDialog(proId) {
//
this.formData = {
pageNum: 1,
pageSize: 10,
teamName: '',
postCode: '',
}
console.log('🚀 ~ openDialog ~ proId:', proId)
this.tableVisible = true
this.getTableList()
},
handleQuery() {
console.log('🚀 ~ handleQuery ~ ', this.formData)
this.getTableList()
},
//
async getTableList() {
const params = {
...this.formData,
proId: this.proId,
}
console.log('🚀 ~ getTableList ~ ', params)
const res = await getTeamDetails(params)
this.tableData = res.rows
this.total = res.total
console.log('🚀 ~ 列表 ~ res:', res)
},
},
}
</script>
<style lang="scss" scoped></style>

View File

@ -111,6 +111,7 @@ import LeftThree from '@/components/home/leftThree.vue'
import LeftFive from '@/components/home/leftFive.vue'
import LeftSix from '@/components/home/leftSix.vue'
import LeftSeven from '@/components/home/leftSeven.vue'
import leftEight from '@/components/home/leftEight.vue'
import RightOne from '@/components/home/rightOne.vue'
import RightTwo from '@/components/home/rightTwo.vue'
import CountryMap from '@/components/home/countryMap.vue'
@ -130,7 +131,8 @@ export default {
CountryMap,
LeftFive,
LeftSix,
LeftSeven
LeftSeven,
leftEight
},
computed: {
searchComp() {
@ -462,7 +464,16 @@ export default {
h: 1,
isAccord: '1*1',
rigCont: '1*3'
}
},
{
id: 10,
name: '班组人员',
componentName: 'leftEight',
w: 1,
h: 1,
isAccord: '1*1',
rigCont: '1*1'
},
],
rowHeight: 0,
previewLayout: [],

View File

@ -22,7 +22,7 @@
>
<div class="item-box">
<component v-if="item.componentName === 'CountryMap'" :is="item.componentName" :send-geo="sendGeo"/>
<component v-else :is="item.componentName" @openDialog="handleDialog" :proId="proId"/>
<component v-else :is="item.componentName" @openDialog="handleDialog" :proId="proId" @handlePieDialog="handlePieDialog"/>
</div>
</GridItem>
</GridLayout>
@ -31,7 +31,9 @@
ref="dialogRef"
>
</common-dialog>
<PieDialog ref="pieDialog" :proId="proId" />
<TeamDialog ref="teamDialog" :proId="proId" />
<LocationDialog ref="locationDialog" :proId="proId" />
</div>
</template>
@ -49,10 +51,14 @@ import LeftThree from '@/components/home/leftThree.vue'
import LeftFive from '@/components/home/leftFive.vue'
import LeftSix from '@/components/home/leftSix.vue'
import LeftSeven from '@/components/home/leftSeven.vue'
import leftEight from '@/components/home/leftEight.vue'
import RightOne from '@/components/home/rightOne.vue'
import RightTwo from '@/components/home/rightTwo.vue'
import CountryMap from '@/components/home/countryMap.vue'
import CommonDialog from '@/components/home/commonDialog.vue'
import PieDialog from '@/components/home/pieDialog.vue'
import TeamDialog from '@/components/home/teamDialog.vue'
import LocationDialog from '@/components/home/locationDialog.vue'
import {
queryTableApi
} from '@/api/home/home'
@ -84,7 +90,11 @@ export default {
CommonDialog,
LeftFive,
LeftSix,
LeftSeven
LeftSeven,
leftEight,
PieDialog,
TeamDialog,
LocationDialog
},
data() {
return {
@ -255,6 +265,15 @@ export default {
}
})
},
handlePieDialog(val) {
if (val == 1) {
this.$refs.pieDialog.openDialog(this.proId)
} else if (val == 2) {
this.$refs.teamDialog.openDialog(this.proId)
} else {
this.$refs.locationDialog.openDialog(this.proId)
}
}
}
}
</script>