feat(登录)

This commit is contained in:
Ankkaya 2024-05-29 17:07:37 +08:00
parent c611e44858
commit c65eb5ddcd
16 changed files with 1012 additions and 910 deletions

2
.env
View File

@ -5,7 +5,7 @@ MALL_VERSION = v1.0.0
MALL_BASE_URL = http://api-dashboard.yudao.iocoder.cn MALL_BASE_URL = http://api-dashboard.yudao.iocoder.cn
# 后端接口 - 测试环境(通过 process.env.NODE_ENV = development # 后端接口 - 测试环境(通过 process.env.NODE_ENV = development
MALL_DEV_BASE_URL = http://mall-backend-dev.jiandyb.cn:7001 MALL_DEV_BASE_URL = https://mall-baclend-local.jiandyb9834.xyz
# 后端接口前缀(一般不建议调整) # 后端接口前缀(一般不建议调整)
MALL_API_PATH = /merchant-api MALL_API_PATH = /merchant-api

View File

@ -3,8 +3,6 @@ import { onLaunch, onShow, onError } from '@dcloudio/uni-app'
import { peachInit } from './peach' import { peachInit } from './peach'
onLaunch(() => { onLaunch(() => {
// 使
uni.hideTabBar()
peachInit() peachInit()
}) })

View File

@ -8,6 +8,9 @@
}, },
"pages": [ "pages": [
//pageshttps://uniapp.dcloud.io/collocation/pages //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/redirect"
},
{ {
"path": "pages/order/list", "path": "pages/order/list",
"style": { "style": {
@ -67,7 +70,6 @@
{ {
"root": "pages/public", "root": "pages/public",
"pages": [ "pages": [
{ {
"path": "error", "path": "error",
"style": { "style": {

View File

@ -3,34 +3,38 @@
<view :style="[{ paddingTop: peach.$platform.navBar + 'px' }]"></view> <view :style="[{ paddingTop: peach.$platform.navBar + 'px' }]"></view>
<view class="dashboard-module ss-p-x-30"> <view class="dashboard-module ss-p-x-30">
<view class="merchant-info flex align-center"> <view class="merchant-info flex align-center">
<image class="logo" :src="state.merchantInfo.logo" mode="aspectFill"></image> <image class="logo" :src="merchantInfo.logo" mode="aspectFill"></image>
<view class="detail flex flex-column justify-center gap-10"> <view class="detail flex flex-column justify-center gap-10">
<view class="name ss-font-26">{{ state.merchantInfo.name }}</view> <view class="name ss-font-26">{{ merchantInfo.name }}</view>
<view class="description ss-font-26">{{ state.merchantInfo.description }}</view> <view class="description ss-font-26">{{ merchantInfo?.contactPhone }}</view>
</view> </view>
</view> </view>
<view class="statistic ss-m-t-24"> <view class="statistic ss-m-t-24">
<view class="title ss-font-24 ss-m-b-20"> <view class="title ss-font-24 ss-m-b-20">
{{ `今日收款金额(成功收款${state.statistic.total}笔)` }} {{ `今日收款金额(成功收款${state.statistic.todayPaymentCount}笔)` }}
</view> </view>
<view class="income flex justify-between align-center"> <view class="income flex justify-between align-center">
<view class="left flex align-center"> <view class="left flex align-center">
<view class="unit self-start"></view> <view class="unit self-start"></view>
<view class="sincome ss-font-60">{{ state.statistic.income }}</view> <view class="sincome ss-font-60">{{ state.statistic.todayPaymentAmount || 0 }}</view>
</view> </view>
<button class="right-btn ss-reset-button">查看详情</button> <button class="right-btn ss-reset-button">查看详情</button>
</view> </view>
<view class="des ss-m-t-20">
总销售额{{ state.statistic.totalSalesAmount }} | 成功退款{{ state.statistic.refundCount }} |
退款金额{{ state.statistic.refundAmount }}
</view>
</view> </view>
<view class="more ss-m-t-70"> <view class="more ss-m-t-70">
<view class="title ss-m-b-30">基础数据</view> <view class="title ss-m-b-30">基础数据</view>
<view class="items"> <view class="items">
<view class="item" v-for="item in state.more"> <view class="item" v-for="item in state.more" :key="item.name">
<view class="label">{{ item.name }}</view> <view class="label">{{ item.name }}</view>
<view class="value">{{ item.value }}</view> <view class="value">{{ item.value }}</view>
<view class="last">昨日 {{ item.last }}</view> <view class="last"> 昨日 {{ item.last }} </view>
</view> </view>
</view> </view>
</view> </view>
@ -39,8 +43,11 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, computed } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import peach from '@/peach' import peach from '@/peach'
import $store from '@/peach/store'
import UserUtil from '@/peach/api/member/user'
import bg from '@/static/bg-page.png' import bg from '@/static/bg-page.png'
const bgStyle = { const bgStyle = {
@ -51,43 +58,62 @@ const bgStyle = {
} }
const state = ref({ const state = ref({
merchantInfo: {
name: '测试商家',
logo: '/static/logo.png',
description: '测试商家描述',
},
statistic: { statistic: {
total: 100, todayPaymentCount: 0,
income: 2222222222, todayPaymentAmount: 0,
totalSalesAmount: 0,
refundCount: 0,
refundAmount: 0,
}, },
more: [ more: [
{ {
name: '支付金额', name: '销售金额',
value: 10000000, key: 'Amount',
last: 100000000, value: 0,
}, last: 0,
{
name: '访客数',
value: 100000,
last: 100000,
}, },
{ {
name: '订单数', name: '订单数',
value: 100000, key: 'orderCount',
last: 10000, value: 0,
last: 0,
}, },
{ {
name: '客单价', name: '待核销',
value: 10000, key: 'verificationOrderCount',
last: 100, value: 0,
}, },
{ {
name: '支付买家数', name: '待配送',
value: 100, key: 'deliveryOrderCount',
last: 100, value: 0,
}, },
], ],
}) })
const userStore = $store('user')
const merchantInfo = computed(() => {
return userStore.userInfo?.particulars
})
async function getStatistic() {
let res = await UserUtil.getHomeStatistics()
for (let key of Object.keys(state.value.statistic)) {
state.value.statistic[key] = res.data[key]
}
state.value.more[0].value = res.data.todayPaymentAmount ?? 0
state.value.more[0].last = res.data.yesterdaySalesAmount ?? 0
state.value.more[1].value = res.data.orderCount
state.value.more[1].last = res.data.yesterdayOrderCount
state.value.more[2].value = res.data.verificationOrderCount
state.value.more[3].value = res.data.deliveryOrderCount
}
onShow(() => {
getStatistic()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -136,6 +162,11 @@ const state = ref({
color: #fff; color: #fff;
} }
} }
.des {
color: var(--ui-TC-2);
font-size: 24rpx;
}
} }
.more { .more {

View File

@ -6,15 +6,32 @@
</view> </view>
<uni-forms ref="smsLoginRef" v-model="state.model" :rules="state.rules" validateTrigger="bind"> <uni-forms ref="smsLoginRef" v-model="state.model" :rules="state.rules" validateTrigger="bind">
<uni-forms-item name="mobile"> <uni-forms-item name="mobile">
<uni-easyinput :styles="state.inputStyle" trim="all" placeholder="请输入手机号" v-model="state.model.mobile" <uni-easyinput
:inputBorder="false" type="number" /> :styles="state.inputStyle"
trim="all"
placeholder="请输入手机号"
v-model="state.model.mobile"
:inputBorder="false"
type="number"
/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item name="code"> <uni-forms-item name="code">
<uni-easyinput :styles="state.inputStyle" trim="all" placeholder="验证码" v-model="state.model.code" <uni-easyinput
:inputBorder="false" type="number" maxlength="4"> :styles="state.inputStyle"
trim="all"
placeholder="验证码"
v-model="state.model.code"
:inputBorder="false"
type="number"
maxlength="4"
>
<template #right> <template #right>
<button :disabled="state.isMobileEnd" :class="{ 'code-btn-end': state.isMobileEnd }" <button
class="ss-reset-button code-btn code-btn-start" @tap="getSmsCode('smsLogin', state.model.mobile)"> :disabled="state.isMobileEnd"
:class="{ 'code-btn-end': state.isMobileEnd }"
class="ss-reset-button code-btn code-btn-start"
@tap="getSmsCode('smsLogin', state.model.mobile)"
>
{{ getSmsTimer('smsLogin') }} {{ getSmsTimer('smsLogin') }}
</button> </button>
</template> </template>
@ -24,8 +41,12 @@
<button class="ss-reset-button login-btn-start" @tap="smsLoginSubmit">登录</button> <button class="ss-reset-button login-btn-start" @tap="smsLoginSubmit">登录</button>
<view class="agreement-box ss-flex ss-row-center" :class="{ shake: state.isShaking }"> <view class="agreement-box ss-flex ss-row-center" :class="{ shake: state.isShaking }">
<label class="radio ss-flex" @tap="onChange"> <label class="radio ss-flex" @tap="onChange">
<radio :checked="state.agreeStatus" color="var(--ui-BG-Main)" style="transform: scale(0.8)" <radio
@tap.stop="onChange" /> :checked="state.agreeStatus"
color="var(--ui-BG-Main)"
style="transform: scale(0.8)"
@tap.stop="onChange"
/>
<view class="agreement-text ss-flex ss-m-l-8"> <view class="agreement-text ss-flex ss-m-l-8">
我已阅读并遵守 我已阅读并遵守
<view class="tcp-text" @tap.stop="onProtocol('商家入驻协议')"> 商家入驻协议 </view> <view class="tcp-text" @tap.stop="onProtocol('商家入驻协议')"> 商家入驻协议 </view>
@ -38,10 +59,10 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { code, mobile } from '@/peach/validate/form'; import { code, mobile } from '@/peach/validate/form'
import AuthUtil from '@/peach/api/member/auth'; import AuthUtil from '@/peach/api/member/auth'
import peach from '@/peach' import peach from '@/peach'
import { showAuthModal, closeAuthModal, getSmsCode, getSmsTimer } from '@/peach/hooks/useModal'; import { showAuthModal, closeAuthModal, getSmsCode, getSmsTimer } from '@/peach/hooks/useModal'
const title = ref('欢迎登录') const title = ref('欢迎登录')
const smsLoginRef = ref(null) const smsLoginRef = ref(null)
@ -56,21 +77,19 @@ const state = ref({
}, },
rules: { rules: {
mobile, mobile,
code code,
}, },
inputStyle: { inputStyle: {
backgroundColor: '#ECECEC' backgroundColor: '#ECECEC',
} },
}) })
function onChange() { function onChange() {
state.value.agreeStatus = !state.value.agreeStatus state.value.agreeStatus = !state.value.agreeStatus
} }
async function smsLoginSubmit() { async function smsLoginSubmit() {
const validate = await smsLoginRef.value.validate().catch(err => { const validate = await smsLoginRef.value.validate().catch((err) => {
console.log('err', err) console.log('err', err)
}) })
if (!validate) return if (!validate) return
@ -84,18 +103,12 @@ async function smsLoginSubmit() {
} }
const { code } = await AuthUtil.smsLogin(state.value.model) const { code } = await AuthUtil.smsLogin(state.value.model)
if (code === 0) {
}
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.login-module { .login-module {
.uni-easyinput { .uni-easyinput {
::v-deep .uni-easyinput__content { ::v-deep .uni-easyinput__content {
border-radius: 41rpx; border-radius: 41rpx;
padding: 0 10rpx; padding: 0 10rpx;
@ -104,7 +117,7 @@ async function smsLoginSubmit() {
.is-focused { .is-focused {
::v-deep .content-clear-icon { ::v-deep .content-clear-icon {
.uniui-clear { .uniui-clear {
color: red !important color: red !important;
} }
} }
} }

View File

@ -3,11 +3,11 @@
<view :style="[{ paddingTop: peach.$platform.navBar + 'px' }]"></view> <view :style="[{ paddingTop: peach.$platform.navBar + 'px' }]"></view>
<view class="my-module ss-p-x-30"> <view class="my-module ss-p-x-30">
<view class="user-info flex align-center"> <view class="user-info flex align-center">
<image class="avatar" :src="state.userInfo.avatar" mode="aspectFill"></image> <image class="avatar" :src="userInfo.avatar || '/static/default_avatar.png'" mode="aspectFill"></image>
<view class="detail flex flex-column justify-center gap-10"> <view class="detail flex flex-column justify-center gap-10">
<view class="name ss-font-26">{{ state.userInfo.name }}</view> <view class="name ss-font-26">{{ userInfo.nickname }}</view>
<view class="description ss-font-26">{{ state.userInfo.description }}</view> <view class="description ss-font-26">{{ userInfo.mobile }}</view>
</view> </view>
</view> </view>
@ -16,17 +16,17 @@
<view class="remain flex justify-between align-center"> <view class="remain flex justify-between align-center">
<view class="left flex align-center"> <view class="left flex align-center">
<view class="unit self-start"></view> <view class="unit self-start"></view>
<view class="sremain ss-font-60">{{ state.statistic.remain }}</view> <view class="sremain ss-font-60">{{ remain }}</view>
</view> </view>
<button class="right-btn ss-reset-button">查看详情</button> <button class="right-btn ss-reset-button">查看详情</button>
</view> </view>
<view class="cent ss-m-t-20"> 总获取积分{{ state.statistic.cent }} </view> <view class="cent ss-m-t-20"> 总获取积分{{ cent }} </view>
</view> </view>
<view class="menu ss-m-t-70"> <view class="menu ss-m-t-70">
<view class="title ss-m-b-30">我的服务</view> <view class="title ss-m-b-30">我的服务</view>
<view class="items"> <view class="items">
<view class="item" v-for="item in state.menus"> <view class="item" v-for="item in state.menus" :key="item.name">
<image class="icon" :src="item.icon" mode="aspectFill"></image> <image class="icon" :src="item.icon" mode="aspectFill"></image>
<view class="label">{{ item.name }}</view> <view class="label">{{ item.name }}</view>
</view> </view>
@ -40,26 +40,17 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, computed } from 'vue'
import $store from '@/peach/store'
import peach from '@/peach' import peach from '@/peach'
const bgStyle = { const bgStyle = {
backgroundImage: '/static/bg-page.png', backgroundImage: '/static/bg-page.png',
imageType: 'local', imageType: 'local',
backgroundColor: '#fff', backgroundColor: '#fff',
description: '',
} }
const state = ref({ const state = ref({
userInfo: {
name: 'Ankkaya',
avatar: '/static/logo.png',
description: '测试商家描述',
},
statistic: {
remain: 2222222222,
cent: 10000,
},
menus: [ menus: [
{ {
name: '余额提现', name: '余额提现',
@ -83,6 +74,17 @@ const state = ref({
}, },
], ],
}) })
const userStore = $store('user')
console.log(userStore)
const remain = computed(() => {
return userStore.userWallet?.balance
})
const userInfo = computed(() => {
return userStore.userInfo
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

31
pages/index/redirect.vue Normal file
View File

@ -0,0 +1,31 @@
<template>
<view></view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app'
import $store from '@/peach/store'
import peach from '@/peach'
const userStore = $store('user')
async function redirectFn() {
//
if (!userStore.isLogin) {
userStore.logOut()
peach.$router.redirect('/pages/index/login')
} else {
await userStore.loginAfter()
if (userStore.lastRoutePage) {
peach.$router.redirect(userStore.lastRoutePage)
} else {
peach.$router.redirect('/pages/index/index')
}
}
}
onLoad(() => {
redirectFn()
})
</script>

View File

@ -1,39 +1,40 @@
import request from "@/peach/request"; import request from '@/peach/request'
const AuthUtil = { const AuthUtil = {
smsLogin: (data) => { smsLogin: (data) => {
return request({ return request({
url: "/particulars/member/auth/sms-login", url: '/particulars/member/auth/sms-login',
method: "POST", method: 'POST',
data, data,
custom: { custom: {
showSuccess: true, showSuccess: true,
loadingMsg: "登陆中", loadingMsg: '登陆中',
successMsg: "登陆成功", successMsg: '登陆成功',
auth: false,
}, },
}); })
}, },
// 发送手机验证码 // 发送手机验证码
sendSmsCode: (mobile, scene) => { sendSmsCode: (mobile, scene) => {
return request({ return request({
url: "/member/auth/send-sms-code", url: '/member/auth/send-sms-code',
method: "POST", method: 'POST',
data: { data: {
mobile, mobile,
scene, scene,
}, },
custom: { custom: {
loadingMsg: "发送中", loadingMsg: '发送中',
showSuccess: true, showSuccess: true,
successMsg: "发送成功", successMsg: '发送成功',
}, },
}); })
}, },
// 刷新令牌 // 刷新令牌
refreshToken: (refreshToken) => { refreshToken: (refreshToken) => {
return request({ return request({
url: "/member/auth/refresh-token", url: '/member/auth/refresh-token',
method: "POST", method: 'POST',
params: { params: {
refreshToken, refreshToken,
}, },
@ -41,8 +42,8 @@ const AuthUtil = {
loading: false, // 不用加载中 loading: false, // 不用加载中
showError: false, // 不展示错误提示 showError: false, // 不展示错误提示
}, },
}); })
}, },
}; }
export default AuthUtil; export default AuthUtil

29
peach/api/member/user.js Normal file
View File

@ -0,0 +1,29 @@
import request from '@/peach/request'
const UserUtil = {
// 获取用户信息
getUserInfo: () => {
return request({
url: '/particulars/member/get',
method: 'GET',
})
},
// 获取钱包
getWalletInfo: () => {
return request({
url: '/pay/wallet/get',
method: 'GET',
})
},
// 首页统计
getHomeStatistics: () => {
return request({
url: '/statistics/index/get-count',
method: 'GET',
})
},
}
export default UserUtil

View File

@ -3,34 +3,34 @@
* @description api 模块管理loading 配置请求拦截错误处理 * @description api 模块管理loading 配置请求拦截错误处理
*/ */
import Request from "luch-request"; import Request from 'luch-request'
import { baseUrl, apiPath } from "@/peach/config"; import { baseUrl, apiPath } from '@/peach/config'
import peach from "@/peach"; import peach from '@/peach'
import $store from "@/peach/store"; import $store from '@/peach/store'
import AuthUtil from "@/peach/api/member/auth"; import AuthUtil from '@/peach/api/member/auth'
const options = { const options = {
// 显示操作成功消息 默认不显示 // 显示操作成功消息 默认不显示
showSuccess: false, showSuccess: false,
// 成功提醒 默认使用后端返回值 // 成功提醒 默认使用后端返回值
successMsg: "", successMsg: '',
// 显示失败消息 默认显示 // 显示失败消息 默认显示
showError: true, showError: true,
// 失败提醒 默认使用后端返回信息 // 失败提醒 默认使用后端返回信息
errorMsg: "", errorMsg: '',
// 显示请求时loading模态框 默认显示 // 显示请求时loading模态框 默认显示
showLoading: true, showLoading: true,
// loading提醒文字 // loading提醒文字
loadingMsg: "加载中", loadingMsg: '加载中',
// 需要授权才能请求 默认放开 // 需要授权才能请求 默认放开
auth: false, auth: true,
}; }
// Loading全局实例 // Loading全局实例
let LoadingInstance = { let LoadingInstance = {
target: null, target: null,
count: 0, count: 0,
}; }
/** /**
* @author Ankkaya * @author Ankkaya
@ -39,21 +39,21 @@ let LoadingInstance = {
* @returns {Type} * @returns {Type}
*/ */
function closeLoading() { function closeLoading() {
if (LoadingInstance.count > 0) LoadingInstance.count--; if (LoadingInstance.count > 0) LoadingInstance.count--
if (LoadingInstance.count === 0) uni.hideLoading(); if (LoadingInstance.count === 0) uni.hideLoading()
} }
// 请求实例 // 请求实例
const http = new Request({ const http = new Request({
baseURL: baseUrl + apiPath, baseURL: baseUrl + apiPath,
timeout: 8000, timeout: 8000,
method: "GET", method: 'GET',
header: { header: {
Accept: "text/json", Accept: 'text/json',
"Content-Type": "application/json;charset=UTF-8", 'Content-Type': 'application/json;charset=UTF-8',
}, },
custom: options, custom: options,
}); })
/** /**
* @author Ankkaya * @author Ankkaya
@ -65,37 +65,38 @@ const http = new Request({
http.interceptors.request.use( http.interceptors.request.use(
(config) => { (config) => {
// 自定义处理【auth 授权】:必须登录的接口,否则提示登录 // 自定义处理【auth 授权】:必须登录的接口,否则提示登录
if (config.custom.auth && !$store("user").isLogin) { if (config.custom.auth && !$store('user').isLogin) {
// 处理登录 // 处理登录
peach.$router.go("/pages/index/login"); peach.$router.go('/pages/index/login')
return Promise.reject(); return Promise.reject()
} }
// 自定义处理【loading 加载中】:如果需要显示 loading则显示 loading // 自定义处理【loading 加载中】:如果需要显示 loading则显示 loading
if (config.custom.showLoading) { if (config.custom.showLoading) {
LoadingInstance.count++; LoadingInstance.count++
LoadingInstance.count === 1 && LoadingInstance.count === 1 &&
uni.showLoading({ uni.showLoading({
title: config.custom.loadingMsg, title: config.custom.loadingMsg,
mask: true, mask: true,
fail: () => { fail: () => {
uni.hideLoading(); uni.hideLoading()
}, },
}); })
} }
// 增加 token 令牌、terminal 终端、tenant 租户的请求头 // 增加 token 令牌、terminal 终端、tenant 租户的请求头
const token = getAccessToken(); const token = getAccessToken()
if (token) { if (token) {
config.header["Authorization"] = token; config.header['Authorization'] = token
} }
config.header["Accept"] = "*/*"; config.header['Accept'] = '*/*'
return config; config.header['tenant-id'] = '1'
return config
}, },
(error) => { (error) => {
return Promise.reject(error); return Promise.reject(error)
} }
); )
/** /**
* @author Ankkaya * @author Ankkaya
@ -105,105 +106,97 @@ http.interceptors.request.use(
*/ */
http.interceptors.response.use( http.interceptors.response.use(
(response) => { (response) => {
console.log("response", response); console.log('response', response)
// 约定:如果是 /auth/ 下的 URL 地址,并且返回了 accessToken 说明是登录相关的接口,则自动设置登陆令牌 // 约定:如果是 /auth/ 下的 URL 地址,并且返回了 accessToken 说明是登录相关的接口,则自动设置登陆令牌
if ( if (response.config.url.indexOf('/member/auth/') >= 0 && response.data?.data?.accessToken) {
response.config.url.indexOf("/member/auth/") >= 0 && $store('user').setToken(response.data.data.accessToken, response.data.data.refreshToken)
response.data?.data?.accessToken
) {
$store("user").setToken(
response.data.data.accessToken,
response.data.data.refreshToken
);
} }
// 自定处理【loading 加载中】:如果需要显示 loading则关闭 loading // 自定处理【loading 加载中】:如果需要显示 loading则关闭 loading
response.config.custom.showLoading && closeLoading(); response.config.custom.showLoading && closeLoading()
// 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示 // 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示
if (response.data.code !== 0) { if (response.data.code !== 0) {
// 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌 // 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌
if (response.data.code === 401) { if (response.data.code === 401) {
return refreshToken(response.config); return refreshToken(response.config)
} }
// 错误提示 // 错误提示
if (response.config.custom.showError) { if (response.config.custom.showError) {
uni.showToast({ uni.showToast({
title: response.data.msg || "服务器开小差啦,请稍后再试~", title: response.data.msg || '服务器开小差啦,请稍后再试~',
icon: "none", icon: 'none',
mask: true, mask: true,
}); })
return Promise.reject(false); return Promise.reject(false)
} }
} }
// 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示 // 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示
if ( if (
response.config.custom.showSuccess && response.config.custom.showSuccess &&
response.config.custom.successMsg !== "" && response.config.custom.successMsg !== '' &&
response.data.code === 0 response.data.code === 0
) { ) {
uni.showToast({ uni.showToast({
title: response.config.custom.successMsg, title: response.config.custom.successMsg,
icon: "none", icon: 'none',
}); })
} }
// 返回结果:包括 code + data + msg // 返回结果:包括 code + data + msg
return Promise.resolve(response.data); return Promise.resolve(response.data)
}, },
(error) => { (error) => {
console.log("error", error); console.log('error', error)
const userStore = $store("user"); const userStore = $store('user')
const isLogin = userStore.isLogin; const isLogin = userStore.isLogin
let errorMessage = "网络请求出错"; let errorMessage = '网络请求出错'
if (error !== undefined) { if (error !== undefined) {
switch (error.statusCode) { switch (error.statusCode) {
case 400: case 400:
errorMessage = "请求错误"; errorMessage = '请求错误'
break; break
case 401: case 401:
errorMessage = isLogin ? "您的登陆已过期" : "请先登录"; errorMessage = isLogin ? '您的登陆已过期' : '请先登录'
// 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized // 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized
break; break
case 403: case 403:
errorMessage = "拒绝访问"; errorMessage = '拒绝访问'
break; break
case 404: case 404:
errorMessage = "请求出错"; errorMessage = '请求出错'
break; break
case 408: case 408:
errorMessage = "请求超时"; errorMessage = '请求超时'
break; break
case 429: case 429:
errorMessage = "请求频繁, 请稍后再访问"; errorMessage = '请求频繁, 请稍后再访问'
break; break
case 500: case 500:
errorMessage = "服务器开小差啦,请稍后再试~"; errorMessage = '服务器开小差啦,请稍后再试~'
break; break
case 501: case 501:
errorMessage = "服务未实现"; errorMessage = '服务未实现'
break; break
case 502: case 502:
errorMessage = "网络错误"; errorMessage = '网络错误'
break; break
case 503: case 503:
errorMessage = "服务不可用"; errorMessage = '服务不可用'
break; break
case 504: case 504:
errorMessage = "网络超时"; errorMessage = '网络超时'
break; break
case 505: case 505:
errorMessage = "HTTP 版本不受支持"; errorMessage = 'HTTP 版本不受支持'
break; break
} }
if (error.errMsg.includes("timeout")) errorMessage = "请求超时"; if (error.errMsg.includes('timeout')) errorMessage = '请求超时'
// #ifdef H5 // #ifdef H5
if (error.errMsg.includes("Network")) if (error.errMsg.includes('Network'))
errorMessage = window.navigator.onLine errorMessage = window.navigator.onLine ? '服务器异常' : '请检查您的网络连接'
? "服务器异常"
: "请检查您的网络连接";
// #endif // #endif
} }
@ -211,95 +204,95 @@ http.interceptors.response.use(
if (error.config.custom.showError === true) { if (error.config.custom.showError === true) {
uni.showToast({ uni.showToast({
title: error.data?.msg || errorMessage, title: error.data?.msg || errorMessage,
icon: "none", icon: 'none',
mask: true, mask: true,
}); })
} }
error.config.custom.showLoading && closeLoading(); error.config.custom.showLoading && closeLoading()
} }
return Promise.reject(false); return Promise.reject(false)
} }
); )
let requestList = []; // 请求队列 let requestList = [] // 请求队列
let isRefreshToken = false; // 是否正在刷新中 let isRefreshToken = false // 是否正在刷新中
const refreshToken = async (config) => { const refreshToken = async (config) => {
// 如果当前已经是 refresh-token 的 URL 地址,并且还是 401 错误,说明是刷新令牌失败了,直接返回 Promise.reject(error) // 如果当前已经是 refresh-token 的 URL 地址,并且还是 401 错误,说明是刷新令牌失败了,直接返回 Promise.reject(error)
if (config.url.indexOf("/member/auth/refresh-token") >= 0) { if (config.url.indexOf('/member/auth/refresh-token') >= 0) {
return Promise.reject("error"); return Promise.reject('error')
} }
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了 // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) { if (!isRefreshToken) {
isRefreshToken = true; isRefreshToken = true
// 1. 如果获取不到刷新令牌,则只能执行登出操作 // 1. 如果获取不到刷新令牌,则只能执行登出操作
const refreshToken = getRefreshToken(); const refreshToken = getRefreshToken()
if (!refreshToken) { if (!refreshToken) {
return handleAuthorized(); return handleAuthorized()
} }
// 2. 进行刷新访问令牌 // 2. 进行刷新访问令牌
try { try {
const refreshTokenResult = await AuthUtil.refreshToken(refreshToken); const refreshTokenResult = await AuthUtil.refreshToken(refreshToken)
if (refreshTokenResult.code !== 0) { if (refreshTokenResult.code !== 0) {
// 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑 // 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑
// noinspection ExceptionCaughtLocallyJS // noinspection ExceptionCaughtLocallyJS
throw new Error("刷新令牌失败"); throw new Error('刷新令牌失败')
} }
// 2.1 刷新成功,则回放队列的请求 + 当前请求 // 2.1 刷新成功,则回放队列的请求 + 当前请求
config.header.Authorization = "Bearer " + getAccessToken(); config.header.Authorization = 'Bearer ' + getAccessToken()
requestList.forEach((cb) => { requestList.forEach((cb) => {
cb(); cb()
}); })
requestList = []; requestList = []
return request(config); return request(config)
} catch (e) { } catch (e) {
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求 // 2.2 刷新失败,只回放队列的请求
requestList.forEach((cb) => { requestList.forEach((cb) => {
cb(); cb()
}); })
// 提示是否要登出。即不回放当前请求!不然会形成递归 // 提示是否要登出。即不回放当前请求!不然会形成递归
return handleAuthorized(); return handleAuthorized()
} finally { } finally {
requestList = []; requestList = []
isRefreshToken = false; isRefreshToken = false
} }
} else { } else {
// 添加到队列,等待刷新获取到新的令牌 // 添加到队列,等待刷新获取到新的令牌
return new Promise((resolve) => { return new Promise((resolve) => {
requestList.push(() => { requestList.push(() => {
config.header.Authorization = "Bearer " + getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修改 config.header.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(request(config)); resolve(request(config))
}); })
}); })
} }
}; }
/** 处理 401 未登陆的错误 */ /** 处理 401 未登陆的错误 */
const handleAuthorized = () => { const handleAuthorized = () => {
const userStore = $store("user"); const userStore = $store('user')
userStore.logout(true); userStore.logOut()
peach.$router.go("/pages/index/login"); peach.$router.go('/pages/index/login')
// 登录超时 // 登录超时
return Promise.reject({ return Promise.reject({
code: 401, code: 401,
msg: userStore.isLogin ? "您的登陆已过期" : "请先登录", msg: userStore.isLogin ? '您的登陆已过期' : '请先登录',
}); })
}; }
/** 获得访问令牌 */ /** 获得访问令牌 */
const getAccessToken = () => { const getAccessToken = () => {
return uni.getStorageSync("token"); return uni.getStorageSync('token')
}; }
/** 获得刷新令牌 */ /** 获得刷新令牌 */
const getRefreshToken = () => { const getRefreshToken = () => {
return uni.getStorageSync("refresh-token"); return uni.getStorageSync('refresh-token')
}; }
const request = (config) => { const request = (config) => {
return http.middleware(config); return http.middleware(config)
}; }
export default request; export default request

View File

@ -1,15 +1,7 @@
import $store from "@/peach/store"; import $store from '@/peach/store'
import { showShareModal } from "@/peach/hooks/useModal"; import { showShareModal } from '@/peach/hooks/useModal'
import { import { isNumber, isString, isEmpty, startsWith, isObject, isNil, clone } from 'lodash'
isNumber, import throttle from '@/peach/helper/throttle'
isString,
isEmpty,
startsWith,
isObject,
isNil,
clone,
} from "lodash";
import throttle from "@/peach/helper/throttle";
const _go = ( const _go = (
path, path,
@ -18,173 +10,173 @@ const _go = (
redirect: false, redirect: false,
} }
) => { ) => {
let page = ""; // 跳转页面 let page = '' // 跳转页面
let query = ""; // 页面参数 let query = '' // 页面参数
let url = ""; // 跳转页面完整路径 let url = '' // 跳转页面完整路径
if (isString(path)) { if (isString(path)) {
// 判断跳转类型是 path 还是http // 判断跳转类型是 path 还是http
if (startsWith(path, "http")) { if (startsWith(path, 'http')) {
// #ifdef H5 // #ifdef H5
window.location = path; window.location = path
return; return
// #endif // #endif
// #ifndef H5 // #ifndef H5
page = `/pages/public/webview`; page = `/pages/public/webview`
query = `url=${encodeURIComponent(path)}`; query = `url=${encodeURIComponent(path)}`
// #endif // #endif
} else if (startsWith(path, "action:")) { } else if (startsWith(path, 'action:')) {
handleAction(path); handleAction(path)
return; return
} else { } else {
[page, query] = path.split("?"); ;[page, query] = path.split('?')
} }
if (!isEmpty(params)) { if (!isEmpty(params)) {
let query2 = paramsToQuery(params); let query2 = paramsToQuery(params)
if (isEmpty(query)) { if (isEmpty(query)) {
query = query2; query = query2
} else { } else {
query += "&" + query2; query += '&' + query2
} }
} }
} }
if (isObject(path)) { if (isObject(path)) {
page = path.url; page = path.url
if (!isNil(path.params)) { if (!isNil(path.params)) {
query = paramsToQuery(path.params); query = paramsToQuery(path.params)
} }
} }
const nextRoute = ROUTES_MAP[page]; const nextRoute = ROUTES_MAP[page]
// 未找到指定跳转页面 // 未找到指定跳转页面
// mark: 跳转404页 // mark: 跳转404页
if (!nextRoute) { if (!nextRoute) {
console.log( console.log(`%c跳转路径参数错误<${page || 'EMPTY'}>`, 'color:red;background:yellow')
`%c跳转路径参数错误<${page || "EMPTY"}>`, return
"color:red;background:yellow"
);
return;
} }
// 页面登录拦截 // 页面登录拦截
if (nextRoute.meta?.auth && !$store("user").isLogin) { if (nextRoute.meta?.auth && !$store('user').isLogin) {
uni.redirectTo({ uni.redirectTo({
url: "/pages/index/login", url: '/pages/index/login',
}); })
return; return
} }
url = page; url = page
if (!isEmpty(query)) { if (!isEmpty(query)) {
url += `?${query}`; url += `?${query}`
} }
// 保存最新的页面地址
$store('user').lastRoutePage = url
// 跳转底部导航 // 跳转底部导航
if (TABBAR.includes(page)) { if (TABBAR.includes(page)) {
uni.switchTab({ uni.switchTab({
url, url,
}); })
return; return
} }
// 使用redirect跳转 // 使用redirect跳转
if (options.redirect) { if (options.redirect) {
uni.redirectTo({ uni.redirectTo({
url, url,
}); })
return; return
} }
uni.navigateTo({ uni.navigateTo({
url, url,
}); })
}; }
// 限流 防止重复点击跳转 // 限流 防止重复点击跳转
function go(...args) { function go(...args) {
throttle(() => { throttle(() => {
_go(...args); _go(...args)
}); })
} }
function paramsToQuery(params) { function paramsToQuery(params) {
if (isEmpty(params)) { if (isEmpty(params)) {
return ""; return ''
} }
// return new URLSearchParams(Object.entries(params)).toString(); // return new URLSearchParams(Object.entries(params)).toString();
let query = []; let query = []
for (let key in params) { for (let key in params) {
query.push(key + "=" + params[key]); query.push(key + '=' + params[key])
} }
return query.join("&"); return query.join('&')
} }
function back() { function back() {
// #ifdef H5 // #ifdef H5
history.back(); history.back()
// #endif // #endif
// #ifndef H5 // #ifndef H5
uni.navigateBack(); uni.navigateBack()
// #endif // #endif
} }
function redirect(path, params = {}) { function redirect(path, params = {}) {
go(path, params, { go(path, params, {
redirect: true, redirect: true,
}); })
} }
// 检测是否有浏览器历史 // 检测是否有浏览器历史
function hasHistory() { function hasHistory() {
// #ifndef H5 // #ifndef H5
const pages = getCurrentPages(); const pages = getCurrentPages()
if (pages.length > 1) { if (pages.length > 1) {
return true; return true
} }
return false; return false
// #endif // #endif
// #ifdef H5 // #ifdef H5
return !!history.back; return !!history.back
// #endif // #endif
} }
function getCurrentRoute(field = "") { function getCurrentRoute(field = '') {
let currentPage = getCurrentPage(); let currentPage = getCurrentPage()
// #ifdef MP // #ifdef MP
currentPage.$page["route"] = currentPage.route; currentPage.$page['route'] = currentPage.route
currentPage.$page["options"] = currentPage.options; currentPage.$page['options'] = currentPage.options
// #endif // #endif
if (field !== "") { if (field !== '') {
return currentPage.$page[field]; return currentPage.$page[field]
} else { } else {
return currentPage.$page; return currentPage.$page
} }
} }
function getCurrentPage() { function getCurrentPage() {
let pages = getCurrentPages(); let pages = getCurrentPages()
return pages[pages.length - 1]; return pages[pages.length - 1]
} }
function handleAction(path) { function handleAction(path) {
const action = path.split(":"); const action = path.split(':')
switch (action[1]) { switch (action[1]) {
case "showShareModal": case 'showShareModal':
showShareModal(); showShareModal()
break; break
} }
} }
function error(errCode, errMsg = "") { function error(errCode, errMsg = '') {
redirect("/pages/public/error", { redirect('/pages/public/error', {
errCode, errCode,
errMsg, errMsg,
}); })
} }
export default { export default {
@ -195,4 +187,4 @@ export default {
getCurrentPage, getCurrentPage,
getCurrentRoute, getCurrentRoute,
error, error,
}; }

View File

@ -1,12 +1,11 @@
import { ref } from "vue"; import { ref } from 'vue'
import { defineStore } from "pinia"; import { defineStore } from 'pinia'
import $platform from "@/peach/platform"; import $platform from '@/peach/platform'
import $router from "@/peach/router"; import $router from '@/peach/router'
import useUserStore from "./user"; import useSysStore from './sys'
import useSysStore from "./sys";
const useAppStore = defineStore( const useAppStore = defineStore(
"app", 'app',
() => { () => {
/** /**
* @description 应用信息 * @description 应用信息
@ -19,14 +18,14 @@ const useAppStore = defineStore(
* @param string filesystem 文件系统 * @param string filesystem 文件系统
*/ */
const info = ref({ const info = ref({
name: "", name: '',
logo: "", logo: '',
version: "", version: '',
copyright: "", copyright: '',
copytime: "", copytime: '',
cdnurl: "", cdnurl: '',
filesystem: "", filesystem: '',
}); })
/** /**
* @description 平台信息 * @description 平台信息
@ -41,12 +40,12 @@ const useAppStore = defineStore(
methods: [], methods: [],
forwardInfo: {}, forwardInfo: {},
posterInfo: {}, posterInfo: {},
linkAddress: "", linkAddress: '',
}, },
bindMobile: 0, bindMobile: 0,
}); })
const chat = ref({}); const chat = ref({})
/** /**
* @description 模板信息 * @description 模板信息
@ -58,50 +57,46 @@ const useAppStore = defineStore(
tabbar: { tabbar: {
items: [ items: [
{ {
activeIconUrl: activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-002.png',
"http://mall.yudao.iocoder.cn/static/images/1-002.png", iconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-001.png',
iconUrl: "http://mall.yudao.iocoder.cn/static/images/1-001.png", text: '首页',
text: "首页", url: '/pages/index/index',
url: "/pages/index/index",
}, },
{ {
activeIconUrl: activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-002.png',
"http://mall.yudao.iocoder.cn/static/images/2-002.png", iconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-001.png',
iconUrl: "http://mall.yudao.iocoder.cn/static/images/2-001.png", text: '产品',
text: "产品", url: '/pages/index/product',
url: "/pages/index/product",
}, },
{ {
activeIconUrl: activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-002.png',
"http://mall.yudao.iocoder.cn/static/images/3-002.png", iconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-001.png',
iconUrl: "http://mall.yudao.iocoder.cn/static/images/3-001.png", text: '订单',
text: "订单", url: '/pages/order/list',
url: "/pages/order/list",
}, },
{ {
activeIconUrl: activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-002.png',
"http://mall.yudao.iocoder.cn/static/images/4-002.png", iconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-001.png',
iconUrl: "http://mall.yudao.iocoder.cn/static/images/4-001.png", text: '我的',
text: "我的", url: '/pages/index/my',
url: "/pages/index/my",
}, },
], ],
style: { style: {
activeColor: "#fc4141", activeColor: '#fc4141',
bgColor: "#fff", bgColor: '#fff',
bgType: "color", bgType: 'color',
color: "#282828", color: '#282828',
}, },
theme: "red", theme: 'red',
}, },
}, },
}); })
// 全局分享信息 // 全局分享信息
const shareInfo = ref({}); const shareInfo = ref({})
// 小程序发货信息管理 0: 没有 1 // 小程序发货信息管理 0: 没有 1
const hasWechatTradeManaged = ref(0); const hasWechatTradeManaged = ref(0)
/** /**
* @author Ankkaya * @author Ankkaya
@ -111,52 +106,47 @@ const useAppStore = defineStore(
*/ */
async function init() { async function init() {
// 检查网络 // 检查网络
const networkStatus = await $platform.checkNetwork(); const networkStatus = await $platform.checkNetwork()
if (!networkStatus) { if (!networkStatus) {
$router.error("NetworkError"); $router.error('NetworkError')
} }
if (true) { if (true) {
this.info = { this.info = {
name: "🍑商城", name: '🍑商城',
logo: "https://static.iocoder.cn/ruoyi-vue-pro-logo.png", logo: 'https://static.iocoder.cn/ruoyi-vue-pro-logo.png',
version: "1.0.0", version: '1.0.0',
copyright: "全部开源,个人与企业可 100% 免费使用", copyright: '全部开源,个人与企业可 100% 免费使用',
copytime: "Copyright© 2018-2024", copytime: 'Copyright© 2018-2024',
cdnurl: "https://file.sheepjs.com", // 云存储域名 cdnurl: 'https://file.sheepjs.com', // 云存储域名
filesystem: "qcloud", // 云存储平台 filesystem: 'qcloud', // 云存储平台
}; }
this.platform = { this.platform = {
share: { share: {
methods: ["poster", "link"], methods: ['poster', 'link'],
linkAddress: "https://shopro.sheepjs.com/#/", linkAddress: 'https://shopro.sheepjs.com/#/',
posterInfo: { posterInfo: {
user_bg: "/static/img/shop/config/user-poster-bg.png", user_bg: '/static/img/shop/config/user-poster-bg.png',
goods_bg: "/static/img/shop/config/goods-poster-bg.png", goods_bg: '/static/img/shop/config/goods-poster-bg.png',
groupon_bg: "/static/img/shop/config/groupon-poster-bg.png", groupon_bg: '/static/img/shop/config/groupon-poster-bg.png',
}, },
}, },
bind_mobile: 0, bind_mobile: 0,
}; }
this.chat = { this.chat = {
chat_domain: "https://api.shopro.sheepjs.com/chat", chat_domain: 'https://api.shopro.sheepjs.com/chat',
room_id: "admin", room_id: 'admin',
}; }
this.has_wechat_trade_managed = 0; this.has_wechat_trade_managed = 0
// 加载主题 // 加载主题
const sysStore = useSysStore(); const sysStore = useSysStore()
sysStore.setTheme(); sysStore.setTheme()
// 模拟用户登录 return Promise.resolve(true)
const userStore = useUserStore();
if (userStore.isLogin) {
userStore.loginAfter();
}
return Promise.resolve(true);
} else { } else {
$router.error("InitError", res.msg || "加载失败"); $router.error('InitError', res.msg || '加载失败')
} }
} }
@ -168,18 +158,18 @@ const useAppStore = defineStore(
shareInfo, shareInfo,
hasWechatTradeManaged, hasWechatTradeManaged,
init, init,
}; }
}, },
{ {
persist: { persist: {
enabled: true, enabled: true,
strategies: [ strategies: [
{ {
key: "app-store", key: 'app-store',
}, },
], ],
}, },
} }
); )
export default useAppStore; export default useAppStore

View File

@ -10,7 +10,6 @@ const useSysStore = defineStore(
const fontSize = ref(1) const fontSize = ref(1)
function setTheme(stheme = '') { function setTheme(stheme = '') {
console.log('setTheme', stheme)
theme.value = stheme ? stheme : 'orange' theme.value = stheme ? stheme : 'orange'
} }

View File

@ -1,21 +1,25 @@
import { ref } from "vue"; import { ref } from 'vue'
import { defineStore } from "pinia"; import { defineStore } from 'pinia'
import $share from "@/peach/platform/share"; import $share from '@/peach/platform/share'
import { isEmpty, cloneDeep, clone } from "lodash"; import $router from '@/peach/router'
import UserUtil from '@/peach/api/member/user'
import { isEmpty, cloneDeep, clone } from 'lodash'
// 默认用户信息 // 默认用户信息
const defaultUserInfo = { const defaultUserInfo = {
avatar: "", // 头像 avatar: '', // 头像
nickname: "", // 昵称 nickname: '', // 昵称
gender: 0, // 性别 mobile: '', // 手机号
mobile: "", // 手机号
point: 0, // 积分 point: 0, // 积分
}; particulars: null,
}
// 默认钱包信息 // 默认钱包信息
const defaultWallet = { const defaultWallet = {
balance: 0, // 余额 balance: 0, // 余额
}; totalExpense: 0, // 总消费
totalRecharge: 0, // 总充值
}
// 默认订单信息 // 默认订单信息
const defaultNumData = { const defaultNumData = {
@ -28,83 +32,93 @@ const defaultNumData = {
uncommentedCount: 0, uncommentedCount: 0,
afterSaleCount: 0, afterSaleCount: 0,
}, },
}; }
const useUserStore = defineStore( const useUserStore = defineStore(
"user", 'user',
() => { () => {
const userInfo = ref(clone(defaultUserInfo)); const userInfo = ref(cloneDeep(defaultUserInfo))
const userWallet = ref(clone(defaultWallet)); const userWallet = ref(clone(defaultWallet))
const userNumData = ref(cloneDeep(defaultNumData)); const userNumData = ref(cloneDeep(defaultNumData))
const isLogin = ref(!!uni.getStorageSync("token")); const isLogin = ref(!!uni.getStorageSync('token'))
const lastUpdateTime = ref(0); const lastUpdateTime = ref(0)
const lastRoutePage = ref(null)
function getUserInfo() {} async function getUserInfo() {
let res = await UserUtil.getUserInfo()
userInfo.value = res.data
}
function getWallet() {} async function getWallet() {
let res = await UserUtil.getWalletInfo()
userWallet.value = res.data
}
function getNumData() {} function getNumData() {}
function setToken(token, refreshToken) { function setToken(token, refreshToken) {
if (token === "") { if (token === '') {
isLogin.value = false; isLogin.value = false
uni.removeStorageSync("token"); uni.removeStorageSync('token')
uni.removeStorageSync("refresh-token"); uni.removeStorageSync('refresh-token')
} else { } else {
isLogin.value = true; isLogin.value = true
uni.setStorageSync("token", token); uni.setStorageSync('token', token)
uni.setStorageSync("refresh-token", refreshToken); uni.setStorageSync('refresh-token', refreshToken)
// 成功后处理 // 成功后处理
loginAfter(); loginAfter()
} }
return isLogin.value; return isLogin.value
} }
function resetUserData() { function resetUserData() {
setToken(""); setToken('')
userInfo.value = clone(defaultUserInfo); userInfo.value = cloneDeep(defaultUserInfo)
userWallet.value = clone(defaultWallet); userWallet.value = clone(defaultWallet)
userNumData.value = cloneDeep(defaultNumData); userNumData.value = cloneDeep(defaultNumData)
} }
async function updateUserData() { async function updateUserData() {
const nowTime = new Date().getTime(); const nowTime = new Date().getTime()
if (lastUpdateTime.value + 5000 > nowTime) { if (lastUpdateTime.value + 5000 > nowTime) {
return; return
} }
lastUpdateTime.value = nowTime; lastUpdateTime.value = nowTime
await Promise.all([getUserInfo(), getWallet(), getNumData()])
await getUserInfo(); return userInfo.value
getWallet();
getNumData();
return userInfo.value;
} }
function loginAfter() { async function loginAfter() {
updateUserData(); await updateUserData()
$share.getShareInfo(); $share.getShareInfo()
$router.go('/pages/index/index')
} }
function logOut() { function logOut() {
resetUserData(); resetUserData()
return !isLogin.value; return !isLogin.value
} }
return { return {
userInfo, userInfo,
userWallet,
isLogin, isLogin,
setToken, setToken,
logOut, logOut,
}; loginAfter,
lastRoutePage,
}
}, },
{ {
persist: true, persist: {
enabled: true,
strategies: [ strategies: [
{ {
key: "user-store", key: 'user-store',
}, },
], ],
},
} }
); )
export default useUserStore; export default useUserStore

View File

@ -31,6 +31,7 @@
</template> </template>
<script setup> <script setup>
import { onLoad } from '@dcloudio/uni-app'
import { computed, unref } from 'vue' import { computed, unref } from 'vue'
import PbSTabbar from './pb-s-tabbar.vue' import PbSTabbar from './pb-s-tabbar.vue'
import peach from '@/peach' import peach from '@/peach'
@ -59,6 +60,12 @@ const props = defineProps({
path: String, path: String,
default: '', default: '',
}) })
onLoad(() => {
// 使
// app.vue tabbar
uni.hideTabBar()
})
</script> </script>
<style lang="scss"> <style lang="scss">

BIN
static/default_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB