FlowForm
流程表单
一些钩子
ts
import { useInjectState } from '@yusui/flow-pages'
const { onAfterGetDetail } = useInjectState()
onAfterGetDetail((data) => {
console.log(data)
})
名称 | 说明 | 参数 |
---|---|---|
onAfterGetDetail | 获取流程详情后 | (data: FlowDetail) => MaybePromise<any> |
onBeforeClick | 获取流程详情后 | (btn: FlowButton) => MaybePromise<any> |
onBeforeSubmit | 流程提交前 | (btn: FlowButton) => MaybePromise<any> |
onAfterSubmit | 流程提交成功后 | (btn: FlowButton) => MaybePromise<any> |
扩展tabs
ts
import FlowPages, { CONFIG_DEFAULT } from '@yusui/flow-pages'
import CustomTab from '@/components/CustomTab.vue'
app.use(FlowPages, {
tabs: [
...CONFIG_DEFAULT.tabs,
// { label: '审批表单', prop: 'formTab', component: InternalForm },
// { label: '附件资料', prop: 'fileTab', component: UploadTable },
// { label: '流程跟踪', prop: 'trackTab', component: FlowTrack },
{ label: '自定义Tab', prop: 'customTab', component: CustomTab },
],
})
vue
<script setup lang="ts">
import { useInjectState } from '@yusui/flow-pages'
import { ElMessage } from 'element-plus'
const { flowDetail, formData } = useInjectState()
function validate() {
if (!formData.value.custom) {
ElMessage.warning('请输入自定义值')
return Promise.reject()
}
}
// 验证不通过可以阻止流程的发送
defineExpose({ validate })
</script>
<template>
<div>这是一个自定义Tab</div>
</template>
扩展按钮
页面 -> 流程按钮 -> 新增 -> { name: "自定义按钮", buttonKey: "flow_custom" }
ts
import FlowPages from '@yusui/flow-pages'
import customButtonHandler from './customButtonHandler.ts'
app.use(FlowPages, {
buttonHandler: customButtonHandler
})
ts
import type { ButtonHandler, FlowFormState } from '@yusui/flow-pages'
export function useButtonHandler(state: FlowFormState): ButtonHandler {
return {
// 自定义
flow_custom() {
// ...做一些自定义操作
// 返回Promise并成功则提交流程
return request.post('xxx/xxx', {})
},
}
}
自定义流程表单
ts
const importedForms = import.meta.glob('../custom-form/**/*.vue')
const customForm = Object.fromEntries(Object.entries(importedForms).map(([key, value]) => [key.replace('../custom-form/', ''), value]))
// {
// "test/index.vue": () => Promise<Component>
// "xxx.vue": () => Promise<Component>
// }
app.use(FlowPages, {
customForm,
})
vue
<script setup lang="ts">
import type { AvueFormInstance, AvueFormOption } from '@smallwei/avue'
import { ref } from 'vue'
import { asyncValidate, useFormDefaults, useInjectState } from '@yusui/flow-pages'
// 获取流程表单上下文数据
const { flowDetail, formData, onAfterGetDetail, onBeforeClick, onBeforeSubmit } = useInjectState()
const formRef = ref<AvueFormInstance>()
const formOption: AvueFormOption = {
menuBtn: false,
span: 24,
column: [
{ prop: 'title', type: 'title', value: '这是一个自定义表单' },
{ label: '输入框', prop: 'input', placeholder: '请输入值', rules: [{ required: true, message: '请输入值' }] },
],
}
// 可以使用FlowForm内置的表单控制,或自行定义
const formDefaults = useFormDefaults(flowDetail)
// 获取流程详情后的钩子
onAfterGetDetail((data) => {
console.log('流程详情', data)
})
// 按钮点击的钩子,返回Promise.reject()可以阻止点击
onBeforeClick((activeBtn) => {
if (activeBtn.buttonKey === 'flow_pass')
console.log('正在选择审批人')
})
// 提交前的钩子,返回Promise.reject()可以阻止提交
onBeforeSubmit((activeBtn) => {
if (activeBtn.buttonKey === 'flow_pass') {
console.log('正在提交')
formData.value = {
...formData.value,
}
}
})
// 暴露异步validate方法作为提交前的校验
const validate = () => asyncValidate(formRef)
defineExpose({ validate })
</script>
<script lang="ts">
export default { name: 'TestForm' }
</script>
<template>
<avue-form ref="formRef" v-model="formData" v-model:defaults="formDefaults" :option="formOption" />
</template>
直接重写FlowForm(不建议)
ts
import FlowPages from '@yusui/flow-pages'
import CustomFlowForm from './CustomFlowForm.vue'
app.use(FlowPages, {
FlowForm: CustomFlowForm
})
vue
<script setup lang="ts">
import { flowFormEmits, flowFormProps, isMobile, useConfigProvider, useProvideState } from '@yusui/flow-pages'
import ButtonList from './components/ButtonList.vue'
import InternalApprovalForm from './components/ApprovalForm.vue'
const props = defineProps(flowFormProps)
const emit = defineEmits(flowFormEmits)
const state = useProvideState(props, emit)
const { ApprovalForm: rewriteApprovalForm, tabsProps } = useConfigProvider()
const ApprovalForm = rewriteApprovalForm ?? InternalApprovalForm
const {
title,
detail,
flowDetail,
tabRefs,
tabList,
activeTab,
formLoading,
tabsRef,
onButtonClick,
onSubmit,
} = state
</script>
<template>
<el-main v-if="formLoading">
<el-skeleton />
</el-main>
<el-container v-else class="flow-form">
<el-header class="flow-form__header" height="auto">
<div class="flow-form__title">
{{ title ?? flowDetail.flowInstance?.title }}
</div>
<ButtonList v-if="!detail && !isMobile()" @click="onButtonClick" />
</el-header>
<el-main class="flow-form__main">
<el-tabs ref="tabsRef" v-model="activeTab" v-bind="tabsProps">
<el-tab-pane
v-for="tab in tabList" :key="tab.prop" :label="tab.label" :name="tab.prop" :lazy="tab.lazy"
:disabled="tab.disabled" :closable="tab.closable"
>
<component :is="tab.component" :ref="(el: any) => tabRefs[tab.prop!] = el" />
</el-tab-pane>
</el-tabs>
</el-main>
<el-footer v-if="!detail && isMobile()" class="flow-form__footer" height="auto">
<ButtonList @click="onButtonClick" />
</el-footer>
<ApprovalForm @submit="onSubmit" />
</el-container>
</template>
<style lang="scss">
.flow-form {
height: 100%;
.flow-form__title {
padding: 8px 0;
font-size: 16px;
}
.flow-form__footer {
border-top: 2px solid var(--el-border-color-light);
padding: 10px;
text-align: center;
}
.flow-form__main {
padding-top: 0;
.avue-form {
padding: 0;
}
.el-tabs {
height: 100%;
.el-tabs__content {
height: calc(100% - var(--el-tabs-header-height) - 15px);
.el-tab-pane {
height: 100%;
overflow-y: auto;
}
}
}
}
}
.flow-form-overlay {
.el-drawer__header,
.el-dialog__header {
margin: 0;
padding: 0;
.el-dialog__headerbtn {
top: 0;
z-index: 1;
}
.el-drawer__close-btn {
position: absolute;
top: 10px;
right: 10px;
z-index: 1;
}
}
.el-drawer__body,
.el-dialog__body {
margin: 0;
padding: 0;
}
}
</style>