diff --git a/.doc/popup-migration-checklist.md b/.doc/popup-migration-checklist.md
new file mode 100644
index 0000000..4aa3bfe
--- /dev/null
+++ b/.doc/popup-migration-checklist.md
@@ -0,0 +1,165 @@
+# PopupContainer V1 → V2 迁移清单
+
+## 文件分析汇总
+
+### 第一批:基础用法(无 subtitle、无按钮)
+
+| 文件 | Props 使用 | Slots 使用 | 迁移复杂度 | 备注 |
+|------|-----------|-----------|----------|------|
+| MessageView.vue | v-model, title, subtitle, height | footer | ⭐⭐ | 有 subtitle (createTime),有条件 footer |
+| EmailRecord.vue | v-model, title, height | header-actions | ⭐⭐⭐ | 使用 header-actions 插槽(重新分析按钮) |
+| PeriodicRecord.vue | v-model, title, height | 默认插槽 | ⭐ | 基础用法,表单内容 |
+| ClassificationNLP.vue | v-model, title, height | 默认插槽 | ⭐ | 基础用法 |
+| BillAnalysisView.vue | v-model, title, height | 默认插槽 | ⭐ | 基础用法 |
+
+### 第二批:带 subtitle
+
+| 文件 | Subtitle 类型 | 迁移方案 |
+|------|--------------|---------|
+| MessageView.vue | 时间戳 (createTime) | 移至内容区域顶部,使用灰色小字 |
+| CategoryBillPopup.vue | 待检查 | 待定 |
+| BudgetChartAnalysis.vue | 待检查 | 待定 |
+| TransactionDetail.vue | 待检查 | 待定 |
+| ReasonGroupList.vue | 待检查 | 待定 |
+
+### 第三批:带确认/取消按钮
+
+| 文件 | 按钮配置 | 迁移方案 |
+|------|---------|---------|
+| AddClassifyDialog.vue | 待检查 | footer 插槽 + van-button |
+| IconSelector.vue | 待检查 | footer 插槽 + van-button |
+| ClassificationEdit.vue | 待检查 | footer 插槽 + van-button |
+
+### 第四批:复杂布局(header-actions)
+
+| 文件 | header-actions 内容 | 迁移方案 |
+|------|-------------------|---------|
+| EmailRecord.vue | "重新分析" 按钮 | 移至内容区域顶部作为操作栏 |
+| BudgetCard.vue | 待检查 | 待定 |
+| BudgetEditPopup.vue | 待检查 | 待定 |
+| SavingsConfigPopup.vue | 待检查 | 待定 |
+| SavingsBudgetContent.vue | 待检查 | 待定 |
+| budgetV2/Index.vue | 待检查 | 待定 |
+
+### 第五批:全局组件
+
+| 文件 | 特殊逻辑 | 迁移方案 |
+|------|---------|---------|
+| GlobalAddBill.vue | 待检查 | 待定 |
+
+## 迁移模式汇总
+
+### 模式 1: 基础迁移(无特殊 props)
+```vue
+
+
+ 内容
+
+
+
+
+
+ 内容
+
+
+```
+
+### 模式 2: subtitle 迁移
+```vue
+
+
+ 内容
+
+
+
+
+
+
{{ createTime }}
+ 内容
+
+
+```
+
+### 模式 3: header-actions 迁移
+```vue
+
+
+
+ 操作
+
+ 内容
+
+
+
+
+
+
+```
+
+### 模式 4: footer 插槽迁移
+```vue
+
+
+ 内容
+
+ 提交
+
+
+
+
+
+
+ 内容
+
+
+ 提交
+
+
+```
+
+## 进度追踪
+
+- [ ] 完成所有文件的详细分析
+- [ ] 确认每个文件的迁移模式
+- [ ] 标记需要特殊处理的文件
+
+## 风险点
+
+1. **EmailRecord.vue**: 有 header-actions 插槽,需要重新设计操作按钮的位置
+2. **MessageView.vue**: subtitle 用于显示时间,需要保持视觉层级
+3. **待检查文件**: 需要逐个检查是否使用了 v-html、复杂布局等特性
diff --git a/Web/src/components/AddClassifyDialog.vue b/Web/src/components/AddClassifyDialog.vue
index 8f894dd..643989a 100644
--- a/Web/src/components/AddClassifyDialog.vue
+++ b/Web/src/components/AddClassifyDialog.vue
@@ -1,30 +1,45 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 确认
+
+
+
+
-
-
diff --git a/Web/src/components/PopupContainerV2.vue b/Web/src/components/PopupContainerV2.vue
index bf231e9..faf73fc 100644
--- a/Web/src/components/PopupContainerV2.vue
+++ b/Web/src/components/PopupContainerV2.vue
@@ -14,7 +14,7 @@ PopupContainer V2 - 通用底部弹窗组件(采用 TransactionDetailSheet 样
## Props
-- modelValue (Boolean, required): 控制弹窗显示/隐藏
+- show (Boolean, required): 控制弹窗显示/隐藏
- title (String, required): 标题文本
- height (String, default: 'auto'): 弹窗高度,支持 'auto', '80%', '500px' 等
- maxHeight (String, default: '85%'): 最大高度
@@ -24,7 +24,7 @@ PopupContainer V2 - 通用底部弹窗组件(采用 TransactionDetailSheet 样
- footer: 固定底部区域(操作按钮等)
## Events
-- update:modelValue: 弹窗显示/隐藏状态变更
+- update:show: 弹窗显示/隐藏状态变更
-->
props.modelValue,
- set: (value) => emit('update:modelValue', value)
+ get: () => props.show,
+ set: (value) => emit('update:show', value)
})
// 判断是否有 footer 插槽
diff --git a/Web/src/components/ReasonGroupList.vue b/Web/src/components/ReasonGroupList.vue
index 496e1d8..b84b712 100644
--- a/Web/src/components/ReasonGroupList.vue
+++ b/Web/src/components/ReasonGroupList.vue
@@ -61,34 +61,42 @@
-
-
-
- 批量分类
-
-
+
+
+
+
+ 共 {{ groupTransactionsTotal }} 笔交易
+
+
+ 批量分类
+
+
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
-
-
-
-
- 支出
-
-
- 收入
-
-
- 不计
-
-
-
-
+
+
+
+
+
+ 支出
+
+
+ 收入
+
+
+ 不计
+
+
+
+
-
-
-
- 请选择分类
- {{ batchForm.classify }}
-
-
+
+
+
+ 请选择分类
+ {{ batchForm.classify }}
+
+
-
-
-
-
+
+
+
+
+
-
+
@@ -189,7 +199,7 @@ import { getReasonGroups, batchUpdateByReason, getTransactionList } from '@/api/
import ClassifySelector from './ClassifySelector.vue'
import BillListComponent from './Bill/BillListComponent.vue'
import TransactionDetail from './TransactionDetail.vue'
-import PopupContainer from './PopupContainer.vue'
+import PopupContainerV2 from './PopupContainerV2.vue'
const props = defineProps({
// 是否支持多选
diff --git a/Web/src/components/TransactionDetail.vue b/Web/src/components/TransactionDetail.vue
index 8e580ee..b258c16 100644
--- a/Web/src/components/TransactionDetail.vue
+++ b/Web/src/components/TransactionDetail.vue
@@ -1,134 +1,135 @@
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
- 支出
-
-
- 收入
-
-
- 不计
-
-
-
-
+
+
+
+
-
-
-
-
+
+
-
-
- 建议: {{ transaction.unconfirmedClassify }}
-
- ({{ getTypeName(transaction.unconfirmedType) }})
-
-
-
- 应用
-
-
-
请选择交易分类
-
{{ editForm.classify }}
-
-
-
+
+ 支出
+
+
+ 收入
+
+
+ 不计
+
+
+
+
-
-
-
+
+
+
+
+
+
+ 建议: {{ transaction.unconfirmedClassify }}
+
+ ({{ getTypeName(transaction.unconfirmedType) }})
+
+
+
+ 应用
+
+
+
请选择交易分类
+
{{ editForm.classify }}
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
@@ -122,7 +137,7 @@ import { ref, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { showToast, showLoadingToast, closeToast } from 'vant'
import { getConfig, setConfig } from '@/api/config'
-import PopupContainer from '@/components/PopupContainer.vue'
+import PopupContainerV2 from '@/components/PopupContainerV2.vue'
const router = useRouter()
const userInput = ref('')
diff --git a/Web/src/views/ClassificationEdit.vue b/Web/src/views/ClassificationEdit.vue
index 1127b82..a75ea2b 100644
--- a/Web/src/views/ClassificationEdit.vue
+++ b/Web/src/views/ClassificationEdit.vue
@@ -112,64 +112,107 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 确认
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 保存
+
+
+
+
-
删除后无法恢复,确定要删除吗?
-
+
+
+
+ 取消
+
+
+ 确定
+
+
+
+
-
-
@@ -133,7 +133,7 @@ import { showToast, showConfirmDialog } from 'vant'
import { nlpAnalysis, batchUpdateClassify } from '@/api/transactionRecord'
import BillListComponent from '@/components/Bill/BillListComponent.vue'
import TransactionDetail from '@/components/TransactionDetail.vue'
-import PopupContainer from '@/components/PopupContainer.vue'
+import PopupContainerV2 from '@/components/PopupContainerV2.vue'
const router = useRouter()
const userInput = ref('')
diff --git a/Web/src/views/EmailRecord.vue b/Web/src/views/EmailRecord.vue
index 77ffa9b..09de162 100644
--- a/Web/src/views/EmailRecord.vue
+++ b/Web/src/views/EmailRecord.vue
@@ -73,23 +73,24 @@
-
-
-
- 重新分析
-
-
-
-
+
-
-
+
-
-
-
- {{ currentMessage.content }}
+
+
+ {{ currentMessage.createTime }}
+
+
+
+ {{ currentMessage.content }}
+
-
+
@@ -111,7 +116,7 @@ import { useRouter } from 'vue-router'
import { showToast, showDialog } from 'vant'
import { getMessageList, markAsRead, deleteMessage, markAllAsRead } from '@/api/message'
import { useMessageStore } from '@/stores/message'
-import PopupContainer from '@/components/PopupContainer.vue'
+import PopupContainerV2 from '@/components/PopupContainerV2.vue'
const messageStore = useMessageStore()
const router = useRouter()
@@ -325,22 +330,6 @@ defineExpose({
height: 100%;
}
-.detail-time {
- color: var(--van-text-color-2);
- font-size: 14px;
-}
-
-.detail-content {
- padding: 16px;
- font-size: 14px;
- line-height: 1.6;
- color: var(--van-text-color);
-}
-
-.detail-content:not(.rich-html-content) {
- white-space: pre-wrap;
-}
-
:deep(.van-pull-refresh) {
flex: 1;
overflow-y: auto;
diff --git a/Web/src/views/PeriodicRecord.vue b/Web/src/views/PeriodicRecord.vue
index 46c4906..72c7b54 100644
--- a/Web/src/views/PeriodicRecord.vue
+++ b/Web/src/views/PeriodicRecord.vue
@@ -107,141 +107,143 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
- 支出
-
-
- 收入
-
-
- 不计
-
-
-
-
-
-
- 请选择交易分类
- {{ form.classify }}
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 支出
+
+
+ 收入
+
+
+ 不计
+
+
+
+
+
+
+ 请选择交易分类
+ {{ form.classify }}
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 已支出
-
-
- ¥{{ formatMoney(budget.current) }}
-
-
-
-
- 预算
-
-
- ¥{{ formatMoney(budget.limit) }}
-
-
-
-
- 余额
-
-
- ¥{{ formatMoney(budget.limit - budget.current) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 已收入
-
-
- ¥{{ formatMoney(budget.current) }}
-
-
-
-
- 目标
-
-
- ¥{{ formatMoney(budget.limit) }}
-
-
-
-
- 差额
-
-
- ¥{{ formatMoney(Math.abs(budget.limit - budget.current)) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
- {{ item.category }}
+ style="padding: 12px 16px; text-align: center; color: #999; font-size: 14px; border-bottom: 1px solid var(--van-border-color)"
+ v-html="`本月共
${uncoveredCategories.length} 个分类未设置预算`"
+ />
+
+
+
+
+
+ {{ item.category }}
+
+
+ {{ item.transactionCount }} 笔记录
+
-
- {{ item.transactionCount }} 笔记录
-
-
-
-
- ¥{{ formatMoney(item.totalAmount) }}
+
+
+ ¥{{ formatMoney(item.totalAmount) }}
+
@@ -343,25 +203,31 @@
我知道了
-
+
-
-
-
+
+
+
+ {{ selectedDate.getFullYear() }}年{{ selectedDate.getMonth() + 1 }}月
+
+
+
-
+
-
-
+