Skip to content
Naive Potato UI
Main Navigation指南组件

Appearance

Sidebar Navigation

组件

Curd Table Curd表格

Async Select 异步选择

Custom Upload 自定义上传

页面导航
Table of Contents for current page

Curd表格 Curd Table ​

演示 ​

包含增删查改,即curd所有功能的表格

基础表格
请输入姓名
请输入部门
开始日期
结束日期
请选择部门
请输入手机号
序号
姓名
部门
年龄
部门
手机号
操作
无数据
共 0 条
1
10 / 页
跳至
vue
<template>
  <div class="h-600px">
    <np-curd-table
      :headers="headers"
      v-model:choosen="choosen"
      :query="handleQuery"
      :query-detail="handleQueryDetail"
      :create="handleCreate"
      :edit="handleEditError"
      :delete="handleDelete"
      :cols="2"
      :action-width="400"
      serial-number
    >
      <template #prefixAction>
        <n-button type="error" quaternary>Prefix</n-button>
      </template>
      <template #suffixAction>
        <n-button type="info" quaternary>Suffix</n-button>
      </template>
    </np-curd-table>
  </div>
</template>

<script setup lang="ts">
import { NpCurdTable, NpCurdTableHeader } from '@naive-potato-ui/ui';
import { NButton } from 'naive-ui';
import { ref, h } from 'vue';

type ResInfo = {
  uuid: string;
  name: string;
  age: number;
  department: string[];
  phone: string;
  create_department: {
    name: string;
    id: string;
  };
};

const headers: NpCurdTableHeader<ResInfo>[] = [
  {
    title: '姓名',
    key: 'name',
    type: 'text',
    column: true,
    query: true,
    defaultConfig: {
      show: true,
      type: 'text',
      default: '人社局',
      rule: {
        trigger: 'blur',
        required: true,
        message: '请确定账号是否绑定部门',
      },
    },
    create: true,
    edit: true,
    info: {
      show: true,
      type: 'custom',
      render: null,
    },
  },
  {
    title: '部门',
    key: 'create_department',
    infoRender: (row) => row.create_department?.name,
    column: {
      show: true,
      key: 'create_department',
      title: '部门',
      type: 'custom',
    },
    query: true,
    type: 'text',
  },
  {
    title: '年龄',
    key: 'age',
    type: 'number',
    infoRender(row: any) {
      return row.age + '岁';
    },
    column: true,
    query: {
      show: true,
      type: 'date',
      config: {
        format: 'yyyy-MM-dd',
        range: true,
        startField: 'start_date',
        endField: 'end_date',
      },
    },
    create: {
      show: true,
      type: 'text',
      required: true,
    },
    edit: true,
    info: true,
  },
  {
    title: '部门',
    key: 'department',
    type: 'multSelect',
    column: true,
    defaultConfig: {
      type: 'multSelect',
      config: {
        options: [
          {
            label: '技术部',
            value: '技术部',
          },
          {
            label: '市场部',
            value: '市场部',
          },
          {
            label: '财务部',
            value: '财务部',
          },
          {
            label: '行政部',
            value: '行政部',
          },
        ],
      },
    },
    query: true,
    create: {
      show: true,
      required: true,
    },
    edit: true,
    info: true,
  },
  {
    title: '手机号',
    key: 'phone',
    type: 'text',
    column: true,
    query: true,
    create: {
      show: true,
      required: true,
    },
    edit: true,
    info: true,
  },
];

interface Employee {
  uuid: string;
  name: string;
  age: number;
  department: string;
  phone: string;
}
async function handleQuery(params: any): Promise<Record<string, any>> {
  console.log(params);

  const departments = ['技术部', '市场部', '财务部', '行政部'];

  const employees: Employee[] = [];

  for (let i = 0; i < 10; i++) {
    const uid = 'uuid' + Math.floor(Math.random() * 1000000000);

    const name = '员工' + (i + 1);

    const age = Math.floor(Math.random() * 15) + 22;

    const department =
      departments[Math.floor(Math.random() * departments.length)];

    const phone =
      '138' + Math.floor(Math.random() * 10000000 + 10000000).toString();

    employees.push({
      uuid: uid.toString(),
      name,
      age,
      department,
      phone,
    });
  }

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        data: employees,
        count: 100,
      });
    }, 1000);
  });
}

async function handleQueryDetail(
  params: Record<string, any>,
): Promise<ResInfo> {
  const departments = ['技术部', '市场部', '财务部', '行政部'];

  const uid = Math.floor(Math.random() * 15) + 22;
  const name = '员工' + (Math.random() * 15 + 1);

  const age = Math.floor(Math.random() * 15) + 22;

  const department =
    departments[Math.floor(Math.random() * departments.length)];

  const phone =
    '138' + Math.floor(Math.random() * 10000000 + 10000000).toString();

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        uuid: uid.toString(),
        name,
        age,
        department: [department],
        phone,
        create_department: {
          name: department,
          id: 'id' + Math.floor(Math.random() * 1000000000),
        },
      });
    }, 1000);
  });
}

async function handleCreate(data: any) {
  console.log(`创建`, data);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        data: {
          code: 200,
          message: '创建成功',
          data: {},
        },
        count: 100,
      });
    }, 1000);
  });
}

// async function handleEdit(data: any) {
//   console.log(`编辑`, data);
//   return new Promise((resolve, reject) => {
//     setTimeout(() => {
//       resolve({
//         data: {
//           code: 200,
//           message: '创建成功',
//           data: {},
//         },
//         count: 100,
//       });
//     }, 1000);
//   });
// }

async function handleEditError(data: any) {
  console.log(`编辑`, data);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject({
        data: {
          code: 400,
          message: '创建失败,测试失败消息',
          data: {},
        },
        count: 100,
      });
    }, 1000);
  });
}

async function handleDelete(data: any) {
  console.log(`删除`, data);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        data: {
          code: 200,
          message: '删除成功',
          data: {},
        },
        count: 100,
      });
    }, 1000);
  });
}

const choosen = ref('');

// Prefix and suffix action btn
const prefixAction = (row: ResInfo) => {
  return h(
    NButton,
    {
      type: 'primary',
      size: 'small',
      secondary: true,
      onClick: () => {
        console.log(row);
      },
    },
    { default: () => 'Prefix' },
  );
};
const suffixAction = (row: ResInfo) => {
  return h('div', { class: 'flex items-center gap-2' }, [
    h(
      NButton,
      { type: 'warning', size: 'small', secondary: true },
      { default: () => 'Suffix1' },
    ),
    h(
      NButton,
      { type: 'info', size: 'small', secondary: true },
      { default: () => 'Suffix2' },
    ),
  ]);
};
</script>

<style scoped></style>

API ​

Props ​

  • *headersNCurdTableHeader[]:表格的配置文件,具体见下表
  • *query(queryParams: Record<string, any>) => Promise<Record<string, any>>:查询列表的查询方法,接受查询参数(在props.headers中配置)并返回查询结果列表,返回结果格式需要符合要求
  • messageRecord<success|info|warning|error,Function>:消息提示方法,必须为对象,包含success、info、warning、error四个方法
  • countFieldstring:查询结果中的总数字段名
  • dataFieldstring:查询结果中的数据列表字段名
  • idFieldstring:查询结果中数据列表的id字段名
  • extraQueryRecord<string, any>:查询列表的额外参数,会与查询参数合并
  • serialNumberboolean:是否显示序号列
  • checkableboolean:是否显示复选框列
  • checkDisabled(row: Record<string, any>) => boolean:复选框是否禁用的判断方法,接受当前行数据,返回布尔值
  • checkedstring[] | number[]:复选框选中的行的id数组
  • rowKey[(row: TInfo) => string | number](row => row[rowKeyField|'uuid']):行的key的生成方法,接受当前行数据,返回字符串或数字,不复杂的情况下直接设置rowKeyField
  • rowKeyFieldstring:行的key的字段名
  • prefixAction(row: TInfo | Record<string, any>) => VNode:默认操作列前面的操作按钮,接受当前行数据,返回VNode
  • suffixAction(row: TInfo | Record<string, any>) => VNode:默认操作列后面的操作按钮,接受当前行数据,返回VNode
  • actionWidthnumber:操作列的宽度(px)
  • choosenstring | number:当前操作选中的行的id(编辑、详情和删除操作)
  • colsnumber:新增、编辑、详情时显示的列数;
  • createFunction:新增方法,接受新增的数据表单,未设置时顶部新增按钮不会显示
  • queryDetailFunction:查询详情方法,接受当前行数据,返回详情数据,未设置时详情按钮不会显示
  • editFunction:编辑方法,接受编辑的行数据表单,未设置时编辑按钮不会显示
  • deleteFunction:删除方法,接受删除的行数据,未设置时删除按钮不会显示
  • hideCreateboolean:是否隐藏新增按钮
  • hideColumnEditboolean:是否隐藏列编辑按钮
  • editable(row: TInfo) => boolean:是否可编辑的判断方法,接受当前行数据,返回布尔值
  • hideColumnInfoboolean:是否隐藏列信息按钮
  • infoable(row: TInfo) => boolean:是否可查看详情的判断方法,接受当前行数据,返回布尔值
  • hideColumnDeleteboolean:是否隐藏列删除按钮
  • deletable(row: TInfo) => boolean:是否可删除的判断方法,接受当前行数据,返回布尔值
  • hideActionboolean:是否隐藏整个操作列
NameTypeDefaultDescription
headers必须
NCurdTableHeader[]
-

表格的配置文件,具体见下表

query必须
(queryParams: Record<string, any>) => Promise<Record<string, any>>
-

查询列表的查询方法,接受查询参数(在props.headers中配置)并返回查询结果列表,返回结果格式需要符合要求

message
Record<success|info|warning|error,Function>
-

消息提示方法,必须为对象,包含success、info、warning、error四个方法

countField
string
'count'

查询结果中的总数字段名

dataField
string
'data'

查询结果中的数据列表字段名

idField
string
'uuid'

查询结果中数据列表的id字段名

extraQuery
Record<string, any>
{}

查询列表的额外参数,会与查询参数合并

serialNumber
boolean
false

是否显示序号列

checkable
boolean
false

是否显示复选框列

checkDisabled
(row: Record<string, any>) => boolean
false

复选框是否禁用的判断方法,接受当前行数据,返回布尔值

checked
string[] | number[]]([
[]

复选框选中的行的id数组

rowKey
(row: TInfo) => string | number](row => row[rowKeyField|'uuid'
row => row[rowKeyField|'uuid']

行的key的生成方法,接受当前行数据,返回字符串或数字,不复杂的情况下直接设置rowKeyField

rowKeyField
string
'uuid'

行的key的字段名

prefixAction
(row: TInfo | Record<string, any>) => VNode
undefined

默认操作列前面的操作按钮,接受当前行数据,返回VNode

suffixAction
(row: TInfo | Record<string, any>) => VNode
undefined

默认操作列后面的操作按钮,接受当前行数据,返回VNode

actionWidth
number
'auto'

操作列的宽度(px)

choosen
string | number

当前操作选中的行的id(编辑、详情和删除操作)

cols
number
1

新增、编辑、详情时显示的列数;

create
Function
undefined

新增方法,接受新增的数据表单,未设置时顶部新增按钮不会显示

queryDetail
Function
undefined

查询详情方法,接受当前行数据,返回详情数据,未设置时详情按钮不会显示

edit
Function
undefined

编辑方法,接受编辑的行数据表单,未设置时编辑按钮不会显示

delete
Function
undefined

删除方法,接受删除的行数据,未设置时删除按钮不会显示

hideCreate
boolean
false

是否隐藏新增按钮

hideColumnEdit
boolean
false

是否隐藏列编辑按钮

editable
(row: TInfo) => boolean
false

是否可编辑的判断方法,接受当前行数据,返回布尔值

hideColumnInfo
boolean
false

是否隐藏列信息按钮

infoable
(row: TInfo) => boolean
false

是否可查看详情的判断方法,接受当前行数据,返回布尔值

hideColumnDelete
boolean
false

是否隐藏列删除按钮

deletable
(row: TInfo) => boolean
false

是否可删除的判断方法,接受当前行数据,返回布尔值

hideAction
boolean
false

是否隐藏整个操作列

表格配置文件 ​

NpCurdTableHeader,props.header的类型,本组件的配置类型

基础配置 ​

基础部分的配置,TForm为列表接口返回的数据类型,TInfo为详情接口返回的数据类型

  • info部分指的是在组件中显示的部分,包括表格内的显示,详情的显示;
  • form部分指的是在组件中编辑的部分,包括表格内的编辑,新增的编辑,详情的编辑以及查询时的form部分;
  • *titlestring:列标题,在表格列头显示
  • *key keyof TForm | string:列的字段名,用于在查询结果中取值
  • infoRender(info: TInfo) => VNode | string | number:渲染详情的默认方法,渲染详情的时候如果没有单独配置,则使用此方法渲染
  • formRender(form: TForm) => VNode | string | number:渲染表单的默认方法,渲染表单的时候如果没有单独配置,则使用此方法渲染
  • defaultany:默认值,用于新增时的表单默认值
  • defaultConfigNCurdTableHeaderRenderOptions< TForm, TInfo >:当显示和编辑都为同义字段,且显示/编辑的逻辑一样,可以只编辑此配置,后续下面的配置未设置时会使用此配置
  • columnNCurdTableHeaderColumn< TForm, TInfo>:表格中显示的配置
  • queryNCurdTableHeaderQuery< TForm >:查询时的配置
  • createNCurdTableHeaderCreate< TForm >:新增时的配置
  • editNCurdTableHeaderEdit< TForm >:编辑时的配置
  • infoNCurdTableHeaderInfo< TInfo >:详情时的配置
NameTypeDefaultDescription
title必须
string
-

列标题,在表格列头显示

key必须
keyof TForm | string
-

列的字段名,用于在查询结果中取值

infoRender
(info: TInfo) => VNode | string | number
-

渲染详情的默认方法,渲染详情的时候如果没有单独配置,则使用此方法渲染

formRender
(form: TForm) => VNode | string | number
-

渲染表单的默认方法,渲染表单的时候如果没有单独配置,则使用此方法渲染

default
any
undefined

默认值,用于新增时的表单默认值

defaultConfig
NCurdTableHeaderRenderOptions< TForm, TInfo >
-

当显示和编辑都为同义字段,且显示/编辑的逻辑一样,可以只编辑此配置,后续下面的配置未设置时会使用此配置

column
NCurdTableHeaderColumn< TForm, TInfo>
-

表格中显示的配置

query
NCurdTableHeaderQuery< TForm >
-

查询时的配置

create
NCurdTableHeaderCreate< TForm >
-

新增时的配置

edit
NCurdTableHeaderEdit< TForm >
-

编辑时的配置

info
NCurdTableHeaderInfo< TInfo >
-

详情时的配置

渲染配置 ​

渲染的配置,用于配置当前字段的显示和编辑的逻辑,单个配置在显示和编辑时的渲染方式已经预先配置好,如果需要自定义渲染方式,可以在设置时使用类型custom,并在render属性中配置自定义渲染方法

当前字段类型有(NCurdTableHeaderType):

类型说明
text文本
textarea多行文本
password密码
number数字
select下拉框
multSelect多选下拉框
asyncSelect异步选择(需引入 AsyncSelect)
radio单选框
date日期
datetime日期时间
time时间
upload上传
custom自定义渲染组件
渲染基础配置 ​
  • titlestring:字段标题,用于表格表头,表单label
  • showboolean:是否展示该字段(即使不展示,该字段也会在query,create,edit表单中存在)
  • active(row: TForm, info?: TInfo) => boolean:根据数据判断是否在表单中展示该字段,为false时,不会渲染,在最终提交表单时,也不会提交该字段
  • disabled(row: TForm, info?: TInfo) => boolean:根据数据判断是否禁用该字段,为true时,不可编辑
  • typeNCurdTableHeaderRenderType:字段展示和编辑的类型,用于表单的渲染
  • configRecord<string,any>:字段展示和编辑的配置,根据不同的 type 配置不同,用于表单的渲染,更多具体配置见下表
  • render(row: TForm, info?: TInfo) => VNode | string | number:字段展示和编辑的自定义渲染方法,当字段 type 为 custom 时,用于表单的渲染
  • defaultany:默认值,用于新增时的表单默认值
  • requiredboolean:简单根据是否填写/选择判断是否必填,用于表单的渲染,复杂判断条件使用 rules 属性
  • rulesRecord<string,any>[]:校验规则,当判断规则比较复杂时覆盖 required 属性,用于表单的渲染
NameTypeDefaultDescription
title
string
-

字段标题,用于表格表头,表单label

show
boolean
true

是否展示该字段(即使不展示,该字段也会在query,create,edit表单中存在)

active
(row: TForm, info?: TInfo) => boolean
-

根据数据判断是否在表单中展示该字段,为false时,不会渲染,在最终提交表单时,也不会提交该字段

disabled
(row: TForm, info?: TInfo) => boolean
-

根据数据判断是否禁用该字段,为true时,不可编辑

type
NCurdTableHeaderRenderType
'text'

字段展示和编辑的类型,用于表单的渲染

config
Record<string,any>
undefined

字段展示和编辑的配置,根据不同的 type 配置不同,用于表单的渲染,更多具体配置见下表

render
(row: TForm, info?: TInfo) => VNode | string | number
-

字段展示和编辑的自定义渲染方法,当字段 type 为 custom 时,用于表单的渲染

default
any
undefined

默认值,用于新增时的表单默认值

required
boolean
false

简单根据是否填写/选择判断是否必填,用于表单的渲染,复杂判断条件使用 rules 属性

rules
Record<string,any>[]
undefined

校验规则,当判断规则比较复杂时覆盖 required 属性,用于表单的渲染

渲染类型配置 ​

根据渲染类型的不同(type),进行相应的配置,下方列出的为 type 为特定值时,config 的配置

字符类型 ​

type 为'text' | 'textarea' | 'password' | 'number'

  • prefix() => VNode:前缀,在显示和编辑时会显示在前面,一般用于显示单位
  • suffix() => VNode:后缀,在显示和编辑时会显示在后面,一般用于显示单位,状态或功能按钮
NameTypeDefaultDescription
prefix
() => VNode
-

前缀,在显示和编辑时会显示在前面,一般用于显示单位

suffix
() => VNode
-

后缀,在显示和编辑时会显示在后面,一般用于显示单位,状态或功能按钮

选择类型 ​

type 为'select' | 'multSelect'

  • optionsArray<SelectOption | SelectGroupOption>:下拉框的选项,格式参考Naive UI 的 Select - options
  • labelFieldstring:下拉框选项的label字段名
  • valueFieldstring:下拉框选项的value字段名
NameTypeDefaultDescription
options
Array<SelectOption | SelectGroupOption>
-

下拉框的选项,格式参考Naive UI 的 Select - options

labelField
string
'label'

下拉框选项的label字段名

valueField
string
'value'

下拉框选项的value字段名

异步选择类型 ​

type 为'asyncSelect'

需引入 AsyncSelect , config配置参考AsyncSelect props

单选类型 ​

type 为'radio'

同选择类型

日期类型 ​

type 为'date' | 'datetime'

  • *formatstring:日期格式(见🔗date-fns format 文档)
  • rangeboolean:是否为范围选择
  • startFieldstring:范围选择的开始字段名
  • endFieldstring:范围选择的结束字段名
NameTypeDefaultDescription
format必须
string](-):日期格式(见[🔗date-fns format 文档
-

日期格式(见🔗date-fns format 文档)

range
boolean
false

是否为范围选择

startField
string
'start'

范围选择的开始字段名

endField
string
'end'

范围选择的结束字段名

时间类型 ​

type 为'time'

  • *formatstring:时间格式(见🔗date-fns format 文档)
  • rangeboolean:是否为范围选择
NameTypeDefaultDescription
format必须
string](-):时间格式(见[🔗date-fns format 文档
-

时间格式(见🔗date-fns format 文档)

range
boolean
false

是否为范围选择

Method ​

方法名说明参数
resetQuery重置查询,恢复到默认状态-
queryData基于当前查询刷新数据-
Next pageAsync Select 异步选择