940 lines
24 KiB
Vue
Raw Normal View History

<template>
<view>
<view class="fixedheader">
<headers :showBack="true">
<view class="headerName">
流程详情
</view>
</headers>
</view>
<view :style="{paddingTop: (mobileTopHeight + 50) * 1.5 + 'rpx'}" v-if="instanceData">
<scroll-view class="w-instace" scroll-y show-scrollbar @scroll="scroll"
:style="{height: contentHeight + 'px'}">
<view class="w-instace-header" v-if="instanceData.staterUser">
<Avatar :name="instanceData.staterUser.name" :src="getRes(instanceData.staterUser.avatar)" showY>
</Avatar>
<view>
<view style="display: flex; align-items: center;">
<text style="margin-right: 20rpx;">{{instanceData.processDefName}}</text>
<uni-tag circle="true" :text="instanceData.status"
:type="getProcTag(instanceData.result).type" inverted></uni-tag>
</view>
<view>编号{{instanceData.instanceId}}</view>
</view>
<image v-if="instanceData.statusImg" :src="instanceData.statusImg" mode="aspectFill"></image>
</view>
<view class="w-instace-form">
<view class="process-form" v-for="item in instanceData.formItems" :key="item.id">
<view>
{{ item.title }}
</view>
<view v-if="item.name == 'ImageUpload'">
<image v-for="ele in instanceData.formData[item.id]" :key="item.id"
@click="previewImg(url_config + 'image/' + ele.url)"
style="width: 200rpx; height: 200rpx" :src="url_config + 'image/' + ele.url"
fit="cover"></image>
</view>
<view v-else-if="item.name == 'FileUpload'">
<view class="download" @click="downloadFn(item)"
v-for="item in instanceData.formData[item.id]" :key="item.id">
{{ item.name }}
</view>
</view>
<view v-else>
{{ formDataFn(item) }}
</view>
</view>
<!-- <form-render :jsonConf="instanceData.formItems" v-model="instanceData.formData"></form-render> -->
</view>
<view class="w-instace-process">
<process-progress :progress="instanceData.progress" :status="instanceData.status"
:result="instanceData.result"></process-progress>
</view>
</scroll-view>
<view class="w-instace-action" v-if="instanceData.operationPerm || !instanceData.finishTime">
<view class="w-action">
<view @click="doAction('comment')">
<uni-icons2 type="chat" class="uni-icons_34"></uni-icons2>
<view>评论</view>
</view>
<!-- <view @click="showMore">
<uni-icons2 type="more-filled" class="uni-icons_34"></uni-icons2>
<view>更多</view>
</view> -->
<view class="w-action-main">
<button
v-if="instanceData.operationPerm && instanceData.operationPerm.refuse && instanceData.operationPerm.refuse.show"
@click="doAction('refuse')">
{{instanceData.operationPerm.refuse.alisa}}
</button>
<button type="primary"
v-if="instanceData.operationPerm && instanceData.operationPerm.agree && instanceData.operationPerm.agree.show"
@click="doAction('agree')">
{{instanceData.operationPerm.agree.alisa}}
</button>
</view>
</view>
</view>
<uni-popup ref="actionPopup" type="bottom" background-color="#fff">
<view class="w-more-title">选择您的审批操作</view>
<view class="w-action-mores">
<view
v-if="instanceData.operationPerm && instanceData.operationPerm.transfer && instanceData.operationPerm.transfer.show"
@click="doAction('transfer')">
<uni-icons2 type="staff" class="uni-icons_34"></uni-icons2>
<view>转交</view>
</view>
<view
v-if="instanceData.operationPerm && instanceData.operationPerm.recall && instanceData.operationPerm.recall.show"
@click="doAction('recall')">
<uni-icons2 type="undo" class="uni-icons_34"></uni-icons2>
<view>退回</view>
</view>
<view
v-if="instanceData.operationPerm && instanceData.operationPerm.afterAdd && instanceData.operationPerm.afterAdd.show"
@click="doAction('afterAdd')">
<uni-icons2 type="personadd" class="uni-icons_34"></uni-icons2>
<view>后加签</view>
</view>
<view v-if="enableCancel" @click="doAction('cancel')">
<uni-icons2 type="refreshempty" class="uni-icons_34"></uni-icons2>
<view>撤销</view>
</view>
</view>
<button class="w-more-close" type="default" @click="$refs.actionPopup.close()"> </button>
</uni-popup>
<uni-popup ref="doActionPopup" type="bottom" background-color="#fff">
<view class="w-more-title">{{action.title}}</view>
<view class="w-action-content">
<view style="display: flex; align-items: center;"
v-if="action.type === 'afterAdd' || action.type === 'transfer'">
<text>目标人员</text>
<view style="flex: 1;">
<UserPicker @update:modelValue="selectedUser= $event" position="bottom"></UserPicker>
</view>
</view>
<view style="display: flex; align-items: center;" v-else-if="action.type === 'recall'">
<text>回退节点</text>
<view style="flex: 1;">
<SelectPicker labelKey="nodeName" valueKey="nodeId"
@update:modelValue="handerParams.targetNode= $event" :options="recallNodes" />
</view>
</view>
<view style="display: flex; align-items: center;" v-if="activeTasks.length > 1">
<text>处理节点</text>
<view style="flex: 1;">
<select-picker placeholder="要处理哪个任务" valueKey="taskId" labelKey="name"
v-model="handerParams.taskId" :options="activeTasks" />
</view>
</view>
<uni-easyinput type="textarea" v-model="handerParams.comment.text" :placeholder="action.tip" />
<view style="margin: 32rpx 0;">
<FileUpload ref="attachFile" :formProps="{maxSize: 10, placeholder:'审批附件'}"
@update:modelValue="attachment.files= $event" />
<ImageUpload :formProps="{maxSize: 10, placeholder:'审批附图', maxNumber: 5}"
@update:modelValue="attachment.images = $event" />
<view style="margin-top: 32rpx;" v-if="showSignCt">
<sign-panel position="bottom" v-model="handerParams.signature" />
</view>
</view>
</view>
<view class="w-action-confirm">
<button type="default" @click="$refs.doActionPopup.close()">取消</button>
<button type="primary" @click="submitAction"> </button>
</view>
</uni-popup>
</view>
</view>
</template>
<script>
import {
getFormAndProcessProgress,
approvalTask,
getEnableRecallNodes,
getTaskNodeSettings
} from '@/api/task'
import {
$nEmpty,
debounce,
} from '@/utils/tool.js'
import {
getUserSign
} from "@/api/org";
import Avatar from './components/Avatar.vue'
// import FormRender from '@/components/FormRender.vue'
import processProgress from './components/processProgress.vue'
import UserPicker from './components/UserPicker.vue'
import ImageUpload from "./components/ImageUpload.vue";
import FileUpload from "./components/FileUpload.vue";
import SelectPicker from "./components/SelectPicker.vue";
export default {
components: {
Avatar,
processProgress,
ImageUpload,
FileUpload,
UserPicker,
SelectPicker
},
data() {
return {
nodeId: null,
instanceId: null,
instanceData: null,
selectedUser: [],
recallNodes: [],
showSign: false,
action: {
type: '',
title: null,
tip: null
},
attachment: {
files: [],
images: []
},
handerParams: {
instanceId: null,
taskId: null,
comment: {
text: null,
attachments: []
},
formData: {},
signature: null,
action: null,
updateSign: false,
targetNode: null,
targetUser: null,
userId: null,
},
workerListOptions: [], // 施工人员
cooperatorList: [], // 所有企业信息
deviceUnitList: [], // 装置列表
enterpriseTypeListFull: [], // 全部企业信息
classifyListUp: [], // 问题描述
projectSn: "",
mobileTopHeight: 0,
}
},
created() {
this.getWorkerInfo();
this.getCooperatorList();
this.projectGroupListFn();
this.getDeviceUnitList();
this.getDescribeClassifyList();
},
onLoad(v) {
this.nodeId = v.nodeId;
this.instanceId = v.instanceId;
this.getInstanceData(v.instanceId, v.nodeId);
this.projectSn = JSON.parse(uni.getStorageSync('projectDetail')).projectSn;
},
mounted() {
//当前登录的用户
this.userId = JSON.parse(uni.getStorageSync('userInfo')).userId;
var that = this
uni.getSystemInfo({
success(res) {
that.mobileTopHeight = res.statusBarHeight ? res.statusBarHeight : 0;
console.log(res)
}
})
},
onShow() {
},
computed: {
//获取文件访问路径
getRes() {
return (url) => {
if (url) {
const reg = /^(http:|https:).*/gi
return reg.test(url) ? url : this.url_config + 'image/' + url
} else {
return url
}
}
},
getProcTag() {
return (result) => {
switch (result) {
case 'RUNNING':
return {
text: '进行中', type: 'primary'
}
case 'COMPLETE':
return {
text: '已结束', type: 'primary'
}
case 'PASS':
return {
text: '审批通过', type: 'success'
}
case 'CANCEL':
return {
text: '已撤销', type: 'default'
}
case 'REFUSE':
return {
text: '审批驳回', type: 'error'
}
default:
return {
text: '未知状态', type: 'default'
}
}
}
},
showSignCt() {
return this.showSign && this.action.type === 'agree'
},
enableCancel() {
try {
return this.instanceData?.externSetting?.enableCancel
} catch (e) {
return false
}
},
//过滤本人下待处理的节点
activeTasks() {
let tasks = [];
(this.instanceData.progress || []).forEach(task => {
if (task.isFuture) return
if (task.users) {
task.users.forEach(tk => {
if (tk.user && tk.user.id === this.userId && !$nEmpty(tk
.finishTime)) {
tasks.push(tk)
}
})
} else {
if (task.user && task.user.id === this.userId && !$nEmpty(task.finishTime)) {
tasks.push(task)
}
}
})
return tasks;
},
contentHeight() {
const h = uni.getSystemInfoSync().windowHeight
return this.instanceData.finishTime ? h - 100 : h - 120
},
formDataFn() {
return (row) => {
const result = this.instanceData.formData;
// console.log(11111, result[row.id], row.name)
if (row.name == 'SelectPlus') {
if (row.id == 'field6262215428808') {
return this.deviceUnitList
.filter(item => result[row.id].includes(item.id))
.map(item => item.deviceUnitName)
.join('、');
} else if (row.id == 'field7328425468551') {
return this.enterpriseTypeListFull
.filter(item => result[row.id].includes(item.id))
.map(item => item.projectGroupName)
.join('、');
} else if (row.id == 'field1488826615159' || row.id == 'field9976626656507' || row.id ==
'field2540125384788') {
// console.log(3333, JSON.stringify(result[row.id]), JSON.stringify(this.cooperatorList))
return this.cooperatorList
.filter(item => result[row.id].includes(item.id))
.map(item => item.enterpriseName)
.join('、');
} else if (row.id == 'field7469574611447') {
return this.workerListOptions
.filter(item => result[row.id].includes(item.id))
.map(item => item.workerName)
.join('、');
}
return result[row.id];
} else if (row.name == 'CascaderSelect') {
if (row.id == 'field9069961325117' || row.id == 'field5281362911293') {
let resultList = result[row.id].split('-');
resultList = row.id == 'field9069961325117' ? [resultList[resultList.length - 1]] :
resultList;
return this.setData(this.classifyListUp, resultList, 'dangerName', 'content', '-');
}
return '';
}
if (Array.isArray(result[row.id])) {
return result[row.id].map(item => item.name).join('、')
}
return result[row.id];
};
},
},
watch: {
'handerParams.taskId': {
handler(newVal) {
this.getTaskSet()
},
}
},
methods: {
downloadFn(item) {
var that = this
uni.showModal({
title: '提示',
content: item.name,
confirmText: '下载',
success: function(res) {
if (res.confirm) {
uni.downloadFile({
url: that.url_config + 'image/' + item.url, //仅为示例,并非真实的资源
success: (res) => {
console.log(res)
if (res.statusCode === 200) {
// uni.showToast({
// title:'下载成功'
// })
var filePath = res.tempFilePath;
if (!filePath) return
uni.openDocument({
filePath: filePath,
success: function(res) {
console.log(res);
console.log('打开文档成功');
uni.showToast({
title: '打开文档成功'
})
}
});
} else {
uni.showToast({
title: '下载失败'
})
}
}
});
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
previewImg(img) {
console.log(img);
uni.previewImage({
urls: [img],
longPressActions: true
})
},
//获取问题描述 和 问题分类 下拉列表
getDescribeClassifyList() {
this.sendRequest({
url: 'xmgl/xzSecurityDangerTypeRecord/selectDangerTypeAndItemList',
method: "post",
data: {
projectSn: this.projectSn,
recordStatus: 0
},
success: res => {
if (res.code == 200) {
this.classifyListUp = this.classifyListFn(res.result);
}
}
})
},
classifyListFn(dataList, reduceList = []) {
dataList.forEach(item => {
reduceList.push(item);
if (item.children) {
this.classifyListFn(item.children, reduceList);
} else if (item.itemList) {
this.classifyListFn(item.itemList, reduceList);
}
});
return reduceList;
},
getDeviceUnitList() {
this.sendRequest({
url: 'xmgl/deviceUnit/page',
method: "get",
data: {
projectSn: this.projectSn,
pageNo: 1,
pageSize: -1,
seeI: 1,
},
success: res => {
if (res.code == 200) {
this.deviceUnitList = res.result.records;
}
}
})
},
projectGroupListFn() {
this.sendRequest({
url: 'xmgl/projectGroup/page',
method: "get",
data: {
projectSn: this.projectSn,
pageNo: 1,
pageSize: -1
},
success: res => {
if (res.code == 200) {
this.enterpriseTypeListFull = res.result.records;
}
}
})
},
//获取列表数据
getCooperatorList() {
this.sendRequest({
url: 'xmgl/projectEnterprise/list',
method: "post",
data: {
projectSn: this.projectSn,
page: 1,
pageSize: -1,
},
success: res => {
if (res.code == 200) {
this.cooperatorList = res.result.records;
}
}
})
},
getWorkerInfo() {
this.sendRequest({
url: 'xmgl/workerInfo/selectWorkerInfoList',
method: "post",
data: {
projectSn: this.projectSn,
},
success: res => {
if (res.code == 200) {
this.workerListOptions = res.result.records;
}
}
})
},
//滚动延时去抖动
scDebounce() {
debounce(() => uni.$emit('showFp'), 500)
},
getTaskSet() {
getTaskNodeSettings(this.handerParams.taskId).then(rsp => {
this.showSign = rsp.data.enableSign || false
}).catch(e => {})
},
recursionFormItems(dataList, resultList = []) {
dataList.forEach(item => {
if (item.name == 'SpanLayout') {
this.recursionFormItems(item.props.items, resultList);
} else {
resultList.push(item);
}
});
return resultList;
},
getInstanceData(instId, nodeId) {
getFormAndProcessProgress(instId, nodeId).then(rsp => {
if (rsp.data.code == 200) {
this.instanceData = rsp.data.result;
this.instanceData.formItems = this.recursionFormItems(rsp.data.result.formItems);
console.log(this.instanceData.formItems)
//设置状态图标
switch (this.instanceData.result) {
case 'PASS':
this.instanceData.statusImg = '/static/image/agree.png'
break
case 'CANCEL':
this.instanceData.statusImg = '/static/image/recall.png'
break
case 'REFUSE':
this.instanceData.statusImg = '/static/image/refuse.png'
break
}
} else {
uni.showToast({
title: rsp.data.message,
icon: 'none'
})
}
})
},
showMore() {
this.$refs.actionPopup.open()
},
urging() {
uni.showModal({
title: '催办确认',
content: '您确认要提醒流程中人员尽快处理任务?',
success: function(res) {
if (res.confirm) {
uni.showToast({
icon: 'none',
title: '该功能暂未实现哈😘'
})
} else if (res.cancel) {
}
}
});
},
doAction(type) {
this.handerParams.taskId = this.getTask()
this.selectedUser = []
this.handerParams.targetUser = null
this.handerParams.comment.text = ''
this.handerParams.comment.attachments = []
switch (type) {
case 'comment':
this.action = {
type: type,
title: '添加评论',
tip: '评论内容'
}
break;
case 'transfer':
this.action = {
type: type,
title: '转交流程',
tip: '转交意见',
}
break;
case 'afterAdd':
this.action = {
type: type,
title: '流程节点加签',
tip: '加签意见'
}
break;
case 'recall':
this.action = {
type: type,
title: '退回流程',
tip: '退回意见'
}
this.getEnableRecallNode()
break;
case 'cancel':
this.action = {
type: type,
title: '撤销流程',
tip: '撤销原因'
}
break;
case 'agree':
this.action = {
type: type,
title: '审批同意',
tip: '审批意见'
}
break;
case 'refuse':
this.action = {
type: type,
title: '审批拒绝',
tip: '审批意见'
}
break;
}
this.$refs.doActionPopup.open()
//使文件选择生效
this.$nextTick(() => {
this.$refs.attachFile && this.$refs.attachFile.show()
})
},
loadBeforeSign() {
getUserSign().then(rsp => {
if (rsp.data === '') {
uni.showToast({
icon: 'none',
title: '您还没有保存过的签名'
})
} else {
this.handerParams.signature = rsp.data
}
})
},
//获取要处理的任务id
getTask() {
if ($nEmpty(this.handerParams.taskId)) {
return this.handerParams.taskId
} else if (this.activeTasks.length > 0) {
return this.activeTasks[0].taskId
} else if (this.action.type === 'cancel') {
const pg = this.instanceData.progress || [];
for (let i = 0; i < pg.length; i++) {
if (pg[i].users) {
for (let j = 0; j < pg[i].users.length; j++) {
if (!$nEmpty(pg[i].users[j].finishTime)) {
return pg[i].users[j].taskId
}
}
} else {
if (!$nEmpty(pg[i].finishTime)) {
return pg[i].taskId
}
}
}
}
return null
},
getEnableRecallNode() {
getEnableRecallNodes(this.instanceData.instanceId, this.getTask()).then(rsp => {
this.recallNodes = rsp.data
}).catch(err => {
uni.showToast({
icon: 'none',
title: '获取可回退节点失败'
})
})
},
submitAction() {
this.handerParams.instanceId = this.instanceData.instanceId
this.handerParams.action = this.action.type
this.handerParams.taskId = this.getTask()
this.handerParams.formData = this.instanceData.formData
this.handerParams.comment.attachments = [...this.attachment.files, ...this.attachment.images]
console.log(this.handerParams.comment.attachments)
if ((this.action.type === 'afterAdd' || this.action.type === 'transfer') && !this.selectedUser.length >
0) {
uni.showToast({
icon: 'none',
title: '请设置人员'
})
} else if (this.action.type === 'recall' && !$nEmpty(this.handerParams.targetNode)) {
uni.showToast({
icon: 'none',
title: '请选择回退节点'
})
} else if (this.showSignCt && !$nEmpty(this.handerParams.signature)) {
uni.showToast({
icon: 'none',
title: '请签字后再提交'
})
} else {
this.handerParams.targetUser = this.selectedUser?.[0]?.id
approvalTask(this.handerParams).then(rsp => {
this.$refs.actionPopup.close()
this.$refs.doActionPopup.close()
if (this.action.type === 'comment') {
this.getInstanceData(this.instanceData.instanceId, this.nodeId)
} else {
// uni.reLaunch({
// url: '/pages/projectEnd/safeSame/list?type=1'
// })
this.getInstanceData(this.instanceId, this.nodeId);
}
uni.showToast({
icon: 'success',
title: '处理成功'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.data.msg
})
})
return
}
},
scroll() {
// #ifdef APP-VUE
uni.$emit('wv:scorll');
// #endif
},
setData(dataList, id, name, name2, str) {
return dataList
.filter(item => id.includes(item.id))
.map(item => item[name] ? item[name] : item[name2])
.join(str);
}
}
}
</script>
<style lang="scss" scoped>
// .uni-popup :deep( view:has(>.uni-popup__wrapper-box)){
// background-color: white;
// }
.download {
color: #1684FC;
}
.uni-popup :deep(>view:last-child ){
background-color: white;
}
.process-form {
>view:first-child {
color: #606266;
}
>view {
min-height: 50rpx;
// line-height: 50rpx;
padding: 0 0;
font-size: 28rpx;
}
}
.fixedheader {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 2;
:deep(.headerBox ){
background: #2b8df3;
color: #fff;
}
}
page {
background-color: #F4F5F7;
}
:deep(.w-instace-form) {
.w-form-item {
margin-bottom: 0;
padding-bottom: 16rpx;
}
.w-form-item-r {
margin-bottom: 16rpx;
}
}
.w-instace {
height: calc(100vh - 88rpx) !important;
font-size: 32rpx;
padding-bottom: 144rpx;
.w-instace-header,
.w-instace-form,
.w-instace-process {
margin: 32rpx 0;
padding: 32rpx 16rpx;
background-color: white;
}
.w-instace-header {
margin-top: 0;
position: relative;
image {
position: absolute;
z-index: 2;
width: 160rpx;
height: 160rpx;
right: 32rpx;
bottom: -96rpx;
}
}
:deep(.w-instace-form) {
padding: 32rpx 16rpx;
.w-form-item-r {
padding-bottom: 0;
font-size: 26rpx;
.w-form-title :last-child {
font-size: 29rpx !important;
color: #848484;
}
}
}
.w-instace-header {
display: flex;
align-items: center;
font-size: 26rpx;
.uni-tag {
font-weight: 400;
}
}
}
.w-instace-action {
width: 100%;
height: 144rpx;
background-color: #EFEFEF;
display: flex;
justify-content: space-between;
position: fixed;
bottom: 0;
.w-action {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 25rpx;
text-align: center;
padding: 0 32rpx;
.w-action-main {
width: 40%;
display: flex;
right: 32rpx;
&>button {
// width: 128rpx;
font-size: 32rpx
}
}
}
}
.w-action-mores {
display: flex;
justify-content: space-between;
padding: 64rpx;
font-size: 32rpx;
&>view {
text-align: center;
}
}
.w-more-close {
background-color: #E8E8E8 !important;
border: none !important;
margin: 0 32rpx 32rpx 32rpx;
border-radius: 48rpx;
color: #848484;
}
.w-more-title {
font-size: 29rpx;
text-align: center;
margin-top: 16rpx;
color: #848484;
}
.w-action-content {
padding: 32rpx;
}
.w-action-confirm {
display: flex;
padding-bottom: 32rpx;
button {
width: 40%;
}
}
</style>