diff --git a/apps/web/app/routes/console/inbox.tsx b/apps/web/app/routes/console/inbox.tsx index c330baef..a38f86d7 100644 --- a/apps/web/app/routes/console/inbox.tsx +++ b/apps/web/app/routes/console/inbox.tsx @@ -25,6 +25,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~ import { Textarea } from "~/components/ui/textarea.tsx"; import { errorMessage } from "~/lib/api.ts"; import { actorText } from "~/lib/labels.ts"; +import { humanizeReason } from "~/lib/reasons.ts"; import { useSse, useSseStatus } from "~/lib/sse.ts"; import { formatDateTime } from "~/lib/utils.ts"; @@ -377,7 +378,9 @@ function DecisionCard({ d }: { d: Decision }) {

{d.title}

- {d.summary ?

{d.summary}

: null} + {d.summary ? ( +

{humanizeReason(d.summary)}

+ ) : null}
diff --git a/apps/web/app/routes/console/organize.$id.tsx b/apps/web/app/routes/console/organize.$id.tsx index 07b9a6e1..59aafd47 100644 --- a/apps/web/app/routes/console/organize.$id.tsx +++ b/apps/web/app/routes/console/organize.$id.tsx @@ -179,7 +179,7 @@ export default function OrganizeRecordPage() { {RECORD_STATUS_LABEL[r.status]} {[ - `${TRIGGER_LABEL[r.trigger]}${ACTION_LABEL[r.action]}`, + `${ACTION_LABEL[r.action]} · ${TRIGGER_LABEL[r.trigger]}`, r.counts.total ? `${r.counts.succeeded}/${r.counts.total} 个文件成功` : null, r.counts.failed ? `${r.counts.failed} 个失败` : null, r.counts.skipped ? `${r.counts.skipped} 个跳过` : null, diff --git a/apps/web/scripts/.deai2-shots.mjs b/apps/web/scripts/.deai2-shots.mjs new file mode 100644 index 00000000..e2da93af --- /dev/null +++ b/apps/web/scripts/.deai2-shots.mjs @@ -0,0 +1,37 @@ +import { existsSync } from "node:fs"; +import { chromium } from "playwright-core"; +const OUT = "/opt/uhd_media_tool-deai2/apps/web/test/screenshots/deai2"; +const PAGES = [ + ["01-home", "/console"], + ["02-inbox", "/console/inbox"], + ["03-schedules", "/console/schedules"], + ["04-agent-run", "/console/agent/a01dccf0-383f-46a9-acec-c2ca3cf571f8"], + ["05-organize-detail", "/console/organize/33000000-0000-4000-8000-000000000903"], + ["06-download-detail", "/console/downloads/33000000-0000-4000-8000-000000000802"], + ["07-tasks", "/console/tasks"], + ["08-settings-interface", "/console/settings#interface"], +]; +const exe = ["/usr/bin/chromium", "/usr/bin/google-chrome"].find((p) => existsSync(p)); +const browser = await chromium.launch({ executablePath: exe, headless: true, args: ["--no-sandbox"] }); +for (const [tag, port] of (process.env.ONLY === "after" ? [["after", 5192]] : [["before", 5191], ["after", 5192]])) { + const base = `http://127.0.0.1:${port}`; + for (const [mode, vp, theme] of [["desk-light", { width: 1440, height: 900 }, "light"], ["desk-dark", { width: 1440, height: 900 }, "dark"], ["mobile", { width: 390, height: 844 }, "light"]]) { + const ctx = await browser.newContext({ viewport: vp, colorScheme: theme, deviceScaleFactor: mode === "mobile" ? 2 : 1 }); + await ctx.addInitScript((t) => localStorage.setItem("umt-theme", t), theme); + const page = await ctx.newPage(); + await page.goto(`${base}/login`, { waitUntil: "networkidle" }); + await page.fill("#username", "w31-admin"); + await page.fill("#password", "deai2-shots-pass"); + await page.click('button[type="submit"]'); + await page.waitForURL((u) => u.pathname.startsWith("/console"), { timeout: 20_000 }); + for (const [name, path] of PAGES) { + if (tag === "before" && name === "08-settings-interface") continue; + await page.goto(base + path, { waitUntil: "networkidle" }).catch(() => {}); + await page.waitForTimeout(1500); + await page.screenshot({ path: `${OUT}/${name}-${mode}-${tag}.png`, fullPage: true }); + } + await ctx.close(); + } +} +await browser.close(); +console.log("done"); diff --git a/docs/design/de-ai-review.md b/docs/design/de-ai-review.md index 68d75b89..df733f38 100644 --- a/docs/design/de-ai-review.md +++ b/docs/design/de-ai-review.md @@ -320,3 +320,53 @@ 5. **首页是否删掉「运行状态」「计划」两块**,只在异常时出现。 6. **「收录」「建档」两个词是否全站退场**,换成「加入媒体库 / 在媒体库 / 已下载」。 7. **Agent 会话里「模型说的(未经核查)」这层防护是否保留**。建议保留一个很轻的标记(回复旁一行「以下是模型的说法」),删掉另外两处。 + +## 6. DEAI-2 处理情况(2026-09-29) + +用户拍板(见 `docs/plan/00-first-version-plan.md`):「版本目标」→「收录版本」;「Agent 上游」→「模型服务」;界面上的 Agent → 「智能体」;技术信息默认折叠(设置 → 界面可默认展开);首页只留三块;计划页维护类收成「数据清理」、智能体巡检置顶;「未经核查」只在最终汇报留一处。术语落地见 [glossary.md](glossary.md)。 + +### P0 + +| # | 状态 | 说明 | +| --- | --- | --- | +| 1 | 完成 | 原因码表 `packages/contracts/src/reasons.ts`,服务端整理记录 message、冲突事项标题/摘要与前端(整理记录、下载时间线、待处理摘要、任务详情)共用;原码进「技术信息」 | +| 2 | 完成 | 「指定作品」主按钮:搜媒体库 + TMDB,走已有 decision resolve(local_entity / manual_tmdb);整理类事项打开重新整理,整理成功后自动关闭事项 | +| 3 | 完成 | 首页状态行按数据说话,0 订阅写「还没有订阅。去搜索添加」 | +| 4 | 部分 | 下载详情在「下载完成但最近一次整理失败」时单独提示入库失败并链到待处理;下载列表行状态未改——需要服务端在下载任务上带最近整理结果,QB-1 正在改整理服务,留给合并后另做 | +| 5 | 完成 | 只读对账移出首页,放进设置 → 自动化 →「高级」 | +| 6 | 完成 | 统一为「没识别出作品」(事项);未确认身份的资源叫「未识别」 | + +### P1 + +| # | 状态 | 说明 | +| --- | --- | --- | +| 1 | 完成 | 见提交说明;对话组件结构不动(另有代理出易用性方案) | +| 2 | 完成 | 删口号;悬浮按钮只在无侧栏的窄屏出现,抽屉打开时不再显示胶囊 | +| 3 | 完成 | 默认隐藏系统任务(可一键显示),标题不用 ID | +| 4 | 完成 | 维护类合成「数据清理」组;自动任务按分类折叠并记忆;说明去表名 | +| 5 | 完成 | | +| 6 | 完成 | 约 14 处页描述删除或改一句 | +| 7 | 完成 | 首页、站点卡、下载、待处理、文件管理、整理记录 | +| 8 | 完成 | RSS、媒体库、建档 / 收录、资产、账本、纳管、哨兵、快照;「外部身份」一词在作品详情改「匹配的 TMDB 条目」,其余处保留 | +| 9 | 完成 | UUID、字段来源、别名全集、路径核验 | + +### P2 + +| # | 状态 | 说明 | +| --- | --- | --- | +| 1 | 完成 | `formatUsd`、`formatDuration` | +| 2 | 完成 | | +| 3 | 部分 | 自动化分区的只读对账 / 存储预算 / 流水保留 / 缓存有效期收进「高级」;会话目录与 fake 脚本只在开发构建显示;没有在 contracts 加 `advanced` 标记(纯前端即可) | +| 4 | 完成 | 进程、趋势、最大表折叠;图例同名序列加序号 | +| 5 | 完成 | | +| 6 | 完成 | | +| 7 | 完成 | | +| 8 | 不做 | 用户栈数据,不是代码 | + +### 页面级条目中不做的 + +- 05b 站点概况的配置回显、05c 资源行「已识别,无收录版本」、「实时补查」按钮位置:DETAIL-1 / SEARCH-3 正在改站点详情与资源列表,只改了名词(抓取、去站点搜),结构留给它们。 +- 10 整理记录里连续的 0 文件失败行合并:需要服务端按下载任务聚合,放到 QB-1 合并之后。 +- 12 媒体库页签只留「作品 / 未识别」、「未命中订阅」不进未识别:DH-1 正在改身份服务,避免冲突。 +- 13-settings-agent MCP 区块的能力计数与接入说明移到文档:保留,只改了一句说明。 +- 14 「已下线实例 N 个」文案:已随进程区折叠,文案不改。 diff --git a/packages/contracts/src/reasons.ts b/packages/contracts/src/reasons.ts index 79fe46c7..a6cd04f5 100644 --- a/packages/contracts/src/reasons.ts +++ b/packages/contracts/src/reasons.ts @@ -38,6 +38,8 @@ const REASONS: Record = { already_in_library: { text: "已在媒体库里" }, main_not_transferred: { text: "主文件没有整理,附属文件一起跳过" }, timeout: { text: "操作超时", action: "稍后重试" }, + downloader_unavailable: { text: "下载器连不上", action: "在设置 → 下载器里测试连接" }, + downloader_error: { text: "下载器报错", action: "查看下载器日志" }, }; /**