UNPKG

vxe-gantt

Version:
1,289 lines (1,175 loc) 101 kB
import { h, ref, PropType, computed, provide, reactive, onBeforeUnmount, onUnmounted, watch, nextTick, VNode, onMounted } from 'vue' import { defineVxeComponent } from '../../ui/src/comp' import XEUtils from 'xe-utils' import { getLastZIndex, nextZIndex, isEnableConf, hasEnableConf, formatText } from '../../ui/src/utils' import { getOffsetHeight, getPaddingTopBottomSize, getDomNode, toCssUnit, addClass, removeClass } from '../../ui/src/dom' import { getSlotVNs } from '../../ui/src/vn' import { VxeUI } from '@vxe-ui/core' import { ganttEmits } from './emits' import { getRefElem } from './util' import { tableEmits } from './table-emits' import { createComponentLog } from '../../ui/src/log' import GanttViewComponent from './gantt-view' import { VxeTable as VxeTableComponent } from 'vxe-table' import type { VxeGanttConstructor, VxeGanttEmits, GanttReactData, GanttInternalData, VxeGanttPropTypes, GanttMethods, GanttPrivateMethods, VxeGanttPrivateMethods, GanttPrivateRef, VxeGanttProps, VxeGanttPrivateComputed, VxeGanttViewInstance, VxeGanttDefines, VxeGanttViewPrivateMethods } from '../../../types' import type { ValueOf, VxeFormEvents, VxeFormInstance, VxeTooltipInstance, VxePagerEvents, VxeFormItemProps, VxePagerInstance, VxeComponentStyleType } from 'vxe-pc-ui' import type { VxeTableMethods, VxeToolbarPropTypes, VxeTableProps, VxeTablePropTypes, VxeTableConstructor, VxeTablePrivateMethods, VxeTableEvents, VxeTableDefines, VxeTableEventProps, VxeToolbarInstance, VxeGridPropTypes, VxeGridDefines } from 'vxe-table' const { warnLog, errLog } = createComponentLog('gantt') const { getConfig, getIcon, getI18n, commands, hooks, useFns, createEvent, globalEvents, GLOBAL_EVENT_KEYS, renderEmptyElement } = VxeUI const tableProps = VxeTableComponent.props const tableComponentPropKeys = Object.keys(tableProps) as (keyof VxeTableProps)[] const tableComponentMethodKeys: (keyof VxeTableMethods)[] = ['clearAll', 'syncData', 'updateData', 'loadData', 'reloadData', 'reloadRow', 'loadColumn', 'reloadColumn', 'getRowNode', 'getColumnNode', 'getRowIndex', 'getVTRowIndex', 'getVMRowIndex', 'getColumnIndex', 'getVTColumnIndex', 'getVMColumnIndex', 'setRow', 'createData', 'createRow', 'revertData', 'clearData', 'isRemoveByRow', 'isInsertByRow', 'isUpdateByRow', 'getColumns', 'getColumnById', 'getColumnByField', 'getTableColumn', 'getFullColumns', 'getData', 'getCheckboxRecords', 'getParentRow', 'getTreeRowChildren', 'getTreeRowLevel', 'getTreeParentRow', 'getRowSeq', 'getRowById', 'getRowid', 'getTableData', 'getFullData', 'setColumnFixed', 'clearColumnFixed', 'setColumnWidth', 'getColumnWidth', 'recalcRowHeight', 'setRowHeightConf', 'getRowHeightConf', 'setRowHeight', 'getRowHeight', 'hideColumn', 'showColumn', 'resetColumn', 'refreshColumn', 'refreshScroll', 'recalculate', 'closeTooltip', 'isAllCheckboxChecked', 'isAllCheckboxIndeterminate', 'getCheckboxIndeterminateRecords', 'setCheckboxRow', 'setCheckboxRowKey', 'isCheckedByCheckboxRow', 'isCheckedByCheckboxRowKey', 'isIndeterminateByCheckboxRow', 'isIndeterminateByCheckboxRowKey', 'toggleCheckboxRow', 'setAllCheckboxRow', 'getRadioReserveRecord', 'clearRadioReserve', 'getCheckboxReserveRecords', 'clearCheckboxReserve', 'toggleAllCheckboxRow', 'clearCheckboxRow', 'setCurrentRow', 'isCheckedByRadioRow', 'isCheckedByRadioRowKey', 'setRadioRow', 'setRadioRowKey', 'clearCurrentRow', 'clearRadioRow', 'getCurrentRecord', 'getRadioRecord', 'getCurrentColumn', 'setCurrentColumn', 'clearCurrentColumn', 'setPendingRow', 'togglePendingRow', 'hasPendingByRow', 'isPendingByRow', 'getPendingRecords', 'clearPendingRow', 'setFilterByEvent', 'sort', 'setSort', 'setSortByEvent', 'clearSort', 'clearSortByEvent', 'isSort', 'getSortColumns', 'closeFilter', 'isFilter', 'clearFilterByEvent', 'isActiveFilterByColumn', 'isRowExpandLoaded', 'clearRowExpandLoaded', 'reloadRowExpand', 'reloadRowExpand', 'toggleRowExpand', 'setAllRowExpand', 'setRowExpand', 'isExpandByRow', 'isRowExpandByRow', 'clearRowExpand', 'clearRowExpandReserve', 'getRowExpandRecords', 'getTreeExpandRecords', 'isTreeExpandLoaded', 'clearTreeExpandLoaded', 'reloadTreeExpand', 'reloadTreeChilds', 'toggleTreeExpand', 'setAllTreeExpand', 'setTreeExpand', 'isTreeExpandByRow', 'clearTreeExpand', 'clearTreeExpandReserve', 'getScroll', 'scrollTo', 'scrollToStartRow', 'scrollToEndRow', 'scrollToRow', 'scrollToStartColumn', 'scrollToEndColumn', 'scrollToColumn', 'clearScroll', 'updateFooter', 'updateStatus', 'setMergeCells', 'removeInsertRow', 'removeMergeCells', 'getMergeCells', 'clearMergeCells', 'setMergeFooterItems', 'removeMergeFooterItems', 'getMergeFooterItems', 'clearMergeFooterItems', 'getCustomStoreData', 'setRowGroupExpand', 'setRowGroupExpandByField', 'setAllRowGroupExpand', 'clearRowGroupExpand', 'isRowGroupExpandByRow', 'isRowGroupRecord', 'isAggregateRecord', 'isAggregateExpandByRow', 'getAggregateContentByRow', 'getAggregateRowChildren', 'setRowGroups', 'clearRowGroups', 'openTooltip', 'moveColumnTo', 'moveRowTo', 'getCellLabel', 'undo', 'redo', 'getCellElement', 'focus', 'blur', 'connect'] const defaultLayouts: VxeGanttPropTypes.Layouts = [['Form'], ['Toolbar', 'Top', 'Gantt', 'Bottom', 'Pager']] function createInternalData (): GanttInternalData { return { linkFromConfMaps: {}, linkToConfMaps: {}, linkUniqueMaps: {}, uFoot: false, resizeTableWidth: 0, // barTipTimeout: null, // dragBarRow: null, // dragLineRow: null, dragLinkToStore: { rowid: null, type: 0 } } } function createReactData (): GanttReactData { return { tableLoading: false, proxyInited: false, isZMax: false, tableLinks: [], tableData: [], filterData: [], formData: {}, sortData: [], footerData: [], tZindex: 0, tablePage: { total: 0, pageSize: getConfig().pager?.pageSize || 10, currentPage: 1 }, showLeftView: true, showRightView: true, taskScaleList: [], barTipStore: { row: null, content: '', visible: false, params: null }, dragLinkFromStore: { rowid: null, type: 0 }, activeBarRowid: null, activeLink: null, isActiveCeLe: false, linkList: [], upLinkFlag: 0, showSplitAnimat: false, nowTime: 0, currLeftSpacing: 0, currRightSpacing: 0 } } const viewTypeLevelMaps = { year: 19, quarter: 17, month: 15, week: 13, day: 11, date: 9, hour: 7, minute: 5, second: 3 } function getViewTypeLevel (type: VxeGanttDefines.ColumnScaleType) { return viewTypeLevelMaps[type || 'date'] || viewTypeLevelMaps.date } export default defineVxeComponent({ name: 'VxeGantt', mixins: [], props: { ...(tableProps as { border: PropType<VxeTablePropTypes.Border> round: PropType<VxeTablePropTypes.Round> loading: PropType<VxeTablePropTypes.Loading> height: PropType<VxeTablePropTypes.Height> minHeight: PropType<VxeTablePropTypes.MinHeight> maxHeight: PropType<VxeTablePropTypes.MaxHeight> seqConfig: PropType<VxeTablePropTypes.SeqConfig> editConfig: PropType<VxeTablePropTypes.EditConfig> sortConfig: PropType<VxeTablePropTypes.SortConfig> treeConfig: PropType<VxeTablePropTypes.TreeConfig> filterConfig: PropType<VxeTablePropTypes.FilterConfig> expandConfig: PropType<VxeTablePropTypes.ExpandConfig> aggregateConfig: PropType<VxeTablePropTypes.AggregateConfig> validConfig: PropType<VxeTablePropTypes.ValidConfig> editRules: PropType<VxeTablePropTypes.EditRules> animat: PropType<VxeTablePropTypes.Animat> scrollbarConfig: PropType<VxeTablePropTypes.ScrollbarConfig> showFooter: PropType<VxeTablePropTypes.ShowFooter> params: PropType<VxeTablePropTypes.Params> }), columns: Array as PropType<VxeGridPropTypes.Columns>, pagerConfig: Object as PropType<VxeGridPropTypes.PagerConfig>, proxyConfig: Object as PropType<VxeGridPropTypes.ProxyConfig<any>>, toolbarConfig: Object as PropType<VxeGridPropTypes.ToolbarConfig>, formConfig: Object as PropType<VxeGridPropTypes.FormConfig>, zoomConfig: Object as PropType<VxeGridPropTypes.ZoomConfig>, links: Array as PropType<VxeGanttPropTypes.Links>, layouts: Array as PropType<VxeGanttPropTypes.Layouts>, taskConfig: Object as PropType<VxeGanttPropTypes.TaskConfig>, taskViewScaleConfig: Object as PropType<VxeGanttPropTypes.TaskViewScaleConfig>, taskNowLineConfig: Object as PropType<VxeGanttPropTypes.TaskNowLineConfig>, taskViewConfig: Object as PropType<VxeGanttPropTypes.TaskViewConfig>, taskLinkConfig: Object as PropType<VxeGanttPropTypes.TaskLinkConfig>, taskBarConfig: Object as PropType<VxeGanttPropTypes.TaskBarConfig>, taskBarMilestoneConfig: Object as PropType<VxeGanttPropTypes.TaskBarMilestoneConfig>, taskBarSubviewConfig: Object as PropType<VxeGanttPropTypes.TaskBarSubviewConfig>, taskBarTooltipConfig: Object as PropType<VxeGanttPropTypes.TaskBarTooltipConfig>, taskSplitConfig: Object as PropType<VxeGanttPropTypes.TaskSplitConfig>, taskBarResizeConfig: Object as PropType<VxeGanttPropTypes.TaskBarResizeConfig>, taskBarMoveConfig: Object as PropType<VxeGanttPropTypes.TaskBarMoveConfig>, size: { type: String as PropType<VxeGridPropTypes.Size>, default: () => getConfig().gantt.size || getConfig().size } }, emits: ganttEmits, setup (props, context) { const { slots, emit } = context const xID = XEUtils.uniqueId() // 使用已安装的组件,如果未安装则不渲染 const VxeUIFormComponent = VxeUI.getComponent('VxeForm') const VxeUIPagerComponent = VxeUI.getComponent('VxePager') const VxeTableComponent = VxeUI.getComponent('VxeTable') const VxeToolbarComponent = VxeUI.getComponent('VxeToolbar') const VxeUITooltipComponent = VxeUI.getComponent('VxeTooltip') const { computeSize } = useFns.useSize(props) const reactData = reactive(createReactData()) const internalData = createInternalData() const refElem = ref<HTMLDivElement>() const refTable = ref<VxeTableConstructor & VxeTablePrivateMethods>() const refForm = ref<VxeFormInstance>() const refToolbar = ref<VxeToolbarInstance>() const refPager = ref<VxePagerInstance>() const refGanttContainerElem = ref<HTMLDivElement>() const refClassifyWrapperElem = ref<HTMLDivElement>() const refGanttView = ref<VxeGanttViewInstance & VxeGanttViewPrivateMethods>() const refPopupContainerElem = ref<HTMLDivElement>() const refFormWrapper = ref<HTMLDivElement>() const refToolbarWrapper = ref<HTMLDivElement>() const refTopWrapper = ref<HTMLDivElement>() const refBottomWrapper = ref<HTMLDivElement>() const refPagerWrapper = ref<HTMLDivElement>() const refTableWrapper = ref<HTMLDivElement>() const refGanttWrapper = ref<HTMLDivElement>() const refTooltip = ref<VxeTooltipInstance>() const refResizableSplitTip = ref<HTMLDivElement>() const extendTableMethods = <T>(methodKeys: T[]) => { const funcs: any = {} methodKeys.forEach(name => { funcs[name] = (...args: any[]) => { const $xeTable: any = refTable.value if ($xeTable && $xeTable[name]) { return $xeTable[name](...args) } } }) return funcs } const ganttExtendTableMethods = extendTableMethods(tableComponentMethodKeys) as VxeTableMethods tableComponentMethodKeys.forEach(name => { ganttExtendTableMethods[name] = (...args: any[]) => { const $xeTable: any = refTable.value if ($xeTable && $xeTable[name]) { return $xeTable && $xeTable[name](...args) } } }) const computeProxyOpts = computed(() => { return XEUtils.merge({}, XEUtils.clone(getConfig().gantt.proxyConfig, true), props.proxyConfig) }) const computeIsRespMsg = computed(() => { const proxyOpts = computeProxyOpts.value return !!(XEUtils.isBoolean(proxyOpts.message) ? proxyOpts.message : proxyOpts.showResponseMsg) }) const computeIsActiveMsg = computed(() => { const proxyOpts = computeProxyOpts.value return XEUtils.isBoolean(proxyOpts.showActionMsg) ? proxyOpts.showActionMsg : !!proxyOpts.showActiveMsg }) const computePagerOpts = computed(() => { return Object.assign({}, getConfig().gantt.pagerConfig, props.pagerConfig) }) const computeFormOpts = computed(() => { return Object.assign({}, getConfig().gantt.formConfig, props.formConfig) }) const computeToolbarOpts = computed(() => { return Object.assign({}, getConfig().gantt.toolbarConfig, props.toolbarConfig) }) const computeZoomOpts = computed(() => { return Object.assign({}, getConfig().gantt.zoomConfig, props.zoomConfig) }) const computeTaskOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskConfig, props.taskConfig) }) const computeTaskViewScaleOpts = computed(() => { return XEUtils.merge({}, getConfig().gantt.taskViewScaleConfig, props.taskViewScaleConfig) }) const computeTaskNowLineOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskNowLineConfig, props.taskNowLineConfig) }) const computeTaskViewOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskViewConfig, props.taskViewConfig) }) const computeTaskBarOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskBarConfig, props.taskBarConfig) }) const computeTaskBarMoveOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskBarMoveConfig, props.taskBarMoveConfig) }) const computeTaskBarResizeOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskBarResizeConfig, props.taskBarResizeConfig) }) const computeTaskSplitOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskSplitConfig, props.taskSplitConfig) }) const computeTaskBarMilestoneOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskBarMilestoneConfig, props.taskBarMilestoneConfig) }) const computeTaskBarSubviewOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskBarSubviewConfig, props.taskBarSubviewConfig) }) const computeTaskBarTooltipOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskBarTooltipConfig, props.taskBarTooltipConfig) }) const computeTaskLinkOpts = computed(() => { return Object.assign({}, getConfig().gantt.taskLinkConfig, props.taskLinkConfig) }) const computeScaleUnit = computed(() => { const minScale = computeMinScale.value return minScale ? minScale.type : 'date' }) const computeMinScale = computed(() => { const { taskScaleList } = reactData return XEUtils.last(taskScaleList) }) const computeWeekScale = computed(() => { const { taskScaleList } = reactData return taskScaleList.find(item => item.type === 'week') }) const computeTaskViewScales = computed(() => { const taskViewOpts = computeTaskViewOpts.value const { scales } = taskViewOpts return scales }) const computeTaskLinkStyle = computed(() => { const { lineType, lineWidth, lineStatus, lineColor } = computeTaskLinkOpts.value return `${lineType || ''}_${lineWidth || ''}_${lineStatus || ''}_${lineColor || ''}` }) const computeTitleField = computed(() => { const taskOpts = computeTaskOpts.value return taskOpts.titleField || 'title' }) const computeStartField = computed(() => { const taskOpts = computeTaskOpts.value return taskOpts.startField || 'start' }) const computeEndField = computed(() => { const taskOpts = computeTaskOpts.value return taskOpts.endField || 'end' }) const computeTypeField = computed(() => { const taskOpts = computeTaskOpts.value return taskOpts.typeField || 'type' }) const computeProgressField = computed(() => { const taskOpts = computeTaskOpts.value return taskOpts.progressField || 'progress' }) const computeScrollbarOpts = computed(() => { return Object.assign({}, getConfig().gantt.scrollbarConfig, props.scrollbarConfig) }) const computeScrollbarXToTop = computed(() => { const scrollbarOpts = computeScrollbarOpts.value return !!(scrollbarOpts.x && scrollbarOpts.x.position === 'top') }) const computeScrollbarYToLeft = computed(() => { const scrollbarOpts = computeScrollbarOpts.value return !!(scrollbarOpts.y && scrollbarOpts.y.position === 'left') }) const computeStyles = computed(() => { const { height, maxHeight, taskBarSubviewConfig } = props const { isZMax, tZindex } = reactData const taskViewOpts = computeTaskViewOpts.value const { viewStyle, tableStyle } = taskViewOpts const taskBarOpts = computeTaskBarOpts.value const { barStyle } = taskBarOpts const taskBarSubviewOpts = computeTaskBarSubviewOpts.value const taskNowLineOpts = computeTaskNowLineOpts.value const { fontColor: nlfColor, bgColor: nlbgColor, width: nlWidth } = taskNowLineOpts const stys: VxeComponentStyleType = {} if (isZMax) { stys.zIndex = tZindex } else { if (height) { stys.height = height === 'auto' || height === '100%' ? '100%' : toCssUnit(height) } if (maxHeight) { stys.maxHeight = maxHeight === 'auto' || maxHeight === '100%' ? '100%' : toCssUnit(maxHeight) } } if (barStyle && !XEUtils.isFunction(barStyle)) { const { bgColor, completedBgColor, overviewBgColor } = barStyle if (bgColor) { stys['--vxe-ui-gantt-view-task-bar-background-color'] = bgColor } if (completedBgColor) { stys['--vxe-ui-gantt-view-task-bar-completed-background-color'] = completedBgColor } if (overviewBgColor && hasEnableConf(taskBarSubviewConfig, taskBarSubviewOpts)) { stys['--vxe-ui-gantt-view-task-bar-overview-background-color'] = overviewBgColor } } if (nlfColor) { stys['--vxe-ui-gantt-view-task-now-line-color'] = nlfColor } if (nlbgColor) { stys['--vxe-ui-gantt-view-task-now-line-background-color'] = nlbgColor } if (nlWidth) { stys['--vxe-ui-gantt-view-task-now-line-width'] = nlWidth } if (viewStyle) { const { cellWidth } = viewStyle if (cellWidth) { stys['--vxe-ui-gantt-view-default-cell-width'] = toCssUnit(cellWidth) } } if (tableStyle) { const { width: defTbWidth } = tableStyle if (defTbWidth) { stys['--vxe-ui-gantt-view-table-default-width'] = toCssUnit(defTbWidth) } } return stys }) const computeTableExtendProps = computed(() => { const rest: Record<string, any> = {} const ganttProps: any = props tableComponentPropKeys.forEach((key) => { if (ganttProps[key] !== undefined) { rest[key] = ganttProps[key] } }) return rest }) const computeTableProps = computed(() => { const { showFooter, seqConfig, pagerConfig, editConfig, proxyConfig } = props const { isZMax, tablePage, footerData } = reactData const taskViewOpts = computeTaskViewOpts.value const { tableStyle } = taskViewOpts const tableExtendProps = computeTableExtendProps.value const proxyOpts = computeProxyOpts.value const pagerOpts = computePagerOpts.value const isLoading = computeIsLoading.value const tProps = Object.assign({}, tableExtendProps, { // 不支持修改的属性 showOverflow: true, showHeaderOverflow: true, showFooterOverflow: true }) if (tableStyle) { const { border } = tableStyle if (!XEUtils.eqNull(border)) { tProps.border = border } } if (showFooter && !tProps.footerData) { // 如果未设置自己的标位数据,则使用代理的 tProps.footerData = footerData } else if (proxyOpts.footer && footerData.length) { // 如果代理标为数据,且未请求到数据,则用自己的 tProps.footerData = footerData } if (isZMax) { if (tProps.maxHeight) { tProps.maxHeight = '100%' } else { tProps.height = '100%' } } if (proxyConfig && isEnableConf(proxyOpts)) { tProps.loading = isLoading if (pagerConfig && proxyOpts.seq && isEnableConf(pagerOpts)) { tProps.seqConfig = Object.assign({}, seqConfig, { startIndex: (tablePage.currentPage - 1) * tablePage.pageSize }) } } if (editConfig) { tProps.editConfig = Object.assign({}, editConfig) } return tProps }) const computeCurrLayoutConf = computed(() => { const { layouts } = props let confs: VxeGanttPropTypes.Layouts = [] if (layouts && layouts.length) { confs = layouts } else { confs = getConfig().gantt.layouts || defaultLayouts } let headKeys: VxeGanttDefines.LayoutKey[] = [] let bodyKeys: VxeGanttDefines.LayoutKey[] = [] let footKeys: VxeGanttDefines.LayoutKey[] = [] if (confs.length) { if (XEUtils.isArray(confs[0])) { headKeys = confs[0] as VxeGanttDefines.LayoutKey[] bodyKeys = (confs[1] || []) as VxeGanttDefines.LayoutKey[] footKeys = (confs[2] || []) as VxeGanttDefines.LayoutKey[] } else { bodyKeys = confs as VxeGanttDefines.LayoutKey[] } } return { headKeys, bodyKeys, footKeys } }) const computeCustomCurrentPageFlag = computed(() => { const pagerOpts = computePagerOpts.value return pagerOpts.currentPage }) const computeCustomPageSizeFlag = computed(() => { const pagerOpts = computePagerOpts.value return pagerOpts.pageSize }) const computeCustomTotalFlag = computed(() => { const pagerOpts = computePagerOpts.value return pagerOpts.total }) const computePageCount = computed(() => { const { tablePage } = reactData return Math.max(Math.ceil(tablePage.total / tablePage.pageSize), 1) }) const computeIsLoading = computed(() => { const { loading, proxyConfig } = props const { tableLoading } = reactData const proxyOpts = computeProxyOpts.value const { showLoading } = proxyOpts return loading || (tableLoading && showLoading && proxyConfig && isEnableConf(proxyOpts)) }) const computeTableBorder = computed(() => { let { border } = props const taskViewOpts = computeTaskViewOpts.value const { viewStyle } = taskViewOpts if (viewStyle) { if (!XEUtils.eqNull(viewStyle.border)) { border = viewStyle.border } } if (border === true) { return 'full' } if (border) { return border } return 'default' }) const refMaps: GanttPrivateRef = { refElem, refTable, refForm, refToolbar, refPager, refGanttView, refGanttContainerElem, refClassifyWrapperElem, refPopupContainerElem } const computeMaps: VxeGanttPrivateComputed = { computeProxyOpts, computePagerOpts, computeFormOpts, computeToolbarOpts, computeZoomOpts, computeTaskOpts, computeTaskViewScaleOpts, computeTaskNowLineOpts, computeTaskViewOpts, computeTaskBarOpts, computeTaskBarMoveOpts, computeTaskBarResizeOpts, computeTaskSplitOpts, computeTaskBarMilestoneOpts, computeTaskBarSubviewOpts, computeTaskBarTooltipOpts, computeTaskLinkOpts, computeTaskViewScales, computeScaleUnit, computeMinScale, computeWeekScale, computeTitleField, computeStartField, computeEndField, computeTypeField, computeProgressField, computeScrollbarOpts, computeScrollbarXToTop, computeScrollbarYToLeft } /** * 已废弃,保留兼容 * @deprecated */ ;(computeMaps as any).computeTaskScaleConfs = computeTaskViewScales const $xeGantt = { xID, props: props as VxeGanttProps, context, reactData, internalData, getRefMaps: () => refMaps, getComputeMaps: () => computeMaps } as VxeGanttConstructor & VxeGanttPrivateMethods const handleTaskScaleConfig = () => { const taskScaleConfs = computeTaskViewScales.value const taskViewScaleOpts = computeTaskViewScaleOpts.value const scaleConfs: VxeGanttDefines.ColumnScaleObj[] = [] const keyMaps: Record<string, boolean> = {} const scaleList = (taskScaleConfs && taskScaleConfs.length ? taskScaleConfs : ['month', 'date'] as VxeGanttDefines.ColumnScaleType[]) scaleList.forEach(conf => { const sConf = !conf || XEUtils.isString(conf) ? { type: conf } : conf const type = sConf.type const step = sConf.step const level = getViewTypeLevel(type) if (step) { errLog('vxe.error.errProp', [`step=${step}`, 'step=1']) } if (!type || !viewTypeLevelMaps[type]) { errLog('vxe.error.errProp', [`type=${type}`, XEUtils.keys(viewTypeLevelMaps).join(',')]) return } if (keyMaps[type]) { errLog('vxe.error.repeatProp', ['type', type]) return } const scaleObj = Object.assign({}, type ? (taskViewScaleOpts[type] || {}) : {}, sConf, { level }) keyMaps[type] = true scaleConfs.push(scaleObj) }) reactData.taskScaleList = XEUtils.orderBy(scaleConfs, { field: 'level', order: 'desc' }) } const initToolbar = () => { const toolbarOpts = computeToolbarOpts.value if (props.toolbarConfig && isEnableConf(toolbarOpts)) { nextTick(() => { const $xeTable = refTable.value const $xeToolbar = refToolbar.value if ($xeTable && $xeToolbar) { $xeTable.connectToolbar($xeToolbar) } }) } } const initGanttView = () => { const $xeTable = refTable.value const $ganttView = refGanttView.value if ($xeTable && $ganttView) { $xeTable.handleConnectGanttView($ganttView) } } const getFormData = () => { const { proxyConfig } = props const { formData } = reactData const proxyOpts = computeProxyOpts.value const formOpts = computeFormOpts.value return proxyConfig && isEnableConf(proxyOpts) && proxyOpts.form ? formData : formOpts.data } const initPages = (propKey?: 'currentPage' | 'pageSize' | 'total') => { const { tablePage } = reactData const { pagerConfig } = props const pagerOpts = computePagerOpts.value if (pagerConfig && isEnableConf(pagerOpts)) { if (propKey) { if (pagerOpts[propKey]) { tablePage[propKey] = XEUtils.toNumber(pagerOpts[propKey]) } } else { const { currentPage, pageSize, total } = pagerOpts if (currentPage) { tablePage.currentPage = currentPage } if (pageSize) { tablePage.pageSize = pageSize } if (total) { tablePage.total = total } } } } const triggerPendingEvent = (code: string) => { const isActiveMsg = computeIsActiveMsg.value const $xeTable = refTable.value const selectRecords = $xeTable ? $xeTable.getCheckboxRecords() : [] if (selectRecords.length) { if ($xeTable) { $xeTable.togglePendingRow(selectRecords) } $xeGantt.clearCheckboxRow() } else { if (isActiveMsg) { if (VxeUI.modal) { VxeUI.modal.message({ id: code, content: getI18n('vxe.grid.selectOneRecord'), status: 'warning' }) } } } } const getRespMsg = (rest: any, defaultMsg: string) => { const proxyOpts = computeProxyOpts.value const resConfigs = proxyOpts.response || proxyOpts.props || {} const messageProp = resConfigs.message const $xeTable = refTable.value let msg if (rest && messageProp) { msg = XEUtils.isFunction(messageProp) ? messageProp({ data: rest, $table: $xeTable as VxeTableConstructor, $grid: null, $gantt: $xeGantt }) : XEUtils.get(rest, messageProp) } return msg || getI18n(defaultMsg) } const handleDeleteRow = (code: string, alertKey: string, callback: () => void): Promise<void> => { const isActiveMsg = computeIsActiveMsg.value const selectRecords = $xeGantt.getCheckboxRecords() if (isActiveMsg) { if (selectRecords.length) { if (VxeUI.modal) { return VxeUI.modal.confirm({ id: `cfm_${code}`, content: getI18n(alertKey), escClosable: true }).then((type) => { if (type === 'confirm') { return callback() } }) } } else { if (VxeUI.modal) { VxeUI.modal.message({ id: `msg_${code}`, content: getI18n('vxe.grid.selectOneRecord'), status: 'warning' }) } } } else { if (selectRecords.length) { callback() } } return Promise.resolve() } const pageChangeEvent: VxePagerEvents.PageChange = (params) => { const { proxyConfig } = props const { tablePage } = reactData const { $event, currentPage, pageSize } = params const proxyOpts = computeProxyOpts.value tablePage.currentPage = currentPage tablePage.pageSize = pageSize $xeGantt.dispatchEvent('page-change', params, $event) if (proxyConfig && isEnableConf(proxyOpts)) { $xeGantt.commitProxy('query').then((rest) => { $xeGantt.dispatchEvent('proxy-query', rest, $event) }) } } const handleSortEvent: VxeTableEvents.SortChange | VxeTableEvents.ClearAllSort = (params) => { const $xeTable = refTable.value const { proxyConfig } = props if (!$xeTable) { return } const { computeSortOpts } = $xeTable.getComputeMaps() const proxyOpts = computeProxyOpts.value const sortOpts = computeSortOpts.value // 如果是服务端排序 if (sortOpts.remote) { reactData.sortData = params.sortList if (proxyConfig && isEnableConf(proxyOpts)) { reactData.tablePage.currentPage = 1 $xeGantt.commitProxy('query').then((rest) => { $xeGantt.dispatchEvent('proxy-query', rest, params.$event) }) } } } const sortChangeEvent: VxeTableEvents.SortChange = (params) => { handleSortEvent(params) $xeGantt.dispatchEvent('sort-change', params, params.$event) } const clearAllSortEvent: VxeTableEvents.ClearAllSort = (params) => { handleSortEvent(params) $xeGantt.dispatchEvent('clear-all-sort', params, params.$event) } const handleFilterEvent: VxeTableEvents.FilterChange | VxeTableEvents.ClearAllFilter = (params) => { const $xeTable = refTable.value const { proxyConfig } = props if (!$xeTable) { return } const { computeFilterOpts } = $xeTable.getComputeMaps() const proxyOpts = computeProxyOpts.value const filterOpts = computeFilterOpts.value // 如果是服务端过滤 if (filterOpts.remote) { reactData.filterData = params.filterList if (proxyConfig && isEnableConf(proxyOpts)) { reactData.tablePage.currentPage = 1 internalData.uFoot = true $xeGantt.commitProxy('query').then((rest) => { $xeGantt.dispatchEvent('proxy-query', rest, params.$event) }) internalData.uFoot = false updateQueryFooter() } } } const filterChangeEvent: VxeTableEvents.FilterChange = (params) => { handleFilterEvent(params) $xeGantt.dispatchEvent('filter-change', params, params.$event) } const clearAllFilterEvent: VxeTableEvents.ClearAllFilter = (params) => { handleFilterEvent(params) $xeGantt.dispatchEvent('clear-all-filter', params, params.$event) } const submitFormEvent: VxeFormEvents.Submit = (params) => { const { proxyConfig } = props const proxyOpts = computeProxyOpts.value if (reactData.tableLoading) { return } if (proxyConfig && isEnableConf(proxyOpts)) { internalData.uFoot = true $xeGantt.commitProxy('reload').then((rest) => { $xeGantt.dispatchEvent('proxy-query', { ...rest, isReload: true }, params.$event) }) internalData.uFoot = false updateQueryFooter() } $xeGantt.dispatchEvent('form-submit', params, params.$event) } const resetFormEvent: VxeFormEvents.Reset = (params) => { const $xeTable = refTable.value const { proxyConfig } = props const { $event } = params const proxyOpts = computeProxyOpts.value if (proxyConfig && isEnableConf(proxyOpts)) { if ($xeTable) { $xeTable.clearScroll() } internalData.uFoot = true $xeGantt.commitProxy('reload').then((rest) => { $xeGantt.dispatchEvent('proxy-query', { ...rest, isReload: true }, $event) }) internalData.uFoot = false updateQueryFooter() } $xeGantt.dispatchEvent('form-reset', params, $event) } const submitInvalidEvent: VxeFormEvents.SubmitInvalid = (params) => { $xeGantt.dispatchEvent('form-submit-invalid', params, params.$event) } const collapseEvent: VxeFormEvents.Collapse = (params) => { const { $event } = params $xeGantt.dispatchEvent('form-toggle-collapse', params, $event) $xeGantt.dispatchEvent('form-collapse', params, $event) } const handleZoom = (isMax?: boolean) => { const { isZMax } = reactData if (isMax ? !isZMax : isZMax) { reactData.isZMax = !isZMax if (reactData.tZindex < getLastZIndex()) { reactData.tZindex = nextZIndex() } } return nextTick() .then(() => $xeGantt.recalculate(true)) .then(() => { setTimeout(() => $xeGantt.recalculate(true), 15) return reactData.isZMax }) } const getFuncSlot = (optSlots: any, slotKey: string) => { const funcSlot = optSlots[slotKey] if (funcSlot) { if (XEUtils.isString(funcSlot)) { if (slots[funcSlot]) { return slots[funcSlot] } else { errLog('vxe.error.notSlot', [funcSlot]) } } else { return funcSlot } } return null } const getConfigSlot = (slotConfigs?: Record<string, any>) => { const slotConf: Record<string, any> = {} XEUtils.objectMap(slotConfigs, (slotFunc, slotKey) => { if (slotFunc) { if (XEUtils.isString(slotFunc)) { if (slots[slotFunc]) { slotConf[slotKey] = slots[slotFunc] } else { errLog('vxe.error.notSlot', [slotFunc]) } } else { slotConf[slotKey] = slotFunc } } }) return slotConf } const dragSplitEvent = (evnt: MouseEvent) => { const el = refElem.value if (!el) { return } const ganttContainerEl = refGanttContainerElem.value if (!ganttContainerEl) { return } const tableWrapperEl = refTableWrapper.value if (!tableWrapperEl) { return } const rsSplitLineEl = refResizableSplitTip.value if (!rsSplitLineEl) { return } const taskViewOpts = computeTaskViewOpts.value const containerRect = ganttContainerEl.getBoundingClientRect() const rsSplitTipEl = rsSplitLineEl.children[0] as HTMLDivElement const disX = evnt.clientX const ganttWidth = ganttContainerEl.clientWidth const tableWidth = tableWrapperEl.clientWidth const tableMinWidth = (taskViewOpts.tableStyle && XEUtils.toNumber(taskViewOpts.tableStyle.minWidth)) || 80 let targetTableWidth = tableWidth let offsetLeft = -1 addClass(el, 'is--split-drag') const handleReStyle = (evnt: MouseEvent) => { const rsNumLeftEl = rsSplitTipEl.children[0] as HTMLDivElement const rsNumRightEl = rsSplitTipEl.children[1] as HTMLDivElement let tipHeight = 0 if (rsNumLeftEl) { if (offsetLeft < 0) { rsNumLeftEl.style.display = 'none' } else { rsNumLeftEl.textContent = `${targetTableWidth}px` rsNumLeftEl.style.display = 'block' tipHeight = rsNumLeftEl.offsetHeight } } if (rsNumRightEl) { if (offsetLeft < 0) { rsNumRightEl.textContent = `${Math.floor(containerRect.width - targetTableWidth)}px` rsNumRightEl.style.display = 'block' tipHeight = rsNumRightEl.offsetHeight } else { rsNumRightEl.style.display = 'none' } } const tipTop = evnt.clientY - containerRect.top - tipHeight / 2 rsSplitLineEl.style.left = `${targetTableWidth}px` rsSplitTipEl.style.top = `${Math.min(containerRect.height - tipHeight - 1, Math.max(1, tipTop))}px` } document.onmousemove = (evnt) => { evnt.preventDefault() offsetLeft = (evnt.clientX - disX) targetTableWidth = Math.min(ganttWidth - 80, Math.max(tableMinWidth, tableWidth + offsetLeft)) handleReStyle(evnt) } document.onmouseup = () => { document.onmousemove = null document.onmouseup = null rsSplitLineEl.style.display = '' tableWrapperEl.style.width = `${targetTableWidth}px` removeClass(el, 'is--split-drag') const $xeTable = refTable.value if ($xeTable) { $xeTable.recalculate(true) } } rsSplitLineEl.style.display = 'block' handleReStyle(evnt) } const handleSplitAnimat = () => { const taskSplitOpts = computeTaskSplitOpts.value const { animation } = taskSplitOpts if (animation) { const { _taTime } = internalData if (_taTime) { clearTimeout(_taTime) } reactData.showSplitAnimat = true internalData._taTime = setTimeout(() => { reactData.showSplitAnimat = false internalData._taTime = null }, 350) } } const handleSplitLeftViewEvent = () => { handleSplitAnimat() reactData.showLeftView = !reactData.showLeftView } const handleSplitRightViewEvent = () => { handleSplitAnimat() reactData.showRightView = !reactData.showRightView } const tableCompEvents: VxeTableEventProps = {} tableEmits.forEach(name => { const type = XEUtils.camelCase(`on-${name}`) as keyof VxeTableEventProps tableCompEvents[type] = (...args: any[]) => emit(name, ...args) }) const getDefaultFormData = () => { const formOpts = computeFormOpts.value if (formOpts.items) { const fData: any = {} formOpts.items.forEach(item => { const { field, itemRender } = item if (field) { let itemValue: any = null if (itemRender) { const { startField, endField, defaultValue } = itemRender if (XEUtils.isFunction(defaultValue)) { itemValue = defaultValue({ item }) } else if (!XEUtils.isUndefined(defaultValue)) { itemValue = defaultValue } if (startField && endField) { XEUtils.set(fData, startField, null) XEUtils.set(fData, endField, null) } } fData[field] = itemValue } }) return fData } return {} } const initProxy = () => { const { proxyConfig, formConfig } = props const { proxyInited } = reactData const proxyOpts = computeProxyOpts.value const formOpts = computeFormOpts.value if (proxyConfig && isEnableConf(proxyOpts)) { if (formConfig && isEnableConf(formOpts) && proxyOpts.form && formOpts.items) { reactData.formData = getDefaultFormData() } if (!proxyInited) { reactData.proxyInited = true if (proxyOpts.autoLoad !== false) { nextTick().then(() => { internalData.uFoot = true const rest = $xeGantt.commitProxy('initial') internalData.uFoot = false updateQueryFooter() return rest }).then((rest) => { dispatchEvent('proxy-query', { ...rest, isInited: true }, new Event('initial')) }) } } } } const updateQueryFooter = () => { const proxyOpts = computeProxyOpts.value const { ajax } = proxyOpts if (ajax && ajax.queryFooter) { return $xeGantt.commitProxy('queryFooter') } } const handleGlobalKeydownEvent = (evnt: KeyboardEvent) => { const zoomOpts = computeZoomOpts.value const isEsc = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ESCAPE) if (isEsc && reactData.isZMax && zoomOpts.escRestore !== false) { $xeGantt.triggerZoomEvent(evnt) } } const dispatchEvent = (type: ValueOf<VxeGanttEmits>, params: Record<string, any>, evnt: Event | null) => { emit(type, createEvent(evnt, { $grid: null, $gantt: $xeGantt }, params)) } const handleTargetEnterEvent = (isClear: boolean) => { const $tooltip = refTooltip.value clearTimeout(internalData.barTipTimeout) if (isClear) { $xeGantt.closeTaskBarTooltip() } else { if ($tooltip && $tooltip.setActived) { $tooltip.setActived(true) } } } const ganttMethods: GanttMethods = { dispatchEvent, getEl () { return refElem.value as HTMLDivElement }, /** * 提交指令,支持 code 或 button * @param {String/Object} code 字符串或对象 */ commitProxy (proxyTarget: string | VxeToolbarPropTypes.ButtonConfig, ...args: any[]) { const { showFooter, proxyConfig, toolbarConfig, pagerConfig, editRules, validConfig } = props const { tablePage } = reactData const isActiveMsg = computeIsActiveMsg.value const isRespMsg = computeIsRespMsg.value const proxyOpts = computeProxyOpts.value const pagerOpts = computePagerOpts.value const toolbarOpts = computeToolbarOpts.value const { beforeQuery, afterQuery, beforeQueryFooter, afterQueryFooter, beforeDelete, afterDelete, beforeSave, afterSave, ajax = {} } = proxyOpts const resConfigs = (proxyOpts.response || proxyOpts.props || {}) as VxeGridDefines.ProxyConfigResponseConfig const $xeTable = refTable.value if (!$xeTable) { return nextTick() } let formData = getFormData() let button: VxeToolbarPropTypes.ButtonConfig | null = null let code: string | null = null if (XEUtils.isString(proxyTarget)) { const { buttons } = toolbarOpts const matchObj = toolbarConfig && isEnableConf(toolbarOpts) && buttons ? XEUtils.findTree(buttons, (item) => item.code === proxyTarget, { children: 'dropdowns' }) : null button = matchObj ? matchObj.item : null code = proxyTarget } else { button = proxyTarget code = button.code as string } const btnParams = button ? button.params : null switch (code) { case 'insert': return $xeTable.insert({}) case 'insert_edit': return $xeTable.insert({}).then(({ row }) => $xeTable.setEditRow(row, true)) // 已废弃 case 'insert_actived': return $xeTable.insert({}).then(({ row }) => $xeTable.setEditRow(row, true)) // 已废弃 case 'mark_cancel': triggerPendingEvent(code) break case 'remove': return handleDeleteRow(code, 'vxe.grid.removeSelectRecord', () => $xeTable.removeCheckboxRow()) case 'import': $xeTable.importData(btnParams) break case 'open_import': $xeTable.openImport(btnParams) break case 'export': $xeTable.exportData(btnParams) break case 'open_export': $xeTable.openExport(btnParams) break case 'reset_custom': return $xeTable.resetCustom(true) case 'initial': case 'reload': case 'query': { const qMethods = ajax.query const qsMethods = ajax.querySuccess const qeMethods = ajax.queryError if (qMethods) { const isInited = code === 'initial' const isReload = code === 'reload' if (!isInited && reactData.tableLoading) { return nextTick() } let operPromise = null let sortList: any[] = [] let filterList: VxeTableDefines.FilterCheckedParams[] = [] let pageParams: any = {} if (pagerConfig) { if (isInited || isReload) { // 重置分页 tablePage.currentPage = 1 } if (isEnableConf(pagerOpts)) { pageParams = { ...tablePage } } } if (isInited) { // 重置代理表单数据 if (proxyConfig && isEnableConf(proxyOpts) && proxyOpts.form) { formData = getDefaultFormData() reactData.formData = formData } if ($xeTable) { const tableInternalData = $xeTable.internalData const { tableFullColumn, fullColumnFieldData } = tableInternalData const { computeSortOpts } = $xeTable.getComputeMaps() const sortOpts = computeSortOpts.value let defaultSort = sortOpts.defaultSort tableFullColumn.forEach((column) => { column.order = null }) // 如果使用默认排序 if (defaultSort) { if (!XEUtils.isArray(defaultSort)) { defaultSort = [defaultSort] } sortList = defaultSort.map((item) => { const { field, order } = item const colRest = fullColumnFieldData[field] if (colRest) { const column = colRest.column if (column) { column.order = order } } return { field, property: field, order } }) } filterList = $xeTable.getCheckedFilters() } } else { if ($xeTable) { if (isReload) { operPromise = $xeTable.clearAll() } else { sortList = $xeTable.getSortColumns() filterList = $xeTable.getCheckedFilters() } } } const commitParams = { $table: $xeTable, $grid: null, $gantt: $xeGantt, code, button, isInited, isReload, page: pageParams, sort: sortList.length ? sortList[0] : {}, sorts: sortList, filters: filterList, form: formData, options: qMethods } reactData.sortData = sortList reactData.filterData = filterList reactData.tableLoading = true return Promise.all([ Promise.resolve((beforeQuery || qMethods)(commitParams, ...args)), operPromise ]).then(([rest]) => { let tableData: any[] = [] reactData.tableLoading = false if (rest) { const rePar