Skip to content

Crud Create/Update ​

z-crud component create and edit form functionality introduction.

Basic Usage ​

Configure add or edit fields in column to implement create or edit form configuration.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    add: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
    edit: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    add: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
    edit: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    add: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    edit: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
  },
  {
    prop: 'date',
    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,
  addApi: commonApi,
  editApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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"
    :detail="false"
    :search="searchFormConfig"
    :request="request"
  />
</template>

Configure columns field in add and edit to implement create and edit form configuration.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

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: 'date',
    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 addFormConfig = ref({
  columns: [
    {
      component: 'input',
      label: 'Name (create)',
      field: 'name',
    },
    {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
    {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  ],
})

const editFormConfig = ref({
  columns: [
    {
      component: 'input',
      label: 'Name (edit)',
      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,
  addApi: commonApi,
  editApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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="searchFormConfig"
    :request="request"
    :detail="false"
    :add="addFormConfig"
    :edit="editFormConfig"
  />
</template>

Configure columns field in form to implement both create and edit form configuration, but it will also configure query and detail information at the same time. You can configure search and detail as false to disable them.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

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: 'date',
    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,
  addApi: commonApi,
  editApi: commonApi,
})

const formConfig = ref({
  columns: [
    {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
    {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
    {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
  ],
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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="searchFormConfig"
    :form="formConfig"
    :request="request"
    :detail="false"
  />
</template>

Configure form field in column items to implement create and edit form configuration, but it will also configure query form at the same time. You can set search as false to disable it.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
  },
  {
    prop: 'date',
    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,
  addApi: commonApi,
  editApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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"
    :detail="false"
    :request="request"
  />
</template>

Confirm API ​

Configure addApi and editApi in request.

editApi will pass an additional rowKey parameter, default is id.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
  },
  {
    prop: 'date',
    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,
  addApi: commonApi,
  editApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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"
    :detail="false"
    :request="request"
  />
</template>

If create and edit APIs are the same, you can configure submitApi. When editing, it will also include rowKey.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { DialogFormSubmitParams } from 'ideaz-element'

interface FormData {
  name?: string
  gender?: string
  age?: string
}

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
  },
  {
    prop: 'date',
    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,
  submitApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: DialogFormSubmitParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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"
    :detail="false"
    :request="request"
  />
</template>

Edit Detail Data ​

Configure detailApi in request to get default data for edit dialog from API.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
  },
  {
    prop: 'date',
    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,
  addApi: commonApi,
  editApi: commonApi,
  detailApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 100)
  })
}

function detailApi(params: { id: number }) {
  console.log(JSON.stringify(params), 'detailApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        data: {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: ['2020-01-01', '2020-01-03'],
        },
      })
    }, 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"
    :detail="false"
    :request="request"
  />
</template>

Detail Data Processing ​

If you need to process the detail data returned by the API, you can configure request.alias.detail. Passing a function supports custom detail data, passing a string supports custom data path.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string[]
  date: string
}

interface FormData {
  name: string
  gender: string
  age: string
}

interface GetTableDataRes { data: { 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',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
  },
  {
    prop: 'date',
    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,
  addApi: commonApi,
  editApi: commonApi,
  detailApi,
  alias: {
    detail: (res: GetTableDataRes) => {
      console.log(res, 'res')
      return {
        ...res.data,
        time: [],
      }
    },
  },
})

function mockApi(): Promise<GetTableDataRes> {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 100)
  })
}

function detailApi(params: { id: number }) {
  console.log(JSON.stringify(params), 'detailApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        data: {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: ['2020-01-01', '2020-01-03'],
        },
      })
    }, 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"
    :detail="false"
    :request="request"
  />
</template>

Custom Confirmation ​

When request doesn't configure submitApi, addApi and editApi, there will be operate-submit event.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { DialogFormSubmitParams } from 'ideaz-element'

interface FormData {
  name?: string
  gender?: string
  age?: string
}

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
  },
  {
    prop: 'date',
    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 = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 handleSubmit({ done, formRef, formData, type, confirmButtonLoading, row, invalidFields }: DialogFormSubmitParams<FormData, RowData>) {
  confirmButtonLoading.value = true
  console.log(formRef, formData, type, invalidFields, row)
  done()
  confirmButtonLoading.value = false
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :columns="columns"
    :options="options"
    :detail="false"
    :request="request"
    @operate-submit="handleSubmit"
  />
</template>

Custom Cancel ​

operate-cancel custom cancel event. If the component is not configured, clicking cancel will close by default.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { DialogFormSubmitParams } from 'ideaz-element'

interface FormData {
  name?: string
  gender?: string
  age?: string
}

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    form: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    search: false,
  },
  {
    prop: 'date',
    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 = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 handleSubmit({ done, formRef, formData, type, confirmButtonLoading, row, invalidFields }: DialogFormSubmitParams<FormData, RowData>) {
  confirmButtonLoading.value = true
  console.log(formRef, formData, type, invalidFields, row)
  done()
  confirmButtonLoading.value = false
}
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:formData="formData"
    v-model:loading="loading"
    :columns="columns"
    :options="options"
    :detail="false"
    :request="request"
    @operate-submit="handleSubmit"
  />
</template>

Form Properties ​

Use add and edit objects to configure create and edit form properties. The form property can uniformly configure create and edit.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    add: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
    edit: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    add: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
    edit: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    add: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    edit: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
  },
  {
    prop: 'date',
    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 addFormConfig = ref({
  labelWidth: '120px',
  labelPosition: 'top',
})

const editFormConfig = ref({
  labelWidth: '80px',
  labelPosition: 'left',
})

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,
  addApi: commonApi,
  editApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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="searchFormConfig"
    :add="addFormConfig"
    :edit="editFormConfig"
    :detail="false"
    :request="request"
  />
</template>

Dialog Properties ​

You can use the dialog object to uniformly configure create and edit dialog properties, or use add.dialog and edit.dialog to configure dialog properties separately.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { EditRequestApiParams } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  date: string
  time: string[]
}

interface FormData {
  name: string
  gender: string
  age: string
}

const loading = ref(false)
const formData = ref({
  name: '',
  gender: '',
  age: '',
})
const tableData = ref([])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    add: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
    edit: {
      component: 'input',
      field: 'name',
      label: 'Name',
      required: true,
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
    add: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
    edit: {
      component: 'select',
      field: 'gender',
      label: 'Gender',
    },
  },
  {
    prop: 'age',
    label: 'Age',
    add: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
    edit: {
      component: 'el-date-picker',
      field: 'time',
      label: 'Date',
      fieldProps: {
        type: 'daterange',
        startPlaceholder: 'Start date',
        endPlaceholder: 'End date',
      },
    },
  },
  {
    prop: 'date',
    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 addFormConfig = ref({
  labelWidth: '120px',
  labelPosition: 'top',
  dialog: {
    title: 'Create Dialog',
  },
})

const editFormConfig = ref({
  labelWidth: '80px',
  labelPosition: 'left',
  dialog: {
    title: 'Edit Dialog',
  },
})

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,
  addApi: commonApi,
  editApi: commonApi,
})

function mockApi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          date: '2020-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          date: '2012-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          date: '2018-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          date: '2028-01-01',
          time: ['2020-01-01', '2020-01-02'],
        },
      ]

      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 commonApi(params: EditRequestApiParams<FormData, RowData>) {
  console.log(JSON.stringify(params), 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 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="searchFormConfig"
    :add="addFormConfig"
    :edit="editFormConfig"
    :detail="false"
    :request="request"
  />
</template>
AttributeDescriptionTypeDefault
detailDetail configurationboolean / object / ({ row, tableRef }) => voidtrue
formSearch, add, edit and view form attribute configurationobject—
actionWhether to show action items (built-in delete, edit buttons)booleantrue
editEdit configurationboolean / objecttrue
addAdd configurationboolean / objecttrue
deleteDelete configurationboolean / ({ row, tableRef, getTableData }) => void / object—
searchSearch configurationboolean / objecttrue
requestAPI configurationobject—

add and edit Attributes ​

AttributeDescriptionTypeDefault
dialogel-dialog component attributesobject—
rulesForm validation rulesobject—
columnsForm itemsarray—
optionsForm option data sourceobject—
colonForm item colonbooleanfalse
alignVertical alignment under flex layouttop / middle /bottom—
label-positionPosition of form field labels. When set to left or right, you also need to set the label-width attributeenumright
label-widthWidth of labels, e.g. '50px'. Form items that are direct children of Form will inherit this value. auto can be used.string / number''
label-suffixSuffix for form field labelsstring''
hide-required-asteriskWhether to hide the red asterisk next to required field labels.booleanfalse
require-asterisk-positionPosition of asterisk.left / rightleft
show-messageWhether to show validation error messagesbooleantrue
inline-messageWhether to display validation messages inlinebooleanfalse
status-iconWhether to display validation result feedback icons in input boxesbooleanfalse
validate-on-rule-changeWhether to trigger validation immediately after the rules attribute changesbooleantrue
sizeSize for controlling components within this formlarge / default / small—
disabledWhether to disable all components in this form. If set to true, it will override the disabled attribute of internal componentsbooleanfalse
scroll-to-errorWhen validation fails, scroll to the first error form itembooleanfalse
scroll-into-view-optionsWhen validation has failed results, scroll to the first failed form itemobject / boolean—

form Attributes ​

AttributeDescriptionTypeDefault
rulesForm validation rulesobject—
columnsForm itemsarray—
optionsForm option data sourceobject—
colonForm item colonbooleanfalse
alignVertical alignment under flex layouttop / middle /bottom—
label-positionPosition of form field labels. When set to left or right, you also need to set the label-width attributeenumright
label-widthWidth of labels, e.g. '50px'. Form items that are direct children of Form will inherit this value. auto can be used.string / number''
label-suffixSuffix for form field labelsstring''
hide-required-asteriskWhether to hide the red asterisk next to required field labels.booleanfalse
require-asterisk-positionPosition of asterisk.left / rightleft
show-messageWhether to show validation error messagesbooleantrue
inline-messageWhether to display validation messages inlinebooleanfalse
status-iconWhether to display validation result feedback icons in input boxesbooleanfalse
validate-on-rule-changeWhether to trigger validation immediately after the rules attribute changesbooleantrue
sizeSize for controlling components within this formlarge / default / small—
disabledWhether to disable all components in this form. If set to true, it will override the disabled attribute of internal componentsbooleanfalse
scroll-to-errorWhen validation fails, scroll to the first error form itembooleanfalse
scroll-into-view-optionsWhen validation has failed results, scroll to the first failed form itemobject / boolean—

request Attributes ​

AttributeDescriptionTypeDefault
searchApiSearch API(params: any) => promise—
submitApiEdit and create confirmation({ [key: string]: any, row: any, type: 'add' / 'edit' / 'view', formData: any }) => promise—
deleteApiDelete API({ [key: string]?: any, row?: any, selectionData?: any }) => promise—
addApiCreate API({ type: 'add' / 'edit' / 'view', formData: any }) => promise—
editApiEdit API({ [key: string]: any, row: any, type: 'add' / 'edit' / 'view', formData: any }) => promise—
detailApiDetail API({ [key: string]: any, row: any }) => promise—
aliasCustom data pathobject—
beforeDataCallback before table data API callFunction—
afterDataCallback after table data API call(res) => void—
searchFuncSearch method override({ params }) => any—
tableDataCustom table data return(res) => any—
Event NameDescriptionType
operate-submitDialog confirm({ done, formRef, formData, type, confirmButtonLoading, row, invalidFields }) => void
operate-cancelDialog cancel({ done, formRef, formData, type, confirmButtonLoading, row }) => void

Released under the MIT License.