mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2025-12-10 11:52:53 +00:00
1820 lines
32 KiB
Plaintext
1820 lines
32 KiB
Plaintext
---
|
||
description: cl-form 组件示例
|
||
globs: *.tsx, *.ts, *.vue
|
||
---
|
||
## 层级显示 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>children</el-tag>
|
||
<span>层级显示</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/children.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '层级显示',
|
||
items: [
|
||
{
|
||
label: '姓名',
|
||
prop: 'name',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
label: '年龄',
|
||
prop: 'age',
|
||
value: 18,
|
||
component: {
|
||
name: 'el-input-number'
|
||
}
|
||
},
|
||
|
||
// 基础信息
|
||
{
|
||
component: {
|
||
//【很重要】使用 cl-form-card 组件渲染,也可以使用自定义
|
||
name: 'cl-form-card',
|
||
props: {
|
||
// 标题
|
||
label: '基础信息',
|
||
// 是否展开,默认 true
|
||
expand: true
|
||
}
|
||
},
|
||
children: [
|
||
{
|
||
label: '账号',
|
||
prop: 'account',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
label: '密码',
|
||
prop: 'password',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
]
|
||
},
|
||
|
||
// 其他信息
|
||
{
|
||
component: {
|
||
name: 'cl-form-card',
|
||
props: {
|
||
label: '其他信息',
|
||
expand: false
|
||
}
|
||
},
|
||
children: [
|
||
{
|
||
label: '身份证',
|
||
prop: 'idcard',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
label: '学校',
|
||
prop: 'school',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
label: '专业',
|
||
prop: 'major',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
]
|
||
}
|
||
],
|
||
on: {
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 组件渲染 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>component</el-tag>
|
||
<span>组件渲染</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code
|
||
:files="[
|
||
'form/component/index.vue',
|
||
'form/component/select-labels.vue',
|
||
'form/component/select-status.vue',
|
||
'form/component/select-work.vue',
|
||
'form/component/select-work2.vue'
|
||
]"
|
||
/>
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form">
|
||
<!-- 年龄插槽 -->
|
||
<template #slot-age="{ scope }">
|
||
<!-- scope 为表单值 -->
|
||
<el-input-number v-model="scope.age" :min="18" :max="100"></el-input-number>
|
||
</template>
|
||
</cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
import { ElMessage } from 'element-plus';
|
||
import SelectWork from './select-work2.vue';
|
||
import SelectLabels from './select-labels.vue';
|
||
import SelectStatus from './select-status.vue';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '组件配置',
|
||
|
||
items: [
|
||
{
|
||
label: '昵称',
|
||
prop: 'name',
|
||
// 组件配置方式1:标签名(方便,但是不建议组件全局注册)
|
||
value: '神仙',
|
||
component: {
|
||
// 必须是“全局注册”的组件名,如 element-plus 的 el-input、el-date-picker 等
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
label: '手机号',
|
||
prop: 'phone',
|
||
value: '13255022000',
|
||
component: {
|
||
name: 'el-input',
|
||
// 自定义插槽
|
||
slots: {
|
||
prepend() {
|
||
return '+86';
|
||
}
|
||
}
|
||
}
|
||
},
|
||
{
|
||
label: '年龄',
|
||
prop: 'age',
|
||
// 组件配置方式2:插槽(万能,就是代码多写点)
|
||
value: 18,
|
||
component: {
|
||
// 必须是 "slot-" 开头
|
||
name: 'slot-age'
|
||
}
|
||
},
|
||
// -- start 组件配置方式3:组件实例(不想全局注册,但又想组件化)
|
||
{
|
||
label: '工作',
|
||
prop: 'work',
|
||
value: '设计',
|
||
component: {
|
||
// 双向绑定
|
||
vm: SelectWork
|
||
}
|
||
},
|
||
{
|
||
label: '标签',
|
||
prop: 'labels',
|
||
value: ['多金', '深情'],
|
||
component: {
|
||
// scope[prop]绑定
|
||
vm: SelectLabels
|
||
}
|
||
},
|
||
{
|
||
label: '状态',
|
||
prop: 'status',
|
||
value: 1,
|
||
component: {
|
||
// useForm 绑定
|
||
vm: SelectStatus
|
||
}
|
||
}
|
||
// -- end
|
||
],
|
||
on: {
|
||
submit(data, { close }) {
|
||
ElMessage.info(
|
||
`${data.name || '无名'}(${data.age || 18}岁)工作:${data.work || '无'}`
|
||
);
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## select-labels 示例
|
||
|
||
```vue
|
||
<template>
|
||
<!--【很重要】直接绑定表单值 scope[prop] -->
|
||
<!-- !符号,只是为了类型提示不错误 -->
|
||
<el-select v-model="scope[prop!]" multiple>
|
||
<el-option
|
||
v-for="(item, index) in list"
|
||
:key="index"
|
||
:label="item.label"
|
||
:value="item.label"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
|
||
<!--【很重要】必须要有name,避免注册后和其他冲突 -->
|
||
<script setup lang="ts">
|
||
defineOptions({
|
||
name: 'select-labels'
|
||
});
|
||
|
||
import { ref } from 'vue';
|
||
|
||
const props = defineProps({
|
||
scope: null, // 表单值
|
||
prop: String // 表单项配置的 prop
|
||
});
|
||
|
||
// 选项列表
|
||
const list = ref<{ label: string; value: string }[]>([
|
||
{
|
||
label: '帅气',
|
||
value: '帅气' // 测试直接使用label,真实情况可能是1,2,3,4或者id
|
||
},
|
||
{
|
||
label: '多金',
|
||
value: '多金'
|
||
},
|
||
{
|
||
label: '深情',
|
||
value: '深情'
|
||
}
|
||
]);
|
||
</script>
|
||
|
||
```
|
||
|
||
## select-status 示例
|
||
|
||
```vue
|
||
<template>
|
||
<!--【很重要】直接绑定status,或者使用 form[prop!] -->
|
||
<el-radio-group v-model="form.status">
|
||
<el-radio v-for="(item, index) in list" :key="index" :value="item.value">
|
||
{{ item.label }}
|
||
</el-radio>
|
||
</el-radio-group>
|
||
</template>
|
||
|
||
<!--【很重要】必须要有name,避免注册后和其他冲突 -->
|
||
<script setup lang="ts">
|
||
defineOptions({
|
||
name: 'select-status'
|
||
});
|
||
|
||
import { useForm } from '@cool-vue/crud';
|
||
import { computed, ref } from 'vue';
|
||
|
||
const props = defineProps({
|
||
scope: null, // 表单值
|
||
prop: String // 表单项配置的 prop
|
||
});
|
||
|
||
// 使用 useForm,能直接获取到上级的表单实例,
|
||
// 比如操作表单的 Form.value?.submit、Form.value?.close等
|
||
// 获取表单值,Form.value?.form
|
||
const Form = useForm();
|
||
|
||
// 表单值,包一层不会太难受
|
||
const form = computed(() => Form.value?.form || {});
|
||
|
||
// 选项列表
|
||
const list = ref<{ label: string; value: number }[]>([
|
||
{
|
||
label: '很好',
|
||
value: 1
|
||
},
|
||
{
|
||
label: '不舒服',
|
||
value: 2
|
||
},
|
||
{
|
||
label: '要嘎了',
|
||
value: 3
|
||
}
|
||
]);
|
||
</script>
|
||
|
||
```
|
||
|
||
## select-work 示例
|
||
|
||
```vue
|
||
<template>
|
||
<el-select v-model="active" @change="onChange">
|
||
<el-option
|
||
v-for="(item, index) in list"
|
||
:key="index"
|
||
:label="item.label"
|
||
:value="item.label"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
|
||
<!-- 【很重要】必须要有name,避免注册后和其他冲突 -->
|
||
<script setup lang="ts">
|
||
defineOptions({
|
||
name: 'select-work'
|
||
});
|
||
|
||
import { ref, watch } from 'vue';
|
||
|
||
const props = defineProps({
|
||
modelValue: String
|
||
});
|
||
|
||
const emit = defineEmits(['update:modelValue', 'change']);
|
||
|
||
//【很重要】绑定值
|
||
// 这种方式虽然麻烦,但是可扩展性高,一些复杂的数据结构可以按这种方式绑定值
|
||
const active = ref();
|
||
|
||
// 选项列表
|
||
const list = ref<{ label: string; value: string }[]>([
|
||
{
|
||
label: '倒茶',
|
||
value: '倒茶' // 测试直接使用label,真实情况可能是1,2,3,4或者id
|
||
},
|
||
{
|
||
label: '设计',
|
||
value: '设计'
|
||
},
|
||
{
|
||
label: '开发',
|
||
value: '开发'
|
||
}
|
||
]);
|
||
|
||
//【很重要】更新绑定值,表单提交才能得到选择后的
|
||
function onChange(val: string) {
|
||
emit('update:modelValue', val);
|
||
emit('change', val);
|
||
}
|
||
|
||
//【很重要】使用监听的方式,避免表单打开数据是异步获取的情况
|
||
watch(
|
||
() => props.modelValue,
|
||
val => {
|
||
// 设置选中的值
|
||
active.value = val;
|
||
},
|
||
{
|
||
immediate: true
|
||
}
|
||
);
|
||
</script>
|
||
|
||
```
|
||
|
||
## select-work2 示例
|
||
|
||
```vue
|
||
<template>
|
||
<el-select v-model="active">
|
||
<el-option
|
||
v-for="(item, index) in list"
|
||
:key="index"
|
||
:label="item.label"
|
||
:value="item.label"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
|
||
<!-- 【很重要】必须要有name,避免注册后和其他冲突 -->
|
||
<script setup lang="ts">
|
||
defineOptions({
|
||
name: 'select-work2'
|
||
});
|
||
|
||
import { ref, useModel } from 'vue';
|
||
|
||
const props = defineProps({
|
||
modelValue: String
|
||
});
|
||
|
||
//【很重要】绑定值,使用 useModel 的方式双向绑定
|
||
const active = useModel(props, 'modelValue');
|
||
|
||
// 选项列表
|
||
const list = ref<{ label: string; value: string }[]>([
|
||
{
|
||
label: '倒茶',
|
||
value: '倒茶' // 测试直接使用label,真实情况可能是1,2,3,4或者id
|
||
},
|
||
{
|
||
label: '设计',
|
||
value: '设计'
|
||
},
|
||
{
|
||
label: '开发',
|
||
value: '开发'
|
||
}
|
||
]);
|
||
</script>
|
||
|
||
```
|
||
|
||
## 参数配置 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>config</el-tag>
|
||
<span>参数配置</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/config.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form">
|
||
<!-- 按钮插槽 -->
|
||
<template #slot-btns>
|
||
<el-button type="danger">按钮插槽</el-button>
|
||
</template>
|
||
</cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
import { ElMessage } from 'element-plus';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '参数配置',
|
||
|
||
// 打开是否重置表单
|
||
isReset: false,
|
||
|
||
// 默认表单值
|
||
form: {
|
||
nickName: '神仙都没用'
|
||
},
|
||
|
||
// 表单配置
|
||
props: {
|
||
// 标签宽度
|
||
labelWidth: '120px',
|
||
|
||
// 标签位置
|
||
labelPosition: 'top'
|
||
},
|
||
|
||
// 窗口的高。配置后,在窗口内部滚动。默认整个页面滚动
|
||
height: '60vh',
|
||
|
||
// 窗口的宽,默认 50%
|
||
width: '60%',
|
||
|
||
// 窗口设置
|
||
dialog: {
|
||
// 是否隐藏头部
|
||
hideHeader: false,
|
||
|
||
// 顶部操作按钮,默认["fullscreen", "close"]
|
||
// fullscreen 全屏
|
||
// close 关闭
|
||
controls: ['close']
|
||
},
|
||
|
||
// 底部操作按钮
|
||
op: {
|
||
// 默认靠右布局
|
||
justify: 'flex-end',
|
||
|
||
// 保存按钮文字
|
||
saveButtonText: '提交',
|
||
|
||
// 关闭按钮文字
|
||
closeButtonText: '关闭',
|
||
|
||
// 是否隐藏
|
||
hidden: false,
|
||
|
||
// 按钮配置
|
||
buttons: [
|
||
// 自定义
|
||
{
|
||
label: '自定义按钮',
|
||
onClick() {
|
||
ElMessage.success('自定义按钮点击');
|
||
}
|
||
},
|
||
// close 关闭
|
||
'close',
|
||
// save 保存
|
||
'save',
|
||
// 插槽使用,配合 template,往上看 cl-form 组件
|
||
'slot-btns'
|
||
]
|
||
},
|
||
|
||
// 表单项配置
|
||
items: [
|
||
{
|
||
label: '昵称',
|
||
prop: 'nickName',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
],
|
||
|
||
// 事件
|
||
on: {
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 内嵌CRUD 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>crud</el-tag>
|
||
<span>内嵌CRUD</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/crud.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form">
|
||
<template #slot-crud>
|
||
<cl-crud ref="Crud" border>
|
||
<cl-row>
|
||
<!-- 刷新按钮 -->
|
||
<cl-refresh-btn />
|
||
<!-- 新增按钮 -->
|
||
<cl-add-btn />
|
||
<!-- 删除按钮 -->
|
||
<cl-multi-delete-btn />
|
||
<cl-flex1 />
|
||
<!-- 关键字搜索 -->
|
||
<cl-search-key placeholder="搜索姓名、手机号" />
|
||
</cl-row>
|
||
|
||
<cl-row>
|
||
<!-- 数据表格 -->
|
||
<cl-table ref="Table" />
|
||
</cl-row>
|
||
|
||
<cl-row>
|
||
<cl-flex1 />
|
||
<!-- 分页控件 -->
|
||
<cl-pagination />
|
||
</cl-row>
|
||
|
||
<!-- 新增、编辑 -->
|
||
<cl-upsert ref="Upsert" />
|
||
</cl-crud>
|
||
</template>
|
||
</cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useCrud, useForm, useTable, useUpsert } from '@cool-vue/crud';
|
||
|
||
// cl-upsert
|
||
const Upsert = useUpsert({
|
||
items: [
|
||
{
|
||
label: '姓名',
|
||
prop: 'name',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
label: '创建时间',
|
||
prop: 'createTime',
|
||
component: {
|
||
name: 'el-date-picker'
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
// cl-table
|
||
const Table = useTable({
|
||
autoHeight: false,
|
||
columns: [
|
||
{
|
||
type: 'selection'
|
||
},
|
||
{
|
||
label: '姓名',
|
||
prop: 'name',
|
||
minWidth: 140
|
||
},
|
||
{
|
||
label: '手机号',
|
||
prop: 'phone',
|
||
minWidth: 140
|
||
},
|
||
{
|
||
type: 'op'
|
||
}
|
||
]
|
||
});
|
||
|
||
// cl-crud
|
||
const Crud = useCrud(
|
||
{
|
||
service: 'test'
|
||
},
|
||
app => {
|
||
app.refresh({
|
||
size: 10
|
||
});
|
||
}
|
||
);
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '内嵌CRUD',
|
||
props: {
|
||
labelPosition: 'top'
|
||
},
|
||
dialog: {
|
||
height: '70vh',
|
||
width: '1000px'
|
||
},
|
||
items: [
|
||
{
|
||
label: '姓名',
|
||
prop: 'name',
|
||
component: {
|
||
name: 'el-input',
|
||
props: {
|
||
placeholder: '请填写姓名'
|
||
}
|
||
},
|
||
rules: {
|
||
required: true,
|
||
message: '姓名不能为空'
|
||
}
|
||
},
|
||
{
|
||
label: '内嵌 cl-crud',
|
||
component: {
|
||
name: 'slot-crud'
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
submit() {
|
||
Form.value?.close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 组件禁用 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>disabled</el-tag>
|
||
<span>组件禁用</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/disabled.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '组件禁用',
|
||
items: [
|
||
{
|
||
label: '账号',
|
||
prop: 'account',
|
||
component: {
|
||
name: 'el-input',
|
||
props: {
|
||
// 设置 boolean 值控制组件的禁用状态(前提是组件支持这个参数,element 的组件几乎都有)
|
||
disabled: true
|
||
}
|
||
}
|
||
},
|
||
{
|
||
label: '密码',
|
||
prop: 'password',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
open() {
|
||
// 通用 setProps 方法去设置 disabled, 1.5s后禁用
|
||
setTimeout(() => {
|
||
Form.value?.setProps('password', { disabled: true });
|
||
}, 1500);
|
||
},
|
||
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 组件事件 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>event</el-tag>
|
||
<span>组件事件</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/event.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
import { ElMessage } from 'element-plus';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '组件事件',
|
||
items: [
|
||
{
|
||
label: '账号',
|
||
prop: 'account',
|
||
component: {
|
||
name: 'el-input',
|
||
props: {
|
||
// 组件内 emit 的用 on[name] 接收,如 onChange、onInput、onBlur 等
|
||
// 前提是组件内有触发事件
|
||
onBlur() {
|
||
ElMessage.info('账号检查中');
|
||
}
|
||
}
|
||
}
|
||
},
|
||
{
|
||
label: '是否实名',
|
||
prop: 'status',
|
||
value: 1,
|
||
component: {
|
||
name: 'el-radio-group',
|
||
options: [
|
||
{
|
||
label: '关闭',
|
||
value: 0
|
||
},
|
||
{
|
||
label: '开启',
|
||
value: 1
|
||
}
|
||
],
|
||
props: {
|
||
// 值改变事件
|
||
onChange(val: number) {
|
||
if (val == 1) {
|
||
// 显示表单项
|
||
Form.value?.showItem('idcard');
|
||
} else {
|
||
// 隐藏表单项
|
||
Form.value?.hideItem('idcard');
|
||
// 清空值
|
||
Form.value?.setForm('idcard', undefined);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
{
|
||
label: '身份证',
|
||
prop: 'idcard',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 分组显示 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>group</el-tag>
|
||
<span>分组显示</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/group.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '分组显示',
|
||
items: [
|
||
{
|
||
//【很重要】必须为 tabs
|
||
type: 'tabs',
|
||
props: {
|
||
// 分组样式
|
||
type: 'card',
|
||
// 分组列表,必须是 { label, value } 的数组格式
|
||
labels: [
|
||
{
|
||
label: '基础信息', // 标题
|
||
value: 'base' // 唯一标识
|
||
},
|
||
{
|
||
label: '认证信息',
|
||
value: 'auth'
|
||
}
|
||
]
|
||
}
|
||
},
|
||
// 基础信息
|
||
{
|
||
group: 'base', // 标识
|
||
label: '账号',
|
||
prop: 'account',
|
||
required: true,
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
group: 'base', // 标识
|
||
label: '密码',
|
||
prop: 'password',
|
||
required: true,
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
|
||
// 其他信息 group = other
|
||
{
|
||
group: 'auth', // 标识
|
||
label: '身份证',
|
||
prop: 'idcard',
|
||
required: true,
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
group: 'auth', // 标识
|
||
label: '学校',
|
||
prop: 'school',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
group: 'auth', // 标识
|
||
label: '专业',
|
||
prop: 'major',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
//【提示】当第一组验证通过后,会自动切换到下一组展示,直到全部通过才可提交
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 隐藏/显示 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>hidden</el-tag>
|
||
<span>隐藏/显示</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/hidden.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '隐藏/显示',
|
||
items: [
|
||
{
|
||
label: '状态',
|
||
prop: 'status',
|
||
value: 0,
|
||
component: {
|
||
name: 'el-radio-group',
|
||
options: [
|
||
{
|
||
label: '关闭',
|
||
value: 0
|
||
},
|
||
{
|
||
label: '开启',
|
||
value: 1
|
||
}
|
||
]
|
||
}
|
||
},
|
||
{
|
||
label: '账号',
|
||
prop: 'account',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
//【很重要】是否隐藏
|
||
hidden({ scope }) {
|
||
// scope 为表单值
|
||
// 返回一个 boolean 来控制当前表单项的隐藏/显示
|
||
return scope.status != 1;
|
||
},
|
||
label: '密码',
|
||
prop: 'password',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 布局 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>layout</el-tag>
|
||
<span>布局</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/layout.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '布局',
|
||
items: [
|
||
{
|
||
//【span】参考文档:https://element-plus.gitee.io/zh-CN/component/layout.html
|
||
// 使用 1/24 分栏,默认 24
|
||
span: 12,
|
||
label: '昵称',
|
||
prop: 'nickname',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
span: 12,
|
||
label: '手机号',
|
||
prop: 'phone',
|
||
component: {
|
||
name: 'el-input',
|
||
props: {
|
||
maxlength: 11
|
||
}
|
||
}
|
||
},
|
||
{
|
||
//【flex】使宽度不填充满
|
||
flex: false,
|
||
label: '标签',
|
||
prop: 'label',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
label: '状态',
|
||
prop: 'status',
|
||
value: 1,
|
||
component: {
|
||
name: 'el-radio-group',
|
||
options: [
|
||
{
|
||
label: '开启',
|
||
value: 1
|
||
},
|
||
{
|
||
label: '关闭',
|
||
value: 0
|
||
}
|
||
]
|
||
}
|
||
},
|
||
{
|
||
label: '备注',
|
||
prop: 'remark',
|
||
component: {
|
||
name: 'el-input',
|
||
props: {
|
||
type: 'textarea',
|
||
rows: 4
|
||
}
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 起步 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>open</el-tag>
|
||
<span>起步</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/open.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<!--【很重要】ref 一定要对应 useForm 定义的值 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="tsx">
|
||
import { useForm } from '@cool-vue/crud';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '起步',
|
||
|
||
items: [
|
||
{
|
||
label: '昵称',
|
||
// 绑定值的标识,表单提交及回显会自动根据 prop 获取对应的值
|
||
prop: 'nickname',
|
||
// 组件绑定
|
||
component: {
|
||
// 必须是“全局注册”的组件名,如 element-plus 的 el-input、el-date-picker 等
|
||
name: 'el-input',
|
||
|
||
// 绑定的组件参数配置,如 clearable、placeholder 等
|
||
// 组件内 emit 的用 on[name] 接收,如 onChange、onInput、onBlur 等
|
||
props: {
|
||
placeholder: '请输入昵称',
|
||
clearable: true,
|
||
onChange(value: string) {}
|
||
}
|
||
}
|
||
},
|
||
{
|
||
prop: 'age',
|
||
component: {
|
||
name: 'el-input-number'
|
||
},
|
||
// 默认值,第一次打开有效
|
||
value: 18
|
||
}
|
||
],
|
||
on: {
|
||
// 打开时触发
|
||
open() {
|
||
console.log(Form.value?.validateField);
|
||
},
|
||
|
||
// 关闭时触发。当配置该方法时,关闭事件会被阻断,使用 done() 关闭窗口
|
||
close(action, done) {
|
||
// action 为关闭窗口的触发动作 "save" | "close"
|
||
// done 关闭事件
|
||
done();
|
||
},
|
||
|
||
// 提交时触发
|
||
submit(data, { done, close }) {
|
||
// data 为表单值
|
||
// done 关闭加载事件、但不关闭窗口
|
||
// close 关闭窗口
|
||
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 选项框配置 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>options</el-tag>
|
||
<span>选项框配置</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/options.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
import { computed, reactive } from 'vue';
|
||
|
||
const Form = useForm();
|
||
|
||
// 觉得麻烦就 any,如 { user: [] as any[] }
|
||
const options = reactive<{ [key: string]: { label: string; value: any }[] }>({
|
||
user: []
|
||
});
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '选项框配置',
|
||
items: [
|
||
{
|
||
label: '下拉框',
|
||
prop: 'select',
|
||
component: {
|
||
name: 'el-select',
|
||
props: {
|
||
clearable: true // 可清除
|
||
},
|
||
options: [
|
||
{
|
||
label: 'javascript',
|
||
value: 1
|
||
},
|
||
{
|
||
label: 'vue',
|
||
value: 2
|
||
},
|
||
{
|
||
label: 'html',
|
||
value: 3
|
||
},
|
||
{
|
||
label: 'css',
|
||
value: 4
|
||
}
|
||
]
|
||
}
|
||
},
|
||
{
|
||
label: '单选框',
|
||
prop: 'radio',
|
||
value: 1,
|
||
component: {
|
||
name: 'el-radio-group',
|
||
options: [
|
||
{
|
||
label: '手机',
|
||
value: 1
|
||
},
|
||
{
|
||
label: '电脑',
|
||
value: 2
|
||
},
|
||
{
|
||
label: '电视',
|
||
value: 3
|
||
}
|
||
]
|
||
}
|
||
},
|
||
{
|
||
label: '多选框',
|
||
prop: 'checkbox',
|
||
value: [2, 3],
|
||
component: {
|
||
name: 'el-checkbox-group',
|
||
options: [
|
||
{
|
||
label: '咖啡',
|
||
value: 1
|
||
},
|
||
{
|
||
label: '汉堡',
|
||
value: 2
|
||
},
|
||
{
|
||
label: '炸鸡',
|
||
value: 3
|
||
},
|
||
{
|
||
label: '奶茶',
|
||
value: 4
|
||
}
|
||
]
|
||
}
|
||
},
|
||
{
|
||
label: '动态配置1',
|
||
prop: 'd1',
|
||
component: {
|
||
name: 'el-select',
|
||
// 动态设置方法1,在 on.open 事件配置 options
|
||
options: []
|
||
}
|
||
},
|
||
{
|
||
label: '动态配置2',
|
||
prop: 'd2',
|
||
component: {
|
||
name: 'el-select',
|
||
// 动态设置方法2,使用 computed 更新 options
|
||
options: computed(() => options.user)
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
open() {
|
||
// 模拟 1.5s 后取的数据
|
||
setTimeout(() => {
|
||
// 动态设置方法1,使用 setOptions 方法设置
|
||
// d1 为 prop 值
|
||
Form.value?.setOptions('d1', [
|
||
{
|
||
label: '😊',
|
||
value: 1
|
||
},
|
||
{
|
||
label: '😭',
|
||
value: 2
|
||
},
|
||
{
|
||
label: '😘',
|
||
value: 3
|
||
}
|
||
]);
|
||
|
||
// 动态设置方法2,直接设置 options.user,由 computed 更新
|
||
options.user = [
|
||
{
|
||
label: '💰',
|
||
value: 1
|
||
},
|
||
{
|
||
label: '🚗',
|
||
value: 2
|
||
}
|
||
];
|
||
}, 1500);
|
||
},
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 插件的使用 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>plugin</el-tag>
|
||
<span>插件的使用</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open('manager')">管理者</el-button>
|
||
<el-button @click="open('user')">用户</el-button>
|
||
<demo-code :files="['form/plugin/index.vue', 'form/plugin/role.ts']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
import { setRole } from './role';
|
||
|
||
const Form = useForm();
|
||
|
||
function open(role: string) {
|
||
Form.value?.open(
|
||
{
|
||
title: '插件的使用',
|
||
|
||
items: [
|
||
{
|
||
label: '姓名',
|
||
prop: 'name',
|
||
required: true,
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
},
|
||
{
|
||
// 自定义参数 role,匹配插件传入的角色
|
||
role: 'user',
|
||
label: '面试职位',
|
||
prop: 'work',
|
||
value: 1,
|
||
component: {
|
||
name: 'el-radio-group',
|
||
options: [
|
||
{
|
||
label: '前端开发',
|
||
value: 1
|
||
},
|
||
{
|
||
label: '后端开发',
|
||
value: 2
|
||
},
|
||
{
|
||
label: 'UI设计',
|
||
value: 3
|
||
}
|
||
]
|
||
}
|
||
},
|
||
{
|
||
role: 'user',
|
||
label: '期望薪资',
|
||
prop: 'salary',
|
||
value: 5000,
|
||
component: {
|
||
name: 'el-input-number',
|
||
props: {
|
||
min: 2000,
|
||
max: 100000
|
||
}
|
||
}
|
||
},
|
||
{
|
||
role: 'manager',
|
||
label: '入职时间',
|
||
prop: 'date',
|
||
component: {
|
||
name: 'el-date-picker'
|
||
}
|
||
},
|
||
{
|
||
role: 'manager',
|
||
label: '负责人',
|
||
prop: 'head',
|
||
component: {
|
||
name: 'el-input'
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
submit(data, { done, close }) {
|
||
close();
|
||
}
|
||
}
|
||
},
|
||
[
|
||
// 自定义插件,角色权限控制
|
||
setRole(role)
|
||
]
|
||
);
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 必填项配置 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>required</el-tag>
|
||
<span>必填项配置</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/required.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form"></cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '必填项配置',
|
||
items: [
|
||
{
|
||
label: '昵称',
|
||
prop: 'nickname',
|
||
component: {
|
||
name: 'el-input'
|
||
},
|
||
// 是否必填,默认判断绑定值是否空
|
||
required: true
|
||
},
|
||
{
|
||
label: '手机号',
|
||
prop: 'phone',
|
||
component: {
|
||
name: 'el-input',
|
||
props: {
|
||
maxlength: 11
|
||
}
|
||
},
|
||
// 自定义规则
|
||
// 基础用法可参考:https://element-plus.gitee.io/zh-CN/component/form.html
|
||
// 高级用法可参考:https://github.com/yiminghe/async-validator
|
||
rules: [
|
||
{
|
||
required: true,
|
||
validator: (rule, value, callback) => {
|
||
if (value === '') {
|
||
callback(new Error('手机号不能为空'));
|
||
} else if (!/^1[3456789]\d{9}$/.test(value)) {
|
||
callback(new Error('手机号格式错误'));
|
||
} else {
|
||
callback();
|
||
}
|
||
}
|
||
}
|
||
]
|
||
}
|
||
],
|
||
on: {
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
```
|
||
|
||
## 添加/删除表单项 示例
|
||
|
||
```vue
|
||
<template>
|
||
<div class="scope">
|
||
<div class="h">
|
||
<el-tag size="small" effect="dark" disable-transitions>rules</el-tag>
|
||
<span>添加/删除表单项</span>
|
||
</div>
|
||
|
||
<div class="c">
|
||
<el-button @click="open">预览</el-button>
|
||
<demo-code :files="['form/rules.vue']" />
|
||
|
||
<!-- 自定义表单组件 -->
|
||
<cl-form ref="Form">
|
||
<template #slot-cert="{ scope }">
|
||
<div class="cert">
|
||
<!--【很重要】prop、rules 配置格式如下 -->
|
||
<el-form-item
|
||
v-for="(item, index) in scope.cert"
|
||
:key="index"
|
||
:label="`证书${index + 1}`"
|
||
:prop="`cert.${index}.label`"
|
||
:rules="{
|
||
message: `请填写证书${index + 1}`,
|
||
required: true
|
||
}"
|
||
>
|
||
<div class="row">
|
||
<!-- 输入框 -->
|
||
<el-input v-model="item.label" placeholder="请填写证书"></el-input>
|
||
|
||
<!-- 删除行 -->
|
||
<el-icon @click="rowDel(index)">
|
||
<delete />
|
||
</el-icon>
|
||
</div>
|
||
</el-form-item>
|
||
|
||
<!-- 添加行 -->
|
||
<el-row type="flex" justify="end">
|
||
<el-button @click="rowAdd()">添加证书</el-button>
|
||
</el-row>
|
||
</div>
|
||
</template>
|
||
</cl-form>
|
||
</div>
|
||
|
||
<div class="f">
|
||
<span class="date">2024-01-01</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { useForm } from '@cool-vue/crud';
|
||
import { Delete } from '@element-plus/icons-vue';
|
||
|
||
const Form = useForm();
|
||
|
||
function open() {
|
||
Form.value?.open({
|
||
title: '添加/删除表单项',
|
||
items: [
|
||
{
|
||
label: '昵称',
|
||
prop: 'nickname',
|
||
component: {
|
||
name: 'el-input'
|
||
},
|
||
required: true
|
||
},
|
||
{
|
||
prop: 'cert',
|
||
//【很重要】默认数据格式,以实际业务为主。
|
||
value: [
|
||
{
|
||
label: ''
|
||
}
|
||
],
|
||
component: {
|
||
name: 'slot-cert'
|
||
}
|
||
}
|
||
],
|
||
on: {
|
||
submit(data, { close }) {
|
||
close();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function rowAdd() {
|
||
Form.value?.form.cert.push({
|
||
label: ''
|
||
});
|
||
}
|
||
|
||
function rowDel(index: number) {
|
||
Form.value?.form.cert.splice(index, 1);
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.cert {
|
||
.row {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.el-input {
|
||
flex: 1;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.el-icon {
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
color: red;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|
||
``` |