peixue-dev/peidu/uniapp/src/pages/user/index.vue

1601 lines
49 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 未登录状态 -->
<view v-if="!isLoggedIn" class="user-header">
<view class="user-avatar">
<text class="avatar-emoji"></text>
</view>
<view class="user-info">
<text class="user-name">你好,欢迎使用习正陪读</text>
<text class="login-tip">登录后享受更多服务</text>
</view>
<view class="login-btn" @click="goToRoleSelect">
<text>登录/注册</text>
</view>
</view>
<!-- 已登录状态 -->
<view v-else class="user-header">
<view class="user-avatar">
<image
v-if="userInfo.avatar"
:src="userInfo.avatar"
class="avatar-image"
mode="aspectFill"
/>
<text v-else class="avatar-emoji">👤</text>
</view>
<view class="user-info">
<text class="user-name">{{ roleName }}</text>
<text class="user-phone" v-if="userInfo.phone">{{ userInfo.phone }}</text>
<!-- 角色标签 -->
<view class="role-tag">{{ getRoleGreeting() }}</view>
</view>
<view class="setting-btn" @click="goSetting">
<text>设置</text>
</view>
</view>
<!-- 角色切换(仅登录后显示) -->
<view v-if="isLoggedIn" class="role-switch-section">
<view class="section-header" @click="showRoleSelector">
<view class="section-left">
<uni-icons class="section-icon" type="person" size="18" color="#2d9687"></uni-icons>
<text class="section-title">当前角色</text>
</view>
<view class="section-right">
<text class="current-role">{{ roleName }}</text>
<text class="arrow" decode="true">></text>
</view>
</view>
</view>
<!-- 我的预约(仅家长,登录后显示) -->
<view class="order-section" v-if="isLoggedIn && currentRole === 'user'">
<view class="section-header" @click="goOrderList()">
<text class="section-title">我的预约</text>
<text class="section-more">全部</text>
<text decode="true">></text>
</view>
<view class="order-tabs">
<view class="order-tab" @click="goOrderList(0)">
<uni-icons class="tab-icon" type="wallet" size="20" color="#333"></uni-icons>
<text>待支付</text>
<text class="badge" v-if="orderCount.unpaid">{{ orderCount.unpaid }}</text>
</view>
<view class="order-tab" @click="goOrderList(1)">
<uni-icons class="tab-icon" type="calendar" size="20" color="#333"></uni-icons>
<text>待服务</text>
<text class="badge" v-if="orderCount.pending">{{ orderCount.pending }}</text>
</view>
<view class="order-tab" @click="goOrderList(3)">
<uni-icons class="tab-icon" type="checkbox-filled" size="20" color="#52c41a"></uni-icons>
<text>已完成</text>
</view>
<view class="order-tab" @click="goOrderList(-1)">
<uni-icons class="tab-icon" type="close" size="20" color="#ff4d4f"></uni-icons>
<text>已取消</text>
</view>
</view>
</view>
<!-- 功能菜单(仅家长,登录后显示) -->
<view class="menu-section" v-if="isLoggedIn && currentRole === 'user'">
<view class="menu-item" @click="goPage('/activity-package/pages/group-buy/index')">
<uni-icons class="menu-icon" type="gift" size="20" color="#2d9687"></uni-icons>
<text>我的拼团</text>
<text class="hot-badge">HOT</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/user/student')">
<uni-icons class="menu-icon" type="person" size="20" color="#2d9687"></uni-icons>
<text>学生管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/user/learning-record')">
<uni-icons class="menu-icon" type="compose" size="20" color="#2d9687"></uni-icons>
<text>学习记录</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/feedback/list')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>服务反馈</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/review/list')">
<uni-icons class="menu-icon" type="star-filled" size="20" color="#faad14"></uni-icons>
<text>我的评价</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/course/my-courses')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>我的课程</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/user/coupon')">
<uni-icons class="menu-icon" type="gift" size="20" color="#2d9687"></uni-icons>
<text>我的优惠券</text>
<text class="badge" v-if="couponCount">{{ couponCount }}</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/user/timecard')">
<uni-icons class="menu-icon" type="calendar" size="20" color="#2d9687"></uni-icons>
<text>我的时卡</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/user/wallet')">
<uni-icons class="menu-icon" type="wallet" size="20" color="#2d9687"></uni-icons>
<text>我的钱包</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/user/points')">
<uni-icons class="menu-icon" type="star" size="20" color="#2d9687"></uni-icons>
<text>我的积分</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/user/package')">
<uni-icons class="menu-icon" type="gift" size="20" color="#2d9687"></uni-icons>
<text>我的套餐</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/course/course-selector')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>课程选择</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/user-package/pages/address/list')">
<uni-icons class="menu-icon" type="location" size="20" color="#2d9687"></uni-icons>
<text>地址管理</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<!-- 职业注册入口(仅家长,登录后显示) -->
<view class="menu-section career-section" v-if="isLoggedIn && currentRole === 'user'">
<view class="menu-item career-item" @click="goToTeacherRegister">
<view class="career-left">
<uni-icons class="menu-icon career-icon" type="person-filled" size="20" color="#1890ff"></uni-icons>
<view class="career-info">
<text class="career-name">成为陪伴员</text>
<text class="career-desc">提供专业陪伴服务,获得收益</text>
</view>
</view>
<view class="career-right">
<text class="badge recommend">热门推荐</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<view class="menu-item career-item" @click="goToDistributorRegister">
<view class="career-left">
<uni-icons class="menu-icon career-icon" type="wallet-filled" size="20" color="#52c41a"></uni-icons>
<view class="career-info">
<text class="career-name">成为分销员</text>
<text class="career-desc">推广课程获得佣金,发展事业</text>
</view>
</view>
<view class="career-right">
<text class="badge commission">高佣金</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<view class="menu-item career-item" @click="goToProviderRegister">
<view class="career-left">
<uni-icons class="menu-icon career-icon" type="home-filled" size="20" color="#fa8c16"></uni-icons>
<view class="career-info">
<text class="career-name">成为服务商</text>
<text class="career-desc">提供专业教育服务,扩大业务</text>
</view>
</view>
<view class="career-right">
<text class="badge professional">专业认证</text>
<text class="arrow" decode="true">></text>
</view>
</view>
</view>
<!-- 陪伴员功能菜单按第4版需求文档 -->
<view class="menu-section" v-if="isLoggedIn && currentRole === 'teacher'">
<view class="menu-item" @click="goPage('/teacher-package/pages/level/index')">
<uni-icons class="menu-icon" type="star" size="20" color="#2d9687"></uni-icons>
<text>我的等级</text>
<text class="level-badge" :class="'level-' + currentLevelType">{{ currentLevelName }}</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/teacher-package/pages/teacher/orders')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>我的工单</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/teacher-package/pages/teacher/schedule')">
<uni-icons class="menu-icon" type="calendar" size="20" color="#2d9687"></uni-icons>
<text>时间管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/teacher-package/pages/teacher/growth-record')">
<uni-icons class="menu-icon" type="compose" size="20" color="#2d9687"></uni-icons>
<text>成长记录</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/teacher-package/pages/teacher/earnings')">
<uni-icons class="menu-icon" type="wallet" size="20" color="#2d9687"></uni-icons>
<text>收益管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/common-package/pages/notification/list')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>消息通知</text>
<text class="badge" v-if="notificationCount">{{ notificationCount }}</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/teacher-package/pages/teacher/settings')">
<uni-icons class="menu-icon" type="compose" size="20" color="#2d9687"></uni-icons>
<text>系统设置</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="contactService">
<uni-icons class="menu-icon" type="phone" size="20" color="#2d9687"></uni-icons>
<text>客服电话</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #ifdef MP-WEIXIN -->
<button class="menu-item" open-type="contact">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<view class="menu-item" @click="contactServiceOnlineFallback">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #endif -->
<view class="menu-item" @click="goPage('/common-package/pages/feedback/create')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>意见反馈</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<!-- 管理师功能菜单 -->
<view class="menu-section" v-if="isLoggedIn && currentRole === 'manager'">
<view class="menu-item" @click="goPage('/manager-package/pages/manager/work-orders')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>工单管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/manager-package/pages/manager/dispatch-list')">
<uni-icons class="menu-icon" type="compose" size="20" color="#2d9687"></uni-icons>
<text>派单管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/manager-package/pages/manager/teachers')">
<uni-icons class="menu-icon" type="person" size="20" color="#2d9687"></uni-icons>
<text>陪伴员管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/manager-package/pages/manager/parents')">
<uni-icons class="menu-icon" type="person" size="20" color="#2d9687"></uni-icons>
<text>家长管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/manager-package/pages/manager/course-hours')">
<uni-icons class="menu-icon" type="wallet" size="20" color="#2d9687"></uni-icons>
<text>课时管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/manager-package/pages/manager/reports')">
<uni-icons class="menu-icon" type="compose" size="20" color="#2d9687"></uni-icons>
<text>汇总报告</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/manager-package/pages/manager/reminders')">
<uni-icons class="menu-icon" type="calendar" size="20" color="#2d9687"></uni-icons>
<text>提醒管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="contactService">
<uni-icons class="menu-icon" type="phone" size="20" color="#2d9687"></uni-icons>
<text>客服电话</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #ifdef MP-WEIXIN -->
<button class="menu-item" open-type="contact">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<view class="menu-item" @click="contactServiceOnlineFallback">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #endif -->
<view class="menu-item" @click="goPage('/common-package/pages/feedback/create')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>意见反馈</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<!-- 分销员功能菜单 -->
<view class="menu-section" v-if="isLoggedIn && currentRole === 'distributor'">
<view class="menu-item" @click="goPage('/distributor-package/pages/distributor/poster')">
<uni-icons class="menu-icon" type="gift" size="20" color="#2d9687"></uni-icons>
<text>推广码管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/distributor-package/pages/distributor/course-list')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>可分销课程</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/distributor-package/pages/distributor/order-list')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>成交记录</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/distributor-package/pages/distributor/commission')">
<uni-icons class="menu-icon" type="wallet" size="20" color="#2d9687"></uni-icons>
<text>佣金管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/distributor-package/pages/distributor/team')">
<uni-icons class="menu-icon" type="person" size="20" color="#2d9687"></uni-icons>
<text>我的团队</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="contactService">
<uni-icons class="menu-icon" type="phone" size="20" color="#2d9687"></uni-icons>
<text>客服电话</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #ifdef MP-WEIXIN -->
<button class="menu-item" open-type="contact">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<view class="menu-item" @click="contactServiceOnlineFallback">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #endif -->
<view class="menu-item" @click="goPage('/common-package/pages/feedback/create')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>意见反馈</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<!-- 服务商功能菜单 -->
<view class="menu-section" v-if="isLoggedIn && currentRole === 'provider'">
<view class="menu-item" @click="goPage('/provider-package/pages/provider/course-manage')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>课程管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/provider-package/pages/provider/student-manage')">
<uni-icons class="menu-icon" type="person" size="20" color="#2d9687"></uni-icons>
<text>学生管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/provider-package/pages/provider/order-list')">
<uni-icons class="menu-icon" type="list" size="20" color="#2d9687"></uni-icons>
<text>订单管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/provider-package/pages/provider/schedule')">
<uni-icons class="menu-icon" type="calendar" size="20" color="#2d9687"></uni-icons>
<text>课程安排</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="goPage('/provider-package/pages/provider/earnings')">
<uni-icons class="menu-icon" type="wallet" size="20" color="#2d9687"></uni-icons>
<text>收益管理</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="contactService">
<uni-icons class="menu-icon" type="phone" size="20" color="#2d9687"></uni-icons>
<text>客服电话</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #ifdef MP-WEIXIN -->
<button class="menu-item" open-type="contact">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<view class="menu-item" @click="contactServiceOnlineFallback">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #endif -->
<view class="menu-item" @click="goPage('/common-package/pages/feedback/create')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>意见反馈</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<!-- 通用功能菜单(仅家长角色显示) -->
<view class="menu-section" v-if="!isLoggedIn || currentRole === 'user'">
<view class="menu-item" @click="goPage('/common-package/pages/notification/list')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>消息通知</text>
<text class="badge" v-if="notificationCount">{{ notificationCount }}</text>
<text class="arrow" decode="true">></text>
</view>
<view class="menu-item" @click="contactService">
<uni-icons class="menu-icon" type="phone" size="20" color="#2d9687"></uni-icons>
<text>客服电话</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #ifdef MP-WEIXIN -->
<button class="menu-item" open-type="contact">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<view class="menu-item" @click="contactServiceOnlineFallback">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>在线客服</text>
<text class="arrow" decode="true">></text>
</view>
<!-- #endif -->
<view class="menu-item" @click="goPage('/common-package/pages/feedback/create')">
<uni-icons class="menu-icon" type="chat" size="20" color="#2d9687"></uni-icons>
<text>意见反馈</text>
<text class="arrow" decode="true">></text>
</view>
</view>
<!-- 测试账号快速登录区域 -->
<view v-if="showTestEntrance" class="test-accounts-section">
<view class="test-accounts-header">
<view class="header-left">
<text class="header-icon">🔑</text>
<text class="header-title">快速测试登录</text>
</view>
<text class="header-tip">点击账号快速登录</text>
</view>
<scroll-view class="test-accounts-scroll" scroll-x>
<view class="test-accounts-list">
<view
class="test-account-card"
v-for="(account, index) in testAccounts"
:key="index"
@click="quickLoginWithTestAccount(account)"
>
<view class="card-badge">TEST</view>
<view class="card-icon-wrapper">
<text class="card-icon">{{ account.icon }}</text>
</view>
<view class="card-info">
<text class="card-role">{{ account.name }}</text>
<text class="card-phone">{{ account.phone }}</text>
</view>
<view class="card-btn">
<text>立即登录</text>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 退出登录按钮 -->
<view v-if="isLoggedIn" class="logout-section">
<button class="logout-btn" @click="handleLogout">退出登录</button>
</view>
<!-- 角色选择弹窗 -->
<view v-if="showRoleModal" class="modal-overlay" @click="closeRoleModal">
<view class="modal-content" @click.stop>
<view class="modal-title">选择角色</view>
<view class="role-list">
<view
v-for="role in availableRoles"
:key="role.value"
class="role-option"
:class="{ active: currentRole === role.value }"
@click="switchRole(role.value)"
>
<text class="role-icon">{{ role.icon }}</text>
<text class="role-name">{{ role.label }}</text>
<text v-if="currentRole === role.value" class="check-icon">✓</text>
</view>
</view>
<view class="modal-close" @click="closeRoleModal">取消</view>
</view>
</view>
</view>
</template>
<script>
import { userApi, orderApi, notificationApi, authApi } from '@/api/index.js'
import { useUserStore } from '@/store/user'
export default {
data() {
return {
isLoggedIn: false,
currentRole: '',
userInfo: {},
showTestEntrance: false,
orderCount: {
unpaid: 0,
pending: 0,
completed: 0,
cancelled: 0
},
couponCount: 0,
notificationCount: 0,
showRoleModal: false,
currentLevelType: 'bronze', // 当前等级类型
currentLevelName: '普通陪伴员', // 当前等级名称
availableRoles: [
{ value: 'user', label: '家长', icon: '👨‍👩‍👧' },
{ value: 'teacher', label: '陪伴员', icon: '👨‍🏫' },
{ value: 'manager', label: '管理师', icon: '👔' },
{ value: 'distributor', label: '分销员', icon: '💼' },
{ value: 'provider', label: '服务商', icon: '🎓' }
],
// 测试账号列表
testAccounts: [
{ role: 'user', name: '家长', phone: '13800138000', password: '123456', icon: '👨‍👩‍👧' },
{ role: 'teacher', name: '陪伴师', phone: '13800138001', password: '123456', icon: '👨‍🏫' },
{ role: 'manager', name: '管理师', phone: '13800138002', password: '123456', icon: '👔' },
{ role: 'distributor', name: '分销员', phone: '13800138003', password: '123456', icon: '💼' },
{ role: 'provider', name: '服务商', phone: '13800138004', password: '123456', icon: '🎓' }
]
}
},
computed: {
roleName() {
const role = this.availableRoles.find(r => r.value === this.currentRole)
return role ? role.label : '用户'
}
},
onLoad() {
this.checkLoginStatus()
this.initTestEntrance()
},
onShow() {
this.checkLoginStatus()
if (this.isLoggedIn) {
this.loadUserData()
}
},
methods: {
initTestEntrance() {
let show = false
// #ifdef MP-WEIXIN
try {
const info = uni.getAccountInfoSync && uni.getAccountInfoSync()
const envVersion = info && info.miniProgram && info.miniProgram.envVersion
show = envVersion === 'develop' || envVersion === 'trial'
} catch (e) {
show = false
}
// #endif
// #ifndef MP-WEIXIN
show = process.env.NODE_ENV !== 'production'
// #endif
this.showTestEntrance = show
},
checkLoginStatus() {
const token = uni.getStorageSync('token')
const userStore = useUserStore()
this.isLoggedIn = !!token
this.currentRole = userStore.currentRole || 'user'
},
async loadUserData() {
try {
// 加载用户信息
const userRes = await userApi.getUserInfo()
if (userRes && userRes.success) {
this.userInfo = userRes.data || {}
console.log('个人中心加载用户信息:', this.userInfo)
console.log('头像URL:', this.userInfo.avatar)
}
} catch (error) {
console.log('加载用户信息失败:', error)
}
// 加载等级信息(仅陪伴员)
if (this.currentRole === 'teacher') {
this.loadLevelInfo()
}
try {
// 加载订单统计
if (this.currentRole === 'user') {
const orderRes = await orderApi.getOrderCount()
if (orderRes && orderRes.success && orderRes.data) {
this.orderCount = orderRes.data
}
}
} catch (error) {
console.log('加载订单统计失败:', error)
}
try {
// 加载优惠券数量
const couponRes = await userApi.getCouponCount()
if (couponRes && (couponRes.success || couponRes.code === 200)) {
const count = typeof couponRes.data === 'number' ? couponRes.data : (couponRes.data?.total || 0)
this.couponCount = count
}
} catch (error) {
console.log('加载优惠券数量失败:', error)
}
try {
// 加载未读消息数
const notifRes = await notificationApi.getUnreadCount()
if (notifRes && (notifRes.success || notifRes.code === 200)) {
const count = typeof notifRes.data === 'number'
? notifRes.data
: (notifRes.data?.total || 0)
this.notificationCount = count
}
} catch (error) {
console.log('加载消息数量失败:', error)
}
},
// 加载等级信息
async loadLevelInfo() {
try {
const userInfo = uni.getStorageSync('userInfo')
const teacherId = userInfo?.id || userInfo?.userId
if (!teacherId) {
return
}
// 使用完整的 API 地址
const baseUrl = getApp().globalData.baseUrl || 'http://localhost:8089'
uni.request({
url: `${baseUrl}/api/teacher/level/current`,
method: 'GET',
data: { teacherId },
header: {
'Authorization': uni.getStorageSync('token') || ''
},
success: (res) => {
if (res.statusCode === 200 && res.data && res.data.code === 200) {
this.currentLevelType = res.data.data.currentLevel || 'bronze'
this.currentLevelName = res.data.data.levelName || '普通陪伴员'
}
},
fail: (error) => {
console.error('加载等级信息失败:', error)
}
})
} catch (error) {
console.error('加载等级信息失败:', error)
}
},
getRoleGreeting() {
const greetings = {
user: '家长',
teacher: '陪伴员',
manager: '管理师',
distributor: '分销员',
provider: '服务商'
}
return greetings[this.currentRole] || '用户'
},
goToRoleSelect() {
uni.navigateTo({
url: '/pages/auth/role-select'
})
},
// 职业注册相关方法
goToTeacherRegister() {
uni.showModal({
title: '成为陪伴员',
content: '陪伴员为用户提供专业的陪伴和辅导服务,获得丰厚收益。我们为您提供完善的培训体系和成长路径,是否立即申请?',
confirmText: '立即申请',
cancelText: '再想想',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/teacher-package/pages/auth/teacher-quick-register'
})
}
}
})
},
goToDistributorRegister() {
uni.showModal({
title: '成为分销员',
content: '分销员推广优质课程获得可观佣金收益,发展自己的教育事业。平台提供专业的营销工具和支持,是否立即申请?',
confirmText: '立即申请',
cancelText: '再想想',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/distributor-package/pages/distributor/apply'
})
}
}
})
},
goToProviderRegister() {
uni.showModal({
title: '成为服务商',
content: '服务商为平台提供专业的教育培训服务,扩大业务范围和影响力。我们为您提供稳定的生源和完善的管理系统,是否立即申请?',
confirmText: '立即申请',
cancelText: '再想想',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/provider-package/pages/service-provider/apply'
})
}
}
})
},
goSetting() {
uni.navigateTo({
url: '/user-package/pages/user/profile'
})
},
goOrderList(status) {
let url = '/order-package/pages/order/my-orders'
if (status !== undefined) {
url += `?status=${status}`
}
uni.navigateTo({ url })
},
goPage(url) {
uni.navigateTo({ url })
},
contactService() {
uni.makePhoneCall({
phoneNumber: '400-000-0000',
fail: () => {
uni.showToast({ title: '请拨打客服电话', icon: 'none' })
}
})
},
contactServiceOnlineFallback() {
uni.showToast({
title: '在线客服仅在微信小程序内可用',
icon: 'none'
})
},
showRoleSelector() {
this.showRoleModal = true
},
closeRoleModal() {
this.showRoleModal = false
},
switchRole(role) {
if (role === this.currentRole) {
this.closeRoleModal()
return
}
// 更新 Pinia store这会同时更新 localStorage
const userStore = useUserStore()
userStore.setRole(role)
this.currentRole = role
this.closeRoleModal()
// 切换到对应的首页
uni.reLaunch({
url: '/pages/index/index'
})
},
// 使用测试账号快速登录
async quickLoginWithTestAccount(account) {
try {
uni.showLoading({ title: '登录中...' })
const res = await authApi.phoneLogin({
phone: account.phone,
password: account.password || '123456'
})
if (res?.code !== 200) {
throw new Error(res?.message || '登录失败')
}
// 保存token和用户信息
const token = res?.data?.token || res?.token
const userInfo = res?.data?.userInfo || res?.userInfo || res?.data
console.log('========== 测试账号登录调试 ==========')
console.log('完整响应:', res)
console.log('token:', token)
console.log('userInfo:', userInfo)
console.log('userInfo.role:', userInfo?.role)
console.log('userInfo.userType:', userInfo?.userType)
console.log('account.role:', account.role)
console.log('=====================================')
if (!token) {
throw new Error(res?.message || '登录失败')
}
const userStore = useUserStore()
userStore.setToken(token)
if (userInfo) {
userStore.setUserInfo(userInfo)
}
// ✅ 修复:使用后端返回的角色,而不是前端定义的角色
// 后端返回的 userInfo.role 或 userInfo.userType 才是数据库中的真实角色
const backendRole = userInfo?.role || userInfo?.userType || account.role
const finalRole = backendRole === 'parent' ? 'user' : backendRole
console.log('🔥 最终设置的角色:', finalRole)
userStore.setRole(finalRole)
uni.hideLoading()
uni.showToast({
title: '登录成功',
icon: 'success',
success: () => {
setTimeout(() => {
// 🔥 强制设置角色并跳转
const userStore = useUserStore()
if (account.role === 'user') {
userStore.setRole('user')
}
uni.reLaunch({
url: '/pages/index/index'
})
}, 500)
}
})
} catch (e) {
uni.hideLoading()
uni.showToast({
title: e?.message || e?.errMsg || '登录失败',
icon: 'none'
})
}
},
handleLogout() {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 使用 store 的 logout 方法
const userStore = useUserStore()
userStore.logout()
this.isLoggedIn = false
this.userInfo = {}
this.currentRole = 'user'
uni.showToast({
title: '已退出登录',
icon: 'success'
})
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
}, 1500)
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
@import '@/static/css/common.scss';
.container {
min-height: 100vh;
background: #f5f7fa;
padding-bottom: 100rpx;
}
.user-header {
background: linear-gradient(135deg, #2d9687 0%, #25806f 100%);
padding: 60rpx 30rpx 40rpx;
display: flex;
align-items: center;
gap: 20rpx;
.user-avatar {
width: 120rpx;
height: 120rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 60rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
flex-shrink: 0;
.avatar-image {
width: 100%;
height: 100%;
border-radius: 60rpx;
}
.avatar-emoji {
font-size: 60rpx;
}
}
.user-info {
flex: 1;
.user-name {
display: block;
font-size: 36rpx;
font-weight: bold;
color: #fff;
margin-bottom: 8rpx;
}
.user-phone,
.login-tip {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.role-tag {
display: inline-block;
background: rgba(255, 255, 255, 0.2);
color: #fff;
font-size: 22rpx;
padding: 4rpx 12rpx;
border-radius: 8rpx;
margin-top: 8rpx;
}
}
.login-btn,
.setting-btn {
background: rgba(255, 255, 255, 0.2);
color: #fff;
font-size: 28rpx;
padding: 12rpx 24rpx;
border-radius: 20rpx;
}
}
.role-switch-section,
.order-section,
.menu-section {
background: white;
margin-bottom: 20rpx;
border-radius: 16rpx;
overflow: hidden;
.section-header {
display: flex;
align-items: center;
padding: 30rpx;
background: #f8f9fa;
border-bottom: 1rpx solid #f0f0f0;
.section-left {
display: flex;
align-items: center;
flex: 1;
}
.section-right {
display: flex;
align-items: center;
}
.section-icon {
margin-right: 16rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.section-desc {
font-size: 24rpx;
color: #999;
margin-left: 16rpx;
}
.current-role {
font-size: 28rpx;
color: #2d9687;
margin-right: 16rpx;
}
}
}
.section-header {
padding: 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
.section-left {
display: flex;
align-items: center;
gap: 12rpx;
.section-icon {
font-size: 32rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
}
.section-right {
display: flex;
align-items: center;
gap: 8rpx;
.current-role {
font-size: 28rpx;
color: #666;
}
.arrow {
font-size: 24rpx;
color: #999;
}
}
.section-more {
font-size: 26rpx;
color: #999;
margin-right: 8rpx;
}
}
.order-tabs {
display: flex;
padding: 0 30rpx 30rpx;
.order-tab {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 12rpx;
position: relative;
.tab-icon {
font-size: 40rpx;
}
text {
font-size: 26rpx;
color: #666;
}
.badge {
position: absolute;
top: -8rpx;
right: 20rpx;
background: #ff6b6b;
color: #fff;
font-size: 20rpx;
padding: 2rpx 8rpx;
border-radius: 10rpx;
min-width: 32rpx;
text-align: center;
}
}
}
.menu-item {
padding: 30rpx;
display: flex;
align-items: center;
gap: 16rpx;
border-bottom: 1rpx solid #f0f0f0;
background: transparent;
text-align: left;
&:last-child {
border-bottom: none;
}
.menu-icon {
font-size: 36rpx;
}
text {
font-size: 30rpx;
color: #333;
}
.hot-badge {
background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
color: #fff;
font-size: 20rpx;
padding: 2rpx 8rpx;
border-radius: 8rpx;
margin-left: auto;
}
.new-badge {
background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%);
color: #fff;
font-size: 20rpx;
padding: 2rpx 8rpx;
border-radius: 8rpx;
margin-left: auto;
}
.badge {
background: #ff6b6b;
color: #fff;
font-size: 20rpx;
padding: 2rpx 8rpx;
border-radius: 10rpx;
min-width: 32rpx;
text-align: center;
margin-left: auto;
}
.level-badge {
font-size: 24rpx;
padding: 4rpx 12rpx;
border-radius: 20rpx;
font-weight: bold;
margin-left: auto;
&.level-bronze {
background: #f5e6d3;
color: #cd7f32;
}
&.level-king {
background: #e8e8e8;
color: #666;
}
&.level-gold {
background: #fff7e6;
color: #ffa940;
}
}
// 职业注册徽章样式
.badge {
font-size: 20rpx;
padding: 4rpx 10rpx;
border-radius: 12rpx;
margin-right: 16rpx;
font-weight: bold;
&.recommend {
background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
color: #1890ff;
border: 1rpx solid #91d5ff;
}
&.commission {
background: linear-gradient(135deg, #f6ffed 0%, #d9f7be 100%);
color: #52c41a;
border: 1rpx solid #b7eb8f;
}
&.professional {
background: linear-gradient(135deg, #fff7e6 0%, #ffe7ba 100%);
color: #fa8c16;
border: 1rpx solid #ffd591;
}
}
.arrow {
font-size: 24rpx;
color: #999;
}
}
// 职业注册特殊样式
.career-section {
background: linear-gradient(135deg, #f0f9f7 0%, #f8fffe 100%);
border: 2rpx solid #e6f7ff;
box-shadow: 0 4rpx 16rpx rgba(45, 150, 135, 0.08);
border-radius: 16rpx;
overflow: hidden;
.career-item {
padding: 32rpx 30rpx;
border-bottom: 1rpx solid rgba(45, 150, 135, 0.08);
background: white;
transition: all 0.3s ease;
&:first-child {
border-top-left-radius: 14rpx;
border-top-right-radius: 14rpx;
}
&:last-child {
border-bottom: none;
border-bottom-left-radius: 14rpx;
border-bottom-right-radius: 14rpx;
}
&:hover {
background: #f8fffe;
}
.career-left {
display: flex;
align-items: center;
flex: 1;
gap: 20rpx;
.career-icon {
width: 48rpx;
height: 48rpx;
background: rgba(45, 150, 135, 0.08);
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
}
.career-info {
flex: 1;
.career-name {
display: block;
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 6rpx;
}
.career-desc {
display: block;
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
}
}
.career-right {
display: flex;
align-items: center;
gap: 12rpx;
}
}
}
// 确保button元素的menu-item样式与view元素一致
button.menu-item {
width: 100%;
border: none;
outline: none;
padding: 30rpx;
display: flex;
align-items: center;
gap: 16rpx;
border-bottom: 1rpx solid #f0f0f0;
background: transparent;
text-align: left;
font-size: 30rpx;
color: #333;
min-height: auto;
height: auto;
line-height: normal;
box-sizing: border-box;
&:last-child {
border-bottom: none;
}
&::after {
border: none;
}
.menu-icon {
font-size: 36rpx;
}
text {
font-size: 30rpx;
color: #333;
}
.arrow {
font-size: 24rpx;
color: #999;
margin-left: auto;
}
}
// 测试账号区域样式
.test-accounts-section {
margin: 20rpx 0 40rpx;
.test-accounts-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx 20rpx;
.header-left {
display: flex;
align-items: center;
gap: 12rpx;
.header-icon {
font-size: 36rpx;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.header-tip {
font-size: 24rpx;
color: #999999;
}
}
.test-accounts-scroll {
white-space: nowrap;
.test-accounts-list {
display: inline-flex;
gap: 20rpx;
padding: 0 30rpx;
.test-account-card {
display: inline-flex;
flex-direction: column;
align-items: center;
width: 210rpx;
padding: 30rpx 10rpx 25rpx;
background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
border-radius: 24rpx;
box-shadow: 0 8rpx 24rpx rgba(45, 150, 135, 0.12);
border: 2rpx solid rgba(45, 150, 135, 0.1);
position: relative;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 8rpx;
background: linear-gradient(90deg, #2d9687 0%, #52c41a 100%);
border-radius: 24rpx 24rpx 0 0;
}
&:active {
transform: translateY(-4rpx) scale(0.98);
box-shadow: 0 12rpx 32rpx rgba(45, 150, 135, 0.2);
}
.card-badge {
position: absolute;
top: 15rpx;
right: 15rpx;
background: linear-gradient(135deg, #faad14 0%, #ffc53d 100%);
color: #ffffff;
font-size: 20rpx;
font-weight: bold;
padding: 4rpx 12rpx;
border-radius: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(250, 173, 20, 0.3);
}
.card-icon-wrapper {
width: 100rpx;
height: 100rpx;
background: linear-gradient(135deg, #f0f9f7 0%, #e6f7f3 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(45, 150, 135, 0.1);
.card-icon {
font-size: 56rpx;
}
}
.card-info {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
margin-bottom: 20rpx;
width: 100%;
.card-role {
font-size: 28rpx;
font-weight: bold;
color: #333333;
}
.card-phone {
font-size: 22rpx;
color: #999999;
font-family: 'Courier New', monospace;
background: #f5f5f5;
padding: 4rpx 12rpx;
border-radius: 12rpx;
}
}
.card-btn {
width: 100%;
padding: 16rpx 0;
background: linear-gradient(135deg, #2d9687 0%, #25806f 100%);
border-radius: 30rpx;
text-align: center;
box-shadow: 0 4rpx 12rpx rgba(45, 150, 135, 0.3);
text {
font-size: 26rpx;
color: #ffffff;
font-weight: bold;
}
}
}
}
}
}
.logout-section {
padding: 30rpx;
.logout-btn {
width: 100%;
height: 88rpx;
background: #fff;
color: #ff6b6b;
font-size: 32rpx;
border-radius: 16rpx;
border: 2rpx solid #ff6b6b;
&::after {
border: none;
}
}
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
z-index: 9999;
.modal-content {
width: 100%;
background: #fff;
border-radius: 32rpx 32rpx 0 0;
padding: 40rpx 30rpx;
.modal-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
text-align: center;
margin-bottom: 30rpx;
}
.role-list {
.role-option {
padding: 30rpx;
display: flex;
align-items: center;
gap: 20rpx;
border-radius: 16rpx;
margin-bottom: 16rpx;
background: #f5f7fa;
&.active {
background: #e8f5f3;
border: 2rpx solid #2d9687;
}
.role-icon {
font-size: 40rpx;
}
.role-name {
flex: 1;
font-size: 32rpx;
color: #333;
}
.check-icon {
font-size: 32rpx;
color: #2d9687;
}
}
}
.modal-close {
margin-top: 20rpx;
padding: 24rpx;
text-align: center;
font-size: 32rpx;
color: #666;
background: #f5f7fa;
border-radius: 16rpx;
}
}
}
</style>