jeecgBootUniapp/src/pages-process/components/taskDeal.vue

653 lines
18 KiB
Vue
Raw Normal View History

2025-05-26 07:00:08 +00:00
<template>
<view class="containerTask">
<view class="cu-bar bg-white solid-bottom height">
<view class="action">
当前环节
2025-05-27 06:49:17 +00:00
<text class="text-bold">[{{resultObj.taskName}}]</text>
2025-05-26 07:00:08 +00:00
</view>
</view>
<view class="margin-top-sm">
2025-05-27 06:49:17 +00:00
<wd-collapse style="width: 100%;" v-model="value1">
2025-05-26 07:00:08 +00:00
<wd-collapse-item name="item1">
<template #title="{expanded,disabled, isFirst }">
<view class="header">
<wd-img class="taskImg" src="/static/user27.png" />
<text class="text-collapse">委托人办理</text>
<wd-icon v-if="expanded" style="float: right;color: #d8d8d8;" name="arrow-down"
size="22px"></wd-icon>
<wd-icon v-else style="float: right;color: #d8d8d8;" name="arrow-up" size="22px"></wd-icon>
</view>
</template>
<view
style="position: relative; display: inline-block; min-width: 60px; margin: 2px 5px;text-align: center;">
<wd-img v-if="!model.entrust" @click="showSelectuser('show1')"
style="width: 32px; height: 32px; margin: 0px auto;margin-top: 10px;"
src="/static/add.png" />
<view v-if="!model.entrust" style="margin-bottom: 10px;">选择</view>
<view @click="reset('show1')">
<wd-img v-if="model.entrust"
style="width: 32px; height: 32px; margin: 0px auto;margin-top: 10px;"
:src="getFileAccessHttpUrl(modelShow.avatar1)" />
<view v-if="model.entrust" style="margin-bottom: 10px;">
{{modelShow.text1}}
</view>
</view>
<SelectUserModal v-if="modelShow.show1" :selected="model.entrust"
@change="(val)=>{show1Change(val,'show1')}" modalTitle="用户选择" :multi="false"
@close="() => (modelShow.show1 = false)"></SelectUserModal>
</view>
</wd-collapse-item>
</wd-collapse>
</view>
<view>
<view class="cu-bar bg-white solid-bottom margin-top-sm">
<view class="action">
<text>
<span>处理意见</span>
</text>
2025-05-27 06:49:17 +00:00
<wd-picker :columns="dropOptions" label="单列选项" v-model="model.reason" use-default-slot>
2025-05-26 07:00:08 +00:00
<view class="cu-tag line-blue margin-left-sm">
<span>选择常用审批语</span>
</view>
</wd-picker>
</view>
</view>
<view class="bg-white" style="height: 100px;">
<wd-textarea v-model="model.reason" placeholder="请输入审批语句" />
</view>
<view class="cu-bar bg-white solid-top">
<view class="action">
<view>
<text class="text" style="font-size: 15px;">
<span>上传附件</span>
</text>
</view>
</view>
</view>
2025-05-27 06:49:17 +00:00
<view class="grid col-4 grid-square padding bg-white ">
<Mupload v-model="fileListTemp" :path="usePath"></Mupload>
</view>
<view class="bg-white solid-top">
<radio-group :value="model.processModel" @change="radioChange">
<label class="uni-list-cell uni-list-cell-pd uni-label-pointer">
<!-- 点击的文字 -->
<radio value="1" style="transform: scale(0.7);" :checked="true"></radio>
2025-05-28 06:52:04 +00:00
<view class="margin-left-sm text-sm">同意</view>
2025-05-27 06:49:17 +00:00
</label>
2025-05-27 10:12:30 +00:00
<label class="uni-list-cell uni-list-cell-pd uni-label-pointer" v-if="resultObj.histListSize>0">
2025-05-27 06:49:17 +00:00
<!-- 点击的文字 -->
<radio value="3" style="transform: scale(0.7);"></radio>
<view class="margin-left-sm text-sm">驳回</view>
</label>
2025-05-27 10:12:30 +00:00
<label class="uni-list-cell uni-list-cell-pd uni-label-pointer">
<!-- 点击的文字 -->
<radio value="4" style="transform: scale(0.7);"></radio>
<view class="margin-left-sm text-sm">不同意</view>
</label>
2025-05-27 06:49:17 +00:00
<label class="uni-list-cell uni-list-cell-pd uni-label-pointer" v-if="model.processModel=='3'">
<wd-picker :columns="rejectColumns" label="单列选项" v-model="model.rejectModelNode"
use-default-slot>
<view>
<text class="text-lg margin-tb-sm">
<span>{{model.rejectModelNode?dictRejctModel(model.rejectModelNode):'选择驳回节点'}}</span>
</text>
</view>
</wd-picker>
</label>
</radio-group>
</view>
</view>
<view class="margin-top-sm">
<wd-collapse style="width: 100%;" v-model="value2">
<wd-collapse-item name="item1">
<template #title="{expanded,disabled, isFirst }">
<view class="header">
<wd-img class="taskImg" src="/static/user27.png" />
<text class="text-collapse">指定下一步操作人</text>
<wd-icon v-if="expanded" style="float: right;color: #d8d8d8;" name="arrow-down"
size="22px"></wd-icon>
<wd-icon v-else style="float: right;color: #d8d8d8;" name="arrow-up" size="22px"></wd-icon>
</view>
</template>
<view
style="position: relative; display: inline-block; min-width: 60px; margin: 2px 5px;text-align: center;">
<wd-img v-if="!model.nextUserName" @click="showSelectuser('show2')"
style="width: 32px; height: 32px; margin: 0px auto;margin-top: 10px;"
src="/static/add.png" />
<view v-if="!model.nextUserName" style="margin-bottom: 10px;">选择</view>
<view @click="reset('show2')">
<wd-img v-if="model.nextUserName"
style="width: 32px; height: 32px; margin: 0px auto;margin-top: 10px;"
:src="getFileAccessHttpUrl(modelShow.avatar2)" />
<view v-if="model.nextUserName" style="margin-bottom: 10px;">
{{modelShow.text2}}
</view>
</view>
<SelectUserModal v-if="modelShow.show2" :selected="model.nextUserName"
@change="(val)=>{show1Change(val,'show2')}" modalTitle="用户选择" :multi="false"
@close="() => (modelShow.show2 = false)"></SelectUserModal>
</view>
</wd-collapse-item>
</wd-collapse>
2025-05-26 07:00:08 +00:00
</view>
2025-05-27 06:49:17 +00:00
<view class="margin-top-sm">
<wd-collapse style="width: 100%;" v-model="value3">
<wd-collapse-item name="item1">
<template #title="{expanded,disabled, isFirst }">
<view class="header">
<wd-img class="taskImg" src="/static/user27.png" />
<text class="text-collapse">指定抄送人</text>
<wd-icon v-if="expanded" style="float: right;color: #d8d8d8;" name="arrow-down"
size="22px"></wd-icon>
<wd-icon v-else style="float: right;color: #d8d8d8;" name="arrow-up" size="22px"></wd-icon>
</view>
</template>
<view
style="position: relative; display: inline-block; min-width: 60px; margin: 2px 5px;text-align: center;">
<wd-img v-if="!model.ccUserIds" @click="showSelectuser('show3')"
style="width: 32px; height: 32px; margin: 0px auto;margin-top: 10px;"
src="/static/add.png" />
<view v-if="!model.ccUserIds" style="margin-bottom: 10px;">选择</view>
<view @click="reset('show3')">
<wd-img v-if="model.ccUserIds"
style="width: 32px; height: 32px; margin: 0px auto;margin-top: 10px;"
:src="getFileAccessHttpUrl(modelShow.avatar3)" />
<view v-if="model.ccUserIds" style="margin-bottom: 10px;">
{{modelShow.text3}}
</view>
</view>
<SelectUserModal v-if="modelShow.show3" :selected="model.ccUserIds"
@change="(val)=>{show1Change(val,'show3')}" modalTitle="用户选择" :multi="false"
@close="() => (modelShow.show3 = false)"></SelectUserModal>
</view>
</wd-collapse-item>
</wd-collapse>
</view>
<view class="padding text-center">
<view v-if="model.processModel==1">
<template v-for="(item,index) in resultObj.transitionList">
<wd-button class="cu-btn" style="margin-bottom: 3px;" @click="finishTask(item.nextnode)">
{{ item.Transition }}
</wd-button>
</template>
</view>
<view v-else>
<wd-button type="primary" @click="handleManyProcessComplete()">确认提交</wd-button>
</view>
</view>
<wd-toast></wd-toast>
<wd-message-box></wd-message-box>
2025-05-26 07:00:08 +00:00
</view>
</template>
<script setup lang="ts">
import SelectUserModal from '@/components/SelectUser/components/SelectUserModal.vue'
import { getFileAccessHttpUrl } from '@/common/uitls'
import { useQueue } from 'wot-design-uni'
import Mupload from '@/components/Mupload/Mupload.vue'
2025-05-28 06:52:04 +00:00
import { getProcessTaskTransInfo, processComplete, taskEntrust, callBackProcessApi, sendMessageApi } from '@/api/process'
2025-05-27 06:49:17 +00:00
import { useToast, useMessage, useNotify, dayjs } from 'wot-design-uni'
2025-05-26 07:00:08 +00:00
defineOptions({
name: 'taskDeal',
options: {
styleIsolation: 'shared',
},
})
2025-05-27 06:49:17 +00:00
const fileListTemp = ref('')
const toast = useToast()
const message = useMessage()
const resultObj = ref({}) //流程信息
const rejectColumns = ref([]) //驳回节点信息
const value1 = ref([])
const value2 = ref([])
const value3 = ref([])
2025-05-26 07:00:08 +00:00
const modelShow = ref({
show1: false,
text1: '',
2025-05-27 06:49:17 +00:00
avatar1: '',
show2: false,
text2: '',
avatar2: '',
show3: false,
text3: '',
avatar3: '',
2025-05-26 07:00:08 +00:00
})
const model = ref({
taskId: '', //taskid
nextnode: '', //下一个节点
nextCodeCount: '',
reason: '同意', //原因
processModel: 1, //分支模式:单分支、多分支
rejectModelNode: '', //驳回节点
nextUserName: '', //下一步会签人员
nextUserId: '', //下一步会签人员id
ccUserIds: '', //抄送人员ids
ccUserRealNames: '', //抄送人员usernames
fileList: '', //文件上传list
ysjqx: true, //压缩机数据权限
entrust: '', //委托人员
})
const { closeOutside } = useQueue()
const dropOptions = ref([ //审批语配置
{ label: '同意', value: '同意' },
{ label: '同意***的意见', value: '同意***的意见' },
{ label: '请指示', value: '请指示' },
{ label: '请***阅示', value: '请***阅示' },
{ label: '请处理', value: '请处理' },
{ label: '不同意', value: '不同意' },
{ label: '请审批', value: '请审批' },
{ label: '审核无误', value: '审核无误' },
])
const props = defineProps({
formData: {
type: Object,
2025-05-28 06:52:04 +00:00
default: () => { }
},
2025-05-26 07:00:08 +00:00
2025-05-28 06:52:04 +00:00
useData: {
type: Object,
default: () => { }
}
2025-05-26 07:00:08 +00:00
})
2025-05-27 06:49:17 +00:00
const usePath = ref('流程办理附件')
watch( //监听文件路径更改
() => props.formData,
(val) => {//监听formdata 加载数据
if (val) {
model.value.taskId = val.taskId;
rejectColumns.value = []; //清空驳回信息
model.value.rejectModelNode = '';
let tempArr = [];
getProcessTaskTransInfo({ taskId: model.value.taskId }).then(res => {
if (res.success) {
resultObj.value = res.result;
res.result.histListNode.forEach(item => {
if (item.NAME_ != res.result.taskName) {//不是当前节点
tempArr.push({ label: item.NAME_, value: item.TASK_DEF_KEY_ })
}
})
rejectColumns.value = tempArr; //赋值驳回信息
}
})
}
},
{ immediate: true, deep: true },
)
const radioChange = (val) => {
model.value.processModel = val.detail.value
if (val.detail.value != 3) {
//清空驳回信息
model.value.rejectModelNode = '';
}
}
2025-05-26 07:00:08 +00:00
const showSelectuser = (val : string) => { //选人组件
modelShow.value[val] = true;
}
const show1Change = (val, type) => {
let selectUser = val[0]
switch (type) {
case 'show1':
model.value.entrust = selectUser.username
modelShow.value['text1'] = selectUser.realname
modelShow.value['avatar1'] = selectUser.avatar
break;
2025-05-27 06:49:17 +00:00
case 'show2':
model.value.nextUserId = selectUser.username
model.value.nextUserName = selectUser.realname
modelShow.value['text2'] = selectUser.realname
modelShow.value['avatar2'] = selectUser.avatar
break;
case 'show3':
model.value.ccUserIds = selectUser.username
model.value.ccUserRealNames = selectUser.realname
modelShow.value['text3'] = selectUser.realname
modelShow.value['avatar3'] = selectUser.avatar
break;
2025-05-26 07:00:08 +00:00
default:
break;
}
}
const reset = (val : string) => { //重置
switch (val) {
case 'show1':
model.value.entrust = ''
modelShow.value['text1'] = ''
modelShow.value['avatar1'] = ''
break;
2025-05-27 06:49:17 +00:00
case 'show2':
model.value.nextUserName = ''
model.value.nextUserId = ''
modelShow.value['text2'] = ''
modelShow.value['avatar2'] = ''
break;
case 'show3':
model.value.ccUserIds = ''
model.value.ccUserRealNames = '';
modelShow.value['text3'] = ''
modelShow.value['avatar3'] = ''
break;
2025-05-26 07:00:08 +00:00
default:
break;
}
}
2025-05-27 06:49:17 +00:00
const dictRejctModel = (val) => {//翻译驳回
return rejectColumns.value.filter(item => {
return item.value = val
})[0].label;
}
const finishTask = (nextNode) => {//完成任务
if (nextNode) {
handleProcessComplete(nextNode)
return;
}
if (resultObj.value.transitionList.length == 1) {
handleProcessComplete(resultObj.value.transitionList[0].nextnode)
} else {
toast.error("存在多分支,请手动选择分支!")
}
}
const handleProcessComplete = (nextNode) => {
2025-05-27 10:12:30 +00:00
if (model.value.processModel == 4) { //4 取回流程
message
.confirm({
msg: '确认取回流程吗?',
title: '提示',
})
.then(() => {
2025-05-28 06:52:04 +00:00
let param = {
reason: model.value.reason,
bpmBizTitle: props.useData.bpmBizTitle,
processApplyUser: props.useData.processApplyUserId,
processApplyUserName: props.useData.processApplyUserName,
taskAssigneeName: props.useData.taskAssigneeName,
taskName: props.useData.taskName,
taskBeginTime: props.useData.taskBeginTime
}
callBackProcessApi({
processInstanceId: props.formData.procInsId
}).then((res) => {
if (res.success) {
sendMessageApi(param) //给发起人发送信息
toast.success(res.message)
setTimeout(() => { //延迟2s
uni.navigateBack()
}, 2000)
} else {
toast.warning(res.message)
}
})
2025-05-27 10:12:30 +00:00
})
} else {
if (!model.value.reason || model.value.reason.length == 0) {
toast.error("请填写处理意见!")
return
}
if (nextNode) { // true
model.value.nextnode = nextNode;
}
2025-05-27 06:49:17 +00:00
2025-05-27 10:12:30 +00:00
if (model.value.entrust) { //如果有委托,不办理流程
var params = {
taskId: model.value.taskId,
taskAssignee: model.value.entrust
};//查询条件
taskEntrust(params).then(res => {
if (res.success) {
2025-05-27 09:31:39 +00:00
toast.success(res.message)
2025-05-27 06:49:17 +00:00
setTimeout(() => { //延迟0.5s
uni.navigateBack()
2025-05-28 06:52:04 +00:00
}, 2000)
2025-05-27 06:49:17 +00:00
} else {
toast.error(res.message)
}
})
2025-05-27 10:12:30 +00:00
return;
}
message
.confirm({
msg: '确认提交审批吗?',
title: '提示',
})
.then(() => {
model.fileList = JSON.stringify(fileListTemp.value)
processComplete(model.value).then(res => {
if (res.success) {//跳转页面或加载下一个任务
toast.success(res.message)
setTimeout(() => { //延迟0.5s
uni.navigateBack()
}, 1000)
} else {
toast.error(res.message)
}
})
})
}
2025-05-27 06:49:17 +00:00
}
const handleManyProcessComplete = () => { //驳回任务提交
if (model.value.processModel == 3) {
if (!model.value.rejectModelNode || model.value.rejectModelNode.length == 0) {
toast.error("请选择驳回节点!")
return
}
// else{
// //添加判断在这个item.TASK_DEF_KEY_的参数下面
// //如果是驳回这个item.TASK_DEF_KEY_参数传递给提交流程
// this.handleProcessComplete();
// }
}
handleProcessComplete('');
}
onMounted(() => {
let yy = new Date().getFullYear();
let mm = new Date().getMonth() + 1;
usePath.value = yy + '-' + mm + '-' + '流程办理附件';
})
2025-05-26 07:00:08 +00:00
</script>
<style lang="scss" scoped>
.bg-white {
background-color: #fff;
color: #666;
}
.height {
height: 48px;
}
.cu-bar {
display: flex;
position: relative;
align-items: center;
min-height: 50px;
justify-content: space-between;
}
.cu-bar .action:last-child {
margin-right: 15px;
}
.cu-bar .action:first-child {
margin-left: 15px;
font-size: 15px;
}
.cu-bar .action {
display: flex;
align-items: center;
height: 100%;
justify-content: center;
max-width: 100%;
}
.margin-top-sm {
margin-top: 10px;
}
.containerTask {
background-color: #f7f7f7;
}
.text-bold {
font-weight: 700;
}
.text-collapse {
flex: 1;
font-size: 14px;
white-space: nowrap;
color: inherit;
overflow: hidden;
text-overflow: ellipsis;
}
.taskImg {
height: 17px;
width: 17px;
margin-right: 10px;
vertical-align: -15%
}
2025-05-27 06:49:17 +00:00
2025-05-26 07:00:08 +00:00
.solid-bottom::after {
2025-05-27 06:49:17 +00:00
border-bottom: 1px solid rgba(0, 0, 0, .1);
2025-05-26 07:00:08 +00:00
}
2025-05-27 06:49:17 +00:00
.text-blue,
.line-blue,
.lines-blue {
color: #0081ff;
2025-05-26 07:00:08 +00:00
}
2025-05-27 06:49:17 +00:00
2025-05-26 07:00:08 +00:00
.margin-left-sm {
2025-05-27 06:49:17 +00:00
margin-left: 10px;
2025-05-26 07:00:08 +00:00
}
2025-05-27 06:49:17 +00:00
2025-05-26 07:00:08 +00:00
.cu-tag {
2025-05-27 06:49:17 +00:00
font-size: 12px;
vertical-align: middle;
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 0px 8px;
height: 24px;
font-family: Helvetica Neue, Helvetica, sans-serif;
white-space: nowrap;
}
2025-05-26 07:00:08 +00:00
.cu-tag[class*="line-"]::after {
2025-05-27 06:49:17 +00:00
border-radius: 0;
2025-05-26 07:00:08 +00:00
}
2025-05-27 06:49:17 +00:00
2025-05-26 07:00:08 +00:00
.cu-tag[class*="line-"]::after {
2025-05-27 06:49:17 +00:00
content: " ";
width: 200%;
height: 200%;
position: absolute;
top: 0;
left: 0;
border: 1px solid currentColor;
-webkit-transform: scale(.5);
transform: scale(.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
box-sizing: border-box;
border-radius: inherit;
z-index: 1;
pointer-events: none;
}
.grid.grid-square {
overflow: hidden;
}
.bg-white {
background-color: #fff;
color: #666;
}
.padding {
padding: 17px;
display: block;
}
.grid {
display: flex;
flex-wrap: wrap;
}
.text-sm {
font-size: 13px;
}
.uni-list-cell {
position: relative;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
border-bottom: 1px solid #f0f0f0;
}
.uni-list-cell-pd {
padding: 8px 15px;
}
.uni-label-pointer {
cursor: pointer;
}
.cu-btn {
position: relative;
border: 0px;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 0 15px;
font-size: 14px;
height: 32px;
line-height: 1;
text-align: center;
text-decoration: none;
overflow: visible;
margin-left: 0;
-webkit-transform: translate(0px, 0px);
transform: translate(0px, 0px);
margin-right: 0;
}
.text-lg {
font-size: 16px;
}
.margin-tb-sm {
margin-top: 10px;
margin-bottom: 10px;
2025-05-26 07:00:08 +00:00
}
</style>