Skip to content

CRUD 快速开发

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

学习目标

掌握使用 Fast Crud 快速开发增删改查页面

简介

Wemirr Platform 集成了

,只需几行代码即可完成 CRUD 页面开发。

基础示例

最简示例

vue
<script setup lang="ts">
import { useFs } from '@fast-crud/fast-crud';
import { getUserList, createUser, updateUser, deleteUser } from './api';

const { crudBinding, crudRef } = useFs({
  crudOptions: {
    request: {
      pageRequest: async (query) => {
        const res = await getUserList(query);
        return { records: res.data.records, total: res.data.total };
      },
      addRequest: async ({ form }) => await createUser(form),
      editRequest: async ({ form }) => await updateUser(form.id, form),
      delRequest: async ({ row }) => await deleteUser(row.id),
    },
    columns: {
      username: {
        title: '用户名',
        type: 'text',
        search: { show: true },
        form: { rules: [{ required: true, message: '请输入用户名' }] },
      },
      email: {
        title: '邮箱',
        type: 'text',
        search: { show: true },
      },
      status: {
        title: '状态',
        type: 'dict-select',
        dict: {
          data: [
            { label: '启用', value: 1, color: 'success' },
            { label: '禁用', value: 0, color: 'error' },
          ],
        },
      },
      createTime: {
        title: '创建时间',
        type: 'datetime',
        form: { show: false },
        column: { width: 180 },
      },
    },
  },
});
</script>

<template>
  <fs-crud ref="crudRef" v-bind="crudBinding" />
</template>

只需要上面这段代码,就能得到一个完整的 CRUD 页面,包含:

  • ✅ 数据列表
  • ✅ 分页
  • ✅ 搜索
  • ✅ 新增
  • ✅ 编辑
  • ✅ 删除

配置详解

columns 列配置

typescript
const columns = {
  // 字段名
  username: {
    title: '用户名',              // 列标题
    type: 'text',                 // 字段类型
    
    // 列表配置
    column: {
      width: 120,                 // 列宽
      fixed: 'left',              // 固定列
      show: true,                 // 是否显示
      sortable: true,             // 是否可排序
      align: 'center',            // 对齐方式
      formatter: (context) => {}, // 格式化
    },
    
    // 表单配置
    form: {
      show: true,                 // 是否显示
      disabled: false,            // 是否禁用
      rules: [],                  // 校验规则
      component: {},              // 组件配置
      col: { span: 12 },          // 栅格配置
    },
    
    // 搜索配置
    search: {
      show: true,                 // 是否显示
      component: {},              // 组件配置
    },
    
    // 新增表单配置(覆盖 form)
    addForm: {},
    
    // 编辑表单配置(覆盖 form)
    editForm: {},
    
    // 查看表单配置
    viewForm: {},
  },
};

字段类型

类型说明示例
text文本输入用户名、标题
textarea多行文本备注、描述
number数字输入年龄、数量
password密码输入密码
select下拉选择状态
dict-select字典下拉带字典的选择
radio单选性别
checkbox多选爱好
switch开关是否启用
date日期生日
datetime日期时间创建时间
daterange日期范围查询时间段
time时间开始时间
cascader级联选择省市区
tree-select树选择部门
upload文件上传头像、附件
editor富文本文章内容

request 请求配置

typescript
const crudOptions = {
  request: {
    // 分页查询
    pageRequest: async (query) => {
      // query 包含: page, limit, 搜索条件
      const { page, limit, ...searchParams } = query;
      const res = await api.list({ current: page, size: limit, ...searchParams });
      return {
        records: res.data.records,
        total: res.data.total,
        currentPage: res.data.current,
        pageSize: res.data.size,
      };
    },
    
    // 新增
    addRequest: async ({ form }) => {
      return await api.create(form);
    },
    
    // 编辑
    editRequest: async ({ form, row }) => {
      return await api.update(row.id, form);
    },
    
    // 删除
    delRequest: async ({ row }) => {
      return await api.delete(row.id);
    },
    
    // 详情(查看时获取)
    infoRequest: async ({ row }) => {
      return await api.getInfo(row.id);
    },
  },
};

高级功能

字典使用

typescript
const columns = {
  status: {
    title: '状态',
    type: 'dict-select',
    dict: {
      // 方式一:静态数据
      data: [
        { label: '启用', value: 1, color: 'success' },
        { label: '禁用', value: 0, color: 'error' },
      ],
      
      // 方式二:远程字典
      url: '/api/dict/status',
      
      // 方式三:自定义获取
      getData: async () => {
        const res = await getDictData('sys_status');
        return res.data;
      },
    },
  },
};

表单联动

typescript
const columns = {
  type: {
    title: '类型',
    type: 'dict-select',
    dict: { data: [{ label: '个人', value: 1 }, { label: '企业', value: 2 }] },
    form: {
      valueChange: ({ form, value }) => {
        // 切换类型时,清空关联字段
        if (value === 1) {
          form.companyName = '';
        } else {
          form.idCard = '';
        }
      },
    },
  },
  companyName: {
    title: '公司名称',
    type: 'text',
    form: {
      // 仅企业类型显示
      show: compute(({ form }) => form.type === 2),
    },
  },
  idCard: {
    title: '身份证号',
    type: 'text',
    form: {
      // 仅个人类型显示
      show: compute(({ form }) => form.type === 1),
    },
  },
};

自定义列渲染

typescript
const columns = {
  avatar: {
    title: '头像',
    type: 'text',
    column: {
      cellRender: ({ row }) => {
        return <a-avatar src={row.avatar} />;
      },
    },
  },
  status: {
    title: '状态',
    type: 'dict-select',
    column: {
      cellRender: ({ row }) => {
        const color = row.status === 1 ? 'green' : 'red';
        const text = row.status === 1 ? '启用' : '禁用';
        return <a-tag color={color}>{text}</a-tag>;
      },
    },
  },
};

自定义操作按钮

typescript
const crudOptions = {
  rowHandle: {
    width: 200,
    buttons: {
      view: { show: true },   // 查看按钮
      edit: { show: true },   // 编辑按钮
      remove: { show: true }, // 删除按钮
      // 自定义按钮
      audit: {
        text: '审核',
        type: 'primary',
        show: compute(({ row }) => row.status === 0),
        click: async ({ row }) => {
          await auditApi(row.id);
          crudExpose.doRefresh();
        },
      },
    },
  },
};

工具栏配置

typescript
const crudOptions = {
  toolbar: {
    buttons: {
      add: { show: true },      // 新增按钮
      refresh: { show: true },  // 刷新按钮
      export: { show: true },   // 导出按钮
      // 自定义按钮
      import: {
        text: '导入',
        icon: 'ant-design:upload-outlined',
        click: () => {
          // 打开导入弹窗
        },
      },
    },
  },
};

权限控制

typescript
import { usePermission } from '@/hooks/web/usePermission';

const { hasPermission } = usePermission();

const crudOptions = {
  toolbar: {
    buttons: {
      add: { show: hasPermission('user:add') },
    },
  },
  rowHandle: {
    buttons: {
      edit: { show: hasPermission('user:edit') },
      remove: { show: hasPermission('user:delete') },
    },
  },
};

完整示例

以下是一个用户管理页面的完整示例:

vue
<script setup lang="ts">
import { ref } from 'vue';
import { useFs, compute } from '@fast-crud/fast-crud';
import { message } from 'ant-design-vue';
import { getUserList, createUser, updateUser, deleteUser, resetPassword } from './api';
import { usePermission } from '@/hooks/web/usePermission';

const { hasPermission } = usePermission();

const { crudBinding, crudRef, crudExpose } = useFs({
  crudOptions: {
    request: {
      pageRequest: async (query) => {
        const { page, limit, ...params } = query;
        const res = await getUserList({ current: page, size: limit, ...params });
        return { records: res.data.records, total: res.data.total };
      },
      addRequest: async ({ form }) => {
        await createUser(form);
        message.success('创建成功');
      },
      editRequest: async ({ form }) => {
        await updateUser(form.id, form);
        message.success('更新成功');
      },
      delRequest: async ({ row }) => {
        await deleteUser(row.id);
        message.success('删除成功');
      },
    },
    
    toolbar: {
      buttons: {
        add: { show: hasPermission('user:add') },
      },
    },
    
    rowHandle: {
      width: 220,
      buttons: {
        view: { show: true },
        edit: { show: hasPermission('user:edit') },
        remove: { show: hasPermission('user:delete') },
        resetPwd: {
          text: '重置密码',
          type: 'link',
          show: hasPermission('user:resetPwd'),
          click: async ({ row }) => {
            await resetPassword(row.id);
            message.success('密码已重置为 123456');
          },
        },
      },
    },
    
    columns: {
      id: {
        title: 'ID',
        type: 'text',
        column: { width: 80 },
        form: { show: false },
      },
      avatar: {
        title: '头像',
        type: 'avatar-uploader',
        column: {
          width: 80,
          align: 'center',
        },
      },
      username: {
        title: '用户名',
        type: 'text',
        search: { show: true },
        form: {
          rules: [{ required: true, message: '请输入用户名' }],
        },
        editForm: { disabled: true },
      },
      nickname: {
        title: '昵称',
        type: 'text',
        form: {
          rules: [{ required: true, message: '请输入昵称' }],
        },
      },
      email: {
        title: '邮箱',
        type: 'text',
        search: { show: true },
        form: {
          rules: [
            { required: true, message: '请输入邮箱' },
            { type: 'email', message: '请输入有效的邮箱地址' },
          ],
        },
      },
      mobile: {
        title: '手机号',
        type: 'text',
        search: { show: true },
        form: {
          rules: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入有效的手机号' }],
        },
      },
      deptId: {
        title: '部门',
        type: 'tree-select',
        form: {
          component: {
            loadData: async () => {
              const res = await getDeptTree();
              return res.data;
            },
            fieldNames: { label: 'name', value: 'id' },
          },
        },
        column: {
          formatter: ({ row }) => row.deptName,
        },
      },
      roleIds: {
        title: '角色',
        type: 'select',
        form: {
          component: {
            mode: 'multiple',
            options: async () => {
              const res = await getRoleList();
              return res.data.map((item) => ({ label: item.name, value: item.id }));
            },
          },
        },
        column: { show: false },
      },
      status: {
        title: '状态',
        type: 'dict-select',
        search: { show: true },
        dict: {
          data: [
            { label: '启用', value: 1, color: 'success' },
            { label: '禁用', value: 0, color: 'error' },
          ],
        },
      },
      createTime: {
        title: '创建时间',
        type: 'datetime',
        form: { show: false },
        column: { width: 180 },
      },
    },
  },
});
</script>

<template>
  <div class="user-manage">
    <fs-crud ref="crudRef" v-bind="crudBinding" />
  </div>
</template>

<style scoped>
.user-manage {
  padding: 16px;
}
</style>

下一步