UNPKG

vxe-table

Version:

A PC-end table component based on Vxe UI, supporting copy-paste, data pivot table, and high-performance virtual list table solution.

658 lines (657 loc) 28.9 kB
import { h, ref, computed, inject, createCommentVNode, reactive, nextTick, onUnmounted } from 'vue'; import { defineVxeComponent } from '../../ui/src/comp'; 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; function createInternalData() { return { connectTable: null }; } export default defineVxeComponent({ name: 'VxeToolbar', props: { loading: Boolean, refresh: [Boolean, Object], refreshOptions: Object, import: [Boolean, Object], importOptions: Object, export: [Boolean, Object], exportOptions: Object, print: [Boolean, Object], printOptions: Object, zoom: [Boolean, Object], zoomOptions: Object, custom: [Boolean, Object], customOptions: 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 = createInternalData(); 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.refreshOptions, props.refresh); }); const computeImportOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.import, true), props.importOptions, props.import); }); const computeExportOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.export, true), props.exportOptions, props.export); }); const computePrintOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.print, true), props.printOptions, props.print); }); const computeZoomOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.zoom, true), props.zoomOptions, props.zoom); }); const computeCustomOpts = computed(() => { return Object.assign({}, XEUtils.clone(getConfig().toolbar.custom, true), props.customOptions, 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); } } }; const handleMouseenterSettingEvent = ({ $event }) => { const { connectTable } = internalData; const $table = connectTable; if ($table) { $table.customOpenEvent($event); } }; 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); } else { warnLog('vxe.error.notProp', ['zoom']); } }; const importEvent = () => { if (checkTable()) { const { connectTable } = internalData; const $table = connectTable; if ($table) { $table.importData(); } } }; const openImportEvent = () => { 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.exportData(); } } }; const openExportEvent = () => { 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.print(); } } }; const openPrintEvent = () => { if (checkTable()) { const { connectTable } = internalData; const $table = connectTable; if ($table) { $table.openPrint(); } } }; const handleDefaultCodeEvent = (eventParams, item, cb) => { switch (item.code) { case 'print': printEvent(); break; case 'open_print': openPrintEvent(); break; case 'custom': handleClickSettingEvent(eventParams); break; case 'export': exportEvent(); break; case 'open_export': openExportEvent(); break; case 'import': importEvent(); break; case 'open_import': openImportEvent(); break; case 'zoom': zoomEvent(eventParams); break; case 'refresh': refreshEvent(eventParams); break; default: cb(); break; } }; const btnEvent = (eventParams, item) => { const { $event } = eventParams; const { connectTable } = internalData; const $table = connectTable; const { code } = item; if (code) { handleDefaultCodeEvent(eventParams, item, () => { if ($xeGrid) { $xeGrid.triggerToolbarBtnEvent(item, $event); } else { const gCommandOpts = commands.get(code); const params = { code, button: item, $table: $table, $grid: $xeGrid, $gantt: null, $event }; if (gCommandOpts) { const tCommandMethod = gCommandOpts.tableCommandMethod || gCommandOpts.commandMethod; if (tCommandMethod) { tCommandMethod(params); } else { errLog('vxe.error.notCommands', [code]); } } $xeToolbar.dispatchEvent('button-click', params, $event); } }); } }; const tolEvent = (eventParams, item) => { const { $event } = eventParams; const { connectTable } = internalData; const $table = connectTable; const { code } = item; if (code) { handleDefaultCodeEvent(eventParams, item, () => { if ($xeGrid) { $xeGrid.triggerToolbarTolEvent(item, $event); } else { const gCommandOpts = commands.get(code); const params = { code, button: null, tool: item, $table: $table, $grid: $xeGrid, $gantt: null, $event }; if (gCommandOpts) { const tCommandMethod = gCommandOpts.tableCommandMethod || gCommandOpts.commandMethod; if (tCommandMethod) { tCommandMethod(params); } else { errLog('vxe.error.notCommands', [code]); } } $xeToolbar.dispatchEvent('tool-click', params, $event); } }); } }; 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: (eventParams) => isBtn ? btnEvent(eventParams, child) : tolEvent(eventParams, 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: (eventParams) => btnEvent(eventParams, 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: (eventParams) => tolEvent(eventParams, 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: openImportEvent }) : 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: openExportEvent }) : 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: openPrintEvent }) : 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 refreshOpts = computeRefreshOpts.value; const queryMethod = refreshOpts.queryMethod || refreshOpts.query; if (props.refresh && !$xeGrid && !queryMethod) { warnLog('vxe.error.notFunc', ['queryMethod']); } if (XEUtils.isPlainObject(props.custom)) { warnLog('vxe.error.delProp', ['custom={...}', 'custom=boolean & custom-options={...}']); } if (XEUtils.isPlainObject(props.print)) { warnLog('vxe.error.delProp', ['print={...}', 'print=boolean & print-options={...}']); } if (XEUtils.isPlainObject(props.export)) { warnLog('vxe.error.delProp', ['export={...}', 'export=boolean & export-options={...}']); } if (XEUtils.isPlainObject(props.import)) { warnLog('vxe.error.delProp', ['import={...}', 'import=boolean & import-options={...}']); } if (XEUtils.isPlainObject(props.refresh)) { warnLog('vxe.error.delProp', ['refresh={...}', 'refresh=boolean & refresh-options={...}']); } if (XEUtils.isPlainObject(props.refresh)) { warnLog('vxe.error.delProp', ['zoom={...}', 'zoom=boolean & zoom-options={...}']); } const customOpts = computeCustomOpts.value; 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 (props.refresh || props.import || props.export || props.print || props.zoom) { if (!VxeUIButtonComponent) { errLog('vxe.error.reqComp', ['vxe-button']); } } }); onUnmounted(() => { XEUtils.assign(internalData, createInternalData()); }); return $xeToolbar; }, render() { return this.renderVN(); } });