| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- <script lang="ts" setup>
- import { useRequest } from 'alova/client'
- import { storeToRefs } from 'pinia'
- import { computed, ref } from 'vue'
- import { getCouponSituation } from '@/api/home'
- import { getCouponIssuerApplyById, getShareState } from '@/api/me'
- import { useShare } from '@/hooks/useShare'
- import { useUserStore } from '@/store'
- import { useInviterStore } from '@/store/inviter'
- import { useTokenStore } from '@/store/token'
- import { changtime } from '@/utils'
- import { getImageUrl } from '@/utils/imageUtil'
- definePage({
- style: {
- navigationBarTitleText: '我的',
- navigationStyle: 'custom',
- },
- })
- const userStore = useUserStore()
- const tokenStore = useTokenStore()
- const inviterStore = useInviterStore()
- // 使用storeToRefs解构userInfo
- const { userInfo } = storeToRefs(userStore)
- const { hasLogin } = storeToRefs(tokenStore)
- const deadline = ref(Date.now())
- // 用户优惠券统计数据
- const { send: getCouponSituationRequest, data: couponSituationData, loading: couponSituationLoading } = useRequest(getCouponSituation, {
- immediate: false,
- })
- const { send: getShareStateRequest, data: shareStateData, loading: shareStateLoading } = useRequest(getShareState, {
- immediate: false,
- })
- // 昵称输入值
- const nicknameInput = ref('')
- onShow(async () => {
- console.log('登录判断:', hasLogin.value)
- // 登录后查询收益数据
- if (hasLogin.value) {
- await getCouponSituationRequest({ queryType: 'time' })
- await getShareStateRequest()
- deadline.value = Date.now()
- }
- })
- function handleLogout() {
- uni.showModal({
- title: '提示',
- content: '确定要退出登录吗?',
- success: async (res) => {
- if (res.confirm) {
- // 清空用户信息
- await useTokenStore().logout()
- // 执行退出登录逻辑
- uni.showToast({
- title: '退出登录成功',
- icon: 'success',
- mask: true,
- duration: 2000,
- complete: () => {
- // #ifdef MP-WEIXIN
- // 微信小程序,去首页
- uni.reLaunch({ url: '/pages/home/home' })
- // #endif
- // #ifndef MP-WEIXIN
- // 非微信小程序,去登录页
- // uni.navigateTo({ url: LOGIN_PAGE })
- // #endif
- }
- })
- }
- },
- })
- }
- // 顶部导航栏高度,设置banner位置
- const navigationBarHeight = ref(0)
- // 头像默认图片
- const defaultAvatar = '../../static/images/me/me-bg.png'
- // 计算头像显示
- const avatarDisplay = computed(() => {
- return userInfo.value?.avatar || defaultAvatar
- })
- // #ifdef MP-WEIXIN
- function getNavigationBarHeight() {
- uni.getSystemInfo({
- success: (res) => {
- const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
- console.log('顶部导航栏高度:', res.statusBarHeight, menuButtonInfo)
- // 顶部导航栏高度 = 状态栏高度 + 胶囊的高度
- navigationBarHeight.value = res.statusBarHeight + menuButtonInfo.height
- },
- })
- }
- getNavigationBarHeight()
- // #endif
- const show = ref(false)
- const refreshing = ref(false)
- function close() {
- show.value = false
- }
- function open() {
- show.value = true
- }
- async function menuClick(page, otherJs?: () => Promise<boolean>) {
- if (otherJs && typeof otherJs === 'function') {
- const execRes = await otherJs(page)
- if (execRes === false) {
- return
- }
- }
- uni.navigateTo({
- url: `/pages-A/${page}/index?couponSituation=${JSON.stringify(couponSituationData.value)}`,
- })
- }
- // 判断是否是发券人
- function isCouponIssuer(currentPage?: string) {
- // 发券人相关页面
- const validPages = ['myInviter', 'shareFriend', 'invitePage']
- console.log('111111111111')
- // 判断跳转页面是否是发券人相关页面
- if (!validPages.includes(currentPage)) {
- return Promise.resolve(true)
- }
- // 是否已经成为发券人
- if (userStore.isPassIssuer()) {
- return Promise.resolve(true)
- }
- else {
- uni.showModal({
- title: '提示',
- content: '您还不是发券人,请先申请成为发券人',
- showCancel: false,
- })
- return Promise.resolve(false)
- }
- }
- //展开弹窗
- function watchUserStatus() {
- if (userInfo.value.status === '0') {
- open();
- return Promise.resolve(false)
- }
- return Promise.resolve(true)
-
- }
- async function getInviteInfo(currentPage?: string) {
- const isCouponIssuerRes = await isCouponIssuer(currentPage)
- if (!isCouponIssuerRes) {
- return isCouponIssuerRes
- }
- const isInviter = await inviterStore.fetchInviterInfo()
- if (!isInviter) {
- uni.showModal({
- title: '提示',
- content: '您没有上级邀请人,无法查看邀请信息',
- showCancel: false,
- })
- }
- return isInviter
- }
- async function onRefresh() {
- refreshing.value = true
- await userStore.fetchUserInfo()
- await getCouponSituationRequest({ queryType: 'time' })
- await getShareStateRequest()
- deadline.value = Date.now()
- refreshing.value = false
- }
- // 创建分享hook实例
- const { getShareConfig, getTimelineShareConfig } = useShare()
- // #ifdef MP-WEIXIN
- // 分享给好友生命周期函数
- onShareAppMessage(async (options) => {
- return await getShareConfig()
- })
- // 分享到朋友圈生命周期函数
- onShareTimeline(async () => {
- return await getTimelineShareConfig()
- })
- // #endif
- </script>
- <template>
- <view class="profile-container">
- <up-pull-refresh :refreshing="refreshing" :threshold="60" @refresh="onRefresh">
- <!-- 顶部区域 -->
- <view class="me-header"
- :style="{ background: `url(${getImageUrl('@img/me/me-bg.png')})`, backgroundSize: 'cover', backgroundRepeat: 'no-repeat', backgroundPosition: 'center center' }">
- <view class="me-header-avatar-info" :style="{ paddingTop: `23rpx` }">
- <up-image :src="avatarDisplay" width="128rpx" height="128rpx" shape="circle" />
- <view class="me-header-info">
- <view class="me-header-name">
- <!-- #ifdef MP-WEIXIN -->
- <!-- <input v-model="userInfo.value.nickname" type="nickname" :disabled="true" placeholder="用户昵称"
- placeholder-style="color: #fff; opacity: 0.7;" class="nickname-input"> -->
- <text class="nickname-input">{{ userInfo.nickname || '用户' }}</text>
- <!-- #endif -->
- <!-- #ifndef MP-WEIXIN -->
- {{ userInfo.value?.nickname || '用户' }}
- <!-- #endif -->
- </view>
- </view>
- </view>
- <view class="me-header-tips">
- <view class="me-header-tips-row header-data-time">
- <view class="desc-time">
- <up-loading-icon v-if="couponSituationLoading || shareStateLoading" size="23rpx"
- :loading="couponSituationLoading || shareStateLoading" color="#fff" />
- <up-icon v-else name="info-circle" size="23rpx" color="#fff" />
- <view v-if="couponSituationLoading || shareStateLoading" class="desc-text">
- 数据加载中...
- </view>
- <view v-else class="desc-text">
- 数据截止到 {{ changtime(deadline, 'YYYY-MM-DD HH:mm:ss') }}
- </view>
- </view>
- </view>
- <view class="me-header-tips-row header-data-info">
- <view class="me-header-tips-item">
- <view class="me-header-tips-item-num">
- {{ shareStateData?.todayShareCount || 0 }}
- </view>
- <view class="me-header-tips-item-des">
- 今日邀请
- </view>
- </view>
- <view class="me-header-tips-item">
- <view class="me-header-tips-item-num">
- {{ shareStateData?.totalShareCount || 0 }}
- </view>
- <view class="me-header-tips-item-des">
- 累计邀请
- </view>
- </view>
- <view class="me-header-tips-item" @click="menuClick('invitePage')">
- <view class="me-header-tips-item-num">
- {{ shareStateData?.totalTeamMemberCount || 0 }}
- </view>
- <view class="me-header-tips-item-des">
- 累计团员
- </view>
- <view class="me-header-tips-item-icon">
- <up-icon name="arrow-right" size="21rpx" color="#FFFFFF" />
- </view>
- </view>
- </view>
- <view class="me-header-tips-row header-data-info">
- <view class="me-header-tips-item">
- <view class="me-header-tips-item-num">
- {{ couponSituationData?.quantityForComplimentary || 0 }}
- </view>
- <view class="me-header-tips-item-des">
- 今日发券
- </view>
- </view>
- <view class="me-header-tips-item">
- <view class="me-header-tips-item-num">
- {{ couponSituationData?.quantityToBeUsed || 0 }}
- </view>
- <view class="me-header-tips-item-des">
- 今日领取
- </view>
- </view>
- <view class="me-header-tips-item" @click="menuClick('incomePage')">
- <view class="me-header-tips-item-num">
- {{ couponSituationData?.usedQuantity || 0 }}
- </view>
- <view class="me-header-tips-item-des">
- 今日使用
- </view>
- <view class="me-header-tips-item-icon">
- <up-icon name="arrow-right" size="21rpx" color="#FFFFFF" />
- </view>
- </view>
- </view>
- </view>
- </view>
- <!-- 菜单 -->
- <view class="me-header-menu">
- <view class="me-header-menu-item" @click="menuClick('applyForm',watchUserStatus)">
- <view class="me-header-menu-icon">
- <image :src="getImageUrl('@img/me/coupon-need.png')" mode="aspectFill" />
- <view class="me-header-menu-text">
- 申请发券人
- </view>
- </view>
- <view class="me-header-menu-left">
- <up-icon name="arrow-right" color="#979797" size="12" />
- </view>
- </view>
- <view class="me-header-menu-item" @click="menuClick('invitePage', isCouponIssuer)">
- <view class="me-header-menu-icon">
- <image :src="getImageUrl('@img/me/invite.png')" mode="aspectFill" />
- <view class="me-header-menu-text">
- 我的邀请
- </view>
- </view>
- <view class="me-header-menu-left">
- <up-icon name="arrow-right" color="#979797" size="12" />
- </view>
- </view>
- <view class="me-header-menu-item" @click="menuClick('myInviter', getInviteInfo)">
- <view class="me-header-menu-icon">
- <image :src="getImageUrl('@img/me/inviter.png')" mode="aspectFill" />
- <view class="me-header-menu-text">
- 我的邀请人
- </view>
- </view>
- <view class="me-header-menu-left">
- <up-icon name="arrow-right" color="#979797" size="12" />
- </view>
- </view>
- <view class="me-header-menu-item" @click="menuClick('shareFriend', isCouponIssuer)">
- <view class="me-header-menu-icon">
- <image :src="getImageUrl('@img/me/share.png')" mode="aspectFill" />
- <view class="me-header-menu-text">
- 邀请好友
- </view>
- </view>
- <view class="me-header-menu-left">
- <up-icon name="arrow-right" color="#979797" size="12" />
- </view>
- </view>
- <view class="me-header-menu-item" @click="menuClick('settingPage')">
- <view class="me-header-menu-icon">
- <image :src="getImageUrl('@img/me/setting.png')" mode="aspectFill" />
- <view class="me-header-menu-text">
- 设置
- </view>
- </view>
- <view class="me-header-menu-left">
- <up-icon name="arrow-right" color="#979797" size="12" />
- </view>
- </view>
- <view class="me-header-menu-item" @click="handleLogout">
- <view class="me-header-menu-icon">
- <image :src="getImageUrl('@img/me/loginOut.png')" mode="aspectFill" />
- <view class="me-header-menu-text">
- 退出登录
- </view>
- </view>
- <view class="me-header-menu-left">
- <up-icon name="arrow-right" color="#979797" size="12" />
- </view>
- </view>
- </view>
- </up-pull-refresh>
- <!-- 申请中的提示框 -->
- <up-modal content="您已提交申请,请耐心等待!" title="提示" :show="show">
- <template #confirmButton>
- <view class="rounded" style="margin-top: 20rpx;" @click="show = false">
- 我知道了
- </view>
- </template>
- </up-modal>
- </view>
- </template>
- <style lang="scss" scoped>
- // 提示框
- ::v-deep .u-modal {
- width: 580rpx !important;
- // height: 376rpx !important;
- border-radius: 20rpx !important;
- }
- ::v-deep .u-modal__title {
- font-weight: 500 !important;
- font-size: 34rpx !important;
- color: #333333 !important;
- padding-top: 29rpx !important;
- padding-bottom: 28rpx !important;
- }
- ::v-deep .u-modal__content {
- border-top: 1px solid #eeeeee;
- border-bottom: 1px solid #eeeeee;
- padding-top: 82rpx !important;
- padding-bottom: 64rpx !important;
- }
- ::v-deep .u-modal__content__text {
- font-weight: 500 !important;
- font-size: 32rpx !important;
- color: #333333 !important;
- text-align: center !important;
- }
- .rounded {
- width: 300rpx;
- line-height: 69rpx;
- background: linear-gradient(90deg, #ee6b67 0%, #ff7d78 100%);
- border-radius: 35rpx;
- font-weight: 400;
- font-size: 30rpx;
- color: #ffffff;
- text-align: center;
- margin: 0 auto;
- }
- .profile-container {
- height: calc(100vh - 100rpx);
- background-color: #f8f8fa;
- .me-header {
- height: 746rpx;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- .me-header-avatar-info {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 24rpx;
- .me-header-info {
- .me-header-name {
- font-weight: 500;
- font-size: 30rpx;
- color: #ffffff;
- }
- }
- }
- .me-header-tips {
- margin-top: 46rpx;
- height: 317rpx;
- width: 702rpx;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 20rpx;
- background: linear-gradient(90deg, #ff7671, #ff8e8a, #ff7671);
- border-radius: 8rpx;
- .me-header-tips-row {
- display: flex;
- .desc-time {
- width: 100%;
- display: flex;
- flex-direction: row;
- flex-wrap: nowrap;
- gap: 6rpx;
- justify-content: flex-end;
- padding-right: 21rpx;
- font-weight: 400;
- font-size: 20rpx;
- color: #ffffff;
- line-height: 20rpx;
- }
- .me-header-tips-item {
- flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 15rpx;
- font-weight: 500;
- font-size: 34rpx;
- color: #ffffff;
- line-height: 1;
- .me-header-tips-item-num {
- font-weight: bold;
- }
- .me-header-tips-item-des {
- font-weight: 400;
- font-size: 24rpx;
- color: #ffffff;
- }
- }
- }
- .header-data-time {
- align-self: flex-end;
- }
- .me-header-tips-row.header-data-info {
- align-self: center;
- width: 642rpx;
- height: 96rpx;
- background: rgba($color: #851b17, $alpha: 0.1);
- border-radius: 10rpx;
- .me-header-tips-item {
- font-weight: 400;
- font-size: 23rpx;
- color: #ffffff;
- position: relative;
- &:not(:last-child):after {
- content: '';
- position: absolute;
- top: 50%;
- right: 0;
- transform: translateY(-50%);
- width: 2px;
- height: 40rpx;
- background: #ffffff;
- }
- .me-header-tips-item-icon {
- position: absolute;
- top: 50%;
- right: 21rpx;
- width: 21rpx;
- height: 21rpx;
- font-weight: bolder;
- transform: translateY(-50%);
- }
- }
- }
- }
- }
- .me-header-menu {
- background: #ffffff;
- border-radius: 10rpx;
- margin: -50rpx 24rpx 0;
- padding: 0 20rpx;
- .me-header-menu-item {
- height: 88rpx;
- display: flex;
- justify-content: space-between;
- align-items: center;
- border-bottom: 1px solid #eeeeee;
- &:last-child {
- border-bottom: none;
- }
- .me-header-menu-icon {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 13rpx;
- image {
- width: 40rpx;
- height: 40rpx;
- }
- .me-header-menu-text {
- font-weight: 400;
- font-size: 26rpx;
- color: #333333;
- }
- }
- .me-header-menu-left {}
- }
- }
- }
- /* 昵称输入框样式 */
- .nickname-input {
- width: 100%;
- height: 100%;
- font-weight: 500;
- font-size: 30rpx;
- color: #ffffff;
- background: transparent;
- border: none;
- outline: none;
- text-align: center;
- }
- </style>
|