Skip to content

综合使用

举例在CURD列表里简化使用操作

此版本代码可能较多,包含类型,样式和分页处理,可按实际需求来

与naive ui table使用

Nai Form Table Test
Name
Age
Address
Tags
Action
No Data
vue

<template>
  <n-card>
    <template #header>
      <div class="title">Nai Form Table Test</div>
      <div class="search">
        <NaiDynamicForm :items="searchFormItems" ref="searchDynamicFormRef" preset="grid"/>
        <div class="searchBtn">
          <n-button type="info" size="small" @click="doSearch">Search</n-button>
          <n-button size="small" @click="doReset">Reset</n-button>
        </div>
      </div>
      <div class="controlBtn">
        <n-button type="success" size="small" @click="addItem">Add</n-button>
      </div>
    </template>
    <n-data-table
        :scroll-x="800"
        :single-line="false"
        :columns="columns"
        :data="pagedData"
        :loading="tableLoading"
    />
    <template #footer>
      <div class="pagination">
        <n-pagination v-model:page="pageModal.pageNo"
                      v-model:page-size="pageModal.pageSize"
                      :item-count="tableData.length">
          <template #prefix="{ itemCount }">
            Total {{ itemCount }}
          </template>
        </n-pagination>
      </div>
    </template>
  </n-card>
  <div class="update">
    <n-modal v-model:show="showModal" :title="referId==='-1'?'add Item':'update Item'" preset="card" draggable
             :style="{width:'70%'}">
      <NaiDynamicForm :items="handleFormItems" ref="handleDynamicFormRef"/>
      <template #footer>
        <div class="fControlBtn">
          <n-button size="small" @click="formCancel">Cancel</n-button>
          <n-button type="info" size="small" @click="formSubmit">Submit</n-button>
        </div>
      </template>
    </n-modal>
  </div>
</template>

<script setup lang="ts">
  import {type DataTableColumns, NSpace} from 'naive-ui'
  import {NButton, NTag, useMessage} from 'naive-ui'
  import {computed, h, nextTick, onMounted, reactive, ref} from 'vue'
  import {NaiDynamicForm, type naiDynamicFormRef, renderInput, renderSelect} from "dynamicformdjx/naiveUi";
  import {useDyForm, useReactiveForm} from "dynamicformdjx";

  const message = useMessage()

  interface RowData {
    key: number
    name: string
    age: number
    address: string
    tags: string[]
  }

  type PageModal = {
    pageSize: number
    pageNo: number
  }
  const data = [
    {
      key: 0,
      name: 'John Brown',
      age: 12,
      address: 'New York No. 1 Lake Park',
      tags: ['nice', 'developer']
    },
    {
      key: 1,
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park',
      tags: ['wow']
    },
    {
      key: 2,
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park',
      tags: ['cool', 'teacher']
    }
  ]
  const tagsSelection = data.flatMap(it => it.tags.map(it => ({label: it, value: it})))
  const columns: DataTableColumns<RowData> = [
    {
      title: 'Name',
      key: 'name'
    },
    {
      title: 'Age',
      key: 'age'
    },
    {
      title: 'Address',
      key: 'address'
    },
    {
      title: 'Tags',
      key: 'tags',
      render(row) {
        if (row.tags === null) return h('div', {}, '-')
        const tags = row.tags.map((tagKey) => {
          return h(
              NTag,
              {
                style: {
                  marginRight: '6px'
                },
                type: 'info',
                bordered: false
              },
              {
                default: () => tagKey
              }
          )
        })
        return tags
      }
    },
    {
      title: 'Action',
      key: 'actions',
      fixed: 'right',
      render(row) {
        return h(
            NSpace, {}, [
              h(NButton,
                  {
                    size: 'small',
                    onClick: () => upItem(row)
                  },
                  {default: () => 'update'}),
              h(NButton,
                  {
                    size: 'small',
                    type: 'error',
                    onClick: () => delItem(row)
                  },
                  {default: () => 'delete'})
            ]
        )
      }
    }
  ]
  const tableData = ref<RowData[]>([])
  const tableLoading = ref<boolean>(false)
  const showModal = ref<boolean>(false)
  const referId = ref<string | number>('-1')
  const pageModal = reactive<PageModal>({pageNo: 1, pageSize: 10})
  const handleDynamicFormRef = ref<naiDynamicFormRef | null>(null)
  const searchDynamicFormRef = ref<naiDynamicFormRef | null>(null)
  const pagedData = computed(() => {
    const {pageNo, pageSize} = pageModal
    const start = (pageNo - 1) * pageSize
    return tableData.value.slice(start, start + pageSize)
  })
  const searchFormItems = useReactiveForm<RowData>([
    {
      key: "name",
      label: "Name",
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    },
    {
      key: "age",
      label: "Age",
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    },
  ])
  const handleFormItems = useReactiveForm<RowData>([
    {
      key: "name",
      label: "Name",
      value: null,
      required: true,
      render2: f => renderInput(f.value, {}, f),
    },
    {
      key: "age",
      label: "Age",
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
    },
    {
      key: "address",
      label: "Address",
      value: null,
      clearable: true,
      type: 'textarea',
      rows: 2,
      render2: f => renderInput(f.value, {}, f),
    },
    {
      key: "tags",
      label: "Tags",
      value: [],
      clearable: true,
      multiple: true,
      render2: f => renderSelect(f.value, tagsSelection, {}, f),
    },
  ])
  const useHandleForm = useDyForm(handleFormItems)
  const doSearch = () => {
    const params = searchDynamicFormRef.value?.getResult?.() as any
    message.info(JSON.stringify(params))
    tableData.value = tableData.value.filter(it => it.name.includes(params.name) || it.age === parseInt(params.age))
    pageModal.pageNo = 1
  }
  const doReset = () => {
    searchDynamicFormRef.value?.reset?.()
    tableData.value = data
    pageModal.pageNo = 1
  }
  const addItem = () => {
    useHandleForm.onReset()
    referId.value = '-1'
    nextTick(() => {
      showModal.value = true
    })
  }

  function upItem(it: RowData) {
    referId.value = it.key
    useHandleForm.setValues(it)
    nextTick(() => {
      showModal.value = true
    })
  }

  function delItem(it: RowData) {
    tableData.value = tableData.value.filter(it2 => it2.key !== it.key)
    message.success('delete successful')
  }

  function formCancel() {
    message.warning('cancel')
    showModal.value = false
  }

  async function formSubmit() {
    // const data = useHandleForm.getValues()
    console.log(referId.value)
    handleDynamicFormRef.value?.validator().then((v: any) => {
      if (referId.value === '-1') {
        tableData.value.push({...v, key: Date.now()})
        message.success('Add successful')
      } else {
        tableData.value = tableData.value.map(it => {
          if (referId.value === it.key) return v as RowData
          return it
        })
        message.success('Update successful')
      }
      nextTick(() => {
        showModal.value = false
        // fetchData()
      })
    })
  }

  async function fetchData() {
    tableLoading.value = true
    const res = await new Promise((resolve, reject) => setTimeout(() => resolve(data), 1000))
    tableData.value = res as RowData[]
    tableLoading.value = false
  }

  onMounted(fetchData)
</script>
<style scoped>
  .title {
    text-align: center;
    font-weight: bold;
    font-size: 18px;
  }

  .search {
    margin: 10px 0;
  }

  .pagination {
    display: flex;
    justify-content: center;
  }

  .search .searchBtn {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
  }

  .fControlBtn {
    display: flex;
    justify-content: center;
    gap: 10px;
  }
</style>
vue

<template>
  <n-card>
    <template #header>
      <div class="title">Nai Form Table Test</div>
      <div class="search">
        <NaiDynamicForm :items="searchFormItems" ref="searchDynamicFormRef" preset="grid"/>
        <div class="searchBtn">
          <n-button type="info" size="small" @click="doSearch">Search</n-button>
          <n-button size="small" @click="doReset">Reset</n-button>
        </div>
      </div>
      <div class="controlBtn">
        <n-button type="success" size="small" @click="addItem">Add</n-button>
      </div>
    </template>
    <n-data-table
        :scroll-x="800"
        :single-line="false"
        :columns="columns"
        :data="pagedData"
        :loading="tableLoading"
    />
    <template #footer>
      <div class="pagination">
        <n-pagination
            v-model:page="pageModal.pageNo"
            v-model:page-size="pageModal.pageSize"
            :item-count="tableData.length"
        >
          <template #prefix="{ itemCount }">
            Total {{ itemCount }}
          </template>
        </n-pagination>
      </div>
    </template>
  </n-card>

  <div class="update">
    <n-modal
        v-model:show="showModal"
        :title="referId==='-1'?'add Item':'update Item'"
        preset="card"
        draggable
        :style="{width:'70%'}"
    >
      <NaiDynamicForm :items="handleFormItems" ref="handleDynamicFormRef"/>
      <template #footer>
        <div class="fControlBtn">
          <n-button size="small" @click="formCancel">Cancel</n-button>
          <n-button type="info" size="small" @click="formSubmit">Submit</n-button>
        </div>
      </template>
    </n-modal>
  </div>
</template>

<script setup>
  import {NSpace} from 'naive-ui'
  import {NButton, NTag, useMessage} from 'naive-ui'
  import {computed, h, nextTick, onMounted, reactive, ref} from 'vue'
  import {NaiDynamicForm, renderInput, renderSelect} from "dynamicformdjx/naiveUi";
  import {useDyForm, useReactiveForm} from "dynamicformdjx";

  const message = useMessage()

  const data = [
    {
      key: 0,
      name: 'John Brown',
      age: 12,
      address: 'New York No. 1 Lake Park',
      tags: ['nice', 'developer']
    },
    {
      key: 1,
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park',
      tags: ['wow']
    },
    {
      key: 2,
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park',
      tags: ['cool', 'teacher']
    }
  ]

  const tagsSelection = data.flatMap(it => it.tags.map(it => ({label: it, value: it})))

  const columns = [
    {
      title: 'Name',
      key: 'name'
    },
    {
      title: 'Age',
      key: 'age'
    },
    {
      title: 'Address',
      key: 'address'
    },
    {
      title: 'Tags',
      key: 'tags',
      render(row) {
        if (row.tags === null) return h('div', {}, '-')
        const tags = row.tags.map((tagKey) => {
          return h(
              NTag,
              {
                style: {
                  marginRight: '6px'
                },
                type: 'info',
                bordered: false
              },
              {
                default: () => tagKey
              }
          )
        })
        return tags
      }
    },
    {
      title: 'Action',
      key: 'actions',
      fixed: 'right',
      render(row) {
        return h(
            NSpace, {}, [
              h(NButton,
                  {
                    size: 'small',
                    onClick: () => upItem(row)
                  },
                  {default: () => 'update'}),
              h(NButton,
                  {
                    size: 'small',
                    type: 'error',
                    onClick: () => delItem(row)
                  },
                  {default: () => 'delete'})
            ]
        )
      }
    }
  ]

  const tableData = ref([])
  const tableLoading = ref(false)
  const showModal = ref(false)
  const referId = ref('-1')
  const pageModal = reactive({pageNo: 1, pageSize: 10})

  const handleDynamicFormRef = ref(null)
  const searchDynamicFormRef = ref(null)

  const pagedData = computed(() => {
    const {pageNo, pageSize} = pageModal
    const start = (pageNo - 1) * pageSize
    return tableData.value.slice(start, start + pageSize)
  })

  const searchFormItems = useReactiveForm([
    {
      key: "name",
      label: "Name",
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    },
    {
      key: "age",
      label: "Age",
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    },
  ])

  const handleFormItems = useReactiveForm([
    {
      key: "name",
      label: "Name",
      value: null,
      required: true,
      render2: f => renderInput(f.value, {}, f),
    },
    {
      key: "age",
      label: "Age",
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
    },
    {
      key: "address",
      label: "Address",
      value: null,
      clearable: true,
      type: 'textarea',
      rows: 2,
      render2: f => renderInput(f.value, {}, f),
    },
    {
      key: "tags",
      label: "Tags",
      value: [],
      clearable: true,
      multiple: true,
      render2: f => renderSelect(f.value, tagsSelection, {}, f),
    },
  ])

  const useHandleForm = useDyForm(handleFormItems)

  const doSearch = () => {
    const params = searchDynamicFormRef.value?.getResult?.()
    message.info(JSON.stringify(params))
    tableData.value = tableData.value.filter(it => it.name.includes(params.name) || it.age === parseInt(params.age))
    pageModal.pageNo = 1
  }

  const doReset = () => {
    searchDynamicFormRef.value?.reset?.()
    tableData.value = data
    pageModal.pageNo = 1
  }

  const addItem = () => {
    useHandleForm.onReset()
    referId.value = '-1'
    nextTick(() => {
      showModal.value = true
    })
  }

  function upItem(it) {
    referId.value = it.key
    useHandleForm.setValues(it)
    nextTick(() => {
      showModal.value = true
    })
  }

  function delItem(it) {
    tableData.value = tableData.value.filter(it2 => it2.key !== it.key)
    message.success('delete successful')
  }

  function formCancel() {
    message.warning('cancel')
    showModal.value = false
  }

  async function formSubmit() {
    // const data = useHandleForm.getValues()
    console.log(referId.value)
    handleDynamicFormRef.value?.validator().then((v) => {
      if (referId.value === '-1') {
        tableData.value.push({...v, key: Date.now()})
        message.success('Add successful')
      } else {
        tableData.value = tableData.value.map(it => {
          if (referId.value === it.key) return v
          return it
        })
        message.success('Update successful')
      }
      nextTick(() => {
        showModal.value = false
        // fetchData()
      })
    })
  }

  async function fetchData() {
    tableLoading.value = true
    const res = await new Promise((resolve, reject) => setTimeout(() => resolve(data), 1000))
    tableData.value = res
    tableLoading.value = false
  }

  onMounted(fetchData)
</script>

<style scoped>
  .title {
    text-align: center;
    font-weight: bold;
    font-size: 18px;
  }

  .search {
    margin: 10px 0;
  }

  .pagination {
    display: flex;
    justify-content: center;
  }

  .search .searchBtn {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
  }

  .fControlBtn {
    display: flex;
    justify-content: center;
    gap: 10px;
  }
</style>

与element plus table使用

ElementPlus Form Table Test
No Data
vue

<template>
  <el-card>
    <template #header>
      <div class="title">ElementPlus Form Table Test</div>

      <div class="search">
        <EleDynamicForm :items="searchFormItems" ref="searchDynamicFormRef" preset="grid"/>
        <div class="searchBtn">
          <el-button type="primary" size="small" @click="doSearch">Search</el-button>
          <el-button size="small" @click="doReset">Reset</el-button>
        </div>
      </div>

      <div class="controlBtn">
        <el-button type="success" size="small" @click="addItem">Add</el-button>
      </div>
    </template>

    <div class="tableScroll">
      <el-table
          v-loading="tableLoading"
          :data="pagedData"
          border
          style="min-width: 900px"
      >
        <el-table-column :prop="r.prop" :label="r.label" v-for="r in tableProps" :key="r.prop">
          <template #scope="row">
            <template v-if="r.prop!=='tags'">{{ row[r.prop] }}</template>
            <template v-else>
              <span v-if="!row.tags || row.tags.length === 0">-</span>
              <template v-else>
                <el-tag
                    v-for="t in row.tags"
                    :key="t"
                    class="tag"
                    type="info"
                    effect="plain"
                >
                  {{ t }}
                </el-tag>
              </template>
            </template>
          </template>
        </el-table-column>

        <el-table-column label="Action" width="180" fixed="right">
          <template #default="{ row }">
            <el-space>
              <el-button size="small" @click="upItem(row)">update</el-button>
              <el-button size="small" type="danger" @click="delItem(row)">delete</el-button>
            </el-space>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <div class="pagination">
      <el-pagination
          v-model:current-page="pageModal.pageNo"
          v-model:page-size="pageModal.pageSize"
          :total="tableData.length"
          layout="total, prev, pager, next"
      />
    </div>
  </el-card>

  <el-dialog
      v-model="showModal"
      :title="referId === -1 ? 'add Item' : 'update Item'"
      width="70%"
      draggable
  >
    <EleDynamicForm :items="handleFormItems" ref="handleDynamicFormRef"/>

    <template #footer>
      <div class="fControlBtn">
        <el-button size="small" @click="formCancel">Cancel</el-button>
        <el-button type="primary" size="small" @click="formSubmit">Submit</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
  import {computed, nextTick, onMounted, reactive, ref} from 'vue'
  import {ElMessage} from 'element-plus'
  import {
    EleDynamicForm,
    type eleDynamicFormRef,
    renderInput,
    renderSelect
  } from 'dynamicformdjx/elementPlus'
  import {useDyForm, useReactiveForm} from 'dynamicformdjx'

  interface RowData {
    key: number
    name: string
    age: number
    address: string
    tags: string[]
  }

  type PageModal = {
    pageSize: number
    pageNo: number
  }
  const pageModal = reactive<PageModal>({pageNo: 1, pageSize: 10})

  const tableLoading = ref(false)
  const showModal = ref(false)
  const referId = ref<number | string>(-1)

  const handleDynamicFormRef = ref<eleDynamicFormRef | null>(null)
  const searchDynamicFormRef = ref<eleDynamicFormRef | null>(null)

  const seedData: RowData[] = [
    {key: 0, name: 'John Brown', age: 12, address: 'New York No. 1 Lake Park', tags: ['nice', 'developer']},
    {key: 1, name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park', tags: ['wow']},
    {key: 2, name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park', tags: ['cool', 'teacher']}
  ]
  const tableProps: { label: string, prop: keyof RowData }[] = [
    {label: 'Name', prop: 'name'},
    {label: 'Age', prop: 'age'},
    {label: 'Address', prop: 'address'},
    {label: 'Tags', prop: 'tags'},
  ]
  const tagsSelection = seedData.flatMap(it => it.tags.map(it => ({label: it, value: it})))
  const tableData = ref<RowData[]>([])

  const pagedData = computed(() => {
    const {pageNo, pageSize} = pageModal
    const start = (pageNo - 1) * pageSize
    return tableData.value.slice(start, start + pageSize)
  })


  const searchFormItems = useReactiveForm<RowData>([
    {
      key: 'name',
      label: 'Name',
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    },
    {
      key: 'age',
      label: 'Age',
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    }
  ])

  const handleFormItems = useReactiveForm<RowData>([
    {
      key: 'name',
      label: 'Name',
      value: null,
      required: true,
      render2: f => renderInput(f.value, {}, f)
    },
    {
      key: 'age',
      label: 'Age',
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f)
    },
    {
      key: 'address',
      label: 'Address',
      value: null,
      clearable: true,
      type: 'textarea',
      rows: 2,
      render2: f => renderInput(f.value, {}, f)
    },
    {
      key: 'tags',
      label: 'Tags',
      value: [],
      clearable: true,
      multiple: true,
      render2: f => renderSelect(f.value, tagsSelection, {}, f)
    }
  ])

  const useHandleForm = useDyForm(handleFormItems)

  const doSearch = () => {
    const params = (searchDynamicFormRef.value?.getResult?.() ?? {}) as any
    ElMessage.info(JSON.stringify(params))
    tableData.value = tableData.value.filter(it => it.name.includes(params.name) || it.age === parseInt(params.age))
    pageModal.pageNo = 1
  }

  const doReset = () => {
    searchDynamicFormRef.value?.reset?.()
    tableData.value = seedData
    pageModal.pageNo = 1
  }

  const addItem = () => {
    useHandleForm.onReset()
    referId.value = -1
    nextTick(() => {
      showModal.value = true
    })
  }

  function upItem(it: RowData) {
    referId.value = it.key
    useHandleForm.setValues(it)
    nextTick(() => {
      showModal.value = true
    })
  }

  function delItem(it: RowData) {
    tableData.value = tableData.value.filter(r => r.key !== it.key)
    ElMessage.success('delete successful')
  }

  function formCancel() {
    ElMessage.warning('cancel')
    showModal.value = false
  }

  async function formSubmit() {
    handleDynamicFormRef.value?.validator().then((v: any) => {
      if (referId.value === -1) {
        const newRow: RowData = {...(v as any), key: Date.now()}
        tableData.value = [...tableData.value, newRow]
        ElMessage.success('Add successful')
      } else {
        tableData.value = tableData.value.map(r =>
            r.key === referId.value ? ({...r, ...(v as any), key: r.key} as RowData) : r
        )
        ElMessage.success('Update successful')
      }

      nextTick(() => {
        showModal.value = false
      })
    })
  }

  async function fetchData() {
    tableLoading.value = true
    const res = await new Promise<RowData[]>(resolve => setTimeout(() => resolve(seedData), 800))
    tableData.value = [...res]
    tableLoading.value = false
  }

  onMounted(fetchData)
</script>

<style scoped>
  .title {
    text-align: center;
    font-weight: bold;
    font-size: 18px;
  }

  .search {
    margin: 10px 0;
  }
  .tableScroll{
    width: 100%;
    overflow-x: auto;
  }
  .pagination {
    display: flex;
    justify-content: center;
    margin-top: 12px;
  }

  .search .searchBtn {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
  }

  .fControlBtn {
    display: flex;
    justify-content: center;
    gap: 10px;
  }

  .tag {
    margin-right: 6px;
  }
</style>
vue

<template>
  <el-card>
    <template #header>
      <div class="title">ElementPlus Form Table Test</div>

      <div class="search">
        <EleDynamicForm :items="searchFormItems" ref="searchDynamicFormRef" preset="grid"/>
        <div class="searchBtn">
          <el-button type="primary" size="small" @click="doSearch">Search</el-button>
          <el-button size="small" @click="doReset">Reset</el-button>
        </div>
      </div>

      <div class="controlBtn">
        <el-button type="success" size="small" @click="addItem">Add</el-button>
      </div>
    </template>

    <div class="tableScroll">
      <el-table
          v-loading="tableLoading"
          :data="pagedData"
          border
          style="min-width: 900px"
      >
        <el-table-column
            :prop="r.prop"
            :label="r.label"
            v-for="r in tableProps"
            :key="r.prop"
        >
          <template #scope="row">
            <template v-if="r.prop !== 'tags'">{{ row[r.prop] }}</template>
            <template v-else>
              <span v-if="!row.tags || row.tags.length === 0">-</span>
              <template v-else>
                <el-tag
                    v-for="t in row.tags"
                    :key="t"
                    class="tag"
                    type="info"
                    effect="plain"
                >
                  {{ t }}
                </el-tag>
              </template>
            </template>
          </template>
        </el-table-column>

        <el-table-column label="Action" width="180" fixed="right">
          <template #default="{ row }">
            <el-space>
              <el-button size="small" @click="upItem(row)">update</el-button>
              <el-button size="small" type="danger" @click="delItem(row)">delete</el-button>
            </el-space>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <div class="pagination">
      <el-pagination
          v-model:current-page="pageModal.pageNo"
          v-model:page-size="pageModal.pageSize"
          :total="tableData.length"
          layout="total, prev, pager, next"
      />
    </div>
  </el-card>

  <el-dialog
      v-model="showModal"
      :title="referId === -1 ? 'add Item' : 'update Item'"
      width="70%"
      draggable
  >
    <EleDynamicForm :items="handleFormItems" ref="handleDynamicFormRef"/>

    <template #footer>
      <div class="fControlBtn">
        <el-button size="small" @click="formCancel">Cancel</el-button>
        <el-button type="primary" size="small" @click="formSubmit">Submit</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup>
  import {computed, nextTick, onMounted, reactive, ref} from 'vue'
  import {ElMessage} from 'element-plus'
  import {EleDynamicForm, renderInput, renderSelect} from 'dynamicformdjx/elementPlus'
  import {useDyForm, useReactiveForm} from 'dynamicformdjx'

  const pageModal = reactive({pageNo: 1, pageSize: 10})

  const tableLoading = ref(false)
  const showModal = ref(false)
  const referId = ref(-1)

  const handleDynamicFormRef = ref(null)
  const searchDynamicFormRef = ref(null)

  const seedData = [
    {key: 0, name: 'John Brown', age: 12, address: 'New York No. 1 Lake Park', tags: ['nice', 'developer']},
    {key: 1, name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park', tags: ['wow']},
    {key: 2, name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park', tags: ['cool', 'teacher']}
  ]

  const tableProps = [
    {label: 'Name', prop: 'name'},
    {label: 'Age', prop: 'age'},
    {label: 'Address', prop: 'address'},
    {label: 'Tags', prop: 'tags'}
  ]

  const tagsSelection = seedData.flatMap(it => it.tags.map(it => ({label: it, value: it})))
  const tableData = ref([])

  const pagedData = computed(() => {
    const {pageNo, pageSize} = pageModal
    const start = (pageNo - 1) * pageSize
    return tableData.value.slice(start, start + pageSize)
  })

  const searchFormItems = useReactiveForm([
    {
      key: 'name',
      label: 'Name',
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    },
    {
      key: 'age',
      label: 'Age',
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f),
      span: 12
    }
  ])

  const handleFormItems = useReactiveForm([
    {
      key: 'name',
      label: 'Name',
      value: null,
      required: true,
      render2: f => renderInput(f.value, {}, f)
    },
    {
      key: 'age',
      label: 'Age',
      value: null,
      clearable: true,
      render2: f => renderInput(f.value, {}, f)
    },
    {
      key: 'address',
      label: 'Address',
      value: null,
      clearable: true,
      type: 'textarea',
      rows: 2,
      render2: f => renderInput(f.value, {}, f)
    },
    {
      key: 'tags',
      label: 'Tags',
      value: [],
      clearable: true,
      multiple: true,
      render2: f => renderSelect(f.value, tagsSelection, {}, f)
    }
  ])

  const useHandleForm = useDyForm(handleFormItems)

  const doSearch = () => {
    const params = searchDynamicFormRef.value?.getResult?.() ?? {}
    ElMessage.info(JSON.stringify(params))
    tableData.value = tableData.value.filter(it => it.name.includes(params.name) || it.age === parseInt(params.age))
    pageModal.pageNo = 1
  }

  const doReset = () => {
    searchDynamicFormRef.value?.reset?.()
    tableData.value = seedData
    pageModal.pageNo = 1
  }

  const addItem = () => {
    useHandleForm.onReset()
    referId.value = -1
    nextTick(() => {
      showModal.value = true
    })
  }

  function upItem(it) {
    referId.value = it.key
    useHandleForm.setValues(it)
    nextTick(() => {
      showModal.value = true
    })
  }

  function delItem(it) {
    tableData.value = tableData.value.filter(r => r.key !== it.key)
    ElMessage.success('delete successful')
  }

  function formCancel() {
    ElMessage.warning('cancel')
    showModal.value = false
  }

  async function formSubmit() {
    handleDynamicFormRef.value?.validator().then((v) => {
      if (referId.value === -1) {
        const newRow = {...(v), key: Date.now()}
        tableData.value = [...tableData.value, newRow]
        ElMessage.success('Add successful')
      } else {
        tableData.value = tableData.value.map(r =>
            r.key === referId.value ? ({...r, ...(v), key: r.key}) : r
        )
        ElMessage.success('Update successful')
      }

      nextTick(() => {
        showModal.value = false
      })
    })
  }

  async function fetchData() {
    tableLoading.value = true
    const res = await new Promise(resolve => setTimeout(() => resolve(seedData), 800))
    tableData.value = [...res]
    tableLoading.value = false
  }

  onMounted(fetchData)
</script>

<style scoped>
  .title {
    text-align: center;
    font-weight: bold;
    font-size: 18px;
  }

  .search {
    margin: 10px 0;
  }

  .tableScroll {
    width: 100%;
    overflow-x: auto;
  }

  .pagination {
    display: flex;
    justify-content: center;
    margin-top: 12px;
  }

  .search .searchBtn {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
  }

  .fControlBtn {
    display: flex;
    justify-content: center;
    gap: 10px;
  }

  .tag {
    margin-right: 6px;
  }
</style>

TIP

上方举例配合在简单增删改查中使用方式,后续会提供通用固定界面组件,更简化template代码,将数据驱动放在setup中