UNPKG

vxe-pc-ui

Version:
486 lines (442 loc) 16.7 kB
import { defineComponent, ref, PropType, 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' import type { ListViewReactData, ListViewPrivateRef, VxeListViewPropTypes, VxeListViewDefines, VxeListViewEmits, VxeListViewPrivateComputed, VxeListViewConstructor, VxeListDesignDefines, ListViewMethods, ListViewPrivateMethods, VxeGlobalRendererHandles, VxeListViewPrivateMethods, VxeButtonGroupDefines, VxeButtonGroupPropTypes, ValueOf } from '../../../types' import type { VxeGridComponent, VxeGridInstance, VxeGridPropTypes, VxeGridProps } from '../../../types/components/grid' import type { VxeTableDefines } from '../../../types/components/table' export default defineComponent({ name: 'VxeListView', props: { size: { type: String as PropType<VxeListViewPropTypes.Size>, default: () => getConfig().listView.size || getConfig().size }, config: Object as PropType<VxeListViewPropTypes.Config>, height: { type: [String, Number] as PropType<VxeListViewPropTypes.Height>, default: () => getConfig().listView.height }, loading: Boolean as PropType<VxeListViewPropTypes.Loading>, formData: Object as PropType<VxeListViewPropTypes.FormData>, actionButtons: Array as PropType<VxeListViewPropTypes.ActionButtons>, gridOptions: Object as PropType<VxeListViewPropTypes.GridOptions>, gridEvents: Object as PropType<VxeListViewPropTypes.GridEvents>, viewRender: Object as PropType<VxeListViewPropTypes.ViewRender> }, emits: [ 'cell-action', 'update:formData', 'update:actionButtons' ] as VxeListViewEmits, setup (props, context) { const VxeTableGridComponent = VxeUI.getComponent<VxeGridComponent>('VxeGrid') const { emit, slots } = context const xID = XEUtils.uniqueId() const refElem = ref<HTMLDivElement>() const refGrid = ref<VxeGridInstance>() const { computeSize } = useSize(props) const reactData = reactive<ListViewReactData>({ formConfig: {} as VxeListDesignDefines.DefaultSettingFormDataObjVO, searchFormData: {}, searchFormItems: [], listTableColumns: [], tableColumns: [], footerData: [ {} // 默认一行合计 ] }) const computeGridOptions = computed<VxeGridProps>(() => { 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: VxeGridPropTypes.ProxyConfig | undefined 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<VxeGridProps>(() => { const { gridEvents } = props const ons: Record<string, any> = {} XEUtils.each(gridEvents, (fn, key) => { ons[XEUtils.camelCase(`on-${key}`)] = fn }) return ons }) const refMaps: ListViewPrivateRef = { refElem, refGrid } const computeMaps: VxeListViewPrivateComputed = { computeSize } const $xeListView = { xID, props, context, reactData, getRefMaps: () => refMaps, getComputeMaps: () => computeMaps } as unknown as VxeListViewConstructor & VxeListViewPrivateMethods const systemConfigList: VxeGlobalRendererHandles.CreateListDesignSettingActionButtonConfigResult[] = [] const customConfigList: VxeGlobalRendererHandles.CreateListDesignSettingActionButtonConfigResult[] = [] 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: VxeListDesignDefines.SearchItemObjItem[]): { data: Record<string, any> items: VxeListDesignDefines.SearchItemObjItem[] } => { if (searchItems && searchItems.length) { const data: Record<string, any> = {} const items: VxeListDesignDefines.SearchItemObjItem[] = 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: VxeListDesignDefines.ListColumnObjItem[]): VxeListDesignDefines.ListColumnObjItem[] => { 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: {} as VxeListDesignDefines.DefaultSettingFormDataObjVO, searchFormData: {}, searchFormItems: [], listTableColumns: [], tableColumns: [], footerData: [ {} // 默认一行合计 ] }) return nextTick() } const loadConfig = (config: Partial<VxeListDesignDefines.ListDesignConfig> | null) => { if (config) { const { formConfig, searchItems, listColumns } = config reactData.formConfig = formConfig || {} as VxeListDesignDefines.DefaultSettingFormDataObjVO setSearchItems(searchItems || []) loadListColumns(listColumns || []) } return nextTick() } const parseForm = (searchItems: VxeListDesignDefines.SearchItemObjItem[]) => { return configToSearchItems(searchItems || []) } const parseTableColumn = (listColumns: VxeListDesignDefines.ListColumnObjItem[], formConfig: VxeListDesignDefines.DefaultSettingFormDataObjVO) => { const formOpts = Object.assign({}, formConfig) const { showSeq, actionButtonList } = formOpts const columns: VxeGridPropTypes.Columns = [] const rowRecord: Record<string, any> = {} 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: VxeTableDefines.ColumnOptions = { ...conf } if (formOpts.showStatistics && footerCellSlot) { columnConf.slots = { footer: (params) => { return footerCellSlot({ ...params }) } } } if (columnConf.field) { rowRecord[columnConf.field] = null } columns.push(columnConf) }) if (actionButtonList && actionButtonList.length) { const actionColumn: VxeTableDefines.ColumnOptions = { field: '_active', title: getI18n('vxe.table.actionTitle'), fixed: 'right', width: 'auto' } const btnOptions: VxeButtonGroupPropTypes.Options = [] 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({ ...params, buttons: btnOptions }) } } } else { actionColumn.cellRender = { name: 'VxeButtonGroup', props: { mode: 'text' }, options: btnOptions, events: { click (params, btnParams: VxeButtonGroupDefines.ClickEventParams) { const { option } = btnParams dispatchEvent('cell-action', { ...params, button: option }, btnParams.$event) } } } } columns.push(actionColumn) } return { rowRecord, columns, actionButtons: actionButtonList } } const parseConfig = (config: Partial<VxeListDesignDefines.ListDesignConfig> | null) => { 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: Partial<VxeListDesignDefines.ListDesignConfig> | VxeListDesignDefines.ListColumnObjItem[] | null | undefined) => { 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: VxeListViewDefines.QueryFilterItem[] = [] const rest: VxeListViewDefines.QueryFilterResult = { 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: VxeListViewDefines.QueryFilterCondition[] = [] condition.push({ field, value: itemValue, match: 'exact', type: XEUtils.isArray(itemValue) ? 'array' : '' }) items.push({ condition, type: 'and' }) } }) return rest } const commitProxy = (code: string, ...args: any[]) => { const $grid = refGrid.value if ($grid) { return $grid.commitProxy(code, ...args) } return Promise.resolve() } const loadListColumns = (listColumns: VxeListDesignDefines.ListColumnObjItem[]) => { 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: VxeListDesignDefines.SearchItemObjItem[]) => { const { data, items } = configToSearchItems(searchItems) reactData.searchFormData = data reactData.searchFormItems = items emit('update:formData', data) return nextTick() } const dispatchEvent = (type: ValueOf<VxeListViewEmits>, params: Record<string, any>, evnt: Event | null) => { emit(type, createEvent(evnt, { $listView: $xeListView }, params)) } const listViewMethods: ListViewMethods = { dispatchEvent, clearConfig, loadConfig, parseConfig, getTableRecord, getQueryFilter, commitProxy } const listViewPrivateMethods: 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.VUE_APP_VXE_ENV === 'development') { nextTick(() => { if (!VxeTableGridComponent) { errLog('vxe.error.reqComp', ['vxe-grid']) } }) } $xeListView.renderVN = renderVN return $xeListView }, render () { return this.renderVN() } })