文件上传
This commit is contained in:
parent
20e4ba931e
commit
4f8a4f87f7
@ -1,215 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="upload-file">
|
|
||||||
<el-upload
|
|
||||||
ref="uploadRef"
|
|
||||||
v-model:file-list="fileList"
|
|
||||||
:action="uploadUrl"
|
|
||||||
:auto-upload="autoUpload"
|
|
||||||
:before-upload="beforeUpload"
|
|
||||||
:disabled="disabled"
|
|
||||||
:drag="drag"
|
|
||||||
:http-request="httpRequest"
|
|
||||||
:limit="props.limit"
|
|
||||||
:multiple="props.limit > 1"
|
|
||||||
:on-error="excelUploadError"
|
|
||||||
:on-exceed="handleExceed"
|
|
||||||
:on-preview="handlePreview"
|
|
||||||
:on-remove="handleRemove"
|
|
||||||
:on-success="handleFileSuccess"
|
|
||||||
:show-file-list="true"
|
|
||||||
class="upload-file-uploader"
|
|
||||||
name="file"
|
|
||||||
>
|
|
||||||
<el-button v-if="!disabled" type="primary">
|
|
||||||
<Icon icon="ep:upload-filled" />
|
|
||||||
选取文件
|
|
||||||
</el-button>
|
|
||||||
<template v-if="isShowTip && !disabled" #tip>
|
|
||||||
<div style="font-size: 8px">
|
|
||||||
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
|
|
||||||
</div>
|
|
||||||
<div style="font-size: 8px">
|
|
||||||
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b> 的文件
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #file="row">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<span>{{ row.file.name }}</span>
|
|
||||||
<div class="ml-10px">
|
|
||||||
<el-link
|
|
||||||
:href="row.file.url"
|
|
||||||
:underline="false"
|
|
||||||
download
|
|
||||||
target="_blank"
|
|
||||||
type="primary"
|
|
||||||
>
|
|
||||||
下载
|
|
||||||
</el-link>
|
|
||||||
</div>
|
|
||||||
<div class="ml-10px">
|
|
||||||
<el-button link type="danger" @click="handleRemove(row.file)"> 删除</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-upload>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { propTypes } from '@/utils/propTypes'
|
|
||||||
import type { UploadInstance, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus'
|
|
||||||
import { isString } from '@/utils/is'
|
|
||||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
|
||||||
import { UploadFile } from 'element-plus/es/components/upload/src/upload'
|
|
||||||
|
|
||||||
defineOptions({ name: 'UploadFile' })
|
|
||||||
|
|
||||||
const message = useMessage() // 消息弹窗
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
|
|
||||||
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // 文件类型, 例如['png', 'jpg', 'jpeg']
|
|
||||||
fileSize: propTypes.number.def(5), // 大小限制(MB)
|
|
||||||
limit: propTypes.number.def(5), // 数量限制
|
|
||||||
autoUpload: propTypes.bool.def(true), // 自动上传
|
|
||||||
drag: propTypes.bool.def(false), // 拖拽上传
|
|
||||||
isShowTip: propTypes.bool.def(true), // 是否显示提示
|
|
||||||
disabled: propTypes.bool.def(false) // 是否禁用上传组件 ==> 非必传(默认为 false)
|
|
||||||
})
|
|
||||||
|
|
||||||
// ========== 上传相关 ==========
|
|
||||||
const uploadRef = ref<UploadInstance>()
|
|
||||||
const uploadList = ref<UploadUserFile[]>([])
|
|
||||||
const fileList = ref<UploadUserFile[]>([])
|
|
||||||
const uploadNumber = ref<number>(0)
|
|
||||||
|
|
||||||
const { uploadUrl, httpRequest } = useUpload()
|
|
||||||
|
|
||||||
// 文件上传之前判断
|
|
||||||
const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => {
|
|
||||||
if (fileList.value.length >= props.limit) {
|
|
||||||
message.error(`上传文件数量不能超过${props.limit}个!`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let fileExtension = ''
|
|
||||||
if (file.name.lastIndexOf('.') > -1) {
|
|
||||||
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
|
|
||||||
}
|
|
||||||
const isImg = props.fileType.some((type: string) => {
|
|
||||||
if (file.type.indexOf(type) > -1) return true
|
|
||||||
return !!(fileExtension && fileExtension.indexOf(type) > -1)
|
|
||||||
})
|
|
||||||
const isLimit = file.size < props.fileSize * 1024 * 1024
|
|
||||||
if (!isImg) {
|
|
||||||
message.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式!`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!isLimit) {
|
|
||||||
message.error(`上传文件大小不能超过${props.fileSize}MB!`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
message.success('正在上传文件,请稍候...')
|
|
||||||
uploadNumber.value++
|
|
||||||
}
|
|
||||||
// 处理上传的文件发生变化
|
|
||||||
// const handleFileChange = (uploadFile: UploadFile): void => {
|
|
||||||
// uploadRef.value.data.path = uploadFile.name
|
|
||||||
// }
|
|
||||||
// 文件上传成功
|
|
||||||
const handleFileSuccess: UploadProps['onSuccess'] = (res: any): void => {
|
|
||||||
message.success('上传成功')
|
|
||||||
|
|
||||||
// 删除自身
|
|
||||||
const index = fileList.value.findIndex((item) => item.response?.data === res.data)
|
|
||||||
fileList.value.splice(index, 1)
|
|
||||||
uploadList.value.push({ name: res.data, url: res.data })
|
|
||||||
if (uploadList.value.length == uploadNumber.value) {
|
|
||||||
fileList.value.push(...uploadList.value)
|
|
||||||
uploadList.value = []
|
|
||||||
uploadNumber.value = 0
|
|
||||||
emitUpdateModelValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 文件数超出提示
|
|
||||||
const handleExceed: UploadProps['onExceed'] = (): void => {
|
|
||||||
message.error(`上传文件数量不能超过${props.limit}个!`)
|
|
||||||
}
|
|
||||||
// 上传错误提示
|
|
||||||
const excelUploadError: UploadProps['onError'] = (): void => {
|
|
||||||
message.error('导入数据失败,请您重新上传!')
|
|
||||||
}
|
|
||||||
// 删除上传文件
|
|
||||||
const handleRemove = (file: UploadFile) => {
|
|
||||||
const index = fileList.value.map((f) => f.name).indexOf(file.name)
|
|
||||||
if (index > -1) {
|
|
||||||
fileList.value.splice(index, 1)
|
|
||||||
emitUpdateModelValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
|
|
||||||
console.log(uploadFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听模型绑定值变动
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(val: string | string[]) => {
|
|
||||||
if (!val) {
|
|
||||||
fileList.value = [] // fix:处理掉缓存,表单重置后上传组件的内容并没有重置
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fileList.value = [] // 保障数据为空
|
|
||||||
// 情况1:字符串
|
|
||||||
if (isString(val)) {
|
|
||||||
fileList.value.push(
|
|
||||||
...val.split(',').map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 情况2:数组
|
|
||||||
fileList.value.push(
|
|
||||||
...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{ immediate: true, deep: true }
|
|
||||||
)
|
|
||||||
// 发送文件链接列表更新
|
|
||||||
const emitUpdateModelValue = () => {
|
|
||||||
// 情况1:数组结果
|
|
||||||
let result: string | string[] = fileList.value.map((file) => file.url!)
|
|
||||||
// 情况2:逗号分隔的字符串
|
|
||||||
if (props.limit === 1 || isString(props.modelValue)) {
|
|
||||||
result = result.join(',')
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('update:modelValue', result)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.upload-file-uploader {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.upload-file-list .el-upload-list__item) {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
line-height: 2;
|
|
||||||
border: 1px solid #e4e7ed;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-upload-list__item-file-name) {
|
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.upload-file-list .ele-upload-list__item-content) {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ele-upload-list__item-content-action .el-link) {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,97 +0,0 @@
|
|||||||
import * as FileApi from '@/api/infra/file'
|
|
||||||
import CryptoJS from 'crypto-js'
|
|
||||||
import { UploadRawFile, UploadRequestOptions } from 'element-plus/es/components/upload/src/upload'
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
export const useUpload = () => {
|
|
||||||
// 后端上传地址
|
|
||||||
const uploadUrl = import.meta.env.VITE_UPLOAD_URL
|
|
||||||
// 是否使用前端直连上传
|
|
||||||
const isClientUpload = UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE
|
|
||||||
// 重写ElUpload上传方法
|
|
||||||
const httpRequest = async (options: UploadRequestOptions) => {
|
|
||||||
// 模式一:前端上传
|
|
||||||
if (isClientUpload) {
|
|
||||||
// 1.1 生成文件名称
|
|
||||||
const fileName = await generateFileName(options.file)
|
|
||||||
// 1.2 获取文件预签名地址
|
|
||||||
const presignedInfo = await FileApi.getFilePresignedUrl(fileName)
|
|
||||||
// 1.3 上传文件(不能使用 ElUpload 的 ajaxUpload 方法的原因:其使用的是 FormData 上传,Minio 不支持)
|
|
||||||
return axios.put(presignedInfo.uploadUrl, options.file, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': options.file.type,
|
|
||||||
}
|
|
||||||
}).then(() => {
|
|
||||||
// 1.4. 记录文件信息到后端(异步)
|
|
||||||
createFile(presignedInfo, fileName, options.file)
|
|
||||||
// 通知成功,数据格式保持与后端上传的返回结果一致
|
|
||||||
return { data: presignedInfo.url }
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// 模式二:后端上传
|
|
||||||
// 重写 el-upload httpRequest 文件上传成功会走成功的钩子,失败走失败的钩子
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
FileApi.updateFile({ file: options.file })
|
|
||||||
.then((res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
resolve(res)
|
|
||||||
} else {
|
|
||||||
reject(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((res) => {
|
|
||||||
reject(res)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
uploadUrl,
|
|
||||||
httpRequest
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建文件信息
|
|
||||||
* @param vo 文件预签名信息
|
|
||||||
* @param name 文件名称
|
|
||||||
* @param file 文件
|
|
||||||
*/
|
|
||||||
function createFile(vo: FileApi.FilePresignedUrlRespVO, name: string, file: UploadRawFile) {
|
|
||||||
const fileVo = {
|
|
||||||
configId: vo.configId,
|
|
||||||
url: vo.url,
|
|
||||||
path: name,
|
|
||||||
name: file.name,
|
|
||||||
type: file.type,
|
|
||||||
size: file.size
|
|
||||||
}
|
|
||||||
FileApi.createFile(fileVo)
|
|
||||||
return fileVo
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成文件名称(使用算法SHA256)
|
|
||||||
* @param file 要上传的文件
|
|
||||||
*/
|
|
||||||
async function generateFileName(file: UploadRawFile) {
|
|
||||||
// 读取文件内容
|
|
||||||
const data = await file.arrayBuffer()
|
|
||||||
const wordArray = CryptoJS.lib.WordArray.create(data)
|
|
||||||
// 计算SHA256
|
|
||||||
const sha256 = CryptoJS.SHA256(wordArray).toString()
|
|
||||||
// 拼接后缀
|
|
||||||
const ext = file.name.substring(file.name.lastIndexOf('.'))
|
|
||||||
return `${sha256}${ext}`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传类型
|
|
||||||
*/
|
|
||||||
enum UPLOAD_TYPE {
|
|
||||||
// 客户端直接上传(只支持S3服务)
|
|
||||||
CLIENT = 'client',
|
|
||||||
// 客户端发送到后端上传
|
|
||||||
SERVER = 'server'
|
|
||||||
}
|
|
@ -1,272 +0,0 @@
|
|||||||
<template>
|
|
||||||
<doc-alert title="流程发起、取消、重新发起" url="https://doc.iocoder.cn/bpm/process-instance/" />
|
|
||||||
|
|
||||||
<!-- 第一步,通过流程定义的列表,选择对应的流程 -->
|
|
||||||
<ContentWrap v-if="!selectProcessDefinition" v-loading="loading">
|
|
||||||
<el-tabs tab-position="left" v-model="categoryActive">
|
|
||||||
<el-tab-pane
|
|
||||||
:label="category.name"
|
|
||||||
:name="category.code"
|
|
||||||
:key="category.code"
|
|
||||||
v-for="category in categoryList"
|
|
||||||
>
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col
|
|
||||||
:lg="6"
|
|
||||||
:sm="12"
|
|
||||||
:xs="24"
|
|
||||||
v-for="definition in categoryProcessDefinitionList"
|
|
||||||
:key="definition.id"
|
|
||||||
>
|
|
||||||
<el-card
|
|
||||||
shadow="hover"
|
|
||||||
class="mb-20px cursor-pointer"
|
|
||||||
@click="handleSelect(definition)"
|
|
||||||
>
|
|
||||||
<template #default>
|
|
||||||
<div class="flex">
|
|
||||||
<el-image :src="definition.icon" class="w-32px h-32px" />
|
|
||||||
<el-text class="!ml-10px" size="large">{{ definition.name }}</el-text>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</ContentWrap>
|
|
||||||
|
|
||||||
<!-- 第二步,填写表单,进行流程的提交 -->
|
|
||||||
<ContentWrap v-else>
|
|
||||||
<el-tabs @tab-click="handleClick" type="card" style="margin-bottom: 20px">
|
|
||||||
<el-tab-pane label="申请信息">
|
|
||||||
<el-card class="box-card">
|
|
||||||
<div class="clearfix">
|
|
||||||
<span class="el-icon-document">申请信息【{{ selectProcessDefinition.name }}】</span>
|
|
||||||
<el-button style="float: right" type="primary" @click="selectProcessDefinition = undefined">
|
|
||||||
<Icon icon="ep:delete" /> 选择其它流程
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
<el-col :span="16" :offset="6" style="margin-top: 20px">
|
|
||||||
<form-create
|
|
||||||
:rule="detailForm.rule"
|
|
||||||
v-model:api="fApi"
|
|
||||||
v-model="detailForm.value"
|
|
||||||
:option="detailForm.option"
|
|
||||||
@submit="submitForm"
|
|
||||||
>
|
|
||||||
<template #type-startUserSelect>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-card class="mb-10px">
|
|
||||||
<template #header>指定审批人</template>
|
|
||||||
<el-form
|
|
||||||
:model="startUserSelectAssignees"
|
|
||||||
:rules="startUserSelectAssigneesFormRules"
|
|
||||||
ref="startUserSelectAssigneesFormRef"
|
|
||||||
>
|
|
||||||
<el-form-item
|
|
||||||
v-for="userTask in startUserSelectTasks"
|
|
||||||
:key="userTask.id"
|
|
||||||
:label="`任务【${userTask.name}】`"
|
|
||||||
:prop="userTask.id"
|
|
||||||
>
|
|
||||||
<el-select
|
|
||||||
v-model="startUserSelectAssignees[userTask.id]"
|
|
||||||
multiple
|
|
||||||
placeholder="请选择审批人"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="user in userList"
|
|
||||||
:key="user.id"
|
|
||||||
:label="user.nickname"
|
|
||||||
:value="user.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</template>
|
|
||||||
</form-create>
|
|
||||||
</el-col>
|
|
||||||
</el-card>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane :lazy="true" label="流程图" name="flowChart">
|
|
||||||
<!-- 流程图预览 -->
|
|
||||||
<ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML as any" />
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
|
|
||||||
</ContentWrap>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import * as DefinitionApi from '@/api/bpm/definition'
|
|
||||||
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
|
|
||||||
import { setConfAndFields2 } from '@/utils/formCreate'
|
|
||||||
import type { ApiAttrs } from '@form-create/element-ui/types/config'
|
|
||||||
import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue'
|
|
||||||
import { CategoryApi } from '@/api/bpm/category'
|
|
||||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
|
||||||
import * as UserApi from '@/api/system/user'
|
|
||||||
import {TabsPaneContext} from "element-plus";
|
|
||||||
|
|
||||||
defineOptions({ name: 'BpmProcessInstanceCreate' })
|
|
||||||
|
|
||||||
const route = useRoute() // 路由
|
|
||||||
const { push, currentRoute } = useRouter() // 路由
|
|
||||||
const message = useMessage() // 消息
|
|
||||||
const { delView } = useTagsViewStore() // 视图操作
|
|
||||||
|
|
||||||
const processInstanceId = route.query.processInstanceId
|
|
||||||
const loading = ref(true) // 加载中
|
|
||||||
const categoryList = ref([]) // 分类的列表
|
|
||||||
const categoryActive = ref('') // 选中的分类
|
|
||||||
const processDefinitionList = ref([]) // 流程定义的列表
|
|
||||||
|
|
||||||
/** 查询列表 */
|
|
||||||
const getList = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
// 流程分类
|
|
||||||
categoryList.value = await CategoryApi.getCategorySimpleList()
|
|
||||||
if (categoryList.value.length > 0) {
|
|
||||||
categoryActive.value = categoryList.value[0].code
|
|
||||||
}
|
|
||||||
// 流程定义
|
|
||||||
processDefinitionList.value = await DefinitionApi.getProcessDefinitionList({
|
|
||||||
suspensionState: 1
|
|
||||||
})
|
|
||||||
|
|
||||||
// 如果 processInstanceId 非空,说明是重新发起
|
|
||||||
if (processInstanceId?.length > 0) {
|
|
||||||
const processInstance = await ProcessInstanceApi.getProcessInstance(processInstanceId)
|
|
||||||
if (!processInstance) {
|
|
||||||
message.error('重新发起流程失败,原因:流程实例不存在')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const processDefinition = processDefinitionList.value.find(
|
|
||||||
(item) => item.key == processInstance.processDefinition?.key
|
|
||||||
)
|
|
||||||
if (!processDefinition) {
|
|
||||||
message.error('重新发起流程失败,原因:流程定义不存在')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await handleSelect(processDefinition, processInstance.formVariables)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 选中分类对应的流程定义列表 */
|
|
||||||
const categoryProcessDefinitionList = computed(() => {
|
|
||||||
return processDefinitionList.value.filter((item) => item.category == categoryActive.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
// ========== 表单相关 ==========
|
|
||||||
const fApi = ref<ApiAttrs>()
|
|
||||||
const detailForm = ref({
|
|
||||||
rule: [],
|
|
||||||
option: {},
|
|
||||||
value: {}
|
|
||||||
}) // 流程表单详情
|
|
||||||
const selectProcessDefinition = ref() // 选择的流程定义
|
|
||||||
|
|
||||||
// 指定审批人
|
|
||||||
const bpmnXML = ref(null) // BPMN 数据
|
|
||||||
const startUserSelectTasks = ref([]) // 发起人需要选择审批人的用户任务列表
|
|
||||||
const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据
|
|
||||||
const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表单 Ref
|
|
||||||
const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules
|
|
||||||
const userList = ref<any[]>([]) // 用户列表
|
|
||||||
|
|
||||||
|
|
||||||
const handleClick = (tab: TabsPaneContext) => {
|
|
||||||
if (tab.props.name==="flowChart"){
|
|
||||||
getProcessInstance()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理选择流程的按钮操作 **/
|
|
||||||
const handleSelect = async (row, formVariables) => {
|
|
||||||
// 设置选择的流程
|
|
||||||
selectProcessDefinition.value = row
|
|
||||||
|
|
||||||
// 重置指定审批人
|
|
||||||
startUserSelectTasks.value = []
|
|
||||||
startUserSelectAssignees.value = {}
|
|
||||||
startUserSelectAssigneesFormRules.value = {}
|
|
||||||
|
|
||||||
// 情况一:流程表单
|
|
||||||
if (row.formType == 10) {
|
|
||||||
// 设置表单
|
|
||||||
setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables)
|
|
||||||
// 加载流程图
|
|
||||||
const processDefinitionDetail = await DefinitionApi.getProcessDefinition(row.id)
|
|
||||||
if (processDefinitionDetail) {
|
|
||||||
bpmnXML.value = processDefinitionDetail.bpmnXml
|
|
||||||
startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks
|
|
||||||
|
|
||||||
// 设置指定审批人
|
|
||||||
if (startUserSelectTasks.value?.length > 0) {
|
|
||||||
detailForm.value.rule.push({
|
|
||||||
type: 'startUserSelect',
|
|
||||||
props: {
|
|
||||||
title: '指定审批人'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 设置校验规则
|
|
||||||
for (const userTask of startUserSelectTasks.value) {
|
|
||||||
startUserSelectAssignees.value[userTask.id] = []
|
|
||||||
startUserSelectAssigneesFormRules.value[userTask.id] = [
|
|
||||||
{ required: true, message: '请选择审批人', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
// 加载用户列表
|
|
||||||
userList.value = await UserApi.getSimpleUserList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 情况二:业务表单
|
|
||||||
} else if (row.formCustomCreatePath) {
|
|
||||||
await push({
|
|
||||||
path: row.formCustomCreatePath
|
|
||||||
})
|
|
||||||
// 这里暂时无需加载流程图,因为跳出到另外个 Tab;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 提交按钮 */
|
|
||||||
const submitForm = async (formData) => {
|
|
||||||
if (!fApi.value || !selectProcessDefinition.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 如果有指定审批人,需要校验
|
|
||||||
if (startUserSelectTasks.value?.length > 0) {
|
|
||||||
await startUserSelectAssigneesFormRef.value.validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交请求
|
|
||||||
fApi.value.btn.loading(true)
|
|
||||||
try {
|
|
||||||
await ProcessInstanceApi.createProcessInstance({
|
|
||||||
processDefinitionId: selectProcessDefinition.value.id,
|
|
||||||
variables: formData,
|
|
||||||
startUserSelectAssignees: startUserSelectAssignees.value
|
|
||||||
})
|
|
||||||
// 提示
|
|
||||||
message.success('发起流程成功')
|
|
||||||
// 跳转回去
|
|
||||||
delView(unref(currentRoute))
|
|
||||||
await push({
|
|
||||||
name: 'BpmProcessInstanceMy'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
fApi.value.btn.loading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 初始化 */
|
|
||||||
onMounted(() => {
|
|
||||||
getList()
|
|
||||||
})
|
|
||||||
</script>
|
|
@ -1,257 +0,0 @@
|
|||||||
<template>
|
|
||||||
<doc-alert title="流程发起、取消、重新发起" url="https://doc.iocoder.cn/bpm/process-instance/" />
|
|
||||||
|
|
||||||
<!-- 第一步,通过流程定义的列表,选择对应的流程 -->
|
|
||||||
<ContentWrap v-if="!selectProcessDefinition" v-loading="loading">
|
|
||||||
<el-tabs tab-position="left" v-model="categoryActive">
|
|
||||||
<el-tab-pane
|
|
||||||
:label="category.name"
|
|
||||||
:name="category.code"
|
|
||||||
:key="category.code"
|
|
||||||
v-for="category in categoryList"
|
|
||||||
>
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col
|
|
||||||
:lg="6"
|
|
||||||
:sm="12"
|
|
||||||
:xs="24"
|
|
||||||
v-for="definition in categoryProcessDefinitionList"
|
|
||||||
:key="definition.id"
|
|
||||||
>
|
|
||||||
<el-card
|
|
||||||
shadow="hover"
|
|
||||||
class="mb-20px cursor-pointer"
|
|
||||||
@click="handleSelect(definition)"
|
|
||||||
>
|
|
||||||
<template #default>
|
|
||||||
<div class="flex">
|
|
||||||
<el-image :src="definition.icon" class="w-32px h-32px" />
|
|
||||||
<el-text class="!ml-10px" size="large">{{ definition.name }}</el-text>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</ContentWrap>
|
|
||||||
|
|
||||||
<!-- 第二步,填写表单,进行流程的提交 -->
|
|
||||||
<ContentWrap v-else>
|
|
||||||
<el-card class="box-card">
|
|
||||||
<div class="clearfix">
|
|
||||||
<span class="el-icon-document">申请信息【{{ selectProcessDefinition.name }}】</span>
|
|
||||||
<el-button style="float: right" type="primary" @click="selectProcessDefinition = undefined">
|
|
||||||
<Icon icon="ep:delete" /> 选择其它流程
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
<el-col :span="16" :offset="6" style="margin-top: 20px">
|
|
||||||
<form-create
|
|
||||||
:rule="detailForm.rule"
|
|
||||||
v-model:api="fApi"
|
|
||||||
v-model="detailForm.value"
|
|
||||||
:option="detailForm.option"
|
|
||||||
@submit="submitForm"
|
|
||||||
>
|
|
||||||
<template #type-startUserSelect>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-card class="mb-10px">
|
|
||||||
<template #header>指定审批人</template>
|
|
||||||
<el-form
|
|
||||||
:model="startUserSelectAssignees"
|
|
||||||
:rules="startUserSelectAssigneesFormRules"
|
|
||||||
ref="startUserSelectAssigneesFormRef"
|
|
||||||
>
|
|
||||||
<el-form-item
|
|
||||||
v-for="userTask in startUserSelectTasks"
|
|
||||||
:key="userTask.id"
|
|
||||||
:label="`任务【${userTask.name}】`"
|
|
||||||
:prop="userTask.id"
|
|
||||||
>
|
|
||||||
<el-select
|
|
||||||
v-model="startUserSelectAssignees[userTask.id]"
|
|
||||||
multiple
|
|
||||||
placeholder="请选择审批人"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="user in userList"
|
|
||||||
:key="user.id"
|
|
||||||
:label="user.nickname"
|
|
||||||
:value="user.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</template>
|
|
||||||
</form-create>
|
|
||||||
</el-col>
|
|
||||||
</el-card>
|
|
||||||
<!-- 流程图预览 -->
|
|
||||||
<ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML as any" />
|
|
||||||
</ContentWrap>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import * as DefinitionApi from '@/api/bpm/definition'
|
|
||||||
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
|
|
||||||
import { setConfAndFields2 } from '@/utils/formCreate'
|
|
||||||
import type { ApiAttrs } from '@form-create/element-ui/types/config'
|
|
||||||
import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue'
|
|
||||||
import { CategoryApi } from '@/api/bpm/category'
|
|
||||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
|
||||||
import * as UserApi from '@/api/system/user'
|
|
||||||
|
|
||||||
defineOptions({ name: 'BpmProcessInstanceCreate' })
|
|
||||||
|
|
||||||
const route = useRoute() // 路由
|
|
||||||
const { push, currentRoute } = useRouter() // 路由
|
|
||||||
const message = useMessage() // 消息
|
|
||||||
const { delView } = useTagsViewStore() // 视图操作
|
|
||||||
|
|
||||||
const processInstanceId = route.query.processInstanceId
|
|
||||||
const loading = ref(true) // 加载中
|
|
||||||
const categoryList = ref([]) // 分类的列表
|
|
||||||
const categoryActive = ref('') // 选中的分类
|
|
||||||
const processDefinitionList = ref([]) // 流程定义的列表
|
|
||||||
|
|
||||||
/** 查询列表 */
|
|
||||||
const getList = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
// 流程分类
|
|
||||||
categoryList.value = await CategoryApi.getCategorySimpleList()
|
|
||||||
if (categoryList.value.length > 0) {
|
|
||||||
categoryActive.value = categoryList.value[0].code
|
|
||||||
}
|
|
||||||
// 流程定义
|
|
||||||
processDefinitionList.value = await DefinitionApi.getProcessDefinitionList({
|
|
||||||
suspensionState: 1
|
|
||||||
})
|
|
||||||
|
|
||||||
// 如果 processInstanceId 非空,说明是重新发起
|
|
||||||
if (processInstanceId?.length > 0) {
|
|
||||||
const processInstance = await ProcessInstanceApi.getProcessInstance(processInstanceId)
|
|
||||||
if (!processInstance) {
|
|
||||||
message.error('重新发起流程失败,原因:流程实例不存在')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const processDefinition = processDefinitionList.value.find(
|
|
||||||
(item) => item.key == processInstance.processDefinition?.key
|
|
||||||
)
|
|
||||||
if (!processDefinition) {
|
|
||||||
message.error('重新发起流程失败,原因:流程定义不存在')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await handleSelect(processDefinition, processInstance.formVariables)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 选中分类对应的流程定义列表 */
|
|
||||||
const categoryProcessDefinitionList = computed(() => {
|
|
||||||
return processDefinitionList.value.filter((item) => item.category == categoryActive.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
// ========== 表单相关 ==========
|
|
||||||
const fApi = ref<ApiAttrs>()
|
|
||||||
const detailForm = ref({
|
|
||||||
rule: [],
|
|
||||||
option: {},
|
|
||||||
value: {}
|
|
||||||
}) // 流程表单详情
|
|
||||||
const selectProcessDefinition = ref() // 选择的流程定义
|
|
||||||
|
|
||||||
// 指定审批人
|
|
||||||
const bpmnXML = ref(null) // BPMN 数据
|
|
||||||
const startUserSelectTasks = ref([]) // 发起人需要选择审批人的用户任务列表
|
|
||||||
const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据
|
|
||||||
const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表单 Ref
|
|
||||||
const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules
|
|
||||||
const userList = ref<any[]>([]) // 用户列表
|
|
||||||
|
|
||||||
/** 处理选择流程的按钮操作 **/
|
|
||||||
const handleSelect = async (row, formVariables) => {
|
|
||||||
// 设置选择的流程
|
|
||||||
selectProcessDefinition.value = row
|
|
||||||
|
|
||||||
// 重置指定审批人
|
|
||||||
startUserSelectTasks.value = []
|
|
||||||
startUserSelectAssignees.value = {}
|
|
||||||
startUserSelectAssigneesFormRules.value = {}
|
|
||||||
|
|
||||||
// 情况一:流程表单
|
|
||||||
if (row.formType == 10) {
|
|
||||||
// 设置表单
|
|
||||||
setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables)
|
|
||||||
// 加载流程图
|
|
||||||
const processDefinitionDetail = await DefinitionApi.getProcessDefinition(row.id)
|
|
||||||
if (processDefinitionDetail) {
|
|
||||||
bpmnXML.value = processDefinitionDetail.bpmnXml
|
|
||||||
startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks
|
|
||||||
|
|
||||||
// 设置指定审批人
|
|
||||||
if (startUserSelectTasks.value?.length > 0) {
|
|
||||||
detailForm.value.rule.push({
|
|
||||||
type: 'startUserSelect',
|
|
||||||
props: {
|
|
||||||
title: '指定审批人'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 设置校验规则
|
|
||||||
for (const userTask of startUserSelectTasks.value) {
|
|
||||||
startUserSelectAssignees.value[userTask.id] = []
|
|
||||||
startUserSelectAssigneesFormRules.value[userTask.id] = [
|
|
||||||
{ required: true, message: '请选择审批人', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
// 加载用户列表
|
|
||||||
userList.value = await UserApi.getSimpleUserList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 情况二:业务表单
|
|
||||||
} else if (row.formCustomCreatePath) {
|
|
||||||
await push({
|
|
||||||
path: row.formCustomCreatePath
|
|
||||||
})
|
|
||||||
// 这里暂时无需加载流程图,因为跳出到另外个 Tab;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 提交按钮 */
|
|
||||||
const submitForm = async (formData) => {
|
|
||||||
if (!fApi.value || !selectProcessDefinition.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 如果有指定审批人,需要校验
|
|
||||||
if (startUserSelectTasks.value?.length > 0) {
|
|
||||||
await startUserSelectAssigneesFormRef.value.validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交请求
|
|
||||||
fApi.value.btn.loading(true)
|
|
||||||
try {
|
|
||||||
await ProcessInstanceApi.createProcessInstance({
|
|
||||||
processDefinitionId: selectProcessDefinition.value.id,
|
|
||||||
variables: formData,
|
|
||||||
startUserSelectAssignees: startUserSelectAssignees.value
|
|
||||||
})
|
|
||||||
// 提示
|
|
||||||
message.success('发起流程成功')
|
|
||||||
// 跳转回去
|
|
||||||
delView(unref(currentRoute))
|
|
||||||
await push({
|
|
||||||
name: 'BpmProcessInstanceMy'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
fApi.value.btn.loading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 初始化 */
|
|
||||||
onMounted(() => {
|
|
||||||
getList()
|
|
||||||
})
|
|
||||||
</script>
|
|
@ -1,391 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ContentWrap>
|
|
||||||
<el-tabs type="card" style="margin-bottom: 20px">
|
|
||||||
<el-tab-pane label="申请信息">
|
|
||||||
<!-- 申请信息 -->
|
|
||||||
<el-card v-loading="processInstanceLoading" class="box-card">
|
|
||||||
<template #header>
|
|
||||||
<span class="el-icon-document">申请信息【{{ processInstance.name }}】</span>
|
|
||||||
</template>
|
|
||||||
<!-- 情况一:流程表单 -->
|
|
||||||
<el-col v-if="processInstance?.processDefinition?.formType === 10" :offset="6" :span="16">
|
|
||||||
<form-create
|
|
||||||
v-model="detailForm.value"
|
|
||||||
v-model:api="fApi"
|
|
||||||
:option="detailForm.option"
|
|
||||||
:rule="detailForm.rule"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
<!-- 情况二:业务表单 -->
|
|
||||||
<div v-if="processInstance?.processDefinition?.formType === 20">
|
|
||||||
<BusinessFormComponent :id="processInstance.businessKey" />
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane :lazy="true" label="流程图">
|
|
||||||
<!-- 高亮流程图 -->
|
|
||||||
<ProcessInstanceBpmnViewer
|
|
||||||
:id="`${id}`"
|
|
||||||
:bpmn-xml="bpmnXml"
|
|
||||||
:loading="processInstanceLoading"
|
|
||||||
:process-instance="processInstance"
|
|
||||||
:tasks="tasks"
|
|
||||||
/>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="审批记录">
|
|
||||||
<!-- 审批记录 -->
|
|
||||||
<ProcessInstanceTaskList
|
|
||||||
:loading="tasksLoad"
|
|
||||||
:process-instance="processInstance"
|
|
||||||
:tasks="tasks"
|
|
||||||
@refresh="getTaskList"
|
|
||||||
/>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane
|
|
||||||
v-for="(index) in runningTasks"
|
|
||||||
:key="index"
|
|
||||||
label="审批内容"
|
|
||||||
>
|
|
||||||
<!-- 审批信息 -->
|
|
||||||
<el-card
|
|
||||||
v-for="(item, index) in runningTasks"
|
|
||||||
:key="index"
|
|
||||||
v-loading="processInstanceLoading"
|
|
||||||
class="box-card"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<span class="el-icon-picture-outline">审批任务【{{ item.name }}】</span>
|
|
||||||
</template>
|
|
||||||
<el-col :offset="6" :span="16">
|
|
||||||
<el-form
|
|
||||||
:ref="'form' + index"
|
|
||||||
:model="auditForms[index]"
|
|
||||||
:rules="auditRule"
|
|
||||||
label-width="100px"
|
|
||||||
>
|
|
||||||
<el-form-item v-if="processInstance && processInstance.name" label="流程名">
|
|
||||||
{{ processInstance.name }}
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
|
|
||||||
{{ processInstance?.startUser.nickname }}
|
|
||||||
<el-tag size="small" type="info">{{ processInstance?.startUser.deptName }}</el-tag>
|
|
||||||
</el-form-item>
|
|
||||||
<el-card v-if="runningTasks[index].formId > 0" class="mb-15px !-mt-10px">
|
|
||||||
<template #header>
|
|
||||||
<span class="el-icon-picture-outline">
|
|
||||||
填写表单【{{ runningTasks[index]?.formName }}】
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<form-create
|
|
||||||
v-model="approveForms[index].value"
|
|
||||||
v-model:api="approveFormFApis[index]"
|
|
||||||
:option="approveForms[index].option"
|
|
||||||
:rule="approveForms[index].rule"
|
|
||||||
/>
|
|
||||||
</el-card>
|
|
||||||
<el-form-item label="审批建议" prop="reason">
|
|
||||||
<el-input
|
|
||||||
v-model="auditForms[index].reason"
|
|
||||||
placeholder="请输入审批建议"
|
|
||||||
type="textarea"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="抄送人" prop="copyUserIds">
|
|
||||||
<el-select v-model="auditForms[index].copyUserIds" multiple placeholder="请选择抄送人">
|
|
||||||
<el-option
|
|
||||||
v-for="item in userOptions"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.nickname"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div style="margin-bottom: 20px; margin-left: 10%; font-size: 14px">
|
|
||||||
<el-button type="success" @click="handleAudit(item, true)">
|
|
||||||
<Icon icon="ep:select" />
|
|
||||||
通过
|
|
||||||
</el-button>
|
|
||||||
<el-button type="danger" @click="handleAudit(item, false)">
|
|
||||||
<Icon icon="ep:close" />
|
|
||||||
不通过
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="openTaskUpdateAssigneeForm(item.id)">
|
|
||||||
<Icon icon="ep:edit" />
|
|
||||||
转办
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="handleDelegate(item)">
|
|
||||||
<Icon icon="ep:position" />
|
|
||||||
委派
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="handleSign(item)">
|
|
||||||
<Icon icon="ep:plus" />
|
|
||||||
加签
|
|
||||||
</el-button>
|
|
||||||
<el-button type="warning" @click="handleBack(item)">
|
|
||||||
<Icon icon="ep:back" />
|
|
||||||
回退
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-card>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
<!-- 弹窗:转派审批人 -->
|
|
||||||
<TaskTransferForm ref="taskTransferFormRef" @success="getDetail" />
|
|
||||||
<!-- 弹窗:回退节点 -->
|
|
||||||
<TaskReturnForm ref="taskReturnFormRef" @success="getDetail" />
|
|
||||||
<!-- 弹窗:委派,将任务委派给别人处理,处理完成后,会重新回到原审批人手中-->
|
|
||||||
<TaskDelegateForm ref="taskDelegateForm" @success="getDetail" />
|
|
||||||
<!-- 弹窗:加签,当前任务审批人为A,向前加签选了一个C,则需要C先审批,然后再是A审批,向后加签B,A审批完,需要B再审批完,才算完成这个任务节点 -->
|
|
||||||
<TaskSignCreateForm ref="taskSignCreateFormRef" @success="getDetail" />
|
|
||||||
</ContentWrap>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { useUserStore } from '@/store/modules/user'
|
|
||||||
import { setConfAndFields2 } from '@/utils/formCreate'
|
|
||||||
import type { ApiAttrs } from '@form-create/element-ui/types/config'
|
|
||||||
import * as DefinitionApi from '@/api/bpm/definition'
|
|
||||||
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
|
|
||||||
import * as TaskApi from '@/api/bpm/task'
|
|
||||||
import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue'
|
|
||||||
import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue'
|
|
||||||
import TaskReturnForm from './dialog/TaskReturnForm.vue'
|
|
||||||
import TaskDelegateForm from './dialog/TaskDelegateForm.vue'
|
|
||||||
import TaskTransferForm from './dialog/TaskTransferForm.vue'
|
|
||||||
import TaskSignCreateForm from './dialog/TaskSignCreateForm.vue'
|
|
||||||
import { registerComponent } from '@/utils/routerHelper'
|
|
||||||
import { isEmpty } from '@/utils/is'
|
|
||||||
import * as UserApi from '@/api/system/user'
|
|
||||||
|
|
||||||
defineOptions({ name: 'BpmProcessInstanceDetail' })
|
|
||||||
|
|
||||||
const { query } = useRoute() // 查询参数
|
|
||||||
const message = useMessage() // 消息弹窗
|
|
||||||
const { proxy } = getCurrentInstance() as any
|
|
||||||
|
|
||||||
const userId = useUserStore().getUser.id // 当前登录的编号
|
|
||||||
const id = query.id as unknown as string // 流程实例的编号
|
|
||||||
const processInstanceLoading = ref(false) // 流程实例的加载中
|
|
||||||
const processInstance = ref<any>({}) // 流程实例
|
|
||||||
const bpmnXml = ref('') // BPMN XML
|
|
||||||
const tasksLoad = ref(true) // 任务的加载中
|
|
||||||
const tasks = ref<any[]>([]) // 任务列表
|
|
||||||
// ========== 审批信息 ==========
|
|
||||||
const runningTasks = ref<any[]>([]) // 运行中的任务
|
|
||||||
const auditForms = ref<any[]>([]) // 审批任务的表单
|
|
||||||
const auditRule = reactive({
|
|
||||||
reason: [{ required: true, message: '审批建议不能为空', trigger: 'blur' }]
|
|
||||||
})
|
|
||||||
const approveForms = ref<any[]>([]) // 审批通过时,额外的补充信息
|
|
||||||
const approveFormFApis = ref<ApiAttrs[]>([]) // approveForms 的 fAPi
|
|
||||||
|
|
||||||
// ========== 申请信息 ==========
|
|
||||||
const fApi = ref<ApiAttrs>() //
|
|
||||||
const detailForm = ref({
|
|
||||||
rule: [],
|
|
||||||
option: {},
|
|
||||||
value: {}
|
|
||||||
}) // 流程实例的表单详情
|
|
||||||
|
|
||||||
/** 监听 approveFormFApis,实现它对应的 form-create 初始化后,隐藏掉对应的表单提交按钮 */
|
|
||||||
watch(
|
|
||||||
() => approveFormFApis.value,
|
|
||||||
(value) => {
|
|
||||||
value?.forEach((api) => {
|
|
||||||
api.btn.show(false)
|
|
||||||
api.resetBtn.show(false)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/** 处理审批通过和不通过的操作 */
|
|
||||||
const handleAudit = async (task, pass) => {
|
|
||||||
// 1.1 获得对应表单
|
|
||||||
const index = runningTasks.value.indexOf(task)
|
|
||||||
const auditFormRef = proxy.$refs['form' + index][0]
|
|
||||||
// 1.2 校验表单
|
|
||||||
const elForm = unref(auditFormRef)
|
|
||||||
if (!elForm) return
|
|
||||||
const valid = await elForm.validate()
|
|
||||||
if (!valid) return
|
|
||||||
|
|
||||||
// 2.1 提交审批
|
|
||||||
const data = {
|
|
||||||
id: task.id,
|
|
||||||
reason: auditForms.value[index].reason,
|
|
||||||
copyUserIds: auditForms.value[index].copyUserIds
|
|
||||||
}
|
|
||||||
if (pass) {
|
|
||||||
// 审批通过,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
|
|
||||||
const formCreateApi = approveFormFApis.value[index]
|
|
||||||
if (formCreateApi) {
|
|
||||||
await formCreateApi.validate()
|
|
||||||
data.variables = approveForms.value[index].value
|
|
||||||
}
|
|
||||||
await TaskApi.approveTask(data)
|
|
||||||
message.success('审批通过成功')
|
|
||||||
} else {
|
|
||||||
await TaskApi.rejectTask(data)
|
|
||||||
message.success('审批不通过成功')
|
|
||||||
}
|
|
||||||
// 2.2 加载最新数据
|
|
||||||
getDetail()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 转派审批人 */
|
|
||||||
const taskTransferFormRef = ref()
|
|
||||||
const openTaskUpdateAssigneeForm = (id: string) => {
|
|
||||||
taskTransferFormRef.value.open(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理审批退回的操作 */
|
|
||||||
const taskDelegateForm = ref()
|
|
||||||
const handleDelegate = async (task) => {
|
|
||||||
taskDelegateForm.value.open(task.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理审批退回的操作 */
|
|
||||||
const taskReturnFormRef = ref()
|
|
||||||
const handleBack = async (task: any) => {
|
|
||||||
taskReturnFormRef.value.open(task.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理审批加签的操作 */
|
|
||||||
const taskSignCreateFormRef = ref()
|
|
||||||
const handleSign = async (task: any) => {
|
|
||||||
taskSignCreateFormRef.value.open(task.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获得详情 */
|
|
||||||
const getDetail = () => {
|
|
||||||
// 1. 获得流程实例相关
|
|
||||||
getProcessInstance()
|
|
||||||
// 2. 获得流程任务列表(审批记录)
|
|
||||||
getTaskList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 加载流程实例 */
|
|
||||||
const BusinessFormComponent = ref(null) // 异步组件
|
|
||||||
const getProcessInstance = async () => {
|
|
||||||
try {
|
|
||||||
processInstanceLoading.value = true
|
|
||||||
const data = await ProcessInstanceApi.getProcessInstance(id)
|
|
||||||
if (!data) {
|
|
||||||
message.error('查询不到流程信息!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
processInstance.value = data
|
|
||||||
|
|
||||||
// 设置表单信息
|
|
||||||
const processDefinition = data.processDefinition
|
|
||||||
if (processDefinition.formType === 10) {
|
|
||||||
setConfAndFields2(
|
|
||||||
detailForm,
|
|
||||||
processDefinition.formConf,
|
|
||||||
processDefinition.formFields,
|
|
||||||
data.formVariables
|
|
||||||
)
|
|
||||||
nextTick().then(() => {
|
|
||||||
fApi.value?.btn.show(false)
|
|
||||||
fApi.value?.resetBtn.show(false)
|
|
||||||
fApi.value?.disabled(true)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// 注意:data.processDefinition.formCustomViewPath 是组件的全路径,例如说:/crm/contract/detail/index.vue
|
|
||||||
BusinessFormComponent.value = registerComponent(data.processDefinition.formCustomViewPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载流程图
|
|
||||||
bpmnXml.value = (
|
|
||||||
await DefinitionApi.getProcessDefinition(processDefinition.id as number)
|
|
||||||
)?.bpmnXml
|
|
||||||
} finally {
|
|
||||||
processInstanceLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 加载任务列表 */
|
|
||||||
const getTaskList = async () => {
|
|
||||||
runningTasks.value = []
|
|
||||||
auditForms.value = []
|
|
||||||
approveForms.value = []
|
|
||||||
approveFormFApis.value = []
|
|
||||||
try {
|
|
||||||
// 获得未取消的任务
|
|
||||||
tasksLoad.value = true
|
|
||||||
const data = await TaskApi.getTaskListByProcessInstanceId(id)
|
|
||||||
tasks.value = []
|
|
||||||
// 1.1 移除已取消的审批
|
|
||||||
data.forEach((task) => {
|
|
||||||
if (task.status !== 4) {
|
|
||||||
tasks.value.push(task)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 1.2 排序,将未完成的排在前面,已完成的排在后面;
|
|
||||||
tasks.value.sort((a, b) => {
|
|
||||||
// 有已完成的情况,按照完成时间倒序
|
|
||||||
if (a.endTime && b.endTime) {
|
|
||||||
return b.endTime - a.endTime
|
|
||||||
} else if (a.endTime) {
|
|
||||||
return 1
|
|
||||||
} else if (b.endTime) {
|
|
||||||
return -1
|
|
||||||
// 都是未完成,按照创建时间倒序
|
|
||||||
} else {
|
|
||||||
return b.createTime - a.createTime
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获得需要自己审批的任务
|
|
||||||
loadRunningTask(tasks.value)
|
|
||||||
} finally {
|
|
||||||
tasksLoad.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置 runningTasks 中的任务
|
|
||||||
*/
|
|
||||||
const loadRunningTask = (tasks) => {
|
|
||||||
tasks.forEach((task) => {
|
|
||||||
if (!isEmpty(task.children)) {
|
|
||||||
loadRunningTask(task.children)
|
|
||||||
}
|
|
||||||
// 2.1 只有待处理才需要
|
|
||||||
if (task.status !== 1 && task.status !== 6) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 2.2 自己不是处理人
|
|
||||||
if (!task.assigneeUser || task.assigneeUser.id !== userId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 2.3 添加到处理任务
|
|
||||||
runningTasks.value.push({ ...task })
|
|
||||||
auditForms.value.push({
|
|
||||||
reason: '',
|
|
||||||
copyUserIds: []
|
|
||||||
})
|
|
||||||
|
|
||||||
// 2.4 处理 approve 表单
|
|
||||||
if (task.formId && task.formConf) {
|
|
||||||
const approveForm = {}
|
|
||||||
setConfAndFields2(approveForm, task.formConf, task.formFields, task.formVariables)
|
|
||||||
approveForms.value.push(approveForm)
|
|
||||||
} else {
|
|
||||||
approveForms.value.push({}) // 占位,避免为空
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 初始化 */
|
|
||||||
const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
|
|
||||||
onMounted(async () => {
|
|
||||||
getDetail()
|
|
||||||
// 获得用户列表
|
|
||||||
userOptions.value = await UserApi.getSimpleUserList()
|
|
||||||
})
|
|
||||||
</script>
|
|
@ -1,381 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ContentWrap>
|
|
||||||
<!-- 审批信息 -->
|
|
||||||
<el-card
|
|
||||||
v-for="(item, index) in runningTasks"
|
|
||||||
:key="index"
|
|
||||||
v-loading="processInstanceLoading"
|
|
||||||
class="box-card"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<span class="el-icon-picture-outline">审批任务【{{ item.name }}】</span>
|
|
||||||
</template>
|
|
||||||
<el-col :offset="6" :span="16">
|
|
||||||
<el-form
|
|
||||||
:ref="'form' + index"
|
|
||||||
:model="auditForms[index]"
|
|
||||||
:rules="auditRule"
|
|
||||||
label-width="100px"
|
|
||||||
>
|
|
||||||
<el-form-item v-if="processInstance && processInstance.name" label="流程名">
|
|
||||||
{{ processInstance.name }}
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
|
|
||||||
{{ processInstance?.startUser.nickname }}
|
|
||||||
<el-tag size="small" type="info">{{ processInstance?.startUser.deptName }}</el-tag>
|
|
||||||
</el-form-item>
|
|
||||||
<el-card v-if="runningTasks[index].formId > 0" class="mb-15px !-mt-10px">
|
|
||||||
<template #header>
|
|
||||||
<span class="el-icon-picture-outline">
|
|
||||||
填写表单【{{ runningTasks[index]?.formName }}】
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<form-create
|
|
||||||
v-model="approveForms[index].value"
|
|
||||||
v-model:api="approveFormFApis[index]"
|
|
||||||
:option="approveForms[index].option"
|
|
||||||
:rule="approveForms[index].rule"
|
|
||||||
/>
|
|
||||||
</el-card>
|
|
||||||
<el-form-item label="审批建议" prop="reason">
|
|
||||||
<el-input
|
|
||||||
v-model="auditForms[index].reason"
|
|
||||||
placeholder="请输入审批建议"
|
|
||||||
type="textarea"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="抄送人" prop="copyUserIds">
|
|
||||||
<el-select v-model="auditForms[index].copyUserIds" multiple placeholder="请选择抄送人">
|
|
||||||
<el-option
|
|
||||||
v-for="item in userOptions"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.nickname"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div style="margin-bottom: 20px; margin-left: 10%; font-size: 14px">
|
|
||||||
<el-button type="success" @click="handleAudit(item, true)">
|
|
||||||
<Icon icon="ep:select" />
|
|
||||||
通过
|
|
||||||
</el-button>
|
|
||||||
<el-button type="danger" @click="handleAudit(item, false)">
|
|
||||||
<Icon icon="ep:close" />
|
|
||||||
不通过
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="openTaskUpdateAssigneeForm(item.id)">
|
|
||||||
<Icon icon="ep:edit" />
|
|
||||||
转办
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="handleDelegate(item)">
|
|
||||||
<Icon icon="ep:position" />
|
|
||||||
委派
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="handleSign(item)">
|
|
||||||
<Icon icon="ep:plus" />
|
|
||||||
加签
|
|
||||||
</el-button>
|
|
||||||
<el-button type="warning" @click="handleBack(item)">
|
|
||||||
<Icon icon="ep:back" />
|
|
||||||
回退
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- 申请信息 -->
|
|
||||||
<el-card v-loading="processInstanceLoading" class="box-card">
|
|
||||||
<template #header>
|
|
||||||
<span class="el-icon-document">申请信息【{{ processInstance.name }}】</span>
|
|
||||||
</template>
|
|
||||||
<!-- 情况一:流程表单 -->
|
|
||||||
<el-col v-if="processInstance?.processDefinition?.formType === 10" :offset="6" :span="16">
|
|
||||||
<form-create
|
|
||||||
v-model="detailForm.value"
|
|
||||||
v-model:api="fApi"
|
|
||||||
:option="detailForm.option"
|
|
||||||
:rule="detailForm.rule"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
<!-- 情况二:业务表单 -->
|
|
||||||
<div v-if="processInstance?.processDefinition?.formType === 20">
|
|
||||||
<BusinessFormComponent :id="processInstance.businessKey" />
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- 审批记录 -->
|
|
||||||
<ProcessInstanceTaskList
|
|
||||||
:loading="tasksLoad"
|
|
||||||
:process-instance="processInstance"
|
|
||||||
:tasks="tasks"
|
|
||||||
@refresh="getTaskList"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 高亮流程图 -->
|
|
||||||
<ProcessInstanceBpmnViewer
|
|
||||||
:id="`${id}`"
|
|
||||||
:bpmn-xml="bpmnXml"
|
|
||||||
:loading="processInstanceLoading"
|
|
||||||
:process-instance="processInstance"
|
|
||||||
:tasks="tasks"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 弹窗:转派审批人 -->
|
|
||||||
<TaskTransferForm ref="taskTransferFormRef" @success="getDetail" />
|
|
||||||
<!-- 弹窗:回退节点 -->
|
|
||||||
<TaskReturnForm ref="taskReturnFormRef" @success="getDetail" />
|
|
||||||
<!-- 弹窗:委派,将任务委派给别人处理,处理完成后,会重新回到原审批人手中-->
|
|
||||||
<TaskDelegateForm ref="taskDelegateForm" @success="getDetail" />
|
|
||||||
<!-- 弹窗:加签,当前任务审批人为A,向前加签选了一个C,则需要C先审批,然后再是A审批,向后加签B,A审批完,需要B再审批完,才算完成这个任务节点 -->
|
|
||||||
<TaskSignCreateForm ref="taskSignCreateFormRef" @success="getDetail" />
|
|
||||||
</ContentWrap>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { useUserStore } from '@/store/modules/user'
|
|
||||||
import { setConfAndFields2 } from '@/utils/formCreate'
|
|
||||||
import type { ApiAttrs } from '@form-create/element-ui/types/config'
|
|
||||||
import * as DefinitionApi from '@/api/bpm/definition'
|
|
||||||
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
|
|
||||||
import * as TaskApi from '@/api/bpm/task'
|
|
||||||
import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue'
|
|
||||||
import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue'
|
|
||||||
import TaskReturnForm from './dialog/TaskReturnForm.vue'
|
|
||||||
import TaskDelegateForm from './dialog/TaskDelegateForm.vue'
|
|
||||||
import TaskTransferForm from './dialog/TaskTransferForm.vue'
|
|
||||||
import TaskSignCreateForm from './dialog/TaskSignCreateForm.vue'
|
|
||||||
import { registerComponent } from '@/utils/routerHelper'
|
|
||||||
import { isEmpty } from '@/utils/is'
|
|
||||||
import * as UserApi from '@/api/system/user'
|
|
||||||
|
|
||||||
defineOptions({ name: 'BpmProcessInstanceDetail' })
|
|
||||||
|
|
||||||
const { query } = useRoute() // 查询参数
|
|
||||||
const message = useMessage() // 消息弹窗
|
|
||||||
const { proxy } = getCurrentInstance() as any
|
|
||||||
|
|
||||||
const userId = useUserStore().getUser.id // 当前登录的编号
|
|
||||||
const id = query.id as unknown as string // 流程实例的编号
|
|
||||||
const processInstanceLoading = ref(false) // 流程实例的加载中
|
|
||||||
const processInstance = ref<any>({}) // 流程实例
|
|
||||||
const bpmnXml = ref('') // BPMN XML
|
|
||||||
const tasksLoad = ref(true) // 任务的加载中
|
|
||||||
const tasks = ref<any[]>([]) // 任务列表
|
|
||||||
// ========== 审批信息 ==========
|
|
||||||
const runningTasks = ref<any[]>([]) // 运行中的任务
|
|
||||||
const auditForms = ref<any[]>([]) // 审批任务的表单
|
|
||||||
const auditRule = reactive({
|
|
||||||
reason: [{ required: true, message: '审批建议不能为空', trigger: 'blur' }]
|
|
||||||
})
|
|
||||||
const approveForms = ref<any[]>([]) // 审批通过时,额外的补充信息
|
|
||||||
const approveFormFApis = ref<ApiAttrs[]>([]) // approveForms 的 fAPi
|
|
||||||
|
|
||||||
// ========== 申请信息 ==========
|
|
||||||
const fApi = ref<ApiAttrs>() //
|
|
||||||
const detailForm = ref({
|
|
||||||
rule: [],
|
|
||||||
option: {},
|
|
||||||
value: {}
|
|
||||||
}) // 流程实例的表单详情
|
|
||||||
|
|
||||||
/** 监听 approveFormFApis,实现它对应的 form-create 初始化后,隐藏掉对应的表单提交按钮 */
|
|
||||||
watch(
|
|
||||||
() => approveFormFApis.value,
|
|
||||||
(value) => {
|
|
||||||
value?.forEach((api) => {
|
|
||||||
api.btn.show(false)
|
|
||||||
api.resetBtn.show(false)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/** 处理审批通过和不通过的操作 */
|
|
||||||
const handleAudit = async (task, pass) => {
|
|
||||||
// 1.1 获得对应表单
|
|
||||||
const index = runningTasks.value.indexOf(task)
|
|
||||||
const auditFormRef = proxy.$refs['form' + index][0]
|
|
||||||
// 1.2 校验表单
|
|
||||||
const elForm = unref(auditFormRef)
|
|
||||||
if (!elForm) return
|
|
||||||
const valid = await elForm.validate()
|
|
||||||
if (!valid) return
|
|
||||||
|
|
||||||
// 2.1 提交审批
|
|
||||||
const data = {
|
|
||||||
id: task.id,
|
|
||||||
reason: auditForms.value[index].reason,
|
|
||||||
copyUserIds: auditForms.value[index].copyUserIds
|
|
||||||
}
|
|
||||||
if (pass) {
|
|
||||||
// 审批通过,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
|
|
||||||
const formCreateApi = approveFormFApis.value[index]
|
|
||||||
if (formCreateApi) {
|
|
||||||
await formCreateApi.validate()
|
|
||||||
data.variables = approveForms.value[index].value
|
|
||||||
}
|
|
||||||
await TaskApi.approveTask(data)
|
|
||||||
message.success('审批通过成功')
|
|
||||||
} else {
|
|
||||||
await TaskApi.rejectTask(data)
|
|
||||||
message.success('审批不通过成功')
|
|
||||||
}
|
|
||||||
// 2.2 加载最新数据
|
|
||||||
getDetail()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 转派审批人 */
|
|
||||||
const taskTransferFormRef = ref()
|
|
||||||
const openTaskUpdateAssigneeForm = (id: string) => {
|
|
||||||
taskTransferFormRef.value.open(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理审批退回的操作 */
|
|
||||||
const taskDelegateForm = ref()
|
|
||||||
const handleDelegate = async (task) => {
|
|
||||||
taskDelegateForm.value.open(task.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理审批退回的操作 */
|
|
||||||
const taskReturnFormRef = ref()
|
|
||||||
const handleBack = async (task: any) => {
|
|
||||||
taskReturnFormRef.value.open(task.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理审批加签的操作 */
|
|
||||||
const taskSignCreateFormRef = ref()
|
|
||||||
const handleSign = async (task: any) => {
|
|
||||||
taskSignCreateFormRef.value.open(task.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获得详情 */
|
|
||||||
const getDetail = () => {
|
|
||||||
// 1. 获得流程实例相关
|
|
||||||
getProcessInstance()
|
|
||||||
// 2. 获得流程任务列表(审批记录)
|
|
||||||
getTaskList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 加载流程实例 */
|
|
||||||
const BusinessFormComponent = ref(null) // 异步组件
|
|
||||||
const getProcessInstance = async () => {
|
|
||||||
try {
|
|
||||||
processInstanceLoading.value = true
|
|
||||||
const data = await ProcessInstanceApi.getProcessInstance(id)
|
|
||||||
if (!data) {
|
|
||||||
message.error('查询不到流程信息!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
processInstance.value = data
|
|
||||||
|
|
||||||
// 设置表单信息
|
|
||||||
const processDefinition = data.processDefinition
|
|
||||||
if (processDefinition.formType === 10) {
|
|
||||||
setConfAndFields2(
|
|
||||||
detailForm,
|
|
||||||
processDefinition.formConf,
|
|
||||||
processDefinition.formFields,
|
|
||||||
data.formVariables
|
|
||||||
)
|
|
||||||
nextTick().then(() => {
|
|
||||||
fApi.value?.btn.show(false)
|
|
||||||
fApi.value?.resetBtn.show(false)
|
|
||||||
fApi.value?.disabled(true)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// 注意:data.processDefinition.formCustomViewPath 是组件的全路径,例如说:/crm/contract/detail/index.vue
|
|
||||||
BusinessFormComponent.value = registerComponent(data.processDefinition.formCustomViewPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载流程图
|
|
||||||
bpmnXml.value = (
|
|
||||||
await DefinitionApi.getProcessDefinition(processDefinition.id as number)
|
|
||||||
)?.bpmnXml
|
|
||||||
} finally {
|
|
||||||
processInstanceLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 加载任务列表 */
|
|
||||||
const getTaskList = async () => {
|
|
||||||
runningTasks.value = []
|
|
||||||
auditForms.value = []
|
|
||||||
approveForms.value = []
|
|
||||||
approveFormFApis.value = []
|
|
||||||
try {
|
|
||||||
// 获得未取消的任务
|
|
||||||
tasksLoad.value = true
|
|
||||||
const data = await TaskApi.getTaskListByProcessInstanceId(id)
|
|
||||||
tasks.value = []
|
|
||||||
// 1.1 移除已取消的审批
|
|
||||||
data.forEach((task) => {
|
|
||||||
if (task.status !== 4) {
|
|
||||||
tasks.value.push(task)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 1.2 排序,将未完成的排在前面,已完成的排在后面;
|
|
||||||
tasks.value.sort((a, b) => {
|
|
||||||
// 有已完成的情况,按照完成时间倒序
|
|
||||||
if (a.endTime && b.endTime) {
|
|
||||||
return b.endTime - a.endTime
|
|
||||||
} else if (a.endTime) {
|
|
||||||
return 1
|
|
||||||
} else if (b.endTime) {
|
|
||||||
return -1
|
|
||||||
// 都是未完成,按照创建时间倒序
|
|
||||||
} else {
|
|
||||||
return b.createTime - a.createTime
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获得需要自己审批的任务
|
|
||||||
loadRunningTask(tasks.value)
|
|
||||||
} finally {
|
|
||||||
tasksLoad.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置 runningTasks 中的任务
|
|
||||||
*/
|
|
||||||
const loadRunningTask = (tasks) => {
|
|
||||||
tasks.forEach((task) => {
|
|
||||||
if (!isEmpty(task.children)) {
|
|
||||||
loadRunningTask(task.children)
|
|
||||||
}
|
|
||||||
// 2.1 只有待处理才需要
|
|
||||||
if (task.status !== 1 && task.status !== 6) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 2.2 自己不是处理人
|
|
||||||
if (!task.assigneeUser || task.assigneeUser.id !== userId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 2.3 添加到处理任务
|
|
||||||
runningTasks.value.push({ ...task })
|
|
||||||
auditForms.value.push({
|
|
||||||
reason: '',
|
|
||||||
copyUserIds: []
|
|
||||||
})
|
|
||||||
|
|
||||||
// 2.4 处理 approve 表单
|
|
||||||
if (task.formId && task.formConf) {
|
|
||||||
const approveForm = {}
|
|
||||||
setConfAndFields2(approveForm, task.formConf, task.formFields, task.formVariables)
|
|
||||||
approveForms.value.push(approveForm)
|
|
||||||
} else {
|
|
||||||
approveForms.value.push({}) // 占位,避免为空
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 初始化 */
|
|
||||||
const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
|
|
||||||
onMounted(async () => {
|
|
||||||
getDetail()
|
|
||||||
// 获得用户列表
|
|
||||||
userOptions.value = await UserApi.getSimpleUserList()
|
|
||||||
})
|
|
||||||
</script>
|
|
Loading…
Reference in New Issue
Block a user