Skip to content

模板化模块

扁平化组件,将父级组件作为通信组件

字段1
字段2
字段3
-
-
-
-
-

暂无数据

  • 1

文件结构

bash
src
 ├─ components
   └─ Page.vue // 分页组件
 ├─ style
   └─ global.scss // 公共样式
 └─ views
    └─ Module
       ├─ components
         ├─ AddDialog.vue // 新增、编辑表单组件
         ├─ Form.vue // 搜索表单组件
         └─ Table.vue // 列表组件
       └─ index.vue // 通信组件

index.vue(通信组件)

点击查看
vue
<template>
  <div class="Container">
    <Form ref="RefForm" class="Form" />
    <Table ref="RefTable" class="Table" />
    <Page ref="RefPage" class="Page" />
    <AddDialog ref="RefAddDialog" />
  </div>
</template>
<script lang="ts">
export type GetRefs = () => ({
  Form: InstanceType<typeof Form>,
  Table: InstanceType<typeof Table>,
  Page: InstanceType<typeof Page>,
  AddDialog: InstanceType<typeof AddDialog>,
})

</script>
<script lang="ts" setup>
import Page from '@/components/Page.vue'
import AddDialog from './components/AddDialog.vue'
import Form from './components/Form.vue'
import Table from './components/Table.vue'

defineOptions({
  name: '模板化模块?sort=0'
})

const RefForm = ref(null)
const RefTable = ref(null)
const RefPage = ref(null)
const RefAddDialog = ref(null)

provide('getRefs', () => ({
  Form: RefForm.value,
  Table: RefTable.value,
  Page: RefPage.value,
  AddDialog: RefAddDialog.value,
}))
</script>

Form.vue(搜索表单组件)

点击查看
vue
<template>
  <FormGenerator v-bind="{...formAttrs}" />
</template>

<script lang="ts" setup>
import { FormGenerator } from 'element-plus-generator'
import type { FormAttrs } from 'element-plus-generator/lib/type'
import type { GetRefs } from './../index.vue'

const formAttrs = ref<FormAttrs>({
  type: 'search',
  model: {},
  formOption: [
    {
      type: 'input',
      formItem: {
        prop: 'key1',
        label: '字段1',
      },
    },
    {
      type: 'select',
      formItem: {
        prop: 'key2',
        label: '字段2',
      },
      control: {
        option: [
          {
            label: '文本1',
            value: '值1'
          },
        ]
      }
    },
    {
      type: 'date-time-picker',
      formItem: {
        prop: 'key3',
        label: '字段3',
      },
    },
    {
      type: 'input',
      formItem: {
        prop: 'key4',
        label: '字段4',
      },
    },
    {
      type: 'input',
      formItem: {
        prop: 'key5',
        label: '字段5',
      },
    },
  ],
  onSubmit: () => {
    getRefs().Page.setPageNum(1)
    getRefs().Table.getTableData()
  }
})


const getRefs = inject<GetRefs>('getRefs')
defineExpose({ model: formAttrs.value.model })
</script>

Table.vue(列表组件)

点击查看
vue
<template>
  <div class="Table">
    <div class="tool">
      <el-button type="primary" @click="openAddDialog()">新增</el-button>
    </div>
    <TableGenerator v-bind="{ ...tableAttrs }">
      <template #operation="scope">
        <el-button link type="primary" @click="openAddDialog(scope.row.id)">编辑</el-button>
        <el-button link type="primary">删除</el-button>
      </template>
    </TableGenerator>
  </div>
</template>
<script lang="ts" setup>
import { TableGenerator } from 'element-plus-generator'
import type { TableAttrs } from 'element-plus-generator/lib/type'
import type { GetRefs } from './../index.vue'
import $api from '@/services'

const $router = useRouter()
const tableAttrs = ref<TableAttrs>({
  loading: false,
  data: [],
  tableOption: [
    {
      prop: 'key1',
      label: '文本1',
    }, {
      prop: 'key2',
      label: '文本2',
    }, {
      prop: 'key3',
      label: '文本3',
    }, {
      prop: 'key4',
      label: '文本4',
    }, {
      prop: 'key5',
      label: '文本5',
    },
  ]
})

async function getTableData() {
  const { Form, Page } = getRefs()
  tableAttrs.value.loading = true
  // const res = await $api.xxx.xxx({
  //   pageNum: Page.getPageNum(),
  //   pageSize: Page.getPageSize(),
  //   ...tableAttrs.value.model,
  // })
  // tableAttrs.value.data = res?.data.list ?? []
  // Page.setTotal(res.total)
  tableAttrs.value.loading = false
}

function openAddDialog(id?: number) {
  getRefs().AddDialog.openDialog(id)
}

async function del(id: number) {
  const bool = await ElMessageBox.confirm('确定删除?')
  // bool && await $api.xxx.xxx({id})
  ElMessage.success('删除成功')
  getRefs().Table.getTableData()
}

onMounted(() => {
  getTableData()
})
const getRefs = inject<GetRefs>('getRefs')
defineExpose({ getTableData })
</script>

AddDialog.vue(新增、编辑表单组件)

点击查看
vue
<template>
  <el-dialog :title="type" v-model="visible" width="500px">
    <FormGenerator ref="RefFormGenerator" v-bind="{ ...formAttrs }" />
  </el-dialog>
</template>

<script lang="tsx" setup>
import { FormGenerator, GeneratorUtils } from 'element-plus-generator'
import type { FormAttrs, RefFormGenerator } from 'element-plus-generator/lib/type'
import type { GetRefs } from './../index.vue'
import $api from '@/services'

const RefFormGenerator = ref<RefFormGenerator>()
const visible = ref(false)
const type = ref<'新增' | '修改'>('新增')
const option = [
  {
    label: '文本1',
    value: '值1'
  },
  {
    label: '文本2',
    value: '值2'
  },
]
const formAttrs = ref<FormAttrs>({
  type: 'dialog',
  model: {},
  formOption: [
    {
      type: 'input',
      formItem: {
        prop: 'key1',
        label: '文本1',
      },
    },
    {
      type: 'select',
      formItem: {
        prop: 'key2',
        label: '文本2',
      },
      control: {
        option
      }
    },
    {
      type: 'input-number',
      formItem: {
        prop: 'key3',
        label: '文本3',
      },
    },
    {
      type: 'radio',
      formItem: {
        prop: 'key4',
        label: '文本4',
      },
      control: {
        radioGroup: option
      }
    },
    {
      type: 'checkbox',
      formItem: {
        prop: 'key5',
        label: '文本5',
      },
      control: {
        checkboxGroup: option
      }
    },
  ],
  onSubmit: () => {
    visible.value = false
    if (type.value === '新增') {
      // await $api.xxx.xxx(form)
    } else {
      // await $api.xxx.xxx(form)
    }
    ElMessage.success(`${type.value}成功`)
    getRefs().Table.getTableData()
  }
})


async function openDialog(id?: number) {
  type.value = id ? '修改' : '新增'
  visible.value = true
  nextTick(async () => {
    RefFormGenerator.value()?.resetFields()
    if (type.value === '新增') {
    } else {
      //  const res = await $api.xxx.xxx()
      // form = res.data
    }
  })
}

const getRefs = inject<GetRefs>('getRefs')
defineExpose({ openDialog })

</script>

Page.vue(分页组件)

点击查看
vue
<template>
  <div>
    <el-pagination :hide-on-single-page="total <= 50" background @size-change="handleSizeChange"
      @current-change="handleCurrentChange" v-model:currentPage="pageNum" layout="prev, pager, next" :page-size="pageSize"
      :total="total"></el-pagination>
  </div>
</template>

<script lang="ts" setup>
const pageNum = ref(1)
const pageSize = ref(50)
const total = ref(0)

function handleCurrentChange(val: number) {
  pageNum.value = val
  getRefs().Table.getTableData(null, 'page')
}
function handleSizeChange(val: number) {
  pageNum.value = 1
  setPageSize(val)
  getRefs().Table.getTableData(null, 'page')
}
function getPageSize() {
  return pageSize.value
}
function getPageNum() {
  return pageNum.value
}
function setPageSize(val: number) {
  pageSize.value = val
}
function setPageNum(val: number) {
  pageNum.value = val
}
function setTotal(val: number) {
  total.value = val
}

const getRefs = inject('getRefs') as Function
defineExpose({ getPageNum, getPageSize, setPageNum, setTotal })

</script>

global.scss(公共样式)

点击查看
scss
@mixin flex-init($justify: center, $align: center, $direction: row, $wrap: nowrap) {
  display: flex;
  flex-direction: $direction;
  justify-content: $justify;
  align-items: $align;
  flex-wrap: $wrap;
}
@mixin grow-shrink($grow: 1, $shrink: -1) {
  flex-grow: $grow;
  flex-shrink: $shrink;
}

.Container {
  width: 100%;
  height: 100%;
  @include flex-init(flex-start, flex-start, $direction: column);
  gap: 12px;
  padding: 12px 20px;
  box-sizing: border-box;

  .Form,
  .FormGenerator {
    @include grow-shrink(0, 0);
    width: 100%;

  }

  .Table {
    width: 100%;
    @include grow-shrink(1, 1);
    @include flex-init(flex-start, $direction: column);
    gap: 10px;

    .tool {
      width: 100%;
      @include flex-init(flex-end);
      @include grow-shrink(0, 0);
    }
  }

  .Page {
    @include grow-shrink(0, 0);
    width: 100%;
    @include flex-init(flex-end);
  }
}