feat: [bpm] 审批详情操作按钮
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import type { Task } from '@/api/bpm/task'
|
||||
import type { PageParam, PageResult } from '@/http/types'
|
||||
import { http } from '@/http/http'
|
||||
|
||||
@@ -47,6 +48,7 @@ export interface ProcessInstance {
|
||||
export interface ApprovalDetail {
|
||||
processInstance: ProcessInstance
|
||||
processDefinition: ProcessDefinition
|
||||
todoTask: Task
|
||||
}
|
||||
|
||||
/** 抄送流程实例 */
|
||||
|
||||
@@ -11,6 +11,10 @@ export interface TaskUser {
|
||||
deptName?: string
|
||||
}
|
||||
|
||||
export interface OperationButtonSetting {
|
||||
displayName: string // 按钮名称
|
||||
enable: boolean // 是否启用
|
||||
}
|
||||
/** 流程任务 */
|
||||
export interface Task {
|
||||
id: string
|
||||
@@ -24,6 +28,8 @@ export interface Task {
|
||||
ownerUser?: TaskUser
|
||||
processInstanceId?: string // 流程实例 ID
|
||||
processInstance: ProcessInstance
|
||||
reasonRequire?: boolean // 是否填写审批意见
|
||||
buttonsSetting?: Record<number, OperationButtonSetting> // 按钮设置
|
||||
}
|
||||
|
||||
/** 查询待办任务分页列表 */
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
<!-- 操作按钮 -->
|
||||
<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>
|
||||
<!-- 更多操作 ActionSheet -->
|
||||
<wd-action-sheet v-if="moreOperations.length > 0" v-model="showMoreActions" :actions="moreOperations" title="请选择操作" @select="handleMoreAction" />
|
||||
</view>
|
||||
<!-- TODO 无待审批的任务 需要显示什么 -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Action } from 'wot-design-uni/components/wd-action-sheet/types'
|
||||
import type { ButtonType } from 'wot-design-uni/components/wd-button/types'
|
||||
import type { Task } from '@/api/bpm/task'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
import {
|
||||
BpmTaskOperationButtonTypeEnum,
|
||||
BpmTaskStatusEnum,
|
||||
OPERATION_BUTTON_NAME,
|
||||
} from '@/utils/constants'
|
||||
|
||||
const showMoreActions = ref(false)
|
||||
|
||||
type MoreOperationType = Action & {
|
||||
operationType: number
|
||||
}
|
||||
|
||||
interface LeftOperationType {
|
||||
operationType: number
|
||||
iconName: string
|
||||
displayName: string
|
||||
}
|
||||
|
||||
interface RightOperationType {
|
||||
operationType: number
|
||||
btnType: ButtonType
|
||||
displayName: string
|
||||
plain: boolean
|
||||
}
|
||||
const operationIconsMap: Record<number, string> = {
|
||||
[BpmTaskOperationButtonTypeEnum.TRANSFER]: 'transfer',
|
||||
[BpmTaskOperationButtonTypeEnum.ADD_SIGN]: 'add',
|
||||
[BpmTaskOperationButtonTypeEnum.DELEGATE]: 'share',
|
||||
[BpmTaskOperationButtonTypeEnum.RETURN]: 'arrow-left',
|
||||
[BpmTaskOperationButtonTypeEnum.COPY]: 'copy',
|
||||
}
|
||||
/** 左侧操作按钮 【最多两个】{转办, 委派, 退回, 加签, 抄送等} */
|
||||
const leftOperations = ref<LeftOperationType[]>([])
|
||||
|
||||
/** 右侧操作按钮【最多两个】{通过,拒绝, 取消,减签} */
|
||||
const rightOperationTypes = []
|
||||
const rightOperations = ref<RightOperationType[]>([])
|
||||
/** 更多操作 */
|
||||
const moreOperations = ref<MoreOperationType[]>([])
|
||||
const toast = useToast()
|
||||
const runningTask = ref<Task>()
|
||||
const reasonRequire = ref<boolean>(false)
|
||||
|
||||
/** 加载待办任务 */
|
||||
function loadTodoTask(task: Task) {
|
||||
runningTask.value = task
|
||||
if (task) {
|
||||
reasonRequire.value = task.reasonRequire ?? false
|
||||
// 右侧按钮
|
||||
if (isHandleTaskStatus() && task.buttonsSetting[BpmTaskOperationButtonTypeEnum.REJECT]?.enable) {
|
||||
rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.REJECT)
|
||||
rightOperations.value.push({
|
||||
operationType: BpmTaskOperationButtonTypeEnum.REJECT,
|
||||
displayName: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.REJECT),
|
||||
btnType: 'error',
|
||||
plain: true,
|
||||
})
|
||||
}
|
||||
if (isHandleTaskStatus() && task.buttonsSetting[BpmTaskOperationButtonTypeEnum.APPROVE]?.enable) {
|
||||
rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.APPROVE)
|
||||
rightOperations.value.push({
|
||||
operationType: BpmTaskOperationButtonTypeEnum.APPROVE,
|
||||
displayName: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.APPROVE),
|
||||
btnType: 'primary',
|
||||
plain: false,
|
||||
})
|
||||
}
|
||||
// TODO 减签
|
||||
// 左侧操作,和更多操作
|
||||
Object.keys(task.buttonsSetting || {}).forEach((key) => {
|
||||
const operationType = Number(key)
|
||||
if (task.buttonsSetting[key].enable && isHandleTaskStatus()
|
||||
&& !rightOperationTypes.includes(operationType)) {
|
||||
if (leftOperations.value.length >= 2) {
|
||||
moreOperations.value.push({
|
||||
name: getButtonDisplayName(operationType),
|
||||
operationType,
|
||||
})
|
||||
} else {
|
||||
leftOperations.value.push({
|
||||
operationType,
|
||||
iconName: operationIconsMap[operationType],
|
||||
displayName: getButtonDisplayName(operationType),
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
/** 跳转到相应的操作页面 */
|
||||
function handleOperation(operationType: number) {
|
||||
if (!runningTask.value) {
|
||||
return
|
||||
}
|
||||
switch (operationType) {
|
||||
case BpmTaskOperationButtonTypeEnum.APPROVE:
|
||||
uni.navigateTo({ url: `/pages-bpm/processInstance/detail/audit/index?id=${runningTask.value.id}&pass=true` })
|
||||
break
|
||||
case BpmTaskOperationButtonTypeEnum.REJECT:
|
||||
uni.navigateTo({ url: `/pages-bpm/processInstance/detail/audit/index?id=${runningTask.value.id}&pass=false` })
|
||||
break
|
||||
case BpmTaskOperationButtonTypeEnum.DELEGATE:
|
||||
toast.show('委派功能待实现')
|
||||
break
|
||||
case BpmTaskOperationButtonTypeEnum.TRANSFER:
|
||||
toast.show('转办功能待实现')
|
||||
break
|
||||
case BpmTaskOperationButtonTypeEnum.ADD_SIGN:
|
||||
toast.show('加签功能待实现')
|
||||
break
|
||||
case BpmTaskOperationButtonTypeEnum.RETURN:
|
||||
toast.show('退回功能待实现')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/** 显示更多操作 */
|
||||
function handleShowMore() {
|
||||
showMoreActions.value = true
|
||||
}
|
||||
|
||||
/** 处理更多操作选择 */
|
||||
function handleMoreAction(action: { item: MoreOperationType }) {
|
||||
handleOperation(action.item.operationType)
|
||||
showMoreActions.value = false
|
||||
}
|
||||
|
||||
/** 获取按钮的显示名称 */
|
||||
function getButtonDisplayName(btnType: BpmTaskOperationButtonTypeEnum) {
|
||||
let displayName = OPERATION_BUTTON_NAME.get(btnType)
|
||||
if (
|
||||
runningTask.value?.buttonsSetting
|
||||
&& runningTask.value?.buttonsSetting[btnType]
|
||||
) {
|
||||
displayName = runningTask.value.buttonsSetting[btnType].displayName
|
||||
}
|
||||
return displayName
|
||||
}
|
||||
|
||||
/** 是否显示按钮 */
|
||||
function isShowButton(btnType: BpmTaskOperationButtonTypeEnum): boolean {
|
||||
let isShow = true
|
||||
if (
|
||||
runningTask.value?.buttonsSetting
|
||||
&& runningTask.value?.buttonsSetting[btnType]
|
||||
) {
|
||||
isShow = runningTask.value.buttonsSetting[btnType].enable
|
||||
}
|
||||
return isShow
|
||||
}
|
||||
|
||||
/** 任务是否为处理中状态 */
|
||||
function isHandleTaskStatus() {
|
||||
let canHandle = false
|
||||
if (BpmTaskStatusEnum.RUNNING === runningTask.value?.status) {
|
||||
canHandle = true
|
||||
}
|
||||
return canHandle
|
||||
}
|
||||
|
||||
/** 暴露方法 */
|
||||
defineExpose({ loadTodoTask })
|
||||
</script>
|
||||
@@ -88,29 +88,15 @@
|
||||
|
||||
<!-- TODO 待开发:区域:流程评论 -->
|
||||
|
||||
<!-- 区域:底部操作栏 TODO @jason:抽成类似:/Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue -->
|
||||
<view v-if="runningTask" class="yd-detail-footer">
|
||||
<view class="yd-detail-footer-actions">
|
||||
<wd-button type="error" plain class="flex-1" @click="handleReject">
|
||||
拒绝
|
||||
</wd-button>
|
||||
<wd-button type="primary" class="flex-1" @click="handleApprove">
|
||||
同意
|
||||
</wd-button>
|
||||
</view>
|
||||
<!-- TODO @jason:审批通过、不通过:缺少签名、选择审批人 -->
|
||||
<!-- TODO @jason:取消流程、重新发起 -->
|
||||
<!-- TODO @jason:抄送、转派、委派、退回 -->
|
||||
<!-- TODO @jason:加签、减签 -->
|
||||
</view>
|
||||
<!-- 区域:底部操作栏 -->
|
||||
<ProcessInstanceOperationButton ref="operationButtonRef" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ProcessDefinition, ProcessInstance } from '@/api/bpm/processInstance'
|
||||
import type { Task } from '@/api/bpm/task'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
import { getApprovalDetail } from '@/api/bpm/processInstance'
|
||||
import { getTaskListByProcessInstanceId } from '@/api/bpm/task'
|
||||
@@ -118,6 +104,12 @@ import { useUserStore } from '@/store'
|
||||
import { navigateBackPlus } from '@/utils'
|
||||
import { formatDateTime, formatPast } from '@/utils/date'
|
||||
import FormDetail from './components/form-detail.vue'
|
||||
import ProcessInstanceOperationButton from './components/operation-button.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
id: string // 流程实例的编号
|
||||
taskId?: string // 任务编号
|
||||
}>()
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
@@ -128,23 +120,13 @@ definePage({
|
||||
|
||||
const userStore = useUserStore()
|
||||
const toast = useToast()
|
||||
const processInstanceId = ref('')
|
||||
const processInstance = ref<Partial<ProcessInstance>>({})
|
||||
const processDefinition = ref<Partial<ProcessDefinition>>({})
|
||||
const tasks = ref<Task[]>([])
|
||||
const orderAsc = ref(true)
|
||||
|
||||
/** 当前用户需要处理的任务 */
|
||||
const runningTask = computed(() => {
|
||||
return tasks.value.find((task) => {
|
||||
// 待处理状态
|
||||
if (task.status !== 1 && task.status !== 6) {
|
||||
return false
|
||||
}
|
||||
// 当前用户是处理人
|
||||
return task.assigneeUser?.id === userStore.userInfo?.id
|
||||
})
|
||||
})
|
||||
// 操作按钮组件 ref
|
||||
const operationButtonRef = ref()
|
||||
|
||||
/** 排序后的任务列表 */
|
||||
const sortedTasks = computed(() => {
|
||||
@@ -244,46 +226,33 @@ function getStatusTextClass(status: number) {
|
||||
return 'text-[#999]'
|
||||
}
|
||||
|
||||
/** 同意 */
|
||||
function handleApprove() {
|
||||
if (!runningTask.value) {
|
||||
return
|
||||
}
|
||||
uni.navigateTo({ url: `/pages-bpm/processInstance/detail/audit/index?id=${runningTask.value.id}&pass=true` })
|
||||
}
|
||||
|
||||
/** 拒绝 */
|
||||
function handleReject() {
|
||||
if (!runningTask.value) {
|
||||
return
|
||||
}
|
||||
uni.navigateTo({ url: `/pages-bpm/processInstance/detail/audit/index?id=${runningTask.value.id}&pass=false` })
|
||||
}
|
||||
|
||||
/** 加载流程实例 */
|
||||
async function loadProcessInstance() {
|
||||
const data = await getApprovalDetail({ processInstanceId: processInstanceId.value })
|
||||
const param = {
|
||||
processInstanceId: props.id,
|
||||
taskId: props.taskId,
|
||||
}
|
||||
const data = await getApprovalDetail(param)
|
||||
if (!data || !data.processInstance) {
|
||||
toast.show('查询不到审批详情信息')
|
||||
return
|
||||
}
|
||||
processInstance.value = data.processInstance
|
||||
processDefinition.value = data.processDefinition || {}
|
||||
operationButtonRef.value?.loadTodoTask(data.todoTask)
|
||||
}
|
||||
|
||||
/** 加载任务列表 */
|
||||
async function loadTasks() {
|
||||
tasks.value = await getTaskListByProcessInstanceId(processInstanceId.value)
|
||||
tasks.value = await getTaskListByProcessInstanceId(props.id)
|
||||
}
|
||||
|
||||
/** 初始化 */
|
||||
onLoad(async (options) => {
|
||||
// TODO @jason:通过 props id 处理;
|
||||
if (!options?.id) {
|
||||
onMounted(async () => {
|
||||
if (!props.id) {
|
||||
toast.show('参数错误')
|
||||
return
|
||||
}
|
||||
processInstanceId.value = options.id
|
||||
await Promise.all([loadProcessInstance(), loadTasks()])
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -118,7 +118,7 @@ function handleReset() {
|
||||
|
||||
/** 查看详情 */
|
||||
function handleDetail(item: Task) {
|
||||
uni.navigateTo({ url: `/pages-bpm/processInstance/detail/index?id=${item.processInstance.id}` })
|
||||
uni.navigateTo({ url: `/pages-bpm/processInstance/detail/index?id=${item.processInstance.id}&taskId=${item.id}` })
|
||||
}
|
||||
|
||||
/** 同意 */
|
||||
|
||||
Reference in New Issue
Block a user