20260811221831

This commit is contained in:
oneao committed 2026-08-11 22:18:31 +08:00
1 parent ce78653207
commit 1d7f7c2bba
3 files changed
+82 -52

No files matched your search

@@ -12,7 +12,7 @@ const props = defineProps({
virtual: { type: Boolean, default: true },
virtualX: { type: Boolean, default: true },
colResizable: { type: Boolean, default: true },
bordered: { type: [Boolean, String], default: true },
bordered: { type: [Boolean, String], default: false },
noDataFull: { type: Boolean, default: true },
showOverflow: { type: Boolean, default: true },
columns: { type: Array, default: () => [] },
@@ -44,7 +44,6 @@ const tableRef = ref(null);
const slots = useSlots();
const appStore = useAppStore();
const tableTheme = computed(() => props.theme ?? (appStore.isDark ? "dark" : "light"));
const containerHeight = ref(0);
// Tab 面板从隐藏恢复时,等到容器拥有有效尺寸再刷新虚拟滚动布局。
// RAF 将同一帧内的多次 ResizeObserver 通知合并,避免重复重排。
@@ -59,7 +58,6 @@ const { resume: refreshLayout } = useRafFn(
useResizeObserver(rootRef, ([entry]) => {
const { width, height } = entry.contentRect;
containerHeight.value = Math.floor(height);
if (width > 0 && height > 0) refreshLayout();
});
@@ -250,7 +248,10 @@ function onColumnsUpdate(columns) {
const real = (columns || [])
.filter(
(c) =>
!isSelectionColumn(c) && c.type !== "seq" && c.type !== "dragRow" && c.dataIndex !== "",
!isSelectionColumn(c) &&
c.type !== "seq" &&
c.type !== "dragRow" &&
c.dataIndex !== "",
)
.map((col) => {
const original = originalByKey.get(String(col.key ?? col.dataIndex ?? ""));
@@ -266,19 +267,14 @@ function handleRowOrderChange(sourceIndex, targetIndex) {
}
// 行高同时作为 CSS 变量与 StkTable 的 row-height / header-row-height
const rowHeight = 34;
const headerRowHeight = 40;
const hasBottomGap = computed(() => {
if (!props.dataSource.length || containerHeight.value <= 0) return false;
const bodyHeight = Math.max(containerHeight.value - headerRowHeight, 0);
return props.dataSource.length * rowHeight < bodyHeight - 1;
});
const rowHeight = 28;
const headerRowHeight = 30;
const customVars = computed(() => {
return {
"--header-row-height": `${headerRowHeight}px`,
"--row-height": `${rowHeight}px`,
"--footer-row-height": "36px",
"--th-bgc": "var(--background)",
"--th-bgc": "#f5f5f8",
"--tf-bgc": "var(--background)",
};
});
@@ -526,16 +522,10 @@ defineExpose({
</script>
<template>
<div
ref="rootRef"
class="fms-table"
:class="{ 'fms-table--bordered': bordered }"
@keydown.capture="handleKeydownCapture"
>
<div ref="rootRef" class="fms-table" @keydown.capture="handleKeydownCapture">
<StkTable
ref="tableRef"
class="fms-table__inner"
:class="{ 'fms-table--bottom-gap': hasBottomGap }"
v-bind="$attrs"
:style="customVars"
:theme="tableTheme"
@@ -554,7 +544,7 @@ defineExpose({
:no-data-full="noDataFull"
:show-overflow="showOverflow"
:area-selection="editable"
:bordered="false"
:bordered="bordered"
@area-selection-change="handleAreaSelectionChange"
@row-order-change="handleRowOrderChange"
>
@@ -576,19 +566,32 @@ defineExpose({
<style scoped>
.fms-table {
position: relative;
width: 100%;
height: 100%;
border-radius: 8px;
overflow: hidden;
}
.fms-table--bordered {
/*
* 用伪元素画外框放到最上层,避免与 td 底边重叠。
* 不管数据多少,外框始终完整,td 行线在伪元素之下。
*/
.fms-table::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
border: 1px solid var(--border);
border-radius: 8px;
border-radius: inherit;
z-index: 2;
}
.fms-table__inner {
width: 100%;
height: 100%;
}
</style>
<!-- 非 scoped 全局样式:原生 checkbox 保持低组件开销,外观使用 shadcn 语义变量。 -->
@@ -600,6 +603,11 @@ defineExpose({
font-size: 13px;
}
/* 行间分割线 */
.stk-tbody-main td {
border-bottom: 1px solid var(--border);
}
th.fms-selection-header {
vertical-align: middle;
@@ -613,29 +621,6 @@ defineExpose({
}
}
/*
* 外层绘制表格边框,表体只保留横向分割线。
*/
.fms-table__inner.stk-table {
th,
td {
border-bottom: 1px solid var(--border);
}
thead th {
border-bottom-color: var(--border);
}
// 数据铺满视口时隐藏最后一行底线,避免与外框底线叠加;数据较少时保留底线标记数据区域结束。
&:not(.fms-table--bottom-gap) {
.stk-tbody-main tr:last-child {
td {
border-bottom: none;
}
}
}
}
.fms-checkbox {
display: flex;
align-items: center;
@@ -782,9 +767,6 @@ defineExpose({
white-space: nowrap;
}
.fms-table__inner td.fms-editor-cell {
padding-inline: 3px;
}
// actions 列按钮容器
.fms-actions-cell {
@@ -26,7 +26,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<AlertDialogPortal>
<AlertDialogOverlay
data-slot="alert-dialog-overlay"
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80"
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50"
/>
<AlertDialogContent
data-slot="alert-dialog-content"