UNPKG

vxe-pc-ui

Version:
438 lines (437 loc) 16.9 kB
import { defineComponent, ref, h, reactive, provide, watch, nextTick, computed, createCommentVNode } from 'vue'; import { VxeUI, getConfig, createEvent, getI18n, renderer, useSize } from '../../ui'; import { errLog } from '../../ui/src/log'; import { toCssUnit } from '../../ui/src/dom'; import { getSlotVNs } from '../../ui/src/vn'; import { createListDesignActionButton } from '../render/util'; import VxeLoadingComponent from '../../loading/src/loading'; import XEUtils from 'xe-utils'; export default defineComponent({ name: 'VxeListView', props: { size: { type: String, default: () => getConfig().listView.size || getConfig().size }, config: Object, height: { type: [String, Number], default: () => getConfig().listView.height }, loading: Boolean, formData: Object, actionButtons: Array, gridOptions: Object, gridEvents: Object, viewRender: Object }, emits: [ 'cell-action', 'update:formData', 'update:actionButtons' ], setup(props, context) { const VxeTableGridComponent = VxeUI.getComponent('VxeGrid'); const { emit, slots } = context; const xID = XEUtils.uniqueId(); const refElem = ref(); const refGrid = ref(); const { computeSize } = useSize(props); const reactData = reactive({ formConfig: {}, searchFormData: {}, searchFormItems: [], listTableColumns: [], tableColumns: [], footerData: [ {} // 默认一行合计 ] }); const computeGridOptions = computed(() => { const { gridOptions } = props; const { formConfig, tableColumns, searchFormData, searchFormItems, footerData } = reactData; const { showStatistics } = formConfig; const gridOpts = gridOptions || {}; const columnOpts = Object.assign({ minWidth: 120 }, gridOpts.columnConfig); let proxyOpts; if (gridOpts.proxyConfig) { proxyOpts = Object.assign({ autoLoad: false }, gridOpts.proxyConfig); } return Object.assign({}, gridOpts, { columns: tableColumns, columnConfig: columnOpts, showFooter: showStatistics, footerData: showStatistics ? footerData : null, formConfig: { data: searchFormData, items: searchFormItems }, proxyConfig: proxyOpts }); }); const computeGridEvents = computed(() => { const { gridEvents } = props; const ons = {}; XEUtils.each(gridEvents, (fn, key) => { ons[XEUtils.camelCase(`on-${key}`)] = fn; }); return ons; }); const refMaps = { refElem, refGrid }; const computeMaps = { computeSize }; const $xeListView = { xID, props, context, reactData, getRefMaps: () => refMaps, getComputeMaps: () => computeMaps }; const systemConfigList = []; const customConfigList = []; renderer.forEach((item, name) => { const { createListDesignSettingActionButtonConfig } = item; if (createListDesignSettingActionButtonConfig) { const params = { name }; const btnConfig = Object.assign(createListDesignActionButton({ code: name }), createListDesignSettingActionButtonConfig(params)); if (btnConfig.type === 'custom') { customConfigList.push(btnConfig); } else { systemConfigList.push(btnConfig); } } }); const configToSearchItems = (searchItems) => { if (searchItems && searchItems.length) { const data = {}; const items = searchItems.map(item => { data[item.field] = null; return { field: item.field, title: item.title, folding: item.folding, itemRender: item.itemRender }; }); items.push({ field: 'active', title: '', folding: false, collapseNode: searchItems.some(item => item.folding), itemRender: { name: 'VxeButtonGroup', options: [ { content: '查询', icon: 'vxe-icon-search', status: 'primary', type: 'submit' }, { content: '重置', icon: 'vxe-icon-repeat', type: 'reset' } ] } }); return { items, data }; } return { items: [], data: {} }; }; const configToListColumns = (listColumns) => { if (listColumns) { return listColumns.map(item => { return { field: item.field, title: item.title, visible: !!item.visible, width: item.width, cellRender: XEUtils.clone(item.cellRender) }; }); } return []; }; const clearConfig = () => { emit('update:formData', {}); Object.assign(reactData, { formConfig: {}, searchFormData: {}, searchFormItems: [], listTableColumns: [], tableColumns: [], footerData: [ {} // 默认一行合计 ] }); return nextTick(); }; const loadConfig = (config) => { if (config) { const { formConfig, searchItems, listColumns } = config; reactData.formConfig = formConfig || {}; setSearchItems(searchItems || []); loadListColumns(listColumns || []); } return nextTick(); }; const parseForm = (searchItems) => { return configToSearchItems(searchItems || []); }; const parseTableColumn = (listColumns, formConfig) => { const formOpts = Object.assign({}, formConfig); const { showSeq, actionButtonList } = formOpts; const columns = []; const rowRecord = {}; const cellActionSlot = slots.cellAction; const footerCellSlot = slots.footerCell; if (showSeq) { columns.push({ type: 'seq', field: '_seq', fixed: 'left', width: 70 }); } configToListColumns(listColumns || []).forEach(conf => { const columnConf = Object.assign({}, conf); if (formOpts.showStatistics && footerCellSlot) { columnConf.slots = { footer: (params) => { return footerCellSlot(Object.assign({}, params)); } }; } if (columnConf.field) { rowRecord[columnConf.field] = null; } columns.push(columnConf); }); if (actionButtonList && actionButtonList.length) { const actionColumn = { field: '_active', title: getI18n('vxe.table.actionTitle'), fixed: 'right', width: 'auto' }; const btnOptions = []; actionButtonList.forEach(btnItem => { if (btnItem.type === 'custom') { return { content: btnItem.name, name: btnItem.code, icon: btnItem.icon }; } const btnConfig = systemConfigList.find(item => item.code === btnItem.code); let btnName = btnItem.name; let btnIcon = btnItem.icon; let btnStatus = btnItem.status; let btnPermissionCode = btnItem.permissionCode; let btnClassify = btnItem.classify; if (btnConfig) { const nameConfig = btnConfig.name; btnIcon = btnConfig.icon || ''; btnStatus = btnConfig.status || ''; btnPermissionCode = btnConfig.permissionCode || ''; btnClassify = btnConfig.classify || ''; btnName = XEUtils.toValueString(XEUtils.isFunction(nameConfig) ? nameConfig({ name: btnConfig.code || '' }) : nameConfig); } if (!btnClassify || btnClassify === 'cellButton') { btnOptions.push({ content: btnName, name: btnItem.code, icon: btnIcon, status: btnStatus, permissionCode: btnPermissionCode }); } }); if (cellActionSlot) { actionColumn.slots = { default(params) { return cellActionSlot(Object.assign(Object.assign({}, params), { buttons: btnOptions })); } }; } else { actionColumn.cellRender = { name: 'VxeButtonGroup', props: { mode: 'text' }, options: btnOptions, events: { click(params, btnParams) { const { option } = btnParams; dispatchEvent('cell-action', Object.assign(Object.assign({}, params), { button: option }), btnParams.$event); } } }; } columns.push(actionColumn); } return { rowRecord, columns, actionButtons: actionButtonList }; }; const parseConfig = (config) => { const { formConfig, searchItems, listColumns } = config || {}; const { columns, rowRecord, actionButtons } = parseTableColumn(listColumns || [], formConfig || reactData.formConfig); const { data, items } = parseForm(searchItems || []); return { formData: data, formItems: items, tableColumns: columns, tableRecord: rowRecord, actionButtons }; }; const getTableRecord = (configOrListColumns) => { if (XEUtils.isArray(configOrListColumns)) { const { rowRecord } = parseTableColumn(configOrListColumns, reactData.formConfig); return rowRecord; } if (configOrListColumns) { const { formConfig, listColumns } = configOrListColumns; const { rowRecord } = parseTableColumn(listColumns || [], formConfig || reactData.formConfig); return rowRecord; } return {}; }; const getQueryFilter = () => { const { searchFormData, searchFormItems } = reactData; const items = []; const rest = { items, type: 'and' }; const $grid = refGrid.value; if (!$grid) { return rest; } searchFormItems.forEach(item => { const { field } = item; const itemValue = searchFormData[field]; if (itemValue) { const condition = []; condition.push({ field, value: itemValue, match: 'exact', type: XEUtils.isArray(itemValue) ? 'array' : '' }); items.push({ condition, type: 'and' }); } }); return rest; }; const commitProxy = (code, ...args) => { const $grid = refGrid.value; if ($grid) { return $grid.commitProxy(code, ...args); } return Promise.resolve(); }; const loadListColumns = (listColumns) => { const { formConfig } = reactData; const listTableColumns = listColumns || []; const { columns, actionButtons } = parseTableColumn(listTableColumns, formConfig); reactData.listTableColumns = listTableColumns; reactData.tableColumns = columns; emit('update:actionButtons', actionButtons); nextTick(() => { const gridOptions = computeGridOptions.value; if (gridOptions.proxyConfig) { commitProxy('reload'); } }); }; const setSearchItems = (searchItems) => { const { data, items } = configToSearchItems(searchItems); reactData.searchFormData = data; reactData.searchFormItems = items; emit('update:formData', data); return nextTick(); }; const dispatchEvent = (type, params, evnt) => { emit(type, createEvent(evnt, { $listView: $xeListView }, params)); }; const listViewMethods = { dispatchEvent, clearConfig, loadConfig, parseConfig, getTableRecord, getQueryFilter, commitProxy }; const listViewPrivateMethods = {}; Object.assign($xeListView, listViewMethods, listViewPrivateMethods); const renderVN = () => { const { height, loading } = props; const vSize = computeSize.value; const gridSlot = slots.grid; const gridOptions = computeGridOptions.value; const gridEvents = computeGridEvents.value; return h('div', { ref: refElem, class: ['vxe-list-view', { [`size--${vSize}`]: vSize, 'is--loading': loading }], style: height ? { height: toCssUnit(height) } : null }, [ h('div', { class: 'vxe-list-view--body' }, [ gridSlot ? h('div', { class: 'vxe-list-view--grid-wrapper' }, getSlotVNs(gridSlot({ $listView: $xeListView }))) : (VxeTableGridComponent ? h(VxeTableGridComponent, Object.assign({}, gridOptions, gridEvents, { ref: refGrid }), Object.assign({}, slots, { default: undefined })) : createCommentVNode()) ]), /** * 加载中 */ h(VxeLoadingComponent, { class: 'vxe-list-view--loading', modelValue: loading }) ]); }; watch(() => props.config, (value) => { loadConfig(value || {}); }); if (props.config) { loadConfig(props.config); } provide('$xeListView', $xeListView); if (process.env.NODE_ENV === 'development') { nextTick(() => { if (!VxeTableGridComponent) { errLog('vxe.error.reqComp', ['vxe-grid']); } }); } $xeListView.renderVN = renderVN; return $xeListView; }, render() { return this.renderVN(); } });