diff --git a/packages/vue/src/grid/src/checkbox/src/handleSelectRow.ts b/packages/renderless/src/grid/checkbox/handleSelectRow.ts similarity index 87% rename from packages/vue/src/grid/src/checkbox/src/handleSelectRow.ts rename to packages/renderless/src/grid/checkbox/handleSelectRow.ts index 6797c1c7e7..d09d8f6837 100644 --- a/packages/vue/src/grid/src/checkbox/src/handleSelectRow.ts +++ b/packages/renderless/src/grid/checkbox/handleSelectRow.ts @@ -24,9 +24,22 @@ */ import { eachTree, find, findTree, get, remove, set } from '@opentiny/vue-renderless/grid/static/' +/** + * 处理树形结构数据的半选中状态 + * + * @param {Object} options - 参数对象 + * @param {Boolean} options.checkStrictly - 是否严格检查 + * @param {String} options.property - 属性名 + * @param {Object} options.row - 当前行数据 + * @param {Object} options.treeConfig - 树形结构配置 + * @param {Array} options.treeIndeterminates - 树节点不确定状态的列表 + * @param {Number} options.value - 选中状态值(-1 表示半选中) + */ function onHalfSelectionProperty({ checkStrictly, property, row, treeConfig, treeIndeterminates, value }) { + // 如果属性存在、树形结构配置存在、非严格检查且值为-1,则处理半选中状态 if (property && treeConfig && !checkStrictly && value === -1) { treeIndeterminates.push(row) + // 将当前行数据的指定属性设置为 false set(row, property, false) } } @@ -132,9 +145,12 @@ function getParentStatusOnParentSelection({ indeterminatesItem, matchObj, select } export function hasCheckField({ row }, value, _vm) { - let { tableFullData, selectConfig = {}, treeConfig, treeIndeterminates } = _vm + const { tableFullData, treeIndeterminates } = _vm.state + const selectConfig = _vm.selectConfig || {} + const treeConfig = _vm.treeConfig let { checkField: property, checkStrictly, checkMethod } = selectConfig + // 树表行半选 onHalfSelectionProperty({ checkStrictly, property, @@ -144,6 +160,7 @@ export function hasCheckField({ row }, value, _vm) { value }) + // 树表行全选 onFullSelectionProperty({ checkMethod, checkStrictly, @@ -179,7 +196,8 @@ export function hasCheckField({ row }, value, _vm) { } function onSelectTreeCheckStrictly({ row }, value, _vm) { - let { selection, tableFullData, selectConfig = {}, treeConfig, treeIndeterminates } = _vm + let { selectConfig = {}, treeConfig } = _vm + const { selection, tableFullData, treeIndeterminates } = _vm.state let { checkField: property, checkStrictly, checkMethod } = selectConfig // 树表行半选 onHalfSelection({ @@ -224,7 +242,8 @@ function onSelectTreeCheckStrictly({ row }, value, _vm) { } function onSelectOther({ row }, value, _vm) { - let { selection, selectConfig = {}, treeConfig } = _vm + let { selectConfig = {}, treeConfig } = _vm + const { selection } = _vm.state let { checkField: property, checkStrictly } = selectConfig if (!property && !(treeConfig && !checkStrictly)) { diff --git a/packages/renderless/src/grid/checkbox/index.ts b/packages/renderless/src/grid/checkbox/index.ts new file mode 100644 index 0000000000..157078ed47 --- /dev/null +++ b/packages/renderless/src/grid/checkbox/index.ts @@ -0,0 +1,357 @@ +import { hasCheckField, hasNoCheckField } from './handleSelectRow' +import { hasCheckFieldNoStrictly, hasNoCheckFieldNoStrictly, setSelectionNoStrictly } from './setAllSelection' +import { getTableRowKey } from '../../../../vue/src/grid/src/table/src/strategy' +import { emitEvent } from '../utils' +import { isArray, get, toStringJSON } from '../static' +import { eachTree, find, set, toArray } from '../static' + +// 处理默认勾选 +export const handleSelectionDefChecked = + ({ api, state, props }) => + () => { + let fullDataRowIdData = state.fullDataRowIdData + const checkAll = props.selectConfig && props.selectConfig.checkAll // 初始时是否选中所有行 + const checkRowKeys = props.selectConfig && props.selectConfig.checkRowKeys // 默认勾选开指定行(只会在初始化时被触发一次,需要有 row-id) + + if (checkAll) { + api.setAllSelection(true) + return + } + if (checkRowKeys) { + let defCheckedRowids = checkRowKeys.map((key) => encodeURIComponent(key)) + let defCheckedRows = [] + + defCheckedRowids.forEach((rowid) => { + let rowCache = fullDataRowIdData[rowid] + if (rowCache) { + defCheckedRows.push(rowCache.row) + } + }) + + api.setSelection(defCheckedRows, true) + } + } + +/** + * 设置选中状态 + * + * @param {object} params + * @param {object} params.api - $table API 对象 + * @param {object} params.vm - $table 实例 + * @returns {function} + */ +export const setSelection = + ({ api, vm }) => + (rows, value) => { + // 如果 rows 不为空 + if (rows) { + // 如果 rows 不是数组,则转换为数组 + if (!isArray(rows)) { + rows = [rows] + } + // 遍历 rows,调用 handleSelectRow 方法设置选中状态 + rows.forEach((row) => api.handleSelectRow({ row }, !!value)) + } + return vm.$nextTick() + } + +// 多选,行选中事件。value:选中true、不选false、不确定-1 +export const handleSelectRow = + ({ api, vm }) => + ({ row }, value) => { + hasCheckField({ row }, value, vm) + hasNoCheckField({ row }, value, vm) + api.checkSelectionStatus() + } + +/** + * 多选,行选中状态切换事件 + * + * @param {object} params + * @param {object} params.api - $table API 对象 + * @param {object} params.vm - $table 实例 + * @param {object} params.state - $table 状态对象 + * @param {object} params.props - $table props对象 + * @param {object} params.row - 选中的行对象 + * @param {Event} params.event - 事件对象 + * @returns {function} + */ +export const handleToggleCheckRowEvent = + ({ props, api, state }) => + (params, event) => { + let selection = state.selection + let checkField = props.selectConfig && props.selectConfig.checkField + let { row } = params + let value = checkField ? !get(row, checkField) : !~selection.indexOf(row) + if (event) { + api.triggerCheckRowEvent(event, params, value) + } else { + api.handleSelectRow(params, value) + } + } + +/** + * 多选,行选中事件 + * + * @param {object} params + * @param {object} params.api - $table API 对象 + * @param {object} params.vm - $table 实例 + * @param {object} params.state - $table 状态对象 + * @param {object} params.props - $table props对象 + * @param {object} params.row - 选中的行对象 + * @param {Event} params.event - 事件对象 + * @param {boolean} value - 选中的状态 + * @returns {function} + */ +export const triggerCheckRowEvent = + ({ props, api, vm }) => + (event, params, value) => { + const selectConfig = props.selectConfig || {} + let { checkMethod } = selectConfig + if (!checkMethod || checkMethod(params)) { + api.handleSelectRow(params, value) + emitEvent(vm, 'select-change', [ + { + selection: api.getSelectRecords(), + checked: value, + $table: vm, + ...params + }, + event + ]) + } + } + +// 多选,切换某一行的选中状态 +export const toggleRowSelection = + ({ api, vm }) => + (row) => { + api.handleToggleCheckRowEvent({ row }) + return vm.$nextTick() + } + +export const setAllSelection = + ({ state, props, api, vm }) => + (value) => { + const selection = state.selection + const { afterFullData } = state + const selectConfig = props.selectConfig || {} + const treeConfig = props.treeConfig || {} + let { checkField: property, reserve, checkStrictly, checkMethod } = selectConfig + hasCheckFieldNoStrictly({ afterFullData, checkMethod, checkStrictly, property, selection, treeConfig, value }) + let selectRows = hasNoCheckFieldNoStrictly({ + afterFullData, + checkMethod, + checkStrictly, + property, + selection, + treeConfig, + value + }) + // 选中每一行 + setSelectionNoStrictly({ _vm: vm, checkStrictly, reserve, selectRows, selection, value, afterFullData }) + api.treeIndeterminates = [] + // 变换表头选中状态为全选 + api.checkSelectionStatus() + } + +export const checkSelectionStatus = + ({ state, props }) => + () => { + let { afterFullData, selection, treeIndeterminates } = state + let { checkField, checkStrictly, checkMethod } = props.selectConfig || {} + let { everyHandler, someHandler } = {} + if (checkStrictly) { + return + } + // 包含新增的数据 + if (checkField) { + everyHandler = checkMethod + ? (row, rowIndex) => !checkMethod({ row, rowIndex }) || get(row, checkField) + : (row) => get(row, checkField) + someHandler = (row) => get(row, checkField) || ~treeIndeterminates.indexOf(row) + state.isAllSelected = false + afterFullData.length && (state.isAllSelected = afterFullData.every(everyHandler)) + state.isIndeterminate = !state.isAllSelected && afterFullData.some(someHandler) + } else { + everyHandler = (row, rowIndex) => !checkMethod({ row, rowIndex }) + state.headerCheckDisabled = checkMethod && afterFullData.length && afterFullData.every(everyHandler) + everyHandler = checkMethod + ? (row, rowIndex) => !checkMethod({ row, rowIndex }) || ~selection.indexOf(row) + : (row) => ~selection.indexOf(row) + someHandler = (row) => ~treeIndeterminates.indexOf(row) || ~selection.indexOf(row) + state.isAllSelected = false + afterFullData.length && (state.isAllSelected = afterFullData.every(everyHandler)) + state.isIndeterminate = !state.isAllSelected && afterFullData.some(someHandler) + } + } + +// 保留选中状态 +export const reserveCheckSelection = + ({ state, props, vm }) => + () => { + let { fullDataRowIdData, selection } = state + let { reserve } = props.selectConfig || {} + let rowkey = getTableRowKey(vm) + if (reserve && selection.length) { + state.selection = selection.map((row) => { + let rowCache = fullDataRowIdData[`${get(row, rowkey)}`] + return rowCache ? rowCache.row : row + }) + } + } + +// 多选,选中所有事件 +export const triggerCheckAllEvent = + ({ api, vm }) => + (event, value) => { + api.setAllSelection(value) + let eventParams = { + selection: api.getSelectRecords(), + checked: value, + $table: vm + } + emitEvent(vm, 'select-all', [eventParams, event]) + } + +// 多选,切换所有行的选中状态 +export const toggleAllSelection = + ({ api, state, vm }) => + () => { + api.triggerCheckAllEvent(null, !state.isAllSelected) + return vm.$nextTick() + } + +export const clearSelection = + ({ state, props, vm }) => + () => { + const tableFullData = state.afterFullData + const treeConfig = props.treeConfig + let { checkField } = props.selectConfig || {} + if (checkField) { + treeConfig + ? eachTree(tableFullData, (item) => set(item, checkField, false), treeConfig) + : tableFullData.forEach((item) => set(item, checkField, false)) + } + Object.assign(state, { + isAllSelected: false, + isIndeterminate: false, + selection: [], + treeIndeterminates: [] + }) + + return vm.$nextTick() + } + +export const initMultipleHistory = + ({ vm, api }) => + () => { + const { isMultipleHistory } = vm.$grid + const toolbarVm = api.getVm('toolbar') + const { + settingOpts: { storageKey }, + id: toolbarId + } = toolbarVm + let remoteSelectedMethod = toolbarVm.setting.multipleHistory.remoteSelectedMethod + let remoteSelectedPromise + + if ( + isMultipleHistory && + toolbarVm && + toolbarVm.setting && + toolbarVm.setting.multipleHistory && + remoteSelectedMethod + ) { + if (typeof remoteSelectedMethod === 'function') { + remoteSelectedPromise = remoteSelectedMethod() + + if (typeof remoteSelectedPromise.then === 'function') { + remoteSelectedPromise.then((storeStr) => { + let storeObj = toStringJSON(storeStr) + storeObj = (storeObj && storeObj[storageKey]) || null + storeObj = (storeObj || {})[toolbarId] || {} + const { columns, pageSize } = storeObj + toolbarVm.applySettings({ columns, pageSize }) + }) + } + } + } + } + +// 显示多选工具栏 +export const showSelectToolbar = + ({ state, vm, api }) => + () => { + const { + $grid: { selectToolbar, showHeader } + } = vm + let { selectToolbarStore } = state + if (selectToolbar && showHeader) { + selectToolbarStore.visible = false + let selectColumn = find(state.visibleColumn, (item) => item.type === 'selection') + let selected = api.getSelectRecords() + let position = typeof selectToolbar === 'object' ? selectToolbar.position : '' + if (selectColumn && selected && selected.length) { + let selectTh = vm.$el.querySelector('th.tiny-grid-header__column.col__selection') + let headerWrapper = vm.$el.querySelector('.tiny-grid>.tiny-grid__header-wrapper') + let tr = selectTh.parentNode + let thArr = toArray(tr.childNodes) + let range = document.createRange() + let rangeBoundingRect + let headerBoundingRect = headerWrapper.getBoundingClientRect() + let layout = { width: 0, height: 0, left: 0, top: 0, zIndex: 1 } + let adjust = 1 + if (selectColumn.fixed === 'right') { + range.setStart(tr, thArr.indexOf(selectTh)) + range.setEnd(tr, thArr.length) + rangeBoundingRect = range.getBoundingClientRect() + layout.left = `${adjust}px` + } else { + range.setStart(tr, 0) + range.setEnd(tr, thArr.indexOf(selectTh) + 1) + rangeBoundingRect = range.getBoundingClientRect() + layout.left = `${rangeBoundingRect.width + adjust}px` + } + layout.width = `${headerBoundingRect.width - rangeBoundingRect.width - 2 * adjust}px` + if (!selectColumn.fixed && position === 'left') { + range = document.createRange() + range.setStart(tr, 0) + range.setEnd(tr, thArr.indexOf(selectTh)) + rangeBoundingRect = range.getBoundingClientRect() + layout.left = `${adjust}px` + layout.width = `${rangeBoundingRect.width - 2 * adjust}px` + } + layout.top = `${headerBoundingRect.height - rangeBoundingRect.height + adjust}px` + layout.height = `${rangeBoundingRect.height - 2 * adjust}px` + return vm.$nextTick().then(() => { + selectToolbarStore.layout = layout + selectToolbarStore.visible = true + }) + } + } + return vm.$nextTick() + } +// 切换多选工具栏的显示 +export const toggleSelectToolbarVisible = + ({ state, vm }) => + () => { + state.selectToolbarStore.visible = !state.selectToolbarStore.visible + return vm.$nextTick() + } + +// 在空数据时Selection列表头复选框禁用,headerAutoDisabled设置为false就会和旧版本兼容 +export const handleSelectionHeader = + ({ state, props }) => + () => { + const { tableFullData, visibleColumn } = state + const selectConfig = props.selectConfig || {} + const { headerAutoDisabled } = selectConfig + const selectionColumn = visibleColumn.find((column) => column.type === 'selection') + if ( + (typeof headerAutoDisabled === 'undefined' || (typeof headerAutoDisabled === 'boolean' && headerAutoDisabled)) && + !tableFullData.length && + selectionColumn + ) { + state.headerCheckDisabled = true + } + } diff --git a/packages/vue/src/grid/src/checkbox/src/setAllSelection.ts b/packages/renderless/src/grid/checkbox/setAllSelection.ts similarity index 98% rename from packages/vue/src/grid/src/checkbox/src/setAllSelection.ts rename to packages/renderless/src/grid/checkbox/setAllSelection.ts index 4be08ec223..fdf7d89501 100644 --- a/packages/vue/src/grid/src/checkbox/src/setAllSelection.ts +++ b/packages/renderless/src/grid/checkbox/setAllSelection.ts @@ -151,11 +151,11 @@ export function setSelectionNoStrictly({ _vm, checkStrictly, reserve, selectRows if (reserve) { // 配置了reserve为true时,只需把当前页没选中部分清除 const unCheckedRows = afterFullData.filter((row) => !selectRows.includes(row)) - _vm.selection = value + _vm.state.selection = value ? selection.concat(selectRows.filter((row) => !selection.includes(row))) : selection.filter((row) => !unCheckedRows.includes(row)) } else { - _vm.selection = selectRows + _vm.state.selection = selectRows } } } diff --git a/packages/renderless/src/grid/checkbox/vue.ts b/packages/renderless/src/grid/checkbox/vue.ts new file mode 100644 index 0000000000..af4937401a --- /dev/null +++ b/packages/renderless/src/grid/checkbox/vue.ts @@ -0,0 +1,39 @@ +import { + checkSelectionStatus, + clearSelection, + handleSelectionDefChecked, + handleSelectionHeader, + handleSelectRow, + handleToggleCheckRowEvent, + initMultipleHistory, + reserveCheckSelection, + setAllSelection, + setSelection, + showSelectToolbar, + toggleAllSelection, + toggleRowSelection, + toggleSelectToolbarVisible, + triggerCheckAllEvent, + triggerCheckRowEvent +} from './index' + +export const installCheckbox = ({ api, state, props, vm }) => { + return { + handleSelectionDefChecked: handleSelectionDefChecked({ api, state, props }), + setSelection: setSelection({ api, vm }), + handleSelectRow: handleSelectRow({ api, vm }), + handleToggleCheckRowEvent: handleToggleCheckRowEvent({ props, api, state }), + triggerCheckRowEvent: triggerCheckRowEvent({ props, api, vm }), + triggerCheckAllEvent: triggerCheckAllEvent({ api, vm }), + toggleRowSelection: toggleRowSelection({ api, vm }), + setAllSelection: setAllSelection({ api, state, props, vm }), + checkSelectionStatus: checkSelectionStatus({ state, props }), + clearSelection: clearSelection({ state, props, vm }), + initMultipleHistory: initMultipleHistory({ api, vm }), + showSelectToolbar: showSelectToolbar({ api, state, vm }), + toggleSelectToolbarVisible: toggleSelectToolbarVisible({ vm, state }), + handleSelectionHeader: handleSelectionHeader({ state, props }), + reserveCheckSelection: reserveCheckSelection({ state, props, vm }), + toggleAllSelection: toggleAllSelection({ api, state, vm }) + } +} diff --git a/packages/renderless/src/grid/table/index.ts b/packages/renderless/src/grid/table/index.ts new file mode 100644 index 0000000000..9f4c404a77 --- /dev/null +++ b/packages/renderless/src/grid/table/index.ts @@ -0,0 +1,240 @@ +import { isEmptyObject, isObject } from '../../common/type' +import { hasChildrenList } from '../utils' +import GlobalConfig from '../../../../vue/src/grid/src/config' +import { extend } from '../../../common/object' + +/** + * some utils + */ +const run = (names, $table) => names.forEach((name) => $table[name].apply($table)) + +/** + * computed state + */ + +export const computedCtxMenuOpts = + ({ props }) => + () => + extend(true, {}, GlobalConfig.menu, props.contextMenu) + +export const computedBodyCtxMenu = + ({ state }) => + () => { + return state.ctxMenuOpts.body && state.ctxMenuOpts.body.options ? state.ctxMenuOpts.body.options : [] + } + +export const computedCtxMenuList = + ({ state }) => + () => { + let rest = [] + state.ctxMenuStore.list.forEach((list) => list.forEach((item) => rest.push(item))) + return rest + } + +export const computedHasFilter = + ({ state }) => + () => + state.tableColumn.some((column) => isObject(column.filter) && !isEmptyObject(column.filter)) + +export const computedHeaderCtxMenu = + ({ state }) => + () => + state.ctxMenuOpts.header && state.ctxMenuOpts.header.options ? state.ctxMenuOpts.header.options : [] + +export const computedIsCtxMenu = + ({ state }) => + () => + state.headerCtxMenu.length || state.bodyCtxMenu.length + +export const computedIsGroup = (state) => () => state.collectColumn.some((column) => hasChildrenList(column)) + +export const computedIsResizable = + ({ state, props }) => + () => + props.resizable || state.tableFullColumn.some((column) => column.resizable) + +export const computedOptimizeOpts = + ({ props }) => + () => + extend(true, {}, GlobalConfig.sortConfig, props.sortConfig) + +export const computedSortOpts = + ({ props }) => + () => + extend(true, {}, GlobalConfig.sortConfig, props.sortConfig) + +export const computedTooltipContentOpts = + ({ state, props }) => + () => { + return extend( + true, + { + content: props.tooltipContent, + pre: state.tooltipContentPre, // pre 元素可定义预格式化的文本 + placement: 'right', + type: props.tooltipConfig.effect ? undefined : 'normal' + }, + props.tooltipConfig + ) + } + +export const computedVSize = + ({ props, vm }) => + () => + props.size || (vm.$parent && vm.$parent.size) || (vm.$parent && vm.$parent.vSize) + +export const computedVaildTipOpts = + ({ sate, props }) => + () => { + return extend( + true, + { + isArrow: false, + placement: 'top', + type: 'error', + content: sate.validTipContent + }, + props.tooltipConfig + ) + } + +export const computedValidOpts = + ({ props, vm }) => + () => { + const config = Object.assign( + { message: 'tooltip' }, + GlobalConfig.validConfig, + vm.$grid?.designConfig?.validConfig, + props.validConfig + ) + + config.isMessageTooltip = config.message === 'tooltip' + config.isMessageDefault = config.message === 'default' + config.isMessageInline = config.message === 'inline' + + return config + } + +export const computedTableBodyHeight = + ({ state }) => + () => + state.tableBodyHeight === 0 ? 'calc(100% - 36px)' : `${state.tableBodyHeight}px` + +// TODO:修改 +export const computedIsThemeTiny = + ({ state }) => + () => + state.tinyTheme === 'tiny' + +export const computedIsThemeSaas = + ({ state }) => + () => + state.tinyTheme === 'saas' +export const computedIsViewDefault = + ({ props }) => + () => + props.view === 'default' + +export const computedIsShapeTable = + ({ state, props, vm }) => + () => + // 表格处于默认视图或mf视图大屏时显示为普通表格;其它视图都显示为多端形式 + state.isViewDefault || (props.viewType === V_MF && vm.$grid.currentBreakpoint !== 'default') + +export const computedColumnNames = + ({ props }) => + () => { + const customColumnNames = props.customColumnNames + const columnNames = [GlobalConfig.defaultColumnName] + + const pushIfNot = (columnName) => { + if (typeof columnName === 'string' && !columnNames.includes(columnName)) { + columnNames.push(columnName) + } + } + + if (Array.isArray(customColumnNames) && customColumnNames.length > 0) { + customColumnNames.forEach(pushIfNot) + } else if (typeof customColumnNames === 'string') { + pushIfNot(customColumnNames) + } + + return columnNames + } + +/** + * Component Methods + */ +export const getParentElem = + ({ vm }) => + () => { + const $el = vm.$grid ? vm.$grid.$el : vm.$el + return $el.parentNode + } + +// TODO:修改 +export const updateParentHeight = + ({ state, vm, api }) => + () => { + if (vm.$grid) { + vm.$grid.updateParentHeight() + } else { + state.parentHeight = api.getParentElem().clientHeight + } + } + +export const getParentHeight = + ({ state }) => + () => { + return state.parentHeight + } + +// TODO:修改 +export const clearAll = + ({ state, vm }) => + (silent) => { + const { fetchOption = {} } = vm.$grid + const { isReloadFilter } = fetchOption + + run(['clearScroll', 'clearSort', 'clearCurrentRow', 'clearCurrentColumn'], this) + run(['clearSelection', 'clearRowExpand', 'clearTreeExpand'], this) + + if (typeof isReloadFilter === 'undefined' ? TINYGrid._filter : !isReloadFilter) { + vm.clearFilter(silent) + } + + if (state.keyboardConfig || state.mouseConfig) { + run(['clearIndexChecked', 'clearHeaderChecked', 'clearChecked', 'clearSelected', 'clearCopyed'], this) + } + + return vm.clearActived() + } + +export const refreshData = + ({ state, api, vm }) => + (data) => { + const next = () => { + state.tableData = [] + return api.loadTableData(data || state.tableFullData) + } + return vm.$nextTick().then(next) + } + +export const refreshStyle = + ({ props, el, vm }) => + () => { + const $el = el + const rowSpan = props.rowSpan + const spanMethod = props.spanMethod + // 存在合并时才刷新样式 + if ($el && (rowSpan || spanMethod)) { + let transform = $el.style.transform + let restore = () => + setTimeout(() => { + $el.style.transform = transform + }) + $el.style.transform = 'scale(0.99999)' + return vm.$nextTick().then(restore) + } + return vm.$nextTick() + } diff --git a/packages/renderless/src/grid/table/vue.ts b/packages/renderless/src/grid/table/vue.ts new file mode 100644 index 0000000000..6283e6d3d1 --- /dev/null +++ b/packages/renderless/src/grid/table/vue.ts @@ -0,0 +1,137 @@ +import type { ISharedRenderlessParamHooks } from '@/types' +import GlobalConfig from '../../../../vue/src/grid/src/config' +import { extend } from '../../../common/object' + +export const api = ['state', 'scrollEvent'] + +const initState = ({ reactive, computed, props }) => { + return reactive({ + // 存储异步加载过的行\列数据 + asyncRenderMap: {}, + // 存放列相关的信息 + columnStore: { + // 自适应的列表集合 + autoList: [], + centerList: [], + // 左侧冻结列表集合 + leftList: [], + // 右侧冻结列表集合 + rightList: [], + // 固定像素宽度列表集合 + pxList: [], + // 设置了最小宽度列表集合 + pxMinList: [], + // 可调整列宽列表集合 + resizeList: [], + // 百分比宽度列表集合 + scaleList: [], + // 百分比最小宽度列表集合 + scaleMinList: [] + }, + // 存放快捷菜单的信息 + ctxMenuStore: { + list: [], + selectChild: null, + selected: null, + showChild: false, + style: null, + visible: false + }, + // 当前行 + currentRow: null, + // 存放可编辑相关信息 + editStore: { + editorAutoRefreshKey: 0, + // 激活 + actived: { column: null, row: null }, + // 所有选中 + checked: { columns: [], rows: [], tColumns: [], tRows: [] }, + // 已复制源 + copyed: { columns: [], cut: false, rows: [] }, + indexs: { columns: [] }, + insertList: [], + removeList: [], + // 选中源 + selected: { column: null, row: null }, + titles: { columns: [] } + }, + // 已展开的行 + expandeds: [], + // 当前选中的筛选列 + filterStore: { + column: null, + condition: { input: '', relation: 'equals' }, + id: '', + multi: false, + options: [], + visible: false + }, + // 表尾合计数据 + footerData: [], + // 所有列已禁用 + headerCheckDisabled: false, + // 是否全选 + isAllSelected: false, + // 多选属性,有选中且非全选状态 + isIndeterminate: false, + // 是否存在横向滚动条 + overflowX: false, + // 是否存在纵向滚动条 + overflowY: true, + // 存储滚动加载,上次滚动的位置 + scrollLoadStore: { bodyHeight: 0, scrollHeight: 0 }, + // 是否启用了横向 X 可视渲染方式加载 + scrollXLoad: false, + // 是否启用了纵向 Y 可视渲染方式加载 + scrollYLoad: false, + // 横向滚动条的高度 + scrollbarHeight: 0, + // 纵向滚动条的宽度 + scrollbarWidth: 0, + // 单选属性,选中行 + selectRow: null, + // 存放多选工具栏相关信息 + selectToolbarStore: { + layout: { height: 0, left: 0, top: 0, width: 0, zIndex: 1 }, + visible: false + }, + // 多选属性,已选中的列 + selection: [], + // 渲染中的数据 + tableData: [], + // tooltip提示内容 + tooltipContent: '', + // tooltip提示内容是否处理换行字符 + tooltipContentPre: false, + // 已展开树节点 + treeExpandeds: [], + // 树节点不确定状态的列表 + treeIndeterminates: [], + // 存放数据校验相关信息 + validStore: { + column: null, + content: '', + isArrow: false, + row: null, + rule: null, + visible: false + }, + // 校验tip提示内容 + validTipContent: '', + // 在编辑模式下 单元格在失去焦点验证的状态 + validatedMap: {}, + // 表尾边框线是否显示和位置 + showFooterBorder: false, + footerBorderBottom: 0, + tableBodyHeight: 0, + // 表格父容器的高度 + parentHeight: 0, + ctxMenuOpts: computed(() => extend(true, {}, GlobalConfig.menu, props.contextMenu)), + hasTip: computed(() => TINYGrid._tooltip) + }) +} + +export const renderless = (props, context: ISharedRenderlessParamHooks, { vm }): any => { + const api = {} as any + return api +} diff --git a/packages/vue/src/grid/src/checkbox/index.ts b/packages/vue/src/grid/src/checkbox/index.ts deleted file mode 100644 index ad8f9d35b9..0000000000 --- a/packages/vue/src/grid/src/checkbox/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2022 - present TinyVue Authors. - * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. - * - * Use of this source code is governed by an MIT-style license. - * - * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, - * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR - * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - * - */ -import Methods from './src/methods' - -export default { - host: 'table', - install(host) { - Object.assign(host.methods, Methods) - } -} diff --git a/packages/vue/src/grid/src/checkbox/src/methods.ts b/packages/vue/src/grid/src/checkbox/src/methods.ts deleted file mode 100644 index cc7f0d6c08..0000000000 --- a/packages/vue/src/grid/src/checkbox/src/methods.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { hasCheckField, hasNoCheckField } from './handleSelectRow' -import { hasCheckFieldNoStrictly, hasNoCheckFieldNoStrictly, setSelectionNoStrictly } from './setAllSelection' -import { getTableRowKey } from '../../table/src/strategy' -import { emitEvent } from '@opentiny/vue-renderless/grid/utils' -import { isArray, set, get, eachTree, find, toStringJSON, toArray } from '@opentiny/vue-renderless/grid/static/' - -export default { - // 处理默认勾选 - handleSelectionDefChecked() { - let fullDataRowIdData = this.fullDataRowIdData - let { checkAll, checkRowKeys } = this.selectConfig || {} - - if (checkAll) { - this.setAllSelection(true) - return - } - if (checkRowKeys) { - let defCheckedRowids = checkRowKeys.map((key) => encodeURIComponent(key)) - let defCheckedRows = [] - - defCheckedRowids.forEach((rowid) => { - let rowCache = fullDataRowIdData[rowid] - if (rowCache) { - defCheckedRows.push(rowCache.row) - } - }) - - this.setSelection(defCheckedRows, true) - } - }, - setSelection(rows, value) { - if (rows) { - if (!isArray(rows)) { - rows = [rows] - } - rows.forEach((row) => this.handleSelectRow({ row }, !!value)) - } - return this.$nextTick() - }, - // 多选,行选中事件。value:选中true、不选false、不确定-1 - handleSelectRow({ row }, value) { - hasCheckField({ row }, value, this) - hasNoCheckField({ row }, value, this) - this.checkSelectionStatus() - }, - handleToggleCheckRowEvent(params, event) { - let selection = this.selection - let { checkField } = this.selectConfig || {} - let { row } = params - let value = checkField ? !get(row, checkField) : !~selection.indexOf(row) - if (event) { - this.triggerCheckRowEvent(event, params, value) - } else { - this.handleSelectRow(params, value) - } - }, - triggerCheckRowEvent(event, params, value) { - let { selectConfig = {} } = this - let { checkMethod } = selectConfig - if (!checkMethod || checkMethod(params)) { - this.handleSelectRow(params, value) - emitEvent(this, 'select-change', [ - { - selection: this.getSelectRecords(), - checked: value, - $table: this, - ...params - }, - event - ]) - } - }, - // 多选,切换某一行的选中状态 - toggleRowSelection(row) { - this.handleToggleCheckRowEvent({ row }) - return this.$nextTick() - }, - setAllSelection(value) { - let { afterFullData, selectConfig = {}, treeConfig, selection } = this - let { checkField: property, reserve, checkStrictly, checkMethod } = selectConfig - hasCheckFieldNoStrictly({ afterFullData, checkMethod, checkStrictly, property, selection, treeConfig, value }) - let selectRows = hasNoCheckFieldNoStrictly({ - afterFullData, - checkMethod, - checkStrictly, - property, - selection, - treeConfig, - value - }) - setSelectionNoStrictly({ _vm: this, checkStrictly, reserve, selectRows, selection, value, afterFullData }) - this.treeIndeterminates = [] - this.checkSelectionStatus() - }, - checkSelectionStatus() { - let { afterFullData, selection, treeIndeterminates } = this - let { checkField, checkStrictly, checkMethod } = this.selectConfig || {} - let { everyHandler, someHandler } = {} - if (checkStrictly) { - return - } - // 包含新增的数据 - if (checkField) { - everyHandler = checkMethod - ? (row, rowIndex) => !checkMethod({ row, rowIndex }) || get(row, checkField) - : (row) => get(row, checkField) - someHandler = (row) => get(row, checkField) || ~treeIndeterminates.indexOf(row) - this.isAllSelected = false - afterFullData.length && (this.isAllSelected = afterFullData.every(everyHandler)) - this.isIndeterminate = !this.isAllSelected && afterFullData.some(someHandler) - } else { - everyHandler = (row, rowIndex) => !checkMethod({ row, rowIndex }) - this.headerCheckDisabled = checkMethod && afterFullData.length && afterFullData.every(everyHandler) - everyHandler = checkMethod - ? (row, rowIndex) => !checkMethod({ row, rowIndex }) || ~selection.indexOf(row) - : (row) => ~selection.indexOf(row) - someHandler = (row) => ~treeIndeterminates.indexOf(row) || ~selection.indexOf(row) - this.isAllSelected = false - afterFullData.length && (this.isAllSelected = afterFullData.every(everyHandler)) - this.isIndeterminate = !this.isAllSelected && afterFullData.some(someHandler) - } - }, - // 保留选中状态 - reserveCheckSelection() { - let { fullDataRowIdData, selection } = this - let { reserve } = this.selectConfig || {} - let rowkey = getTableRowKey(this) - if (reserve && selection.length) { - this.selection = selection.map((row) => { - let rowCache = fullDataRowIdData[`${get(row, rowkey)}`] - return rowCache ? rowCache.row : row - }) - } - }, - // 多选,选中所有事件 - triggerCheckAllEvent(event, value) { - this.setAllSelection(value) - let eventParams = { - selection: this.getSelectRecords(), - checked: value, - $table: this - } - emitEvent(this, 'select-all', [eventParams, event]) - }, - // 多选,切换所有行的选中状态 - toggleAllSelection() { - this.triggerCheckAllEvent(null, !this.isAllSelected) - return this.$nextTick() - }, - clearSelection() { - let { tableFullData, treeConfig } = this - let { checkField } = this.selectConfig || {} - if (checkField) { - treeConfig - ? eachTree(tableFullData, (item) => set(item, checkField, false), treeConfig) - : tableFullData.forEach((item) => set(item, checkField, false)) - } - Object.assign(this, { - isAllSelected: false, - isIndeterminate: false, - selection: [], - treeIndeterminates: [] - }) - - return this.$nextTick() - }, - initMultipleHistory() { - const { isMultipleHistory } = this.$grid - const toolbarVm = this.getVm('toolbar') - const { - settingOpts: { storageKey }, - id: toolbarId - } = toolbarVm - let remoteSelectedMethod = toolbarVm.setting.multipleHistory.remoteSelectedMethod - let remoteSelectedPromise - - if ( - isMultipleHistory && - toolbarVm && - toolbarVm.setting && - toolbarVm.setting.multipleHistory && - remoteSelectedMethod - ) { - if (typeof remoteSelectedMethod === 'function') { - remoteSelectedPromise = remoteSelectedMethod() - - if (typeof remoteSelectedPromise.then === 'function') { - remoteSelectedPromise.then((storeStr) => { - let storeObj = toStringJSON(storeStr) - storeObj = (storeObj && storeObj[storageKey]) || null - storeObj = (storeObj || {})[toolbarId] || {} - const { columns, pageSize } = storeObj - toolbarVm.applySettings({ columns, pageSize }) - }) - } - } - } - }, - // 显示多选工具栏 - showSelectToolbar() { - let { - $grid: { selectToolbar, showHeader }, - selectToolbarStore - } = this - if (selectToolbar && showHeader) { - selectToolbarStore.visible = false - let selectColumn = find(this.visibleColumn, (item) => item.type === 'selection') - let selected = this.getSelectRecords() - let position = typeof selectToolbar === 'object' ? selectToolbar.position : '' - if (selectColumn && selected && selected.length) { - let selectTh = this.$el.querySelector('th.tiny-grid-header__column.col__selection') - let headerWrapper = this.$el.querySelector('.tiny-grid>.tiny-grid__header-wrapper') - let tr = selectTh.parentNode - let thArr = toArray(tr.childNodes) - let range = document.createRange() - let rangeBoundingRect - let headerBoundingRect = headerWrapper.getBoundingClientRect() - let layout = { width: 0, height: 0, left: 0, top: 0, zIndex: 1 } - let adjust = 1 - if (selectColumn.fixed === 'right') { - range.setStart(tr, thArr.indexOf(selectTh)) - range.setEnd(tr, thArr.length) - rangeBoundingRect = range.getBoundingClientRect() - layout.left = `${adjust}px` - } else { - range.setStart(tr, 0) - range.setEnd(tr, thArr.indexOf(selectTh) + 1) - rangeBoundingRect = range.getBoundingClientRect() - layout.left = `${rangeBoundingRect.width + adjust}px` - } - layout.width = `${headerBoundingRect.width - rangeBoundingRect.width - 2 * adjust}px` - if (!selectColumn.fixed && position === 'left') { - range = document.createRange() - range.setStart(tr, 0) - range.setEnd(tr, thArr.indexOf(selectTh)) - rangeBoundingRect = range.getBoundingClientRect() - layout.left = `${adjust}px` - layout.width = `${rangeBoundingRect.width - 2 * adjust}px` - } - layout.top = `${headerBoundingRect.height - rangeBoundingRect.height + adjust}px` - layout.height = `${rangeBoundingRect.height - 2 * adjust}px` - return this.$nextTick().then(() => { - selectToolbarStore.layout = layout - selectToolbarStore.visible = true - }) - } - } - return this.$nextTick() - }, - // 切换多选工具栏的显示 - toggleSelectToolbarVisible() { - this.selectToolbarStore.visible = !this.selectToolbarStore.visible - return this.$nextTick() - }, - // 在空数据时Selection列表头复选框禁用,headerAutoDisabled设置为false就会和旧版本兼容 - handleSelectionHeader() { - const { tableFullData, visibleColumn, selectConfig = {} } = this - const { headerAutoDisabled } = selectConfig - const selectionColumn = visibleColumn.find((column) => column.type === 'selection') - if ( - (typeof headerAutoDisabled === 'undefined' || (typeof headerAutoDisabled === 'boolean' && headerAutoDisabled)) && - !tableFullData.length && - selectionColumn - ) { - this.headerCheckDisabled = true - } - } -} diff --git a/packages/vue/src/grid/src/table/src/pc.vue b/packages/vue/src/grid/src/table/src/pc.vue new file mode 100644 index 0000000000..2d85312856 --- /dev/null +++ b/packages/vue/src/grid/src/table/src/pc.vue @@ -0,0 +1,1003 @@ +