|
- <template>
- <view class="profile">
- <ai-nav-title title="AI在线-解放你的生产力" />
-
- <scroll-view class="page-scroll" scroll-y>
- <view class="profile-content">
- <view class="balance-card">
- <image class="balance-texture" src="/static/profile/balance_texture.png" mode="aspectFit" />
- <view class="balance-copy">
- <text class="hello">{{ userStore.isLogin ? `Hi,${userStore.nickname}!` : 'Hi,手机微信昵称!' }}</text>
- <text class="balance-label">点数余额</text>
- <view class="balance-bottom">
- <text class="balance-value">{{ userStore.isLogin ? userStore.pointsText : '123456' }}</text>
- <view class="balance-actions">
- <view class="outline-btn" @click="go('bill')">账单</view>
- <view class="solid-btn" @click="go('recharge')">充值</view>
- </view>
- </view>
- </view>
- </view>
-
- <view class="menu-panel">
- <view v-for="item in menus" :key="item.key" class="menu-row" @click="onMenu(item)">
- <image class="menu-icon" :src="item.icon" mode="aspectFit" />
- <text class="menu-name">{{ item.name }}</text>
- <text v-if="item.hint" class="menu-hint">{{ item.hint }}</text>
- <image class="arrow" src="/static/profile/icon_arrow.png" mode="aspectFit" />
- </view>
- </view>
-
- <view class="logout" @click="logout">退出登录</view>
- </view>
- </scroll-view>
- </view>
- </template>
-
- <script setup>
- import { ref } from 'vue'
- import { onShow } from '@dcloudio/uni-app'
- import { inviteApi } from '@/api/index.js'
- import { useUserStore } from '@/store/user.js'
- import { useApp } from '@/utils/useApp.js'
-
- const userStore = useUserStore()
- const { toast } = useApp()
-
- const inviteMenuConfig = {
- key: 'invite',
- name: '邀请好友',
- hint: '得100点分享奖励',
- icon: '/static/profile/icon_invite.png',
- auth: true
- }
-
- const menus = ref([
- { key: 'account', name: '我的账号', hint: '提示文字#999', icon: '/static/profile/icon_account.png', auth: true },
- { ...inviteMenuConfig },
- { key: 'news', name: '前沿资讯', hint: '提示文字#999', icon: '/static/profile/icon_news.png', soon: true },
- { key: 'tutorial', name: '使用教程', icon: '/static/profile/icon_tutorial.png', soon: true },
- { key: 'official', name: '关注公众号', icon: '/static/profile/icon_official.png', soon: true },
- { key: 'contact', name: '联系我们', icon: '/static/profile/icon_contact.png' },
- { key: 'feedback', name: '意见反馈', hint: '得10点奖励', icon: '/static/profile/icon_feedback.png', soon: true },
- { key: 'terms', name: '服务条款', icon: '/static/profile/icon_terms.png' },
- { key: 'version', name: '当前版本', icon: '/static/profile/icon_version.png', soon: true }
- ])
-
- const MENU_ROUTE = {
- invite: '/pages/invite/invite',
- contact: '/pages/agreement/agreement?key=contact',
- terms: '/pages/agreement/agreement?key=terms'
- }
-
- function requireLogin() {
- if (userStore.isLogin) return true
- uni.navigateTo({ url: '/pages/login/login' })
- return false
- }
-
- function onMenu(item) {
- if (item.auth && !requireLogin()) return
- if (item.soon) return toast(`${item.name} 即将上线`)
- const route = MENU_ROUTE[item.key]
- if (route) return uni.navigateTo({ url: route })
- toast(`${item.name}(待开发)`)
- }
-
- function go(page) {
- if (!requireLogin()) return
- if (page === 'bill') return uni.navigateTo({ url: '/pages/bill/bill?type=recharge' })
- if (page === 'recharge') return uni.navigateTo({ url: '/pages/recharge/recharge' })
- toast(`${page}(待开发)`)
- }
-
- function syncInviteMenu(config = {}) {
- const currentIndex = menus.value.findIndex((item) => item.key === 'invite')
- if (Number(config.status) !== 1) {
- if (currentIndex > -1) menus.value.splice(currentIndex, 1)
- return
- }
-
- const points = Number(config.inviter_points || 0)
- const item = {
- ...inviteMenuConfig,
- hint: points > 0 ? `得${points}点分享奖励` : '分享给好友'
- }
- if (currentIndex > -1) {
- menus.value.splice(currentIndex, 1, item)
- return
- }
-
- const accountIndex = menus.value.findIndex((menu) => menu.key === 'account')
- menus.value.splice(accountIndex > -1 ? accountIndex + 1 : 0, 0, item)
- }
-
- async function loadProfile() {
- if (!userStore.isLogin) return
- try {
- await Promise.all([userStore.fetchUserInfo(), userStore.fetchBalance()])
- } catch (e) {
- // 登录失效由 request 统一处理
- }
- }
-
- async function loadInviteConfig() {
- try {
- const res = await inviteApi.getConfig()
- const config = (res.data && res.data.config) || {}
- syncInviteMenu(config)
- } catch (e) {}
- }
-
- function logout() {
- if (!userStore.isLogin) return requireLogin()
- uni.showModal({
- title: '提示',
- content: '确定退出登录?',
- success: (r) => {
- if (r.confirm) {
- userStore.clear()
- toast('已退出登录')
- }
- }
- })
- }
-
- onShow(() => {
- loadInviteConfig()
- loadProfile()
- })
- </script>
-
- <style lang="scss" scoped>
- .profile {
- height: 100vh;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- background: #f3f3f3;
- }
-
- .page-scroll {
- flex: 1;
- height: 0;
- }
-
- .profile-content {
- min-height: 100vh;
- padding: 30rpx 30rpx 120rpx;
- box-sizing: border-box;
- background: #f3f3f3;
- }
-
- .balance-card {
- position: relative;
- height: 266rpx;
- border-radius: 24rpx;
- overflow: hidden;
- background: linear-gradient(135deg, #3f94ff 0%, #2384f8 100%);
- box-sizing: border-box;
-
- }
-
- .balance-texture {
- position: absolute;
- right: 13rpx;
- top: -44rpx;
- width: 269rpx;
- height: 288rpx;
- }
-
- .balance-copy {
- position: relative;
- z-index: 1;
- height: 100%;
- padding: 44rpx 62rpx;
- display: flex;
- flex-direction: column;
- box-sizing: border-box;
- }
-
- .hello {
- max-width: 430rpx;
- color: #ffffff;
- font-size: 27rpx;
- line-height: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .balance-label {
- margin-top: auto;
- color: rgba(255, 255, 255, 0.65);
- font-size: 25rpx;
- line-height: 1;
- }
-
- .balance-value {
- color: #ffffff;
- font-size: 40rpx;
- font-weight: 700;
- line-height: 1;
- }
-
- .balance-bottom {
- margin-top: 16rpx;
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 24rpx;
- }
-
- .balance-actions {
- display: flex;
- gap: 22rpx;
- flex-shrink: 0;
- }
-
- .outline-btn,
- .solid-btn {
- width: 127rpx;
- height: 58rpx;
- border-radius: 29rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 27rpx;
- box-sizing: border-box;
- }
-
- .outline-btn {
- color: #ffffff;
- border: 1rpx solid rgba(255, 255, 255, 0.75);
- background: rgba(255, 255, 255, 0.08);
- }
-
- .solid-btn {
- color: #ffffff;
- border: 1rpx solid rgba(255, 255, 255, 0.75);
- background: rgba(255, 255, 255, 0.08);
- }
-
- .menu-panel {
- margin-top: 28rpx;
- padding-top: 18rpx;
- padding-bottom: 14rpx;
- border-radius: 21rpx;
- background: #ffffff;
- overflow: hidden;
- box-sizing: border-box;
- }
-
- .menu-row {
- position: relative;
- height: 100rpx;
- padding: 0 27rpx 0 27rpx;
- display: flex;
- align-items: center;
- box-sizing: border-box;
-
- &::after {
- content: '';
- position: absolute;
- left: 25rpx;
- right: 24rpx;
- bottom: 0;
- height: 1rpx;
- background: #eeeeee;
- }
-
- &:last-child::after {
- display: none;
- }
- }
-
- .menu-icon {
- width: 34rpx;
- height: 34rpx;
- flex-shrink: 0;
- }
-
- .menu-name {
- margin-left: 25rpx;
- color: #333333;
- font-size: 28rpx;
- line-height: 1;
- flex: 1;
- min-width: 0;
- }
-
- .menu-hint {
- margin-left: 20rpx;
- max-width: 300rpx;
- color: #999999;
- font-size: 26rpx;
- line-height: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .arrow {
- width: 14rpx;
- height: 22rpx;
- margin-left: 20rpx;
- flex-shrink: 0;
- }
-
- .logout {
- height: 104rpx;
- color: #333333;
- font-size: 27rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- </style>
|