Crud Form
Introduction to the form part of the z-crud component.
If you only want to use the component's filter form and table features, please refer to the following examples.
Basic Usage
Configure search in the column item to generate form items.
labelandfieldcan be omitted, defaulting topropandlabel- The component configures
clearable,placeholderandfilterableby default - For the specific configuration of the
searchattribute, refer to thecolumnitems ofz-form - The form layout is fixed as
{ xs: 24, sm: 12, md: 8, lg: 8, xl: 6 }
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
interface RowData {
name: string
gender: string
age: number
time: string
}
interface GetTableDataRes { result: { page: number, pageSize: number, list: RowData[], total: number } }
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
age: '',
})
const tableData = ref<RowData[]>([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
label: 'Name',
field: 'name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
label: 'Gender',
field: 'gender',
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'input',
label: 'Age',
field: 'age',
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
function mockApi(params: any): Promise<GetTableDataRes> {
console.log(params, 'params')
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
result: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
async function getTableData() {
loading.value = true
try {
const params = {
...pagination.value,
...formData.value,
}
const res = await mockApi(params)
tableData.value = res.result.list
pagination.value.total = res.result.total
}
catch (error) {
console.log(error)
}
loading.value = false
}
function handleSearch() {
pagination.value.page = 1
getTableData()
}
getTableData()
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
:columns="columns"
:options="options"
:loading="loading"
:action="false"
@refresh="getTableData"
@search="handleSearch"
@reset="handleSearch"
/>
</template>Configuring the columns field of search can also achieve the same effect. If you want to configure other attributes such as the form's labelWidth, you can also put them in search.
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
age: '',
})
const tableData = ref([])
const columns = ref([
{
prop: 'name',
label: 'Name',
},
{
prop: 'gender',
label: 'Gender',
},
{
prop: 'age',
label: 'Age',
},
{
prop: 'time',
label: 'Date',
},
])
const searchFormConfig = ref({
labelWith: '80px',
columns: [
{
component: 'input',
label: 'Name',
field: 'name',
},
{
component: 'select',
label: 'Gender',
field: 'gender',
},
{
component: 'input',
label: 'Age',
field: 'age',
},
],
})
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi() {
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:options="options"
:columns="columns"
:search="searchFormConfig"
:action="false"
:request="request"
/>
</template>Configuring form in column can also generate query form items, but it will also generate add, edit, and query form items at the same time. If not needed, you can set the add and edit fields to false.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
interface RowData {
name: string
gender: string
age: number
time: string
}
interface GetTableDataRes { result: { page: number, pageSize: number, list: RowData[], total: number } }
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
age: '',
})
const tableData = ref<RowData[]>([])
const columns = ref([
{
prop: 'name',
label: 'Name',
add: false,
edit: false,
form: {
component: 'input',
label: 'Name',
field: 'name',
},
},
{
prop: 'gender',
label: 'Gender',
add: false,
edit: false,
form: {
component: 'select',
label: 'Gender',
field: 'gender',
},
},
{
prop: 'age',
label: 'Age',
add: false,
edit: false,
form: {
component: 'input',
label: 'Age',
field: 'age',
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
function mockApi(params: any): Promise<GetTableDataRes> {
console.log(params, 'any')
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
result: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
async function getTableData() {
loading.value = true
try {
const params = {
...pagination.value,
...formData.value,
}
const res = await mockApi(params)
tableData.value = res.result.list
pagination.value.total = res.result.total
}
catch (error) {
console.log(error)
}
loading.value = false
}
function handleSearch() {
pagination.value.page = 1
getTableData()
}
getTableData()
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
:columns="columns"
:options="options"
:loading="loading"
@refresh="getTableData"
@search="handleSearch"
@reset="handleSearch"
/>
</template>If a column item does not want a table column and only wants a form item, do not configure fields such as type, slot, render, label, prop, component in column, and then configure form-related fields such as search, form to achieve it.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
interface RowData {
name: string
gender: string
age: number
time: string
}
interface GetTableDataRes { result: { page: number, pageSize: number, list: RowData[], total: number } }
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
age: '',
})
const tableData = ref<RowData[]>([])
const columns = ref([
{
// Only search is configured
search: {
component: 'input',
label: 'Name',
field: 'name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
label: 'Gender',
field: 'gender',
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'input',
label: 'Age',
field: 'age',
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
function mockApi(params: any): Promise<GetTableDataRes> {
console.log(params, 'params')
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
result: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
async function getTableData() {
loading.value = true
try {
const params = {
...pagination.value,
...formData.value,
}
const res = await mockApi(params)
tableData.value = res.result.list
pagination.value.total = res.result.total
}
catch (error) {
console.log(error)
}
loading.value = false
}
function handleSearch() {
pagination.value.page = 1
getTableData()
}
getTableData()
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
:columns="columns"
:options="options"
:loading="loading"
:action="false"
@refresh="getTableData"
@search="handleSearch"
@reset="handleSearch"
/>
</template>Condition Caching
Configure the name field to enable caching by default. The filter form data and pagination data will be cached in sessionStorage, and the condition data will be retrieved from the cache first on the next load.
Data retrieval needs to be called in the onMounted lifecycle.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
interface RowData {
name: string
gender: string
age: number
time: string
}
interface GetTableDataRes { result: { page: number, pageSize: number, list: RowData[], total: number } }
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
age: '',
})
const tableData = ref<RowData[]>([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
label: 'Name',
field: 'name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
label: 'Gender',
field: 'gender',
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'input',
label: 'Age',
field: 'age',
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
function mockApi(params: any): Promise<GetTableDataRes> {
console.log(params, 'params')
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
result: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
async function getTableData() {
loading.value = true
try {
const params = {
...pagination.value,
...formData.value,
}
console.log(params, 'cache params')
const res = await mockApi(params)
tableData.value = res.result.list
pagination.value.total = res.result.total
}
catch (error) {
console.log(error)
}
loading.value = false
}
function handleSearch() {
pagination.value.page = 1
getTableData()
}
onMounted(() => {
getTableData()
})
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
:columns="columns"
:options="options"
:loading="loading"
:action="false"
name="crudCache"
@refresh="getTableData"
@search="handleSearch"
@reset="handleSearch"
/>
</template>After configuring request, cached conditions will be handled internally.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
time: [],
})
const tableData = ref([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
field: 'name',
label: 'Name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
field: 'gender',
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'el-date-picker',
field: 'time',
label: 'Date',
fieldProps: {
type: 'daterange',
startPlaceholder: 'Start date',
endPlaceholder: 'End date',
},
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi(params: any) {
console.log(params, 'cache params second')
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:options="options"
:columns="columns"
:action="false"
:request="request"
name="nameCacheSecond"
/>
</template>Validation
- Add the
requiredfield in theformfield, or set therequiredfield informItemPropsto set it as required. The validation message will be automatically generated based on thelabelor can be customized. - Configure the
rulesfield in thesearchobject passed toz-crudto define form validation rules. - Configure
rulesin the form items in theformfield to define the validation rules for the current form item.
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
time: [],
})
const tableData = ref([])
const searchFormConfig = ref({
labelWidth: '80px',
rules: {
time: [{ required: true, message: 'Date is required' }],
},
})
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
field: 'name',
label: 'Name',
required: true,
message: 'Please provide the full name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
field: 'gender',
formItemProps: {
required: true,
label: 'Gender',
},
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'el-date-picker',
field: 'time',
label: 'Date',
rules: {
required: true,
message: 'Date is required',
},
fieldProps: {
type: 'daterange',
startPlaceholder: 'Start date',
endPlaceholder: 'End date',
},
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi() {
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:options="options"
:columns="columns"
:action="false"
:search="searchFormConfig"
:request="request"
/>
</template>Custom Form Items
We can use slot or render to customize the content of form items.
<script lang="ts" setup>
import { h, ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
age: '',
height: 'Custom height label',
})
const tableData = ref([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
field: 'name',
label: 'Name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
slot: 'ageSlot',
label: 'Age',
},
},
{
prop: 'age',
label: 'Age',
search: {
render: () => h('span', {}, formData.value.height),
label: 'Height',
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi() {
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:columns="columns"
:options="options"
:search="{ size: 'default' }"
:action="false"
:request="request"
>
<template #ageSlot>
<el-input v-model="formData.age" placeholder="Please enter an age" clearable />
</template>
</z-crud>
</template>Custom label and error
label and error support passing strings, render functions, or concatenated Slot strings.
<script lang="ts" setup>
import { h, ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
time: [],
})
const tableData = ref([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
field: 'name',
label: () => h('span', {}, 'Name'),
required: true,
error: 'error message',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
field: 'gender',
label: 'labelSlot',
required: true,
error: h('span', {}, 'errorSlot'),
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'el-date-picker',
field: 'time',
label: 'Date',
required: true,
error: 'errorSlot',
fieldProps: {
type: 'daterange',
startPlaceholder: 'Start date',
endPlaceholder: 'End date',
},
},
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi() {
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:columns="columns"
:options="options"
:action="false"
:search="{ labelWidth: '80px' }"
:request="request"
>
<template #labelSlot>
<span>Gender</span>
</template>
<template #errorSlot>
<span>Date is required</span>
</template>
</z-crud>
</template>Linkage
Use hide to configure the visibility of form items. When gender male is selected, the birth date filter item will be displayed.
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
time: [],
})
const tableData = ref([])
const visible = ref(false)
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
field: 'name',
label: 'Name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
field: 'gender',
label: 'Gender',
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'el-date-picker',
field: 'time',
label: 'Date',
hide: () => !visible.value,
fieldProps: {
type: 'daterange',
startPlaceholder: 'Start date',
endPlaceholder: 'End date',
},
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi() {
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
function handleClick() {
visible.value = !visible.value
}
</script>
<template>
<el-button @click="handleClick">
Toggle visibility
</el-button>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:options="options"
:columns="columns"
:search="{ labelWidth: '80px' }"
:action="false"
:request="request"
/>
</template>Operation Buttons
Button operations will have search and reset events, with built-in reset and validation operations. Customization is supported.
For details, please refer to the z-filter-form component documentation.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
time: [],
})
const tableData = ref([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
field: 'name',
label: 'Name',
required: true,
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
field: 'gender',
label: 'Gender',
required: true,
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'el-date-picker',
field: 'time',
label: 'Date',
required: true,
fieldProps: {
type: 'daterange',
startPlaceholder: 'Start date',
endPlaceholder: 'End date',
},
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi() {
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
function handleSearch() {
console.log(formData.value, 'formData')
}
function handleReset() {
console.log(formData.value, 'formData')
}
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:columns="columns"
:options="options"
:search="{ labelWidth: '80px' }"
:action="false"
:request="request"
@search="handleSearch"
@reset="handleReset"
/>
</template>Default Collapsed
Configure collapsed to false in search, and the form will be collapsed by default.
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
time: [],
})
const tableData = ref([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
field: 'name',
label: 'Name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
field: 'gender',
label: 'Gender',
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'el-date-picker',
field: 'time',
label: 'Date',
fieldProps: {
type: 'daterange',
startPlaceholder: 'Start date',
endPlaceholder: 'End date',
},
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
const request = ref({
searchApi: mockApi,
})
function mockApi() {
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
data: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
v-model:loading="loading"
:columns="columns"
:options="options"
:search="{ labelWidth: '80px', collapsed: false }"
:action="false"
:request="request"
/>
</template>Decorator Components
Configure formDecorator and crudDecorator to set the background of the filter form and table. The name field can be tags such as div, span, or the name of a globally registered component.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
interface RowData {
name: string
gender: string
age: number
time: string
}
interface GetTableDataRes { result: { page: number, pageSize: number, list: RowData[], total: number } }
const loading = ref(false)
const formData = ref({
name: '',
gender: '',
age: '',
})
const tableData = ref<RowData[]>([])
const columns = ref([
{
prop: 'name',
label: 'Name',
search: {
component: 'input',
label: 'Name',
field: 'name',
},
},
{
prop: 'gender',
label: 'Gender',
search: {
component: 'select',
label: 'Gender',
field: 'gender',
},
},
{
prop: 'age',
label: 'Age',
search: {
component: 'input',
label: 'Age',
field: 'age',
},
},
{
prop: 'time',
label: 'Date',
},
])
const options = {
gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}
const pagination = ref({
page: 1,
pageSize: 2,
total: 4,
})
function mockApi(params: any): Promise<GetTableDataRes> {
console.log(params, 'params')
return new Promise((resolve) => {
setTimeout(() => {
const data = [
{
name: 'Steven',
gender: 'male',
age: 22,
time: '2020-01-01',
},
{
name: 'Helen',
gender: 'male',
age: 12,
time: '2012-01-01',
},
{
name: 'Nancy',
gender: 'female',
age: 18,
time: '2018-01-01',
},
{
name: 'Jack',
gender: 'male',
age: 28,
time: '2028-01-01',
},
]
resolve({
result: {
page: 1,
pageSize: 10,
total: 4,
list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
},
})
}, 100)
})
}
async function getTableData() {
loading.value = true
try {
const params = {
...pagination.value,
...formData.value,
}
const res = await mockApi(params)
tableData.value = res.result.list
pagination.value.total = res.result.total
}
catch (error) {
console.log(error)
}
loading.value = false
}
function handleSearch() {
pagination.value.page = 1
getTableData()
}
getTableData()
</script>
<template>
<z-crud
v-model:pagination="pagination"
v-model:data="tableData"
v-model:formData="formData"
:columns="columns"
:options="options"
:loading="loading"
:action="false"
:form-decorator="{ name: 'div', style: { border: '1px solid #e4e7ed', paddingTop: '18px' } }"
:table-decorator="{ name: 'el-card', shadow: 'hover' }"
@refresh="getTableData"
@search="handleSearch"
@reset="handleSearch"
/>
</template>z-crud Search Form Related Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| modelValue:formData | Query form data | object | — |
| detail | Detail configuration | boolean / object / ({ row, tableRef }) => void | true |
| form | Configuration of query, add, edit and view form attributes | object | — |
| action | Whether to display action items (built-in delete, edit and other buttons) | boolean | true |
| edit | Edit configuration | boolean / object | true |
| add | Add configuration | boolean / object | true |
| delete | Delete configuration | boolean / ({ row, tableRef, getTableData }) => void / object | — |
| search | Search configuration | boolean / object | true |
| request | API configuration | object | — |
| paginationStorage | Pagination caching | boolean | false |
| formStorage | Query form data caching | boolean | false |
| formDecorator | Form background | object | { name: 'el-card' } |
| tableDecorator | Table background | object | { name: 'el-card' } |
search Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| collapsed | Default expand/collapse of the form | boolean | true |
| searchButtonProps | Search button attribute configuration | object | — |
| searchButtonLabel | Search button text | string | Search |
| searchButtonLoading | Search button loading state | boolean | — |
| resetButtonProps | Reset button attribute configuration | object | — |
| resetButtonLabel | Reset button text | string | Reset |
| resetButtonLoading | Reset button loading state | boolean | — |
| rules | Form validation rules | object | — |
| label-position | Position of the form field label. When set to left or right, you also need to set label-width | enum | right |
| label-width | Length of the label, e.g. '50px'. Form-items that are direct children of Form inherit this value. auto can be used. | string / number | '' |
| label-suffix | Suffix of the form field label | string | '' |
| hide-required-asterisk | Whether to hide the red asterisk next to required field labels | boolean | false |
| require-asterisk-position | Position of the asterisk | left / right | left |
| show-message | Whether to display validation error messages | boolean | true |
| inline-message | Whether to display validation messages inline | boolean | false |
| status-icon | Whether to display validation result feedback icons in the input box | boolean | false |
| validate-on-rule-change | Whether to trigger a validation immediately after the rules attribute changes | boolean | true |
| size | Size used to control the components within this form | large / default / small | — |
| disabled | Whether to disable all components in this form. If set to true, it overrides internal components' disabled | boolean | false |
z-crud Query Form Methods
| Name | Description | Type |
|---|---|---|
| validate | Validate the entire form. Accepts a callback function or returns a Promise. | Function |
| validateField | Validate a specific field. | Function |
| resetFields | Reset this form item, restore its value to the initial value, and remove the validation result | Function |
| scrollToField | Scroll to the specified field | Function |
| clearValidate | Clear the validation information of a certain field. | Function |
Form Item Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| component | Form item component | string / () => VNode / Component | — |
| field | Field name | string | — |
| fieldProps | component attributes | object | — |
| formItemProps | formItem attributes | object | — |
| label | Form label name | string / () => VNode | — |
| hide | Show / hide | boolean / (formData) => boolean | — |
| show | Show / hide using v-show | boolean / (formData) => boolean | — |
| slot | Custom content slot of item | string | — |
| render | Custom content render of item | () => VNode | — |
| required | Whether the field is required | boolean | — |
| rules | Validation rules of the field | boolean | — |
| error | Error message | string / () => VNode | — |
| tooltip | Tooltip message | string / () => VNode | — |
| extra | Extra information | string / () => VNode | — |
formItemProps Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| tooltip | Tooltip text | string / () => VNode | — |
| extra | Extra information | string / () => VNode | — |
| colon | Colon | boolean | — |
| label | Label text | string / () => VNode | — |
| label-width | Label width, e.g. '50px'. auto can be used. | string / number | '' |
| required | Whether it is required. If not set, it will be confirmed according to the validation rules | boolean | — |
| rules | Form validation rules. See table below; more at async-validator | object | — |
| error | Prompt information when the form field validation fails. Setting this value will cause the form validation state to become error and display this error message. | string / () => VNode | — |
| show-message | Whether to display validation error messages | boolean | true |
| inline-message | Whether to display validation messages inline | string / boolean | '' |
| size | Default size of components under this form field | large / default / small | — |
| for | Same capability as the native label | string | — |
| validate-status | Validation status of formItem | error / validating / success | — |
z-crud Query Form Related Events
| Event Name | Description | Type |
|---|---|---|
| update:formData | Form item data | Function |
| reset | Reset | Function |
| search | Search | Function |