review:【bpm】审批详情的操作们

This commit is contained in:
YunaiV
2026-01-14 19:28:11 +08:00
parent 00d3f4fbee
commit 9260346aaa
10 changed files with 67 additions and 63 deletions

View File

@@ -11,10 +11,12 @@ export interface TaskUser {
deptName?: string
}
/** 操作按钮设置 */
export interface OperationButtonSetting {
displayName: string // 按钮名称
enable: boolean // 是否启用
}
/** 流程任务 */
export interface Task {
id: string

View File

@@ -85,13 +85,10 @@ const taskId = computed(() => props.taskId)
const processInstanceId = computed(() => props.processInstanceId)
const toast = useToast()
const submitting = ref(false)
const formRef = ref<FormInstance>()
const formData = reactive({
userIds: [] as number[],
reason: '',
})
const formRules = {
userIds: [
{ required: true, message: '加签处理人不能为空', validator: (value: number[]) => value.length > 0 },
@@ -100,12 +97,14 @@ const formRules = {
{ required: true, message: '审批意见不能为空' },
],
}
const formRef = ref<FormInstance>()
/** 返回上一页 */
function handleBack() {
navigateBackPlus(`/pages-bpm/processInstance/detail/index?id=${processInstanceId.value}&taskId=${taskId.value}`)
}
// TODO @jason最好放在 onMounted 里?或者其他地方,有个入口方法。
/** 初始化校验 */
if (!props.taskId || !props.processInstanceId) {
toast.show('参数错误')
@@ -113,23 +112,24 @@ if (!props.taskId || !props.processInstanceId) {
/** 提交操作 */
async function handleSubmit(type: 'before' | 'after') {
if (submitting.value)
if (submitting.value) {
return
// 使用 wd-form 的校验方法
}
const { valid } = await formRef.value!.validate()
if (!valid) {
return
}
// TODO @jasonsubmitting 改成 formLoading 哇?统一代码风格哈;
submitting.value = true
try {
// TODO @jason这里是不是不用判断 result 哈?
const result = await signCreateTask({
id: taskId.value as string,
type,
userIds: formData.userIds,
reason: formData.reason,
})
if (result) {
const actionText = type === 'before' ? '向前加签' : '向后加签'
toast.success(`${actionText}成功`)
@@ -137,9 +137,10 @@ async function handleSubmit(type: 'before' | 'after') {
uni.redirectTo({
url: `/pages-bpm/processInstance/detail/index?id=${processInstanceId.value}&taskId=${taskId.value}`,
})
}, 1500)
}, 500)
}
} catch (error) {
// TODO @jason可以不用这里的 catch 哈?
const actionText = type === 'before' ? '向前加签' : '向后加签'
console.error(`[add-sign] ${actionText}失败:`, error)
toast.error(`${actionText}失败`)

View File

@@ -1,6 +1,6 @@
<template>
<view class="yd-page-container">
<!-- TODO @芋艿还有一些细节在审批通过没搞完 -->
<!-- TODO @jason还有一些细节在审批通过没搞完1签名2选择审批人3其它等等 -->
<!-- 顶部导航栏 -->
<wd-navbar
:title="isApprove ? '审批同意' : '审批拒绝'"
@@ -93,14 +93,18 @@ function validateForm() {
/** 提交审批 */
async function handleSubmit() {
// TODO @jason看看是不是要用原生的校验
if (submitting.value)
if (submitting.value) {
return
if (!validateForm())
}
if (!validateForm()) {
return
}
// TODO @jason要不换成 formLoading保持项目统一
submitting.value = true
try {
const api = isApprove.value ? approveTask : rejectTask
// TODO @jason这里看看不用 result
const result = await api({
id: taskId.value as string,
reason: formData.reason,
@@ -111,8 +115,6 @@ async function handleSubmit() {
handleBack()
}, 1500)
}
} catch (error) {
console.error('[audit] 审批失败:', error)
} finally {
submitting.value = false
}

View File

@@ -16,7 +16,7 @@
<!-- 更多操作 ActionSheet -->
<wd-action-sheet v-if="moreOperations.length > 0" v-model="showMoreActions" :actions="moreOperations" title="请选择操作" @select="handleMoreAction" />
<!-- 右侧按钮TODO 是否一定要保留两个按钮 -->
<!-- 右侧按钮TODO @jason是否一定要保留两个按钮需要的哈 -->
<view class="flex flex-1 gap-16rpx">
<wd-button
v-for="(action, idx) in rightOperations"
@@ -33,7 +33,7 @@
</view>
</view>
</view>
<!-- 无待审批的任务 仅显示取消按钮TODO 看看还需要显示 -->
<!-- 无待审批的任务 仅显示取消按钮TODO @jason看看还需要显示这个微信交流下 -->
<view v-if="!runningTask && isShowProcessStartCancel()" class="yd-detail-footer">
<wd-button
plain
@@ -90,6 +90,7 @@ const operationIconsMap: Record<number, string> = {
}
const userStore = useUserStore()
// TODO @jason字段注释使用尾注释哈
/** 左侧操作按钮 【最多两个】{转办, 委派, 退回, 加签, 抄送等} */
const leftOperations = ref<LeftOperationType[]>([])
@@ -98,7 +99,6 @@ const rightOperationTypes = []
const rightOperations = ref<RightOperationType[]>([])
/** 更多操作 */
const moreOperations = ref<MoreOperationType[]>([])
const toast = useToast()
const runningTask = ref<Task>()
const processInstance = ref<ProcessInstance>()
const reasonRequire = ref<boolean>(false)
@@ -109,6 +109,7 @@ function init(theProcessInstance: ProcessInstance, task: Task) {
runningTask.value = task
if (task) {
reasonRequire.value = task.reasonRequire ?? false
// TODO @jason这里的判断是否可以简化哈就是默认计算出按钮然后根据数量去渲染具体的按钮。
// 右侧按钮
if (isHandleTaskStatus() && isShowButton(BpmTaskOperationButtonTypeEnum.REJECT)) {
rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.REJECT)
@@ -148,7 +149,8 @@ function init(theProcessInstance: ProcessInstance, task: Task) {
}
}
})
/** 减签操作的显示 */
// 减签操作的显示
if (isShowDeleteSign()) {
if (leftOperations.value.length >= 2) {
moreOperations.value.push({
@@ -191,6 +193,7 @@ function init(theProcessInstance: ProcessInstance, task: Task) {
}
}
}
/** 跳转到相应的操作页面 */
function handleOperation(operationType: number) {
switch (operationType) {

View File

@@ -76,14 +76,11 @@ const taskId = computed(() => props.taskId)
const processInstanceId = computed(() => props.processInstanceId)
const toast = useToast()
const submitting = ref(false)
const formRef = ref<FormInstance>()
const taskOptions = ref<any[]>([])
const formData = reactive({
deleteSignTaskId: '',
reason: '',
})
const formRules = {
deleteSignTaskId: [
{ required: true, message: '减签人员不能为空' },
@@ -92,6 +89,7 @@ const formRules = {
{ required: true, message: '审批意见不能为空' },
],
}
const formRef = ref<FormInstance>()
/** 返回上一页 */
function handleBack() {
@@ -99,6 +97,7 @@ function handleBack() {
}
/** 初始化校验 */
// TODO @jason最好放在 onMounted 里?或者其他地方,有个入口方法。
if (!props.taskId || !props.processInstanceId) {
toast.show('参数错误')
}
@@ -114,7 +113,7 @@ function getDeleteSignUserLabel(task: any): string {
async function loadDeleteSignTaskList() {
try {
let childTasks = []
// TODO @jason这里应该是从 props 里获取?
// 从 URL 参数中获取子任务数据
if (props.children) {
try {
@@ -123,7 +122,6 @@ async function loadDeleteSignTaskList() {
console.error('[delete-sign] 解析子任务数据失败:', parseError)
}
}
// 提示没有子任务数据
if (childTasks.length === 0) {
toast.show('没有可减签的任务')
@@ -135,6 +133,7 @@ async function loadDeleteSignTaskList() {
label: getDeleteSignUserLabel(task),
}))
} catch (error) {
// TODO @jason这里不用 try catch 哈
console.error('[delete-sign] 获取可减签任务失败:', error)
toast.error('获取可减签任务失败')
}
@@ -142,31 +141,32 @@ async function loadDeleteSignTaskList() {
/** 提交操作 */
async function handleSubmit() {
if (submitting.value)
if (submitting.value) {
return
// 使用 wd-form 的校验方法
}
const { valid } = await formRef.value!.validate()
if (!valid) {
return
}
// TODO @jasonsubmitting 改成 formLoading 哇?统一代码风格哈;
submitting.value = true
try {
// TODO @jason这里是不是不用判断 result 哈?
const result = await signDeleteTask({
id: formData.deleteSignTaskId,
reason: formData.reason,
})
if (result) {
toast.success('减签成功')
setTimeout(() => {
uni.redirectTo({
url: `/pages-bpm/processInstance/detail/index?id=${processInstanceId.value}&taskId=${taskId.value}`,
})
}, 1500)
}, 500)
}
} catch (error) {
// TODO @jason可以不用这里的 catch 哈?
console.error('[delete-sign] 减签失败:', error)
toast.error('减签失败')
} finally {
@@ -174,7 +174,7 @@ async function handleSubmit() {
}
}
/** 页面加载时获取可减签任务列表 */
/** 页面加载时获取可减签任务列表 */
onMounted(() => {
loadDeleteSignTaskList()
})

View File

@@ -117,19 +117,18 @@ definePage({
},
})
const userStore = useUserStore()
const toast = useToast()
const processInstance = ref<ProcessInstance>()
const processDefinition = ref<ProcessDefinition>()
const tasks = ref<Task[]>([])
const orderAsc = ref(true)
// 操作按钮组件 ref
const operationButtonRef = ref()
const operationButtonRef = ref() // 操作按钮组件 ref
/** 排序后的任务列表 */
const sortedTasks = computed(() => {
const list = [...tasks.value].filter(t => t.status !== 4) // 过滤已取消
// TODO @jason这里有红色报错看看 fix 下哇?或者这块排序逻辑去掉,貌似没啥用。
list.sort((a, b) => {
if (a.endTime && b.endTime) {
return orderAsc.value ? a.endTime - b.endTime : b.endTime - a.endTime
@@ -227,11 +226,10 @@ function getStatusTextClass(status: number) {
/** 加载流程实例 */
async function loadProcessInstance() {
const param = {
const data = await getApprovalDetail({
processInstanceId: props.id,
taskId: props.taskId,
}
const data = await getApprovalDetail(param)
})
if (!data || !data.processInstance) {
toast.show('查询不到审批详情信息')
return

View File

@@ -72,17 +72,15 @@ const processInstanceId = computed(() => props.processInstanceId)
const taskId = computed(() => props.taskId)
const toast = useToast()
const submitting = ref(false)
const formRef = ref<FormInstance>()
const formData = reactive({
cancelReason: '',
})
const formRules = {
cancelReason: [
{ required: true, message: '取消理由不能为空' },
],
}
const formRef = ref<FormInstance>()
/** 返回上一页 */
function handleBack() {
@@ -99,31 +97,32 @@ if (!props.processInstanceId) {
/** 提交操作 */
async function handleSubmit() {
if (submitting.value)
if (submitting.value) {
return
// 使用 wd-form 的校验方法
}
const { valid } = await formRef.value!.validate()
if (!valid) {
return
}
// TODO @jason最好放在 onMounted 里?或者其他地方,有个入口方法。
submitting.value = true
try {
// TODO @jason不判断 result 可以哇?
const result = await cancelProcessInstanceByStartUser(
processInstanceId.value,
formData.cancelReason,
)
if (result) {
toast.success('流程取消成功')
setTimeout(() => {
uni.redirectTo({
url: `/pages-bpm/processInstance/detail/index?id=${processInstanceId.value}`,
})
}, 1500)
}, 500)
}
} catch (error) {
// TODO @jason错误处理这里可以去掉哈。
console.error('[process-cancel] 取消流程失败:', error)
toast.error('取消流程失败')
} finally {

View File

@@ -76,13 +76,10 @@ const operationType = computed(() => props.type || 'transfer') // 默认转办
const isDelegate = computed(() => operationType.value === 'delegate')
const toast = useToast()
const submitting = ref(false)
const formRef = ref<FormInstance>()
const formData = reactive({
userId: undefined as number | undefined,
reason: '',
})
const formRules = {
userId: [
{ required: true, message: `请选择${isDelegate.value ? '接收人' : '新审批人'}` },
@@ -91,6 +88,7 @@ const formRules = {
{ required: true, message: '审批意见不能为空' },
],
}
const formRef = ref<FormInstance>()
/** 返回上一页 */
function handleBack() {
@@ -98,52 +96,51 @@ function handleBack() {
}
/** 初始化校验 */
// TODO @jason最好放在 onMounted 里?或者其他地方,有个入口方法。
if (!props.taskId || !props.processInstanceId) {
toast.show('参数错误')
}
/** 提交操作 */
async function handleSubmit() {
if (submitting.value)
if (submitting.value) {
return
// 使用 wd-form 的校验方法
}
const { valid } = await formRef.value!.validate()
if (!valid) {
return
}
// TODO @jasonsubmitting 改成 formLoading 哇?统一代码风格哈;
submitting.value = true
try {
const data = {
id: taskId.value as string,
reason: formData.reason,
}
let result
// todo @jason这里是不是不用判断 result 哈?
let result: boolean
if (isDelegate.value) {
// 委派
result = await delegateTask({
...data,
delegateUserId: String(formData.userId),
})
} else {
// 转办
result = await transferTask({
...data,
assigneeUserId: String(formData.userId),
})
}
if (result) {
toast.success(`${isDelegate.value ? '委派' : '转办'}成功`)
setTimeout(() => {
uni.redirectTo({
url: `/pages-bpm/processInstance/detail/index?id=${processInstanceId.value}&taskId=${taskId.value}`,
})
}, 1500)
}, 500)
}
} catch (error) {
// TODO @jason可以不用这里的 catch 哈?
console.error(`[reassign] ${isDelegate.value ? '委派' : '转办'}失败:`, error)
toast.error(`${isDelegate.value ? '委派' : '转办'}失败`)
} finally {

View File

@@ -74,14 +74,11 @@ 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: '退回节点不能为空' },
@@ -90,6 +87,7 @@ const formRules = {
{ required: true, message: '退回原因不能为空' },
],
}
const formRef = ref<FormInstance>()
/** 返回上一页 */
function handleBack() {
@@ -97,6 +95,7 @@ function handleBack() {
}
/** 初始化校验 */
// TODO @jason最好放在 onMounted 里?或者其他地方,有个入口方法。
if (!props.taskId || !props.processInstanceId) {
toast.show('参数错误')
}
@@ -105,10 +104,12 @@ if (!props.taskId || !props.processInstanceId) {
async function loadReturnTaskList() {
try {
const result = await getTaskListByReturn(taskId.value)
// TODO @jason这个判断可以考虑去掉哈。
if (result && Array.isArray(result)) {
activityOptions.value = result
}
} catch (error) {
// TODO @jason错误处理这里可以去掉哈。
console.error('[return] 获取可退回节点失败:', error)
toast.error('获取可退回节点失败')
}
@@ -116,32 +117,33 @@ async function loadReturnTaskList() {
/** 提交操作 */
async function handleSubmit() {
if (submitting.value)
if (submitting.value) {
return
// 使用 wd-form 的校验方法
}
const { valid } = await formRef.value!.validate()
if (!valid) {
return
}
// TODO @jasonsubmitting 改成 formLoading 哇?统一代码风格哈;
submitting.value = true
try {
// TODO @jason这里是不是不用判断 result 哈?
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)
}, 500)
}
} catch (error) {
// TODO @jason可以不用这里的 catch 哈?
console.error('[return] 退回失败:', error)
toast.error('退回失败')
} finally {

View File

@@ -63,7 +63,7 @@ export const useUserStore = defineStore(
/** 获取用户信息 */
const fetchUserInfo = async () => {
const res = await getAuthPermissionInfo()
// 后端返回的用户 Id 字段为 id.
// 兼容:后端返回的用户 id 字段为 id
res.user.userId = res.user.id
setUserInfo(res)
return res