diff --git a/apps/web-antd/src/api/bpm/processInstance/index.ts b/apps/web-antd/src/api/bpm/processInstance/index.ts index 7ee5421f8..f8442c35c 100644 --- a/apps/web-antd/src/api/bpm/processInstance/index.ts +++ b/apps/web-antd/src/api/bpm/processInstance/index.ts @@ -83,6 +83,7 @@ export namespace BpmProcessInstanceApi { reason: string; signPicUrl: string; status: number; + attachments?: string[]; } /** 抄送流程实例 */ diff --git a/apps/web-antd/src/components/upload/file-upload.vue b/apps/web-antd/src/components/upload/file-upload.vue index 85afc3b9d..8f78d2f24 100644 --- a/apps/web-antd/src/components/upload/file-upload.vue +++ b/apps/web-antd/src/components/upload/file-upload.vue @@ -34,6 +34,7 @@ const props = withDefaults(defineProps(), { resultField: '', returnText: false, showDescription: false, + showDownloadIcon: true, }); const emit = defineEmits([ 'change', @@ -295,7 +296,7 @@ function getValue() { :show-upload-list="{ showPreviewIcon: true, showRemoveIcon: true, - showDownloadIcon: true, + showDownloadIcon, }" @remove="handleRemove" @preview="handlePreview" @@ -361,3 +362,10 @@ function getValue() { color: #999; } + + diff --git a/apps/web-antd/src/components/upload/typing.ts b/apps/web-antd/src/components/upload/typing.ts index 990aa7d8a..7a9475f73 100644 --- a/apps/web-antd/src/components/upload/typing.ts +++ b/apps/web-antd/src/components/upload/typing.ts @@ -29,5 +29,6 @@ export interface FileUploadProps { resultField?: string; // support xxx.xxx.xx returnText?: boolean; // 是否返回文件文本内容 showDescription?: boolean; // 是否显示下面的描述 + showDownloadIcon?: boolean; // 是否显示下载按钮 value?: string | string[]; } diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue b/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue index ed0d81325..e10a87ba6 100644 --- a/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue +++ b/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue @@ -56,6 +56,7 @@ import { transferTask, } from '#/api/bpm/task'; import { setConfAndFields2 } from '#/components/form-create'; +import { FileUpload } from '#/components/upload'; import { $t } from '#/locales'; import Signature from './signature.vue'; @@ -120,6 +121,7 @@ const approveReasonForm: any = reactive({ reason: '', signPicUrl: '', nextAssignees: {}, + attachments: [], }); const approveReasonRule: Record = computed(() => { return { @@ -142,6 +144,7 @@ const approveReasonRule: Record = computed(() => { const rejectFormRef = ref(); const rejectReasonForm = reactive({ reason: '', + attachments: [], }); // 拒绝表单 const rejectReasonRule: any = computed(() => { return { @@ -290,6 +293,14 @@ function closePopover(type: string, formRef: any | FormInstance) { if (formRef) { formRef.resetFields(); } + if (type === 'approve') { + approveReasonForm.reason = ''; + approveReasonForm.attachments = []; + approveReasonForm.signPicUrl = ''; + } else if (type === 'reject') { + rejectReasonForm.reason = ''; + rejectReasonForm.attachments = []; + } if (popOverVisible.value[type]) popOverVisible.value[type] = false; nextAssigneesActivityNode.value = []; // 清理 Timeline 组件中的自定义审批人数据 @@ -401,6 +412,7 @@ async function handleAudit(pass: boolean, formRef: FormInstance | undefined) { const data = { id: runningTask.value.id, reason: approveReasonForm.reason, + attachments: approveReasonForm.attachments, variables, // 审批通过, 把修改的字段值赋于流程实例变量 nextAssignees: approveReasonForm.nextAssignees, // 下个自选节点选择的审批人信息 } as any; @@ -414,6 +426,9 @@ async function handleAudit(pass: boolean, formRef: FormInstance | undefined) { await formCreateApi.validate(); } await approveTask(data); + approveReasonForm.reason = ''; + approveReasonForm.attachments = []; + approveReasonForm.signPicUrl = ''; popOverVisible.value.approve = false; nextAssigneesActivityNode.value = []; // 清理 Timeline 组件中的自定义审批人数据 @@ -426,8 +441,11 @@ async function handleAudit(pass: boolean, formRef: FormInstance | undefined) { const data = { id: runningTask.value.id, reason: rejectReasonForm.reason, + attachments: rejectReasonForm.attachments, }; await rejectTask(data); + rejectReasonForm.reason = ''; + rejectReasonForm.attachments = []; popOverVisible.value.reject = false; message.success('审批不通过成功'); } @@ -748,6 +766,34 @@ function handleSignFinish(url: string) { approveFormRef.value?.validateFields(['signPicUrl']); } +/** 附件图片预览 */ +const imagePreviewVisible = ref(false); +const imagePreviewUrl = ref(''); + +/** 判断文件是否为图片类型 */ +function isImageUrl(url: string) { + return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(url); +} + +/** 处理文件预览 */ +function handleFilePreview(file: any) { + if (!file?.url && !file?.response) { + message.warning('文件地址不存在,无法预览'); + return; + } + const url = file.url || file?.response?.url || file?.response; + if (!url) { + message.warning('文件地址不存在,无法预览'); + return; + } + if (isImageUrl(url)) { + imagePreviewUrl.value = url; + imagePreviewVisible.value = true; + } else { + window.open(url, '_blank'); + } +} + /** 处理弹窗可见性 */ function handlePopoverVisible(visible: boolean) { if (!visible) { @@ -843,6 +889,16 @@ defineExpose({ loadTodoTask }); :rows="4" /> + + +