路由及相应重构回退vxe

This commit is contained in:
gexinzhineng/gxzn27
2023-04-06 14:33:01 +08:00
parent 561b617ca4
commit af26859ba8
5 changed files with 7 additions and 622 deletions

View File

@ -1,106 +0,0 @@
<template>
<ContentWrap>
<!-- 表单设计器 -->
<fc-designer ref="designer" height="780px">
<template #handle>
<el-button round size="small" type="primary" @click="handleSave">
<Icon icon="ep:plus" class="mr-5px" /> 保存
</el-button>
</template>
</fc-designer>
</ContentWrap>
<!-- 表单保存的弹窗 -->
<Dialog title="保存表单" v-model="modelVisible" width="600">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
<el-form-item label="表单名" prop="name">
<el-input v-model="formData.name" placeholder="请输入表单名" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants'
import * as FormApi from '@/api/bpm/form'
import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息
const { query } = useRoute() // 路由
const designer = ref() // 表单设计器
const modelVisible = ref(false) // 弹窗是否展示
const formLoading = ref(false) // 表单的加载中:提交的按钮禁用
const formData = ref({
name: '',
status: CommonStatusEnum.ENABLE,
remark: ''
})
const formRules = reactive({
name: [{ required: true, message: '表单名不能为空', trigger: 'blur' }],
status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
/** 处理保存按钮 */
const handleSave = () => {
modelVisible.value = true
}
/** 提交表单 */
const submitForm = async () => {
// 校验表单
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
// 提交请求
formLoading.value = true
try {
const data = formData.value as FormApi.FormVO
data.conf = encodeConf(designer) // 表单配置
data.fields = encodeFields(designer) // 表单字段
if (!data.id) {
await FormApi.createFormApi(data)
message.success(t('common.createSuccess'))
} else {
await FormApi.updateFormApi(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
} finally {
formLoading.value = false
}
}
/** 初始化 **/
onMounted(async () => {
// 场景一:新增表单
const id = query.id as unknown as number
if (!id) {
return
}
// 场景二:修改表单
const data = await FormApi.getFormApi(id)
formData.value = data
setConfAndFields(designer, data.conf, data.fields)
})
</script>

View File

@ -1,102 +0,0 @@
<template>
<ContentWrap>
<!-- 流程设计器负责绘制流程等 -->
<my-process-designer
key="designer"
v-if="xmlString !== undefined"
v-model="xmlString"
:value="xmlString"
v-bind="controlForm"
keyboard
ref="processDesigner"
@init-finished="initModeler"
:additionalModel="controlForm.additionalModel"
@save="save"
/>
<!-- 流程属性器负责编辑每个流程节点的属性 -->
<my-properties-panel
key="penal"
:bpmnModeler="modeler"
:prefix="controlForm.prefix"
class="process-panel"
:model="model"
/>
</ContentWrap>
</template>
<script setup lang="ts">
// 自定义元素选中时的弹出菜单(修改 默认任务 为 用户任务)
import CustomContentPadProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/content-pad'
// 自定义左侧菜单(修改 默认任务 为 用户任务)
import CustomPaletteProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/palette'
import * as ModelApi from '@/api/bpm/model'
const router = useRouter() // 路由
const { query } = useRoute() // 路由的查询
const message = useMessage() // 国际化
const xmlString = ref(undefined) // BPMN XML
const modeler = ref(null) // BPMN Modeler
const controlForm = ref({
simulation: true,
labelEditing: false,
labelVisible: false,
prefix: 'flowable',
headerButtonSize: 'mini',
additionalModel: [CustomContentPadProvider, CustomPaletteProvider]
})
const model = ref<ModelApi.ModelVO>() // 流程模型的信息
/** 初始化 modeler */
const initModeler = (item) => {
setTimeout(() => {
modeler.value = item
}, 10)
}
/** 添加/修改模型 */
const save = async (bpmnXml) => {
const data = {
...model.value,
bpmnXml: bpmnXml // bpmnXml 只是初始化流程图,后续修改无法通过它获得
} as unknown as ModelApi.ModelVO
// 提交
if (data.id) {
await ModelApi.updateModelApi(data)
message.success('修改成功')
} else {
await ModelApi.createModelApi(data)
message.success('新增成功')
}
// 跳转回去
close()
}
/** 关闭按钮 */
const close = () => {
router.push({ path: '/bpm/manager/model' })
}
/** 初始化 */
onMounted(async () => {
const modelId = query.modelId as unknown as number
if (!modelId) {
message.error('缺少模型 modelId 编号')
return
}
// 查询模型
const data = await ModelApi.getModelApi(modelId)
xmlString.value = data.bpmnXml
model.value = {
...data,
bpmnXml: undefined // 清空 bpmnXml 属性
}
})
</script>
<style lang="scss">
.process-panel__container {
position: absolute;
right: 60px;
top: 90px;
}
</style>

View File

@ -1,130 +0,0 @@
<template>
<!-- 第一步通过流程定义的列表选择对应的流程 -->
<ContentWrap v-if="!selectProcessInstance">
<el-table v-loading="loading" :data="list">
<el-table-column label="流程名称" align="center" prop="name" />
<el-table-column label="流程分类" align="center" prop="category">
<template #default="scope">
<dict-tag :type="DICT_TYPE.BPM_MODEL_CATEGORY" :value="scope.row.category" />
</template>
</el-table-column>
<el-table-column label="流程版本" align="center" prop="version">
<template #default="scope">
<el-tag>v{{ scope.row.version }}</el-tag>
</template>
</el-table-column>
<el-table-column label="流程描述" align="center" prop="description" />
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button link type="primary" @click="handleSelect(scope.row)">
<Icon icon="ep:plus" /> 选择
</el-button>
</template>
</el-table-column>
</el-table>
</ContentWrap>
<!-- 第二步填写表单进行流程的提交 -->
<ContentWrap v-else>
<el-card class="box-card">
<div class="clearfix">
<span class="el-icon-document">申请信息{{ selectProcessInstance.name }}</span>
<el-button style="float: right" type="primary" @click="selectProcessInstance = 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"
:option="detailForm.option"
@submit="submitForm"
/>
</el-col>
</el-card>
<!-- 流程图预览 -->
<ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML" />
</ContentWrap>
</template>
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
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'
const router = useRouter() // 路由
const message = useMessage() // 消息
// ========== 列表相关 ==========
const loading = ref(true) // 列表的加载中
const list = ref([]) // 列表的数据
const queryParams = reactive({
suspensionState: 1
})
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
list.value = await DefinitionApi.getProcessDefinitionList(queryParams)
} finally {
loading.value = false
}
}
// ========== 表单相关 ==========
const bpmnXML = ref(null) // BPMN 数据
const fApi = ref<ApiAttrs>()
const detailForm = ref({
// 流程表单详情
rule: [],
option: {}
})
const selectProcessInstance = ref() // 选择的流程实例
/** 处理选择流程的按钮操作 **/
const handleSelect = async (row) => {
// 设置选择的流程
selectProcessInstance.value = row
// 情况一:流程表单
if (row.formType == 10) {
// 设置表单
setConfAndFields2(detailForm, row.formConf, row.formFields)
// 加载流程图
bpmnXML.value = await DefinitionApi.getProcessDefinitionBpmnXML(row.id)
// 情况二:业务表单
} else if (row.formCustomCreatePath) {
await router.push({
path: row.formCustomCreatePath
})
// 这里暂时无需加载流程图,因为跳出到另外个 Tab
}
}
/** 提交按钮 */
const submitForm = async (formData) => {
if (!fApi.value || !selectProcessInstance.value) {
return
}
// 提交请求
fApi.value.btn.loading(true)
try {
await ProcessInstanceApi.createProcessInstanceApi({
processDefinitionId: selectProcessInstance.value.id,
variables: formData
})
// 提示
message.success('发起流程成功')
router.go(-1)
} finally {
fApi.value.btn.loading(false)
}
}
/** 初始化 */
onMounted(() => {
getList()
})
</script>

View File

@ -1,277 +0,0 @@
<template>
<ContentWrap>
<!-- 审批信息 -->
<el-card
class="box-card"
v-loading="processInstanceLoading"
v-for="(item, index) in runningTasks"
:key="index"
>
<template #header>
<span class="el-icon-picture-outline">审批任务{{ item.name }}</span>
</template>
<el-col :span="16" :offset="6">
<el-form
:ref="'form' + index"
:model="auditForms[index]"
:rules="auditRule"
label-width="100px"
>
<el-form-item label="流程名" v-if="processInstance && processInstance.name">
{{ processInstance.name }}
</el-form-item>
<el-form-item label="流程发起人" v-if="processInstance && processInstance.startUser">
{{ processInstance.startUser.nickname }}
<el-tag type="info" size="small">{{ processInstance.startUser.deptName }}</el-tag>
</el-form-item>
<el-form-item label="审批建议" prop="reason">
<el-input
type="textarea"
v-model="auditForms[index].reason"
placeholder="请输入审批建议"
/>
</el-form-item>
</el-form>
<div style="margin-left: 10%; margin-bottom: 20px; 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="warning" @click="handleBack(item)">
<Icon icon="ep:back" /> 退回
</el-button>
</div>
</el-col>
</el-card>
<!-- 申请信息 -->
<el-card class="box-card" v-loading="processInstanceLoading">
<template #header>
<span class="el-icon-document">申请信息{{ processInstance.name }}</span>
</template>
<!-- 情况一流程表单 -->
<el-col v-if="processInstance?.processDefinition?.formType === 10" :span="16" :offset="6">
<form-create
ref="fApi"
:rule="detailForm.rule"
:option="detailForm.option"
v-model="detailForm.value"
/>
</el-col>
<!-- 情况二流程表单 -->
<div v-if="processInstance?.processDefinition?.formType === 20">
<router-link
:to="
processInstance.processDefinition.formCustomViewPath +
'?id=' +
processInstance.businessKey
"
>
<el-button type="primary"><Icon icon="ep:view" /> 点击查看</el-button>
</router-link>
</div>
</el-card>
<!-- 审批记录 -->
<ProcessInstanceTaskList :loading="tasksLoad" :tasks="tasks" />
<!-- 高亮流程图 -->
<ProcessInstanceBpmnViewer
:id="id"
:process-instance="processInstance"
:loading="processInstanceLoading"
:tasks="tasks"
:bpmn-xml="bpmnXML"
/>
<!-- 弹窗转派审批人 -->
<TaskUpdateAssigneeForm ref="taskUpdateAssigneeFormRef" @success="getDetail" />
</ContentWrap>
</template>
<script setup lang="ts">
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 TaskUpdateAssigneeForm from './TaskUpdateAssigneeForm.vue'
import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue'
import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue'
const { query } = useRoute() // 查询参数
const message = useMessage() // 消息弹窗
const { proxy } = getCurrentInstance() as any
const userId = useUserStore().getUser.id // 当前登录的编号
const id = query.id as unknown as number // 流程实例的编号
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 fApi = ref<ApiAttrs>() //
const detailForm = ref({
// 流程表单详情
rule: [],
option: {},
value: {}
})
/** 处理审批通过和不通过的操作 */
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
}
if (pass) {
await TaskApi.approveTask(data)
message.success('审批通过成功')
} else {
await TaskApi.rejectTask(data)
message.success('审批不通过成功')
}
// 2.2 加载最新数据
getDetail()
}
/** 转派审批人 */
const taskUpdateAssigneeFormRef = ref()
const openTaskUpdateAssigneeForm = (id: string) => {
taskUpdateAssigneeFormRef.value.open(id)
}
/** 处理审批退回的操作 */
const handleDelegate = async (task) => {
message.error('暂不支持【委派】功能,可以使用【转派】替代!')
console.log(task)
}
/** 处理审批退回的操作 */
const handleBack = async (task) => {
message.error('暂不支持【退回】功能!')
console.log(task)
}
/** 获得详情 */
const getDetail = () => {
// 1. 获得流程实例相关
getProcessInstance()
// 2. 获得流程任务列表(审批记录)
getTaskList()
}
/** 加载流程实例 */
const getProcessInstance = async () => {
try {
processInstanceLoading.value = true
const data = await ProcessInstanceApi.getProcessInstanceApi(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?.fapi?.btn.show(false)
fApi.value?.fapi?.resetBtn.show(false)
fApi.value?.fapi?.disabled(true)
})
}
// 加载流程图
bpmnXML.value = await DefinitionApi.getProcessDefinitionBpmnXML(processDefinition.id)
} finally {
processInstanceLoading.value = false
}
}
/** 加载任务列表 */
const getTaskList = async () => {
try {
// 获得未取消的任务
tasksLoad.value = true
const data = await TaskApi.getTaskListByProcessInstanceId(id)
tasks.value = []
// 1.1 移除已取消的审批
data.forEach((task) => {
if (task.result !== 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
}
})
// 获得需要自己审批的任务
runningTasks.value = []
auditForms.value = []
tasks.value.forEach((task) => {
// 2.1 只有待处理才需要
if (task.result !== 1) {
return
}
// 2.2 自己不是处理人
if (!task.assigneeUser || task.assigneeUser.id !== userId) {
return
}
// 2.3 添加到处理任务
runningTasks.value.push({ ...task })
auditForms.value.push({
reason: ''
})
})
} finally {
tasksLoad.value = false
}
}
/** 初始化 */
onMounted(() => {
getDetail()
})
</script>