Files
agt-web/apps/web-antd/src/adapter/vxe-table.ts
2025-05-16 14:52:30 +08:00

304 lines
8.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Recordable } from '@vben/types';
import { h } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { $te } from '@vben/locales';
import {
AsyncComponents,
setupVbenVxeTable,
useVbenVxeGrid,
} from '@vben/plugins/vxe-table';
import { isFunction, isString } from '@vben/utils';
import { Button, Image, Popconfirm, Switch } from 'ant-design-vue';
import { DictTag } from '#/components/dict-tag';
import { $t } from '#/locales';
import { useVbenForm } from './form';
import '#/adapter/style.css';
setupVbenVxeTable({
configVxeTable: (vxeUI) => {
vxeUI.setConfig({
grid: {
align: 'center',
border: false,
columnConfig: {
resizable: true,
},
minHeight: 180,
formConfig: {
// 全局禁用vxe-table的表单配置使用formOptions
enabled: false,
},
toolbarConfig: {
import: false, // 是否导入
export: false, // 是否导出
refresh: true, // 是否刷新
print: false, // 是否打印
zoom: true, // 是否缩放
custom: true, // 是否自定义配置
},
customConfig: {
mode: 'modal',
},
proxyConfig: {
autoLoad: true,
response: {
result: 'list',
total: 'total',
},
showActiveMsg: true,
showResponseMsg: false,
},
pagerConfig: {
enabled: true,
},
sortConfig: {
multiple: true,
},
round: true,
showOverflow: true,
size: 'small',
},
});
// 表格配置项可以用 cellRender: { name: 'CellImage' },
vxeUI.renderer.add('CellImage', {
renderTableDefault(_renderOpts, params) {
const { column, row } = params;
return h(Image, { src: row[column.field] });
},
});
// 表格配置项可以用 cellRender: { name: 'CellLink' },
vxeUI.renderer.add('CellLink', {
renderTableDefault(renderOpts) {
const { props } = renderOpts;
return h(
Button,
{ size: 'small', type: 'link' },
{ default: () => props?.text },
);
},
});
// 表格配置项可以用 cellRender: { name: 'CellDict', props:{dictType: ''} },
vxeUI.renderer.add('CellDict', {
renderTableDefault(renderOpts, params) {
const { props } = renderOpts;
const { column, row } = params;
if (!props) {
return '';
}
// 使用 DictTag 组件替代原来的实现
return h(DictTag, {
type: props.type,
value: row[column.field]?.toString(),
});
},
});
// 表格配置项可以用 cellRender: { name: 'CellSwitch', props: { beforeChange: () => {} } },
// add by 芋艿from https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/adapter/vxe-table.ts#L97-L123
vxeUI.renderer.add('CellSwitch', {
renderTableDefault({ attrs, props }, { column, row }) {
const loadingKey = `__loading_${column.field}`;
const finallyProps = {
checkedChildren: $t('common.enabled'),
checkedValue: 1,
unCheckedChildren: $t('common.disabled'),
unCheckedValue: 0,
...props,
checked: row[column.field],
loading: row[loadingKey] ?? false,
'onUpdate:checked': onChange,
};
async function onChange(newVal: any) {
row[loadingKey] = true;
try {
const result = await attrs?.beforeChange?.(newVal, row);
if (result !== false) {
row[column.field] = newVal;
}
} finally {
row[loadingKey] = false;
}
}
return h(Switch, finallyProps);
},
});
// 注册表格的操作按钮渲染器 cellRender: { name: 'CellOperation', options: ['edit', 'delete'] }
// add by 芋艿from https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/adapter/vxe-table.ts#L125-L255
vxeUI.renderer.add('CellOperation', {
renderTableDefault({ attrs, options, props }, { column, row }) {
const defaultProps = { size: 'small', type: 'link', ...props };
let align = 'end';
switch (column.align) {
case 'center': {
align = 'center';
break;
}
case 'left': {
align = 'start';
break;
}
default: {
align = 'end';
break;
}
}
const presets: Recordable<Recordable<any>> = {
delete: {
danger: true,
text: $t('common.delete'),
},
edit: {
text: $t('common.edit'),
},
};
const operations: Array<Recordable<any>> = (
options || ['edit', 'delete']
)
.map((opt) => {
if (isString(opt)) {
return presets[opt]
? { code: opt, ...presets[opt], ...defaultProps }
: {
code: opt,
text: $te(`common.${opt}`) ? $t(`common.${opt}`) : opt,
...defaultProps,
};
} else {
return { ...defaultProps, ...presets[opt.code], ...opt };
}
})
.map((opt) => {
const optBtn: Recordable<any> = {};
Object.keys(opt).forEach((key) => {
optBtn[key] = isFunction(opt[key]) ? opt[key](row) : opt[key];
});
return optBtn;
})
.filter((opt) => opt.show !== false);
function renderBtn(opt: Recordable<any>, listen = true) {
return h(
Button,
{
...props,
...opt,
icon: undefined,
onClick: listen
? () =>
attrs?.onClick?.({
code: opt.code,
row,
})
: undefined,
},
{
default: () => {
const content = [];
if (opt.icon) {
content.push(
h(IconifyIcon, { class: 'size-5', icon: opt.icon }),
);
}
content.push(opt.text);
return content;
},
},
);
}
function renderConfirm(opt: Recordable<any>) {
return h(
Popconfirm,
{
getPopupContainer(el) {
return el.closest('tbody') || document.body;
},
placement: 'topLeft',
title: $t('ui.actionTitle.delete', [attrs?.nameTitle || '']),
...props,
...opt,
icon: undefined,
onConfirm: () => {
attrs?.onClick?.({
code: opt.code,
row,
});
},
},
{
default: () => renderBtn({ ...opt }, false),
description: () =>
h(
'div',
{ class: 'truncate' },
$t('ui.actionMessage.deleteConfirm', [
row[attrs?.nameField || 'name'],
]),
),
},
);
}
const btns = operations.map((opt) =>
opt.code === 'delete' ? renderConfirm(opt) : renderBtn(opt),
);
return h(
'div',
{
class: 'flex table-operations',
style: { justifyContent: align },
},
btns,
);
},
});
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// vxeUI.formats.add
// add by 星语:数量格式化,例如说:金额
vxeUI.formats.add('formatAmount', {
cellFormatMethod({ cellValue }, digits = 2) {
if (cellValue === null || cellValue === undefined) {
return '';
}
if (isString(cellValue)) {
cellValue = Number.parseFloat(cellValue);
}
// 如果非 number则直接返回空串
if (Number.isNaN(cellValue)) {
return '';
}
return cellValue.toFixed(digits);
},
});
},
useVbenForm,
});
export { useVbenVxeGrid };
const [VxeTable, VxeColumn, VxeToolbar] = AsyncComponents;
export { VxeColumn, VxeTable, VxeToolbar };
// add by 芋艿from https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/adapter/vxe-table.ts#L264-L270
export type OnActionClickParams<T = Recordable<any>> = {
code: string;
row: T;
};
export type OnActionClickFn<T = Recordable<any>> = (
params: OnActionClickParams<T>,
) => void;
export type * from '@vben/plugins/vxe-table';