xiongchengqiang ed6ba5d444 优化
2020-12-18 11:32:04 +08:00

737 lines
24 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="goals">
<SmallNav />
<div class="goals-content boderAndRadius">
<div class="goals-content-name">
<InfoHeader :obj="{
src:obj.avatar,
name:obj.staffName,
departmentName:obj.departmentName
}" />
</div>
<div class="goals-content-tabbar">
<el-tabs :value="activeId">
<el-tab-pane v-for="(i,index) in obj.recortModelDtos"
:key="i.id"
:label="i.name + ' ( '+( i.maxCount===null?(handleNumber(i)):(handleNumber(i)+'/'+i.maxCount))+' ) '"
:name="String(i.id)">
<div class="goals-content-tabbar-table">
<div class="goals-content-tabbar-table-header commonFont">
<span style="width:200px;">指标名称</span>
<span class="kaohe"
style="flex:1 0 auto;">考核标准</span>
<span style="width:100px;">权重</span>
<span style="width:240px;">操作</span>
</div>
<div style="justify-content:center;"
v-if="handleFilter(i.detailDtos).length===0"
class="zanwu goals-content-tabbar-table-content commonFont items">
暂无指标
</div>
<draggable v-model="i.tagetLibItems"
:options='options1'>
<div class="goals-content-tabbar-table-content commonFont items"
v-for="(j,indexJ) in handleFilter(i.detailDtos)"
:key="indexJ">
<div class="goals-content-tabbar-table-content-top">
<div style="width:200px;"
class="my-handle pre"><img style="width:20px;height:20px;"
src="@/assets/img/yidong.png"
alt="">
<pre>{{j.target}}</pre>
</div>
<div style="flex:1 0 auto;"
class="kaohe">
<pre>{{j.keyResult}}</pre>
</div>
<div style="width:100px;">{{ Math.round((j.checkWeight * 100)*1000)/1000}}%</div>
<div style="width:240px;">
<el-button @click="hanidleAddTask(j,0)"
type="primary" plain
size="mini">
添加任务
</el-button>
<el-button @click="hanidleEdit(j,indexJ,index)"
type="text"
size="small">
编辑
</el-button>
<el-button style="color:#F56C6C;" @click="handleDelateWeidu(j,indexJ,index)"
type="text"
size="small">
删除
</el-button>
</div>
</div>
<div v-for="(kitem,indexK) in handleFilter(j.taskDtos)"
:key="indexK"
class="goals-content-tabbar-table-content-bottom">
<div>任务{{indexK+1}}{{kitem.name.length>16?kitem.name.substring(0,12):kitem.name}}(当前进度:{{Math.round((kitem.processRate * 100)*1000)/1000|| 0}}%)</div>
<div style="width:240px;padding: 0 0 0 20px;">
<el-button style="visibility:hidden;"
type="primary" plain
size="mini">
添加任务
</el-button>
<el-button type="text"
@click="hanidleAddTask(j,1,kitem)"
size="small">
编辑
</el-button>
<el-button type="text"
style="color:#F56C6C;"
@click="handleDeleteTask(j,kitem)"
size="small">
删除
</el-button>
</div>
</div>
</div>
</draggable>
<div style=" padding: 10px;font-size:16px;"
class="commonFont">
<div>
业务指标权重:{{handleGetWeight(i)}}% <span v-if="i.weight !== null">/{{Math.round((i.weight * 100)*1000)/1000}}%</span>
</div>
<div>
所有指标总权重: <span style="color:#EE6723;">{{ handleGetWeight1()}}%</span><span>/100%</span>
</div>
</div>
<div style=" padding: 10px;">
<!-- <el-button size="mini" plain>选择指标项</el-button> -->
<el-button @click="hanidleEdit(i,-1,index)"
type="primary"
icon="el-icon-plus"
size="small"
plain>增加指标项</el-button>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
<popup-right v-if="showTask"
@cancel='handleCancelTask'
@submit="handleSubmitTask"
:title="taskTitle">
<div slot="content"
class="weiduManage">
<el-form label-position="left"
ref="formTask"
:model="formTask"
:rules="ruleIndicators"
label-width="180px">
<el-form-item prop="name"
label='任务名称'>
<el-input clearable
type="textarea"
:rows="2"
size="small"
placeholder="请输入任务名称"
v-model="formTask.name"></el-input>
</el-form-item>
<el-form-item label="任务进度"
prop="weight">
<el-input size="small"
@blur="$handleBlur('formTask.processRate')"
@input.native="$handleInputInt('formTask.processRate')"
v-model="formTask.processRate">
<template slot="append">%</template>
</el-input>
</el-form-item>
</el-form>
</div>
<el-button slot="footer"
@click="handleSubmitTask(1)"
size="small"
type="primary"
>确定并继续添加</el-button>
</popup-right>
<popup-right v-if="showIndicators"
@cancel='handleCancelZhibiao'
@submit="handleSubmitZhibiao"
:title="zhibiaoTitle">
<div slot="content"
class="weiduManage">
<el-form label-position="left"
ref="formIndicators"
:model="formIndicators"
:rules="ruleIndicators"
label-width="180px">
<el-form-item label="指标类型">
<el-select v-model="formIndicators.type"
disabled
placeholder="请选择维度类型">
<el-option v-for="i in dimensionsList"
:key="i.id"
:label="i.name"
:value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="target"
label='指标名称'>
<el-input clearable
:rows="4"
type="textarea"
size="small"
v-model="formIndicators.target"></el-input>
</el-form-item>
<el-form-item label="考核标准"
prop="keyResult">
<el-input size="small"
clearable
:rows="22"
type="textarea"
v-model="formIndicators.keyResult"></el-input>
</el-form-item>
<el-form-item label="权重"
prop="weight">
<el-input size="small"
@blur="$handleBlur('formIndicators.checkWeight')"
@input.native="$handleInputInt('formIndicators.checkWeight')"
v-model="formIndicators.checkWeight">
<template slot="append">%</template>
</el-input>
</el-form-item>
</el-form>
</div>
</popup-right>
<div class="goals-bottom">
<div class="goals-bottom-content">
<el-button size='small'
v-if="this.$route.query.saveIn===1"
@click="handleSaveDetail(obj,1)"
plain>保存</el-button>
<el-button size='small'
v-if="this.$route.query.saveAndAdd===1"
@click="handleSaveDetail(obj,2)"
plain>暂存</el-button>
<el-button size='small'
type="primary"
v-if="this.$route.query.saveAndAdd===1"
@click="handleGetNext">提交</el-button>
</div>
</div>
</div>
</template>
<script>
import SmallNav from '@/components/kpi-layout/SmallNav'
import InfoHeader from '@/components/InfoHeader'
import PopupRight from '@/components/PopupRight'
import draggable from 'vuedraggable'
import { getDimensions } from '@/api/data'
import { apiResultGetDetail, apiSaveDetail, apiSaveapproval } from '@/api/assessment'
import delete$ from 'dingtalk-jsapi/api/biz/cspace/delete'
export default {
data () {
return {
showTask: false,
taskTitle: '添加任务',
formItem: {},
editItem: {},
formTask: {
name: '',
processRate: '0'
},
zhibiaoTitle: '添加指标',
showIndicators: false,
dimensionsList: [],
formIndicators: {},
ruleIndicators: {
name: [{
required: true,
message: '请输入任务名称',
trigger: 'blur'
}
],
target: [{
required: true,
message: '请输入指标名称',
trigger: 'blur'
}
],
keyResult: [{
required: true,
message: '请输入考核标准',
trigger: 'blur'
}
],
checkWeight: [{
required: true,
message: '请输入权重大小',
trigger: 'blur'
}
]
},
activeId: null,
obj: {
recortModelDto: []
},
options1: {
group: 'names',
draggable: '.items',
handle: '.my-handle',
scroll: true,
sort: true, // 内部排序列表
delay: 0, // 以毫秒为单位定义排序何时开始。
touchStartThreshold: 0, // px,在取消延迟拖动事件之前,点应该移动多少像素?
disabled: false, // 如果设置为真则禁用sortable。
store: null, // @see Store
animation: 150 // ms, 动画速度运动项目排序时,' 0 ' -没有动画。
}
}
},
components: {
SmallNav,
InfoHeader,
draggable,
PopupRight
},
computed: {},
beforeMount () { },
mounted () {
console.log('auth', this.auth)
this.handleGetDimensions()
this.handleGetTbale()
},
methods: {
// 删除任务
handleDeleteTask (parent, item) {
this.$confirm('此操作不可撤回, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (item.id) {
parent.taskDtos.map(i => {
if (i === item) {
i.isDelete = 1
}
})
} else {
parent.taskDtos = parent.taskDtos.filter(i => i !== item)
}
this.$forceUpdate()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
// 取消添加任务
handleCancelTask () {
this.showTask = false
},
// 提交添加任务
handleSubmitTask (type) {
this.$refs.formTask.validate((v) => {
if (v) {
this.formTask.processRate = Number(this.formTask.processRate) / 100
if (this.formTask.isNew) {
delete this.formTask.isNew
this.formItem.taskDtos.push(this.formTask)
} else {
this.editItem.name = this.formTask.name
this.editItem.processRate = this.formTask.processRate || '0'
}
this.$forceUpdate()
if (!type) this.handleCancelTask()
this.formTask = {
name: '',
processRate: '0',
isNew: true
}
console.log(this.formTask)
}
})
},
handleGetProgress (process, arr = []) {
const result = this.handleFilter(arr).reduce((result, item) => {
result += Number(item.processRate)
return result
}, 0)
const _process = Number(result.toFixed(2)) / this.handleFilter(arr).length || 0
process.processRate = _process || 0
return Number((_process * 100).toFixed(2))
},
hanidleAddTask (j, type, item) {
!j.taskDtos && (j.taskDtos = [])
this.formTask = {}
if (type === 1) {
this.formTask = Object.assign({}, item, { processRate: item.processRate * 100 })
this.editItem = item
this.taskTitle = '编辑任务'
} else {
this.taskTitle = '添加任务'
this.formTask = {
name: '',
processRate: '0',
isNew: true
}
}
// this.formTask = type === 1 ? Object.assign({}, item, { item }) : {
// name: '',
// processRate: '0',
// isNew: true
// }
this.formItem = j
this.showTask = true
console.log(this.formTask)
},
handleNumber (item) {
return item.detailDtos ? item.detailDtos.filter(i => !i.isDelete).length : 0
},
handleFilter (item) {
return item ? item.filter(i => !i.isDelete) : []
},
async handleGetNext () {
const arr = this.handleFilter(this.obj.recortModelDtos)
if (arr.some(i => i.weight === null)) {
let weight = 0
let maxWeight = 0
const nullArray = arr.map(i => {
this.handleFilter(i.detailDtos).map(j => {
if (i.weight === null) maxWeight += j.checkWeight
weight += j.checkWeight
})
})
if (weight !== 1) {
const noWeightArr = arr.filter(i => i.weight === null)
let str = noWeightArr.map(i => i.name).join(',')
this.$message.error(str + '维度内的权重和必须为100%')
return
}
} else {
for (let i in arr) {
let num = 0
this.handleFilter(arr[i].detailDtos).map(l => {
num += l.checkWeight
})
if (num.toFixed(2) !== arr[i].weight.toFixed(2)) {
return this.$message.error(arr[i].name + '维度内的权重和必须为' + Math.round((arr[i].weight * 100) * 1000) / 1000)
}
}
}
this.obj.recortModelDtos.map(i => {
i.detailDtos.map(j => {
const result = this.handleFilter(j.taskDtos).reduce((result, item) => {
result += Number(item.processRate)
return result
}, 0)
const _process = Number(result.toFixed(2)) / this.handleFilter(j.taskDtos).length || 0
j.processRate = _process.toFixed(2) || 0
})
})
let res1 = await apiSaveDetail(this.obj)
if (res1.code !== 200) {
this.$message.error(res1.msg)
return
}
const obj = { status: 1, menuName: '制定了' }
const params = Object.assign({}, { resultRecordId: this.$route.query.id || '' }, obj)
params.commentId = res1.commentId || ''
let res = await apiSaveapproval(params)
if (res.code !== 200) {
this.$message.error(res.msg || '出错了 ')
return
}
this.$message({
message: res.msg,
type: 'success'
})
history.go(-1)
},
handleGetWeight1 () {
let num = 0
this.obj.recortModelDtos.map(i => {
i.detailDtos.filter(i => !i.isDelete).map(i => {
num += i.checkWeight
})
})
return Math.round((num * 100) * 1000) / 1000
},
handleGetWeight (arr) {
const weight = arr.detailDtos.filter(i => !i.isDelete).reduce((num, i) => {
num += i.isDelete !== 1 ? i.checkWeight : 0
return num
}, 0)
arr.isTrue = (Math.round((weight * 100) * 1000) / 1000) === (Math.round((arr.weight * 100) * 1000) / 1000)
return Math.round((weight * 100) * 1000) / 1000
},
async handleSaveDetail (params = this.obj, type) {
if (type === 1) {
const arr = this.handleFilter(this.obj.recortModelDtos)
if (arr.some(i => i.weight === null)) {
let weight = 0
let maxWeight = 0
const nullArray = arr.map(i => {
this.handleFilter(i.detailDtos).map(j => {
if (i.weight === null) maxWeight += j.checkWeight
weight += j.checkWeight
})
})
if (weight !== 1) {
const noWeightArr = arr.filter(i => i.weight === null)
let str = noWeightArr.map(i => i.name).join(',')
this.$message.error(str + '维度内的权重和必须为100%')
return
}
} else {
for (let i in arr) {
let num = 0
this.handleFilter(arr[i].detailDtos).map(l => {
num += l.checkWeight
})
if (num.toFixed(2) !== arr[i].weight.toFixed(2)) {
return this.$message.error(arr[i].name + '维度内的权重和必须为' + Math.round((arr[i].weight * 100) * 1000) / 1000)
}
}
}
}
params.recortModelDtos.map(i => {
i.detailDtos.map(j => {
const result = this.handleFilter(j.taskDtos).reduce((result, item) => {
result += Number(item.processRate)
return result
}, 0)
const _process = Number(result.toFixed(2)) / this.handleFilter(j.taskDtos).length || 0
j.processRate = _process.toFixed(2) || 0
})
})
let res = await apiSaveDetail(Object.assign({}, params, { save: 1 }))
if (res.code !== 200) {
this.$message.error(res.msg)
}
this.$message({
message: res.msg,
type: 'success'
})
if (type === 1) {
history.go(-1)
} else {
this.handleGetTbale()
}
},
// 获取维度类型
async handleGetDimensions () {
try {
let res = await getDimensions()
if (res.code !== 200) {
this.dimensionsList = []
return
}
res = res.data
this.dimensionsList = res
} catch (error) {
this.$message.error(error.msg)
}
},
handleCancelZhibiao () {
this.showIndicators = false
},
handleSubmitZhibiao () {
console.log(this.formIndicators)
const arr = this.obj.recortModelDtos[this.formIndicators.dazhibiaoIndex].detailDtos
this.$refs.formIndicators.validate((v) => {
if (v) {
if (this.formIndicators.index === -1) {
arr.push(Object.assign({}, this.formIndicators, { checkWeight: this.formIndicators.checkWeight / 100 }))
} else {
let _index = 0
this.obj.recortModelDtos[this.formIndicators.dazhibiaoIndex].detailDtos = arr.map(i => {
if (i.isDelete !== 1) {
if (_index === this.formIndicators.index) {
i = Object.assign({}, this.formIndicators, { checkWeight: this.formIndicators.checkWeight / 100 })
}
_index++
}
return i
})
}
this.$forceUpdate()
this.showIndicators = false
}
})
console.log(' this.obj', this.obj)
},
// 编辑
hanidleEdit (item, index, type) {
if (item.maxCount !== null) {
const len = this.handleNumber(item)
if (item.maxCount <= len) {
this.$message.info('指标数量不能大于' + item.maxCount)
return
}
}
this.zhibiaoTitle = index === -1 ? '添加指标' : '编辑指标'
if (index === -1) {
this.formIndicators = {
checkWeight: 0
}
} else {
this.formIndicators = Object.assign({}, item)
this.formIndicators.checkWeight = this.formIndicators.checkWeight * 100
}
this.formIndicators.dazhibiaoIndex = type
this.formIndicators.index = index
this.formIndicators.type = item.type
this.showIndicators = true
},
handleDelateWeidu (item, index, type) {
this.$confirm('此操作不可撤回, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (item.id) {
item.isDelete = 1
this.$forceUpdate()
return
}
this.obj.recortModelDtos[type].detailDtos = this.obj.recortModelDtos[type].detailDtos.filter(i => i !== item)
this.$forceUpdate()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
async handleGetTbale (id = this.$route.query.id) {
let res = await apiResultGetDetail({ id })
if (res.code !== 200) return
this.obj = res.data
this.activeId = String(res.data.recortModelDtos[0].id)
}
},
watch: {}
}
</script>
<style lang='less' scoped>
.goals {
span,div{
box-sizing: border-box;
}
.kaohe {
flex: none;
width: 500px;
display: block;
pre {
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-all;
}
}
margin-bottom: 100px;
position: relative;
.my-handle {
cursor: move;
display: flex;
align-items: center;
img {
margin-right: 10px;
}
}
&-bottom {
position: fixed;
height: 60px;
border-top: 1px solid @borderColor;
padding: 0 80px;
width: 100%;
background: #fff;
bottom: 0;
left: 0;
&-content {
padding: 0 80px;
margin: 0 auto;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
&-content {
padding: 28px;
&-name {
display: flex;
align-items: center;
justify-content: space-between;
}
&-title {
margin: 0 0 10px 0;
display: flex;
align-items: center;
&-img {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
&-right {
margin-left: 20px;
display: flex;
flex-direction: column;
}
}
&-tabbar {
&-table {
&-header {
display: flex;
justify-content: space-between;
align-items: center;
height: 60px;
background: rgb(231, 231, 231);
border-bottom: 1px solid @borderColor;
span {
padding: 0 0 0 20px;
}
}
&-content {
// align-items: center;
// height: 60px;
border-bottom: 1px solid @borderColor;
&-top {
border-bottom: 1px solid @borderColor;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 20px 0;
> div {
padding: 0 0 0 20px;
}
}
&-bottom {
font-size: 14px;
display: flex;
color:#999999;
align-items: center;
justify-content: space-between;
margin: 0 0 0 50px;
> div {
flex-shrink: 0;
}
}
}
}
}
}
.zanwu {
.center();
padding: 20px 0;
}
}
</style>