Files
reimburse/界面优化方案.md
T
2026-09-20 16:31:24 +08:00

159 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 贴票台 · 界面优化方案
> 依据当前代码(`reimburse/` 下 26 个 Swift 视图文件)整理,只提优化建议,不改动代码。
> 应用结构:顶层 TabView`项目管理 AdminView` + `本地贴票 ContentView`),本地贴票内含 `材料扫描 ScanPage`、`人工配对 PairPage`、`已核对 MatchedPage` 三个页面,以及报销单模板、收款信息、报销单预览等弹窗。
---
## 一、现状盘点
### 信息架构
| 层级 | 内容 | 现状评价 |
|---|---|---|
| 顶层 Tab | 项目管理 / 本地贴票 | 应用名为"贴票台"且主功能是本地贴票,但项目管理排在第一个 Tab,与产品定位略有错位 |
| 本地贴票 | 侧栏 3 页 + 顶栏统计 + 工具栏 3 按钮 | 结构清晰,导航合理 |
| 弹窗 | 报销模板(1000×700)、收款信息(宽 580)、个人报销单(870×620)、预览(动态)、材料预览(1000×700) | 尺寸规格不统一,部分固定尺寸在小屏上有溢出风险 |
### 已做好的地方(应保留)
- `MaterialCard` 卡片 + Canvas 贝塞尔连线的配对交互,直观且具辨识度;
- `MatchExplanationPopover` 的 100 分制证据评分明细,透明度高;
- 拖拽导入的 dropDestination 高亮反馈、`.help()` 悬停提示、`accessibilityLabel` 覆盖较全;
- Table + 分组 Picker + 跨分组保留勾选的选择模型,业务逻辑扎实。
---
## 二、设计系统层面(全局问题)
### 2.1 颜色语义不统一 ⭐ 高优先级
- **现状**:teal 同时承担「品牌色、强调色、成功色、进行中状态」四种语义(侧栏图标、付款金额、匹配满分、通知横幅全是 teal);警告用 orange、错误用 red、AdminView 里成功又用 green。同一语义在两个 Tab 中颜色不同。
- **建议**
1. 建立语义色枚举(如 `AppTheme.success / warning / danger / accent`),收敛到一处定义;
2. teal 保留为品牌/强调色;成功态用系统 green、警告 orange、危险 red,与项目管理端对齐;
3. 「自动匹配 ≥90 分」与「人工确认」目前用 teal / blue 区分,建议改为统一的徽章组件(形状+图标+色),而非仅靠文字前缀。
- 金额显示可遵循国内财务习惯:发票与付款两列总额(topbar)目前一灰一 teal,对比弱,建议付款列加图标或用同色不同字重,避免用户误读为涨跌。
### 2.2 深色模式适配缺失 ⭐ 高优先级
- **现状**`MaterialThumbnail``Color.white` 背景、`SpreadsheetPreview / ExpenseTemplateManager` 大量 `.background(.white)`、预览区 `.black.opacity(0.04)`。深色模式下会出现大面积刺眼的白色块与文字对比不足。
- **建议**:表格/缩略图区保留白底是合理的(还原纸张观感),但外层容器、边框、占位图标应改用 `Color(nsColor: .textBackgroundColor)` 或材质色;至少验证 `Window` 在深色外观下所有页面无纯白大色块、无低对比 caption。
### 2.3 排版与间距 token 化
- **现状**`padding(28) / (26) / (22) / (20)``cornerRadius 16 / 13 / 12 / 10 / 9 / 8`、字号 `.title2 / .title3 / .system(size: 34 / 44 / 42)` 混用,页面间无对应关系。
- **建议**:定义间距(4 的倍数:8/12/16/24/28)与圆角(8 卡片内、12 卡片、16 面板)两档规格;页面主标题统一为 `.title2.bold()`(当前 PairPage 是 title3、MatchedPage 是 title2)。
### 2.4 组件重复实现
- `AdminView` 内自建了 `statusBadge / sectionCard / searchField / emptyState``ContentView` 一侧有 `Panel / EmptyPanel`,两套体系风格接近但参数不同。
- **建议**:抽出共享组件库(Badge、Card、SearchField、EmptyState、StatNumber),两个 Tab 复用,减少后续维护分叉。
---
## 三、页面级优化
### 3.1 材料扫描 ScanPage
| 问题 | 建议 | 优先级 |
|---|---|---|
| 空工作区时仍显示全部统计面板(全是 0),首屏信息密度高但价值低 | 无材料时展示「导入引导」大空状态:仅保留拖拽卡片 + 模板卡片,统计面板在导入后再出现 | P1 |
| 单列滚动太长:导入卡、模板卡、警告、3 个统计卡、2 个金额面板、分类汇总、底部计数,关键动作「前往人工配对」沉底 | ① 统计卡片改为一行 4 列紧凑指标条;②「前往人工配对」在有待配对材料时上浮为醒目入口(如导入完成后的成功横幅内嵌跳转按钮);③ 分类汇总与金额概览合并为一个「金额」面板 | P1 |
| 拖拽高亮 `opacity 0→1` 突变 | 加 `withAnimation(.easeInOut(duration: 0.15))`,并让图标/文字随 targeted 状态做位移或缩放微动效 | P2 |
| warnings 面板无法关闭、数量多时占据大量空间 | 逐条可关闭 + 超过 3 条折叠为「N 条提醒」;每条加对应的跳转动作(如跳转到识别失败的材料) | P2 |
| 三个统计卡数字 `size: 34` 硬编码,视觉与「金额概览」面板重复 | 数字统一走 `StatNumber` 组件(`.rounded` 数字字体 + tabular),金额面板可考虑用小图表(分类占比条)替代纯文本 | P3 |
### 3.2 人工配对 PairPage
| 问题 | 建议 | 优先级 |
|---|---|---|
| 材料多时无法定位:无搜索、无排序切换、无金额/日期过滤 | 每栏顶部加搜索框(文件名/商户/金额)+ 排序菜单(日期/金额/文件名),复用 AdminView 的 `searchField` 样式 | P0 |
| 已选 N 张发票 × N 张付款为全连接,选 5×5 时 25 条虚线交叉难以阅读 | 连线改为:hover/聚焦某卡片时只高亮与它相关的连线;或选中的卡片显示序号,连线带序号标签 | P1 |
| 只有 Return 键可操作选中,无方向键导航 | 利用现有 `.focusable()` 补充 ↑↓ 移动焦点、Space 选中,形成完整键盘流;说明文字中标注快捷键 | P1 |
| 缩略图固定 180pt 网格,看不清细节需逐个开预览 | 增加缩放滑杆(紧凑/标准/大图三档),或双击卡片直接放大预览后可从预览中「选中此材料」 | P2 |
| 确认配对按钮位于右上角,与底部的选中信息分离 | 选中数 >0 时在两栏之间显示居中的「确认配对(N×M)」悬浮按钮,动线更短 | P2 |
| 空状态文案两栏雷同 | 左栏空时提示「所有发票已处理或已核对」,右栏提示对应付款文案,并可放「撤销上一组」入口 | P3 |
### 3.3 已核对 MatchedPage
| 问题 | 建议 | 优先级 |
|---|---|---|
| 无搜索/过滤:几十组材料时找特定金额/商户困难 | 表格上方加搜索框(金额、商户、日期),支持过滤后再勾选 | P0 |
| `MaterialCell` 只列前 2 个文件名链接,「还有 N 份」不可展开 | 点击单元格弹出 popover 缩略图网格,与 PairPage 的卡片视觉统一;>2 份时显示「+N」叠图效果 | P1 |
| 底部三行 caption 说明文字(勾选规则、PPT 版式)常驻 | 收敛为一个「导出说明」帮助按钮(`questionmark.circle`)弹出;常用信息已在按钮禁用态与选中计数中体现 | P2 |
| 分组多时 segmented Picker 挤压变形 | 分类 ≥5 个时改用 Menu + 下拉,或横向滚动 chips | P2 |
| 「操作」列撤销仅图标按钮,与分类 Picker 挤在一列 | 撤销改为 hover 行时出现的 trailing 按钮或右键菜单;分类修改也可考虑双击单元格弹出,减少列宽 | P2 |
| 表格无小计:分组切换后看不到当前分组金额合计 | 表格底部(或分组标题旁)显示「本分组合计:发票 X · 付款 Y」 | P2 |
| 评分 <90 分为橙色但没有聚合入口(「哪些组需要人工复核」) | 增加「需关注」过滤(评分 <90 或识别失败),配合 P0 搜索框;侧栏「已核对」徽标可显示低分组数量 | P1 |
### 3.4 个人报销单 ExpenseSheet 与预览
| 问题 | 建议 | 优先级 |
|---|---|---|
| 固定 `frame(width: 870, height: 620)`,小屏(MacBook Air 13" 缩放)可能顶出屏幕 | 改为 `min` 上限策略(参照 `ExpensePreviewSheet``min(1200, visibleFrame - 80)` 写法) | P1 |
| 费用行用途 TextField 无校验反馈(空值、重复用途不易发现) | 空用途时行内灰字提示;重复用途合并提示 | P3 |
| 签字岗位 minus.circle 无确认,误触即删 | 删除加轻量确认或支持撤销 toast;输入框加默认岗位快选 Menu | P3 |
| `expenseSelectionValid` 失效只显示一行红字,动作指引弱 | 失效时禁用预览按钮并把红字放进醒目横幅,附「返回重新选择」按钮 | P2 |
| 预览弹窗已较好;「返回修改」与「确认并保存」并排但视觉主次不明 | 确认按钮保持 prominent 即可;建议保存成功后用横幅告知保存路径并提供「在访达中显示」 | P2 |
### 3.5 报销模板管理 ExpenseTemplateManager / ExpenseTemplateFields
| 问题 | 建议 | 优先级 |
|---|---|---|
| 模板字段调整(列字母/单元格地址)要求用户手工填 "C" "C23",认知门槛高 | ① 输入框支持点选:在左侧表格预览上点击单元格即回填地址(SwiftUI 可用 onTapGesture + 布局信息);② 输入时实时校验字母/地址格式并给出示例反馈 | P1 |
| 「查看单元格地址与原文」DisclosureGroup 是纯文本行,对照困难 | 与左侧预览联动:hover 某行时高亮预览中对应行;保留行号列 | P3 |
| 未识别完整时只有一行橙色警告,确认按钮置灰原因不直观 | 每个缺失必填项(用途/金额列)在对应输入框旁标橙点,按钮旁注明「还差 N 项」 | P2 |
| 模板卡片(ExpenseTemplateSummary)与导入卡片视觉相似,都是 teal 虚线框 | 模板卡片改为普通卡片 + 右上「模板」徽标,虚线拖拽样式只留给导入场景,减少误拖 | P3 |
### 3.6 收款信息 PayeeProfileSheet
- 现状已经较好(SecureField + 显隐切换 + 删除确认)。可补充:保存成功后 toast 确认;`PayeeProfileSummary` 中「尾号 XXXX」处加复制按钮。
- 优先级 P3。
### 3.7 项目管理 AdminView
| 问题 | 建议 | 优先级 |
|---|---|---|
| 单文件 1364 行、50+ 个 `@State`,六个页签全部内联 | 拆分为独立 View 文件(`AdminExpensesTab` 等);这不是纯界面问题,但直接影响后续所有 UI 迭代效率 | P1(技术债) |
| 自绘 tab 条(navigationItem)与 macOS 惯例不符,窗口宽度不足时六个标签挤压 | 采用 macOS 15 可用的 `TabView` 新样式或保留但允许横向滚动 + 更多收纳进 Menu | P2 |
| 登录页固定 400 宽输入区 + ScrollView,视觉重心偏上 | 居中卡片式布局;服务地址输入记忆历史地址下拉;微信扫码过期自动刷新提示 | P2 |
| 报销审批表无分页指示、无列排序 | Table 补充排序(金额/日期);行数多时显示计数 | P2 |
| 错误横幅红色整条较突兀 | 收敛为顶部统一通知组件(同本地贴票端的 notice 样式),成功/警告/错误三态 | P2 |
---
## 四、全局交互与反馈
1. **统一通知体系**(P1):目前成功提示是自定义 teal 横幅、错误是 `alert`、Admin 是红横幅。建议统一为三态通知条(成功/警告/错误),支持多条堆叠与自动消失(错误不自动消失),并复用 macOS 15 的 `SymbolEffect`
2. **菜单栏与快捷键**(P2):已有 ⌘O 导入。建议补充:⌘Z 撤销最近核对组(复用 store.undo)、⌘F 聚焦搜索(配合 P0 搜索项)、⌘1/2/3 切换三个页面、⌘, 打开设置类弹窗(模板/收款信息)。
3. **空状态体系**P1):EmptyPanel 目前只有图标+标题+说明,可按页面补一个行动按钮(如「选择文件夹」「前往人工配对」),形成闭环。
4. **进度反馈**P2):busy 时是整页 `disabled` + 顶部进度条;扫描大目录时建议在 Dock 图标显示进度(NSApp.dockTile.progress),并保留页面滚动可读。
5. **危险操作确认**(P2):「清空重置」的 confirmationDialog 文案已很详细,但「恢复内置模板」「删除收款信息」等破坏性操作可统一加「需要输入确认/二次点击」模式中的轻量档:按钮文字改为具体后果(如「移除本机模板副本」)。
---
## 五、性能相关(影响体感的界面项)
| 问题 | 建议 | 优先级 |
|---|---|---|
| `MaterialPreview``NSImage(contentsOf:)` 在主线程同步解码整图,大图/PDF 首页可能卡顿 | 改为 `task` 异步加载 + 占位 ProgressView;预览窗口打开先显示缩略图再换全图 | P1 |
| `Workspace.sortedMatches``matches(for:)``groups`、表格行的 `index(of:)` 都是每次重算的 computed 属性,匹配组多时 Table 滚动会重复计算 | 在 Store 层缓存排序结果(matches 变更时失效);`index(of:)``Dictionary(id→index)` 替代 | P2 |
| ScanPage 分类汇总对每个 category 全量 filter7 × N | 一次遍历 reduce 成字典再渲染 | P3 |
| `MaterialThumbnail` 700px 缩略图生成已异步(好);但 `task(id: previewURL)` 取消旧任务的行为依赖 detached task,建议显式检查 `Task.isCancelled` | 补充取消检查,避免快速滚动时旧图覆盖新图 | P2 |
---
## 六、无障碍与本地化细节
- caption / caption2 + `.tertiary` 的组合在浅色模式下对比度偏低(如「支持图片和 PDF · PDF 处理首页」),建议 tertiary 只用于辅助信息,主说明用 secondary。
- `MatchConfidenceCell` 的颜色(teal/orange)承载了语义,建议在 accessibilityLabel 中补充「评分高/需关注」文字(目前已有百分比,可再补状态词)。
- PairPage 连线是 Canvas 绘制,VoiceOver 完全不可见;建议在读出的标签中描述配对关系(已有 accessibilityLabel 基础,补充「已与 N 张付款连线」)。
---
## 七、实施路线图
| 阶段 | 内容 | 预期收益 |
|---|---|---|
| **P0(先做)** | PairPage / MatchedPage 搜索与排序;低分组「需关注」过滤 | 解决材料量大时的核心查找痛点 |
| **P1** | 颜色语义统一 + 深色模式适配;语义色/间距 token 化;空状态行动按钮;ScanPage 信息层级重组;MaterialPreview 异步加载;AdminView 拆分 | 视觉一致性与小屏/深色体验 |
| **P2** | 统一通知组件;键盘快捷键;表格 MaterialCell 缩略图 popover;分组小计;模板字段可视化点选;拖拽动效;进度 Dock 反馈 | 效率与细节打磨 |
| **P3** | 统计卡组件化、金额小图表、模板卡片徽标、签字岗位快选 | 锦上添花 |
> 约束提醒:以上均为界面层建议,实施时须保持 README 中列明的业务口径不变(PPT 版式、金额计算口径、勾选保留规则等),尤其 P1 中 ScanPage 重组不要改变「再次导入替换工作区」的确认流程。