Browse Source

个人中心信息编写

“陈博论” 9 tháng trước cách đây
mục cha
commit
3b9419a7b4

+ 50 - 0
web/src/api/frontend/me.ts

@@ -0,0 +1,50 @@
+import createAxios from '/@/utils/axios'
+
+//我的主页数据
+export function dashboard() {
+    return createAxios({
+        url: '/api/user/dashboard',
+        method: 'get',
+    })
+}
+
+//用户购买记录
+export function purchaseRecordsSimple() {
+  return createAxios({
+      url: '/api/invitation.order/purchaseRecordsSimple',
+      method: 'get',
+  })
+}
+
+//获取订单详情
+export function orderDetail(data:anyObj) {
+  return createAxios({
+      url: '/api/invitation.order/orderDetail',
+      method: 'get',
+      params:data,
+  })
+}
+
+//产品列表
+export function purchasedList() {
+  return createAxios({
+      url: '/api/invitation.product/purchasedList',
+      method: 'get',
+  })
+}
+
+//产品详情
+export function productDetail() {
+  return createAxios({
+      url: '/api/invitation.product/detail',
+      method: 'get',
+  })
+}
+
+//获取下级用户列表
+export function subordinateList() {
+  return createAxios({
+      url: '/api/user/subordinateList',
+      method: 'get',
+  })
+}

+ 0 - 5
web/src/views/frontend/Me.vue

@@ -61,11 +61,6 @@ const menuList = reactive<MenuItem[]>([
   { label: '我的企业', value: 'enterprise', component: markRaw(Enterprise), icon: markRaw(OfficeBuilding) }
 ])
 
-const currentMenuLabel = computed(() => {
-  const current = menuList.find(item => item.value === activeMenu.value)
-  return current ? current.label : ''
-})
-
 const currentComponent = computed(() => {
   const current = menuList.find(item => item.value === activeMenu.value)
   return current ? current.component : Info

+ 15 - 3
web/src/views/frontend/Register.vue

@@ -40,7 +40,7 @@
         </el-form-item>
 
         <el-form-item label="邀请码(选填)" prop="inviteCode">
-          <el-input v-model.trim="registerForm.inviteCode" placeholder="没有可留空" clearable />
+          <el-input :disabled="userRegister" v-model.trim="registerForm.inviteCode" placeholder="没有可留空" clearable />
         </el-form-item>
 
         <el-form-item>
@@ -57,8 +57,8 @@
 </template>
 
 <script setup>
-import { computed, onBeforeUnmount, reactive, ref } from 'vue'
-import { useRouter } from 'vue-router'
+import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
+import { useRouter, useRoute } from 'vue-router'
 import { ElMessage } from 'element-plus'
 import { checkIn } from '/@/api/frontend/user/index'
 import { sendEms } from '/@/api/common'
@@ -69,7 +69,10 @@ import { useUserInfo } from '/@/stores/userInfo'
 defineOptions({ name: 'ClientRegister' })
 
 const router = useRouter()
+const route = useRoute()
 const userInfo = useUserInfo()
+// 邀请码开关
+const userRegister = ref(false)
 
 const registerFormRef = ref(null)
 const registerForm = reactive({
@@ -215,6 +218,15 @@ const handleSendEmailCode = () => {
   })
 }
 
+// 组件挂载时检查 URL 中的邀请码参数
+onMounted(() => {
+  const inviteCode = route.query.invite
+  if (inviteCode && typeof inviteCode === 'string') {
+    registerForm.inviteCode = inviteCode.trim()
+    userRegister.value = true
+  }
+})
+
 onBeforeUnmount(() => {
   clearCountdown()
 })

+ 661 - 45
web/src/views/frontend/components/Me/info.vue

@@ -10,56 +10,193 @@
       <p class="welcome-text">欢迎回来, {{ userName }}</p>
     </div>
 
-    <!-- 财务卡片 -->
-    <div class="finance-cards">
-      <div class="finance-card">
-        <div class="card-icon">
-          <el-icon class="card-icon__inner">
-            <Medal />
-          </el-icon>
+   
+
+    <!-- 佣金详情区域 -->
+    <div class="commission-section">
+      <h3 class="section-title">
+        <el-icon class="title-icon"><TrendCharts /></el-icon>
+        佣金详情
+      </h3>
+      <div class="commission-grid">
+        <div class="commission-card">
+          <div class="commission-icon icon-total">
+            <el-icon><Medal /></el-icon>
+          </div>
+          <div class="commission-content">
+            <div class="commission-label">总佣金</div>
+            <div class="commission-value">¥{{ formatMoney(uersInfo?.commission_info?.total_commission) }}</div>
+            <div class="commission-desc">累计获得的所有佣金</div>
+          </div>
+        </div>
+        <div class="commission-card">
+          <div class="commission-icon icon-current">
+            <el-icon><Wallet /></el-icon>
+          </div>
+          <div class="commission-content">
+            <div class="commission-label">当前佣金</div>
+            <div class="commission-value">¥{{ formatMoney(uersInfo?.commission_info?.current_commission) }}</div>
+            <div class="commission-desc">可提现的佣金余额</div>
+          </div>
+        </div>
+        <div class="commission-card">
+          <div class="commission-icon icon-withdrawn">
+            <el-icon><Money /></el-icon>
+          </div>
+          <div class="commission-content">
+            <div class="commission-label">已提现佣金</div>
+            <div class="commission-value">¥{{ formatMoney(uersInfo?.commission_info?.withdrawn_commission) }}</div>
+            <div class="commission-desc">已经成功提现的金额</div>
+          </div>
+        </div>
+        <div class="commission-card">
+          <div class="commission-icon icon-frozen">
+            <el-icon><Lock /></el-icon>
+          </div>
+          <div class="commission-content">
+            <div class="commission-label">冻结中佣金</div>
+            <div class="commission-value">¥{{ formatMoney(uersInfo?.commission_info?.frozen_commission) }}</div>
+            <div class="commission-desc">暂时无法提现的佣金</div>
+          </div>
+        </div>
+        <div class="commission-card">
+          <div class="commission-icon icon-today">
+            <el-icon><Calendar /></el-icon>
+          </div>
+          <div class="commission-content">
+            <div class="commission-label">今日佣金</div>
+            <div class="commission-value">¥{{ formatMoney(uersInfo?.commission_info?.today_income) }}</div>
+            <div class="commission-desc">今天获得的佣金收入</div>
+          </div>
+        </div>
+        <div class="commission-card">
+          <div class="commission-icon icon-month">
+            <el-icon><TrendCharts /></el-icon>
+          </div>
+          <div class="commission-content">
+            <div class="commission-label">当月佣金</div>
+            <div class="commission-value">¥{{ formatMoney(uersInfo?.commission_info?.month_income) }}</div>
+            <div class="commission-desc">本月累计获得的佣金</div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 邀请信息 -->
+    <div class="promotion-section">
+      <h3 class="section-title">
+        <el-icon class="title-icon"><User /></el-icon>
+        邀请信息
+      </h3>
+      
+      <!-- 邀请统计卡片 -->
+      <div class="promotion-stats">
+        <div class="stat-card stat-primary">
+          <div class="stat-icon">
+            <el-icon><Avatar /></el-icon>
+          </div>
+          <div class="stat-content">
+            <div class="stat-label">邀请总人数</div>
+            <div class="stat-value">{{ uersInfo?.promotion_info?.total_invitation || 0 }}</div>
+            <div class="stat-desc">累计邀请的总人数</div>
+          </div>
         </div>
-        <div class="card-content">
-          <div class="card-label">总收入</div>
-          <div class="card-value">¥{{ commission_total || '0' }}</div>
+        <div class="stat-card stat-success">
+          <div class="stat-icon">
+            <el-icon><Calendar /></el-icon>
+          </div>
+          <div class="stat-content">
+            <div class="stat-label">今日邀请人数</div>
+            <div class="stat-value">{{ uersInfo?.promotion_info?.invitation_count || 0 }}</div>
+            <div class="stat-desc">今天新增的邀请人数</div>
+          </div>
         </div>
       </div>
-      <div class="finance-card">
-        <div class="card-icon">
-          <el-icon class="card-icon__inner">
-            <Coin />
-          </el-icon>
+
+      <!-- 邀请码卡片 -->
+      <div class="promotion-card">
+        <div class="promotion-card-header">
+          <div class="promotion-card-title">
+            <el-icon class="title-icon-small"><Ticket /></el-icon>
+            <span>我的邀请码</span>
+          </div>
         </div>
-        <div class="card-content">
-          <div class="card-label">余额</div>
-          <div class="card-value">¥{{ commission_amount || '0' }}</div>
+        <div class="promotion-card-body">
+          <div class="code-display">
+            <span class="code-text">{{ uersInfo?.promotion_info?.invitation_code || '-' }}</span>
+            <el-button 
+              type="primary" 
+              :icon="DocumentCopy" 
+              size="small" 
+              circle
+              @click="copyInvitationCode"
+              class="copy-btn"
+            />
+          </div>
+          <div class="code-desc">分享此邀请码给好友,好友注册后您将获得丰厚佣金</div>
         </div>
       </div>
-      <div class="finance-card">
-        <div class="card-icon">
-          <el-icon class="card-icon__inner">
-            <Avatar />
-          </el-icon>
+
+      <!-- 邀请链接卡片 -->
+      <div class="promotion-card">
+        <div class="promotion-card-header">
+          <div class="promotion-card-title">
+            <el-icon class="title-icon-small"><Link /></el-icon>
+            <span>我的邀请链接</span>
+          </div>
         </div>
-        <div class="card-content">
-          <div class="card-label">推广人数</div>
-          <div class="card-value">{{ promoters || '0' }}</div>
+        <div class="promotion-card-body">
+          <div class="link-display">
+            <div class="link-text">{{ uersInfo?.promotion_info?.promotion_link || '-' }}</div>
+            <el-button 
+              type="primary" 
+              :icon="DocumentCopy" 
+              size="small" 
+              circle
+              @click="copyInvitationLink"
+              class="copy-btn"
+            />
+          </div>
+          <div class="link-desc">通过该链接注册的用户,其消费将为您带来丰厚佣金</div>
         </div>
       </div>
     </div>
 
-    <!-- 商户信息 -->
-    <div class="info-section">
-      <h3 class="section-title">商户信息</h3>
-      <div class="info-grid">
-        <div class="info-item">
-          <span class="info-label">商户ID:</span>
-          <span class="info-value merchant-id">{{ user_id || '-' }}</span>
+    <!-- 登录信息 -->
+    <div class="login-section">
+      <h3 class="section-title">
+        <el-icon class="title-icon"><Monitor /></el-icon>
+        登录信息
+      </h3>
+      <div class="login-grid">
+        <div class="login-card">
+          <div class="login-icon icon-current">
+            <el-icon><Clock /></el-icon>
+          </div>
+          <div class="login-content">
+            <div class="login-label">本次登录时间</div>
+            <div class="login-value">{{ uersInfo?.login_info?.current_login_time || '-' }}</div>
+            <div class="login-desc">您当前会话的登录时间</div>
+          </div>
+        </div>
+        <div class="login-card">
+          <div class="login-icon icon-last">
+            <el-icon><Clock /></el-icon>
+          </div>
+          <div class="login-content">
+            <div class="login-label">上次登录时间</div>
+            <div class="login-value">{{ uersInfo?.login_info?.last_login_time || '-' }}</div>
+            <div class="login-desc">您上一次登录的时间</div>
+          </div>
         </div>
-        <div class="info-item full-width">
-          <span class="info-label">推广链接:</span>
-          <div class="promotion-link-wrapper">
-            <span>{{ promotion_link || '-' }}</span>
-            <span class="promotion-desc">(通过该链接消费的人会给您丰厚的佣金)</span>
+        <div class="login-card">
+          <div class="login-icon icon-ip">
+            <el-icon><Connection /></el-icon>
+          </div>
+          <div class="login-content">
+            <div class="login-label">登录IP地址</div>
+            <div class="login-value">{{ uersInfo?.login_info?.join_ip || '-' }}</div>
+            <div class="login-desc">您当前登录的IP地址</div>
           </div>
         </div>
       </div>
@@ -70,25 +207,75 @@
 
 <script setup lang="ts">
 import { computed, onMounted, ref } from 'vue'
-import { Avatar, Coin, Medal } from '@element-plus/icons-vue'
+import { Avatar, Coin, Medal, Wallet, Money, Lock, TrendCharts, Calendar, DocumentCopy, User, Link, Ticket, Clock, Monitor, Connection } from '@element-plus/icons-vue'
+import { ElMessage } from 'element-plus'
 import { storeToRefs } from 'pinia'
 import { useUserInfo } from '/@/stores/userInfo'
+import { dashboard } from '/@/api/frontend/me'
 
 defineOptions({ name: 'MeInfo' })
 
 const userStore = useUserInfo()
 const { username, email, id } = storeToRefs(userStore)
 
-const promoters = ref<string | number>(0)
-const promotion_link = ref('')
-const commission_total = ref<string | number>(0)
-const commission_amount = ref<string | number>(0)
-const user_id = computed(() => id.value || '-')
+// 用户信息
+const uersInfo = ref<anyObj>({})
 
 const userName = computed(() => username.value || email.value)
 
+// 格式化金额
+const formatMoney = (amount: number | undefined) => {
+  if (amount === undefined || amount === null) return '0.00'
+  return Number(amount).toFixed(2)
+}
+
+// 复制邀请码
+const copyInvitationCode = () => {
+  const code = uersInfo.value?.promotion_info?.invitation_code
+  if (!code) {
+    ElMessage.warning('邀请码不存在')
+    return
+  }
+  navigator.clipboard.writeText(code).then(() => {
+    ElMessage.success('邀请码已复制到剪贴板')
+  }).catch(() => {
+    // 降级方案
+    const textarea = document.createElement('textarea')
+    textarea.value = code
+    document.body.appendChild(textarea)
+    textarea.select()
+    document.execCommand('copy')
+    document.body.removeChild(textarea)
+    ElMessage.success('邀请码已复制到剪贴板')
+  })
+}
+
+// 复制邀请链接
+const copyInvitationLink = () => {
+  const link = uersInfo.value?.promotion_info?.promotion_link
+  if (!link) {
+    ElMessage.warning('邀请链接不存在')
+    return
+  }
+  navigator.clipboard.writeText(link).then(() => {
+    ElMessage.success('邀请链接已复制到剪贴板')
+  }).catch(() => {
+    // 降级方案
+    const textarea = document.createElement('textarea')
+    textarea.value = link
+    document.body.appendChild(textarea)
+    textarea.select()
+    document.execCommand('copy')
+    document.body.removeChild(textarea)
+    ElMessage.success('邀请链接已复制到剪贴板')
+  })
+}
+
+// 获取用户信息
 const getUserInfo = () => {
-  // TODO: 接入实际的用户信息获取逻辑
+  dashboard().then(res => {
+    uersInfo.value = res.data
+  })
 }
 
 onMounted(() => {
@@ -134,6 +321,197 @@ onMounted(() => {
       font-weight: 600;
       color: #303133;
     }
+  }
+
+  .promotion-section {
+    margin-top: 30px;
+    padding: 24px;
+    background: linear-gradient(135deg, #fafbfc 0%, #ffffff 100%);
+    border-radius: 12px;
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
+
+    .section-title {
+      display: flex;
+      align-items: center;
+      margin: 0 0 24px 0;
+      font-size: 20px;
+      font-weight: 600;
+      color: #303133;
+
+      .title-icon {
+        margin-right: 8px;
+        font-size: 22px;
+        color: #409EFF;
+      }
+    }
+
+    .promotion-stats {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr);
+      gap: 16px;
+      margin-bottom: 24px;
+
+      @media (max-width: 768px) {
+        grid-template-columns: 1fr;
+      }
+
+      .stat-card {
+        display: flex;
+        align-items: center;
+        padding: 20px;
+        background: #ffffff;
+        border-radius: 10px;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+        border: 1px solid #f0f0f0;
+        transition: all 0.3s ease;
+
+        &:hover {
+          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+          transform: translateY(-2px);
+        }
+
+        &.stat-primary {
+          border-left: 4px solid #409EFF;
+        }
+
+        &.stat-success {
+          border-left: 4px solid #67C23A;
+        }
+
+        .stat-icon {
+          width: 48px;
+          height: 48px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          border-radius: 10px;
+          margin-right: 16px;
+          flex-shrink: 0;
+          font-size: 24px;
+          color: #fff;
+        }
+
+        &.stat-primary .stat-icon {
+          background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
+        }
+
+        &.stat-success .stat-icon {
+          background: linear-gradient(135deg, #67C23A 0%, #85ce61 100%);
+        }
+
+        .stat-content {
+          flex: 1;
+
+          .stat-label {
+            font-size: 14px;
+            color: #909399;
+            margin-bottom: 6px;
+            font-weight: 500;
+          }
+
+          .stat-value {
+            font-size: 28px;
+            font-weight: 700;
+            color: #303133;
+            margin-bottom: 4px;
+          }
+
+          .stat-desc {
+            font-size: 12px;
+            color: #C0C4CC;
+            line-height: 1.4;
+          }
+        }
+      }
+    }
+
+    .promotion-card {
+      margin-bottom: 20px;
+      background: #ffffff;
+      border-radius: 10px;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+      border: 1px solid #f0f0f0;
+      overflow: hidden;
+      transition: all 0.3s ease;
+
+      &:hover {
+        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+      }
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .promotion-card-header {
+        padding: 16px 20px;
+        background: linear-gradient(135deg, #f5f7fa 0%, #ffffff 100%);
+        border-bottom: 1px solid #f0f0f0;
+
+        .promotion-card-title {
+          display: flex;
+          align-items: center;
+          font-size: 16px;
+          font-weight: 600;
+          color: #303133;
+
+          .title-icon-small {
+            margin-right: 8px;
+            font-size: 18px;
+            color: #409EFF;
+          }
+        }
+      }
+
+      .promotion-card-body {
+        padding: 20px;
+
+        .code-display,
+        .link-display {
+          display: flex;
+          align-items: center;
+          gap: 12px;
+          margin-bottom: 12px;
+          padding: 12px 16px;
+          background: #f5f7fa;
+          border-radius: 8px;
+          border: 1px solid #e4e7ed;
+
+          .code-text {
+            flex: 1;
+            font-size: 18px;
+            font-weight: 600;
+            color: #409EFF;
+            letter-spacing: 2px;
+            font-family: 'Courier New', monospace;
+          }
+
+          .link-text {
+            flex: 1;
+            font-size: 14px;
+            color: #606266;
+            word-break: break-all;
+            line-height: 1.5;
+          }
+
+          .copy-btn {
+            flex-shrink: 0;
+            transition: all 0.3s ease;
+
+            &:hover {
+              transform: scale(1.1);
+            }
+          }
+        }
+
+        .code-desc,
+        .link-desc {
+          font-size: 13px;
+          color: #909399;
+          line-height: 1.6;
+          padding-left: 4px;
+        }
+      }
+    }
 
     .info-grid {
       display: grid;
@@ -160,6 +538,7 @@ onMounted(() => {
           margin-right: 10px;
           min-width: 100px;
           flex-shrink: 0;
+          text-align: right;
         }
 
         .info-value {
@@ -239,6 +618,18 @@ onMounted(() => {
         transform: translateY(-2px);
       }
 
+      &.card-primary .card-icon {
+        background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
+      }
+
+      &.card-success .card-icon {
+        background: linear-gradient(135deg, #67C23A 0%, #85ce61 100%);
+      }
+
+      &.card-info .card-icon {
+        background: linear-gradient(135deg, #909399 0%, #a6a9ad 100%);
+      }
+
       .card-icon {
         width: 48px;
         height: 48px;
@@ -273,6 +664,231 @@ onMounted(() => {
       }
     }
   }
+
+  .commission-section {
+    margin-top: 30px;
+    padding: 24px;
+    background: linear-gradient(135deg, #fafbfc 0%, #ffffff 100%);
+    border-radius: 12px;
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
+
+    .section-title {
+      display: flex;
+      align-items: center;
+      margin: 0 0 24px 0;
+      font-size: 20px;
+      font-weight: 600;
+      color: #303133;
+
+      .title-icon {
+        margin-right: 8px;
+        font-size: 22px;
+        color: #409EFF;
+      }
+    }
+
+    .commission-grid {
+      display: grid;
+      grid-template-columns: repeat(3, 1fr);
+      gap: 20px;
+
+      @media (max-width: 1024px) {
+        grid-template-columns: repeat(2, 1fr);
+      }
+
+      @media (max-width: 768px) {
+        grid-template-columns: 1fr;
+        gap: 16px;
+      }
+
+      .commission-card {
+        display: flex;
+        align-items: flex-start;
+        padding: 20px;
+        background: #ffffff;
+        border-radius: 10px;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+        transition: all 0.3s ease;
+        border: 1px solid #f0f0f0;
+
+        &:hover {
+          box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+          transform: translateY(-3px);
+          border-color: #e0e0e0;
+        }
+
+        .commission-icon {
+          width: 56px;
+          height: 56px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          border-radius: 12px;
+          margin-right: 16px;
+          flex-shrink: 0;
+          font-size: 28px;
+          color: #fff;
+
+          &.icon-total {
+            background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
+          }
+
+          &.icon-current {
+            background: linear-gradient(135deg, #67C23A 0%, #85ce61 100%);
+          }
+
+          &.icon-withdrawn {
+            background: linear-gradient(135deg, #E6A23C 0%, #ebb563 100%);
+          }
+
+          &.icon-frozen {
+            background: linear-gradient(135deg, #F56C6C 0%, #f78989 100%);
+          }
+
+          &.icon-today {
+            background: linear-gradient(135deg, #909399 0%, #a6a9ad 100%);
+          }
+
+          &.icon-month {
+            background: linear-gradient(135deg, #9C27B0 0%, #ba68c8 100%);
+          }
+        }
+
+        .commission-content {
+          flex: 1;
+          min-width: 0;
+
+          .commission-label {
+            font-size: 14px;
+            color: #909399;
+            margin-bottom: 8px;
+            font-weight: 500;
+          }
+
+          .commission-value {
+            font-size: 24px;
+            font-weight: 700;
+            color: #303133;
+            margin-bottom: 6px;
+            word-break: break-all;
+          }
+
+          .commission-desc {
+            font-size: 12px;
+            color: #C0C4CC;
+            line-height: 1.4;
+          }
+        }
+      }
+    }
+  }
+
+  .login-section {
+    margin-top: 30px;
+    padding: 24px;
+    background: linear-gradient(135deg, #fafbfc 0%, #ffffff 100%);
+    border-radius: 12px;
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
+
+    .section-title {
+      display: flex;
+      align-items: center;
+      margin: 0 0 24px 0;
+      font-size: 20px;
+      font-weight: 600;
+      color: #303133;
+
+      .title-icon {
+        margin-right: 8px;
+        font-size: 22px;
+        color: #409EFF;
+      }
+    }
+
+    .login-grid {
+      display: grid;
+      grid-template-columns: repeat(3, 1fr);
+      gap: 20px;
+
+      @media (max-width: 1024px) {
+        grid-template-columns: repeat(2, 1fr);
+      }
+
+      @media (max-width: 768px) {
+        grid-template-columns: 1fr;
+        gap: 16px;
+      }
+
+      .login-card {
+        display: flex;
+        align-items: flex-start;
+        padding: 18px;
+        background: #ffffff;
+        border-radius: 10px;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+        transition: all 0.3s ease;
+        border: 1px solid #f0f0f0;
+
+        &:hover {
+          box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+          transform: translateY(-3px);
+          border-color: #e0e0e0;
+        }
+
+        .login-icon {
+          width: 56px;
+          height: 56px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          border-radius: 12px;
+          margin-right: 16px;
+          flex-shrink: 0;
+          font-size: 28px;
+          color: #fff;
+
+          &.icon-current {
+            background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
+          }
+
+          &.icon-last {
+            background: linear-gradient(135deg, #67C23A 0%, #85ce61 100%);
+          }
+
+          &.icon-ip {
+            background: linear-gradient(135deg, #E6A23C 0%, #ebb563 100%);
+          }
+        }
+
+        .login-content {
+          flex: 1;
+          min-width: 0;
+
+          .login-label {
+            font-size: 14px;
+            color: #909399;
+            margin-bottom: 8px;
+            font-weight: 500;
+          }
+
+          .login-value {
+            font-size: 16px;
+            font-weight: 600;
+            color: #303133;
+            margin-bottom: 6px;
+            word-break: break-all;
+            line-height: 1.5;
+          }
+
+          .login-desc {
+            font-size: 12px;
+            color: #C0C4CC;
+            line-height: 1.4;
+          }
+        }
+      }
+    }
+  }
 }
 </style>
 

+ 3 - 5
web/src/views/frontend/user/login.vue

@@ -5,7 +5,7 @@
       <p class="client-login__subtitle">探索并购买前沿AI工具,赋能您的效率与创意</p>
       <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" class="client-login__form" @submit.prevent>
         <el-form-item prop="username">
-          <el-input v-model="loginForm.username" placeholder="请输入邮箱" size="large" clearable>
+          <el-input v-model="loginForm.username" placeholder="请输入用户名/邮箱" size="large" clearable>
             <template #prefix>
               <Icon name="fa fa-user" size="16" color="var(--el-input-icon-color)" />
             </template>
@@ -77,7 +77,7 @@ const loginForm = reactive({
 
 const validateUsername = (rule, value, callback) => {
   if (!value) {
-    callback(new Error('请输入邮箱'))
+    callback(new Error('请输入用户名/邮箱'))
   } else {
     callback()
   }
@@ -182,9 +182,7 @@ watch(
 onMounted(() => {
   checkIn('get').then((res) => {
     if (res.data) {
-      userLoginCaptchaSwitch.value = res.data.userLoginCaptchaSwitch !== undefined
-        ? res.data.userLoginCaptchaSwitch
-        : true
+      userLoginCaptchaSwitch.value = res.data.userLoginCaptchaSwitch !== undefined? res.data.userLoginCaptchaSwitch : true
     }
   })
 })