diff --git a/web-next/src/pages/update/UpdatePage.tsx b/web-next/src/pages/update/UpdatePage.tsx index 8fdd7b9..64c836f 100644 --- a/web-next/src/pages/update/UpdatePage.tsx +++ b/web-next/src/pages/update/UpdatePage.tsx @@ -273,6 +273,7 @@ export default function UpdatePage({ const [actionBusy, setActionBusy] = useState(false); const [reloadReady, setReloadReady] = useState(false); const [showNotesDialog, setShowNotesDialog] = useState(false); + const [showPipelineDialog, setShowPipelineDialog] = useState(false); const [now, setNow] = useState(() => Date.now()); const announced = useRef(null); @@ -338,6 +339,10 @@ export default function UpdatePage({ }, [isMock]); const job = info?.job; + useEffect(() => { + if (job && activeStatuses.has(job.status)) setShowPipelineDialog(true); + }, [job?.id, job?.status]); + const applyQueuedAt = timestamp(job?.applyQueuedAt); const restartAt = timestamp(job?.restartDeadline) ?? @@ -468,6 +473,7 @@ export default function UpdatePage({ mockTimer.current = null; setActionBusy(false); setConfirmVersion(null); + setShowPipelineDialog(true); if (confirmAction === "download") { handleScenarioChange("downloading_30"); notify?.("Mock:开始模拟下载,状态已流转至 [下载中]", "info"); @@ -496,6 +502,7 @@ export default function UpdatePage({ setConfirmVersion(null); setReloadReady(false); setLiveInfo((current) => (current ? { ...current, job: result.job } : current)); + setShowPipelineDialog(true); notify?.( confirmAction === "download" ? "更新包下载已开始" : "更新已开始,服务会短暂重启", "info" @@ -715,11 +722,18 @@ export default function UpdatePage({ - {/* Stepper Process Card */} - + {/* Stepper Process Dialog */} + setShowPipelineDialog(false)} + onClose={() => setShowPipelineDialog(false)} + > +
-

版本升级流水线

标准化发布流程:版本发现 → 校验签名与清单 → 安全暂存 → 原子切换并重启 @@ -834,7 +848,8 @@ export default function UpdatePage({ 更新成功完成!新版本已通过内置端点健康检查,账本数据与附件完整无损。
)} - +
+
{/* Release Details Section */} {latest ? ( @@ -856,32 +871,8 @@ export default function UpdatePage({ )} -
- {notes && ( - - )} -
- {/* Release Notes Preview snippet */} - {notes && ( -
-
- 更新内容概览 -
-
- -
-
- )} - {/* Integrity & compatibility facts grid */}
@@ -963,6 +954,30 @@ export default function UpdatePage({ )} + {latest && notes && ( + +
+
+ 更新日志 +

本次版本更新内容

+
+ +
+
+
+ +
+
+
+ )} + {/* Manual source warning if not systemd */} {!info.configured && (
diff --git a/web-next/src/styles/theme.css b/web-next/src/styles/theme.css index 2a3bf84..44f8f88 100644 --- a/web-next/src/styles/theme.css +++ b/web-next/src/styles/theme.css @@ -847,6 +847,17 @@ input:focus-visible, textarea:focus-visible, select:focus-visible { margin-bottom: 16px; padding: 20px; } +.tn-release-notes-surface { + margin-bottom: 16px; + padding: 20px; +} +.tn-release-notes-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + margin-bottom: 12px; +} .tn-release-header { display: flex; align-items: flex-start; @@ -870,7 +881,7 @@ input:focus-visible, textarea:focus-visible, select:focus-visible { color: var(--tn-text-secondary); } .tn-release-notes-box { - margin: 16px 0; + margin: 0; padding: 12px 16px; background: #f8fafc; border: 1px solid var(--tn-border); @@ -1064,6 +1075,13 @@ input:focus-visible, textarea:focus-visible, select:focus-visible { .tn-release-header { flex-direction: column; } + .tn-release-notes-header { + align-items: flex-start; + flex-direction: column; + } + .tn-release-notes-header .t-button { + width: 100%; + } .tn-release-card-actions { flex-direction: column; width: 100%;