Skip to content

组件使用指南

作者:唐亚峰 | battcn
字数统计:1.4k 字

学习目标

掌握 Wemirr Platform 内置组件的使用方法

组件概览

Wemirr Platform 基于 Vben Admin 5.x 和 Ant Design Vue 4.x,提供了丰富的业务组件。

基础组件

组件说明
BasicForm表单组件,支持动态表单
BasicTable表格组件,支持分页、筛选
BasicModal弹窗组件
BasicDrawer抽屉组件

业务组件

组件说明
DictSelect字典下拉选择
TreeSelect树形选择器
Upload文件上传
Editor富文本编辑器

BasicForm 表单组件

基础用法

vue
<script setup lang="ts">
import { BasicForm, useForm } from '@vben/common-ui';
import type { FormSchema } from '@vben/common-ui';

const schemas: FormSchema[] = [
  {
    field: 'username',
    label: '用户名',
    component: 'Input',
    required: true,
    colProps: { span: 12 },
  },
  {
    field: 'email',
    label: '邮箱',
    component: 'Input',
    rules: [{ type: 'email', message: '请输入有效的邮箱地址' }],
    colProps: { span: 12 },
  },
  {
    field: 'status',
    label: '状态',
    component: 'Select',
    componentProps: {
      options: [
        { label: '启用', value: 1 },
        { label: '禁用', value: 0 },
      ],
    },
  },
  {
    field: 'remark',
    label: '备注',
    component: 'InputTextArea',
    colProps: { span: 24 },
  },
];

const [registerForm, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
  schemas,
  labelWidth: 100,
  showActionButtonGroup: true,
  actionColOptions: { span: 24 },
  submitButtonOptions: { text: '提交' },
  resetButtonOptions: { text: '重置' },
});

async function handleSubmit() {
  const values = await validate();
  console.log('表单数据:', values);
}
</script>

<template>
  <BasicForm @register="registerForm" @submit="handleSubmit" />
</template>

表单配置项

typescript
interface FormSchema {
  field: string;           // 字段名
  label: string;           // 标签
  component: string;       // 组件类型
  componentProps?: object; // 组件属性
  required?: boolean;      // 是否必填
  rules?: Rule[];          // 校验规则
  colProps?: object;       // 栅格配置
  slot?: string;           // 自定义插槽
  ifShow?: boolean | Fn;   // 是否显示
  dynamicDisabled?: boolean | Fn; // 是否禁用
  defaultValue?: any;      // 默认值
}

支持的组件类型

类型说明
Input输入框
InputNumber数字输入框
InputPassword密码输入框
InputTextArea文本域
Select下拉选择
TreeSelect树形选择
RadioGroup单选组
CheckboxGroup多选组
Switch开关
DatePicker日期选择
RangePicker日期范围
TimePicker时间选择
Upload上传

表单联动

typescript
const schemas: FormSchema[] = [
  {
    field: 'type',
    label: '类型',
    component: 'Select',
    componentProps: {
      options: [
        { label: '个人', value: 1 },
        { label: '企业', value: 2 },
      ],
    },
  },
  {
    field: 'companyName',
    label: '公司名称',
    component: 'Input',
    // 仅当类型为企业时显示
    ifShow: ({ values }) => values.type === 2,
  },
  {
    field: 'idCard',
    label: '身份证号',
    component: 'Input',
    // 仅当类型为个人时显示
    ifShow: ({ values }) => values.type === 1,
  },
];

BasicTable 表格组件

基础用法

vue
<script setup lang="ts">
import { BasicTable, useTable } from '@vben/common-ui';
import type { BasicColumn } from '@vben/common-ui';
import { getUserList, deleteUser } from './api';

const columns: BasicColumn[] = [
  { title: 'ID', dataIndex: 'id', width: 80 },
  { title: '用户名', dataIndex: 'username', width: 120 },
  { title: '邮箱', dataIndex: 'email', width: 180 },
  {
    title: '状态',
    dataIndex: 'status',
    width: 100,
    customRender: ({ record }) => {
      return record.status === 1 ? '启用' : '禁用';
    },
  },
  { title: '创建时间', dataIndex: 'createTime', width: 180 },
];

const [registerTable, { reload, getSelectRows }] = useTable({
  columns,
  api: getUserList,
  rowKey: 'id',
  bordered: true,
  showIndexColumn: true,
  rowSelection: { type: 'checkbox' },
  pagination: { pageSize: 10 },
  actionColumn: {
    title: '操作',
    width: 150,
    fixed: 'right',
  },
});

function handleEdit(record) {
  console.log('编辑:', record);
}

async function handleDelete(record) {
  await deleteUser(record.id);
  reload();
}
</script>

<template>
  <BasicTable @register="registerTable">
    <template #toolbar>
      <a-button type="primary" @click="handleAdd">新增</a-button>
      <a-button @click="handleBatchDelete">批量删除</a-button>
    </template>
    <template #action="{ record }">
      <a-button type="link" size="small" @click="handleEdit(record)">
        编辑
      </a-button>
      <a-popconfirm title="确定删除?" @confirm="handleDelete(record)">
        <a-button type="link" size="small" danger>删除</a-button>
      </a-popconfirm>
    </template>
  </BasicTable>
</template>

表格配置项

typescript
interface TableProps {
  columns: BasicColumn[];     // 列配置
  api?: Function;             // 数据接口
  dataSource?: any[];         // 静态数据
  rowKey?: string;            // 行键
  bordered?: boolean;         // 是否显示边框
  pagination?: object | false;// 分页配置
  rowSelection?: object;      // 行选择配置
  showIndexColumn?: boolean;  // 是否显示序号列
  actionColumn?: object;      // 操作列配置
  searchInfo?: object;        // 额外搜索参数
  beforeFetch?: Function;     // 请求前处理
  afterFetch?: Function;      // 请求后处理
}

表格方法

方法说明
reload(opt?)刷新表格数据
getSelectRows()获取选中行数据
getSelectRowKeys()获取选中行键
clearSelectedRowKeys()清空选中
setSelectedRowKeys(keys)设置选中行
getPaginationRef()获取分页信息
setPagination(info)设置分页
getDataSource()获取表格数据
setTableData(data)设置表格数据

BasicModal 弹窗组件

基础用法

vue
<script setup lang="ts">
import { BasicModal, useModal } from '@vben/common-ui';

const [registerModal, { openModal, closeModal, setModalProps }] = useModal();

function handleOpen() {
  openModal(true, { id: 1 });
}
</script>

<template>
  <a-button @click="handleOpen">打开弹窗</a-button>
  
  <BasicModal
    @register="registerModal"
    title="用户详情"
    :width="600"
    @ok="handleSubmit"
  >
    <div>弹窗内容</div>
  </BasicModal>
</template>

弹窗方法

typescript
const [registerModal, { 
  openModal,      // 打开弹窗,可传递数据
  closeModal,     // 关闭弹窗
  setModalProps,  // 设置弹窗属性
  getVisible,     // 获取显示状态
}] = useModal();

// 在子组件中接收数据
const [registerModal, { closeModal }] = useModalInner((data) => {
  console.log('接收到的数据:', data);
});

BasicDrawer 抽屉组件

基础用法

vue
<script setup lang="ts">
import { BasicDrawer, useDrawer } from '@vben/common-ui';

const [registerDrawer, { openDrawer }] = useDrawer();
</script>

<template>
  <a-button @click="openDrawer(true, { id: 1 })">
    打开抽屉
  </a-button>
  
  <BasicDrawer
    @register="registerDrawer"
    title="详情"
    :width="500"
  >
    <div>抽屉内容</div>
  </BasicDrawer>
</template>

字典组件

DictSelect 字典下拉

vue
<script setup lang="ts">
import { DictSelect } from '@/components/Dict';
</script>

<template>
  <!-- 基础用法 -->
  <DictSelect v-model:value="formData.status" dict-code="sys_status" />
  
  <!-- 多选 -->
  <DictSelect
    v-model:value="formData.tags"
    dict-code="sys_tags"
    mode="multiple"
  />
  
  <!-- 在表单中使用 -->
  <a-form-item label="状态">
    <DictSelect v-model:value="formData.status" dict-code="sys_status" />
  </a-form-item>
</template>

DictTag 字典标签

vue
<template>
  <!-- 显示字典标签 -->
  <DictTag dict-code="sys_status" :value="record.status" />
</template>

文件上传组件

基础用法

vue
<script setup lang="ts">
import { BasicUpload } from '@/components/Upload';

const fileList = ref([]);

function handleChange(list) {
  fileList.value = list;
}
</script>

<template>
  <!-- 单文件上传 -->
  <BasicUpload
    v-model:value="fileList"
    :max-count="1"
    :api="uploadApi"
    @change="handleChange"
  />
  
  <!-- 多文件上传 -->
  <BasicUpload
    v-model:value="fileList"
    :max-count="5"
    :api="uploadApi"
    accept=".jpg,.png,.pdf"
    :max-size="10"
  />
  
  <!-- 图片上传 -->
  <BasicUpload
    v-model:value="fileList"
    :api="uploadApi"
    list-type="picture-card"
    accept="image/*"
  />
</template>

树形选择器

部门树选择

vue
<script setup lang="ts">
import { TreeSelect } from 'ant-design-vue';
import { getDeptTree } from '@/api/system/dept';

const treeData = ref([]);
const selectedDept = ref<number>();

onMounted(async () => {
  treeData.value = await getDeptTree();
});
</script>

<template>
  <TreeSelect
    v-model:value="selectedDept"
    :tree-data="treeData"
    :field-names="{ label: 'name', value: 'id', children: 'children' }"
    placeholder="请选择部门"
    allow-clear
    tree-default-expand-all
  />
</template>

图标选择器

vue
<script setup lang="ts">
import { IconPicker } from '@/components/Icon';

const selectedIcon = ref('');
</script>

<template>
  <IconPicker v-model:value="selectedIcon" />
</template>

下一步