feat: add vxe-table component (#4563)
* chore: wip vxe-table * feat: add table demo * chore: follow ci recommendations to adjust details * chore: add custom-cell demo * feat: add custom-cell table demo * feat: add table from demo
This commit is contained in:
@@ -1 +1,2 @@
|
||||
export * from './form';
|
||||
export * from './vxe-table';
|
||||
|
59
playground/src/adapter/vxe-table.ts
Normal file
59
playground/src/adapter/vxe-table.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { h } from 'vue';
|
||||
|
||||
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
|
||||
|
||||
import { Button, Image } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from './form';
|
||||
|
||||
setupVbenVxeTable({
|
||||
configVxeTable: (vxeUI) => {
|
||||
vxeUI.setConfig({
|
||||
grid: {
|
||||
align: 'center',
|
||||
border: true,
|
||||
minHeight: 180,
|
||||
proxyConfig: {
|
||||
autoLoad: true,
|
||||
response: {
|
||||
result: 'items',
|
||||
total: 'total',
|
||||
list: 'items',
|
||||
},
|
||||
showActiveMsg: true,
|
||||
showResponseMsg: false,
|
||||
},
|
||||
round: true,
|
||||
size: 'small',
|
||||
},
|
||||
});
|
||||
|
||||
// 表格配置项可以用 cellRender: { name: 'CellImage' },
|
||||
vxeUI.renderer.add('CellImage', {
|
||||
renderDefault(_renderOpts, params) {
|
||||
const { column, row } = params;
|
||||
return h(Image, { src: row[column.field] });
|
||||
},
|
||||
});
|
||||
|
||||
// 表格配置项可以用 cellRender: { name: 'CellLink' },
|
||||
vxeUI.renderer.add('CellLink', {
|
||||
renderDefault(renderOpts) {
|
||||
const { props } = renderOpts;
|
||||
return h(
|
||||
Button,
|
||||
{ size: 'small', type: 'link' },
|
||||
{ default: () => props?.text },
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
|
||||
// vxeUI.formats.add
|
||||
},
|
||||
useVbenForm,
|
||||
});
|
||||
|
||||
export { useVbenVxeGrid };
|
||||
|
||||
export type * from '@vben/plugins/vxe-table';
|
@@ -1 +1,2 @@
|
||||
export * from './status';
|
||||
export * from './table';
|
18
playground/src/api/examples/table.ts
Normal file
18
playground/src/api/examples/table.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace DemoTableApi {
|
||||
export interface PageFetchParams {
|
||||
[key: string]: any;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取示例表格数据
|
||||
*/
|
||||
async function getExampleTableApi(params: DemoTableApi.PageFetchParams) {
|
||||
return requestClient.get('/table/list', { params });
|
||||
}
|
||||
|
||||
export { getExampleTableApi };
|
@@ -1,2 +1,2 @@
|
||||
export * from './core';
|
||||
export * from './demos';
|
||||
export * from './examples';
|
||||
|
@@ -82,6 +82,18 @@
|
||||
"api": "Api",
|
||||
"merge": "Merge Form"
|
||||
},
|
||||
"vxeTable": {
|
||||
"title": "Vxe Table",
|
||||
"basic": "Basic Table",
|
||||
"remote": "Remote Load",
|
||||
"tree": "Tree Table",
|
||||
"fixed": "Fixed Header/Column",
|
||||
"virtual": "Virtual Scroll",
|
||||
"editCell": "Edit Cell",
|
||||
"editRow": "Edit Row",
|
||||
"custom-cell": "Custom Cell",
|
||||
"form": "Form Table"
|
||||
},
|
||||
"captcha": {
|
||||
"title": "Captcha",
|
||||
"pointSelection": "Point Selection Captcha",
|
||||
|
@@ -82,6 +82,18 @@
|
||||
"api": "Api",
|
||||
"merge": "合并表单"
|
||||
},
|
||||
"vxeTable": {
|
||||
"title": "Vxe 表格",
|
||||
"basic": "基础表格",
|
||||
"remote": "远程加载",
|
||||
"tree": "树形表格",
|
||||
"fixed": "固定表头/列",
|
||||
"virtual": "虚拟滚动",
|
||||
"editCell": "单元格编辑",
|
||||
"editRow": "行编辑",
|
||||
"custom-cell": "自定义单元格",
|
||||
"form": "开启搜索表单"
|
||||
},
|
||||
"captcha": {
|
||||
"title": "验证码",
|
||||
"pointSelection": "点选验证",
|
||||
|
@@ -42,7 +42,6 @@ const routes: RouteRecordRaw[] = [
|
||||
title: $t('page.examples.ellipsis.title'),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'FormExample',
|
||||
path: '/examples/form',
|
||||
@@ -109,6 +108,89 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'VxeTableExample',
|
||||
path: '/examples/vxe-table',
|
||||
meta: {
|
||||
icon: 'lucide:table',
|
||||
title: $t('page.examples.vxeTable.title'),
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'VxeTableBasicExample',
|
||||
path: '/examples/vxe-table/basic',
|
||||
component: () => import('#/views/examples/vxe-table/basic.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.basic'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableRemoteExample',
|
||||
path: '/examples/vxe-table/remote',
|
||||
component: () => import('#/views/examples/vxe-table/remote.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.remote'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableTreeExample',
|
||||
path: '/examples/vxe-table/tree',
|
||||
component: () => import('#/views/examples/vxe-table/tree.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.tree'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableFixedExample',
|
||||
path: '/examples/vxe-table/fixed',
|
||||
component: () => import('#/views/examples/vxe-table/fixed.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.fixed'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableCustomCellExample',
|
||||
path: '/examples/vxe-table/custom-cell',
|
||||
component: () =>
|
||||
import('#/views/examples/vxe-table/custom-cell.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.custom-cell'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableFormExample',
|
||||
path: '/examples/vxe-table/form',
|
||||
component: () => import('#/views/examples/vxe-table/form.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.form'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableEditCellExample',
|
||||
path: '/examples/vxe-table/edit-cell',
|
||||
component: () => import('#/views/examples/vxe-table/edit-cell.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.editCell'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableEditRowExample',
|
||||
path: '/examples/vxe-table/edit-row',
|
||||
component: () => import('#/views/examples/vxe-table/edit-row.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.editRow'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VxeTableVirtualExample',
|
||||
path: '/examples/vxe-table/virtual',
|
||||
component: () => import('#/views/examples/vxe-table/virtual.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.vxeTable.virtual'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'CaptchaExample',
|
||||
path: '/examples/captcha',
|
||||
|
@@ -12,5 +12,5 @@ function handleClick() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button type="link" @click="handleClick">查看组件文档</Button>
|
||||
<Button @click="handleClick">查看组件文档</Button>
|
||||
</template>
|
||||
|
@@ -6,6 +6,8 @@ import dayjs from 'dayjs';
|
||||
|
||||
import { useVbenForm } from '#/adapter';
|
||||
|
||||
import DocButton from '../doc-button.vue';
|
||||
|
||||
const [BaseForm, baseFormApi] = useVbenForm({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
@@ -329,6 +331,9 @@ function handleSetFormValue() {
|
||||
description="表单组件基础示例,请注意,该页面用到的参数代码会添加一些简单注释,方便理解,请仔细查看。"
|
||||
title="表单组件"
|
||||
>
|
||||
<template #extra>
|
||||
<DocButton path="/components/common-ui/vben-form" />
|
||||
</template>
|
||||
<Card title="基础示例">
|
||||
<template #extra>
|
||||
<Button type="primary" @click="handleSetFormValue">设置表单值</Button>
|
||||
|
93
playground/src/views/examples/vxe-table/basic.vue
Normal file
93
playground/src/views/examples/vxe-table/basic.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridListeners, VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
|
||||
import DocButton from '../doc-button.vue';
|
||||
import { MOCK_TABLE_DATA } from './table-data';
|
||||
|
||||
interface RowType {
|
||||
address: string;
|
||||
age: number;
|
||||
id: number;
|
||||
name: string;
|
||||
nickname: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ field: 'name', title: 'Name' },
|
||||
{ field: 'age', sortable: true, title: 'Age' },
|
||||
{ field: 'nickname', title: 'Nickname' },
|
||||
{ field: 'role', title: 'Role' },
|
||||
{ field: 'address', showOverflow: true, title: 'Address' },
|
||||
],
|
||||
data: MOCK_TABLE_DATA,
|
||||
sortConfig: {
|
||||
multiple: true,
|
||||
},
|
||||
};
|
||||
|
||||
const gridEvents: VxeGridListeners<RowType> = {
|
||||
cellClick: ({ row }) => {
|
||||
message.info(`cell-click: ${row.name}`);
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridEvents, gridOptions });
|
||||
|
||||
const showBorder = gridApi.useStore((state) => state.gridOptions?.border);
|
||||
const showStripe = gridApi.useStore((state) => state.gridOptions?.stripe);
|
||||
|
||||
function changeBorder() {
|
||||
gridApi.setGridOptions({
|
||||
border: !showBorder.value,
|
||||
});
|
||||
}
|
||||
|
||||
function changeStripe() {
|
||||
gridApi.setGridOptions({
|
||||
stripe: !showStripe.value,
|
||||
});
|
||||
}
|
||||
|
||||
function changeLoading() {
|
||||
gridApi.setLoading(true);
|
||||
setTimeout(() => {
|
||||
gridApi.setLoading(false);
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page
|
||||
description="表格组件常用于快速开发数据展示与交互界面,示例数据为静态数据。该组件是对vxe-table进行简单的二次封装,大部分属性与方法与vxe-table保持一致。"
|
||||
title="表格基础示例"
|
||||
>
|
||||
<template #extra>
|
||||
<DocButton path="/components/common-ui/vben-vxe-table" />
|
||||
</template>
|
||||
<Grid>
|
||||
<template #toolbar-actions>
|
||||
<Button class="mr-2" type="primary">左右按钮插槽</Button>
|
||||
</template>
|
||||
<template #toolbar-tools>
|
||||
<Button class="mr-2" type="primary" @click="changeBorder">
|
||||
{{ showBorder ? '隐藏' : '显示' }}边框
|
||||
</Button>
|
||||
<Button class="mr-2" type="primary" @click="changeLoading">
|
||||
显示loading
|
||||
</Button>
|
||||
<Button class="mr-2" type="primary" @click="changeStripe">
|
||||
{{ showStripe ? '隐藏' : '显示' }}斑马纹
|
||||
</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
110
playground/src/views/examples/vxe-table/custom-cell.vue
Normal file
110
playground/src/views/examples/vxe-table/custom-cell.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Button, Image, Switch, Tag } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
import { getExampleTableApi } from '#/api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
imageUrl: string;
|
||||
open: boolean;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
status: 'error' | 'success' | 'warning';
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
labelField: 'name',
|
||||
},
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ field: 'category', title: 'Category', width: 100 },
|
||||
{
|
||||
field: 'imageUrl',
|
||||
slots: { default: 'image-url' },
|
||||
title: 'Image',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
cellRender: { name: 'CellImage' },
|
||||
field: 'imageUrl2',
|
||||
title: 'Render Image',
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
field: 'open',
|
||||
slots: { default: 'open' },
|
||||
title: 'Open',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
slots: { default: 'status' },
|
||||
title: 'Status',
|
||||
width: 100,
|
||||
},
|
||||
{ field: 'color', title: 'Color', width: 100 },
|
||||
{ field: 'productName', title: 'Product Name', width: 200 },
|
||||
{ field: 'price', title: 'Price', width: 100 },
|
||||
{
|
||||
field: 'releaseDate',
|
||||
formatter: ({ cellValue }) => {
|
||||
return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
title: 'Date',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
cellRender: { name: 'CellLink', props: { text: '编辑' } },
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
title: '操作',
|
||||
width: 120,
|
||||
},
|
||||
],
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid>
|
||||
<template #image-url="{ row }">
|
||||
<Image :src="row.imageUrl" height="30" width="30" />
|
||||
</template>
|
||||
<template #open="{ row }">
|
||||
<Switch v-model:checked="row.open" />
|
||||
</template>
|
||||
<template #status="{ row }">
|
||||
<Tag :color="row.color">{{ row.status }}</Tag>
|
||||
</template>
|
||||
<template #action>
|
||||
<Button type="link">编辑</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
57
playground/src/views/examples/vxe-table/edit-cell.vue
Normal file
57
playground/src/views/examples/vxe-table/edit-cell.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
import { getExampleTableApi } from '#/api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ editRender: { name: 'input' }, field: 'category', title: 'Category' },
|
||||
{ editRender: { name: 'input' }, field: 'color', title: 'Color' },
|
||||
{
|
||||
editRender: { name: 'input' },
|
||||
field: 'productName',
|
||||
title: 'Product Name',
|
||||
},
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', title: 'Date' },
|
||||
],
|
||||
editConfig: {
|
||||
mode: 'cell',
|
||||
trigger: 'click',
|
||||
},
|
||||
height: 'auto',
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
showOverflow: true,
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid />
|
||||
</Page>
|
||||
</template>
|
94
playground/src/views/examples/vxe-table/edit-row.vue
Normal file
94
playground/src/views/examples/vxe-table/edit-row.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
import { getExampleTableApi } from '#/api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ editRender: { name: 'input' }, field: 'category', title: 'Category' },
|
||||
{ editRender: { name: 'input' }, field: 'color', title: 'Color' },
|
||||
{
|
||||
editRender: { name: 'input' },
|
||||
field: 'productName',
|
||||
title: 'Product Name',
|
||||
},
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', title: 'Date' },
|
||||
{ slots: { default: 'action' }, title: '操作' },
|
||||
],
|
||||
editConfig: {
|
||||
mode: 'row',
|
||||
trigger: 'click',
|
||||
},
|
||||
height: 'auto',
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
showOverflow: true,
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||
|
||||
function hasEditStatus(row: RowType) {
|
||||
return gridApi.grid?.isEditByRow(row);
|
||||
}
|
||||
|
||||
function editRowEvent(row: RowType) {
|
||||
gridApi.grid?.setEditRow(row);
|
||||
}
|
||||
|
||||
async function saveRowEvent(row: RowType) {
|
||||
await gridApi.grid?.clearEdit();
|
||||
|
||||
gridApi.setLoading(true);
|
||||
setTimeout(() => {
|
||||
gridApi.setLoading(false);
|
||||
message.success({
|
||||
content: `保存成功!category=${row.category}`,
|
||||
});
|
||||
}, 600);
|
||||
}
|
||||
|
||||
const cancelRowEvent = (_row: RowType) => {
|
||||
gridApi.grid?.clearEdit();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid>
|
||||
<template #action="{ row }">
|
||||
<template v-if="hasEditStatus(row)">
|
||||
<Button type="link" @click="saveRowEvent(row)">保存</Button>
|
||||
<Button type="link" @click="cancelRowEvent(row)">取消</Button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Button type="link" @click="editRowEvent(row)">编辑</Button>
|
||||
</template>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
64
playground/src/views/examples/vxe-table/fixed.vue
Normal file
64
playground/src/views/examples/vxe-table/fixed.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
import { getExampleTableApi } from '#/api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ fixed: 'left', title: '序号', type: 'seq', width: 50 },
|
||||
{ field: 'category', title: 'Category', width: 300 },
|
||||
{ field: 'color', title: 'Color', width: 300 },
|
||||
{ field: 'productName', title: 'Product Name', width: 300 },
|
||||
{ field: 'price', title: 'Price', width: 300 },
|
||||
{ field: 'releaseDate', title: 'Date', width: 500 },
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 120,
|
||||
},
|
||||
],
|
||||
height: 'auto',
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid>
|
||||
<template #action>
|
||||
<Button type="link">编辑</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
102
playground/src/views/examples/vxe-table/form.vue
Normal file
102
playground/src/views/examples/vxe-table/form.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VbenFormProps, VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
import { getExampleTableApi } from '#/api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
schema: [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'category',
|
||||
label: 'Category',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'productName',
|
||||
label: 'ProductName',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'price',
|
||||
label: 'Price',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Color1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: 'Color2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
},
|
||||
fieldName: 'color',
|
||||
label: 'Color',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
fieldName: 'datePicker',
|
||||
label: 'Date',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
labelField: 'name',
|
||||
},
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ align: 'left', title: 'Name', type: 'checkbox', width: 100 },
|
||||
{ field: 'category', title: 'Category' },
|
||||
{ field: 'color', title: 'Color' },
|
||||
{ field: 'productName', title: 'Product Name' },
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', title: 'Date' },
|
||||
],
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
message.success(`Query params: ${JSON.stringify(formValues)}`);
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid />
|
||||
</Page>
|
||||
</template>
|
65
playground/src/views/examples/vxe-table/remote.vue
Normal file
65
playground/src/views/examples/vxe-table/remote.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
import { getExampleTableApi } from '#/api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
labelField: 'name',
|
||||
},
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ align: 'left', title: 'Name', type: 'checkbox', width: 100 },
|
||||
{ field: 'category', title: 'Category' },
|
||||
{ field: 'color', title: 'Color' },
|
||||
{ field: 'productName', title: 'Product Name' },
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', title: 'Date' },
|
||||
],
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid>
|
||||
<template #toolbar-tools>
|
||||
<Button class="mr-2" type="primary" @click="() => gridApi.query()">
|
||||
刷新当前页面
|
||||
</Button>
|
||||
<Button type="primary" @click="() => gridApi.reload()">
|
||||
刷新并返回第一页
|
||||
</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
172
playground/src/views/examples/vxe-table/table-data.ts
Normal file
172
playground/src/views/examples/vxe-table/table-data.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
interface TableRowData {
|
||||
address: string;
|
||||
age: number;
|
||||
id: number;
|
||||
name: string;
|
||||
nickname: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
const roles = ['User', 'Admin', 'Manager', 'Guest'];
|
||||
|
||||
export const MOCK_TABLE_DATA: TableRowData[] = (() => {
|
||||
const data: TableRowData[] = [];
|
||||
for (let i = 0; i < 40; i++) {
|
||||
data.push({
|
||||
address: `New York${i}`,
|
||||
age: i + 1,
|
||||
id: i,
|
||||
name: `Test${i}`,
|
||||
nickname: `Test${i}`,
|
||||
role: roles[Math.floor(Math.random() * roles.length)] as string,
|
||||
});
|
||||
}
|
||||
return data;
|
||||
})();
|
||||
|
||||
export const MOCK_TREE_TABLE_DATA = [
|
||||
{
|
||||
date: '2020-08-01',
|
||||
id: 10_000,
|
||||
name: 'Test1',
|
||||
parentId: null,
|
||||
size: 1024,
|
||||
type: 'mp3',
|
||||
},
|
||||
{
|
||||
date: '2021-04-01',
|
||||
id: 10_050,
|
||||
name: 'Test2',
|
||||
parentId: null,
|
||||
size: 0,
|
||||
type: 'mp4',
|
||||
},
|
||||
{
|
||||
date: '2020-03-01',
|
||||
id: 24_300,
|
||||
name: 'Test3',
|
||||
parentId: 10_050,
|
||||
size: 1024,
|
||||
type: 'avi',
|
||||
},
|
||||
{
|
||||
date: '2021-04-01',
|
||||
id: 20_045,
|
||||
name: 'Test4',
|
||||
parentId: 24_300,
|
||||
size: 600,
|
||||
type: 'html',
|
||||
},
|
||||
{
|
||||
date: '2021-04-01',
|
||||
id: 10_053,
|
||||
name: 'Test5',
|
||||
parentId: 24_300,
|
||||
size: 0,
|
||||
type: 'avi',
|
||||
},
|
||||
{
|
||||
date: '2021-10-01',
|
||||
id: 24_330,
|
||||
name: 'Test6',
|
||||
parentId: 10_053,
|
||||
size: 25,
|
||||
type: 'txt',
|
||||
},
|
||||
{
|
||||
date: '2020-01-01',
|
||||
id: 21_011,
|
||||
name: 'Test7',
|
||||
parentId: 10_053,
|
||||
size: 512,
|
||||
type: 'pdf',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 22_200,
|
||||
name: 'Test8',
|
||||
parentId: 10_053,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2020-11-01',
|
||||
id: 23_666,
|
||||
name: 'Test9',
|
||||
parentId: null,
|
||||
size: 2048,
|
||||
type: 'xlsx',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_677,
|
||||
name: 'Test10',
|
||||
parentId: 23_666,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_671,
|
||||
name: 'Test11',
|
||||
parentId: 23_677,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_672,
|
||||
name: 'Test12',
|
||||
parentId: 23_677,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_688,
|
||||
name: 'Test13',
|
||||
parentId: 23_666,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_681,
|
||||
name: 'Test14',
|
||||
parentId: 23_688,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_682,
|
||||
name: 'Test15',
|
||||
parentId: 23_688,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2020-10-01',
|
||||
id: 24_555,
|
||||
name: 'Test16',
|
||||
parentId: null,
|
||||
size: 224,
|
||||
type: 'avi',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 24_566,
|
||||
name: 'Test17',
|
||||
parentId: 24_555,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 24_577,
|
||||
name: 'Test18',
|
||||
parentId: 24_555,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
];
|
59
playground/src/views/examples/vxe-table/tree.vue
Normal file
59
playground/src/views/examples/vxe-table/tree.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
|
||||
import { MOCK_TREE_TABLE_DATA } from './table-data';
|
||||
|
||||
interface RowType {
|
||||
date: string;
|
||||
id: number;
|
||||
name: string;
|
||||
parentId: null | number;
|
||||
size: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ type: 'seq', width: 70 },
|
||||
{ field: 'name', minWidth: 300, title: 'Name', treeNode: true },
|
||||
{ field: 'size', title: 'Size' },
|
||||
{ field: 'type', title: 'Type' },
|
||||
{ field: 'date', title: 'Date' },
|
||||
],
|
||||
data: MOCK_TREE_TABLE_DATA,
|
||||
treeConfig: {
|
||||
parentField: 'parentId',
|
||||
rowField: 'id',
|
||||
transform: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||
|
||||
const expandAll = () => {
|
||||
gridApi.grid?.setAllTreeExpand(true);
|
||||
};
|
||||
|
||||
const collapseAll = () => {
|
||||
gridApi.grid?.setAllTreeExpand(false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page>
|
||||
<Grid>
|
||||
<template #toolbar-tools>
|
||||
<Button class="mr-2" type="primary" @click="expandAll">
|
||||
展开全部
|
||||
</Button>
|
||||
<Button type="primary" @click="collapseAll"> 折叠全部 </Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
63
playground/src/views/examples/vxe-table/virtual.vue
Normal file
63
playground/src/views/examples/vxe-table/virtual.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter';
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter';
|
||||
|
||||
interface RowType {
|
||||
id: number;
|
||||
name: string;
|
||||
role: string;
|
||||
sex: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ type: 'seq', width: 70 },
|
||||
{ field: 'name', title: 'Name' },
|
||||
{ field: 'role', title: 'Role' },
|
||||
{ field: 'sex', title: 'Sex' },
|
||||
],
|
||||
data: [],
|
||||
height: 'auto',
|
||||
scrollY: {
|
||||
enabled: true,
|
||||
gt: 0,
|
||||
},
|
||||
showOverflow: true,
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||
|
||||
// 模拟行数据
|
||||
const loadList = (size = 200) => {
|
||||
try {
|
||||
const dataList: RowType[] = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
dataList.push({
|
||||
id: 10_000 + i,
|
||||
name: `Test${i}`,
|
||||
role: 'Developer',
|
||||
sex: '男',
|
||||
});
|
||||
}
|
||||
gridApi.setGridOptions({ data: dataList });
|
||||
} catch (error) {
|
||||
console.error('Failed to load data:', error);
|
||||
// Implement user-friendly error handling
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadList(1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid />
|
||||
</Page>
|
||||
</template>
|
Reference in New Issue
Block a user