feat(登录)
This commit is contained in:
parent
c611e44858
commit
c65eb5ddcd
2
.env
2
.env
|
@ -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
|
||||||
|
|
2
App.vue
2
App.vue
|
@ -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()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
26
pages.json
26
pages.json
|
@ -8,6 +8,9 @@
|
||||||
},
|
},
|
||||||
"pages": [
|
"pages": [
|
||||||
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
|
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
|
||||||
|
{
|
||||||
|
"path": "pages/index/redirect"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/order/list",
|
"path": "pages/order/list",
|
||||||
"style": {
|
"style": {
|
||||||
|
@ -64,18 +67,17 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"subPackages": [
|
"subPackages": [
|
||||||
{
|
{
|
||||||
"root": "pages/public",
|
"root": "pages/public",
|
||||||
"pages": [
|
"pages": [
|
||||||
|
{
|
||||||
{
|
"path": "error",
|
||||||
"path": "error",
|
"style": {
|
||||||
"style": {
|
"navigationBarTitleText": "错误页面"
|
||||||
"navigationBarTitleText": "错误页面"
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
]
|
}
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
"list": [
|
"list": [
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -1,181 +1,194 @@
|
||||||
<template>
|
<template>
|
||||||
<pb-layout :leftIcon="''" navbar="inner" :bgStyle="{ backgroundColor: '#fff' }">
|
<pb-layout :leftIcon="''" navbar="inner" :bgStyle="{ backgroundColor: '#fff' }">
|
||||||
<view class="login-module ss-p-x-30">
|
<view class="login-module ss-p-x-30">
|
||||||
<view class="login-title ss-font-56 ss-m-b-72">
|
<view class="login-title ss-font-56 ss-m-b-72">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</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"
|
||||||
</uni-forms-item>
|
trim="all"
|
||||||
<uni-forms-item name="code">
|
placeholder="请输入手机号"
|
||||||
<uni-easyinput :styles="state.inputStyle" trim="all" placeholder="验证码" v-model="state.model.code"
|
v-model="state.model.mobile"
|
||||||
:inputBorder="false" type="number" maxlength="4">
|
:inputBorder="false"
|
||||||
<template #right>
|
type="number"
|
||||||
<button :disabled="state.isMobileEnd" :class="{ 'code-btn-end': state.isMobileEnd }"
|
/>
|
||||||
class="ss-reset-button code-btn code-btn-start" @tap="getSmsCode('smsLogin', state.model.mobile)">
|
</uni-forms-item>
|
||||||
{{ getSmsTimer('smsLogin') }}
|
<uni-forms-item name="code">
|
||||||
</button>
|
<uni-easyinput
|
||||||
</template>
|
:styles="state.inputStyle"
|
||||||
</uni-easyinput>
|
trim="all"
|
||||||
</uni-forms-item>
|
placeholder="验证码"
|
||||||
</uni-forms>
|
v-model="state.model.code"
|
||||||
<button class="ss-reset-button login-btn-start" @tap="smsLoginSubmit">登录</button>
|
:inputBorder="false"
|
||||||
<view class="agreement-box ss-flex ss-row-center" :class="{ shake: state.isShaking }">
|
type="number"
|
||||||
<label class="radio ss-flex" @tap="onChange">
|
maxlength="4"
|
||||||
<radio :checked="state.agreeStatus" color="var(--ui-BG-Main)" style="transform: scale(0.8)"
|
>
|
||||||
@tap.stop="onChange" />
|
<template #right>
|
||||||
<view class="agreement-text ss-flex ss-m-l-8">
|
<button
|
||||||
我已阅读并遵守
|
:disabled="state.isMobileEnd"
|
||||||
<view class="tcp-text" @tap.stop="onProtocol('商家入驻协议')"> 《商家入驻协议》 </view>
|
:class="{ 'code-btn-end': state.isMobileEnd }"
|
||||||
</view>
|
class="ss-reset-button code-btn code-btn-start"
|
||||||
</label>
|
@tap="getSmsCode('smsLogin', state.model.mobile)"
|
||||||
</view>
|
>
|
||||||
</view>
|
{{ getSmsTimer('smsLogin') }}
|
||||||
</pb-layout>
|
</button>
|
||||||
|
</template>
|
||||||
|
</uni-easyinput>
|
||||||
|
</uni-forms-item>
|
||||||
|
</uni-forms>
|
||||||
|
<button class="ss-reset-button login-btn-start" @tap="smsLoginSubmit">登录</button>
|
||||||
|
<view class="agreement-box ss-flex ss-row-center" :class="{ shake: state.isShaking }">
|
||||||
|
<label class="radio ss-flex" @tap="onChange">
|
||||||
|
<radio
|
||||||
|
: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="tcp-text" @tap.stop="onProtocol('商家入驻协议')"> 《商家入驻协议》 </view>
|
||||||
|
</view>
|
||||||
|
</label>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</pb-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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)
|
||||||
|
|
||||||
const state = ref({
|
const state = ref({
|
||||||
isMobileEnd: false,
|
isMobileEnd: false,
|
||||||
agreeStatus: false,
|
agreeStatus: false,
|
||||||
isShaking: false,
|
isShaking: false,
|
||||||
model: {
|
model: {
|
||||||
mobile: '15036370128',
|
mobile: '15036370128',
|
||||||
code: '9999',
|
code: '9999',
|
||||||
},
|
},
|
||||||
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
|
||||||
if (!state.value.agreeStatus) {
|
if (!state.value.agreeStatus) {
|
||||||
state.value.isShaking = true
|
state.value.isShaking = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
state.value.isShaking = false
|
state.value.isShaking = false
|
||||||
}, 1000)
|
}, 1000)
|
||||||
peach.$helper.toast('请勾选同意')
|
peach.$helper.toast('请勾选同意')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const { code } = await AuthUtil.smsLogin(state.value.model)
|
|
||||||
if (code === 0) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const { code } = await AuthUtil.smsLogin(state.value.model)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.login-module {
|
.login-module {
|
||||||
|
.uni-easyinput {
|
||||||
.uni-easyinput {
|
::v-deep .uni-easyinput__content {
|
||||||
|
border-radius: 41rpx;
|
||||||
::v-deep .uni-easyinput__content {
|
padding: 0 10rpx;
|
||||||
border-radius: 41rpx;
|
}
|
||||||
padding: 0 10rpx;
|
|
||||||
}
|
.is-focused {
|
||||||
|
::v-deep .content-clear-icon {
|
||||||
.is-focused {
|
.uniui-clear {
|
||||||
::v-deep .content-clear-icon {
|
color: red !important;
|
||||||
.uniui-clear {
|
}
|
||||||
color: red !important
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.login-module {
|
.login-module {
|
||||||
margin-top: 50%;
|
margin-top: 50%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.login-title {
|
.login-title {
|
||||||
color: '#1818d';
|
color: '#1818d';
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
|
||||||
|
|
||||||
.login-btn-start {
|
|
||||||
height: 82rpx;
|
|
||||||
line-height: normal;
|
|
||||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
|
||||||
border-radius: 28rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code-btn-start {
|
|
||||||
width: 160rpx;
|
|
||||||
height: 56rpx;
|
|
||||||
line-height: normal;
|
|
||||||
border-radius: 28rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
font-weight: 400;
|
|
||||||
color: var(--ui-BG-Main);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agreement-box {
|
|
||||||
margin: -10px auto 10px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 30rpx;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.protocol-check {
|
|
||||||
transform: scale(0.7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.agreement-text {
|
.login-btn-start {
|
||||||
font-size: 26rpx;
|
height: 82rpx;
|
||||||
font-weight: 500;
|
line-height: normal;
|
||||||
color: #999999;
|
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||||
|
border-radius: 28rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.tcp-text {
|
.code-btn-start {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
line-height: normal;
|
||||||
|
border-radius: 28rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 400;
|
||||||
color: var(--ui-BG-Main);
|
color: var(--ui-BG-Main);
|
||||||
}
|
opacity: 1;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.shake {
|
|
||||||
animation: shake 0.05s linear 4 alternate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shake {
|
|
||||||
from {
|
|
||||||
transform: translateX(-5rpx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
.agreement-box {
|
||||||
transform: translateX(5rpx);
|
margin: -10px auto 10px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30rpx;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.protocol-check {
|
||||||
|
transform: scale(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #999999;
|
||||||
|
|
||||||
|
.tcp-text {
|
||||||
|
color: var(--ui-BG-Main);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shake {
|
||||||
|
animation: shake 0.05s linear 4 alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
from {
|
||||||
|
transform: translateX(-5rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateX(5rpx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
|
@ -1,48 +1,49 @@
|
||||||
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) => {
|
// 发送手机验证码
|
||||||
return request({
|
sendSmsCode: (mobile, scene) => {
|
||||||
url: "/member/auth/send-sms-code",
|
return request({
|
||||||
method: "POST",
|
url: '/member/auth/send-sms-code',
|
||||||
data: {
|
method: 'POST',
|
||||||
mobile,
|
data: {
|
||||||
scene,
|
mobile,
|
||||||
},
|
scene,
|
||||||
custom: {
|
},
|
||||||
loadingMsg: "发送中",
|
custom: {
|
||||||
showSuccess: true,
|
loadingMsg: '发送中',
|
||||||
successMsg: "发送成功",
|
showSuccess: true,
|
||||||
},
|
successMsg: '发送成功',
|
||||||
});
|
},
|
||||||
},
|
})
|
||||||
// 刷新令牌
|
},
|
||||||
refreshToken: (refreshToken) => {
|
// 刷新令牌
|
||||||
return request({
|
refreshToken: (refreshToken) => {
|
||||||
url: "/member/auth/refresh-token",
|
return request({
|
||||||
method: "POST",
|
url: '/member/auth/refresh-token',
|
||||||
params: {
|
method: 'POST',
|
||||||
refreshToken,
|
params: {
|
||||||
},
|
refreshToken,
|
||||||
custom: {
|
},
|
||||||
loading: false, // 不用加载中
|
custom: {
|
||||||
showError: false, // 不展示错误提示
|
loading: false, // 不用加载中
|
||||||
},
|
showError: false, // 不展示错误提示
|
||||||
});
|
},
|
||||||
},
|
})
|
||||||
};
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default AuthUtil;
|
export default AuthUtil
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
@ -63,39 +63,40 @@ 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['tenant-id'] = '1'
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
config.header["Accept"] = "*/*";
|
)
|
||||||
return config;
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ankkaya
|
* @author Ankkaya
|
||||||
|
@ -104,202 +105,194 @@ http.interceptors.request.use(
|
||||||
* @returns {Type}
|
* @returns {Type}
|
||||||
*/
|
*/
|
||||||
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(
|
// 自定处理【loading 加载中】:如果需要显示 loading,则关闭 loading
|
||||||
response.data.data.accessToken,
|
response.config.custom.showLoading && closeLoading()
|
||||||
response.data.data.refreshToken
|
|
||||||
);
|
// 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示
|
||||||
|
if (response.data.code !== 0) {
|
||||||
|
// 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌
|
||||||
|
if (response.data.code === 401) {
|
||||||
|
return refreshToken(response.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误提示
|
||||||
|
if (response.config.custom.showError) {
|
||||||
|
uni.showToast({
|
||||||
|
title: response.data.msg || '服务器开小差啦,请稍后再试~',
|
||||||
|
icon: 'none',
|
||||||
|
mask: true,
|
||||||
|
})
|
||||||
|
return Promise.reject(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示
|
||||||
|
if (
|
||||||
|
response.config.custom.showSuccess &&
|
||||||
|
response.config.custom.successMsg !== '' &&
|
||||||
|
response.data.code === 0
|
||||||
|
) {
|
||||||
|
uni.showToast({
|
||||||
|
title: response.config.custom.successMsg,
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回结果:包括 code + data + msg
|
||||||
|
return Promise.resolve(response.data)
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.log('error', error)
|
||||||
|
const userStore = $store('user')
|
||||||
|
const isLogin = userStore.isLogin
|
||||||
|
let errorMessage = '网络请求出错'
|
||||||
|
if (error !== undefined) {
|
||||||
|
switch (error.statusCode) {
|
||||||
|
case 400:
|
||||||
|
errorMessage = '请求错误'
|
||||||
|
break
|
||||||
|
case 401:
|
||||||
|
errorMessage = isLogin ? '您的登陆已过期' : '请先登录'
|
||||||
|
// 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized
|
||||||
|
break
|
||||||
|
case 403:
|
||||||
|
errorMessage = '拒绝访问'
|
||||||
|
break
|
||||||
|
case 404:
|
||||||
|
errorMessage = '请求出错'
|
||||||
|
break
|
||||||
|
case 408:
|
||||||
|
errorMessage = '请求超时'
|
||||||
|
break
|
||||||
|
case 429:
|
||||||
|
errorMessage = '请求频繁, 请稍后再访问'
|
||||||
|
break
|
||||||
|
case 500:
|
||||||
|
errorMessage = '服务器开小差啦,请稍后再试~'
|
||||||
|
break
|
||||||
|
case 501:
|
||||||
|
errorMessage = '服务未实现'
|
||||||
|
break
|
||||||
|
case 502:
|
||||||
|
errorMessage = '网络错误'
|
||||||
|
break
|
||||||
|
case 503:
|
||||||
|
errorMessage = '服务不可用'
|
||||||
|
break
|
||||||
|
case 504:
|
||||||
|
errorMessage = '网络超时'
|
||||||
|
break
|
||||||
|
case 505:
|
||||||
|
errorMessage = 'HTTP 版本不受支持'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (error.errMsg.includes('timeout')) errorMessage = '请求超时'
|
||||||
|
// #ifdef H5
|
||||||
|
if (error.errMsg.includes('Network'))
|
||||||
|
errorMessage = window.navigator.onLine ? '服务器异常' : '请检查您的网络连接'
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error && error.config) {
|
||||||
|
if (error.config.custom.showError === true) {
|
||||||
|
uni.showToast({
|
||||||
|
title: error.data?.msg || errorMessage,
|
||||||
|
icon: 'none',
|
||||||
|
mask: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
error.config.custom.showLoading && closeLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(false)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// 自定处理【loading 加载中】:如果需要显示 loading,则关闭 loading
|
let requestList = [] // 请求队列
|
||||||
response.config.custom.showLoading && closeLoading();
|
let isRefreshToken = false // 是否正在刷新中
|
||||||
|
|
||||||
// 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示
|
|
||||||
if (response.data.code !== 0) {
|
|
||||||
// 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌
|
|
||||||
if (response.data.code === 401) {
|
|
||||||
return refreshToken(response.config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 错误提示
|
|
||||||
if (response.config.custom.showError) {
|
|
||||||
uni.showToast({
|
|
||||||
title: response.data.msg || "服务器开小差啦,请稍后再试~",
|
|
||||||
icon: "none",
|
|
||||||
mask: true,
|
|
||||||
});
|
|
||||||
return Promise.reject(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示
|
|
||||||
if (
|
|
||||||
response.config.custom.showSuccess &&
|
|
||||||
response.config.custom.successMsg !== "" &&
|
|
||||||
response.data.code === 0
|
|
||||||
) {
|
|
||||||
uni.showToast({
|
|
||||||
title: response.config.custom.successMsg,
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回结果:包括 code + data + msg
|
|
||||||
return Promise.resolve(response.data);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.log("error", error);
|
|
||||||
const userStore = $store("user");
|
|
||||||
const isLogin = userStore.isLogin;
|
|
||||||
let errorMessage = "网络请求出错";
|
|
||||||
if (error !== undefined) {
|
|
||||||
switch (error.statusCode) {
|
|
||||||
case 400:
|
|
||||||
errorMessage = "请求错误";
|
|
||||||
break;
|
|
||||||
case 401:
|
|
||||||
errorMessage = isLogin ? "您的登陆已过期" : "请先登录";
|
|
||||||
// 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized
|
|
||||||
break;
|
|
||||||
case 403:
|
|
||||||
errorMessage = "拒绝访问";
|
|
||||||
break;
|
|
||||||
case 404:
|
|
||||||
errorMessage = "请求出错";
|
|
||||||
break;
|
|
||||||
case 408:
|
|
||||||
errorMessage = "请求超时";
|
|
||||||
break;
|
|
||||||
case 429:
|
|
||||||
errorMessage = "请求频繁, 请稍后再访问";
|
|
||||||
break;
|
|
||||||
case 500:
|
|
||||||
errorMessage = "服务器开小差啦,请稍后再试~";
|
|
||||||
break;
|
|
||||||
case 501:
|
|
||||||
errorMessage = "服务未实现";
|
|
||||||
break;
|
|
||||||
case 502:
|
|
||||||
errorMessage = "网络错误";
|
|
||||||
break;
|
|
||||||
case 503:
|
|
||||||
errorMessage = "服务不可用";
|
|
||||||
break;
|
|
||||||
case 504:
|
|
||||||
errorMessage = "网络超时";
|
|
||||||
break;
|
|
||||||
case 505:
|
|
||||||
errorMessage = "HTTP 版本不受支持";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (error.errMsg.includes("timeout")) errorMessage = "请求超时";
|
|
||||||
// #ifdef H5
|
|
||||||
if (error.errMsg.includes("Network"))
|
|
||||||
errorMessage = window.navigator.onLine
|
|
||||||
? "服务器异常"
|
|
||||||
: "请检查您的网络连接";
|
|
||||||
// #endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error && error.config) {
|
|
||||||
if (error.config.custom.showError === true) {
|
|
||||||
uni.showToast({
|
|
||||||
title: error.data?.msg || errorMessage,
|
|
||||||
icon: "none",
|
|
||||||
mask: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
error.config.custom.showLoading && closeLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject(false);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let requestList = []; // 请求队列
|
|
||||||
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. 进行刷新访问令牌
|
||||||
|
try {
|
||||||
|
const refreshTokenResult = await AuthUtil.refreshToken(refreshToken)
|
||||||
|
if (refreshTokenResult.code !== 0) {
|
||||||
|
// 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error('刷新令牌失败')
|
||||||
|
}
|
||||||
|
// 2.1 刷新成功,则回放队列的请求 + 当前请求
|
||||||
|
config.header.Authorization = 'Bearer ' + getAccessToken()
|
||||||
|
requestList.forEach((cb) => {
|
||||||
|
cb()
|
||||||
|
})
|
||||||
|
requestList = []
|
||||||
|
return request(config)
|
||||||
|
} catch (e) {
|
||||||
|
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
|
||||||
|
// 2.2 刷新失败,只回放队列的请求
|
||||||
|
requestList.forEach((cb) => {
|
||||||
|
cb()
|
||||||
|
})
|
||||||
|
// 提示是否要登出。即不回放当前请求!不然会形成递归
|
||||||
|
return handleAuthorized()
|
||||||
|
} finally {
|
||||||
|
requestList = []
|
||||||
|
isRefreshToken = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 添加到队列,等待刷新获取到新的令牌
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
requestList.push(() => {
|
||||||
|
config.header.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||||
|
resolve(request(config))
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// 2. 进行刷新访问令牌
|
}
|
||||||
try {
|
|
||||||
const refreshTokenResult = await AuthUtil.refreshToken(refreshToken);
|
|
||||||
if (refreshTokenResult.code !== 0) {
|
|
||||||
// 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑
|
|
||||||
// noinspection ExceptionCaughtLocallyJS
|
|
||||||
throw new Error("刷新令牌失败");
|
|
||||||
}
|
|
||||||
// 2.1 刷新成功,则回放队列的请求 + 当前请求
|
|
||||||
config.header.Authorization = "Bearer " + getAccessToken();
|
|
||||||
requestList.forEach((cb) => {
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
requestList = [];
|
|
||||||
return request(config);
|
|
||||||
} catch (e) {
|
|
||||||
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
|
|
||||||
// 2.2 刷新失败,只回放队列的请求
|
|
||||||
requestList.forEach((cb) => {
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
// 提示是否要登出。即不回放当前请求!不然会形成递归
|
|
||||||
return handleAuthorized();
|
|
||||||
} finally {
|
|
||||||
requestList = [];
|
|
||||||
isRefreshToken = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 添加到队列,等待刷新获取到新的令牌
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
requestList.push(() => {
|
|
||||||
config.header.Authorization = "Bearer " + getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
|
|
||||||
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
|
||||||
|
|
|
@ -1,198 +1,190 @@
|
||||||
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,
|
||||||
params = {},
|
params = {},
|
||||||
options = {
|
options = {
|
||||||
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)) {
|
||||||
|
let query2 = paramsToQuery(params)
|
||||||
|
if (isEmpty(query)) {
|
||||||
|
query = query2
|
||||||
|
} else {
|
||||||
|
query += '&' + query2
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!isEmpty(params)) {
|
|
||||||
let query2 = paramsToQuery(params);
|
if (isObject(path)) {
|
||||||
if (isEmpty(query)) {
|
page = path.url
|
||||||
query = query2;
|
if (!isNil(path.params)) {
|
||||||
} else {
|
query = paramsToQuery(path.params)
|
||||||
query += "&" + query2;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (isObject(path)) {
|
const nextRoute = ROUTES_MAP[page]
|
||||||
page = path.url;
|
|
||||||
if (!isNil(path.params)) {
|
// 未找到指定跳转页面
|
||||||
query = paramsToQuery(path.params);
|
// mark: 跳转404页
|
||||||
|
if (!nextRoute) {
|
||||||
|
console.log(`%c跳转路径参数错误<${page || 'EMPTY'}>`, 'color:red;background:yellow')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const nextRoute = ROUTES_MAP[page];
|
// 页面登录拦截
|
||||||
|
if (nextRoute.meta?.auth && !$store('user').isLogin) {
|
||||||
|
uni.redirectTo({
|
||||||
|
url: '/pages/index/login',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 未找到指定跳转页面
|
url = page
|
||||||
// mark: 跳转404页
|
if (!isEmpty(query)) {
|
||||||
if (!nextRoute) {
|
url += `?${query}`
|
||||||
console.log(
|
}
|
||||||
`%c跳转路径参数错误<${page || "EMPTY"}>`,
|
|
||||||
"color:red;background:yellow"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 页面登录拦截
|
// 保存最新的页面地址
|
||||||
if (nextRoute.meta?.auth && !$store("user").isLogin) {
|
$store('user').lastRoutePage = url
|
||||||
uni.redirectTo({
|
|
||||||
url: "/pages/index/login",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
url = page;
|
// 跳转底部导航
|
||||||
if (!isEmpty(query)) {
|
if (TABBAR.includes(page)) {
|
||||||
url += `?${query}`;
|
uni.switchTab({
|
||||||
}
|
url,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 跳转底部导航
|
// 使用redirect跳转
|
||||||
if (TABBAR.includes(page)) {
|
if (options.redirect) {
|
||||||
uni.switchTab({
|
uni.redirectTo({
|
||||||
url,
|
url,
|
||||||
});
|
})
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用redirect跳转
|
uni.navigateTo({
|
||||||
if (options.redirect) {
|
url,
|
||||||
uni.redirectTo({
|
})
|
||||||
url,
|
}
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.navigateTo({
|
|
||||||
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 {
|
||||||
go,
|
go,
|
||||||
back,
|
back,
|
||||||
hasHistory,
|
hasHistory,
|
||||||
redirect,
|
redirect,
|
||||||
getCurrentPage,
|
getCurrentPage,
|
||||||
getCurrentRoute,
|
getCurrentRoute,
|
||||||
error,
|
error,
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,185 +1,175 @@
|
||||||
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 应用信息
|
||||||
* @param string name 应用名称
|
* @param string name 应用名称
|
||||||
* @param string logo 应用logo
|
* @param string logo 应用logo
|
||||||
* @param string version 应用版本
|
* @param string version 应用版本
|
||||||
* @param string copyright 版权信息
|
* @param string copyright 版权信息
|
||||||
* @param string copyrightTime 版权时间
|
* @param string copyrightTime 版权时间
|
||||||
* @param string cdnurl 静态资源域名
|
* @param string cdnurl 静态资源域名
|
||||||
* @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 平台信息
|
||||||
* @param Array share.methods 分享方式
|
* @param Array share.methods 分享方式
|
||||||
* @param Object share.forwardInfo 转发信息
|
* @param Object share.forwardInfo 转发信息
|
||||||
* @param Object share.posterInfo 海报信息
|
* @param Object share.posterInfo 海报信息
|
||||||
* @param string share.linkAddress 分享链接地址
|
* @param string share.linkAddress 分享链接地址
|
||||||
* @param number bindMobile 绑定手机号提醒 0: 提醒 1: 不提醒
|
* @param number bindMobile 绑定手机号提醒 0: 提醒 1: 不提醒
|
||||||
*/
|
*/
|
||||||
const platform = ref({
|
const platform = ref({
|
||||||
share: {
|
share: {
|
||||||
methods: [],
|
methods: [],
|
||||||
forwardInfo: {},
|
forwardInfo: {},
|
||||||
posterInfo: {},
|
posterInfo: {},
|
||||||
linkAddress: "",
|
linkAddress: '',
|
||||||
},
|
|
||||||
bindMobile: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
const chat = ref({});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 模板信息
|
|
||||||
* @param Object basic 基础模板
|
|
||||||
* @param Object tabbar 底部导航模板
|
|
||||||
*/
|
|
||||||
const template = ref({
|
|
||||||
basic: {
|
|
||||||
tabbar: {
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
activeIconUrl:
|
|
||||||
"http://mall.yudao.iocoder.cn/static/images/1-002.png",
|
|
||||||
iconUrl: "http://mall.yudao.iocoder.cn/static/images/1-001.png",
|
|
||||||
text: "首页",
|
|
||||||
url: "/pages/index/index",
|
|
||||||
},
|
},
|
||||||
{
|
bindMobile: 0,
|
||||||
activeIconUrl:
|
})
|
||||||
"http://mall.yudao.iocoder.cn/static/images/2-002.png",
|
|
||||||
iconUrl: "http://mall.yudao.iocoder.cn/static/images/2-001.png",
|
const chat = ref({})
|
||||||
text: "产品",
|
|
||||||
url: "/pages/index/product",
|
/**
|
||||||
|
* @description 模板信息
|
||||||
|
* @param Object basic 基础模板
|
||||||
|
* @param Object tabbar 底部导航模板
|
||||||
|
*/
|
||||||
|
const template = ref({
|
||||||
|
basic: {
|
||||||
|
tabbar: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-002.png',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-001.png',
|
||||||
|
text: '首页',
|
||||||
|
url: '/pages/index/index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-002.png',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-001.png',
|
||||||
|
text: '产品',
|
||||||
|
url: '/pages/index/product',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-002.png',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-001.png',
|
||||||
|
text: '订单',
|
||||||
|
url: '/pages/order/list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-002.png',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-001.png',
|
||||||
|
text: '我的',
|
||||||
|
url: '/pages/index/my',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
style: {
|
||||||
|
activeColor: '#fc4141',
|
||||||
|
bgColor: '#fff',
|
||||||
|
bgType: 'color',
|
||||||
|
color: '#282828',
|
||||||
|
},
|
||||||
|
theme: 'red',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
})
|
||||||
activeIconUrl:
|
|
||||||
"http://mall.yudao.iocoder.cn/static/images/3-002.png",
|
|
||||||
iconUrl: "http://mall.yudao.iocoder.cn/static/images/3-001.png",
|
|
||||||
text: "订单",
|
|
||||||
url: "/pages/order/list",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
activeIconUrl:
|
|
||||||
"http://mall.yudao.iocoder.cn/static/images/4-002.png",
|
|
||||||
iconUrl: "http://mall.yudao.iocoder.cn/static/images/4-001.png",
|
|
||||||
text: "我的",
|
|
||||||
url: "/pages/index/my",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
style: {
|
|
||||||
activeColor: "#fc4141",
|
|
||||||
bgColor: "#fff",
|
|
||||||
bgType: "color",
|
|
||||||
color: "#282828",
|
|
||||||
},
|
|
||||||
theme: "red",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 全局分享信息
|
// 全局分享信息
|
||||||
const shareInfo = ref({});
|
const shareInfo = ref({})
|
||||||
|
|
||||||
// 小程序发货信息管理 0: 没有 1:有
|
// 小程序发货信息管理 0: 没有 1:有
|
||||||
const hasWechatTradeManaged = ref(0);
|
const hasWechatTradeManaged = ref(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ankkaya
|
* @author Ankkaya
|
||||||
* @description 小程序初始化
|
* @description 小程序初始化
|
||||||
* @param {Type} -
|
* @param {Type} -
|
||||||
* @returns {Type}
|
* @returns {Type}
|
||||||
*/
|
*/
|
||||||
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();
|
} else {
|
||||||
if (userStore.isLogin) {
|
$router.error('InitError', res.msg || '加载失败')
|
||||||
userStore.loginAfter();
|
}
|
||||||
}
|
}
|
||||||
return Promise.resolve(true);
|
|
||||||
} else {
|
|
||||||
$router.error("InitError", res.msg || "加载失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
info,
|
info,
|
||||||
platform,
|
platform,
|
||||||
chat,
|
chat,
|
||||||
template,
|
template,
|
||||||
shareInfo,
|
shareInfo,
|
||||||
hasWechatTradeManaged,
|
hasWechatTradeManaged,
|
||||||
init,
|
init,
|
||||||
};
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
persist: {
|
|
||||||
enabled: true,
|
|
||||||
strategies: [
|
|
||||||
{
|
|
||||||
key: "app-store",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
}
|
{
|
||||||
);
|
persist: {
|
||||||
|
enabled: true,
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'app-store',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export default useAppStore;
|
export default useAppStore
|
||||||
|
|
|
@ -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'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,110 +1,124 @@
|
||||||
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 = {
|
||||||
unusedCouponCount: 0,
|
unusedCouponCount: 0,
|
||||||
orderCount: {
|
orderCount: {
|
||||||
allCount: 0,
|
allCount: 0,
|
||||||
unpaidCount: 0,
|
unpaidCount: 0,
|
||||||
undeliveredCount: 0,
|
undeliveredCount: 0,
|
||||||
deliveredCount: 0,
|
deliveredCount: 0,
|
||||||
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() {
|
||||||
|
setToken('')
|
||||||
|
userInfo.value = cloneDeep(defaultUserInfo)
|
||||||
|
userWallet.value = clone(defaultWallet)
|
||||||
|
userNumData.value = cloneDeep(defaultNumData)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateUserData() {
|
||||||
|
const nowTime = new Date().getTime()
|
||||||
|
if (lastUpdateTime.value + 5000 > nowTime) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastUpdateTime.value = nowTime
|
||||||
|
await Promise.all([getUserInfo(), getWallet(), getNumData()])
|
||||||
|
return userInfo.value
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loginAfter() {
|
||||||
|
await updateUserData()
|
||||||
|
$share.getShareInfo()
|
||||||
|
$router.go('/pages/index/index')
|
||||||
|
}
|
||||||
|
|
||||||
|
function logOut() {
|
||||||
|
resetUserData()
|
||||||
|
return !isLogin.value
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
userInfo,
|
||||||
|
userWallet,
|
||||||
|
isLogin,
|
||||||
|
setToken,
|
||||||
|
logOut,
|
||||||
|
loginAfter,
|
||||||
|
lastRoutePage,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
persist: {
|
||||||
|
enabled: true,
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'user-store',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
function resetUserData() {
|
export default useUserStore
|
||||||
setToken("");
|
|
||||||
userInfo.value = clone(defaultUserInfo);
|
|
||||||
userWallet.value = clone(defaultWallet);
|
|
||||||
userNumData.value = cloneDeep(defaultNumData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateUserData() {
|
|
||||||
const nowTime = new Date().getTime();
|
|
||||||
if (lastUpdateTime.value + 5000 > nowTime) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastUpdateTime.value = nowTime;
|
|
||||||
|
|
||||||
await getUserInfo();
|
|
||||||
getWallet();
|
|
||||||
getNumData();
|
|
||||||
return userInfo.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loginAfter() {
|
|
||||||
updateUserData();
|
|
||||||
$share.getShareInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
function logOut() {
|
|
||||||
resetUserData();
|
|
||||||
return !isLogin.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
userInfo,
|
|
||||||
isLogin,
|
|
||||||
setToken,
|
|
||||||
logOut,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
persist: true,
|
|
||||||
strategies: [
|
|
||||||
{
|
|
||||||
key: "user-store",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export default useUserStore;
|
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Loading…
Reference in New Issue