UNPKG

@opensig/opendesign

Version:

652 lines (651 loc) 31.6 kB
"use strict"; const vue = require("vue"); const core = require("@vueuse/core"); const is = require("../_utils/is.js"); const dom = require("../_utils/dom.js"); require("../hooks/use-theme.js"); require("../_utils/global.js"); const vueUtils = require("../_utils/vue-utils.js"); const onResize = require("../directives/on-resize.js"); const helper = require("../_utils/helper.js"); const icons = require("../_utils/icons.js"); const index = require("../scrollbar/index.js"); const index$1 = require("../checkbox/index.js"); const index$2 = require("../popover/index.js"); require("../table/index.js"); const useTableCommon = require("../table/useTableCommon.js"); const types = require("./types.js"); const utils = require("./utils.js"); const TableColGroup_vue_vue_type_script_setup_true_lang = require("./TableColGroup.vue.js"); const TableRow_vue_vue_type_script_setup_true_lang = require("./TableRow.vue.js"); const TableColumnFilter_vue_vue_type_script_setup_true_lang = require("./TableColumnFilter.vue.js"); const TableColumnSorter_vue_vue_type_script_setup_true_lang = require("./TableColumnSorter.vue.js"); const provide = require("./provide.js"); const useDataColumn = require("./use-data-column.js"); const useTableMeta = require("../table/useTableMeta.js"); const _hoisted_1 = { key: 0, class: "o-data-table-header-divider-h" }; const _hoisted_2 = { key: 1, class: "o-data-table-left-shadow" }; const _hoisted_3 = ["colspan", "rowspan", "data-cell-index"]; const _hoisted_4 = { class: "o-table-cell__inner" }; const _hoisted_5 = { key: 1, class: "o-table-row-icon-placeholder" }; const _hoisted_6 = { class: "o-table-cell__inner-content" }; const _hoisted_7 = ["onMousedown"]; const _hoisted_8 = { key: 0, class: "o-table-column-resizer__indicator" }; const _hoisted_9 = { key: 0, class: "empty-placeholder" }; const _hoisted_10 = { key: 2, class: "o-table-loading-wrap" }; const _hoisted_11 = { class: "o-table-loading-label" }; const _hoisted_12 = { key: 3, class: "o-table-tip-wrap" }; const _hoisted_13 = { class: "o-table-empty-label" }; const _hoisted_14 = { key: 4, class: "o-data-table-right-shadow" }; const _sfc_main = /* @__PURE__ */ vue.defineComponent({ __name: "ODataTable", props: /* @__PURE__ */ vue.mergeModels(types.dataTableProps, { "expanded-row-keys": { default: () => vue.reactive([]) }, "expanded-row-keysModifiers": {}, "conditions": { /** * @important 兜底如果外面没有传值的情况 */ default: () => vue.reactive({}) }, "conditionsModifiers": {}, "sortSequence": { /** * @important 兜底如果外面没有传值的情况 */ default: () => vue.reactive([]) }, "sortSequenceModifiers": {}, "selectedKeys": { default: () => vue.reactive([]) }, "selectedKeysModifiers": {} }), emits: /* @__PURE__ */ vue.mergeModels(["condition-update", "sort-update", "update:selected-keys", "selection", "selection-change", "selection-all", "load-children", "column-resize"], ["update:expanded-row-keys", "update:conditions", "update:sortSequence", "update:selectedKeys"]), setup(__props, { expose: __expose, emit: __emit }) { const props = __props; const emits = __emit; const slots = vue.useSlots(); const tdSlotNames = vue.computed(() => Object.keys(slots).filter((name) => name.startsWith("td_"))); const rootRef = vue.ref(); const { width: containerBoundingWidth } = core.useElementBounding(rootRef); const containerWidth = core.refDebounced( vue.computed(() => { var _a; void containerBoundingWidth.value; return ((_a = rootRef.value) == null ? void 0 : _a.clientWidth) ?? 0; }) ); const headerRef = vue.ref(); const { height: headerTableHeight } = core.useElementBounding(headerRef); const tableTextSize = core.useCssVar("--table-text-size", headerRef); const tableTextHeight = core.useCssVar("--table-text-height", headerRef); const tableEl = vue.ref(); const overflowState = vue.ref(); const checkTableOverflow = helper.debounceRAF(() => { if (!tableEl.value) { return; } overflowState.value = dom.checkElementOverflow({ element: tableEl.value, parentElement: rootRef.value, // 由于右固定列与前一列边框重合,宽容两个边框宽度 threshold: Number.parseFloat(dom.getCssVariable("--table-border-width", rootRef.value)) * 2 }); }); const getRowKey = (row, rowIndex) => { if (is.isFunction(props.rowKey)) { return props.rowKey(row) ?? rowIndex; } return helper.getValueByPath(row, props.rowKey) ?? rowIndex; }; const { emptyLabel, loadingLabel, borderClass, handleMouseOver, clearHighlight, handleTouchStart } = useTableCommon.useTableCommon({ ...vue.toRefs(props), tableEl }); const { dataColumnMap, dataColumns, groupColumns, isBodyCellRemoved, isLastLeftFixedCell, isFirstRightFixedCell, hasLeftFixedColumn, hasRightFixedColumn, handleColumnResizerMousedown, resizingColumnKey } = useDataColumn.useDataColumn({ ...vue.toRefs(props), tableEl, containerWidth }); const setThRef = (el, column) => { if (!el) { return; } column.thRef = vue.markRaw(el); }; const expandedRowKeys = vue.useModel(__props, "expanded-row-keys"); const hasExpandSlot = vue.computed(() => !!slots.expand); const isLevelExpandable = vue.computed(() => utils.getIsLevelExpandable({ list: props.data, hasExpandSlot, expandMethod: props.expandMethod })); const conditions = vue.useModel(__props, "conditions"); const sortSequence = vue.useModel(__props, "sortSequence"); const getTableFilterValue = (key) => { return helper.getValueByPath(conditions.value, key); }; const handleTableFilterChange = (key, newVal) => { helper.setValueByPath(conditions.value, key, newVal); emits("condition-update", { key, newVal }); }; const getTableSorterValue = (key) => { return helper.getValueByPath(conditions.value, key); }; const sortKeys = vue.computed(() => Array.from(new Set(dataColumns.value.filter((v) => v.sortKey).map((v) => v.sortKey)))); const handleTableSorterChange = (key, newVal) => { if (!key) { return; } let _sortSequence = [...sortSequence.value]; if (props.sortMode === "single") { sortKeys.value.forEach((_key) => { helper.setValueByPath(conditions.value, _key, types.DataTableSortMethod.NA); }); _sortSequence = [key]; } helper.setValueByPath(conditions.value, key, newVal); if (newVal === types.DataTableSortMethod.NA) { _sortSequence = _sortSequence.filter((k) => k !== key); } else if (!_sortSequence.includes(key)) { _sortSequence.push(key); } sortSequence.value = _sortSequence; emits("condition-update"); emits("sort-update", { key, newVal, sortSequence: [..._sortSequence] }); }; const rowKeyMap = vue.computed(() => { var _a; const _map = /* @__PURE__ */ new Map(); const traverse = ({ row, rowIndex, ancestorRowKeys, setDescendant }) => { const rowKey = getRowKey(row, rowIndex); setDescendant == null ? void 0 : setDescendant(rowKey); const record = { row, rowIndex, disabled: is.isNil(props.disabledProp) ? false : !!helper.getValueByPath(row, props.disabledProp), ancestorRowKeys, descendantRowKeys: [] }; const _setDescendant = (descendant) => { record.descendantRowKeys.push(descendant); setDescendant == null ? void 0 : setDescendant(descendant); }; if (is.isArray(row.children)) { row.children.forEach((v, i) => traverse({ row: v, rowIndex: i, ancestorRowKeys: [rowKey, ...ancestorRowKeys], setDescendant: _setDescendant })); } _map.set(rowKey, record); }; (_a = props.data) == null ? void 0 : _a.forEach((row, rowIndex) => traverse({ row, rowIndex, ancestorRowKeys: [] })); return _map; }); const allRowKeys = vue.computed(() => { var _a; return ((_a = props.data) == null ? void 0 : _a.reduce((prev, row, rowIndex) => { var _a2; const rowKey = getRowKey(row, rowIndex); return [...prev, rowKey, ...((_a2 = rowKeyMap.value.get(rowKey)) == null ? void 0 : _a2.descendantRowKeys) || []]; }, [])) || []; }); const toFilteredSelectable = (arr) => { return arr.filter((v) => { var _a; return !((_a = rowKeyMap.value.get(v)) == null ? void 0 : _a.disabled); }); }; const selectableRowKeys = vue.computed(() => toFilteredSelectable(allRowKeys.value)); const selectedKeys = vue.useModel(__props, "selectedKeys"); const allChecked = vue.ref([]); const indeterminate = vue.computed(() => { return Boolean( selectedKeys.value.length && selectableRowKeys.value.some((v) => !selectedKeys.value.includes(v)) && // 兼容数据分页时,selectedKeys中包含非data的key(可能来自于其他分页) selectableRowKeys.value.some((v) => selectedKeys.value.includes(v)) ); }); const selectionChangedBySelectAll = vue.ref(false); vue.watch( () => [selectedKeys.value, selectableRowKeys.value], () => { if (selectionChangedBySelectAll.value) { selectionChangedBySelectAll.value = false; return; } if (selectedKeys.value.length === selectableRowKeys.value.length) { allChecked.value = [1]; } else if (!selectedKeys.value.length) { allChecked.value = []; } }, { immediate: true } ); const handleTableSelection = (key, newVal) => { emits("selection", { key, selected: !!newVal.length }); }; const handleSelectionAll = (newVal) => { selectionChangedBySelectAll.value = true; emits("selection-all", !!newVal.length); const prev = selectedKeys.value; selectedKeys.value = newVal.length ? [...selectableRowKeys.value] : []; emits("selection-change", { prev, cur: selectedKeys.value }); }; const popoverVisible = vue.ref(false); const popoverTarget = vue.shallowRef(); const popoverContent = vue.ref(); const popoverKey = vue.ref(); const handleTableMouseover = async (e) => { const cellTarget = dom.findClosestElementWithClass(e.target, "o-table-cell-tooltip", tableEl.value); const cellInnerContent = cellTarget == null ? void 0 : cellTarget.querySelector(":scope > .o-table-cell__inner > .o-table-cell__inner-content"); if (cellTarget && cellInnerContent) { popoverKey.value = cellTarget.dataset.cellIndex; popoverTarget.value = cellInnerContent; } if (!cellTarget || cellTarget === tableEl.value || !cellInnerContent || !dom.isOverflown(cellInnerContent)) { popoverVisible.value = false; popoverTarget.value = void 0; popoverContent.value = void 0; return; } await vue.nextTick(); popoverContent.value = cellInnerContent.innerText; popoverVisible.value = true; }; vue.provide(provide.dataTableInjectKey, { ...vue.toRefs(props), getRowKey, containerWidth, dataColumnMap, dataColumns, groupColumns, hasExpandSlot, expandedRowKeys, isBodyCellRemoved, isLastLeftFixedCell, isFirstRightFixedCell, rowKeyMap, allRowKeys, toFilteredSelectable, selectedKeys, handleTableSelection, handleLoadChildren(payload) { emits("load-children", payload); } }); vue.provide(provide.dataTableRowInjectKey, { isLevelExpandable }); __expose({ getRowKey, dataColumnMap, dataColumns, groupColumns, /** * @zh-CN 全选 * @en-US Select all * @since 1.2.2 */ selectAll() { selectedKeys.value = [...selectableRowKeys.value]; }, /** * @zh-CN 清空全选 * @en-US Clear all selections * @since 1.2.2 */ clearAll: () => selectedKeys.value = [], /** * @zh-CN 展开全部 * @en-US Expand all rows * @since 1.2.2 */ expandAll() { expandedRowKeys.value = [...allRowKeys.value]; }, /** * @zh-CN 收起全部 * @en-US Fold all rows * @since 1.2.2 */ foldAll: () => expandedRowKeys.value = [] }); return (_ctx, _cache) => { var _a, _b, _c, _d, _e; return vue.withDirectives((vue.openBlock(), vue.createElementBlock( "div", { ref_key: "rootRef", ref: rootRef, class: vue.normalizeClass([ "o-table", `o-table-${props.size}`, `o-table-header-${props.headerStyle}`, "o-data-table", { "o-table-stripe": props.stripe, "is-overflow-left": (_a = overflowState.value) == null ? void 0 : _a.isOverflowLeft, "is-overflow-right": (_b = overflowState.value) == null ? void 0 : _b.isOverflowRight, "is-overflow-top": (_c = overflowState.value) == null ? void 0 : _c.isOverflowTop }, ...vue.unref(borderClass) ]), style: vue.normalizeStyle({ "--table-header-height": vue.unref(headerTableHeight), "--table-height": vue.unref(is.isNumeric)(props.height) ? props.height + "px" : props.height, "--table-max-height": vue.unref(is.isNumeric)(props.maxHeight) ? props.maxHeight + "px" : props.maxHeight }) }, [ props.showHeader && props.headerStyle === "split-line" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1)) : vue.createCommentVNode("v-if", true), !vue.unref(hasLeftFixedColumn) && !props.loading && props.data.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2)) : vue.createCommentVNode("v-if", true), vue.createVNode(vue.unref(index.OScroller), { class: "o-table-scroller", "wrap-class": "o-table-wrap", "bar-class": "o-table-scroll-bar", size: props.size, "disabled-x": props.loading || !props.data.length, "show-type": "always", "auto-update-on-scroll-size": "", onScroll: vue.unref(checkTableOverflow) }, { default: vue.withCtx(() => { var _a2; return [ vue.createElementVNode( "table", { ref_key: "tableEl", ref: tableEl, class: "o-table-inner-table", style: vue.normalizeStyle({ minWidth: vue.unref(is.isNumeric)(props.minTableWidth) ? `${props.minTableWidth}px` : props.minTableWidth }), onMouseover: handleTableMouseover }, [ _cache[4] || (_cache[4] = vue.createElementVNode( "caption", null, null, -1 /* CACHED */ )), vue.createVNode(TableColGroup_vue_vue_type_script_setup_true_lang), props.showHeader ? (vue.openBlock(), vue.createElementBlock( "thead", { key: 0, ref_key: "headerRef", ref: headerRef, class: "o-table-header" }, [ vue.renderSlot(_ctx.$slots, "header", { columns: vue.unref(dataColumns), groupColumns: vue.unref(groupColumns) }, () => [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList(vue.unref(groupColumns), (groupColumn, groupIndex) => { var _a3; return vue.openBlock(), vue.createElementBlock("tr", { key: (_a3 = groupColumn[0]) == null ? void 0 : _a3.key, class: "o-table-row o-table-header-row" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList(groupColumn, (column, colIndex) => { var _a4, _b2; return vue.openBlock(), vue.createElementBlock( vue.Fragment, { key: column.key }, [ !column.headerHidden ? (vue.openBlock(), vue.createElementBlock("th", { key: 0, ref_for: true, ref: (el) => setThRef(el, column), colspan: column.colSpan || column.customColSpan, rowspan: column.rowSpan, class: vue.normalizeClass({ "o-table-cell": true, "o-table-header-cell": true, "o-table-column-as-header": column.asHeader, "o-table-cell-tooltip": column.showHeaderOverflowToolTip !== false && column.showHeaderOverflowToolTip !== 0, "o-table-cell-wrappable": vue.unref(is.isNumber)(column.showHeaderOverflowToolTip) && column.showHeaderOverflowToolTip > 1, "o-table-last-header-row-cell": !((_a4 = column.children) == null ? void 0 : _a4.length), "o-table-cell-fixed": column.fixed, "o-table-cell-fixed-left": column.fixed === "left", "o-table-cell-fixed-right": column.fixed === "right", "o-table-cell-last-left-fixed": column.isLastLeftFixedCol, "o-table-cell-first-right-fixed": column.isFirstRightFixedCol, [vue.unref(useTableMeta.DEFAULT_CELL_FIRST_COL_MARKER)]: column.isFirstCol, [vue.unref(useTableMeta.DEFAULT_CELL_LAST_COL_MARKER)]: column.isLastCol }), style: vue.normalizeStyle({ ...vue.unref(utils.getColumnPosition)({ column, dataColumns: vue.unref(dataColumns), groupColumns: vue.unref(groupColumns), border: props.border, isHeader: true }), "--cell-max-row": vue.unref(is.isNumber)(column.showHeaderOverflowToolTip) ? column.showHeaderOverflowToolTip : 1 }), "data-cell-index": `th_${groupIndex}_${colIndex}` }, [ vue.createElementVNode("span", _hoisted_4, [ column.isFirstCol && props.selection ? (vue.openBlock(), vue.createBlock(vue.unref(index$1.OCheckbox), { key: 0, modelValue: allChecked.value, "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => allChecked.value = $event), indeterminate: indeterminate.value, value: 1, class: "o-table-row-checkbox", onChange: handleSelectionAll }, null, 8, ["modelValue", "indeterminate"])) : vue.createCommentVNode("v-if", true), column.isFirstCol && !props.selection && isLevelExpandable.value.expandable ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_5)) : vue.createCommentVNode("v-if", true), vue.createElementVNode("span", _hoisted_6, [ vue.renderSlot(_ctx.$slots, `th_${column.key}`, { column }, () => [ (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(vue.unref(vueUtils.getRenderableComponent)(column.label)))) ]) ]), column.filter ? (vue.openBlock(), vue.createBlock(TableColumnFilter_vue_vue_type_script_setup_true_lang, { key: 2, disabled: props.loading, column, "model-value": getTableFilterValue(column.key), style: vue.normalizeStyle({ "--table-text-size": vue.unref(tableTextSize), "--table-text-height": vue.unref(tableTextHeight) }), "onUpdate:modelValue": (newVal) => handleTableFilterChange(column.key, newVal) }, null, 8, ["disabled", "column", "model-value", "style", "onUpdate:modelValue"])) : column.sortKey ? (vue.openBlock(), vue.createBlock(TableColumnSorter_vue_vue_type_script_setup_true_lang, { key: 3, disabled: props.loading, "model-value": getTableSorterValue(column.sortKey), "onUpdate:modelValue": (newVal) => handleTableSorterChange(column.sortKey, newVal) }, null, 8, ["disabled", "model-value", "onUpdate:modelValue"])) : vue.createCommentVNode("v-if", true), column.description ? (vue.openBlock(), vue.createBlock( vue.unref(index$2.OPopover), { key: 4, position: "top", "wrap-class": "o-table-tooltip-wrapper" }, { target: vue.withCtx(() => [ vue.createVNode(vue.unref(icons.IconInfoTip), { class: "o-data-table-info__trigger" }) ]), default: vue.withCtx(() => [ (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(vue.unref(vueUtils.getRenderableComponent)(column.description)))) ]), _: 2 /* DYNAMIC */ }, 1024 /* DYNAMIC_SLOTS */ )) : vue.createCommentVNode("v-if", true) ]), vue.createCommentVNode(" 如果可调整宽度,且没有合并单元格,则显示 "), props.columnResizable && (vue.unref(is.isNil)(column.customColSpan) || column.customColSpan <= 1) && !((_b2 = column.children) == null ? void 0 : _b2.length) ? (vue.openBlock(), vue.createElementBlock("div", { key: 0, class: "o-table-column-resizer", onMousedown: (event) => vue.unref(handleColumnResizerMousedown)({ event, column, colIndex }) }, [ vue.unref(resizingColumnKey) === column.key ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_8)) : vue.createCommentVNode("v-if", true) ], 40, _hoisted_7)) : vue.createCommentVNode("v-if", true) ], 14, _hoisted_3)) : vue.createCommentVNode("v-if", true) ], 64 /* STABLE_FRAGMENT */ ); }), 128 /* KEYED_FRAGMENT */ )) ]); }), 128 /* KEYED_FRAGMENT */ )) ]) ], 512 /* NEED_PATCH */ )) : vue.createCommentVNode("v-if", true), vue.createElementVNode( "tbody", { class: "o-table-body", onMousemove: _cache[1] || (_cache[1] = //@ts-ignore (...args) => vue.unref(handleMouseOver) && vue.unref(handleMouseOver)(...args)), onMouseleave: _cache[2] || (_cache[2] = //@ts-ignore (...args) => vue.unref(clearHighlight) && vue.unref(clearHighlight)(...args)), onTouchstart: _cache[3] || (_cache[3] = //@ts-ignore (...args) => vue.unref(handleTouchStart) && vue.unref(handleTouchStart)(...args)) }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList(props.data, (row, rowIndex) => { return vue.openBlock(), vue.createBlock(TableRow_vue_vue_type_script_setup_true_lang, { key: getRowKey(row, rowIndex), row, "row-index": rowIndex, level: 0 }, vue.createSlots({ _: 2 /* DYNAMIC */ }, [ vue.renderList(tdSlotNames.value, (name) => { return { name, fn: vue.withCtx((slotProps) => [ vue.renderSlot(_ctx.$slots, name, vue.mergeProps({ ref_for: true }, slotProps)) ]) }; }), slots.expand ? { name: "expand", fn: vue.withCtx(() => [ vue.renderSlot(_ctx.$slots, "expand", { row, rowIndex }) ]), key: "0" } : void 0 ]), 1032, ["row", "row-index"]); }), 128 /* KEYED_FRAGMENT */ )), props.loading || !((_a2 = props.data) == null ? void 0 : _a2.length) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9)) : vue.createCommentVNode("v-if", true) ], 32 /* NEED_HYDRATION */ ) ], 36 /* STYLE, NEED_HYDRATION */ ) ]; }), _: 3 /* FORWARDED */ }, 8, ["size", "disabled-x", "onScroll"]), props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10, [ vue.renderSlot(_ctx.$slots, "loading", {}, () => [ vue.createVNode(vue.unref(icons.IconLoading), { class: "o-rotating" }), vue.createElementVNode( "div", _hoisted_11, vue.toDisplayString(vue.unref(loadingLabel)), 1 /* TEXT */ ) ]) ])) : !((_d = props.data) == null ? void 0 : _d.length) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12, [ !props.loading ? vue.renderSlot(_ctx.$slots, "empty", { key: 0 }, () => [ vue.createElementVNode( "div", _hoisted_13, vue.toDisplayString(vue.unref(emptyLabel)), 1 /* TEXT */ ) ]) : vue.createCommentVNode("v-if", true) ])) : vue.createCommentVNode("v-if", true), !vue.unref(hasRightFixedColumn) && !props.loading && props.data.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14)) : vue.createCommentVNode("v-if", true), popoverVisible.value ? (vue.openBlock(), vue.createBlock(vue.unref(index$2.OPopover), { key: popoverKey.value, visivle: "", target: popoverTarget.value, position: ((_e = popoverKey.value) == null ? void 0 : _e.startsWith("td")) ? "bottom" : "top", "wrap-class": "o-table-tooltip-wrapper" }, { default: vue.withCtx(() => [ vue.createTextVNode( vue.toDisplayString(popoverContent.value), 1 /* TEXT */ ) ]), _: 1 /* STABLE */ }, 8, ["target", "position"])) : vue.createCommentVNode("v-if", true) ], 6 /* CLASS, STYLE */ )), [ [vue.unref(onResize.vOnResize), vue.unref(checkTableOverflow)] ]); }; } }); module.exports = _sfc_main;