xiongchengqiang 47bfdd9264 优化
2020-12-15 17:14:22 +08:00

789 lines
25 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="drawer commonFont">
<el-drawer title="任务详情"
:visible.sync="drawer"
direction="btt"
:before-close="handleClose">
<div class="drawer-content">
<div class="drawer-content-left">
<div class="drawer-content-left-jiaoyi">
<div class="title">
<span>名称: {{(taskInfo.target && taskInfo.target.length>10)?(taskInfo.target.substring(0,8)+'...'):taskInfo.target}}</span>
</div>
<div class="process">
<span>
<span>整体进度</span>
</span>
<el-progress :percentage="handleGetProgress(taskInfo.resultTasks)"></el-progress>
</div>
</div>
<div class="drawer-content-left-title">
<div> 关键结果{{handleFilter(taskInfo.resultTasks).length}}</div>
<div>
<el-button icon="el-icon-plus"
@click="handleAddTask"
type="text">添加</el-button>
</div>
</div>
<div style="overflow:hidden;box-sizing: border-box;" :style="{height:(!dialogFormVisible?0:274 )+ 'px'}" :class="{boderAndRadius:dialogFormVisible}" class=" drawer-content-left-content">
<div style="padding:20px;">
<el-form :model="form"
ref="form"
label-width="80px"
:rules="formRules">
<el-form-item prop="name"
label='任务名称'>
<el-input clearable
type="textarea"
:row='2'
size="small"
placeholder="请输入任务名称"
v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="任务进度"
prop="weight">
<el-input size="small"
style="width:200px;"
@blur="$handleBlur('form.processRate')"
@input.native="$handleInputInt('form.processRate')"
v-model="form.processRate">
<template slot="append">%</template>
</el-input>
<!-- <br />
<el-slider
v-model="form.processRate"
:step="10">
</el-slider> -->
</el-form-item>
</el-form>
<div slot="footer"
class="dialog-footer" style="text-align:right;">
<el-button size="small"
@click="dialogFormVisible = false">取 消</el-button>
<el-button size="small"
type="primary"
@click="handleEditTask(3)">确 定</el-button>
</div>
</div>
</div>
<div v-for="(i,index) in handleFilter(taskInfo.resultTasks)"
:key="i.id"
class="boderAndRadius drawer-content-left-content">
<div :style="{border:!(!i.showTask)?'none':''}"
class="drawer-content-left-content-top">
<div class="drawer-content-left-content-top-process">
<div>
<el-progress type="circle"
:width='50'
:stroke-width='4'
:percentage="Math.round((i.processRate * 100)*1000)/1000 "></el-progress>
</div>
<div style="margin:0 30px 0 10px;">
<span v-if="!i.editProcess">KR{{index+1}} : {{i.name}}</span>
<el-input v-if="i.editProcess"
size="small"
placeholder="请输入内容"
v-model="form.name"
clearable>
</el-input>
</div>
</div>
<div class="right">
<div v-if="i.editProcess">
<el-button size="mini"
@click="handleEditTask(1)"
type="primary">确认</el-button>
<el-button size="mini"
@click="handleEditProcess(i,false)"
type="danger">取消</el-button>
</div>
<div v-if="!i.editProcess"
class="right-item">
<div>
<el-tooltip class="item"
effect="dark"
content="更新进度"
placement="top-start">
<i @click="handleUpdateProcess(i,true)"
class="el-icon-refresh-left"></i>
</el-tooltip>
</div>
<div class="right-item-center">
<el-tooltip class="item"
effect="dark"
content="评论"
placement="top-start">
<i @click="handleAddPinglun(i)" class="el-icon-chat-square"></i>
</el-tooltip>
</div>
<div>
<el-dropdown size="mini">
<el-tooltip class="item"
effect="dark"
content="更多"
placement="top-start">
<i class="el-icon-more"></i>
</el-tooltip>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="handleEditProcess(i,true)">编辑</el-dropdown-item>
<el-dropdown-item @click.native="handleDetele(i.id)">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
</div>
<div v-if="!i.updateProcess && i.typeDesc"
class="drawer-content-left-content-center"
:class="{bg:i.showTask}">
<div class="content commonFont" style="padding:0 20px;">
<div class="drawer-content-left-content-center-left">
<img v-if="!i.showTask"
:onerror="defaultImg"
:src='i.avatar || defaultImg'
alt="">
<span v-if="!i.showTask">{{i.staffName}}:</span>
<span class="label"
style="word-wrap:break-word;"
v-if="!i.showTask">{{(i.typeDesc && i.typeDesc.length>10)?(i.typeDesc.substring(0,8)+'...'):i.typeDesc}}</span>
</div>
<div style="user-select:none;">
<i :class="{rate:!i.showTask}"
@click="handleShowAll(i)"
style=" cursor: pointer;color:#3ba1ff;transition: all 0.2s;"
class="el-icon-arrow-down"></i>
</div>
</div>
<div style="overflow:auto;max-height:300px;padding:0 20px;">
<pinglun v-if="i.showTask"
background='#fff'
:pinglunList='i.taskList' />
</div>
</div>
<div v-if="i.updateProcess"
class="drawer-content-left-content-bottom">
<el-form :model="form"
:rules="formRules"
label-width="80px">
<el-form-item label="当前进度:"
prop="weight">
<!-- <el-slider
v-model="form.processRate"
:step="10">
</el-slider> -->
<el-input size="small"
style="width:200px;"
@blur="$handleBlur('form.processRate')"
@input.native="$handleInputInt('form.processRate')"
v-model="form.processRate">
<template slot="append">%</template>
</el-input>
</el-form-item>
<el-form-item label="进度说明:"
prop="remark">
<el-input type="textarea"
size="small"
placeholder="请输入进度说明"
v-model="form.remark">
</el-input>
</el-form-item>
<el-form-item>
<div style="text-align: right;">
<el-button type="primary"
size="mini"
@click="handleEditTask(2)">确定</el-button>
<el-button @click="handleUpdateProcess(i,false)"
size="mini">取消</el-button>
</div>
</el-form-item>
</el-form>
</div>
</div>
</div>
<div class="drawer-content-right">
<div style="padding: 0 20px;">
<el-tabs v-model="activeName"
@tab-click="handleClick">
<el-tab-pane label="评论"
name="1">
</el-tab-pane>
<el-tab-pane label="记录"
name="2"></el-tab-pane>
</el-tabs>
</div>
<div v-if="activeName==='1'"
class="drawer-content-right-item pinglun">
<div class="pinglun-top" ref="pingList">
<pinglun :pinglunList='nowPingLunList' />
</div>
<div class="pinglun-bottom">
<div v-if="staffList.list.length>0" class="pinglun-bottom-content top">
<div v-if="staffList.list.length>0">
<el-tag
size="mini"
style="margin:2px 4px;"
v-for="tag in staffList.list"
:key="tag.staffId"
@close="handleCloseItem(tag)"
closable>
{{tag.name}}
</el-tag>
</div>
<i @click="staffList.list=[]" style="font-size:20px;" class="el-icon-circle-close"> </i>
</div>
<div v-if="pinglunForm.id" class="pinglun-bottom-content top">
<div v-if="pinglunForm.id">评论KR「{{pinglunForm.name}}」</div>
<i @click="handleCloseAll" style="font-size:20px;" class="el-icon-circle-close"> </i>
</div>
<div class="pinglun-bottom-content" style=" flex-direction: column;">
<el-input type="textarea"
clearable
ref="input"
placeholder="请输入评论内容。。。"
v-model="form.content"></el-input>
<div class="button">
<div class="left">
<span class="at" @click="handleAtSomeOne">@</span>
</div>
<el-button size="small"
@click="handleSendPingLun"
type="primary">发送</el-button>
</div>
</div>
</div>
</div>
<div v-if="activeName==='2'"
class="drawer-content-right-item jilu">
<pinglun :isJilu='true' :pinglunList='pinglunList' />
</div>
</div>
</div>
</el-drawer>
<!-- <el-dialog :title="title"
:visible.sync="dialogFormVisible">
<el-form :model="form"
:rules="formRules">
<el-form-item prop="name"
label='任务名称'>
<el-input clearable
size="small"
placeholder="请输入任务名称"
v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="任务进度"
prop="weight">
<el-input size="small"
@blur="$handleBlur('form.processRate')"
@input.native="$handleInputInt('form.processRate')"
v-model="form.processRate">
<template slot="append">%</template>
</el-input>
</el-form-item>
</el-form>
<div slot="footer"
class="dialog-footer">
<el-button size="small"
@click="dialogFormVisible = false"> </el-button>
<el-button size="small"
type="primary"
@click="handleEditTask(3)"> </el-button>
</div>
</el-dialog> -->
<getPersonnel @cb='handleCheckStaffIds' v-if="isShow" :value.sync='form.ids' :isShow.sync='isShow' :showDataList.sync='staffList'/>
</div>
</template>
<script>
import InfoHeader from '@/components/InfoHeader'
import pinglun from './pinglun.vue'
import getPersonnel from '@/components/getPersonnel'
import { apiDeleteTask, apiEditTask, apiChangeTaskList, apiTaskCommentList, apiAddTaskComment } from '@/api/assessment'
export default {
props: {
drawer: {
type: Boolean,
default: false
},
taskObj: {
type: Object,
default: () => {
return {
target: ''
}
}
}
},
data () {
return {
isShow: false,
staffList: {
list: []
},
taskInfo: {},
activeName: '1',
formRules: {
name: [{
required: true,
message: '请输入任务名称',
trigger: 'blur'
}
]
},
form: {
name: '',
processRate: 0
},
pinglunForm: {},
pinglunList: [],
nowPingLunList: [],
dialogFormVisible: false,
title: '添加任务',
defaultImg: 'this.src="' + require('@/assets/img/default.jpg') + '"'
}
},
components: { pinglun, InfoHeader, getPersonnel },
computed: {},
beforeMount () { },
mounted () {
this.taskInfo = Object.assign({}, this.taskObj)
this.handleGetChangeTaskList()
this.handleGetPingLunList()
console.log(this.taskInfo)
},
methods: {
handleAtSomeOne () {
this.isShow = true
},
handleCloseAll () {
this.pinglunForm = {}
},
handleCheckStaffIds (list) {
console.log('🚀 ~ file: process.vue ~ line 321 ~ handleCheckStaffIds ~ list', list)
this.staffList = list
this.isShow = false
this.$nextTick(() => {
const pingList = this.$refs.pingList
pingList.scrollTop = pingList.scrollHeight
})
},
handleCloseItem (item) {
this.staffList.list = this.staffList.list.filter(i => i !== item)
},
async handleGetPingLunList () {
const params = {
currPage: 1,
detailId: this.taskInfo.detailId,
pageSize: 2300
}
let res = await apiTaskCommentList(params)
if (res.code !== 200) {
this.$message.error(res.msg)
return
}
this.nowPingLunList = res.data.list.reverse()
this.$nextTick(() => {
const pingList = this.$refs.pingList
pingList.scrollTop = pingList.scrollHeight
})
},
// 发送评论
async handleSendPingLun (event) {
const str = this.staffList.list.map(i => i.staffId).join(',')
let params = {}
// debugger
if (!this.form.content.replace(/(^\s*)|(\s*$)/g, '')) return
this.form.content = this.form.content.replace(/(^\s*)|(\s*$)/g, '')
params.content = this.form.content
if (str) params.atStaffIds = str
params[this.pinglunForm.id ? 'taskId' : 'detailId'] = this.pinglunForm.id ? this.pinglunForm.id : this.taskInfo.detailId
let res = await apiAddTaskComment(params)
if (res.code !== 200) {
this.$message.error(res.msg)
}
this.taskInfo = await this.$parent.handleGetTaskDetail(this.taskInfo.detailId)
this.handleGetPingLunList()
this.form.content = ''
},
// 对任务添加评论
handleAddPinglun (item) {
this.staffList.list = []
this.taskInfo.resultTasks.map(i => {
i.updateProcess = false
i.editProcess = false
})
this.dialogFormVisible = false
this.pinglunForm = Object.assign({}, item)
const pingList = this.$refs.pingList
pingList.scrollTop = pingList.scrollHeight
this.$refs.input.focus()
},
// 获取当前任务的评论
async handleShowAll (i) {
if (i.showTask) {
i.showTask = false
this.$forceUpdate()
return
}
const params = {
currPage: 1,
taskId: i.id,
pageSize: 2300
}
i.taskList = []
let res = await apiChangeTaskList(params)
if (res.code !== 200) {
this.$message.error(res.msg)
return
}
this.taskInfo.resultTasks.map(j => {
j.updateProcess = false
j.editProcess = false
j.showTask = false
})
i.showTask = true
i.taskList = res.data.list
this.$forceUpdate()
},
async handleGetChangeTaskList () {
const params = {
currPage: 1,
detailId: this.taskInfo.detailId,
pageSize: 2300,
useType: 0
}
this.pinglunList = []
let res = await apiChangeTaskList(params)
if (res.code !== 200) {
this.$message.error(res.msg)
return
}
this.pinglunList = res.data.list
},
async handleEditTask (type) {
this.$refs.form.validate(async v => {
if (v) {
const params = Object.assign({}, this.form)
if (type === 2 || type === 3) params.processRate = this.form.processRate / 100
if (type === 3) params.detailId = this.taskInfo.detailId
const res = await apiEditTask(params)
if (res.code !== 200) {
this.$message.error(res.msg)
return
}
// this.form = {}
this.taskInfo = await this.$parent.handleGetTaskDetail(this.taskInfo.detailId)
this.dialogFormVisible = false
this.handleGetChangeTaskList()
this.$parent.handleGetTable(true)
this.$message({
message: res.msg,
type: 'success'
})
}
})
},
handleGetProgress (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
return Number((_process * 100).toFixed(2))
},
async handleDetele (id) {
this.$confirm('此操作不可撤回, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
let res = await apiDeleteTask({ taskId: id })
if (res.code !== 200) {
this.$message.error(res.msg)
return
}
this.taskInfo = await this.$parent.handleGetTaskDetail(this.taskInfo.detailId)
this.$parent.handleGetTable(true)
this.$message({
message: res.msg,
type: 'success'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
// 更新进度
handleUpdateProcess (i, type = false) {
this.taskInfo.resultTasks.map(i => {
i.updateProcess = false
i.editProcess = false
})
this.dialogFormVisible = false
if (type) {
this.form = Object.assign({}, i)
this.form.taskId = this.form.id
this.form.processRate = Math.round(Number(this.form.processRate) * 100)
} else {
this.form = {}
}
i.updateProcess = type
console.log(this.form)
this.$forceUpdate()
},
// 编辑/取消编辑进度
handleEditProcess (i, type = false) {
this.taskInfo.resultTasks.map(i => {
i.updateProcess = false
i.editProcess = false
})
this.dialogFormVisible = false
i.editProcess = type
this.form = Object.assign({}, i)
this.form.taskId = this.form.id
this.$forceUpdate()
},
handleFilter (item) {
return item ? item.filter(i => !i.isDelete) : []
},
handleClick (tab, event) {
console.log(tab, event)
},
handleAddTask () {
this.taskInfo.resultTasks.map(i => {
i.updateProcess = false
i.editProcess = false
i.showTask = false
})
this.$refs.form.resetFields()
this.dialogFormVisible = true
},
handleClose () {
this.$emit('update:drawer', false)
}
},
watch: {}
}
</script>
<style lang="less">
.drawer {
.el-drawer {
border-radius: 12px 12px 0 0 !important;
height: 80% !important;
overflow: auto;
}
.el-drawer__header {
margin: 0;
}
.el-drawer__body {
overflow: auto;
}
.el-progress-bar {
width: 94% !important;
}
}
</style>
<style lang='less'>
.drawer {
&-content {
display: flex;
height: 100%;
box-sizing: border-box;
background: #fafafa;
> div {
width: 50%;
box-sizing: border-box;
overflow: auto;
}
&-left {
padding: 20px 20px 0;
.img {
width: 20px;
height: 20px;
}
border-right: 1px solid #e7e7e7;
&-jiaoyi {
.title {
font-size: 16px;
margin-bottom: 10px;
}
.process {
padding: 0 0 0 20px;
display: flex;
align-items: center;
// width: %;
.el-progress {
width: 400px;
}
}
}
&-title {
margin: 10px 0;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 16px;
}
&-content {
margin-bottom: 20px;
max-height:2000px;
transition:all 0.4s;
box-shadow: 0 1px 6px 0 rgba(0,0,0,.12), 0 1px 6px 0 rgba(0,0,0,.12);
&-top {
display: flex;
// align-content: center;
justify-content: space-between;
border-bottom: 1px solid @borderColor;
margin: 20px 20px 0;
padding-bottom: 12px;
&-process {
display: flex;
// align-content: center;
> div {
// .center();
}
}
.right {
// .center();
font-size: 16px;
&-item {
cursor: pointer;
border: 1px solid @borderColor;
> div {
padding: 2px;
}
display: flex;
&-center {
border-left: 1px solid @borderColor;
border-right: 1px solid @borderColor;
}
}
}
}
.bg {
background: #fafafa;
}
.rate {
transform: rotate(-180deg);
}
&-center {
padding: 6px 0 6px;
.label {
width: 300px;
}
.content {
flex:1;
display: flex;
align-items: center;
justify-content: space-between;
// > div {
// flex-shrink: 0;
// }
}
&-left {
flex: 1 ;
display: flex;
align-items: center;
img {
width: 28px;
height: 28px;
border-radius: 50%;
overflow: hidden;
margin-right: 10px;
}
}
}
&-bottom {
padding: 10px 20px 6px;
border-top: 1px solid @borderColor;
}
}
}
&-right {
display: flex;
flex-direction: column;
&-item {
flex: 1 0 auto;
overflow: auto;
}
.pinglun {
display: flex;
flex: 1;
// overflow: auto;
flex-direction: column;
&-top {
flex: 1;
display: flex;
flex-direction: column;
overflow: auto;
padding: 0 20px;
}
&-bottom {
width: 100%;
border-top: 1px solid @borderColor;
.top{
border-bottom: 1px solid @borderColor;
}
&-content{
padding: 6px 8px;
display: flex;
background: #fff;
align-items: center;
justify-content: space-between;
i{
cursor: pointer;
}
.button{
padding: 6px 0;
width: 100%;
display: flex;
.left{
flex: 1 0 auto;
display: flex;
align-items: center;
.at{
padding: 4px;
cursor: pointer;
}
}
}
}
textarea {
resize: none;
height: 46px;
font-size: 12px;
background: #f6f6f6;
border:none;
}
.el-button--small {
height: 30px;
margin: 0 0 0 6px;
}
}
}
.jilu {
padding: 0 20px;
flex: 1;
overflow: auto;
}
}
}
}
</style>