UNPKG

@blueking/vxe-table

Version:

一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、列拖拽,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...

572 lines (571 loc) 25.5 kB
import { defineComponent, h, ref, computed, inject, createCommentVNode, reactive, nextTick } from 'vue'; import XEUtils from 'xe-utils'; import { VxeUI } from '../../ui'; import { getSlotVNs } from '../../ui/src/vn'; import { warnLog, errLog } from '../../ui/src/log'; const { getConfig, getIcon, getI18n, renderer, commands, createEvent, useFns } = VxeUI; export default defineComponent({ name: 'VxeToolbar', props: { loading: Boolean, refresh: [Boolean, Object], import: [Boolean, Object], export: [Boolean, Object], print: [Boolean, Object], zoom: [Boolean, Object], custom: [Boolean, Object], buttons: { type: Array, default: () => getConfig().toolbar.buttons }, tools: { type: Array, default: () => getConfig().toolbar.tools }, perfect: { type: Boolean, default: () => getConfig().toolbar.perfect }, size: { type: String, default: () => getConfig().toolbar.size || getConfig().size }, className: [String, Function] }, emits: [ 'button-click', 'tool-click' ], setup(props, context) { const { slots, emit } = context; const xID = XEUtils.uniqueId(); // 使用已安装的组件,如果未安装则不渲染 const VxeUIButtonComponent = VxeUI.getComponent('VxeButton'); const { computeSize } = useFns.useSize(props); const reactData = reactive({ isRefresh: false, connectFlag: 0, columns: [] }); const internalData = { connectTable: null }; const refElem = ref(); const refMaps = { refElem }; const $xeToolbar = { xID, props, context, reactData, internalData, getRefMaps: () => refMaps }; let toolbarMethods = {}; const $xeGrid = inject('$xeGrid', null); const computeRefreshOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.refresh, true), props.refresh); }); const computeImportOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.import, true), props.import); }); const computeExportOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.export, true), props.export); }); const computePrintOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.print, true), props.print); }); const computeZoomOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.zoom, true), props.zoom); }); const computeCustomOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.custom, true), props.custom); }); const computeTableCustomOpts = computed(() => { const { connectTable } = internalData; const $table = connectTable; if (reactData.connectFlag || $table) { if ($table) { const { computeCustomOpts } = $table.getComputeMaps(); return computeCustomOpts.value; } } return { trigger: '' }; }); const computeTrigger = computed(() => { const tableCustomOpts = computeTableCustomOpts.value; return tableCustomOpts.trigger; }); const checkTable = () => { const { connectTable } = internalData; const $table = connectTable; if ($table) { return true; } errLog('vxe.error.barUnableLink'); }; const handleClickSettingEvent = ({ $event }) => { const { connectTable } = internalData; const $table = connectTable; if ($table) { if ($table.triggerCustomEvent) { $table.triggerCustomEvent($event); } else { errLog('vxe.error.reqModule', ['VxeTableCustomModule']); } } }; const handleMouseenterSettingEvent = ({ $event }) => { const { connectTable } = internalData; const $table = connectTable; if ($table) { $table.customOpenEvent($event); } else { errLog('vxe.error.reqModule', ['VxeTableCustomModule']); } }; const handleMouseleaveSettingEvent = ({ $event }) => { const { connectTable } = internalData; const $table = connectTable; if ($table) { const { customStore } = $table.reactData; customStore.activeBtn = false; setTimeout(() => { if (!customStore.activeBtn && !customStore.activeWrapper) { $table.customCloseEvent($event); } }, 350); } }; const refreshEvent = ({ $event }) => { const { isRefresh } = reactData; const refreshOpts = computeRefreshOpts.value; if (!isRefresh) { const queryMethod = refreshOpts.queryMethod || refreshOpts.query; if (queryMethod) { reactData.isRefresh = true; try { Promise.resolve(queryMethod({})).catch((e) => e).then(() => { reactData.isRefresh = false; }); } catch (e) { reactData.isRefresh = false; } } else if ($xeGrid) { reactData.isRefresh = true; $xeGrid.triggerToolbarCommitEvent({ code: refreshOpts.code || 'reload' }, $event).catch((e) => e).then(() => { reactData.isRefresh = false; }); } } }; const zoomEvent = ({ $event }) => { if ($xeGrid) { $xeGrid.triggerZoomEvent($event); } }; const btnEvent = (evnt, item) => { const { connectTable } = internalData; const $table = connectTable; const { code } = item; if (code) { if ($xeGrid) { $xeGrid.triggerToolbarBtnEvent(item, evnt); } else { const gCommandOpts = commands.get(code); const params = { code, button: item, $table: $table, $grid: $xeGrid, $event: evnt }; if (gCommandOpts) { const tCommandMethod = gCommandOpts.tableCommandMethod || gCommandOpts.commandMethod; if (tCommandMethod) { tCommandMethod(params); } else { if (process.env.NODE_ENV === 'development') { errLog('vxe.error.notCommands', [code]); } } } $xeToolbar.dispatchEvent('button-click', params, evnt); } } }; const tolEvent = (evnt, item) => { const { connectTable } = internalData; const $table = connectTable; const { code } = item; if (code) { if ($xeGrid) { $xeGrid.triggerToolbarTolEvent(item, evnt); } else { const gCommandOpts = commands.get(code); const params = { code, tool: item, $table: $table, $grid: $xeGrid, $event: evnt }; if (gCommandOpts) { const tCommandMethod = gCommandOpts.tableCommandMethod || gCommandOpts.commandMethod; if (tCommandMethod) { tCommandMethod(params); } else { if (process.env.NODE_ENV === 'development') { errLog('vxe.error.notCommands', [code]); } } } $xeToolbar.dispatchEvent('tool-click', params, evnt); } } }; const importEvent = () => { if (checkTable()) { const { connectTable } = internalData; const $table = connectTable; if ($table) { $table.openImport(); } } }; const exportEvent = () => { if (checkTable()) { const { connectTable } = internalData; const $table = connectTable; if ($table) { $table.openExport(); } } }; const printEvent = () => { if (checkTable()) { const { connectTable } = internalData; const $table = connectTable; if ($table) { $table.openPrint(); } } }; const dispatchEvent = (type, params, evnt) => { emit(type, createEvent(evnt, { $toolbar: $xeToolbar }, params)); }; toolbarMethods = { dispatchEvent, syncUpdate(params) { internalData.connectTable = params.$table; reactData.columns = params.collectColumn; reactData.connectFlag++; } }; Object.assign($xeToolbar, toolbarMethods); const renderDropdowns = (item, isBtn) => { const { dropdowns } = item; const downVNs = []; if (dropdowns) { return dropdowns.map((child, index) => { if (child.visible === false) { return createCommentVNode(); } return VxeUIButtonComponent ? h(VxeUIButtonComponent, { key: index, disabled: child.disabled, loading: child.loading, type: child.type, mode: child.mode, icon: child.icon, circle: child.circle, round: child.round, status: child.status, content: child.name, title: child.title, routerLink: child.routerLink, permissionCode: child.permissionCode, prefixTooltip: child.prefixTooltip, suffixTooltip: child.suffixTooltip, onClick: ({ $event }) => isBtn ? btnEvent($event, child) : tolEvent($event, child) }) : createCommentVNode(); }); } return downVNs; }; /** * 渲染按钮 */ const renderLeftBtns = () => { const { buttons } = props; const { connectTable } = internalData; const $table = connectTable; const buttonPrefixSlot = slots.buttonPrefix || slots['button-prefix']; const buttonSuffixSlot = slots.buttonSuffix || slots['button-suffix']; const btnVNs = []; if (buttonPrefixSlot) { btnVNs.push(...getSlotVNs(buttonPrefixSlot({ buttons: buttons || [], $grid: $xeGrid, $table: $table }))); } if (buttons) { buttons.forEach((item, index) => { const { dropdowns, buttonRender } = item; if (item.visible !== false) { const compConf = buttonRender ? renderer.get(buttonRender.name) : null; if (buttonRender && compConf && compConf.renderToolbarButton) { const toolbarButtonClassName = compConf.toolbarButtonClassName; const params = { $grid: $xeGrid, $table: $table, button: item }; btnVNs.push(h('span', { key: `br${item.code || index}`, class: ['vxe-button--item', toolbarButtonClassName ? (XEUtils.isFunction(toolbarButtonClassName) ? toolbarButtonClassName(params) : toolbarButtonClassName) : ''] }, getSlotVNs(compConf.renderToolbarButton(buttonRender, params)))); } else { if (VxeUIButtonComponent) { btnVNs.push(h(VxeUIButtonComponent, { key: `bd${item.code || index}`, disabled: item.disabled, loading: item.loading, type: item.type, mode: item.mode, icon: item.icon, circle: item.circle, round: item.round, status: item.status, content: item.name, title: item.title, routerLink: item.routerLink, permissionCode: item.permissionCode, prefixTooltip: item.prefixTooltip, suffixTooltip: item.suffixTooltip, destroyOnClose: item.destroyOnClose, placement: item.placement, transfer: item.transfer, onClick: ({ $event }) => btnEvent($event, item) }, dropdowns && dropdowns.length ? { dropdowns: () => renderDropdowns(item, true) } : {})); } } } }); } if (buttonSuffixSlot) { btnVNs.push(...getSlotVNs(buttonSuffixSlot({ buttons: buttons || [], $grid: $xeGrid, $table: $table }))); } return btnVNs; }; /** * 渲染右侧工具 */ const renderRightTools = () => { const { tools } = props; const { connectTable } = internalData; const $table = connectTable; const toolPrefixSlot = slots.toolPrefix || slots['tool-prefix']; const toolSuffixSlot = slots.toolSuffix || slots['tool-suffix']; const btnVNs = []; if (toolPrefixSlot) { btnVNs.push(...getSlotVNs(toolPrefixSlot({ tools: tools || [], $grid: $xeGrid, $table: $table }))); } if (tools) { tools.forEach((item, tIndex) => { const { dropdowns, toolRender } = item; if (item.visible !== false) { const rdName = toolRender ? toolRender.name : null; const compConf = toolRender ? renderer.get(rdName) : null; if (toolRender && compConf && compConf.renderToolbarTool) { const toolbarToolClassName = compConf.toolbarToolClassName; const params = { $grid: $xeGrid, $table: $table, tool: item }; btnVNs.push(h('span', { key: rdName, class: ['vxe-tool--item', toolbarToolClassName ? (XEUtils.isFunction(toolbarToolClassName) ? toolbarToolClassName(params) : toolbarToolClassName) : ''] }, getSlotVNs(compConf.renderToolbarTool(toolRender, params)))); } else { if (VxeUIButtonComponent) { btnVNs.push(h(VxeUIButtonComponent, { key: tIndex, disabled: item.disabled, loading: item.loading, type: item.type, mode: item.mode, icon: item.icon, circle: item.circle, round: item.round, status: item.status, content: item.name, title: item.title, routerLink: item.routerLink, permissionCode: item.permissionCode, prefixTooltip: item.prefixTooltip, suffixTooltip: item.suffixTooltip, destroyOnClose: item.destroyOnClose, placement: item.placement, transfer: item.transfer, onClick: ({ $event }) => tolEvent($event, item) }, dropdowns && dropdowns.length ? { dropdowns: () => renderDropdowns(item, false) } : {})); } } } }); } if (toolSuffixSlot) { btnVNs.push(...getSlotVNs(toolSuffixSlot({ tools: tools || [], $grid: $xeGrid, $table: $table }))); } return btnVNs; }; const renderToolImport = () => { const importOpts = computeImportOpts.value; return VxeUIButtonComponent ? h(VxeUIButtonComponent, { key: 'import', circle: true, icon: importOpts.icon || getIcon().TOOLBAR_TOOLS_IMPORT, title: getI18n('vxe.toolbar.import'), onClick: importEvent }) : createCommentVNode(); }; const renderToolExport = () => { const exportOpts = computeExportOpts.value; return VxeUIButtonComponent ? h(VxeUIButtonComponent, { key: 'export', circle: true, icon: exportOpts.icon || getIcon().TOOLBAR_TOOLS_EXPORT, title: getI18n('vxe.toolbar.export'), onClick: exportEvent }) : createCommentVNode(); }; const renderToolPrint = () => { const printOpts = computePrintOpts.value; return VxeUIButtonComponent ? h(VxeUIButtonComponent, { key: 'print', circle: true, icon: printOpts.icon || getIcon().TOOLBAR_TOOLS_PRINT, title: getI18n('vxe.toolbar.print'), onClick: printEvent }) : createCommentVNode(); }; const renderToolRefresh = () => { const refreshOpts = computeRefreshOpts.value; return VxeUIButtonComponent ? h(VxeUIButtonComponent, { key: 'refresh', circle: true, icon: reactData.isRefresh ? (refreshOpts.iconLoading || getIcon().TOOLBAR_TOOLS_REFRESH_LOADING) : (refreshOpts.icon || getIcon().TOOLBAR_TOOLS_REFRESH), title: getI18n('vxe.toolbar.refresh'), onClick: refreshEvent }) : createCommentVNode(); }; const renderToolZoom = () => { const zoomOpts = computeZoomOpts.value; return $xeGrid && VxeUIButtonComponent ? h(VxeUIButtonComponent, { key: 'zoom', circle: true, icon: $xeGrid.isMaximized() ? (zoomOpts.iconOut || getIcon().TOOLBAR_TOOLS_MINIMIZE) : (zoomOpts.iconIn || getIcon().TOOLBAR_TOOLS_FULLSCREEN), title: getI18n(`vxe.toolbar.zoom${$xeGrid.isMaximized() ? 'Out' : 'In'}`), onClick: zoomEvent }) : createCommentVNode(); }; const renderToolCustom = () => { const customOpts = computeCustomOpts.value; const btnTrigger = computeTrigger.value; const customBtnOns = {}; if (btnTrigger === 'manual') { // 手动触发 } else if (btnTrigger === 'hover') { // hover 触发 customBtnOns.onMouseenter = handleMouseenterSettingEvent; customBtnOns.onMouseleave = handleMouseleaveSettingEvent; } else { // 点击触发 customBtnOns.onClick = handleClickSettingEvent; } return VxeUIButtonComponent ? h(VxeUIButtonComponent, Object.assign({ key: 'custom', circle: true, icon: customOpts.icon || getIcon().TOOLBAR_TOOLS_CUSTOM, title: getI18n('vxe.toolbar.custom'), className: 'vxe-toolbar-custom-target' }, customBtnOns)) : createCommentVNode(); }; const renderVN = () => { const { perfect, loading, refresh, zoom, custom, className } = props; const { connectTable } = internalData; const vSize = computeSize.value; const toolsSlot = slots.tools; const buttonsSlot = slots.buttons; const $table = connectTable; return h('div', { ref: refElem, class: ['vxe-toolbar', className ? (XEUtils.isFunction(className) ? className({ $toolbar: $xeToolbar }) : className) : '', { [`size--${vSize}`]: vSize, 'is--perfect': perfect, 'is--loading': loading }] }, [ h('div', { class: 'vxe-buttons--wrapper' }, buttonsSlot ? buttonsSlot({ $grid: $xeGrid, $table: $table }) : renderLeftBtns()), h('div', { class: 'vxe-tools--wrapper' }, toolsSlot ? toolsSlot({ $grid: $xeGrid, $table: $table }) : renderRightTools()), h('div', { class: 'vxe-tools--operate' }, [ props.import ? renderToolImport() : createCommentVNode(), props.export ? renderToolExport() : createCommentVNode(), props.print ? renderToolPrint() : createCommentVNode(), refresh ? renderToolRefresh() : createCommentVNode(), zoom && $xeGrid ? renderToolZoom() : createCommentVNode(), custom ? renderToolCustom() : createCommentVNode() ]) ]); }; $xeToolbar.renderVN = renderVN; nextTick(() => { const { refresh } = props; const refreshOpts = computeRefreshOpts.value; const queryMethod = refreshOpts.queryMethod || refreshOpts.query; if (refresh && !$xeGrid && !queryMethod) { warnLog('vxe.error.notFunc', ['queryMethod']); } const customOpts = computeCustomOpts.value; if (process.env.NODE_ENV === 'development') { if (customOpts.isFooter) { warnLog('vxe.error.delProp', ['toolbar.custom.isFooter', 'table.custom-config.showFooter']); } if (customOpts.showFooter) { warnLog('vxe.error.delProp', ['toolbar.custom.showFooter', 'table.custom-config.showFooter']); } if (customOpts.immediate) { warnLog('vxe.error.delProp', ['toolbar.custom.immediate', 'table.custom-config.immediate']); } if (customOpts.trigger) { warnLog('vxe.error.delProp', ['toolbar.custom.trigger', 'table.custom-config.trigger']); } } if (process.env.NODE_ENV === 'development') { if (props.refresh || props.import || props.export || props.print || props.zoom) { if (!VxeUIButtonComponent) { errLog('vxe.error.reqComp', ['vxe-button']); } } } }); return $xeToolbar; }, render() { return this.renderVN(); } });