532 lines
13 KiB
Vue
532 lines
13 KiB
Vue
<script setup lang="ts">
|
||
import * as R from "ramda";
|
||
import dayjs from 'dayjs'
|
||
import useEventEmit from "@/hooks/useEventEmit";
|
||
import { EventEnum } from "@/constant/enums";
|
||
import { useConfigStore, useUserStore } from "@/store";
|
||
import MineSkeleton from "./components/mine-skeleton.vue";
|
||
const configStore = useConfigStore();
|
||
const userStore = useUserStore();
|
||
import { Agreement } from "@/constant/enums";
|
||
import Config from '@/config/index'
|
||
import {formatTimestampWithMonthName, loadWeixinService} from "@/utils/utils";
|
||
const { t } = useI18n();
|
||
|
||
const loading = ref(true);
|
||
|
||
const emits = defineEmits<{
|
||
chooseLanguage: [];
|
||
logOut: [];
|
||
inviteUser: [];
|
||
customerService: [];
|
||
changeOrder: [];
|
||
}>();
|
||
interface Tab {
|
||
iconPath: string;
|
||
path: string;
|
||
text: string;
|
||
code: string;
|
||
isLogin: boolean;
|
||
}
|
||
|
||
const tabBarList = ref<Tab[]>([
|
||
{
|
||
iconPath: "/static/images/chef/100201.png",
|
||
path: "/pages-user/pages/coupon/index",
|
||
text: t("pages.mine.discount"),
|
||
code: "discount",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100200.png",
|
||
path: "/pages-user/pages/faqs/index",
|
||
text: t("pages.mine.help"),
|
||
code: "help",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100199.png",
|
||
path: "/pages-user/pages/coupon/index",
|
||
text: t("pages.mine.inviteFriends"),
|
||
code: "inviteFriends",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/100203.png",
|
||
path: "/pages-user/pages/invited-person/index",
|
||
text: t('pages.mine.my-invitations'),
|
||
code: "myInvitations",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100198.png",
|
||
path: "/pages-user/pages/store-settle-in/index",
|
||
text: t("pages.mine.storeSettled"),
|
||
code: "storeSettled",
|
||
isLogin: false,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100197.png",
|
||
path: "/pages-user/pages/coupon/index",
|
||
text: t("pages.mine.support"),
|
||
code: "support",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100196.png",
|
||
path: "/pages/agreement/index?code=" + Agreement.CHEF_PLATFORM_AGREEMENT,
|
||
text: t("pages.mine.platformAgreement"),
|
||
code: "platformAgreement",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100195.png",
|
||
path: "/pages/agreement/index?code=" + Agreement.PRIVACY_POLICY,
|
||
text: t("pages.mine.privacyPolicy"),
|
||
code: "privacyPolicy",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100194.png",
|
||
path: "/pages-user/pages/complaints/index",
|
||
text: t("pages.mine.complaintsAndSuggestions"),
|
||
code: "complaintsAndSuggestions",
|
||
isLogin: true,
|
||
},
|
||
{
|
||
iconPath: "/static/images/chef/100192.png",
|
||
path: "/pages-user/pages/setting/index",
|
||
text: t("pages.mine.set"),
|
||
code: "set",
|
||
isLogin: true,
|
||
},
|
||
]);
|
||
|
||
function navigateTo(url: string) {
|
||
if(userStore.checkLogin()) {
|
||
uni.navigateTo({
|
||
url,
|
||
});
|
||
}
|
||
}
|
||
|
||
function checkNeedLogin(isNeedLogin: boolean) {
|
||
return isNeedLogin ? userStore.checkLogin() : true;
|
||
}
|
||
|
||
// 用户会员状态是否已开通
|
||
const isUserMember = computed(()=> {
|
||
if(!userStore.userInfo.userMembershipVo) return false
|
||
if(userStore.userInfo.userMembershipVo && userStore.userInfo.userMembershipVo.expireTime ){
|
||
return dayjs().isBefore(dayjs(Number(userStore.userInfo.userMembershipVo.expireTime)))
|
||
} else {
|
||
return false
|
||
}
|
||
})
|
||
|
||
function handleTabClick(item: Tab) {
|
||
switch (item.code) {
|
||
case "inviteFriends": {
|
||
R.both(
|
||
checkNeedLogin,
|
||
R.pipe(() => emits("inviteUser"), R.T)
|
||
)(item.isLogin);
|
||
break;
|
||
}
|
||
case "support": {
|
||
// emits("customerService");
|
||
loadWeixinService()
|
||
break;
|
||
}
|
||
default: {
|
||
// navigateTo(item.path)
|
||
if (item.code === "set") {
|
||
navigateTo("/pages-user/pages/setting/index");
|
||
} else {
|
||
R.both(
|
||
checkNeedLogin,
|
||
R.pipe(() => navigateTo(item.path), R.T)
|
||
)(item.isLogin);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
function changeOrderFn() {
|
||
emits("changeOrder");
|
||
}
|
||
|
||
async function initData() {
|
||
loading.value = false;
|
||
// setTimeout(() => {
|
||
// loading.value = false;
|
||
// }, 300);
|
||
userStore.getUserInfo()
|
||
}
|
||
|
||
async function getPlatformDefaultStoreInfo() {}
|
||
|
||
defineExpose({
|
||
initData,
|
||
init: getPlatformDefaultStoreInfo,
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<view
|
||
class="view-bg"
|
||
:style="[
|
||
{
|
||
height: configStore.windowHeight + 'px',
|
||
},
|
||
]"
|
||
>
|
||
<z-paging ref="paging">
|
||
<template #top>
|
||
<status-bar />
|
||
</template>
|
||
<view
|
||
v-show="loading"
|
||
class="animate-in fade-in animate-ease-out animate-duration-300"
|
||
>
|
||
<mine-skeleton />
|
||
</view>
|
||
<view
|
||
v-show="!loading"
|
||
class="animate-in fade-in animate-ease-in animate-duration-300"
|
||
>
|
||
<view class="mine-page ">
|
||
<!-- 顶部用户信息 -->
|
||
<view class="mine-header" @click="navigateTo('/pages-user/pages/user-info/index')">
|
||
<view class="mine-header__left">
|
||
<text class="mine-header__name">
|
||
{{
|
||
userStore.isLogin
|
||
? ([userStore.userInfo.firstName, userStore.userInfo.surname].filter(Boolean).join(' ') ||
|
||
t('common.unknownUser'))
|
||
: t('common.pleaseLogin')
|
||
}}
|
||
</text>
|
||
<view class="mine-header__sub" v-if="userStore.isLogin">
|
||
<text class="mine-header__member">{{ Config.appName }} {{ t('pages.mine.member') }}</text>
|
||
<view class="mine-header__badge" v-if="!isUserMember">
|
||
{{ t('pages.mine.openMember') }}
|
||
</view>
|
||
<text class="mine-header__chev">›</text>
|
||
</view>
|
||
<text class="mine-header__date" v-if="isUserMember && userStore.userInfo.userMembershipVo?.expireTime">
|
||
{{ t('common.expireTime') }}:{{ formatTimestampWithMonthName(userStore.userInfo.userMembershipVo?.expireTime) }}
|
||
</text>
|
||
</view>
|
||
|
||
<image
|
||
v-if="userStore.isLogin"
|
||
:src="userStore.userInfo.avatar"
|
||
class="mine-header__avatar"
|
||
mode="aspectFill"
|
||
/>
|
||
<image v-else class="mine-header__avatar" mode="aspectFill" src="@img/chef/default_avatar.png" />
|
||
</view>
|
||
|
||
<!-- 三项数据胶囊卡 -->
|
||
<view class="mine-stats">
|
||
<view class="mine-stats__item" @click="navigateTo('/pages-user/pages/collection/index')">
|
||
<text class="mine-stats__num">{{ userStore.userInfo.collectNum || 0 }}</text>
|
||
<text class="mine-stats__label">{{ t('pages.mine.collection') }}</text>
|
||
</view>
|
||
<view class="mine-stats__divider" />
|
||
<view class="mine-stats__item" @click="navigateTo('/pages-user/pages/balance/index')">
|
||
<text class="mine-stats__num">{{ userStore.userInfo?.balance || 0 }}</text>
|
||
<text class="mine-stats__label">{{ t('pages.mine.wallet') }}</text>
|
||
</view>
|
||
<view class="mine-stats__divider" />
|
||
<view class="mine-stats__item" @click="changeOrderFn">
|
||
<text class="mine-stats__num">{{ userStore.userInfo.orderNum || 0 }}</text>
|
||
<text class="mine-stats__label">{{ t('pages.mine.order') }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<template v-if="isUserMember">
|
||
<view @click="navigateTo('/pages-user/pages/member/index')" class="member-banner">
|
||
<image src="@img/chef/100203.png" class="member-banner__bg"></image>
|
||
<view class="member-banner__content">
|
||
<view class="member-banner__title">{{ Config.appName }}</view>
|
||
<view class="member-banner__sub">
|
||
{{ t('common.expireTime') }}:{{ formatTimestampWithMonthName(userStore.userInfo.userMembershipVo?.expireTime) }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<template v-else>
|
||
<view @click="navigateTo('/pages-user/pages/member/index')" class="member-banner">
|
||
<image src="@img/chef/100203.png" class="member-banner__bg"></image>
|
||
<view class="member-banner__content">
|
||
<view class="member-banner__title">
|
||
<template v-if="!userStore.userInfo.userMembershipVo">{{ t('pages.mine.member-title') }}</template>
|
||
<template v-else>{{ t('pages.mine.join') }} {{ Config.appName }}</template>
|
||
</view>
|
||
<view class="member-banner__sub">{{ t('pages.mine.member-desc') }}</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<view style="height: 30rpx;background-color: #f5f5f5;" />
|
||
|
||
<!-- 菜单列表卡片 -->
|
||
<view class="mine-menu">
|
||
<view
|
||
class="mine-menu__row"
|
||
v-for="(item, index) in tabBarList"
|
||
:key="item.code"
|
||
:class="[index === tabBarList.length - 1 ? 'mine-menu__row--last' : '']"
|
||
@click="handleTabClick(item)"
|
||
>
|
||
<view class="mine-menu__left">
|
||
<image class="mine-menu__icon" :src="item.iconPath"></image>
|
||
<text class="mine-menu__text">{{ item.text }}</text>
|
||
</view>
|
||
<image class="mine-menu__arrow" src="@img/chef/100202.png"></image>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="mine-bottom-spacer" />
|
||
</view>
|
||
|
||
</view>
|
||
<template #bottom>
|
||
<view class="h-50px"></view>
|
||
<view :style="[configStore.iosSafeBottomPlaceholder]"></view>
|
||
</template>
|
||
</z-paging>
|
||
</view>
|
||
</template>
|
||
|
||
<style scoped lang="scss">
|
||
.view-bg {
|
||
background-color: #fff;
|
||
}
|
||
|
||
.mine-page {
|
||
padding-bottom: 20rpx;
|
||
}
|
||
|
||
.mine-header {
|
||
margin: 0 30rpx;
|
||
padding: 32rpx 0 28rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
&__left {
|
||
min-width: 0;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
|
||
&__name {
|
||
font-size: 38rpx;
|
||
line-height: 40rpx;
|
||
font-weight: 700;
|
||
color: #333;
|
||
letter-spacing: 0.04em;
|
||
max-width: 520rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
&__sub {
|
||
margin-top: 12rpx;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
color: #b68b3e;
|
||
font-size: 22rpx;
|
||
line-height: 22rpx;
|
||
font-weight: 600;
|
||
}
|
||
|
||
&__member {
|
||
color: #b68b3e;
|
||
}
|
||
|
||
&__badge {
|
||
padding: 8rpx 16rpx;
|
||
border-radius: 999rpx;
|
||
background: rgba(182, 139, 62, 0.12);
|
||
color: #b68b3e;
|
||
font-size: 20rpx;
|
||
line-height: 20rpx;
|
||
font-weight: 700;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
|
||
&__chev {
|
||
transform: translateY(-1rpx);
|
||
color: #b68b3e;
|
||
font-size: 24rpx;
|
||
line-height: 22rpx;
|
||
}
|
||
|
||
&__date {
|
||
margin-top: 10rpx;
|
||
font-size: 22rpx;
|
||
line-height: 22rpx;
|
||
color: #999;
|
||
font-weight: 500;
|
||
}
|
||
|
||
&__avatar {
|
||
width: 90rpx;
|
||
height: 90rpx;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
background-color: #eee;
|
||
}
|
||
}
|
||
|
||
.mine-stats {
|
||
margin: 15rpx 35rpx;
|
||
// margin-top: 24rpx;
|
||
background: #fff;
|
||
border-radius: 36rpx;
|
||
height: 120rpx;
|
||
padding: 0 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
box-shadow: 0 12rpx 30rpx rgba(10, 10, 10, 0.06);
|
||
|
||
&__item {
|
||
flex: 1;
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8rpx;
|
||
|
||
}
|
||
|
||
&__num {
|
||
font-size: 32rpx;
|
||
line-height: 30rpx;
|
||
font-weight: 700;
|
||
color: #333;
|
||
}
|
||
|
||
&__label {
|
||
font-size: 26rpx;
|
||
line-height: 28rpx;
|
||
color: #666;
|
||
font-weight: 700;
|
||
letter-spacing: 0.04em;
|
||
// font-weight: 500;
|
||
}
|
||
|
||
&__divider {
|
||
width: 1rpx;
|
||
height: 56rpx;
|
||
background: #eaeaea;
|
||
flex-shrink: 0;
|
||
}
|
||
}
|
||
|
||
.member-banner {
|
||
margin: 15rpx 30rpx;
|
||
height: 152rpx;
|
||
position: relative;
|
||
border-radius: 36rpx;
|
||
overflow: hidden;
|
||
|
||
&__bg {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
}
|
||
|
||
&__content {
|
||
position: relative;
|
||
z-index: 1;
|
||
height: 100%;
|
||
padding: 22rpx 165rpx 22rpx 28rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
&__title {
|
||
font-size: 32rpx;
|
||
line-height: 32rpx;
|
||
font-weight: 800;
|
||
color: #333;
|
||
}
|
||
|
||
&__sub {
|
||
font-size: 20rpx;
|
||
line-height: 20rpx;
|
||
font-weight: 600;
|
||
color: #935d04;
|
||
letter-spacing: 0.08em;
|
||
}
|
||
}
|
||
|
||
.mine-menu {
|
||
margin:20rpx 30rpx 30rpx;
|
||
background: #fff;
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
|
||
&__row {
|
||
padding: 28rpx 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
border-bottom: 1rpx solid #efefef;
|
||
}
|
||
|
||
&__row--last {
|
||
border-bottom: none;
|
||
}
|
||
|
||
&__left {
|
||
min-width: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 18rpx;
|
||
}
|
||
|
||
&__icon {
|
||
width: 38rpx;
|
||
height: 38rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
&__text {
|
||
font-size: 26rpx;
|
||
line-height: 26rpx;
|
||
color: #333;
|
||
// font-weight: 600;
|
||
letter-spacing: 0.04em;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
&__arrow {
|
||
width: 22rpx;
|
||
height: 30rpx;
|
||
flex-shrink: 0;
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
|
||
.mine-bottom-spacer {
|
||
height: 58rpx;
|
||
}
|
||
</style>
|