2024-04-02 18:10:48 +08:00
|
|
|
|
## 注意事项
|
2024-04-03 15:54:15 +08:00
|
|
|
|
### 不要被框架束缚思路
|
|
|
|
|
|
框架只是个代码生成器而已,前后端代码都在你手里,只要不影响其他模块,你想怎么实现怎么实现。
|
2024-04-02 18:10:48 +08:00
|
|
|
|
### 设计相关
|
|
|
|
|
|
- 一个表单只能绑定一个流程,一个流程也只能绑定一个表单,虽然框架支持单流程带多表单,但是我们在代码中屏蔽了这部分设计,如果表单内容较多,建议以子流程、tab页、分区等方式合理显示。
|
|
|
|
|
|
- 一旦某表单绑定了流程,该表单就只能以绑定流程的方式使用(展示一个流程的纯表单部分无意义,用户一定是想和流程一起查看或者审批)
|
|
|
|
|
|
- 流程草稿在单据列表里不会显示(草稿箱中可以找到),这是延续老系统的设计,不属于bug
|
|
|
|
|
|
- 因为代码生成器的特殊性,建议在设计的时候尽可能完善,或者预留某些字段,隐藏起来以便需求调整,开发者需要评估重新生成代码与自行添加字段的工作量
|
|
|
|
|
|
### 界面与用户体验
|
|
|
|
|
|
- 设计器支持响应式布局,因为设计器架构问题,并未默认打开,对于表单内字段,除了附件、多行文本框等占用宽度较大的组件外,都建议开启响应式布局
|
|
|
|
|
|
- 表单和表格需要合理调整字段宽度,响应式布局下需要使用定宽模式,一般情况下,字段的宽度取平均字长 + 2个汉字的宽度为宜,不要留太长的label,也要避免出现label换行
|
|
|
|
|
|
|
2024-05-09 09:42:56 +08:00
|
|
|
|
## Q&A
|
|
|
|
|
|
### 为什么表单所有字段都成了必填
|
|
|
|
|
|
默认情况下,绑定流程后,新建节点的所有字段都被设置为必填,需要在流程的开始节点-表单设置中去掉非必填的项。
|
|
|
|
|
|
|
2024-04-02 18:10:48 +08:00
|
|
|
|
## 在Tab页中打开表单/流程
|
|
|
|
|
|
如果你需要自己编程实现Tab页跳转,或者升级旧版框架的页面,可以参考下面步骤:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
const { currentRoute } = useRouter();
|
|
|
|
|
|
// 获取表单的绑定的流程 schemaId通过菜单中的路由参数给出
|
|
|
|
|
|
const schemaIdComputedRef = computed(() => currentRoute.value.meta.schemaId as string);
|
|
|
|
|
|
//处理新增逻辑
|
|
|
|
|
|
function handleAdd(){
|
|
|
|
|
|
if (schemaIdComputedRef.value) {
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/flow/' + schemaIdComputedRef.value + '/0/createFlow'
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/form/bizoutapply/0/createForm',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
formPath: 'dev/bizoutapply' //这里是表单的所在目录
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 处理行的双击逻辑,其他地方可以类似处理
|
|
|
|
|
|
function dbClickRow(record) {
|
|
|
|
|
|
const workflowData = record.workflowData || {};
|
|
|
|
|
|
const { processId, taskIds, schemaId } = workflowData;
|
|
|
|
|
|
if (schemaId && taskIds) {
|
|
|
|
|
|
// 待办
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/flow/' + schemaId + '/' + processId + '/approveFlow',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
taskId: taskIds[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else if (schemaId && !taskIds) {
|
|
|
|
|
|
// 已审批的单子
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/flow/' + schemaId + '/' + processId + '/approveFlow',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
readonly: 1,
|
|
|
|
|
|
taskId: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 非流程
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/form/overtimeapply/' + record.id + '/viewForm',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
formPath: 'dev/overtimeapply' // 模块路径也要跟着改
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2024-05-09 09:42:56 +08:00
|
|
|
|
同时,因为外层封装页面需要表单加载后的元数据,需要在Form.vue中通过事件将表单数据传出。
|
2024-04-02 18:10:48 +08:00
|
|
|
|
```javascript
|
|
|
|
|
|
// 这行是原来有的
|
|
|
|
|
|
import { formProps, formEventConfigs } from './config';
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
emits('form-mounted', formProps); // 补上这一句
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
2024-04-03 15:54:15 +08:00
|
|
|
|
## 如何自定义表单字段
|
|
|
|
|
|
一般情况下,字段会和权限绑定,假设你已经解决了字段的权限问题(对于简单的数据结构,可以建一个纯文本字段,然后在前端换成自定义渲染的)。
|
|
|
|
|
|
|
|
|
|
|
|
首先我们定义一个组件,这里为了简单起见只用了一个文本框,一般情况下,你要实现v-model,同时接收disabled参数以处理只读模式。注意vue<3.4的版本并不支持defineModel。
|
|
|
|
|
|
```vue
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="custom-input">
|
|
|
|
|
|
<input style="width: 100%" v-if="!disabled" :value="props.modelValue" @change="onChange($event)" />
|
|
|
|
|
|
<span v-else style="color: #cc0000">{{ props.modelValue }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
input {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
border: 1px solid #cc0000;
|
|
|
|
|
|
line-height: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import {defineProps} from 'vue';
|
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps(['modelValue', 'disabled'])
|
|
|
|
|
|
const emit = defineEmits(['update:modelValue'])
|
|
|
|
|
|
|
|
|
|
|
|
function onChange(event) {
|
|
|
|
|
|
emit('update:modelValue', event.target.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
```
|
|
|
|
|
|
然后在表单页面Form.vue中引入该字段
|
|
|
|
|
|
```vue
|
|
|
|
|
|
<SimpleForm>
|
|
|
|
|
|
<template v-slot:addr="scope">
|
|
|
|
|
|
<FormItem :label-col="{style: {width: '120px'}}" label="出差地点">
|
|
|
|
|
|
<custom-field :disabled="scope.schema.dynamicDisabled" v-model="scope.formModel.chuChaDiDian3876"></custom-field>
|
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</SimpleForm>
|
|
|
|
|
|
```
|
|
|
|
|
|
这里需要注意的是,自定义字段中需要自行实现label部分,所以外层用了一个FormItem,如果你需要在表单中间独立成行,也可以去掉FormItem这层。
|
|
|
|
|
|
|
|
|
|
|
|
最后在config.ts中换掉字段的类型:
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
export const formProps: FormProps = {
|
|
|
|
|
|
labelCol: { span: 3, offset: 0 },
|
|
|
|
|
|
labelAlign: 'right',
|
|
|
|
|
|
layout: 'horizontal',
|
|
|
|
|
|
size: 'default',
|
|
|
|
|
|
schemas: [
|
|
|
|
|
|
{
|
|
|
|
|
|
key: '783e504378024a2c9db35b9e741eb5c3',
|
|
|
|
|
|
field: 'chuChaDiDian3876',
|
|
|
|
|
|
label: '出差地点',
|
|
|
|
|
|
type: 'slot', // type和slotName需要换掉
|
|
|
|
|
|
slotName: 'addr' // 和template中的插槽名字对应
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
## 如何自定义列表页字段
|
|
|
|
|
|
列表页的字段定义比较简单,首先在columns中补充需要的列(或者替换已有的列),然后再bodyCell插槽里替换所需的部分接即可。
|
|
|
|
|
|
```vue
|
|
|
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
|
<template v-if="column.dataIndex === 'action'">
|
|
|
|
|
|
<TableAction :actions="getActions(record)" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<!-- 下面是要定制的列 --->
|
|
|
|
|
|
<template v-if="column.dataIndex === 'chuChaDiDian3876'">
|
|
|
|
|
|
<span style="color: #f00">{{record.chuChaDiDian3876}}</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
```
|
|
|
|
|
|
注意,根据antd-vue的文档,bodyCell里除了要修改的列,不能写其他内容,否则会将内容覆盖到所有列上。
|
2024-05-09 09:42:56 +08:00
|
|
|
|
## 如何在按钮栏中刚增加按钮
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 如何修改选项卡标题
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
|
|
|
|
|
import { useRouter } from 'vue-router';
|
|
|
|
|
|
|
|
|
|
|
|
const tabStore = useMultipleTabStore();
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const currentRoute = router.currentRoute.value;
|
|
|
|
|
|
const fullPath = currentRoute.fullPath;
|
|
|
|
|
|
tabStore.changeTitle(fullPath, `选项卡标题`);
|
|
|
|
|
|
|
|
|
|
|
|
// 顺便tabStore也支持关闭选项卡
|
|
|
|
|
|
tabStore.closeTab(currentRoute, router);
|
|
|
|
|
|
```
|