修复表格刷新布局跳动并补齐多端回归验收
前端验证 / verify (push) Failing after 4m40s

This commit is contained in:
cieanyau committed 2026-11-07 07:08:48 +08:00
1 parent 1c0c0f16bc
commit 90989f8f8a
6 files changed
+480 -55

No files matched your search

+8 -22
View File
@@ -1252,19 +1252,15 @@ video {
.p-datatable-header-cell {
white-space: nowrap;
}
.p-datatable-tbody > tr > td {
overflow-wrap: anywhere;
}
/* 视口条件 (width<=768px) 下的响应式覆盖;保留相对基础规则的层叠顺序。 */
@media (width<=768px) {
.p-datatable-table:not(:has(.p-datatable-empty-message)) {
/* 空表、加载与有数据共用断点布局,不能随接口结果切换表头和最小宽度。 */
.p-datatable-table {
min-width: 680px;
}
.p-datatable-table:has(.p-datatable-empty-message) {
table-layout: fixed;
width: 100%;
min-width: 0 !important;
}
.p-datatable-table:has(.p-datatable-empty-message) thead {
display: none;
}
}
/* 尊重减少动态效果偏好:保留状态信息,降低或取消非必要动画。 */
@media (prefers-reduced-motion: reduce) {
@@ -1961,9 +1957,6 @@ video {
max-width: 100%;
overflow: hidden;
}
.list-table:has(.p-datatable-mask):has(.p-datatable-empty-message) {
min-height: 100dvh;
}
.list-table .p-datatable-header-cell {
color: var(--p-text-color);
white-space: nowrap;
@@ -2049,6 +2042,9 @@ video {
position: absolute;
overflow: hidden;
}
.p-datatable .row-actions {
flex-wrap: wrap;
}
.host-list-page .host-row-placeholder {
flex-direction: column;
justify-content: center;
@@ -2070,16 +2066,6 @@ video {
}
/* 视口条件 (width<=768px) 下的响应式覆盖;保留相对基础规则的层叠顺序。 */
@media (width<=768px) {
.list-table:has(.p-datatable-mask)
.p-datatable-table:has(.p-datatable-empty-message) {
table-layout: auto;
min-width: 680px !important;
}
.list-table:has(.p-datatable-mask)
.p-datatable-table:has(.p-datatable-empty-message)
thead {
display: table-header-group;
}
.list-head {
gap: 10px;
}
+38 -31
View File
@@ -11,7 +11,6 @@ import "~/assets/styles/HostList.B3U15sJm.css";
import { nextTick } from "vue";
import { toDisplayString } from "vue";
import { renderList } from "vue";
import { onMounted } from "vue";
import { normalizeClass } from "vue";
import { onBeforeUnmount } from "vue";
import { renderSlot } from "vue";
@@ -667,7 +666,9 @@ var Ye = {
}),
});
((gn.value = T?.page ?? 1), (I.value = T?.limit ?? 20));
let L = computed(() => !hn.value && !F.value),
// 列定义与列表响应一起确认;缓存只有行数据,不能据此猜测本次动态列。
let schemaReady = computed(() => D.value !== null),
L = computed(() => (!hn.value || !schemaReady.value) && !F.value),
bn = computed(() =>
Array.from(
{
@@ -705,19 +706,18 @@ var Ye = {
(onBeforeUnmount(() => {
(O++, En(), (Tn = null));
}),
onMounted(async () => {
(await nextTick(),
requestAnimationFrame(() =>
requestAnimationFrame(() => {
(Tn !== null &&
window.scrollTo({
top: Tn,
behavior: `instant`,
}),
(Tn = null));
}),
));
}),
// 表格与列定义已真实渲染后恢复位置;短加载态不能提前消费长列表的滚动快照。
watch(
() => schemaReady.value && hn.value && !P.value,
async (ready) => {
if (!ready || Tn === null) return;
await nextTick();
if (Tn === null || !schemaReady.value || !hn.value) return;
window.scrollTo({ top: Tn, behavior: `instant` });
Tn = null;
},
{ flush: `post` },
),
watch(
() => w.token,
(e) => {
@@ -1574,37 +1574,43 @@ var Ye = {
`div`,
{
class: `list-table`,
"aria-busy": unref(P) || unref(L),
"aria-busy":
unref(P) || (!unref(schemaReady) && !unref(F)),
},
[
unref(L)
? (openBlock(),
createElementBlock(`span`, nt, `正在读取服务器列表`))
: createCommentVNode(``, !0),
unref(F) && !unref(hn) && !unref(P)
!unref(schemaReady) ||
(unref(F) && !unref(hn) && !unref(P))
? (openBlock(),
createBlock(
p,
{
key: 1,
icon: `pi pi-exclamation-circle`,
title: `服务器加载失败`,
description: unref(F),
icon: unref(F)
? `pi pi-exclamation-circle`
: `pi pi-spin pi-spinner`,
title: unref(F) ? `服务器加载失败` : `加载中…`,
description: unref(F) || `正在读取服务器列表`,
},
{
default: withCtx(() => [
createVNode(u, {
label: `重新加载`,
icon: `pi pi-refresh`,
severity: `secondary`,
size: `small`,
onClick: Dn,
}),
unref(F)
? createVNode(u, {
label: `重新加载`,
icon: `pi pi-refresh`,
severity: `secondary`,
size: `small`,
onClick: Dn,
})
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`description`],
[`icon`, `title`, `description`],
))
: (openBlock(),
createBlock(
@@ -2800,7 +2806,7 @@ var Ye = {
8,
tt,
),
unref(xn).length
unref(schemaReady) && unref(xn).length
? (openBlock(),
createElementBlock(`p`, Nt, [
...(r[21] ||= [
@@ -2885,7 +2891,8 @@ var Ye = {
"host-list-foot-empty": !unref(L) && !unref(mn),
},
]),
inert: unref(L) || !unref(mn) || void 0,
inert:
!unref(schemaReady) || unref(L) || !unref(mn) || void 0,
},
[
createElementVNode(`div`, Ft, [
@@ -2952,7 +2959,7 @@ var Ye = {
10,
Pt,
),
unref(F) && unref(hn)
unref(F) && unref(hn) && unref(schemaReady)
? (openBlock(),
createBlock(
Pe,
+29
View File
@@ -1,8 +1,21 @@
/** OpenVue 客户端统一配置:中文交互文案、蓝色主色以及 .app-dark 暗色切换。 */
import { definePreset } from "@openvue/themes";
import Aura from "@openvue/themes/aura";
import { normalizeStyle } from "vue";
import locale from "./locale.zh-CN.json";
// 列宽只取声明,不让接口数据、骨架或空态参与浏览器的自动列宽分配。
// 百分比宽度原来用于自动布局的伸缩提示;固定布局改用原有最小宽度或统一默认宽度。
function columnWidth(props) {
const style = normalizeStyle([props.style, props.headerStyle]) ?? {};
const width =
style.width && !String(style.width).includes("%") ? style.width : undefined;
const minimum = style.minWidth ?? style["min-width"];
return width && minimum
? `max(${width}, ${minimum})`
: width || minimum || "12rem";
}
// 使用 MIT 许可的主题包,并采用控制台的 blue/slate/zinc 配色。
// 只覆盖 Aura 的语义色阶,保留组件自身设计令牌;浅色用 slate,深色用 zinc。
const preset = definePreset(Aura, {
@@ -46,8 +59,24 @@ export default {
// 列标题与单元格同次渲染,移除手机卡片对后补布局标签的依赖。
pt: {
datatable: {
table: ({ instance }) => ({
style: {
tableLayout: "fixed",
width: "100%",
minWidth: `calc(${
(instance.columns ?? [])
.filter((column) => !column.props?.hidden)
.map((column) => columnWidth(column.props ?? {}))
.join(" + ") || "0px"
})`,
},
}),
column: {
headerCell: ({ props }) => ({
style: { width: columnWidth(props) },
}),
bodyCell: ({ props }) => ({
style: { width: columnWidth(props) },
"data-label":
typeof props.header === "string" ? props.header.trim() : "",
}),