Files
laws_weilai/jero-web/src/views/projectManagement/projectStatusBoard/index.vue
T

635 lines
19 KiB
Java

<template>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :md="6" :sm="8">
<div class="box-title-text">
<div class="title-text" :title="$t('entryName')">
<span>{{$t('entryName')}}</span>
</div>
<j-input class="box-input" :placeholder="$t('PleaseEnter')+$t('entryName')"
v-model="queryParam.projectName"></j-input>
</div>
</a-col>
<a-col :md="6" :sm="8">
<div class="box-title-text">
<div class="title-text" :title="$t('targetMarket')">
<span>{{$t('targetMarket')}}</span>
</div>
<j-dict-select-tag class="box-input" v-model="queryParam.targetMarket"
:placeholder="$t('PleaseSelect')+$t('targetMarket')"
:type="'select'"
:triggerChange="false" :dictCode="'region'"/>
</div>
</a-col>
<span style="float: right;overflow: hidden;margin-right: 11px" class="table-page-search-submitButtons">
<a-col :md="6" :sm="24">
<a-button class="box-button" type="primary" @click="searchQuery">{{$t('query')}}</a-button>
<a-button class="box-button" style="margin-left: 8px" @click="searchReset">{{$t('reset')}}</a-button>
</a-col>
</span>
</a-row>
</a-form>
</div>
<div class="box-top">
<span class="box-top-text">{{$t('regulatoryCertificationTaskPlan')}}</span>
<span class="box-top-text fullScreenView" @click="TaskPlanListClick">{{$t('fullScreenView')}}</span>
<span style="float: right" class="box-top-text-right">
<a-range-picker
:placeholder="[this.$t('startMonth'), this.$t('endMonth')]"
format="YYYY-MM"
v-model="getTime"
:mode="mode2"
:open="open"
@openChange="openChange"
@panelChange="panelChange"
@change="hodeChange"
>
<div slot="renderExtraFooter" style="width: 100%;display: block">
<div style="text-align: right;width: 100%">
<a @click="okChange">{{$t('determine')}}</a>
</div>
</div>
</a-range-picker>
</span>
<div class="box-top-content" style="position: relative">
<!-- <div id="main"></div>-->
<!-- <div class="axis-tip"></div>-->
<div class="box-top-content-left">
<div class="box-top-content-left-text" :title="item.projectName"
v-for="(item,index) in timeData" :key="index">
{{item.projectName}}
</div>
</div>
<div class="box-top-content-right">
<div class="box-top-content-right-top">
<div class="box-top-content-right-top-text" v-for="(item,index) in timeList" :key="index">{{item}}</div>
</div>
<div class="box-top-content-right-bottom">
<div class="process-content" v-for="(item,index) in timeData" :key="index">
<div class="process-content-right-xian"></div>
<div class="process-content-content" :style="val.left"
v-for="(val,indexOne) in item.data[0]" :key="indexOne">
<a-tooltip placement="topLeft">
<template slot="title">
<span>{{val.time.slice(0,11)}}</span>
</template>
<div class="process-content-right-top">{{val.name}}</div>
<img v-if="val.status == 1" src="../../../assets/done.svg" class="process-content-left"
alt="">
<img v-else-if="val.status == 2" src="../../../assets/open.svg"
class="process-content-left"
alt="">
<img v-else-if="val.status == 3" src="../../../assets/inprogress.svg" class="process-content-left"
alt="">
</a-tooltip>
<!-- <div class="process-content-right-button">{{val.time.slice(0,11)}}</div>-->
</div>
</div>
<div class="box-top-content-right-xian"></div>
<div class="box-top-content-right-text">
{{handlingTime}}
</div>
</div>
</div>
<JLoading :loading="loadingMain">{{this.$t('dataLoading')}}</JLoading>
</div>
</div>
<div class="box-bottom">
<span class="box-top-text">{{$t('projectStatusAndProgress')}}</span>
<span class="box-top-text fullScreenView" @click="projectNameClick">{{$t('fullScreenView')}}</span>
<div>
<a-table
ref="table"
size="middle"
:loading="loading"
:pagination="false"
:scroll="{x: '100%',y:500}"
:data-source="dataSource"
:columns="columns"
>
<span slot="projectStatusTitle">
<span>{{this.$t('CurrentStatusOfTheProject')}}</span><br/>
<span>{{'('+$t('red')+'/'+$t('yellow')+'/'+$t('green')+'/'+$t('blue')+')'}}</span>
</span>
<span slot="CertificationProgressTitle">
<span>{{this.$t('CertificationProgress')}}</span><br/>
<span>{{'('+$t('notInvolved')+'/'+$t('toBeStarted')+'/'+$t('inProgress')+'/'+$t('experimentFailed')+'/'+$t('experimentPassed')+')'}}</span>
</span>
<span slot="listConfirmationStatusTitle">
<span>{{this.$t('listConfirmation')}}</span><br/>
<span>{{'('+$t('notLaunch')+'/'+$t('toBeConfirmed')+'/'+$t('accept')+'/'+$t('refuse')+')'}}</span>
</span>
<span slot="taskAffirmStatusTitle">
<span>{{this.$t('taskAffirm')}}</span><br/>
<span>{{'('+$t('notLaunch')+'/'+$t('toBeConfirmed')+'/'+$t('accept')+'/'+$t('refuse')+')'}}</span>
</span>
<span slot="designComplianceReviewTitle">
<span>{{this.$t('designComplianceReview')}}</span><br/>
<span>{{'('+$t('toBeConfirmed')+'/'+$t('accord')+'/'+$t('nonConformity')+'/'+$t('Tracked')+'/'+$t('notInvolved')+'/'+$t('taskTermination')+')'}}</span>
</span>
<span slot="preHomeConfirmationTitle">
<span>{{this.$t('preHomeConfirmation')}}</span><br/>
<span>{{'('+$t('toBeConfirmed')+'/'+$t('accord')+'/'+$t('nonConformity')+'/'+$t('Tracked')+'/'+$t('notInvolved')+'/'+$t('taskTermination')+')'}}</span>
</span>
<span slot="verificationComplianceReviewTitle">
<span>{{this.$t('verificationComplianceReview')}}</span><br/>
<span>{{'('+$t('toBeConfirmed')+'/'+$t('accord')+'/'+$t('nonConformity')+'/'+$t('Tracked')+'/'+$t('notInvolved')+'/'+$t('taskTermination')+')'}}</span>
</span>
</a-table>
</div>
</div>
</a-card>
</template>
<script>
import { getAction, postAction, deleteAction, downloadFile } from '@/api/manage'
import * as echarts from 'echarts'
import moment from 'moment'
export default {
name: 'index',
data() {
return {
queryParam: {},
timeList: [],
timeData: [],
loading: false,
loadingMain: false,
dataSource: [],
open: false,
getTime: [],
mode2: ['month', 'month'],
url: {
list: '/project/ProjectStatusBoardController/scheduleInfoList',
timeline: '/project/ProjectStatusBoardController/timeline',
timelineList: '/project/ProjectStatusBoardController/timelineList'
},
columns: [
{
title: this.$t('entryName'),
align: 'center',
dataIndex: 'projectName',
scopedSlots: { customRender: 'projectName' },
width: 180,
ellipsis: true
},
{
title: this.$t('targetMarket'),
align: 'center',
dataIndex: 'targetMarket',
width: 180,
ellipsis: true
},
{
align: 'center',
dataIndex: 'projectStatus',
scopedSlots: { title: 'projectStatusTitle' },
width: 240,
ellipsis: true
},
{
align: 'center',
dataIndex: 'certificationProgress',
width: 380,
ellipsis: true,
scopedSlots: { title: 'CertificationProgressTitle' }
},
{
align: 'center',
dataIndex: 'inventory',
width: 340,
ellipsis: true,
scopedSlots: { title: 'listConfirmationStatusTitle' }
},
{
align: 'center',
dataIndex: 'task',
width: 340,
ellipsis: true,
scopedSlots: { title: 'taskAffirmStatusTitle' }
},
{
align: 'center',
dataIndex: 'design',
width: 440,
scopedSlots: { title: 'designComplianceReviewTitle' }
},
{
dataIndex: 'pre',
align: 'center',
width: 440,
scopedSlots: { title: 'preHomeConfirmationTitle' }
},
{
dataIndex: 'verify',
align: 'center',
width: 440,
scopedSlots: { title: 'verificationComplianceReviewTitle' }
}
],
startTime: undefined,
endTime: undefined,
handlingTime: ''
}
},
mounted() {
this.getList()
this.getTimeline()
this.handlingTime = moment(new Date()).format('YYYY-MM-DD')
},
methods: {
getTimeline() {
let query = {
startTime: this.startTime,
endTime: this.endTime,
...this.queryParam
}
this.loadingMain = true
getAction(this.url.timeline, query).then((res) => {
if (res.success) {
this.getTimelineList(res.result)
} else {
this.loadingMain = false
}
})
},
openChange(val) {
this.open = val
},
okChange() {
this.open = false
this.getTimeline()
},
hodeChange() {
this.getTime = []
this.startTime = undefined
this.endTime = undefined
this.getTimeline()
},
panelChange(value, mode) {
this.getTime = value
this.startTime = moment(value[0]).format('YYYY-MM')
this.endTime = moment(value[1]).format('YYYY-MM')
},
getTimelineList(time) {
let query = {
startTime: this.startTime,
endTime: this.endTime,
...this.queryParam
}
getAction(this.url.timelineList, query).then((res) => {
if (res.success) {
this.getEcharts(time, res.result)
} else {
this.loadingMain = false
}
})
},
getEcharts(timeList, timeData) {
this.timeList = []
if (timeList.length <= 12) {
this.timeList = timeList
} else if (timeList.length <= 24) {
timeList.forEach((res, index) => {
if (index == 0) {
this.timeList.push(res)
} else if (index == timeList.length - 1) {
this.timeList.push(res)
} else if (index % 2 == 0) {
if (this.timeList.length < 11) {
this.timeList.push(res)
}
}
})
} else if (timeList.length <= 36) {
timeList.forEach((res, index) => {
if (index == 0) {
this.timeList.push(res)
} else if (index == timeList.length - 1) {
this.timeList.push(res)
} else if (index % 3 == 0) {
if (this.timeList.length < 11) {
this.timeList.push(res)
}
}
})
} else if (timeList.length <= 48) {
timeList.forEach((res, index) => {
if (index == 0) {
this.timeList.push(res)
} else if (index == timeList.length - 1) {
this.timeList.push(res)
} else if (index % 4 == 0) {
if (this.timeList.length < 11) {
this.timeList.push(res)
}
}
})
} else if (timeList.length <= 60) {
timeList.forEach((res, index) => {
if (index == 0) {
this.timeList.push(res)
} else if (index == timeList.length - 1) {
this.timeList.push(res)
} else if (index % 5 == 0) {
if (this.timeList.length < 11) {
this.timeList.push(res)
}
}
})
}
let dataList = document.getElementsByClassName('box-top-content-right-top-text')
let contentRightText = document.getElementsByClassName('box-top-content-right-text')
let contentRightXian = document.getElementsByClassName('box-top-content-right-xian')
setTimeout(() => {
let length = timeList.length / dataList.length
let clientWidth = dataList[0].clientWidth
clientWidth = clientWidth / length
for (let i = 0; i < timeData.length; i++) {
for (let j = 0; j < timeData[i].data[0].length; j++) {
for (let k = 0; k < dataList.length; k++) {
let num = (Math.ceil(clientWidth / 31)) * parseInt(timeData[i].data[0][j].time.slice(8, 10))
timeList.forEach((res, index) => {
if (timeData[i].data[0][j].time.slice(0, 7) == res.slice(0, 7)) {
timeData[i].data[0][j].left = 'left:' + ((clientWidth * index + num) - 16) + 'px'
}
})
}
}
}
contentRightText[0].style = 'display:none'
contentRightXian[0].style = 'display:none'
let clientWidthOne = dataList[0].clientWidth
clientWidthOne = clientWidthOne / length
let num = Math.ceil(clientWidthOne / 31) * parseInt(this.handlingTime.slice(8, 10))
timeList.forEach((res, index) => {
if (res.slice(0, 7) == this.handlingTime.slice(0, 7)) {
contentRightText[0].style = 'left:' + ((clientWidthOne * index + num) - 24) + 'px;' + 'display:block'
contentRightXian[0].style = 'left:' + ((clientWidthOne * index + num) + 10) + 'px;' + 'display:block'
}
})
this.timeData = timeData
this.timeData = [...this.timeData]
this.loadingMain = false
}, 500)
},
TaskPlanListClick() {
let newUrl = this.$router.resolve({
path: '/TaskPlanList'
})
window.open(newUrl.href, '_blank')
},
searchQuery() {
this.getTimeline()
this.getList()
},
searchReset() {
this.queryParam = {}
this.getTimeline()
this.getList()
},
getList() {
this.loading = true
getAction(this.url.list, this.queryParam).then((res) => {
if (res.success) {
this.loading = false
this.dataSource = res.result || []
} else {
this.loading = false
this.dataSource = []
}
})
},
projectNameClick() {
let newUrl = this.$router.resolve({
path: '/projectStatusAndProgress'
})
window.open(newUrl.href, '_blank')
}
}
}
</script>
<style>
.box-top-text-right .ant-calendar-picker-input {
height: 38px;
width: 300px;
}
</style>
<style scoped lang="less">
@import '~@assets/less/common.less';
.box-title-text {
line-height: 1.4;
display: flex;
align-items: center;
margin-bottom: 10px;
}
.title-text {
width: 70px;
color: #000F16;
display: inline-block;
font-weight: 500;
font-size: 14px;
margin-right: 16px;
margin-top: 3px;
text-align: right;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.box-input {
display: inline-block;
width: 70%;
height: 38px;
margin-top: 2px;
}
.box-top-text {
font-size: 16px;
font-weight: 500;
color: #000F16;
margin-bottom: 20px;
display: inline-block;
}
.box-top-content {
width: 100%;
height: 500px;
margin-bottom: 20px;
padding: 20px 58px 20px 10px;
box-sizing: border-box;
overflow: auto;
}
.box-button {
height: 38px;
}
#main {
width: 100%;
height: 100%;
}
.axis-tip {
display: none;
position: absolute;
padding: 5px 5px;
font-size: 12px;
line-height: 18px;
color: #575757;
background: #ffffff;
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2);
border-radius: 4px;
}
.box-top-text-right {
display: inline-block;
float: right;
height: 38px;
width: 300px;
margin-top: -4px;
}
.fullScreenView {
margin-left: 16px;
color: #21c9cc;
cursor: pointer;
}
.box-top-content-left {
width: 160px;
float: left;
padding-top: 100px;
margin-right: 20px;
}
.box-top-content-left-text {
color: #191E29;
font-weight: bold;
font-size: 14px;
height: 104px;
letter-spacing: 0px;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.box-top-content-right {
width: calc(100% - 180px);
float: left;
}
.box-top-content-right-top {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.box-top-content-right-top-text {
border-left: 1px #EAEAEC solid;
border-top: 1px #EAEAEC solid;
border-bottom: 1px #EAEAEC solid;
flex: 1;
height: 36px;
padding-left: 10px;
color: #54565A;
font-weight: bold;
font-size: 14px;
line-height: 36px;
letter-spacing: 0px;
text-align: center;
}
.box-top-content-right-top-text:last-child {
border-right: 1px #EAEAEC solid;
}
.box-top-content-right-bottom {
position: relative;
padding-top: 60px;
}
.process-content {
position: relative;
height: 104px;
.process-content-content {
background: #fff;
z-index: 98;
/*padding: 0 6px;*/
position: absolute;
left: 40px;
text-align: center;
width: 24px;
height: 24px;
border-radius: 50%;
margin-top: 5px;
.process-content-left {
width: 24px;
height: 24px;
/*margin-top: 5px;*/
}
.process-content-right-top {
font-size: 14px;
color: #040B29;
max-width: 155px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
position: absolute;
top: -8px;
left: 50%;
transform: translate(-50%, -50%);
}
.process-content-right-button {
width: 70px;
font-size: 12px;
font-weight: 400;
color: #6F7385;
position: absolute;
left: 50%;
top: 34px;
transform: translate(-50%, -50%);
}
}
.process-content-right-xian {
height: 2px;
width: 100%;
background: #E6E6E9;
position: absolute;
top: 16px;
}
}
.box-top-content-right-xian {
width: 2px;
height: 100%;
border: 1px #21c9cc dashed;
position: absolute;
top: -36px;
z-index: 999;
}
.box-top-content-right-text {
position: absolute;
top: -60px;
color: #21c9cc;
font-weight: bold;
font-size: 14px;
width: 100px;
}
</style>