优化(前端): 清理资料研究导入冲突并实施全功能路由懒加载与错误边界

This commit is contained in:
zizi 2026-09-21 21:12:38 +08:00
parent 00aa5e3238
commit d5e338ad97
5 changed files with 245 additions and 74 deletions

View File

@ -118,7 +118,6 @@ export async function 发起拆书(
输入: { config_id: string; reason?: string | null }, 输入: { config_id: string; reason?: string | null },
) { ) {
if (!输入.config_id.trim()) throw new Error("请明确指定已启用的分析配置。"); if (!输入.config_id.trim()) throw new Error("请明确指定已启用的分析配置。");
const { 客户端 } = await import("../../接口/生成/客户端");
const { data, error } = await 客户端.POST( const { data, error } = await 客户端.POST(
"/api/v1/sources/{source_id}/analyses", "/api/v1/sources/{source_id}/analyses",
{ {
@ -136,7 +135,6 @@ export async function 发起拆书(
} }
export async function 恢复拆书(taskId: string) { export async function 恢复拆书(taskId: string) {
const { 客户端 } = await import("../../接口/生成/客户端");
const { data, error } = await 客户端.POST( const { data, error } = await 客户端.POST(
"/api/v1/analyses/{task_id}/resume", "/api/v1/analyses/{task_id}/resume",
{ {

View File

@ -1,5 +1,6 @@
/** 资料对照页:来源版本原文、清理候选对照与榜单快照(含失败态)。 */ /** 资料对照页:来源版本原文、清理候选对照与榜单快照(含失败态)。 */
import { useState } from "react"; import { useState } from "react";
import { 客户端 } from "../../接口/生成/客户端";
import { useMuse来源列表, useMuse版本原文 } from "./数据"; import { useMuse来源列表, useMuse版本原文 } from "./数据";
import { Ui反馈状态 } from "../../界面/反馈状态"; import { Ui反馈状态 } from "../../界面/反馈状态";
import { useMuse作者会话 } from "../../应用/作者会话"; import { useMuse作者会话 } from "../../应用/作者会话";
@ -14,12 +15,12 @@ export function Ui资料页() {
async function 生成并应用(sourceId: string, revision: number) { async function 生成并应用(sourceId: string, revision: number) {
try { try {
const { data, error } = await (await import("../../接口/生成/客户端")).客户端.POST( const { data, error } = await 客户端.POST(
"/api/v1/sources/{source_id}/versions/{revision}/clean-candidates", "/api/v1/sources/{source_id}/versions/{revision}/clean-candidates",
{ params: { path: { source_id: sourceId, revision } } }, { params: { path: { source_id: sourceId, revision } } },
); );
if (!data) throw new Error((error as { message?: string })?.message ?? "生成失败"); if (!data) throw new Error((error as { message?: string })?.message ?? "生成失败");
const apply = await (await import("../../接口/生成/客户端")).客户端.POST( const apply = await 客户端.POST(
"/api/v1/clean-candidates/{candidate_id}/apply", "/api/v1/clean-candidates/{candidate_id}/apply",
{ params: { path: { candidate_id: (data as { candidate_id: string }).candidate_id } } }, { params: { path: { candidate_id: (data as { candidate_id: string }).candidate_id } } },
); );

View File

@ -1,76 +1,186 @@
import { lazy, Suspense } from "react";
import { Navigate, Route, Routes } from "react-router-dom"; import { Navigate, Route, Routes } from "react-router-dom";
import { Ui审校页, Ui声音页, Ui规则页 } from "../功能/审校修订"; import { Ui反馈状态 } from "../界面/反馈状态";
import { Ui任务列表 } from "../功能/任务运行"; import { Ui页面错误边界 } from "./页面错误边界";
import { Ui实验页 } from "../功能/效果评测";
import { // 首屏核心静态保留:轻量作品列表
Ui作品首页, import { Ui作品首页 } from "../功能/作品规划/作品首页";
Ui作品档案,
Ui探索工作区, // 其余功能页路由级懒加载(精准具体页面入口,避免聚合出口产生重叠打包)
Ui规划工作区, const Ui探索工作区 = lazy(() =>
} from "../功能/作品规划"; import("../功能/作品规划/探索工作区").then((m) => ({ default: m.Ui探索工作区 })),
import { Ui候选审阅页, Ui正文页 } from "../功能/正文写作"; );
import { Ui资料页, Ui拆书工作区, Ui榜单与选题页 } from "../功能/资料研究"; const Ui作品档案 = lazy(() =>
import { Ui世界资料页, Ui人物关系页, Ui时间与伏笔页 } from "../功能/故事世界"; import("../功能/作品规划/作品档案").then((m) => ({ default: m.Ui作品档案 })),
import { Ui方法库页, Ui方法详情, Ui版本绑定 } from "../功能/知识方法"; );
import { Ui偏好页, Ui反馈对照, Ui改进提案页 } from "../功能/作者经验"; const Ui规划工作区 = lazy(() =>
import { import("../功能/作品规划/规划工作区").then((m) => ({ default: m.Ui规划工作区 })),
Ui全书整理页, );
Ui定稿导出页,
Ui连载计划页, // 正文写作与审阅(含富文本编辑器重依赖)
Ui读者反馈页, const Ui正文页 = lazy(() =>
} from "../功能/交付连载"; import("../功能/正文写作/正文页").then((m) => ({ default: m.Ui正文页 })),
import { Ui连接与模型页, Ui数据管理页, Ui备份恢复页 } from "../功能/系统管理"; );
const Ui候选审阅页 = lazy(() =>
import("../功能/正文写作/候选审阅").then((m) => ({ default: m.Ui候选审阅页 })),
);
// 审校修订
const Ui审校页 = lazy(() =>
import("../功能/审校修订/审校页").then((m) => ({ default: m.Ui审校页 })),
);
const Ui声音页 = lazy(() =>
import("../功能/审校修订/声音档案").then((m) => ({ default: m.Ui声音页 })),
);
const Ui规则页 = lazy(() =>
import("../功能/审校修订/规则页").then((m) => ({ default: m.Ui规则页 })),
);
// 任务运行与效果评测
const Ui任务列表 = lazy(() =>
import("../功能/任务运行/任务列表").then((m) => ({ default: m.Ui任务列表 })),
);
const Ui实验页 = lazy(() =>
import("../功能/效果评测/实验页").then((m) => ({ default: m.Ui实验页 })),
);
// 故事世界
const Ui世界资料页 = lazy(() =>
import("../功能/故事世界/世界资料页").then((m) => ({ default: m.Ui世界资料页 })),
);
const Ui人物关系页 = lazy(() =>
import("../功能/故事世界/人物关系页").then((m) => ({ default: m.Ui人物关系页 })),
);
const Ui时间与伏笔页 = lazy(() =>
import("../功能/故事世界/时间与伏笔页").then((m) => ({ default: m.Ui时间与伏笔页 })),
);
// 资料研究
const Ui资料页 = lazy(() =>
import("../功能/资料研究/资料页").then((m) => ({ default: m.Ui资料页 })),
);
const Ui拆书工作区 = lazy(() =>
import("../功能/资料研究/拆书工作区").then((m) => ({ default: m.Ui拆书工作区 })),
);
const Ui榜单与选题页 = lazy(() =>
import("../功能/资料研究/榜单与选题页").then((m) => ({ default: m.Ui榜单与选题页 })),
);
// 知识方法
const Ui方法库页 = lazy(() =>
import("../功能/知识方法/方法库页").then((m) => ({ default: m.Ui方法库页 })),
);
const Ui方法详情 = lazy(() =>
import("../功能/知识方法/方法详情").then((m) => ({ default: m.Ui方法详情 })),
);
const Ui版本绑定 = lazy(() =>
import("../功能/知识方法/版本绑定").then((m) => ({ default: m.Ui版本绑定 })),
);
// 交付连载
const Ui全书整理页 = lazy(() =>
import("../功能/交付连载/全书整理页").then((m) => ({ default: m.Ui全书整理页 })),
);
const Ui定稿导出页 = lazy(() =>
import("../功能/交付连载/定稿导出页").then((m) => ({ default: m.Ui定稿导出页 })),
);
const Ui连载计划页 = lazy(() =>
import("../功能/交付连载/连载计划页").then((m) => ({ default: m.Ui连载计划页 })),
);
const Ui读者反馈页 = lazy(() =>
import("../功能/交付连载/读者反馈页").then((m) => ({ default: m.Ui读者反馈页 })),
);
// 系统管理
const Ui连接与模型页 = lazy(() =>
import("../功能/系统管理/连接与模型页").then((m) => ({ default: m.Ui连接与模型页 })),
);
const Ui数据管理页 = lazy(() =>
import("../功能/系统管理/数据管理页").then((m) => ({ default: m.Ui数据管理页 })),
);
const Ui备份恢复页 = lazy(() =>
import("../功能/系统管理/备份恢复页").then((m) => ({ default: m.Ui备份恢复页 })),
);
// 作者经验
const Ui偏好页 = lazy(() =>
import("../功能/作者经验/偏好页").then((m) => ({ default: m.Ui偏好页 })),
);
const Ui反馈对照 = lazy(() =>
import("../功能/作者经验/反馈对照").then((m) => ({ default: m.Ui反馈对照 })),
);
const Ui改进提案页 = lazy(() =>
import("../功能/作者经验/改进提案页").then((m) => ({ default: m.Ui改进提案页 })),
);
export function Ui页面路由() { export function Ui页面路由() {
return ( return (
<Routes> <Ui页面错误边界>
<Route path="/works" element={<Ui作品首页 />} /> <Suspense
<Route path="/explorations/:draft_id?" element={<Ui探索工作区 />} /> fallback={
<Route path="/works/:work_id/profile" element={<Ui作品档案 />} /> <main className="content">
<Route path="/works/:work_id/plans" element={<Ui规划工作区 />} /> <div className="page-heading">
<Route path="/works/:work_id/write/:chapter_id?" element={<Ui正文页 />} /> <Ui反馈状态 message="正在载入页面组件…" />
<Route </div>
path="/works/:work_id/candidates/:chapter_id" </main>
element={<Ui候选审阅页 />} }
/> >
<Route path="/works/:work_id/review" element={<Ui审校页 />} /> <Routes>
<Route path="/works/:work_id/voice" element={<Ui声音页 />} /> <Route path="/works" element={<Ui作品首页 />} />
<Route path="/works/:work_id/delivery" element={<Ui全书整理页 />} /> <Route path="/explorations/:draft_id?" element={<Ui探索工作区 />} />
<Route <Route path="/works/:work_id/profile" element={<Ui作品档案 />} />
path="/works/:work_id/delivery/export/:delivery_id?" <Route path="/works/:work_id/plans" element={<Ui规划工作区 />} />
element={<Ui定稿导出页 />} <Route
/> path="/works/:work_id/write/:chapter_id?"
<Route path="/works/:work_id/serial" element={<Ui连载计划页 />} /> element={<Ui正文页 />}
<Route />
path="/works/:work_id/reader-feedback" <Route
element={<Ui读者反馈页 />} path="/works/:work_id/candidates/:chapter_id"
/> element={<Ui候选审阅页 />}
<Route path="/review-rules" element={<Ui规则页 />} /> />
<Route path="/tasks" element={<Ui任务列表 />} /> <Route path="/works/:work_id/review" element={<Ui审校页 />} />
<Route path="/evaluations/:experiment_id?" element={<Ui实验页 />} /> <Route path="/works/:work_id/voice" element={<Ui声音页 />} />
<Route path="/works/:work_id/world" element={<Ui世界资料页壳 />} /> <Route path="/works/:work_id/delivery" element={<Ui全书整理页 />} />
<Route <Route
path="/works/:work_id/world/relations" path="/works/:work_id/delivery/export/:delivery_id?"
element={<Ui人物关系页壳 />} element={<Ui定稿导出页 />}
/> />
<Route <Route path="/works/:work_id/serial" element={<Ui连载计划页 />} />
path="/works/:work_id/world/timeline" <Route
element={<Ui时间与伏笔页Shell />} path="/works/:work_id/reader-feedback"
/> element={<Ui读者反馈页 />}
<Route path="/sources" element={<Ui资料页 />} /> />
<Route path="/research" element={<Ui拆书工作区 />} /> <Route path="/review-rules" element={<Ui规则页 />} />
<Route path="/rankings" element={<Ui榜单与选题页 />} /> <Route path="/tasks" element={<Ui任务列表 />} />
<Route path="/methods" element={<Ui方法库页Shell />} /> <Route path="/evaluations/:experiment_id?" element={<Ui实验页 />} />
<Route path="/methods/:method_id" element={<Ui方法详情壳 />} /> <Route path="/works/:work_id/world" element={<Ui世界资料页壳 />} />
<Route path="/works/:work_id/methods" element={<Ui版本绑定壳 />} /> <Route
<Route path="/system" element={<Ui连接与模型页 />} /> path="/works/:work_id/world/relations"
<Route path="/system/data" element={<Ui数据管理页 />} /> element={<Ui人物关系页壳 />}
<Route path="/system/backups" element={<Ui备份恢复页 />} /> />
<Route path="/preferences" element={<Ui偏好页 />} /> <Route
<Route path="/feedback/:feedback_id" element={<Ui反馈对照 />} /> path="/works/:work_id/world/timeline"
<Route path="/improvements/:improvement_id?" element={<Ui改进提案页 />} /> element={<Ui时间与伏笔页Shell />}
<Route path="*" element={<Navigate to="/works" replace />} /> />
</Routes> <Route path="/sources" element={<Ui资料页 />} />
<Route path="/research" element={<Ui拆书工作区 />} />
<Route path="/rankings" element={<Ui榜单与选题页 />} />
<Route path="/methods" element={<Ui方法库页Shell />} />
<Route path="/methods/:method_id" element={<Ui方法详情壳 />} />
<Route path="/works/:work_id/methods" element={<Ui版本绑定壳 />} />
<Route path="/system" element={<Ui连接与模型页 />} />
<Route path="/system/data" element={<Ui数据管理页 />} />
<Route path="/system/backups" element={<Ui备份恢复页 />} />
<Route path="/preferences" element={<Ui偏好页 />} />
<Route path="/feedback/:feedback_id" element={<Ui反馈对照 />} />
<Route
path="/improvements/:improvement_id?"
element={<Ui改进提案页 />}
/>
<Route path="*" element={<Navigate to="/works" replace />} />
</Routes>
</Suspense>
</Ui页面错误边界>
); );
} }

View File

@ -0,0 +1,62 @@
import { Component, type ErrorInfo, type ReactNode } from "react";
import { Ui反馈状态 } from "../界面/反馈状态";
interface Props {
children: ReactNode;
}
interface State {
hasError: boolean;
error: Error | null;
}
export class Ui页面错误边界 extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error("页面加载或渲染失败:", error, errorInfo);
}
重试 = () => {
this.setState({ hasError: false, error: null });
};
render() {
if (this.state.hasError) {
return (
<main className="content">
<div className="page-heading">
<div>
<p className="eyebrow">加载受阻</p>
<h1>页面未正常载入</h1>
<p className="muted">可能是网络暂时中断或应用版本已更新。</p>
</div>
</div>
<Ui反馈状态
error
message={
this.state.error?.message ||
"页面组件加载失败,请尝试重新载入。"
}
/>
<div style={{ marginTop: "1rem", display: "flex", gap: "0.5rem" }}>
<button className="primary" onClick={this.重试}>
重新尝试加载
</button>
<button onClick={() => window.location.assign("/works")}>
返回作品首页
</button>
</div>
</main>
);
}
return this.props.children;
}
}

File diff suppressed because one or more lines are too long