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

1852 lines
55 KiB
Vue
Raw Normal View History

<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">
2026-02-28 19:07:38 +08:00
<view class="section-header" @click="toggleRoleList">
<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>
2026-02-28 19:07:38 +08:00
<text class="arrow" :class="{ expanded: showRoleList }" decode="true"></text>
</view>
</view>
<!-- 角色列表折叠展开 -->
<view v-if="showRoleList && userRoles.length > 0" class="role-list-container">
<view
v-for="role in userRoles"
:key="role.roleType"
class="role-item"
:class="{ active: currentRole === getRoleValue(role.roleType), primary: role.isPrimary }"
@click="switchToRole(role.roleType)"
>
<text class="role-icon">{{ getRoleIcon(role.roleType) }}</text>
<view class="role-info">
<text class="role-name">{{ getRoleLabel(role.roleType) }}</text>
<text v-if="role.isPrimary" class="primary-badge">主身份</text>
</view>
<text v-if="currentRole === getRoleValue(role.roleType)" class="check-icon"></text>
</view>
<!-- 申请新身份入口 -->
<view class="apply-role-btn" @click="goToApplyRole">
<text class="plus-icon">+</text>
<text>申请其他身份</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,
2026-02-28 19:07:38 +08:00
showRoleList: false, // 角色列表展开状态
userRoles: [], // 用户的所有角色(从数据库加载)
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()
2026-02-28 19:07:38 +08:00
this.loadUserRoles() // 加载用户的所有角色
}
},
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] || '用户'
},
2026-02-28 19:07:38 +08:00
// 加载用户的所有角色(从数据库)
async loadUserRoles() {
try {
const userStore = useUserStore()
await userStore.loadAllRoles()
// 从 store 获取角色数据
this.userRoles = userStore.allRoles.map(roleType => ({
roleType: roleType,
isPrimary: roleType === userStore.primaryRole
}))
console.log('加载用户角色:', this.userRoles)
} catch (error) {
console.error('加载用户角色失败:', error)
}
},
// 切换角色列表展开/收起
toggleRoleList() {
this.showRoleList = !this.showRoleList
},
// 切换到指定角色
async switchToRole(roleType) {
const roleValue = this.getRoleValue(roleType)
if (roleValue === this.currentRole) {
this.showRoleList = false
return
}
try {
uni.showLoading({ title: '切换中...' })
const userStore = useUserStore()
const success = await userStore.switchRole(roleType)
if (success) {
this.currentRole = roleValue
this.showRoleList = false
uni.hideLoading()
uni.showToast({
title: '切换成功',
icon: 'success'
})
// 刷新页面
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
}, 500)
} else {
uni.hideLoading()
uni.showToast({
title: '切换失败',
icon: 'none'
})
}
} catch (error) {
uni.hideLoading()
uni.showToast({
title: error.message || '切换失败',
icon: 'none'
})
}
},
// 跳转到申请身份页面
goToApplyRole() {
uni.navigateTo({
url: '/src/pages/user/apply-role'
})
},
// 角色类型转换(数据库字段 -> 前端值)
getRoleValue(roleType) {
// parent -> user, 其他保持不变
return roleType === 'parent' ? 'user' : roleType
},
// 获取角色图标
getRoleIcon(roleType) {
const icons = {
parent: '👨‍👩‍👧',
user: '👨‍👩‍👧',
teacher: '👨‍🏫',
manager: '👔',
distributor: '💼',
provider: '🎓'
}
return icons[roleType] || '👤'
},
// 获取角色名称
getRoleLabel(roleType) {
const labels = {
parent: '家长',
user: '家长',
teacher: '陪伴员',
manager: '管理师',
distributor: '分销员',
provider: '服务商'
}
return labels[roleType] || '用户'
},
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;
}
2026-02-28 19:07:38 +08:00
.arrow {
font-size: 20rpx;
color: #999;
transition: transform 0.3s;
&.expanded {
transform: rotate(180deg);
}
}
}
// 角色列表容器
.role-list-container {
padding: 20rpx 30rpx 30rpx;
animation: slideDown 0.3s ease-out;
.role-item {
display: flex;
align-items: center;
padding: 24rpx;
background: #f8f9fa;
border-radius: 12rpx;
margin-bottom: 16rpx;
transition: all 0.3s;
&.active {
background: #e8f5f3;
border: 2rpx solid #2d9687;
}
&.primary {
position: relative;
&::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 6rpx;
background: #2d9687;
border-radius: 12rpx 0 0 12rpx;
}
}
.role-icon {
font-size: 40rpx;
margin-right: 16rpx;
}
.role-info {
flex: 1;
display: flex;
align-items: center;
gap: 12rpx;
.role-name {
font-size: 30rpx;
color: #333;
font-weight: 500;
}
.primary-badge {
font-size: 20rpx;
padding: 4rpx 10rpx;
background: linear-gradient(135deg, #2d9687 0%, #25806f 100%);
color: #fff;
border-radius: 8rpx;
}
}
.check-icon {
font-size: 32rpx;
color: #2d9687;
font-weight: bold;
}
}
.apply-role-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
padding: 24rpx;
background: linear-gradient(135deg, #f0f9f7 0%, #e6f7f3 100%);
border: 2rpx dashed #2d9687;
border-radius: 12rpx;
margin-top: 8rpx;
.plus-icon {
font-size: 32rpx;
color: #2d9687;
font-weight: bold;
}
text {
font-size: 28rpx;
color: #2d9687;
font-weight: 500;
}
}
}
}
@keyframes slideDown {
from {
opacity: 0;
max-height: 0;
transform: translateY(-20rpx);
}
to {
opacity: 1;
max-height: 1000rpx;
transform: translateY(0);
}
}
.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>