feat: [bpm] 退回任务

This commit is contained in:
jason
2026-01-11 23:00:51 +08:00
parent a430c23a2d
commit a7d3d42111
3 changed files with 202 additions and 33 deletions

View File

@@ -71,3 +71,13 @@ export function delegateTask(data: { id: string, delegateUserId: string, reason:
export function transferTask(data: { id: string, assigneeUserId: string, reason: string }) {
return http.put<boolean>('/bpm/task/transfer', data)
}
/** 退回任务 */
export function returnTask(data: { id: string, targetTaskDefinitionKey: string, reason: string }) {
return http.put<boolean>('/bpm/task/return', data)
}
/** 获取可退回的节点列表 */
export function getTaskListByReturn(taskId: string) {
return http.get<any[]>(`/bpm/task/list-by-return?id=${taskId}`)
}

View File

@@ -1,40 +1,39 @@
<!-- 操作按钮 -->
<template>
<view class="yd-detail-footer">
<!-- 有待审批的任务 -->
<view v-if="runningTask">
<view v-if="leftOperations.length > 0" class="w-full flex items-center">
<!-- 左侧操作按钮 -->
<view v-for="(action, idx) in leftOperations" :key="idx" class="mr-32rpx w-60rpx flex flex-col items-center" @click="handleOperation(action.operationType)">
<wd-icon :name="action.iconName" size="40rpx" color="#1890ff" />
<text class="mt-4rpx text-22rpx text-[#333]">{{ action.displayName }}</text>
</view>
<!-- 更多操作按钮 -->
<view v-if="moreOperations.length > 0" class="mr-32rpx w-60rpx flex flex-col items-center" @click="handleShowMore">
<wd-icon name="ellipsis" size="40rpx" color="#1890ff" />
<text class="mt-4rpx text-22rpx text-[#333]">更多</text>
</view>
<!-- 右侧按钮TODO 是否一定要保留两个按钮 -->
<view class="flex flex-1 gap-16rpx">
<wd-button
v-for="(action, idx) in rightOperations"
:key="idx"
:plain="action.plain"
:type="action.btnType"
:round="false"
class="flex-1"
custom-style="min-width: 200rpx; width: 200rpx;"
@click="handleOperation(action.operationType)"
>
{{ action.displayName }}
</wd-button>
</view>
<!-- 有待审批的任务 -->
<view v-if="runningTask" class="yd-detail-footer">
<view class="w-full flex items-center">
<!-- 左侧操作按钮 -->
<view v-for="(action, idx) in leftOperations" :key="idx" class="mr-32rpx w-60rpx flex flex-col items-center" @click="handleOperation(action.operationType)">
<wd-icon :name="action.iconName" size="40rpx" color="#1890ff" />
<text class="mt-4rpx text-22rpx text-[#333]">{{ action.displayName }}</text>
</view>
<!-- 更多操作按钮 -->
<view v-if="moreOperations.length > 0" class="mr-32rpx w-60rpx flex flex-col items-center" @click="handleShowMore">
<wd-icon name="ellipsis" size="40rpx" color="#1890ff" />
<text class="mt-4rpx text-22rpx text-[#333]">更多</text>
</view>
<!-- 更多操作 ActionSheet -->
<wd-action-sheet v-if="moreOperations.length > 0" v-model="showMoreActions" :actions="moreOperations" title="请选择操作" @select="handleMoreAction" />
<!-- 右侧按钮TODO 是否一定要保留两个按钮 -->
<view class="flex flex-1 gap-16rpx">
<wd-button
v-for="(action, idx) in rightOperations"
:key="idx"
:plain="action.plain"
:type="action.btnType"
:round="false"
class="flex-1"
custom-style="min-width: 200rpx; width: 200rpx;"
@click="handleOperation(action.operationType)"
>
{{ action.displayName }}
</wd-button>
</view>
</view>
<!-- TODO 无待审批的任务 需要显示什么 -->
</view>
<!-- TODO 无待审批的任务 需要显示什么 -->
</template>
<script lang="ts" setup>
@@ -91,7 +90,7 @@ function loadTodoTask(task: Task) {
if (task) {
reasonRequire.value = task.reasonRequire ?? false
// 右侧按钮
if (isHandleTaskStatus() && task.buttonsSetting[BpmTaskOperationButtonTypeEnum.REJECT]?.enable) {
if (isHandleTaskStatus() && task.buttonsSetting && task.buttonsSetting[BpmTaskOperationButtonTypeEnum.REJECT]?.enable) {
rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.REJECT)
rightOperations.value.push({
operationType: BpmTaskOperationButtonTypeEnum.REJECT,
@@ -100,7 +99,7 @@ function loadTodoTask(task: Task) {
plain: true,
})
}
if (isHandleTaskStatus() && task.buttonsSetting[BpmTaskOperationButtonTypeEnum.APPROVE]?.enable) {
if (isHandleTaskStatus() && task.buttonsSetting && task.buttonsSetting[BpmTaskOperationButtonTypeEnum.APPROVE]?.enable) {
rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.APPROVE)
rightOperations.value.push({
operationType: BpmTaskOperationButtonTypeEnum.APPROVE,
@@ -109,6 +108,7 @@ function loadTodoTask(task: Task) {
plain: false,
})
}
console.log('rightOperationTypes====>', rightOperationTypes)
// TODO 减签
// 左侧操作,和更多操作
Object.keys(task.buttonsSetting || {}).forEach((key) => {
@@ -157,7 +157,9 @@ function handleOperation(operationType: number) {
toast.show('加签功能待实现')
break
case BpmTaskOperationButtonTypeEnum.RETURN:
toast.show('退回功能待实现')
uni.navigateTo({
url: `/pages-bpm/processInstance/detail/return/index?processInstanceId=${runningTask.value.processInstanceId}&taskId=${runningTask.value.id}`,
})
break
}
}

View File

@@ -0,0 +1,157 @@
<template>
<view class="yd-page-container">
<!-- 顶部导航栏 -->
<wd-navbar
title="退回任务"
left-arrow placeholder safe-area-inset-top fixed
@click-left="handleBack"
/>
<!-- 操作表单 -->
<view class="p-24rpx">
<wd-form ref="formRef" :model="formData" :rules="formRules">
<wd-cell-group border>
<!-- 退回节点选择 -->
<wd-picker
v-model="formData.targetActivityId"
label="退回节点:"
prop="targetActivityId"
:columns="activityOptions"
value-key="taskDefinitionKey"
label-key="name"
placeholder="请选择退回节点"
/>
<!-- 退回原因 -->
<wd-textarea
v-model="formData.reason"
prop="reason"
label="退回原因:"
label-width="180rpx"
placeholder="请输入退回原因"
:maxlength="500"
show-word-limit
clearable
/>
</wd-cell-group>
<!-- 提交按钮 -->
<view class="mt-48rpx">
<wd-button
type="primary"
block
:loading="submitting"
:disabled="submitting"
@click="handleSubmit"
>
退回
</wd-button>
</view>
</wd-form>
</view>
</view>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'wot-design-uni/components/wd-form/types'
import { computed, onMounted, reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { getTaskListByReturn, returnTask } from '@/api/bpm/task'
import { navigateBackPlus } from '@/utils'
const props = defineProps<{
processInstanceId: string
taskId: string
}>()
definePage({
style: {
navigationBarTitleText: '',
navigationStyle: 'custom',
},
})
const taskId = computed(() => props.taskId)
const processInstanceId = computed(() => props.processInstanceId)
const toast = useToast()
const submitting = ref(false)
const formRef = ref<FormInstance>()
const activityOptions = ref<any[]>([])
const formData = reactive({
targetActivityId: '',
reason: '',
})
const formRules = {
targetActivityId: [
{ required: true, message: '退回节点不能为空' },
],
reason: [
{ required: true, message: '退回原因不能为空' },
],
}
/** 返回上一页 */
function handleBack() {
navigateBackPlus(`/pages-bpm/processInstance/detail/index?id=${processInstanceId.value}&taskId=${taskId.value}`)
}
/** 初始化校验 */
if (!props.taskId || !props.processInstanceId) {
toast.show('参数错误')
}
/** 获取可退回的节点列表 */
async function loadReturnTaskList() {
try {
const result = await getTaskListByReturn(taskId.value)
console.log('[return] 获取可退回节点:', result)
if (result && Array.isArray(result)) {
activityOptions.value = result
}
} catch (error) {
console.error('[return] 获取可退回节点失败:', error)
toast.error('获取可退回节点失败')
}
}
/** 提交操作 */
async function handleSubmit() {
if (submitting.value)
return
// 使用 wd-form 的校验方法
const { valid } = await formRef.value!.validate()
if (!valid) {
return
}
submitting.value = true
try {
const result = await returnTask({
id: taskId.value as string,
targetTaskDefinitionKey: formData.targetActivityId,
reason: formData.reason,
})
if (result) {
toast.success('退回成功')
setTimeout(() => {
uni.redirectTo({
url: `/pages-bpm/processInstance/detail/index?id=${processInstanceId.value}&taskId=${taskId.value}`,
})
}, 1500)
}
} catch (error) {
console.error('[return] 退回失败:', error)
toast.error('退回失败')
} finally {
submitting.value = false
}
}
/** 页面加载时获取可退回节点列表 */
onMounted(() => {
loadReturnTaskList()
})
</script>