fix
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 16s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 16s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
## Context
|
||||
|
||||
当前项目中存在两个弹窗组件:
|
||||
- **PopupContainer.vue (V1)**: 使用 Vant 主题变量,支持 subtitle、header-actions 插槽、确认/取消按钮等丰富功能,默认高度 80%,被 18 个组件使用
|
||||
- **PopupContainerV2.vue (V2)**: 采用 Inter 字体和现代化设计风格(纯色背景、16px 圆角),API 更简洁(只提供 title、footer 插槽),默认高度 auto(最大 85%),已被 TransactionDetailSheet 使用
|
||||
|
||||
V1 和 V2 的 API 差异较大,V1 提供了更多开箱即用的功能(如内置按钮、subtitle),而 V2 追求灵活性和视觉一致性。此次迁移需要在保持功能不变的前提下,统一使用 V2 的现代化设计。
|
||||
|
||||
**约束条件**:
|
||||
- 不能改变现有页面的交互逻辑和用户体验
|
||||
- 需要保持暗色模式的正确支持
|
||||
- 必须通过 ESLint 和现有的代码规范
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 统一弹窗组件为 PopupContainerV2,删除 V1 版本
|
||||
- 迁移 18 个使用 V1 的组件,保持功能等价性
|
||||
- 适配 API 差异(props → 插槽、样式调整)
|
||||
- 确保迁移后视觉效果和交互逻辑一致
|
||||
|
||||
**Non-Goals:**
|
||||
- 不重新设计弹窗的交互流程或视觉风格(完全按照 V2 现有设计)
|
||||
- 不优化或重构业务逻辑(仅做组件替换和 API 适配)
|
||||
- 不处理与弹窗无关的代码问题
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: 迁移策略 - 逐文件手动迁移 vs 自动化脚本
|
||||
|
||||
**选择**: 手动逐文件迁移
|
||||
|
||||
**理由**:
|
||||
- V1 和 V2 的 API 差异大(props → 插槽),无法通过简单的查找替换完成
|
||||
- 每个组件对 subtitle、header-actions、确认/取消按钮的使用方式不同,需要根据业务语义定制迁移方案
|
||||
- 自动化脚本的开发成本高于手动迁移 18 个文件的时间成本
|
||||
- 手动迁移可以确保每个文件的视觉和逻辑正确性
|
||||
|
||||
**备选方案**:
|
||||
- AST 转换工具(如 jscodeshift):复杂度高,难以处理插槽和样式的语义转换
|
||||
|
||||
### Decision 2: subtitle 功能的迁移方式
|
||||
|
||||
**选择**: 根据业务语义分类处理
|
||||
- **统计信息类 subtitle**(如 "共 10 笔交易")→ 移至默认插槽顶部,使用自定义样式组件
|
||||
- **纯文本副标题** → 移至默认插槽,或合并到 title 中(如 "分类详情 - 餐饮")
|
||||
|
||||
**理由**:
|
||||
- V2 没有 subtitle prop,必须通过插槽实现
|
||||
- 统计信息通常有特定的业务含义,应作为内容区域的一部分而非标题的附属
|
||||
- 纯文本副标题可以简化为一级标题的扩展
|
||||
|
||||
**备选方案**:
|
||||
- 扩展 V2 组件增加 subtitle prop:违背 V2 简化 API 的设计原则,不采纳
|
||||
|
||||
### Decision 3: 确认/取消按钮的迁移方式
|
||||
|
||||
**选择**: 转换为 footer 插槽 + 手动事件绑定
|
||||
|
||||
**实现模式**:
|
||||
```vue
|
||||
<!-- V1 -->
|
||||
<PopupContainer
|
||||
show-confirm-button
|
||||
show-cancel-button
|
||||
confirm-text="确定"
|
||||
@confirm="handleConfirm"
|
||||
@cancel="handleCancel"
|
||||
/>
|
||||
|
||||
<!-- V2 -->
|
||||
<PopupContainerV2>
|
||||
<template #footer>
|
||||
<div class="footer-buttons">
|
||||
<van-button plain @click="handleCancel">取消</van-button>
|
||||
<van-button type="primary" @click="handleConfirm">确定</van-button>
|
||||
</div>
|
||||
</template>
|
||||
</PopupContainerV2>
|
||||
|
||||
<style scoped>
|
||||
.footer-buttons {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
.footer-buttons .van-button {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**理由**:
|
||||
- V2 的 footer 插槽提供了足够的灵活性
|
||||
- Vant Button 的样式与 V1 内置按钮一致,迁移成本低
|
||||
- 手动绑定事件可以保持原有的业务逻辑不变
|
||||
|
||||
### Decision 4: header-actions 插槽的处理
|
||||
|
||||
**选择**: 移至默认插槽顶部或改用自定义布局
|
||||
|
||||
**理由**:
|
||||
- V2 没有 header-actions 插槽,标题区域只有标题文本和关闭按钮
|
||||
- 根据现有代码(如 BudgetCard.vue、SavingsBudgetContent.vue),header-actions 通常是"编辑"、"删除"等操作按钮
|
||||
- 这些按钮更适合放在内容区域顶部或 footer 中,符合 V2 的极简标题设计
|
||||
|
||||
**实现模式**:
|
||||
```vue
|
||||
<!-- V2 -->
|
||||
<PopupContainerV2>
|
||||
<div class="content-with-actions">
|
||||
<div class="action-bar">
|
||||
<van-button size="small" @click="handleEdit">编辑</van-button>
|
||||
</div>
|
||||
<!-- 原内容区域 -->
|
||||
</div>
|
||||
</PopupContainerV2>
|
||||
```
|
||||
|
||||
### Decision 5: 高度属性的处理
|
||||
|
||||
**选择**: 显式指定 `:height="'80%'"` 保持视觉一致性
|
||||
|
||||
**理由**:
|
||||
- V1 默认 `height="80%"`,V2 默认 `height="auto"`(最大 85%)
|
||||
- 直接使用 V2 的 auto 可能导致内容过少时弹窗过小,影响用户体验
|
||||
- 显式设置 80% 可以确保迁移前后视觉效果一致
|
||||
- 如果某些组件的内容确实很少,可以在迁移时根据实际情况调整为 auto
|
||||
|
||||
### Decision 6: 样式和暗色模式的适配
|
||||
|
||||
**选择**: 信任 V2 的内置暗色模式支持,不额外修改
|
||||
|
||||
**理由**:
|
||||
- V2 已在组件内部通过 `@media (prefers-color-scheme: dark)` 实现暗色模式
|
||||
- V1 使用 Vant 的 CSS 变量,V2 使用硬编码颜色,但两者在暗色模式下都能正确切换
|
||||
- 业务组件只需确保内容区域的样式兼容暗色模式即可
|
||||
|
||||
**风险**: 如果业务组件的内容区域使用了与 V2 不兼容的颜色,需要单独调整(通过人工检查)
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
### Risk 1: 迁移后视觉效果差异
|
||||
**风险**: V1 和 V2 的字体、颜色、圆角不同,可能导致用户感知到不一致
|
||||
**缓解措施**:
|
||||
- 在开发环境逐个测试迁移后的页面
|
||||
- 重点检查弹窗的标题、内容、按钮的对齐和间距
|
||||
- 如果某个页面的差异过大,考虑调整 V2 的样式或在该页面单独处理
|
||||
|
||||
### Risk 2: subtitle 和 header-actions 迁移语义变化
|
||||
**风险**: 将 subtitle 移至内容区域可能改变信息层级,header-actions 移至内容顶部可能影响交互流畅性
|
||||
**缓解措施**:
|
||||
- 迁移时保持原有的语义和视觉层级(如 subtitle 仍然显示在顶部且样式相似)
|
||||
- 通过 CSS 模拟 V1 的 Grid 布局,确保按钮位置不变
|
||||
|
||||
### Risk 3: 高度变化导致滚动问题
|
||||
**风险**: V1 的 80% 固定高度和 V2 的 auto 可能导致滚动行为不同(如内容过多时 V2 可能超出最大高度)
|
||||
**缓解措施**:
|
||||
- 统一使用 `:height="'80%'"` 作为默认值
|
||||
- 对于内容特别少的弹窗(如确认对话框),可以单独设置为 auto
|
||||
|
||||
### Risk 4: 事件处理器遗漏
|
||||
**风险**: 手动迁移确认/取消按钮时,可能遗漏原有的 `@confirm`、`@cancel` 事件逻辑
|
||||
**缓解措施**:
|
||||
- 迁移前通过搜索确认每个组件是否使用了这些事件
|
||||
- 迁移后通过功能测试验证按钮点击是否正确触发
|
||||
|
||||
### Risk 5: ESLint 和代码规范问题
|
||||
**风险**: 手动创建的 footer 插槽可能不符合项目的 ESLint 规则(如缩进、引号)
|
||||
**缓解措施**:
|
||||
- 迁移完成后运行 `pnpm lint` 并修复所有错误
|
||||
- 参考现有 V2 的使用示例(TransactionDetailSheet.vue)保持风格一致
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### Phase 1: 准备阶段
|
||||
1. 审查 18 个待迁移文件,分析每个文件使用的 V1 功能(subtitle、buttons、header-actions)
|
||||
2. 为每个文件制定迁移清单(需要修改的部分)
|
||||
|
||||
### Phase 2: 迁移阶段
|
||||
逐文件迁移,按以下步骤:
|
||||
1. 更新 import 路径和组件名
|
||||
2. 替换基础 props(保留 v-model:show、title,显式设置 height)
|
||||
3. 迁移 subtitle(根据语义选择方案)
|
||||
4. 迁移 header-actions(移至内容区域或 footer)
|
||||
5. 迁移确认/取消按钮(创建 footer 插槽)
|
||||
6. 调整内容区域的 padding(V2 无默认 padding)
|
||||
7. 测试功能和视觉效果
|
||||
|
||||
### Phase 3: 验证阶段
|
||||
1. 运行 `pnpm lint` 确保代码规范
|
||||
2. 手动测试每个迁移的页面,验证弹窗的打开/关闭、内容展示、按钮交互
|
||||
3. 检查暗色模式下的显示效果
|
||||
|
||||
### Phase 4: 清理阶段
|
||||
1. 确认所有迁移完成且测试通过
|
||||
2. 删除 `Web/src/components/PopupContainer.vue`
|
||||
3. 全局搜索 `PopupContainer` 确认无残留引用
|
||||
|
||||
### Rollback 策略
|
||||
- 如果迁移后发现重大问题(如性能下降、功能缺失),可以通过 Git 回滚到迁移前的版本
|
||||
- V1 和 V2 是独立文件,迁移失败不会影响现有功能(除非删除了 V1)
|
||||
- 建议在完成所有迁移并验证通过后再删除 V1 文件
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **是否需要对 V2 组件进行增强?**
|
||||
- 例如增加 subtitle prop 简化迁移
|
||||
- **暂定答案**: 不修改 V2,保持其简洁性,通过插槽实现所有功能
|
||||
|
||||
2. **是否需要统一 footer 按钮的样式?**
|
||||
- 目前每个文件需要手动创建 `.footer-buttons` 样式
|
||||
- **暂定答案**: 可以提取为全局样式或在 V2 中提供默认样式(后续优化项)
|
||||
|
||||
3. **是否需要通知用户 UI 风格变化?**
|
||||
- V1 到 V2 的视觉差异可能被用户感知
|
||||
- **暂定答案**: 作为内部优化,不需要用户通知
|
||||
Reference in New Issue
Block a user