fix(reports): 生成报告 shows the curtain and opens the report; 年运 veil fills the page (BUG-1630)
The report center passed onCreated={() => void load()}, so a successful create
only re-read the list below: no move, no notice, a faint 「正在创建…」 at most.
The button now holds the page curtain while it submits and opens the created
report, whose page shows the writing progress; an error drops the curtain and
says why. The 年运 page took the content's height inside the start-aligned
page grid, so its veil stopped short of the window bottom; it now fills the cell.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
This commit is contained in:
@@ -22240,3 +22240,18 @@
|
||||
- 关联记录:BUG-1628(打开期间的幕布)、BUG-1516(入口「继续 / 新建一次」)、issue #124(校正界面代码与开案并行下载)。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `feat/global-boot-loader`。
|
||||
|
||||
## BUG-1630 | 点「生成报告」没有任何反应;年运页遮罩下面多出一块黑色
|
||||
|
||||
- 状态:fixed-pending-verify(代码 + 回归测试;登录态真机未测)
|
||||
- 首次发现 / 最近更新:2026-11-05(产品负责人截图反馈)/ 2026-11-05
|
||||
- 影响面:`frontend/src/components/personal-report/generate-personal-report-button.tsx`、`personal-report-center.tsx`、`app/annual-report.css`。
|
||||
- 现象:① 我的报告页点「完整本命报告 · 生成报告」,看不到任何动画、提示或跳转(报告其实已创建并写完,列表里出现了当天的「已完成」)。② 年运页开始前的半透明遮罩只盖到内容高度,下面露出一条更深的底色。
|
||||
- 触发条件:① 报告中心点生成报告且创建成功。② 年运页内容高度小于窗口。
|
||||
- 根因:① 报告中心给按钮传了 `onCreated={() => void load()}`,成功后不跳转、不提示,只悄悄重读下面的列表;等待中只有按钮文字变成浅色「正在创建…」。② `.secondary-page` 是 `align-content: start` 的网格,`.annual-page` 的 `height: 100%` 只取到内容高度,绝对定位的遮罩随之变短。
|
||||
- 修复:① 按钮在提交期间立即持有整窗页面幕布(「正在创建报告」),成功后跳到该报告页(报告页自己显示写作进度),幕布一直留到报告页接手;失败照旧弹出原因并撤下幕布。报告中心不再传 `onCreated`。② `.secondary-page:has(> .annual-page)` 改为单行 `minmax(0, 1fr)` 并拉伸,年运页填满页面主体。
|
||||
- 验证:新增 `frontend/tests/report-create-feedback-1630.test.ts` 2 条;报告与年运相关测试 212 条全绿;`tsc --noEmit` 0 错;改动文件 eslint 0 error。
|
||||
- 防复发:任何「创建 / 提交」按钮成功后必须有可见结果(跳转或提示),不得只静默刷新;等待期间用页面幕布或按钮内的同一动画,不只改按钮文字。
|
||||
- 关联记录:BUG-1613(页面幕布)、BUG-1611(年运写一半失败)。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `feat/global-boot-loader`。
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
padding: var(--space-10) var(--space-8) var(--space-16);
|
||||
}
|
||||
.annual-page.is-veiled { overflow: hidden; }
|
||||
/* The page body's grid lines content up at the top, so `height: 100%` above
|
||||
resolved to the content's height and the veil stopped short of the window
|
||||
bottom, leaving a bare band under it (BUG-1630). The annual page fills the cell. */
|
||||
.secondary-page:has(> .annual-page) { grid-template-rows: minmax(0, 1fr); align-content: stretch; }
|
||||
@media (max-width: 720px) { .annual-page { padding: var(--space-6) var(--space-4) var(--space-12); } }
|
||||
|
||||
.annual-report {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { navigateAppPath } from "@/lib/app-navigation";
|
||||
import { notifyError } from "@/lib/notify";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { usePageCurtain } from "@/hooks/use-page-curtain";
|
||||
|
||||
export { DEFAULT_REPORT_THEMES };
|
||||
|
||||
@@ -146,6 +147,10 @@ export function GeneratePersonalReportButton({
|
||||
const router = useRouter();
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const inFlight = useRef(false);
|
||||
// The click shows at once (BUG-1630, product: 「点击生成报告没有任何反应也没有动画」):
|
||||
// the page curtain covers the create request and the move to the report,
|
||||
// whose own page then shows the writing progress. An error drops it and says why.
|
||||
usePageCurtain(submitting, { title: "正在创建报告", detail: "提交给报告服务", immediate: true });
|
||||
|
||||
async function handleGenerate() {
|
||||
if (inFlight.current || submitting) {
|
||||
@@ -153,6 +158,7 @@ export function GeneratePersonalReportButton({
|
||||
}
|
||||
inFlight.current = true;
|
||||
setSubmitting(true);
|
||||
let navigating = false;
|
||||
try {
|
||||
const requestId = createReportRequestId();
|
||||
if (requestId === null) {
|
||||
@@ -177,6 +183,8 @@ export function GeneratePersonalReportButton({
|
||||
if (onCreated) {
|
||||
onCreated(outcome.reportId);
|
||||
} else {
|
||||
// Leaving for the report: the curtain stays up until its page holds it.
|
||||
navigating = true;
|
||||
navigateAppPath(
|
||||
`/reports/${encodeURIComponent(outcome.reportId)}`,
|
||||
(href) => router.push(href),
|
||||
@@ -189,7 +197,7 @@ export function GeneratePersonalReportButton({
|
||||
notifyError("网络异常,请检查连接后重试。");
|
||||
} finally {
|
||||
inFlight.current = false;
|
||||
setSubmitting(false);
|
||||
if (!navigating) setSubmitting(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -293,7 +293,10 @@ export function PersonalReportCenter() {
|
||||
<h2 id="report-center-create-title">完整本命报告</h2>
|
||||
<p>星盘、力量、大运和瑜伽,中英两版</p>
|
||||
</div>
|
||||
<GeneratePersonalReportButton onCreated={() => void load()} />
|
||||
{/* BUG-1630: a created report opens at once (its page shows the writing
|
||||
progress) behind the page curtain; it used to only re-read this list,
|
||||
so the click looked like it did nothing. */}
|
||||
<GeneratePersonalReportButton />
|
||||
</section>
|
||||
{/* #154: the annual entry opens the annual report page directly (no entry page). */}
|
||||
<section className="report-center-entry" aria-labelledby="report-center-annual-title">
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import test from "node:test";
|
||||
|
||||
// BUG-1630(2026-11-05 产品:「点击生成报告没有任何反应也没有动画,也没有提醒」;「年运下面怎么还多一块黑色」)。
|
||||
|
||||
const read = (path: string) => readFileSync(new URL(path, import.meta.url), "utf8");
|
||||
|
||||
test("生成报告 holds the page curtain at once and opens the created report", () => {
|
||||
const button = read("../src/components/personal-report/generate-personal-report-button.tsx");
|
||||
assert.match(button, /usePageCurtain\(submitting, \{ title: "正在创建报告", detail: "提交给报告服务", immediate: true \}\);/);
|
||||
assert.match(button, /navigating = true;\n\s+navigateAppPath\(/);
|
||||
assert.match(button, /if \(!navigating\) setSubmitting\(false\);/);
|
||||
const center = read("../src/components/personal-report/personal-report-center.tsx");
|
||||
// 原值:<GeneratePersonalReportButton onCreated={() => void load()} />(成功后只重读列表,看起来没反应)
|
||||
assert.match(center, /<GeneratePersonalReportButton \/>/);
|
||||
assert.doesNotMatch(center, /onCreated=\{/);
|
||||
});
|
||||
|
||||
test("the 年运 page fills the page body, so its veil reaches the window bottom", () => {
|
||||
const css = read("../src/app/annual-report.css");
|
||||
assert.match(css, /\.secondary-page:has\(> \.annual-page\) \{ grid-template-rows: minmax\(0, 1fr\); align-content: stretch; \}/);
|
||||
});
|
||||
Reference in New Issue
Block a user