diff --git a/CLAUDE.md b/CLAUDE.md
index 26dc12e..de83cb8 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -98,3 +98,9 @@ pnpm deploy:server # 部署后端到生产环境
- 当前无老师归属字段,统计范围是工作室;operatorId 不是授课老师。COMPLETED 是系统完成状态,不代表签到。
- 已上课程按时段去重,时长按已完成时段累加;上课人次按 COMPLETED 预约计数,学员按 userId 去重。取消、未出席、待确认、已确认独立计数。无日期补录不参与。
- 月历、学员排行和会员卡分布统计已完成记录;明细可组合日期、学员、状态筛选。新增测试目录只放该服务的 *.spec.ts。
+
+### 个人中心会员卡包
+- 个人中心资料区域以单行展示持有卡种和张数,下方每张卡以单行浅色进度槽承载卡名和用量文字,不使用大卡片或轮播;点击进入我的会员卡。`OwnedMembershipCard.vue` 在我的会员卡页面展示余额、已用进度和到期日。
+- 累计上课、本月上课、剩余课时集中在我的会员卡页面,个人资料卡不重复展示汇总。
+- 次数限制以 remainingTimes 是否为 null 判断,不能按卡种推断。次数进度表示已用占总次数,已用包括预约占用;不限次卡不伪造耗课数。
+- 会员卡加载失败显示重试,不当作无卡;会话变化时丢弃旧请求结果。
diff --git a/packages/app/src/components/OwnedMembershipCard.vue b/packages/app/src/components/OwnedMembershipCard.vue
new file mode 100644
index 0000000..ecf778f
--- /dev/null
+++ b/packages/app/src/components/OwnedMembershipCard.vue
@@ -0,0 +1,54 @@
+
+
+
+ {{ getCardTypeLabel(membership.cardType.type) }} · MEMBERSHIP{{ membership.cardType.name }}
+ {{ compact ? '查看 ›' : '有效' }}
+
+
+ {{ unlimited ? '有效期内' : '剩余' }}
+ {{ unlimited ? '不限次' : membership.remainingTimes }}
+ 次
+ 已用 {{ used }} / {{ total }} 次
+ {{ days }} 天后到期
+
+
+
+ {{ membership.startDate.slice(0, 10).replace(/-/g, '.') }} 起{{ membership.expireDate.slice(0, 10).replace(/-/g, '.') }} 到期
+
+
+
+
+
+
+
diff --git a/packages/app/src/components/UserCard.vue b/packages/app/src/components/UserCard.vue
index 732df0e..12c9825 100644
--- a/packages/app/src/components/UserCard.vue
+++ b/packages/app/src/components/UserCard.vue
@@ -49,36 +49,35 @@
-
-
-
- {{ stats?.totalBookings ?? '—' }}
- 累计上课 · 节
-
-
-
- {{ stats?.monthBookings ?? '—' }}
- 本月上课 · 节
-
-
-
- {{ remainingSessions }}
- 剩余课时 · 节
-
+
+
+