fix: refine mobile project verification
This commit is contained in:
@@ -569,6 +569,46 @@ await page.setViewportSize({ width: 390, height: 844 })
|
|||||||
await page.waitForFunction(() => [...document.querySelectorAll('.project-rail, .channel-sidebar')]
|
await page.waitForFunction(() => [...document.querySelectorAll('.project-rail, .channel-sidebar')]
|
||||||
.every((node) => getComputedStyle(node).visibility === 'hidden'))
|
.every((node) => getComputedStyle(node).visibility === 'hidden'))
|
||||||
const mobileProjectMetrics = await collectMetrics()
|
const mobileProjectMetrics = await collectMetrics()
|
||||||
|
const mobileProjectOverviewLayout = await page.evaluate(() => {
|
||||||
|
const hero = document.querySelector('.project-overview-hero')
|
||||||
|
const heroTitle = document.querySelector('.project-overview-identity h3')
|
||||||
|
const shareButton = document.querySelector('.project-overview-share .arco-btn')
|
||||||
|
const metricColumns = [...document.querySelectorAll('.project-overview-page > .metric-row > .arco-col')]
|
||||||
|
const metricLabels = [...document.querySelectorAll('.project-overview-page .metric-card .arco-typography-secondary')]
|
||||||
|
const lineCount = (node) => {
|
||||||
|
if (!node) return 0
|
||||||
|
const styles = getComputedStyle(node)
|
||||||
|
const lineHeight = Number.parseFloat(styles.lineHeight)
|
||||||
|
return lineHeight > 0 ? Math.round(node.getBoundingClientRect().height / lineHeight) : 0
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
viewportWidth: document.documentElement.clientWidth,
|
||||||
|
hero: hero?.getBoundingClientRect().toJSON() ?? null,
|
||||||
|
heroTitle: heroTitle ? { ...heroTitle.getBoundingClientRect().toJSON(), lines: lineCount(heroTitle) } : null,
|
||||||
|
shareButton: shareButton?.getBoundingClientRect().toJSON() ?? null,
|
||||||
|
metricColumnLefts: metricColumns.map((column) => Math.round(column.getBoundingClientRect().left)),
|
||||||
|
metricLabels: metricLabels.map((label) => ({
|
||||||
|
text: label.textContent?.trim() ?? '',
|
||||||
|
width: label.getBoundingClientRect().width,
|
||||||
|
lines: lineCount(label),
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!mobileProjectOverviewLayout.heroTitle || mobileProjectOverviewLayout.heroTitle.lines > 2) {
|
||||||
|
failures.push(`mobile project title must fit in at most two readable lines, got ${JSON.stringify(mobileProjectOverviewLayout.heroTitle)}`)
|
||||||
|
}
|
||||||
|
if (!mobileProjectOverviewLayout.shareButton || mobileProjectOverviewLayout.shareButton.right > mobileProjectOverviewLayout.viewportWidth) {
|
||||||
|
failures.push(`mobile project URL must stay inside the viewport, got ${JSON.stringify(mobileProjectOverviewLayout.shareButton)}`)
|
||||||
|
}
|
||||||
|
if (new Set(mobileProjectOverviewLayout.metricColumnLefts).size !== 2) {
|
||||||
|
failures.push(`mobile project metrics must use two columns, got left edges ${JSON.stringify(mobileProjectOverviewLayout.metricColumnLefts)}`)
|
||||||
|
}
|
||||||
|
for (const label of mobileProjectOverviewLayout.metricLabels) {
|
||||||
|
const minimumReadableWidth = label.text.length * 12
|
||||||
|
if (label.width < minimumReadableWidth || label.lines > 2) {
|
||||||
|
failures.push(`mobile project metric label must remain horizontally readable, got ${JSON.stringify(label)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
await page.screenshot({ path: 'test-results/project-react-acro-mobile.png', fullPage: true })
|
await page.screenshot({ path: 'test-results/project-react-acro-mobile.png', fullPage: true })
|
||||||
const projectNavButton = page.getByRole('button', { name: '打开项目导航', exact: true })
|
const projectNavButton = page.getByRole('button', { name: '打开项目导航', exact: true })
|
||||||
if (await projectNavButton.count() === 0) {
|
if (await projectNavButton.count() === 0) {
|
||||||
|
|||||||
@@ -2278,6 +2278,68 @@
|
|||||||
padding: var(--space-3);
|
padding: var(--space-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.project-overview-hero {
|
||||||
|
align-items: stretch;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-identity > div,
|
||||||
|
.project-overview-share,
|
||||||
|
.project-overview-share .arco-btn,
|
||||||
|
.project-overview-share .arco-btn > span:last-child {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-identity h3 {
|
||||||
|
word-break: normal;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-share {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
justify-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-share .arco-typography {
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-share .arco-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-page > .metric-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: var(--space-3);
|
||||||
|
margin-right: 0 !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-page > .metric-row > .arco-col {
|
||||||
|
width: auto;
|
||||||
|
max-width: none;
|
||||||
|
flex: none;
|
||||||
|
padding-right: 0 !important;
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-page .metric-card.arco-card,
|
||||||
|
.project-overview-page .metric-card .arco-space {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-page .metric-card .arco-space-item:last-child {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-overview-page .metric-card .arco-typography-secondary {
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
|
||||||
.statusbar {
|
.statusbar {
|
||||||
grid-template-columns: minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr);
|
||||||
padding: 0 var(--space-3);
|
padding: 0 var(--space-3);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## 结论
|
## 结论
|
||||||
|
|
||||||
本轮对统一版 MVP 做了后端、Web、桌面壳和响应式页面的全量验证。自动化命令均以 0 退出;最终截图逐张打开检查,未发现裁切、错误页、加载中画面或横向溢出。PostgreSQL 实时连接因本机未配置 `DATABASE_URL` 而跳过,不能据此宣称数据库集成环境已验收。
|
本轮对统一版 MVP 做了后端、Web、桌面壳和响应式页面的全量验证。核心验证命令均以 0 退出;Docker 探测因本机没有 Docker CLI 而失败。最终截图逐张打开检查,未发现裁切、错误页、加载中画面或横向溢出。PostgreSQL 实时连接测试未运行,不能据此宣称数据库集成环境已验收。
|
||||||
|
|
||||||
截图是本地审计产物,保存在 `apps/web_v1/test-results/`,由 Git 忽略,不随本文档提交。
|
截图是本地审计产物,保存在 `apps/web_v1/test-results/`,由 Git 忽略,不随本文档提交。
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
| 1440×1024 | `project-ai-controlled.png` | 会话列表、受控创建入口和“不会自动生成正式对象”说明可见 |
|
| 1440×1024 | `project-ai-controlled.png` | 会话列表、受控创建入口和“不会自动生成正式对象”说明可见 |
|
||||||
| 1440×1024 | `project-inbox-confirmed.png` | 收集内容、分析建议、选择项、确认结果和不可重复写入状态可见 |
|
| 1440×1024 | `project-inbox-confirmed.png` | 收集内容、分析建议、选择项、确认结果和不可重复写入状态可见 |
|
||||||
| 390×844 | `login-react-acro-mobile.png` | 单栏布局,无水平裁切;首屏下方内容可纵向滚动 |
|
| 390×844 | `login-react-acro-mobile.png` | 单栏布局,无水平裁切;首屏下方内容可纵向滚动 |
|
||||||
| 390×844 | `project-react-acro-mobile.png` | 默认关闭导航后主内容可访问,无横向溢出 |
|
| 390×844 | `project-react-acro-mobile.png` | 默认关闭导航后主内容可访问;标题正常横排、URL 位于视口内,指标以 2×2 排列 |
|
||||||
| 390×844 | `project-navigation-mobile.png` | 项目抽屉、遮罩与关闭路径可见 |
|
| 390×844 | `project-navigation-mobile.png` | 项目抽屉、遮罩与关闭路径可见 |
|
||||||
| 390×844 | `channel-navigation-mobile.png` | 频道抽屉、最近会话与关闭路径可见 |
|
| 390×844 | `channel-navigation-mobile.png` | 频道抽屉、最近会话与关闭路径可见 |
|
||||||
| 390×844 | `project-inbox-confirmed-mobile.png` | Inbox 列表和详情按单列重排,无横向溢出 |
|
| 390×844 | `project-inbox-confirmed-mobile.png` | Inbox 列表和详情按单列重排,无横向溢出 |
|
||||||
@@ -28,13 +28,14 @@
|
|||||||
|
|
||||||
## 与初始审计的对比
|
## 与初始审计的对比
|
||||||
|
|
||||||
对照 `apps/web_v1/test-results/audit-current/01-login.png` 至 `05-tasks.png`:
|
对照本地 Git ignored 证据 `apps/web_v1/test-results/audit-current/01-login.png` 至 `05-tasks.png`。这些截图不随仓库提交;其审计结论由已跟踪的[统一设计规格“现状审计”章节](superpowers/specs/2026-07-21-senlinai-mvp-unification-design.md#2-现状审计)记录:
|
||||||
|
|
||||||
- 登录页由会裁切右栏的三栏卡片改为完整双栏;`森林Agent`、`SenlinAI`、`AI Agent` 已统一为“森林AI / AI 助手”,字母占位图形替换为正式图标。
|
- 登录页由会裁切右栏的三栏卡片改为完整双栏;`森林Agent`、`SenlinAI`、`AI Agent` 已统一为“森林AI / AI 助手”,字母占位图形替换为正式图标。
|
||||||
- 工作台与项目页移除了升级、支付、固定存储空间、`AI 空闲`、`实时接口` 和固定 `进度 60%` 等无真实依据的状态。
|
- 工作台与项目页移除了升级、支付、固定存储空间、`AI 空闲`、`实时接口` 和固定 `进度 60%` 等无真实依据的状态。
|
||||||
- 项目页取消常驻右侧检查器,布局边界变为项目轨道、频道侧栏和主内容三段连续结构;项目强调色集中在横幅和小型标记。
|
- 项目页取消常驻右侧检查器,布局边界变为项目轨道、频道侧栏和主内容三段连续结构;项目强调色集中在横幅和小型标记。
|
||||||
- 任务页从静态示例卡片改为后端工作区数据驱动的标签、计数和空状态。
|
- 任务页从静态示例卡片改为后端工作区数据驱动的标签、计数和空状态。
|
||||||
- 390px 项目页不再是桌面布局左侧切片;主内容默认可见,项目与频道分别通过顶部按钮打开抽屉。
|
- 390px 项目页不再是桌面布局左侧切片;主内容默认可见,项目与频道分别通过顶部按钮打开抽屉。
|
||||||
|
- 390px 项目概览标题保持正常横排,项目 URL 保持在容器内并可在必要时省略,四项指标使用 2×2 网格并保持标签、数值和说明横向可读。
|
||||||
- Inbox 和 AI 页面明确保留“分析/受控会话 → 用户确认 → 正式对象”的边界,不把 AI 输出表现为已经自动执行。
|
- Inbox 和 AI 页面明确保留“分析/受控会话 → 用户确认 → 正式对象”的边界,不把 AI 输出表现为已经自动执行。
|
||||||
|
|
||||||
## 核心交互与安全边界
|
## 核心交互与安全边界
|
||||||
@@ -53,11 +54,10 @@
|
|||||||
|
|
||||||
## 剩余限制
|
## 剩余限制
|
||||||
|
|
||||||
- 当前环境没有 `DATABASE_URL`,且 PostgreSQL 测试带 `integration` build tag;指定的非 tag 命令只报告 `no tests to run`。需要在隔离测试库中显式运行带 tag 的集成测试。
|
- PostgreSQL 测试带 `integration` build tag,未带 tag 时不会被编译。当前 `DATABASE_DSN` 与 `DATABASE_URL` 均未配置,因此本轮未运行 tagged live check;在隔离测试库配置其一后,应运行 `go test -tags=integration ./internal/models -run TestPostgresPing -v`。缺少两个变量时该测试会失败,而不是跳过。
|
||||||
- 当前环境未安装 Docker CLI,未执行 Compose 启动、数据库初始化或容器内端到端检查。
|
- 当前环境未安装 Docker CLI,未执行 Compose 启动、数据库初始化或容器内端到端检查。
|
||||||
- Web 构建成功,但主 JavaScript chunk 约 663 kB、主 CSS chunk 约 591 kB,Vite 报告大于 500 kB 的体积警告;这是性能优化项,不阻塞 MVP 正确性验收。
|
- Web 构建成功,但主 JavaScript chunk 约 663 kB、主 CSS chunk 约 592 kB,Vite 报告大于 500 kB 的体积警告;这是性能优化项,不阻塞 MVP 正确性验收。
|
||||||
- 桌面壳构建成功;Windows 链接器输出了导入库创建信息并被 Rust 记录为一条 linker warning,没有构建错误。
|
- 桌面壳构建成功;Windows 链接器输出了导入库创建信息并被 Rust 记录为一条 linker warning,没有构建错误。
|
||||||
- 390px 项目概览的四个指标仍保持单行四列,中文标签换行较密;内容可读且未溢出,但后续可改为两列以提升扫读效率。
|
|
||||||
- 390×844 登录首屏为了保留品牌说明,登录按钮位于首屏下方,需要纵向滚动;页面无水平裁切,仍可完成登录。
|
- 390×844 登录首屏为了保留品牌说明,登录按钮位于首屏下方,需要纵向滚动;页面无水平裁切,仍可完成登录。
|
||||||
- 截图只能证明采集状态下的视觉结果,不能替代真实网络、慢设备、缩放、键盘和辅助技术测试。
|
- 截图只能证明采集状态下的视觉结果,不能替代真实网络、慢设备、缩放、键盘和辅助技术测试。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user