Преглед изворни кода

重新规划'我的'页面:四大区域布局+角色智能展示

核心变更:
- 四大区域:用户卡片(墨蓝渐变)→会员状态(按角色分支)→功能菜单(三组卡片)→退出登录
- 普通用户:品牌色upsell卡片展示4项权益+¥131开通按钮
- C端年费:橙色渐变卡+有效期+升级能量师按钮
- 能量师:紫色渐变卡+有效期+续费按钮+种子价专属badge
- 功能菜单:我的服务(分析/学业方向/推广)+推广工具(推广码独立金色卡)+更多(标签/关于我们)
- 编辑资料入口改到头像旁✏图标
- 学业方向入口标注NEW(EPIC 9)
- style-guide.md 6.5同步更新布局图
- 版本 v20260531.3
liaoxg пре 3 месеци
родитељ
комит
8f413a01e8
4 измењених фајлова са 713 додато и 159 уклоњено
  1. 616 123
      client/pages/profile/index.vue
  2. 20 11
      docs/phase1-user-stories.md
  3. 34 1
      docs/requirements-changelog.md
  4. 43 24
      docs/style-guide.md

+ 616 - 123
client/pages/profile/index.vue

@@ -1,93 +1,196 @@
 <template>
   <view class="page-profile">
+    <!-- ========== Region 1: User Card ========== -->
+    <view class="user-card">
+      <!-- Login prompt for unauthenticated users -->
+      <view v-if="!userStore.isLoggedIn" class="user-card__login" @click="goLogin">
+        <view class="avatar avatar--empty">
+          <text class="avatar__icon">+</text>
+        </view>
+        <text class="user-card__nickname">未登录</text>
+        <text class="user-card__login-hint">点击登录 / 注册</text>
+      </view>
+
+      <!-- Authenticated user card -->
+      <view v-else class="user-card__logged">
+        <view class="avatar">
+          <image :src="userStore.avatarUrl || '/static/default-avatar.png'" mode="aspectFill" />
+          <view class="avatar__edit" @click="goEditProfile">
+            <text class="avatar__edit-icon">✏</text>
+          </view>
+        </view>
+        <text class="user-card__nickname">{{ userStore.nickname }}</text>
+
+        <!-- Role tag -->
+        <view
+          class="user-card__tag"
+          :class="{
+            'user-card__tag--practitioner': userStore.vipType === 'practitioner',
+            'user-card__tag--annual': userStore.vipType === 'annual',
+            'user-card__tag--normal': !userStore.vipType
+          }"
+        >
+          <text v-if="!userStore.vipType">普通用户</text>
+          <text v-else-if="userStore.vipType === 'annual'">C端会员</text>
+          <text v-else>能量师 🌟</text>
+        </view>
+
+        <!-- Social summary (optional) -->
+        <text v-if="userStore.bio || userStore.city" class="user-card__summary">
+          {{ userStore.city || '' }}{{ userStore.city && userStore.bio ? ' · ' : '' }}{{ userStore.bio || '' }}
+        </text>
+      </view>
+    </view>
+
+    <!-- ========== Region 2: Membership Status Cards ========== -->
+
     <!-- US-5.1 §13: Profile incomplete banner -->
     <view v-if="userStore.isLoggedIn && userStore.profileIncomplete" class="banner" @click="goEditProfile">
-      <text class="banner-text">📝 请完善个人资料,开启能量匹配</text>
-      <text class="banner-arrow">›</text>
+      <text class="banner__text">📝 请完善个人资料,开启能量匹配</text>
+      <text class="banner__arrow">›</text>
     </view>
 
-    <!-- US-4.3: Renewal reminder -->
-    <view v-if="isExpiringSoon" class="renewal-banner" @click="goPayment">
-      <text class="renewal-text">⏰ 您的会员即将到期,请及时续费</text>
-      <text class="renewal-arrow">›</text>
+    <!-- US-4.3: Renewal reminder (7 days before expiry) -->
+    <view v-if="isExpiringSoon" class="banner banner--warning" @click="goRenew">
+      <text class="banner__text">⏰ 您的会员即将到期,请及时续费</text>
+      <text class="banner__arrow">›</text>
     </view>
 
-    <!-- User info card -->
-    <view class="user-card" @click="goLogin">
-      <view class="avatar">
-        <image :src="userStore.avatarUrl || '/static/default-avatar.png'" mode="aspectFill" />
-      </view>
-      <text class="nickname">{{ userStore.nickname || '未登录' }}</text>
-      <text v-if="!userStore.isLoggedIn" class="login-hint">点击登录</text>
-      <view v-if="userStore.isVip" class="vip-badge">VIP 会员</view>
+    <!-- Seed-price badge -->
+    <view v-if="userStore.isSeedPriceUser" class="seed-badge">
+      <text class="seed-badge__text">🌱 种子价专属会员</text>
     </view>
 
-    <!-- VIP status -->
-    <view v-if="userStore.vipType === 'practitioner' && userStore.isVip" class="vip-card pro" @click="goPayment">
-      <view class="vip-info">
-        <text class="vip-title">能量师会员</text>
-        <text class="vip-desc">
-          有效期至: {{ userStore.vipEndTime?.slice(0, 10) }}
+    <!-- VIP status card — role-based -->
+    <!-- Case 1: Energy master (practitioner, in valid period) -->
+    <view
+      v-if="userStore.vipType === 'practitioner' && userStore.isVip && !isExpired"
+      class="vip-card vip-card--practitioner"
+    >
+      <view class="vip-card__body">
+        <text class="vip-card__title">能量师会员 🌟</text>
+        <text class="vip-card__desc">
+          有效期至 {{ formatDate(userStore.vipEndTime) }}
         </text>
       </view>
-      <text class="vip-action">续费</text>
+      <text class="vip-card__action" @click="goRenew">续费</text>
     </view>
-    <view v-else-if="userStore.vipType === 'annual' && userStore.isVip" class="vip-card annual" @click="goUpgradePractitioner">
-      <view class="vip-info">
-        <text class="vip-title">C端会员</text>
-        <text class="vip-desc">
-          有效期至: {{ userStore.vipEndTime?.slice(0, 10) }}
+
+    <!-- Case 2: C-end annual subscriber (in valid period) -->
+    <view
+      v-else-if="userStore.vipType === 'annual' && userStore.isVip && !isExpired"
+      class="vip-card vip-card--annual"
+    >
+      <view class="vip-card__body">
+        <text class="vip-card__title">C端会员</text>
+        <text class="vip-card__desc">
+          有效期至 {{ formatDate(userStore.vipEndTime) }}
         </text>
       </view>
-      <text class="vip-action">升级能量师</text>
+      <text class="vip-card__action" @click="goUpgradePractitioner">升级能量师</text>
     </view>
-    <view v-else class="vip-card" @click="goPayment">
-      <view class="vip-info">
-        <text class="vip-title">VIP 会员</text>
-        <text class="vip-desc">
-          开通VIP获取完整分析
+
+    <!-- Case 3: Expired member (vipEndTime < now) -->
+    <view v-else-if="userStore.vipType && isExpired" class="vip-card vip-card--expired">
+      <view class="vip-card__body">
+        <text class="vip-card__title">会员已过期</text>
+        <text class="vip-card__desc">
+          过期时间 {{ formatDate(userStore.vipEndTime) }}
         </text>
       </view>
-      <text class="vip-action">立即开通</text>
+      <text class="vip-card__action" @click="goPayment">重新开通</text>
     </view>
 
-    <!-- Daily quota (non-VIP) -->
-    <view v-if="!userStore.isVip" class="quota-card">
-      <view class="quota-item">
-        <text class="quota-label">今日分析</text>
-        <text class="quota-value">{{ userStore.usedCharts }}/{{ userStore.maxCharts }}</text>
+    <!-- Case 4: Free user — upsell card -->
+    <view v-else class="vip-card vip-card--upsell">
+      <view class="vip-card__body">
+        <text class="vip-card__title">开通VIP · 解锁完整分析</text>
+        <view class="vip-card__benefits">
+          <text class="vip-card__benefit">✅ AI 完整五区解读</text>
+          <text class="vip-card__benefit">✅ 不限次 AI 追问互动</text>
+          <text class="vip-card__benefit">✅ 导出 PDF 报告</text>
+          <text class="vip-card__benefit">✅ 分销推广赚佣金</text>
+        </view>
       </view>
-      <view class="quota-divider"></view>
-      <view class="quota-item">
-        <text class="quota-label">今日解读</text>
-        <text class="quota-value">{{ userStore.usedChats }}/{{ userStore.maxChats }}</text>
+      <text class="vip-card__cta" @click="goPayment">立即开通 ¥131/年</text>
+    </view>
+
+    <!-- Daily quota (non-VIP only) -->
+    <view v-if="!userStore.isVip" class="quota-bar">
+      <view class="quota-bar__item">
+        <text class="quota-bar__label">今日分析</text>
+        <text class="quota-bar__value">{{ userStore.usedCharts }}/{{ userStore.maxCharts }}</text>
+      </view>
+      <view class="quota-bar__divider"></view>
+      <view class="quota-bar__item">
+        <text class="quota-bar__label">今日解读</text>
+        <text class="quota-bar__value">{{ userStore.usedChats }}/{{ userStore.maxChats }}</text>
       </view>
     </view>
 
-    <!-- Menu list -->
+    <!-- ========== Region 3: Feature Menu ========== -->
+
+    <!-- Group 1: My Services -->
     <view class="menu-section">
-      <view class="menu-item" @click="goEditProfile">
-        <text>✏️ 编辑资料</text>
-        <text class="menu-arrow">›</text>
+      <view class="menu-section__header">我的服务</view>
+
+      <!-- Analysis history (all logged-in) -->
+      <view v-if="userStore.isLoggedIn" class="menu-item" @click="goRecords">
+        <text class="menu-item__label">📋 我的分析</text>
+        <text class="menu-item__arrow">›</text>
       </view>
-      <view class="menu-item" @click="goRecords">
-        <text>📋 我的分析</text>
-        <text class="menu-arrow">›</text>
+
+      <!-- Academic orientation (all users, NEW badge) — EPIC 9 -->
+      <view v-if="userStore.isLoggedIn" class="menu-item" @click="goAcademicOrientation">
+        <text class="menu-item__label">📖 学业方向</text>
+        <view class="menu-item__badge menu-item__badge--new">NEW</view>
+        <text class="menu-item__arrow">›</text>
       </view>
-      <view class="menu-item" @click="goCommission">
-        <text>💰 我的推广</text>
-        <text class="menu-arrow">›</text>
+
+      <!-- Distribution panel (paid users only) -->
+      <view v-if="userStore.isLoggedIn && userStore.isVip" class="menu-item" @click="goCommission">
+        <text class="menu-item__label">💰 我的推广</text>
+        <text class="menu-item__arrow">›</text>
       </view>
-      <view class="menu-item" @click="copyReferral">
-        <text>🔗 推广码: {{ userStore.referralCode || '加载中' }}</text>
-        <text class="menu-tip">点击复制</text>
+    </view>
+
+    <!-- Group 2: Promotion Tools (paid users only) -->
+    <view v-if="userStore.isLoggedIn && userStore.isVip && userStore.referralCode" class="menu-section">
+      <view class="menu-section__header">推广工具</view>
+      <view class="promo-card">
+        <view class="promo-card__code-area">
+          <text class="promo-card__prefix">推广码</text>
+          <text class="promo-card__code">{{ userStore.referralCode }}</text>
+        </view>
+        <view class="promo-card__actions">
+          <text class="promo-card__btn" @click="copyReferral">复制推广码</text>
+          <text class="promo-card__divider">|</text>
+          <text class="promo-card__btn" @click="generatePoster">生成推广海报</text>
+        </view>
       </view>
     </view>
 
-    <!-- Actions -->
+    <!-- Group 3: More -->
     <view class="menu-section">
-      <view class="menu-item" @click="handleLogout">
-        <text style="color: #EF4444;">退出登录</text>
+      <view class="menu-section__header">更多</view>
+
+      <!-- My tags (practitioner only, P2) -->
+      <view v-if="userStore.vipType === 'practitioner'" class="menu-item" @click="goTags">
+        <text class="menu-item__label">🏷 我的标签</text>
+        <text class="menu-item__arrow">›</text>
+      </view>
+
+      <!-- About us (all) -->
+      <view class="menu-item" @click="goAbout">
+        <text class="menu-item__label">ℹ️ 关于我们</text>
+        <text class="menu-item__arrow">›</text>
+      </view>
+    </view>
+
+    <!-- ========== Region 4: Logout ========== -->
+    <view v-if="userStore.isLoggedIn" class="menu-section">
+      <view class="menu-item menu-item--danger" @click="handleLogout">
+        <text class="menu-item__label menu-item__label--danger">退出登录</text>
       </view>
     </view>
   </view>
@@ -108,6 +211,17 @@ const isExpiringSoon = computed(() => {
   return diffHours > 0 && diffHours <= 7 * 24
 })
 
+// US-4.3: Expired check
+const isExpired = computed(() => {
+  if (!userStore.vipEndTime) return false
+  return new Date(userStore.vipEndTime) < new Date()
+})
+
+function formatDate(dateStr) {
+  if (!dateStr) return ''
+  return dateStr.slice(0, 10)
+}
+
 onShow(() => {
   if (userStore.isLoggedIn) {
     userStore.fetchProfile()
@@ -116,6 +230,10 @@ onShow(() => {
   }
 })
 
+function goLogin() {
+  uni.navigateTo({ url: '/pages/login/index' })
+}
+
 function goEditProfile() {
   if (!userStore.isLoggedIn) {
     uni.navigateTo({ url: '/pages/login/index' })
@@ -124,15 +242,15 @@ function goEditProfile() {
   uni.navigateTo({ url: '/pages/profile/edit' })
 }
 
-function goLogin() {
-  if (!userStore.isLoggedIn) {
-    uni.navigateTo({ url: '/pages/login/index' })
-  }
-}
-
 function goPayment() {
   uni.navigateTo({ url: '/pages/payment/index?product=annual' })
 }
+
+function goRenew() {
+  const product = userStore.vipType === 'practitioner' ? 'practitioner' : 'annual'
+  uni.navigateTo({ url: `/pages/payment/index?product=${product}` })
+}
+
 function goUpgradePractitioner() {
   uni.navigateTo({ url: '/pages/payment/index?product=practitioner' })
 }
@@ -141,6 +259,11 @@ function goRecords() {
   uni.switchTab({ url: '/pages/records/index' })
 }
 
+function goAcademicOrientation() {
+  // EPIC 9: Navigate to academic orientation history
+  uni.navigateTo({ url: '/pages/academic/index' })
+}
+
 function goCommission() {
   if (!userStore.isLoggedIn) {
     uni.navigateTo({ url: '/pages/login/index' })
@@ -158,6 +281,19 @@ function copyReferral() {
   }
 }
 
+function generatePoster() {
+  uni.showToast({ title: '海报生成中…', icon: 'none' })
+  // US-6.5: Backend generates poster with mini-program code
+}
+
+function goTags() {
+  uni.navigateTo({ url: '/pages/tags/index' })
+}
+
+function goAbout() {
+  uni.navigateTo({ url: '/pages/about/index' })
+}
+
 function handleLogout() {
   uni.showModal({
     title: '确认退出',
@@ -173,82 +309,439 @@ function handleLogout() {
 </script>
 
 <style scoped lang="scss">
-.page-profile { padding: 16px; }
+// Brand colors (aligned with style-guide.md)
+$blue-dark: #1E3A5F;
+$gold: #C9A84C;
+$gold-light: #F8F0D8;
+$warm-white: #F8F6F1;
+$white: #FFFFFF;
+$text-primary: #1F2937;
+$text-secondary: #6B7280;
+$text-muted: #9CA3AF;
+$danger: #EF4444;
+
+.page-profile {
+  padding: 16px;
+  min-height: 100vh;
+  background: $warm-white;
+}
+
+// ========== Region 1: User Card ==========
 .user-card {
-  text-align: center; padding: 30px 0; background: #fff;
-  border-radius: 12px; margin-bottom: 16px;
+  background: linear-gradient(135deg, $blue-dark, darken($blue-dark, 6%));
+  border-radius: 16px;
+  padding: 32px 20px 28px;
+  margin-bottom: 16px;
+  text-align: center;
+
+  &__login {
+    cursor: pointer;
+  }
+
+  &__logged {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
+  &__nickname {
+    font-size: 18px;
+    font-weight: 600;
+    color: $white;
+    display: block;
+    margin-top: 12px;
+  }
+
+  &__login-hint {
+    font-size: 12px;
+    color: rgba(255, 255, 255, 0.7);
+    display: block;
+    margin-top: 4px;
+  }
+
+  &__tag {
+    display: inline-flex;
+    padding: 3px 14px;
+    border-radius: 20px;
+    font-size: 12px;
+    margin-top: 8px;
+
+    &--practitioner {
+      background: $gold;
+      color: $blue-dark;
+      font-weight: 600;
+    }
+
+    &--annual {
+      background: rgba($gold, 0.25);
+      color: $gold;
+    }
+
+    &--normal {
+      background: rgba(255, 255, 255, 0.15);
+      color: rgba(255, 255, 255, 0.8);
+    }
+  }
+
+  &__summary {
+    font-size: 12px;
+    color: rgba(255, 255, 255, 0.55);
+    margin-top: 6px;
+  }
 }
+
+// Avatar
 .avatar {
-  width: 64px; height: 64px; border-radius: 50%; overflow: hidden;
-  margin: 0 auto 12px;
+  width: 68px;
+  height: 68px;
+  border-radius: 50%;
+  overflow: visible;
+  position: relative;
+  margin: 0 auto;
+
+  image {
+    width: 100%;
+    height: 100%;
+    border-radius: 50%;
+    border: 2px solid rgba(255, 255, 255, 0.3);
+  }
+
+  &--empty {
+    background: rgba(255, 255, 255, 0.12);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border: 2px dashed rgba(255, 255, 255, 0.25);
+  }
+
+  &__icon {
+    font-size: 28px;
+    color: rgba(255, 255, 255, 0.5);
+  }
+
+  &__edit {
+    position: absolute;
+    right: -2px;
+    bottom: -2px;
+    width: 24px;
+    height: 24px;
+    border-radius: 50%;
+    background: $gold;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    z-index: 1;
+    cursor: pointer;
+
+    &-icon {
+      font-size: 12px;
+      color: $blue-dark;
+      font-weight: 700;
+    }
+  }
+}
+
+// ========== Region 2: Membership Status ==========
+
+// Banners
+.banner {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 10px 14px;
+  border-radius: 10px;
+  margin-bottom: 12px;
+  background: #FEF3C7;
+  border: 1px solid #FDE68A;
+
+  &--warning {
+    background: #FEF3C7;
+    border-color: #FDE68A;
+  }
+
+  &__text {
+    font-size: 13px;
+    color: #92400E;
+    flex: 1;
+  }
+
+  &__arrow {
+    font-size: 18px;
+    color: #92400E;
+    margin-left: 8px;
+  }
 }
-.avatar image { width: 100%; height: 100%; }
-.nickname { font-size: 18px; font-weight: 600; display: block; color: #1F2937; }
-.login-hint { font-size: 12px; color: #3B82F6; display: block; margin-top: 4px; }
-.vip-badge {
-  display: inline-block; background: #FEF3C7; color: #D97706;
-  padding: 2px 12px; border-radius: 12px; font-size: 12px; margin-top: 8px;
+
+// Seed-price badge
+.seed-badge {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 6px 14px;
+  border-radius: 8px;
+  margin-bottom: 12px;
+  background: $gold-light;
+  border: 1px solid $gold;
+
+  &__text {
+    font-size: 12px;
+    color: $blue-dark;
+    font-weight: 500;
+  }
 }
+
+// VIP status card
 .vip-card {
-  background: linear-gradient(135deg, #3B82F6, #2563EB); border-radius: 12px;
-  padding: 16px; display: flex; justify-content: space-between;
-  align-items: center; margin-bottom: 16px;
+  border-radius: 12px;
+  padding: 16px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 16px;
+
+  &__body {
+    flex: 1;
+  }
+
+  &__title {
+    font-weight: 600;
+    font-size: 16px;
+    display: block;
+  }
+
+  &__desc {
+    font-size: 12px;
+    opacity: 0.8;
+    display: block;
+    margin-top: 4px;
+  }
+
+  &__action {
+    font-size: 14px;
+    font-weight: 500;
+    padding: 6px 14px;
+    border-radius: 8px;
+    white-space: nowrap;
+    cursor: pointer;
+  }
+
+  // Practitioner
+  &--practitioner {
+    background: linear-gradient(135deg, #7c3aed, #6d28d9);
+    .vip-card__title, .vip-card__desc { color: #fff; }
+    .vip-card__action {
+      color: #7c3aed;
+      background: rgba(255, 255, 255, 0.95);
+    }
+  }
+
+  // Annual
+  &--annual {
+    background: linear-gradient(135deg, #f59e0b, #d97706);
+    .vip-card__title, .vip-card__desc { color: #fff; }
+    .vip-card__action {
+      color: #d97706;
+      background: rgba(255, 255, 255, 0.95);
+    }
+  }
+
+  // Expired
+  &--expired {
+    background: #E5E7EB;
+    .vip-card__title { color: $text-secondary; }
+    .vip-card__desc { color: $text-muted; }
+    .vip-card__action {
+      color: $text-secondary;
+      background: $white;
+    }
+  }
+
+  // Upsell (free user)
+  &--upsell {
+    background: linear-gradient(135deg, $blue-dark, darken($blue-dark, 4%));
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 14px;
+
+    .vip-card__title {
+      color: $gold;
+      font-size: 16px;
+    }
+
+    & .vip-card__benefits {
+      display: flex;
+      flex-direction: column;
+      gap: 4px;
+      margin-top: 8px;
+    }
+
+    .vip-card__benefit {
+      color: rgba(255, 255, 255, 0.8);
+      font-size: 13px;
+    }
+
+    .vip-card__cta {
+      align-self: stretch;
+      text-align: center;
+      background: $gold;
+      color: $blue-dark;
+      font-weight: 600;
+      font-size: 15px;
+      padding: 12px;
+      border-radius: 10px;
+      cursor: pointer;
+    }
+  }
 }
-.vip-card.annual {
-  background: linear-gradient(135deg, #f59e0b, #d97706);
+
+// Daily quota
+.quota-bar {
+  background: $white;
+  border-radius: 12px;
+  padding: 16px;
+  margin-bottom: 16px;
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
+
+  &__item {
+    text-align: center;
+  }
+
+  &__label {
+    font-size: 12px;
+    color: $text-secondary;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  &__value {
+    font-size: 20px;
+    font-weight: 700;
+    color: $text-primary;
+  }
+
+  &__divider {
+    width: 1px;
+    height: 36px;
+    background: #E5E7EB;
+  }
 }
-.vip-card.pro {
-  background: linear-gradient(135deg, #7c3aed, #6d28d9);
+
+// ========== Region 3: Feature Menu ==========
+.menu-section {
+  background: $white;
+  border-radius: 12px;
+  margin-bottom: 16px;
+  overflow: hidden;
+
+  &__header {
+    font-size: 12px;
+    font-weight: 600;
+    color: $text-muted;
+    text-transform: uppercase;
+    letter-spacing: 0.5px;
+    padding: 14px 16px 6px;
+  }
 }
-.vip-title { color: #fff; font-weight: 600; font-size: 16px; display: block; }
-.vip-desc { color: rgba(255,255,255,0.8); font-size: 12px; display: block; margin-top: 4px; }
-.vip-action { color: #fff; font-size: 14px; font-weight: 500; }
-.menu-section { background: #fff; border-radius: 12px; margin-bottom: 16px; overflow: hidden; }
+
 .menu-item {
-  display: flex; justify-content: space-between; align-items: center;
-  padding: 14px 16px; border-bottom: 1px solid #F3F4F6;
-}
-.menu-item:last-child { border-bottom: none; }
-.menu-arrow { color: #9CA3AF; font-size: 18px; }
-.menu-tip { color: #3B82F6; font-size: 12px; }
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  padding: 14px 16px;
+  border-bottom: 1px solid #F3F4F6;
+  cursor: pointer;
+  transition: background 0.15s;
 
-.quota-card {
-  background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 16px;
-  display: flex; align-items: center; justify-content: space-around;
-}
-.quota-item { text-align: center; }
-.quota-label { font-size: 12px; color: #6B7280; display: block; margin-bottom: 4px; }
-.quota-value { font-size: 20px; font-weight: 700; color: #1F2937; }
-.quota-divider { width: 1px; height: 36px; background: #E5E7EB; }
+  &:active {
+    background: #F9FAFB;
+  }
 
-  /* US-5.1 §13 profile incomplete banner */
-  .banner {
-    background: #FEF3C7; border: 1px solid #FDE68A; border-radius: 10px;
-    padding: 10px 14px; margin-bottom: 12px;
-    display: flex; justify-content: space-between; align-items: center;
+  &:last-child {
+    border-bottom: none;
   }
-  .banner-text { font-size: 13px; color: #92400E; flex: 1; }
-  .banner-arrow { font-size: 18px; color: #92400E; margin-left: 8px; }
 
-  /* US-4.3 Renewal reminder */
-  .renewal-banner {
-    background: #FEF3C7;
-    border: 1px solid #FDE68A;
-    border-radius: 10px;
-    padding: 10px 14px;
-    margin-bottom: 12px;
+  &__label {
+    flex: 1;
+    font-size: 15px;
+    color: $text-primary;
+
+    &--danger {
+      color: $danger;
+    }
+  }
+
+  &__badge {
+    font-size: 10px;
+    font-weight: 700;
+    padding: 2px 6px;
+    border-radius: 4px;
+
+    &--new {
+      background: #FEF3C7;
+      color: #D97706;
+    }
+  }
+
+  &__arrow {
+    color: $text-muted;
+    font-size: 18px;
+  }
+
+  &--danger {
+    justify-content: center;
+    border-bottom: none;
+  }
+}
+
+// Promotion tools card
+.promo-card {
+  margin: 0 16px 14px;
+  background: #FFFBEB;
+  border: 1px solid #FDE68A;
+  border-radius: 10px;
+  overflow: hidden;
+
+  &__code-area {
     display: flex;
-    justify-content: space-between;
     align-items: center;
+    justify-content: center;
+    gap: 10px;
+    padding: 14px 16px 8px;
   }
-  .renewal-text {
+
+  &__prefix {
     font-size: 13px;
-    color: #92400E;
-    flex: 1;
+    color: $text-secondary;
   }
-  .renewal-arrow {
-    font-size: 18px;
-    color: #92400E;
-    margin-left: 8px;
+
+  &__code {
+    font-size: 22px;
+    font-weight: 700;
+    color: $blue-dark;
+    letter-spacing: 3px;
+    font-family: monospace;
+  }
+
+  &__actions {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 10px;
+    padding: 6px 16px 14px;
   }
-</style>
+
+  &__btn {
+    font-size: 12px;
+    color: $blue-dark;
+    font-weight: 500;
+    cursor: pointer;
+  }
+
+  &__divider {
+    color: #D1D5DB;
+    font-size: 12px;
+  }
+}
+</style>

+ 20 - 11
docs/phase1-user-stories.md

@@ -431,11 +431,19 @@
 
 **验收标准:**
 
-1. 个人中心显示:订阅状态(能量师/C端会员/已过期/普通用户)
-2. 显示到期日期,到期前 7 天显示续费提醒
-3. 到期后自动降级为普通用户,分销面板入口隐藏
-4. 续费操作按**标准价**执行(种子价仅限首次,不限能量师或C端)
-5. 续费成功后有效期在原到期日基础上延长1年
+1. 个人中心("我的"页面)显示用户头像、昵称、角色标签(普通用户/C端年费/能量师 🌟)
+2. 角色标签使用暗金色 #C9A84C,字体 12px
+3. 用户卡片下方按角色显示**会员状态卡片**:
+   - **普通用户**(`vipType=NULL`):品牌色(墨蓝 #1E3A5F)渐变卡片 + 权益摘要(3-4项)+ "立即开通 ¥131/年"按钮
+   - **C端年费**(`vipType='annual'`,有效期内):橙色渐变卡片 + "已开通C端会员" + 有效期 + "升级能量师"按钮
+   - **能量师**(`vipType='practitioner'`,有效期内):紫色渐变卡片 + "能量师会员 🌟" + 有效期 + "续费"按钮  
+   - **已过期**(`vipEndTime < now`):灰色卡片 + "已过期"标记 + "重新开通"按钮
+4. 种子价会员在状态卡片下方额外显示"🌱 种子价专属标记"(暗金文字,淡金色背景)
+5. 到期前 7 天在状态卡片上方显示黄色 banner:"⏰ 您的会员即将到期,请及时续费"
+6. 资料不完整的用户(`profile_incomplete = true`)在状态卡片上方显示引导 banner:"📝 请完善个人资料,开启能量匹配"
+7. 到期后自动降级为普通用户,分销面板入口隐藏
+8. 续费操作按**标准价**执行(种子价仅限首次)
+9. 续费成功后有效期在原到期日基础上延长1年
 
 ### US-4.4 年费升级能量师(升级定价与流程)
 
@@ -445,7 +453,7 @@
 
 **验收标准(升级定价):**
 
-1. 用户现有 `vipType='annual'` 且 `vipEndTime > now`,可在个人中心点击"升级能量师"
+1. 用户现有 `vipType='annual'` 且 `vipEndTime > now`,可在"我的"页面 → 会员状态卡片(C端年费)点击"升级能量师"按钮
 2. 升级价格由后端计算,公式:
 
 ```
@@ -549,7 +557,7 @@
 16. `POST /api/auth/login` 响应增加 `profileIncomplete` 字段
 17. 新增 `POST /api/profile/complete` 接口,接收所有注册字段
 18. 新增 `POST /api/profile/update` 接口,允许修改任意字段
-19. `POST /api/profile/info` 响应增加全部新字段
+19. `POST /api/profile/info` 响应增加全部新字段,额外新增 `isSeedPriceUser`(Boolean — 当前用户是否以种子价购买的能量师)
 
 **验收标准(老用户兼容):**
 
@@ -565,7 +573,7 @@
 
 **验收标准:**
 
-1. 个人中心页包含"我的咨询"列表
+1. "我的"页面 → "我的服务"分组 → "📋 我的分析"入口 → 跳转到咨询记录列表页
 2. 列表按最后互动时间倒序排列
 3. 每条记录显示:姓名、生日、咨询时间、最后一条消息摘要
 4. 点击记录可跳转到对应的命盘展示页,并恢复完整的聊天历史
@@ -581,7 +589,7 @@
 
 **验收标准:**
 
-1. 个人中心新增"编辑资料"入口
+1. "我的"页面 → 用户卡片 → 头像旁的✏️图标(或文字链接)→ 跳转到编辑资料页
 2. 编辑页包含:头像、昵称、性别、生日、简介、城市、兴趣标签、想认识
 3. 资料字段定义同 US-5.1 注册完善页
 4. 修改后调用 `POST /api/profile/update`
@@ -802,7 +810,7 @@ isUpgrade = false → 全额发放:L1 = ¥500,L2 = ¥100
 **验收标准:**
 
 **入口权限:**
-1. 个人中心菜单项"💰 我的推广"→ 跳转到分销面板
+1. "我的"页面 → "我的服务"分组 → "💰 我的推广"入口 → 跳转到分销面板
 2. **仅付费用户可见**(`vipEndTime > now`),普通用户看不到入口
 3. 付费到期后入口自动隐藏
 
@@ -909,7 +917,8 @@ isUpgrade = false → 全额发放:L1 = ¥500,L2 = ¥100
 
 **入口:**
 1. 命盘解读页底部增加"🎓 学业方向分析"按钮(位于通用解读下方第二行)
-2. 点击后调用新接口 `POST /api/chart/academic-orientation`
+2. "我的"页面 → "我的服务"分组 → "📖 学业方向"入口 → 跳转到学业方向历史列表页
+3. 点击后调用新接口 `POST /api/chart/academic-orientation`
 
 **AI 解读内容:**
 3. 后端转发至 Dify **学业方向专用 Workflow**,命盘24个数字(A-X)作为 `inputs`

+ 34 - 1
docs/requirements-changelog.md

@@ -5,7 +5,40 @@
 
 ---
 
-## v20260531.2(当前版本)
+## v20260531.3(当前版本)
+
+**发布日期:** 2026-05-31
+**变更类型:** 设计重构
+**状态:** ✅ 已确认
+
+### 版本摘要
+
+重新规划"我的"页面(个人中心),从纯列表菜单改为四大区域布局(用户卡片→会员状态→功能菜单→退出登录),按用户角色(普通/C端/能量师)智能展示不同内容。
+
+### 变更清单
+
+| # | 类型 | 变更 | 涉及位置 |
+|---|------|------|---------|
+| 1 | 🆕 设计 | 四大区域布局:用户卡片(墨蓝渐变背景+角色标签+社交摘要) | style-guide.md 6.5 |
+| 2 | 🆕 设计 | 会员状态卡片按角色分支展示(免费upsell/年费橙色/能量师紫色/已过期灰色) | US-4.3 |
+| 3 | 🔧 更新 | 功能菜单改为三组卡片式:我的服务 + 推广工具 + 更多 | US-5.2 |
+| 4 | 🆕 新增 | 学业方向入口(📖)置于我的服务组,标注NEW | EPIC 9 |
+| 5 | 🆕 新增 | 推广码独立卡片(金色背景,大号monospace字体) | US-6.5 |
+| 6 | 🔧 更新 | 编辑资料入口改到头像旁 ✏ 图标 | US-5.3 |
+| 7 | 🆕 新增 | 种子价会员在状态卡片下方显示专属标记"🌱 种子价专属会员" | US-4.3 |
+| 8 | 🆕 新增 | 前端代码:页面重构(`client/pages/profile/index.vue`) | 前端代码 |
+
+### 影响范围
+
+- 前端页面:`client/pages/profile/index.vue`(重构)
+- 需求文档:US-4.3(重写验收标准1-9)、US-5.2(入口描述)、US-5.3(编辑入口)、US-6.5(入口描述)、US-9.1(新增学业方向入口)
+- 样式指南:style-guide.md 6.5(完整布局图)
+- 种子价会员:状态卡片下方新增金色 badge
+- 种子价会员:需后端字段 `isSeedPriceUser`
+
+---
+
+## v20260531.2(已归档)
 
 **发布日期:** 2026-05-31
 **变更类型:** 修正

+ 43 - 24
docs/style-guide.md

@@ -462,30 +462,49 @@ button[disabled] {
 ### 6.5 个人中心
 
 ```
-┌─────────────────────┐
-│  我的                │
-├─────────────────────┤
-│                     │
-│  ┌───────────────┐  │
-│  │   (头像)       │  │  用户卡片(居中)
-│  │   张三          │  │  16px bold
-│  │   🔮 能量师会员  │  │  金色VIP标记
-│  │   有效期至...    │  │
-│  └───────────────┘  │
-│                     │
-│  ┌───────────────┐  │
-│  │  📋 我的分析    ›│  │  功能菜单列表
-│  │  💰 我的推广    ›│  │  仅能量师可见
-│  │  ℹ️ 关于我们    ›│  │
-│  └───────────────┘  │
-│                     │
-│  ┌───────────────┐  │
-│  │  退出登录       │  │  红色文字
-│  └───────────────┘  │
-│                     │
-├─────────────────────┤
-│  TabBar              │
-└─────────────────────┘
+┌─────────────────────────┐
+│  我的                     │
+├─────────────────────────┤
+│                         │
+│  ┌─────────────────┐    │
+│  │    (头像/64px)    │    │  区域一:用户卡片
+│  │    张三           │    │  白色16px bold
+│  │    能量师 🌟      │    │  (暗金)C9A84C 标签
+│  │    北京 · 射手座    │    │  社交摘要(可选)
+│  │  ✏️ 编辑资料       │    │  灰色12px
+│  │                     │    │  背景: #1E3A5F 渐变
+│  └─────────────────┘    │
+│                         │
+│  ┌─────────────────┐    │
+│  │  能量师会员       │    │  区域二:会员状态卡片
+│  │  有效期至 2027-05 │    │  (按角色动态展示)
+│  │  [续费] [升级]     │    │  (暗金渐变/橙色/紫色/灰色)
+│  └─────────────────┘    │
+│  ┌─────────────────┐    │
+│  │  种子价专属标记    │    │  仅种子价会员显示
+│  └─────────────────┘    │
+│                         │
+│  ┌─────────────────┐    │  区域三:功能菜单(分组卡片)
+│  │  📋 我的分析    ›│    │  「我的服务」
+│  │  📖 学业方向    ›│    │  所有用户(标注 NEW)
+│  │  💰 我的推广    ›│    │  仅付费用户可见
+│  └─────────────────┘    │
+│  ┌─────────────────┐    │
+│  │  🔗 ABC123       │    │  「推广工具」(仅付费用户)
+│  │  [复制推广码]     │    │  金色背景条 #FEF3C7
+│  └─────────────────┘    │
+│  ┌─────────────────┐    │
+│  │  🏷 我的标签    ›│    │  「更多」(能量师)
+│  │  ℹ️ 关于我们    ›│    │  所有用户
+│  └─────────────────┘    │
+│                         │
+│  ┌─────────────────┐    │  区域四:退出登录
+│  │  退出登录(红色)   │    │
+│  └─────────────────┘    │
+│                         │
+├─────────────────────────┤
+│  TabBar                  │
+└─────────────────────────┘
 ```
 
 **设计要点:**