@opensig/opendesign
Version:
653 lines (652 loc) • 30.9 kB
JavaScript
import { defineComponent, mergeModels, useSlots, computed, ref, toRefs, useModel, watch, shallowRef, provide, withDirectives, createElementBlock, openBlock, normalizeStyle, normalizeClass, unref, createCommentVNode, createVNode, createBlock, withCtx, createElementVNode, renderSlot, Fragment, renderList, resolveDynamicComponent, createSlots, mergeProps, toDisplayString, createTextVNode, reactive, markRaw, nextTick } from "vue";
import { useElementBounding, refDebounced, useCssVar } from "@vueuse/core";
import { isNumeric, isNumber, isNil, isFunction, isArray } from "../_utils/is.mjs";
import { checkElementOverflow, getCssVariable, findClosestElementWithClass, isOverflown } from "../_utils/dom.mjs";
import "../hooks/use-theme.mjs";
import "../_utils/global.mjs";
import { getRenderableComponent } from "../_utils/vue-utils.mjs";
import { vOnResize } from "../directives/on-resize.mjs";
import { debounceRAF, getValueByPath, setValueByPath } from "../_utils/helper.mjs";
import { IconInfoTip, IconLoading } from "../_utils/icons.mjs";
import { OScroller } from "../scrollbar/index.mjs";
import { OCheckbox } from "../checkbox/index.mjs";
import { OPopover } from "../popover/index.mjs";
import "../table/index.mjs";
import { useTableCommon } from "../table/useTableCommon.mjs";
import { dataTableProps, DataTableSortMethod } from "./types.mjs";
import { getIsLevelExpandable, getColumnPosition } from "./utils.mjs";
import _sfc_main$1 from "./TableColGroup.vue.mjs";
import _sfc_main$4 from "./TableRow.vue.mjs";
import _sfc_main$2 from "./TableColumnFilter.vue.mjs";
import _sfc_main$3 from "./TableColumnSorter.vue.mjs";
import { dataTableInjectKey, dataTableRowInjectKey } from "./provide.mjs";
import { useDataColumn } from "./use-data-column.mjs";
import { DEFAULT_CELL_LAST_COL_MARKER, DEFAULT_CELL_FIRST_COL_MARKER } from "../table/useTableMeta.mjs";
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__ */ defineComponent({
__name: "ODataTable",
props: /* @__PURE__ */ mergeModels(dataTableProps, {
"expanded-row-keys": { default: () => reactive([]) },
"expanded-row-keysModifiers": {},
"conditions": {
/**
* @important 兜底如果外面没有传值的情况
*/
default: () => reactive({})
},
"conditionsModifiers": {},
"sortSequence": {
/**
* @important 兜底如果外面没有传值的情况
*/
default: () => reactive([])
},
"sortSequenceModifiers": {},
"selectedKeys": { default: () => reactive([]) },
"selectedKeysModifiers": {}
}),
emits: /* @__PURE__ */ 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 = useSlots();
const tdSlotNames = computed(() => Object.keys(slots).filter((name) => name.startsWith("td_")));
const rootRef = ref();
const { width: containerBoundingWidth } = useElementBounding(rootRef);
const containerWidth = refDebounced(
computed(() => {
var _a;
void containerBoundingWidth.value;
return ((_a = rootRef.value) == null ? void 0 : _a.clientWidth) ?? 0;
})
);
const headerRef = ref();
const { height: headerTableHeight } = useElementBounding(headerRef);
const tableTextSize = useCssVar("--table-text-size", headerRef);
const tableTextHeight = useCssVar("--table-text-height", headerRef);
const tableEl = ref();
const overflowState = ref();
const checkTableOverflow = debounceRAF(() => {
if (!tableEl.value) {
return;
}
overflowState.value = checkElementOverflow({
element: tableEl.value,
parentElement: rootRef.value,
// 由于右固定列与前一列边框重合,宽容两个边框宽度
threshold: Number.parseFloat(getCssVariable("--table-border-width", rootRef.value)) * 2
});
});
const getRowKey = (row, rowIndex) => {
if (isFunction(props.rowKey)) {
return props.rowKey(row) ?? rowIndex;
}
return getValueByPath(row, props.rowKey) ?? rowIndex;
};
const { emptyLabel, loadingLabel, borderClass, handleMouseOver, clearHighlight, handleTouchStart } = useTableCommon({ ...toRefs(props), tableEl });
const {
dataColumnMap,
dataColumns,
groupColumns,
isBodyCellRemoved,
isLastLeftFixedCell,
isFirstRightFixedCell,
hasLeftFixedColumn,
hasRightFixedColumn,
handleColumnResizerMousedown,
resizingColumnKey
} = useDataColumn({ ...toRefs(props), tableEl, containerWidth });
const setThRef = (el, column) => {
if (!el) {
return;
}
column.thRef = markRaw(el);
};
const expandedRowKeys = useModel(__props, "expanded-row-keys");
const hasExpandSlot = computed(() => !!slots.expand);
const isLevelExpandable = computed(() => getIsLevelExpandable({ list: props.data, hasExpandSlot, expandMethod: props.expandMethod }));
const conditions = useModel(__props, "conditions");
const sortSequence = useModel(__props, "sortSequence");
const getTableFilterValue = (key) => {
return getValueByPath(conditions.value, key);
};
const handleTableFilterChange = (key, newVal) => {
setValueByPath(conditions.value, key, newVal);
emits("condition-update", { key, newVal });
};
const getTableSorterValue = (key) => {
return getValueByPath(conditions.value, key);
};
const sortKeys = 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) => {
setValueByPath(conditions.value, _key, DataTableSortMethod.NA);
});
_sortSequence = [key];
}
setValueByPath(conditions.value, key, newVal);
if (newVal === 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 = 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: isNil(props.disabledProp) ? false : !!getValueByPath(row, props.disabledProp),
ancestorRowKeys,
descendantRowKeys: []
};
const _setDescendant = (descendant) => {
record.descendantRowKeys.push(descendant);
setDescendant == null ? void 0 : setDescendant(descendant);
};
if (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 = 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 = computed(() => toFilteredSelectable(allRowKeys.value));
const selectedKeys = useModel(__props, "selectedKeys");
const allChecked = ref([]);
const indeterminate = 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 = ref(false);
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 = ref(false);
const popoverTarget = shallowRef();
const popoverContent = ref();
const popoverKey = ref();
const handleTableMouseover = async (e) => {
const cellTarget = 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 || !isOverflown(cellInnerContent)) {
popoverVisible.value = false;
popoverTarget.value = void 0;
popoverContent.value = void 0;
return;
}
await nextTick();
popoverContent.value = cellInnerContent.innerText;
popoverVisible.value = true;
};
provide(dataTableInjectKey, {
...toRefs(props),
getRowKey,
containerWidth,
dataColumnMap,
dataColumns,
groupColumns,
hasExpandSlot,
expandedRowKeys,
isBodyCellRemoved,
isLastLeftFixedCell,
isFirstRightFixedCell,
rowKeyMap,
allRowKeys,
toFilteredSelectable,
selectedKeys,
handleTableSelection,
handleLoadChildren(payload) {
emits("load-children", payload);
}
});
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 withDirectives((openBlock(), createElementBlock(
"div",
{
ref_key: "rootRef",
ref: rootRef,
class: 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
},
...unref(borderClass)
]),
style: normalizeStyle({
"--table-header-height": unref(headerTableHeight),
"--table-height": unref(isNumeric)(props.height) ? props.height + "px" : props.height,
"--table-max-height": unref(isNumeric)(props.maxHeight) ? props.maxHeight + "px" : props.maxHeight
})
},
[
props.showHeader && props.headerStyle === "split-line" ? (openBlock(), createElementBlock("div", _hoisted_1)) : createCommentVNode("v-if", true),
!unref(hasLeftFixedColumn) && !props.loading && props.data.length ? (openBlock(), createElementBlock("div", _hoisted_2)) : createCommentVNode("v-if", true),
createVNode(unref(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: unref(checkTableOverflow)
}, {
default: withCtx(() => {
var _a2;
return [
createElementVNode(
"table",
{
ref_key: "tableEl",
ref: tableEl,
class: "o-table-inner-table",
style: normalizeStyle({
minWidth: unref(isNumeric)(props.minTableWidth) ? `${props.minTableWidth}px` : props.minTableWidth
}),
onMouseover: handleTableMouseover
},
[
_cache[4] || (_cache[4] = createElementVNode(
"caption",
null,
null,
-1
/* CACHED */
)),
createVNode(_sfc_main$1),
props.showHeader ? (openBlock(), createElementBlock(
"thead",
{
key: 0,
ref_key: "headerRef",
ref: headerRef,
class: "o-table-header"
},
[
renderSlot(_ctx.$slots, "header", {
columns: unref(dataColumns),
groupColumns: unref(groupColumns)
}, () => [
(openBlock(true), createElementBlock(
Fragment,
null,
renderList(unref(groupColumns), (groupColumn, groupIndex) => {
var _a3;
return openBlock(), createElementBlock("tr", {
key: (_a3 = groupColumn[0]) == null ? void 0 : _a3.key,
class: "o-table-row o-table-header-row"
}, [
(openBlock(true), createElementBlock(
Fragment,
null,
renderList(groupColumn, (column, colIndex) => {
var _a4, _b2;
return openBlock(), createElementBlock(
Fragment,
{
key: column.key
},
[
!column.headerHidden ? (openBlock(), createElementBlock("th", {
key: 0,
ref_for: true,
ref: (el) => setThRef(el, column),
colspan: column.colSpan || column.customColSpan,
rowspan: column.rowSpan,
class: 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": unref(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,
[unref(DEFAULT_CELL_FIRST_COL_MARKER)]: column.isFirstCol,
[unref(DEFAULT_CELL_LAST_COL_MARKER)]: column.isLastCol
}),
style: normalizeStyle({
...unref(getColumnPosition)({ column, dataColumns: unref(dataColumns), groupColumns: unref(groupColumns), border: props.border, isHeader: true }),
"--cell-max-row": unref(isNumber)(column.showHeaderOverflowToolTip) ? column.showHeaderOverflowToolTip : 1
}),
"data-cell-index": `th_${groupIndex}_${colIndex}`
}, [
createElementVNode("span", _hoisted_4, [
column.isFirstCol && props.selection ? (openBlock(), createBlock(unref(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"])) : createCommentVNode("v-if", true),
column.isFirstCol && !props.selection && isLevelExpandable.value.expandable ? (openBlock(), createElementBlock("span", _hoisted_5)) : createCommentVNode("v-if", true),
createElementVNode("span", _hoisted_6, [
renderSlot(_ctx.$slots, `th_${column.key}`, { column }, () => [
(openBlock(), createBlock(resolveDynamicComponent(unref(getRenderableComponent)(column.label))))
])
]),
column.filter ? (openBlock(), createBlock(_sfc_main$2, {
key: 2,
disabled: props.loading,
column,
"model-value": getTableFilterValue(column.key),
style: normalizeStyle({
"--table-text-size": unref(tableTextSize),
"--table-text-height": unref(tableTextHeight)
}),
"onUpdate:modelValue": (newVal) => handleTableFilterChange(column.key, newVal)
}, null, 8, ["disabled", "column", "model-value", "style", "onUpdate:modelValue"])) : column.sortKey ? (openBlock(), createBlock(_sfc_main$3, {
key: 3,
disabled: props.loading,
"model-value": getTableSorterValue(column.sortKey),
"onUpdate:modelValue": (newVal) => handleTableSorterChange(column.sortKey, newVal)
}, null, 8, ["disabled", "model-value", "onUpdate:modelValue"])) : createCommentVNode("v-if", true),
column.description ? (openBlock(), createBlock(
unref(OPopover),
{
key: 4,
position: "top",
"wrap-class": "o-table-tooltip-wrapper"
},
{
target: withCtx(() => [
createVNode(unref(IconInfoTip), { class: "o-data-table-info__trigger" })
]),
default: withCtx(() => [
(openBlock(), createBlock(resolveDynamicComponent(unref(getRenderableComponent)(column.description))))
]),
_: 2
/* DYNAMIC */
},
1024
/* DYNAMIC_SLOTS */
)) : createCommentVNode("v-if", true)
]),
createCommentVNode(" 如果可调整宽度,且没有合并单元格,则显示 "),
props.columnResizable && (unref(isNil)(column.customColSpan) || column.customColSpan <= 1) && !((_b2 = column.children) == null ? void 0 : _b2.length) ? (openBlock(), createElementBlock("div", {
key: 0,
class: "o-table-column-resizer",
onMousedown: (event) => unref(handleColumnResizerMousedown)({ event, column, colIndex })
}, [
unref(resizingColumnKey) === column.key ? (openBlock(), createElementBlock("div", _hoisted_8)) : createCommentVNode("v-if", true)
], 40, _hoisted_7)) : createCommentVNode("v-if", true)
], 14, _hoisted_3)) : createCommentVNode("v-if", true)
],
64
/* STABLE_FRAGMENT */
);
}),
128
/* KEYED_FRAGMENT */
))
]);
}),
128
/* KEYED_FRAGMENT */
))
])
],
512
/* NEED_PATCH */
)) : createCommentVNode("v-if", true),
createElementVNode(
"tbody",
{
class: "o-table-body",
onMousemove: _cache[1] || (_cache[1] = //@ts-ignore
(...args) => unref(handleMouseOver) && unref(handleMouseOver)(...args)),
onMouseleave: _cache[2] || (_cache[2] = //@ts-ignore
(...args) => unref(clearHighlight) && unref(clearHighlight)(...args)),
onTouchstart: _cache[3] || (_cache[3] = //@ts-ignore
(...args) => unref(handleTouchStart) && unref(handleTouchStart)(...args))
},
[
(openBlock(true), createElementBlock(
Fragment,
null,
renderList(props.data, (row, rowIndex) => {
return openBlock(), createBlock(_sfc_main$4, {
key: getRowKey(row, rowIndex),
row,
"row-index": rowIndex,
level: 0
}, createSlots({
_: 2
/* DYNAMIC */
}, [
renderList(tdSlotNames.value, (name) => {
return {
name,
fn: withCtx((slotProps) => [
renderSlot(_ctx.$slots, name, mergeProps({ ref_for: true }, slotProps))
])
};
}),
slots.expand ? {
name: "expand",
fn: withCtx(() => [
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) ? (openBlock(), createElementBlock("div", _hoisted_9)) : createCommentVNode("v-if", true)
],
32
/* NEED_HYDRATION */
)
],
36
/* STYLE, NEED_HYDRATION */
)
];
}),
_: 3
/* FORWARDED */
}, 8, ["size", "disabled-x", "onScroll"]),
props.loading ? (openBlock(), createElementBlock("div", _hoisted_10, [
renderSlot(_ctx.$slots, "loading", {}, () => [
createVNode(unref(IconLoading), { class: "o-rotating" }),
createElementVNode(
"div",
_hoisted_11,
toDisplayString(unref(loadingLabel)),
1
/* TEXT */
)
])
])) : !((_d = props.data) == null ? void 0 : _d.length) ? (openBlock(), createElementBlock("div", _hoisted_12, [
!props.loading ? renderSlot(_ctx.$slots, "empty", { key: 0 }, () => [
createElementVNode(
"div",
_hoisted_13,
toDisplayString(unref(emptyLabel)),
1
/* TEXT */
)
]) : createCommentVNode("v-if", true)
])) : createCommentVNode("v-if", true),
!unref(hasRightFixedColumn) && !props.loading && props.data.length ? (openBlock(), createElementBlock("div", _hoisted_14)) : createCommentVNode("v-if", true),
popoverVisible.value ? (openBlock(), createBlock(unref(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: withCtx(() => [
createTextVNode(
toDisplayString(popoverContent.value),
1
/* TEXT */
)
]),
_: 1
/* STABLE */
}, 8, ["target", "position"])) : createCommentVNode("v-if", true)
],
6
/* CLASS, STYLE */
)), [
[unref(vOnResize), unref(checkTableOverflow)]
]);
};
}
});
export {
_sfc_main as default
};