Browse Source

refactor(list-table-v2): restructure mini-table rendering and cleanup

- Refactor mini-table to use useTemplateRef for better Vue 3 compatibility
- Add conditional wrapper for mini-table rows container
- Add debug info display for row/header height estimation
- Fix md5 import to use named export in router
- Fix loading state bug in getUser callback
- Add @types/js-md5 dev dependency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dev
hechang27-sprt 3 months ago
parent
commit
a2eeb86a28
  1. 3
      bun.lock
  2. 1
      examples/view/base/table-v2.vue
  3. 1
      package.json
  4. 100
      packages/base/data/list-table-v2.vue
  5. 11
      packages/manage/router/index.vue

3
bun.lock

@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
"xterm-addon-fit": "^0.8.0",
},
"devDependencies": {
"@types/js-md5": "^0.8.0",
"@types/lodash-es": "^4.17.12",
"@vitejs/plugin-legacy": "^7.2.1",
"@vitejs/plugin-vue": "^6.0.3",
@ -483,6 +484,8 @@ @@ -483,6 +484,8 @@
"@types/http-proxy": ["@types/http-proxy@1.17.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw=="],
"@types/js-md5": ["@types/js-md5@0.8.0", "", {}, "sha512-gQkc1Felhyj+aB9jmz/ICLm1fDPQx7l/60JIBSSEC+j09JeaINlzd0Wj9LZlQkHnV5rJYkroOHE5wdbDgADJrw=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@types/lodash": ["@types/lodash@4.17.23", "", {}, "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA=="],

1
examples/view/base/table-v2.vue

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
:example="example"
:row-key="'id'"
@query="handleQuery"
debug
></ListTableV2>
</template>

1
package.json

@ -106,6 +106,7 @@ @@ -106,6 +106,7 @@
"xterm-addon-fit": "^0.8.0"
},
"devDependencies": {
"@types/js-md5": "^0.8.0",
"@types/lodash-es": "^4.17.12",
"@vitejs/plugin-legacy": "^7.2.1",
"@vitejs/plugin-vue": "^6.0.3",

100
packages/base/data/list-table-v2.vue

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
<!-- Mini hidden table for measuring row height and header height (only when using dynamic height mode) -->
<!-- This mirrors the real table's cell rendering for accurate height estimation -->
<div v-if="shouldUseProbeRow" ref="miniTableRef" class="mini-table" aria-hidden="true">
<div v-if="miniTableData.length > 0" class="mini-table-inner">
<div class="mini-table-inner">
<!-- Mini header row -->
<div ref="miniHeaderRef" class="mini-row mini-header">
<div
@ -16,26 +16,32 @@ @@ -16,26 +16,32 @@
</div>
</div>
<!-- Mini data rows -->
<div v-for="(rowData, rowIndex) in miniTableData" :key="rowIndex" class="mini-row">
<div
v-for="(column, columnIndex) in tableColumns || []"
:key="column.key"
class="mini-cell"
:style="getMiniCellStyle(column)"
>
<MiniTableCell
:cellData="lodash.get(rowData, String(column.dataKey || column.key))"
:columnIndex
:columns="tableColumns"
:column
:rowData
:rowIndex
/>
<div v-if="miniTableData.length > 0" ref="miniTableRowsRef" class="mini-table-rows">
<div v-for="(rowData, rowIndex) in miniTableData" :key="rowIndex" class="mini-row">
<div
v-for="(column, columnIndex) in tableColumns || []"
:key="column.key"
class="mini-cell"
:style="getMiniCellStyle(column)"
>
<MiniTableCell
:cellData="lodash.get(rowData, String(column.dataKey || column.key))"
:columnIndex
:columns="tableColumns"
:column
:rowData
:rowIndex
/>
</div>
</div>
</div>
</div>
</div>
<div v-if="debug" class="debug-info">
<div>Estimated Row Height: {{ resolvedRowHeight }}</div>
<div>Estimated Header Height: {{ resolvedHeaderHeight }}</div>
</div>
<div ref="myTableRef" class="my-table">
<el-auto-resizer>
<template #default="{ height, width }">
@ -47,7 +53,7 @@ @@ -47,7 +53,7 @@
:height="resolvedHeight(height)"
:row-height="prop.rowHeight"
:header-height="resolvedHeaderHeight"
:estimated-row-height="estimatedRowHeightToUse"
:estimated-row-height="resolvedRowHeight"
:border="border"
:row-key="rowKey"
:class="border ? 'has-border' : ''"
@ -88,6 +94,7 @@ import { @@ -88,6 +94,7 @@ import {
nextTick,
VNode,
StyleValue,
useTemplateRef,
} from "vue";
import { useI18n } from "vue3-i18n";
import { Column, ElAutoResizer, ElTableV2 } from "element-plus";
@ -106,10 +113,10 @@ const slots = useSlots(); @@ -106,10 +113,10 @@ const slots = useSlots();
const { t } = useI18n();
const { state } = useStore();
const table = ref();
const miniTableRef = ref();
const miniHeaderRef = ref();
const myTableRef = ref(); // Reference to .my-table for ResizeObserver
const miniTableRef = useTemplateRef("miniTableRef");
const miniHeaderRef = useTemplateRef("miniHeaderRef");
const miniTableRowsRef = useTemplateRef("miniTableRowsRef");
const myTableRef = useTemplateRef("myTableRef"); // Reference to .my-table for ResizeObserver
const miniTableData = ref<any[]>([]);
const estimatedRowHeight = ref<number | undefined>(undefined);
const estimatedHeaderHeight = ref<number | undefined>(undefined);
@ -129,16 +136,6 @@ type TimestampValue = @@ -129,16 +136,6 @@ type TimestampValue =
type?: "iso8601" | "unix" | "unixMillis";
};
interface TzDateTimeProps {
value: string | number;
valueFormat?: string;
valueTz?: string;
displayFormat?: string;
locale?: string;
type?: "iso8601" | "unix" | "unixMillis";
slot?: boolean;
}
interface TzDateTimeConfig {
valueFormat?: string;
valueTz?: string;
@ -184,6 +181,7 @@ interface Props { @@ -184,6 +181,7 @@ interface Props {
rowHeight?: number;
estimatedRowHeight?: number;
headerHeight?: number;
debug?: boolean;
}
const prop = withDefaults(defineProps<Props>(), {
@ -226,7 +224,7 @@ const shouldUseProbeRow = computed(() => { @@ -226,7 +224,7 @@ const shouldUseProbeRow = computed(() => {
// The estimated row height to pass to el-table-v2
// Only used when rowHeight is NOT set (dynamic height mode)
const estimatedRowHeightToUse = computed(() => {
const resolvedRowHeight = computed(() => {
if (prop.rowHeight !== undefined) return undefined; // fixed height mode, don't use estimated
if (prop.estimatedRowHeight !== undefined) return prop.estimatedRowHeight; // user provided estimate
return estimatedRowHeight.value; // use probe-measured value
@ -248,22 +246,18 @@ watch( @@ -248,22 +246,18 @@ watch(
if (!shouldUseProbeRow.value || !data || data.length === 0) {
return;
}
// Use up to 5 rows for mini table
miniTableData.value = data.slice(0, 5);
// Use up to 3 rows for mini table
miniTableData.value = lodash.sampleSize(data, 3);
// Wait for mini table to render
await nextTick();
// Wait TWO frames for layout to settle
await new Promise((resolve) => requestAnimationFrame(resolve));
await new Promise((resolve) => requestAnimationFrame(resolve));
// Measure header height
const headerEl = miniTableRef.value?.querySelector(".mini-header");
const headerHeight = headerEl?.offsetHeight;
const { headerHeight, rowHeight } = estimateTableRowHeight();
if (headerHeight && headerHeight > 0) {
estimatedHeaderHeight.value = headerHeight;
}
// Measure first row height
const firstRow = miniTableRef.value?.querySelector(".mini-row:not(.mini-header)");
const rowHeight = firstRow?.offsetHeight;
if (rowHeight && rowHeight > 0) {
estimatedRowHeight.value = rowHeight;
}
@ -271,6 +265,17 @@ watch( @@ -271,6 +265,17 @@ watch(
{ immediate: true }
);
function estimateTableRowHeight() {
const headerHeight = miniHeaderRef.value?.offsetHeight;
const tableRowsHeight = miniTableRowsRef.value?.offsetHeight;
const rowHeight =
tableRowsHeight && tableRowsHeight > 0 && miniTableData.value.length > 0
? lodash.round(tableRowsHeight / miniTableData.value.length)
: undefined;
return { headerHeight, rowHeight };
}
// Setup ResizeObserver on mount (not window resize - that causes flickering)
onMounted(() => {
// Resize handler - measure first, then clear and set in same microtask
@ -283,10 +288,7 @@ onMounted(() => { @@ -283,10 +288,7 @@ onMounted(() => {
await new Promise((resolve) => requestAnimationFrame(resolve));
// Measure first while old values still set
const headerEl = miniTableRef.value?.querySelector(".mini-header");
const headerHeight = headerEl?.offsetHeight;
const firstRow = miniTableRef.value?.querySelector(".mini-row:not(.mini-header)");
const rowHeight = firstRow?.offsetHeight;
const { headerHeight, rowHeight } = estimateTableRowHeight();
const newHeader = headerHeight && headerHeight > 0 ? headerHeight : estimatedHeaderHeight.value;
const newRow = rowHeight && rowHeight > 0 ? rowHeight : estimatedRowHeight.value;
@ -554,6 +556,10 @@ const getMiniCellStyle = ({ width, minWidth, maxWidth, flexGrow, flexShrink }: C @@ -554,6 +556,10 @@ const getMiniCellStyle = ({ width, minWidth, maxWidth, flexGrow, flexShrink }: C
</script>
<style lang="scss" scoped>
.debug-info {
font-size: 9px;
}
.list-table-v2 {
display: flex;
flex-direction: column;
@ -579,6 +585,12 @@ const getMiniCellStyle = ({ width, minWidth, maxWidth, flexGrow, flexShrink }: C @@ -579,6 +585,12 @@ const getMiniCellStyle = ({ width, minWidth, maxWidth, flexGrow, flexShrink }: C
width: 100%;
}
.mini-table-rows {
display: flex;
flex-direction: column;
flex: 1;
}
.mini-row {
display: flex;
align-items: stretch;

11
packages/manage/router/index.vue

@ -35,7 +35,7 @@ import { onBeforeUnmount, onMounted, reactive, ref, watch, computed } from "vue" @@ -35,7 +35,7 @@ import { onBeforeUnmount, onMounted, reactive, ref, watch, computed } from "vue"
import { useStore } from "vuex";
import { useRouter, useRoute } from "vue-router";
import { Api, NoobHead } from "noob-mengyxu";
import md5 from "js-md5";
import { md5 } from "js-md5";
const DEV_MODE_TS = "2026-03-26T08:35:00.000Z";
const { VITE_APP_VERSION, VITE_GIT_HASH, NODE_ENV } = import.meta.env;
@ -106,12 +106,11 @@ const onResize = () => { @@ -106,12 +106,11 @@ const onResize = () => {
};
const getUser = (first?) => {
if (!props.checkUser) {
return;
}
first && (flag.loading = true);
if (!props.checkUser) return;
if (first) flag.loading = true;
Api.pub.getInfo().then((rsp) => {
first && (flag.loading = false);
if (first) flag.loading = false;
if (rsp) {
if (state.user?.userId !== rsp.userId) {
commit("updateState", ["user", rsp]);

Loading…
Cancel
Save