Skip to content

Commit bc9c3f0

Browse files
authored
Merge pull request #2 from WeBankFinTech/feat-element-plugin
Feat element plugin
2 parents 23d9579 + 4518275 commit bc9c3f0

File tree

134 files changed

+4402
-3849
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+4402
-3849
lines changed
File renamed without changes.

README.md

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<p align="center">
2-
<!-- <a href="https://fes-design-4gvn317r3b6bfe17-1254145788.ap-shanghai.app.tcloudbase.com/"> -->
3-
<img width="362" src="./docs/public/logo.png">
2+
<a href="../../">
3+
<img alt="koala" width="250" src="./docs/public/logo.png">
44
</a>
55
</p>
66

@@ -9,8 +9,46 @@
99
<div align="center">
1010

1111
低代码表单解决方案,让你跟考拉一样“懒”
12+
13+
[![GitHub issues](https://img.shields.io/github/issues/WeBankFinTech/KoalaForm.svg?style=flat-square)](../../issues)
14+
[![MIT](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](http://opensource.org/licenses/MIT)
15+
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](../../pulls)
16+
[![Page Views Count](https://badges.toozhao.com/badges/01H51S4REBN596ZZ2BTNVV6566/green.svg)](https://badges.toozhao.com/stats/01H51S4REBN596ZZ2BTNVV6566 "Get your own page views count badge on badges.toozhao.com")
17+
1218
</div>
1319

20+
- 使用文档 - [https://koala-form.mumblefe.cn/](https://koala-form.mumblefe.cn/)
21+
- 更新日志 - [CHANGELOG.md](./CHANGELOG.md)
22+
23+
# 痛点
24+
25+
对于中后台产品的前端开发来说,最常见的场景无非是开发一个表的CURD操作
26+
27+
- Create:创建表单
28+
- Update:更新表单
29+
- Retrieve 查询表单&表格展示
30+
- Delete:删除
31+
32+
当你开发多个表单页面时,你会发现这些页面除了字段和接口不同,大概有80%的其他逻辑基本一样,但还是少不了那些胶水代码。而`Koala Form`可以帮你减少这80%的胶水代码
33+
34+
## Koala Form 是什么?
35+
36+
`Koala Form` 是一个表单页面的低代码解决方案。以Vue3为基础,围绕后台产品的表单场景进行封装,使得开发者仅需关注表单页面的字段和接口。
37+
38+
它主要具备以下特点
39+
40+
- 🚀 **高效的** ,从零开发一个完整的表单页面也许需要你花一天或者几个小时,而Koala From也许仅需几分钟,你需要做的就配置字段的展示规则。
41+
- 🧨 **简单的** ,内置基础的表单场景,`useScene`, `useFrom``useTable``useModal``usePager`, 根据传入的字段规则解析,返回场景上下文用于操作场景内容,render函数可以减少了你对UI的关注。
42+
43+
- 💪 **灵活的** ,丰富的场景可以自由组合;所有的字段也支持vueslot; 可扩展自己的插件,render自己的UI。
44+
45+
## UI库插件
46+
47+
| 插件 | 介绍 |
48+
| ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
49+
| [@koala-form/fes-plugin](https://koala-form.mumblefe.cn/zh/ui/fes.html) | Fes Design组件库的桥接插件 |
50+
| [@koala-form/element-plugin](https://koala-form.mumblefe.cn/zh/ui/element.html) | Element Plus组件库的桥接插件 |
51+
1452
## Install
1553

1654
```bash
@@ -58,6 +96,20 @@ export default {
5896
};
5997
</script>
6098
```
99+
## 反馈
100+
101+
| Github Issue | KoalaForm社区群 |
102+
| ------------------------------------ | ------------------------------------------------------------------------------------------------ |
103+
| [KoalaForm/issues](../../issues) | 微信添加好友`aring_93`,邀请进社区群 |
104+
105+
## 参与共建
106+
107+
我们非常欢迎社区同学能提交 PR:
61108

109+
1. fork 项目!
110+
2. 创建你的功能分支: `git checkout -b my-new-feature`
111+
3. 本地提交新代码: `git commit -am 'Add some feature'`
112+
4. 推送本地到服务器分支: `git push origin my-new-feature`
113+
5. 创建一个 PR
62114

63-
## 反馈
115+
如果是发现 Bug 或者期望添加新功能,请提交[issue](../../issues)

docs/.vitepress/config.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export default {
3636
alias: {
3737
'@koala-form/core': path.resolve('packages/core/src/index.ts'),
3838
'@koala-form/fes-plugin': path.resolve('packages/fes-plugin/src/index.ts'),
39+
'@koala-form/element-plugin': path.resolve('packages/element-plugin/src/index.ts'),
3940
},
4041
},
4142
json: {
@@ -66,7 +67,8 @@ export default {
6667
link: '/zh/ui',
6768
activeMatch: '^/zh/ui',
6869
items: [
69-
{ text: 'Fes Plugin', link: '/zh/ui/fes' },
70+
{ text: 'Fes Design Plugin', link: '/zh/ui/fes' },
71+
{ text: 'Element Plus Plugin', link: '/zh/ui/element' },
7072
]
7173
},
7274
// { text: '精彩示例', link: '/zh/demos/', activeMatch: '^/zh/demos' },
@@ -78,7 +80,10 @@ export default {
7880
sidebar: {
7981
'/zh/guide/': getGuideSidebar(),
8082
'/zh/ui/fes': [
81-
{ text: 'Fes Plugin', link: '/zh/ui/fes' },
83+
{ text: 'Fes Design Plugin', link: '/zh/ui/fes' },
84+
],
85+
'/zh/ui/element': [
86+
{ text: 'Element Plus Plugin', link: '/zh/ui/element' },
8287
],
8388
'/zh/demos/': getDemosSidebar(),
8489
}

docs/examples/elementCurd.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { defineComponent } from 'vue';
2+
import {
3+
ComponentType,
4+
doCloseModal,
5+
doOpenModal,
6+
doQuery,
7+
doRefresh,
8+
doResetQuery,
9+
formatByOptions,
10+
useForm,
11+
useModal,
12+
usePager,
13+
useSceneContext,
14+
useTable,
15+
} from '@koala-form/core';
16+
import { genForm, genQueryAction, genTableAction, componentPlugin } from '@koala-form/element-plugin';
17+
import { ElMessage } from 'element-plus';
18+
19+
const name = { name: 'name', label: '姓名' };
20+
const age = { name: 'age', label: '年龄' };
21+
const sex = {
22+
name: 'sex',
23+
label: '性别',
24+
options: [
25+
{ value: '0', label: '女' },
26+
{ value: '1', label: '男' },
27+
],
28+
};
29+
30+
const formFileds = [
31+
{ ...name, components: { name: ComponentType.Input } },
32+
{ ...age, components: { name: ComponentType.InputNumber } },
33+
{ ...sex, components: { name: ComponentType.Select } },
34+
];
35+
36+
export default defineComponent({
37+
setup() {
38+
const {
39+
ctxs: [query, table, pager, modal, edit],
40+
} = useSceneContext(['query', 'table', 'pager', 'modal', 'edit'], [componentPlugin]);
41+
42+
let isCreate = false;
43+
const queryActions = genQueryAction({
44+
query: () => doQuery({ api: '/user.json', form: query, table, pager }),
45+
reset: () => doResetQuery({ api: '/user.json', form: query, table, pager }),
46+
create: () => {
47+
doOpenModal({ modal, form: edit });
48+
modal.modelRef.value.title = '新增用户';
49+
isCreate = true;
50+
},
51+
});
52+
const tableAction = genTableAction({
53+
view: ({ row }) => ElMessage.info(row.name),
54+
delete: ({ row }) => {
55+
ElMessage.success('删除 ' + row.name);
56+
},
57+
update: ({ row }) => {
58+
doOpenModal({ modal, form: edit, row });
59+
modal.modelRef.value.title = '修改用户';
60+
isCreate = false;
61+
},
62+
});
63+
useForm({ ctx: query, fields: [...formFileds, queryActions], form: genForm(true) });
64+
useTable({ ctx: table, fields: [name, age, { ...sex, format: formatByOptions }, tableAction] });
65+
usePager({ ctx: pager, pager: { events: { onCurrentChange: () => doRefresh({ api: '/user.json', form: query, table, pager }) } } });
66+
useForm({ ctx: edit, fields: formFileds });
67+
useModal({
68+
ctx: modal,
69+
modal: {
70+
children: edit,
71+
events: {
72+
async onOk() {
73+
debugger;
74+
let api = '/success.json';
75+
if (isCreate) {
76+
api = '/error.json';
77+
}
78+
await doCloseModal({ api, form: edit, modal });
79+
ElMessage.success('保存成功');
80+
},
81+
},
82+
},
83+
});
84+
85+
return () => [query.render(), table.render(), pager.render(), modal.render()];
86+
},
87+
});

docs/examples/elementUseCurd.vue

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<template>
2+
<KoalaRender :render="render">
3+
<!-- 扩展查询操作 -->
4+
<template #queryActionsExtend>
5+
<ElButton type="primary" @click="doExport">导出</ElButton>
6+
<ElButton type="primary" @click="doBatch">批量</ElButton>
7+
</template>
8+
<template #tableActionsExtend="{ row }">
9+
<ElButton type="primary" link @click="doPass(row)">审核</ElButton>
10+
<ElButton type="primary" link :disabled="row.id === '2'" @click="openModal('update', { row })">更新</ElButton>
11+
</template>
12+
</KoalaRender>
13+
</template>
14+
15+
<script setup>
16+
import { ComponentType, KoalaRender, doGetFormData, useSceneContext } from '@koala-form/core';
17+
import { useCurd, mapTableFields, componentPlugin } from '@koala-form/element-plugin';
18+
import { computed } from 'vue';
19+
import { ElButton, ElMessage } from 'element-plus';
20+
const sexOptions = [
21+
{ value: '0', label: '' },
22+
{ value: '1', label: '' },
23+
];
24+
25+
const educationOptions = [
26+
{ value: '1', label: '高中以下' },
27+
{ value: '2', label: '大专' },
28+
{ value: '3', label: '大学本科' },
29+
{ value: '4', label: '研究生' },
30+
{ value: '5', label: '其他' },
31+
];
32+
33+
const hobbyOptions = [
34+
{ value: '1', label: '' },
35+
{ value: '2', label: '' },
36+
{ value: '3', label: 'rap' },
37+
{ value: '4', label: '篮球' },
38+
];
39+
40+
const FIELDS = {
41+
id: { name: 'id', label: '编号', format: (model, value) => value },
42+
name: { name: 'name', label: '姓名', components: { name: ComponentType.Input } },
43+
age: { name: 'age', label: '年龄', components: { name: ComponentType.InputNumber } },
44+
sex: { name: 'sex', label: '性别', options: sexOptions, components: { name: ComponentType.Select } },
45+
hobby: { name: 'hobby', type: 'array', label: '爱好', options: hobbyOptions, components: { name: ComponentType.CheckboxGroup } },
46+
birthday: { name: 'birthday', label: '出生日期', components: { name: ComponentType.DatePicker, props: { type: 'daterange' } } },
47+
idCard: { name: 'idCard', label: '身份证', components: { name: ComponentType.Input } },
48+
education: { name: 'education', label: '学历', options: educationOptions, components: { name: ComponentType.Select } },
49+
degree: { name: 'degree', label: '学位', components: { name: ComponentType.Input } },
50+
address: { name: 'address', label: '住址', components: { name: ComponentType.Input, props: { type: 'textarea' } } },
51+
};
52+
53+
const {
54+
ctxs: [query, table, pager, modal, edit],
55+
} = useSceneContext(['query', 'table', 'pager', 'modal', 'edit'], [componentPlugin]);
56+
57+
const showDegree = computed(() => ['2', '3', '4'].includes(edit.modelRef.value.education));
58+
59+
const { render, editTypeRef, selectedRows, openModal } = useCurd({
60+
name: '用户',
61+
query: {
62+
ctx: query,
63+
fields: [FIELDS.name, FIELDS.sex, FIELDS.birthday],
64+
},
65+
table: {
66+
ctx: table,
67+
rowKey: 'id',
68+
selection: { props: { fixed: true, width: 50 } },
69+
actionField: { props: { fixed: 'right', width: 320 } },
70+
fields: mapTableFields(
71+
[
72+
{ ...FIELDS.id, props: { fixed: true, width: 80 } },
73+
FIELDS.name,
74+
FIELDS.age,
75+
FIELDS.sex,
76+
FIELDS.hobby,
77+
{ ...FIELDS.idCard, format: (model, value) => value && '****' + value.slice(14) },
78+
FIELDS.birthday,
79+
FIELDS.education,
80+
{ ...FIELDS.address, props: { width: 300 } },
81+
],
82+
{ props: { width: 150 } },
83+
),
84+
},
85+
pager: { ctx: pager },
86+
edit: {
87+
ctx: edit,
88+
fields: [
89+
{ ...FIELDS.id, vIf: computed(() => editTypeRef.value !== 'create') },
90+
{ ...FIELDS.name, required: true },
91+
FIELDS.age,
92+
FIELDS.sex,
93+
FIELDS.education,
94+
FIELDS.hobby,
95+
FIELDS.idCard,
96+
{ ...FIELDS.birthday, components: { name: ComponentType.DatePicker } },
97+
{ ...FIELDS.degree, vIf: showDegree },
98+
FIELDS.address,
99+
],
100+
},
101+
modal: { ctx: modal },
102+
actions: {
103+
query: {
104+
api: '/user.json',
105+
},
106+
create: {
107+
api: '/success.json',
108+
},
109+
reset: {},
110+
update: {
111+
hidden: true, // 更新按钮修改行数据判断时,可以隐藏默认更新按钮,在template实现
112+
api: '/error.json',
113+
},
114+
delete: {
115+
api: '/success.json',
116+
},
117+
view: {},
118+
},
119+
});
120+
121+
// 插件局部安装
122+
query.use(componentPlugin);
123+
table.use(componentPlugin);
124+
pager.use(componentPlugin);
125+
modal.use(componentPlugin);
126+
edit.use(componentPlugin);
127+
128+
const doExport = () => {
129+
ElMessage.success('导出');
130+
console.log('导出', doGetFormData(query));
131+
};
132+
133+
const doBatch = () => {
134+
if (!selectedRows.value?.length) {
135+
ElMessage.error('至少选择一条记录');
136+
return;
137+
}
138+
ElMessage.success('批量操作 ==> ids: ' + selectedRows.value);
139+
console.log('批量操作', selectedRows.value);
140+
};
141+
142+
const doPass = (record) => {
143+
ElMessage.success('审核 ===> ' + record.name);
144+
console.log(record);
145+
};
146+
</script>

docs/examples/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import FesdUseCurd from './fesdUseCurd.vue';
2525

2626
import LabelPlugin from './labelPlugin';
2727

28+
import ElementCurd from './elementCurd';
29+
import ElementUseCurd from './elementUseCurd.vue';
30+
2831
export default {
2932
// Test,
3033
StartedSceneVue,
@@ -47,6 +50,8 @@ export default {
4750
FesdCurd,
4851
FesdUseCurd,
4952
LabelPlugin,
53+
ElementCurd,
54+
ElementUseCurd,
5055
// User,
5156
// UseForm,
5257
// UseFormSlots,

docs/zh/guide/base/component.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface ComponentDesc {
1515
disabled?: Ref<boolean> | When;
1616
events?: Record<string, (value: any, ...args: any[]) => void>;
1717
slotName?: string;
18+
slots?: Slots; // version >= 2.0.1
1819
children?: Array<string | ComponentDesc | SceneContext> | string | ComponentDesc | SceneContext;
1920
}
2021
```

docs/zh/guide/base/field.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface Field {
2020
required?: boolean | Ref<boolean>;
2121
components?: ComponentDesc | ComponentDesc[];
2222
slotName?: string;
23+
slots?: Slots; // version >= 2.0.1
2324
format?: (model: any, value: any, scheme: Scheme) => VNodeChild | string;
2425
}
2526
```

docs/zh/guide/plugin/how.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ import { useSceneContext } from '@koala-form/core';
8080
const { ctx } = useSceneContext(['form'])
8181

8282
ctx.use(formLabelColonPlugin)
83+
84+
85+
// 多场景安装 version >= 2.0.1
86+
useSceneContext(['form', 'table'], [formLabelColonPlugin])
87+
8388
```
8489

8590
运行示例效果

docs/zh/guide/scene/useScene.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ useForm({ ctx })
5555
const { ctxs: [form, table] } = useSceneContext(['form', 'table']);
5656
useForm({ ctx: form })
5757
useTable({ ctx: table })
58+
5859
```

0 commit comments

Comments
 (0)