对接接口

This commit is contained in:
wangxiaowei
2025-12-17 00:45:31 +08:00
parent 977f7d4038
commit 018a784a8c
20 changed files with 455 additions and 816 deletions

View File

@ -1,7 +1,6 @@
import type { ICaptcha, IUpdateInfo, IUpdatePassword, IUserInfoVo, IUserLogin } from './types/login'
import { http } from '@/http/alova'
/**
* 登录表单
*/
@ -17,8 +16,10 @@ export interface ILoginForm {
*/
export interface IMobileLoginForm {
account: string
terminal: number
password: string
scene: number
terminal: number
channel: number
}
/**
@ -34,7 +35,7 @@ export function getCode() {
* @param loginForm 登录表单
*/
export function login(loginForm: ILoginForm) {
return http.Post<IUserLogin>('/api/user/login', loginForm)
return http.Post<IUserLogin>('/storeapi/user/login', loginForm)
}
/**
@ -42,7 +43,7 @@ export function login(loginForm: ILoginForm) {
* @param loginForm 登录表单
*/
export function mobileLogin(loginForm: IMobileLoginForm) {
return http.Post<IUserLogin>('/api/login/account',
return http.Post<IUserLogin>('/storeapi/storeLogin/account',
loginForm,
{
meta: { ignoreAuth: true } // 忽略认证
@ -54,28 +55,14 @@ export function mobileLogin(loginForm: IMobileLoginForm) {
* 获取用户信息
*/
export function getUserInfo() {
return http.Get<IUserInfoVo>('/api/user/info')
return http.Post<IUserInfoVo>('/storeapi/user/info')
}
/**
* 退出登录
*/
export function logout() {
return http.Get<void>('/user/logout')
}
/**
* 修改用户信息
*/
export function updateInfo(data: IUpdateInfo) {
return http.Get('/user/updateInfo', data)
}
/**
* 修改用户密码
*/
export function updateUserPassword(data: IUpdatePassword) {
return http.Get('/user/updatePassword', data)
return http.Post('/storeapi/storeLogin/logout')
}
/**
@ -102,7 +89,7 @@ export function getWxCode() {
* @returns Promise 包含登录结果
*/
export function wxLogin(data: { code: string }) {
return http.Post<IUserLogin>('/api/login/mnpLogin',
return http.Post<IUserLogin>('/storeapi/login/mnpLogin',
data,
{
meta: { ignoreAuth: true } // 忽略认证

22
src/api/store.ts Normal file
View File

@ -0,0 +1,22 @@
import { http } from '@/http/alova'
/**
* 获取门店列表
*/
export function getStoreList() {
return http.Post<any>('/storeapi/Store/userStoreList')
}
/**
* 门店详情
*/
export function getStoreDetails(id: number) {
return http.Post<any>('/storeapi/store/userStoreDetails', { id })
}
/**
* 切换门店信息
*/
export function switchStore(id: number) {
return http.Post('/storeapi/store/switchStore', { id })
}

View File

@ -8,139 +8,34 @@ import type { IUserResult } from '@/api/types/user'
* 获取用户个人信息
*/
export function getUserInfo() {
return http.Post<IUserResult>('/api/user/info')
return http.Post<IUserResult>('/storeapi/user/info')
}
/**
* 获取优惠券列表
*/
export function getUserCoupons() {
return http.Post('/api/UserCoupon/UserCoupinList')
}
/**
* 获取用户地址
*/
export function getUserAddress() {
return http.Post('/api/user/addressList')
}
/**
* 用户添加地址
*/
export interface IAddUserAddressParams {
id: number
contact: string
telephone: string
province: string
province_id?: number
city: string
city_id?: number
district: string
district_id?: number
address: string
is_default: number
}
export function addUserAddress(data: IAddUserAddressParams) {
return http.Post<IUserAddressListResult>('/api/user/addAddress', data)
}
/**
* 编辑用户地址
*/
export interface IEditUserAddressParams extends IAddUserAddressParams {
id: number
}
export function editUserAddress(data: IAddUserAddressParams) {
return http.Post('/api/user/editAddress', data)
}
/**
* 删除用户地址
*/
export interface IDeleteUserAddressParams {
id: number
}
export function deleteUserAddress(data: IDeleteUserAddressParams) {
return http.Post('/api/user/delAddress', data)
}
/**
* 获取地址详情
*/
export interface IUserAddressDetailsParams extends IDeleteUserAddressParams {}
export function userAddressDetails(data: IUserAddressDetailsParams) {
return http.Post<IUserAddressDetailsResult>('/api/user/addressDetails', data)
}
/**
* 优惠券列表(从订单页获取)
*/
export interface IGetCouponsParams {
id: number
numbers: number
type_id: number
}
export function getCoupons(data: IGetCouponsParams) {
return http.Post<IUserCouponListResult>('/api/UserCoupon/UserCoupinList', data)
}
/**
* 优惠券列表(从个人中心点击进去)
*/
export interface IGetMyCouponsParams {
status: number
type_id: number
}
export function getMyCoupons(data: IGetMyCouponsParams) {
return http.Post('/api/UserCoupon/orderCoupinList', data)
}
/**
* 个人中心优惠券
*/
export function getMyCoupon() {
return http.Post<IUserCouponListResult>('/api/UserCoupon/coupinList')
}
/**
* 领取个人中心优惠券
*/
export interface IClaimMyCouponParams {
id: number
}
export function claimMyCoupon(data: IClaimMyCouponParams) {
return http.Post('/api/UserCoupon/receiveCoupon', data)
}
/**
* 金额使用记录
*/
export interface IGetUserMoneyLogParams {
page: number
size: number
month: string
}
export function getUserMoneyLog(data: IGetUserMoneyLogParams) {
return http.Post<IOrderListResult>('/api/user/moneyLogList', data)
}
/**
* 修改用户信息
*/
export interface IUpdateUserInfoParams {
field: string,
value: string | number
nickname?: string
avatar?: string
mobile?: number
band_mobile?: string
password?: string
}
export function updateUserInfo(data: IUpdateUserInfoParams) {
return http.Post('/api/user/setInfo', data)
console.log("🚀 ~ updateUserInfo ~ data:", data)
return http.Post('/storeapi/user/updateUser', data)
}
/**
* 获取验证码
*/
export interface IGetVerificationCodeParams {
mobile: string
scene: number
}
export function getVerificationCode(data: IGetVerificationCodeParams) {
return http.Post('/storeapi/sms/sendCode', data)
}

View File

@ -7,37 +7,26 @@
}</route>
<template>
<view class="mt-54rpx">
<view class="mt-54rpx pb-40rpx">
<view class="font-bold text-44rpx text-[#303133] leading-60rpx text-center">切换账号</view>
<view class="mx-30rpx mt-48rpx">
<view class="bg-white rounded-16rpx px-30rpx py-36rpx flex justify-between items-center mb-20rpx">
<view class="flex items-center">
<wd-img width="70rpx" height="70rpx" round src="https://shchazhi.oss-cn-hangzhou.aliyuncs.com/fronted/icon/icon_avatar.png" mode="aspectFit" />
<view class="w-360rpx line-1 ml-24rpx">茶址24小时智能茶室(...</view>
</view>
<view class="flex-1 flex justify-end">
<template v-if="2 < 1">
<view class="font-400 text-28rpx text-[#4C9F44] leading-40rpx">当前登录</view>
</template>
<template v-if="2 > 1">
<view class="w-120rpx h-60rpx bg-[#4C9F44] text-center leading-60rpx text-[#fff] font-400 text-28rpx leading-40rpx rounded-8rpx text-center">切换</view>
</template>
</view>
</view>
<view class="bg-white rounded-16rpx px-30rpx py-36rpx flex justify-between items-center mb-20rpx">
<view class="flex items-center">
<wd-img width="70rpx" height="70rpx" round src="https://shchazhi.oss-cn-hangzhou.aliyuncs.com/fronted/icon/icon_avatar.png" mode="aspectFit" />
<view class="w-360rpx line-1 ml-24rpx">茶址24小时智能茶室(...</view>
</view>
<view class="flex-1 flex justify-end">
<template v-if="2 > 1">
<view class="font-400 text-28rpx text-[#4C9F44] leading-40rpx">当前登录</view>
</template>
<template v-if="2 < 1">
<view class="w-120rpx h-60rpx bg-[#4C9F44] text-center leading-60rpx text-[#fff] font-400 text-28rpx leading-40rpx rounded-8rpx text-center">切换</view>
</template>
</view>
<view
class="bg-white rounded-16rpx px-30rpx py-36rpx flex justify-between items-center mb-20rpx"
v-for="(item, index) in useStore.storeList" :key="item.id">
<view class="flex items-center">
<wd-img width="70rpx" height="70rpx" round src="https://shchazhi.oss-cn-hangzhou.aliyuncs.com/fronted/icon/icon_avatar.png" mode="aspectFit" />
<view class="w-360rpx line-1 ml-24rpx">{{ item.name }}</view>
</view>
<view class="flex-1 flex justify-end">
<template v-if="item.id === useStore.defaultStore.id">
<view class="font-400 text-28rpx text-[#4C9F44] leading-40rpx">当前登录</view>
</template>
<template v-else>
<view class="w-120rpx h-60rpx bg-[#4C9F44] text-center leading-60rpx text-[#fff] font-400 text-28rpx leading-40rpx rounded-8rpx text-center"
@click="Switch.handleChangeAccount(item, index)">切换
</view>
</template>
</view>
</view>
</view>
</view>
@ -45,6 +34,39 @@
<script lang="ts" setup>
import { useStoreStore } from '@/store'
import { switchStore } from '@/api/store'
import { router } from '@/utils/tools'
// 读取仓库
const useStore = useStoreStore()
// 店铺列表
const storeList = ref<Array<any>>([])
onShow(async () => {
// 获取店铺列表
})
onLoad(() => {
console.log("🚀 ~ useStore.defaultStore:", useStore.defaultStore)
})
const Switch = {
handleChangeAccount: async (item: any, index: number) => {
const res = await switchStore(item.id)
// 切换账号
useStore.setDefaultStore({
id: item.id,
name: item.name,
index
})
// 跳转首页
router.navigateBack()
}
}
</script>
<style lang="scss" scoped>

View File

@ -1,211 +0,0 @@
<route lang="jsonc" type="page">
{
"needLogin": true,
"layout": "default",
"style": {
"navigationStyle": "custom"
}
}
</route>
<template>
<view class="pb-180rpx">
<view>
<navbar :title="couponType == 1 ? '优惠券' : '团购券'" custom-class='!bg-[#F6F7F8]'></navbar>
</view>
<view>
<view class="mt-30rpx">
<view v-if="couponType == 1">
<!-- 优惠券 -->
<view class="mx-30rpx">
<view class="mx30rpx">
<text class="text-[#303133] font-bold text-30rpx leading-42rpx">可用优惠券</text>
<text class="text-[#606266] font-400 text-28rpx leading-40rpx ml-24rpx">{{ couponList.use.length }}</text>
</view>
<view class="mt-28rpx radio">
<wd-radio-group v-model="checkedId" size="large" checked-color="#4C9F44">
<coupon
v-for="(item, index) in couponList.use"
:key="item.id"
:coupon="item"
canUse
showChecked
:checked="item.id === checkedId"
:onCheck="Coupons.handleCheck"
:class="index !== couponList.use.length - 1 ? 'mb-20rpx' : ''"
></coupon>
</wd-radio-group>
</view>
</view>
<view class="mx-30rpx">
<view class="mx30rpx">
<text class="text-[#303133] font-bold text-30rpx leading-42rpx">不可用优惠券</text>
<text class="text-[#606266] font-400 text-28rpx leading-40rpx ml-24rpx">{{ couponList.no_use.length }}</text>
</view>
<view class="mt-28rpx radio">
<wd-radio-group v-model="checkedId" size="large" checked-color="#4C9F44">
<coupon
v-for="(item, index) in couponList.no_use"
:key="item.id"
:coupon="item"
:canUse="false"
showChecked
:checked="item.id === checkedId"
:onCheck="Coupons.handleCheck"
:class="index !== couponList.no_use.length - 1 ? 'mb-20rpx' : ''"
></coupon>
</wd-radio-group>
</view>
</view>
</view>
<!-- 团购券 -->
<view v-if="couponType == 2">
<view class="mx-30rpx">
<view class="mx30rpx">
<text class="text-[#303133] font-bold text-30rpx leading-42rpx">可用团购券</text>
<text class="text-[#606266] font-400 text-28rpx leading-40rpx ml-24rpx">2</text>
</view>
<view class="mt-28rpx radio">
<wd-radio-group v-model="checkedId" size="large" checked-color="#4C9F44">
<group-coupon
v-for="(item, index) in groupCouponList"
:key="item.id"
:coupon="item"
canUse
:checked="item.id === checkedId"
:onCheck="Coupons.handleCheck"
:class="index !== groupCouponList.length - 1 ? 'mb-20rpx' : ''"
></group-coupon>
</wd-radio-group>
</view>
</view>
<!-- <view class="mx-30rpx">
<view class="mx30rpx">
<text class="text-[#303133] font-bold text-30rpx leading-42rpx">不可用团购券</text>
<text class="text-[#606266] font-400 text-28rpx leading-40rpx ml-24rpx">2</text>
</view>
<view class="mt-28rpx radio">
<wd-radio-group v-model="checkedId" size="large" checked-color="#4C9F44">
<group-coupon
v-for="(item, index) in unCouponList"
:key="item.id"
:coupon="item"
:canUse="false"
:checked="item.id === checkedId"
:onCheck="Coupons.handleCheck"
:class="index !== couponList.length - 1 ? 'mb-20rpx' : ''"
></group-coupon>
</wd-radio-group>
</view>
</view> -->
</view>
</view>
</view>
<view class="fixed left-0 right-0 bottom-0 z-2 bg-[#fff] flex justify-between items-center" :style="{ height: '140rpx'}">
<view class="ml-60rpx text-[#121212] text-24rpx leading-34rpx">已选择{{ checkedId ? 1 : 0 }}</view>
<view class="mr-30rpx">
<wd-button custom-class='!bg-[#4C9F44] !rounded-8rpx !h-70rpx' @click="Coupons.handleConfirmCoupon">确定</wd-button>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import Coupon from '@/components/coupon/Coupon.vue'
import GroupCoupon from '@/components/coupon/GroupCoupon.vue'
import { getCoupons } from '@/api/user'
import { getTeaRoomGroupCouponList } from '@/api/tea-room'
import type { IUserCouponListResult } from '@/api/types/user'
import { router } from '@/utils/tools'
import { CouponType } from '@/utils/coupon'
const couponType = ref<number>(2) // couponType 1:优惠券 2:团购券
const couponList = ref<IUserCouponListResult>({
no_use: [],
use: []
})
const groupCouponList = ref<any>()
const checkedId = ref<number>(0)
const unCouponList = ref([
{ id: 1, amount: 20, limit: 100, expire: '2024.08.20' },
{ id: 2, amount: 10, limit: 50, expire: '2024.08.25' }
])
const storeId = ref<number>(0) // 门店ID
const teaRoomId = ref<number>(0) // 包间ID
onLoad((args) => {
teaRoomId.value = args.id
storeId.value = args.storeId || 0
couponType.value = args.type // 1:优惠券 2:团购券
// 初始化优惠券数据
if (args.id && args.numbers && args.type == 1) {
// 获取到包间ID和预定了几个小时
Coupons.handleInitCoupon(args.id, args.numbers)
} else if (args.id && args.type == 2) {
Coupons.handleInitGroupCoupon(args.id, args.numbers)
}
})
const Coupons = {
/**
* 初始化优惠券列表
* @param id 包间ID
* @param numbers 预定时长
*/
handleInitCoupon: async (id: number, numbers: number) => {
const res = await getCoupons({id, numbers, type_id: 2})
couponList.value = res
},
/**
* 初始化团购券列表
*/
handleInitGroupCoupon: async (id: number, numbers: number) => {
const res = await getTeaRoomGroupCouponList({store_id: storeId.value})
groupCouponList.value = res.list
},
/**
* 选择优惠券
* @param id 优惠券ID
*/
handleCheck: (id: number) => {
checkedId.value = id
},
/**
* 确认选择优惠券
*/
handleConfirmCoupon: () => {
let coupon = null
if (couponType.value == CouponType.Discount) {
coupon = couponList.value.use.find(item => item.user_coupon_id === checkedId.value)
} else {
coupon = groupCouponList.value.find(item => item.id === checkedId.value)
}
uni.$emit('chooseCoupon', { coupon })
router.navigateBack()
}
}
</script>
<style lang="scss">
page {
background-color: $cz-page-background;
}
.radio {
:deep() {
.wd-radio-group {
background-color: transparent !important;
}
}
}
</style>

View File

@ -1,182 +0,0 @@
<route lang="jsonc" type="page">
{
"needLogin": true,
"layout": "default",
"style": {
"navigationStyle": "custom"
}
}
</route>
<template>
<view class="pb-180rpx">
<view>
<navbar title="优惠券" custom-class='!bg-[#F6F7F8]'></navbar>
</view>
<view>
<view class="coupon-tab">
<wd-tabs v-model="tab" swipeable slidable="always" @click="MyCoupon.handleChangeTab" :lazy="false">
<wd-tab title="茶室优惠券">
<view class="mx-30rpx">
<view class="flex">
<view v-for="(item, index) in tag" :key="index"
@click="MyCoupon.handleChangeTag(item.value)"
class="font-400 text-28rpx leading-40rpx w-116rpx h-64rpx flex justify-center items-center border-2rpx border-solid rounded-12rpx mr-20rpx"
:class="item.value === currentTag ? ' border-[#4C9F44] bg-[#F0F6EF] text-[#4C9F44]' : 'border-[#fff] bg-[#fff]'">
{{ item.label }}
</view>
</view>
<view class="mt-32rpx">
<coupon
v-for="(item, index) in couponList"
:key="item.id"
:coupon="item"
canUse
:showChecked="false"
:checked="item.id === checkedId"
:onCheck="MyCoupon.handleCouponCheck"
:class="index !== couponList.length - 1 ? 'mb-20rpx' : ''"
></coupon>
</view>
</view>
</wd-tab>
<wd-tab title="茶艺师优惠券">
<view class="mx-30rpx">
<view class="flex">
<view v-for="(item, index) in tag" :key="index"
@click="MyCoupon.handleChangeTag(item.value)"
class="font-400 text-28rpx leading-40rpx w-116rpx h-64rpx flex justify-center items-center border-2rpx border-solid rounded-12rpx mr-20rpx"
:class="item.value === currentTag ? ' border-[#4C9F44] bg-[#F0F6EF] text-[#4C9F44]' : 'border-[#fff] bg-[#fff]'">
{{ item.label }}
</view>
</view>
<view class="mt-32rpx">
<coupon
v-for="(item, index) in couponList"
:key="item.id"
:coupon="item"
canUse
:showChecked="false"
:checked="item.id === checkedId"
:onCheck="MyCoupon.handleCouponCheck"
:class="index !== couponList.length - 1 ? 'mb-20rpx' : ''"
></coupon>
</view>
</view>
</wd-tab>
</wd-tabs>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import {ref} from 'vue'
import Coupon from '@/components/coupon/Coupon.vue'
import GroupCoupon from '@/components/coupon/GroupCoupon.vue'
import { getMyCoupons } from '@/api/user'
//
const tab = ref<number>(0)
const tag = ref<Array<any>>([
{label: '全部', value: 0 },
{label: '已使用', value: 1 },
{label: '快过期', value: 3 },
])
const currentTab = ref<number>(0)
const currentTag = ref<number>(0)
const couponType = ref<number>(2) // couponType 1:优惠券 2:团购券
const OSS = inject('OSS')
const couponList = ref<any[]>([])
const checkedId = ref<number>(0)
const unCouponList = ref([
{ id: 1, amount: 20, limit: 100, expire: '2024.08.20' },
{ id: 2, amount: 10, limit: 50, expire: '2024.08.25' }
])
onLoad((args) => {
if (args.type) {
couponType.value = args.type
}
MyCoupon.handleInit()
})
const MyCoupon = {
/**
* 初始化优惠券列表
*/
handleInit: async () => {
const res: any = await getMyCoupons({status: currentTag.value, type_id: currentTab.value == 0 ? 2 : 1})
if (Array.isArray(res)) {
res.map((res) => {
couponList.value.push({
id: res.coupon_id,
coupon_price: res.userCouponType[0].coupon_price,
use_price: res.userCouponType[0].use_price,
title: res.userCouponType[0].title,
effect_time: res.userCouponType[0].effect_time,
user_coupon_id: res.coupon_id,
expire: res.expire
})
})
}
},
/**
* 切换tab
* @param item 切换项
*/
handleChangeTab: (item: {index: number}) => {
currentTab.value = item.index
currentTag.value = 0
couponList.value = []
MyCoupon.handleInit()
},
/**
* 切换tag
* @param item 切换项
*/
handleChangeTag: (item: number) => {
currentTag.value = item
couponList.value = []
MyCoupon.handleInit()
},
/**
* 选择优惠券-保留这个函数,暂时用不着
* @param id 切换项
*/
handleCouponCheck: (id: number) => {
checkedId.value = id
}
}
</script>
<style lang="scss">
page {
background-color: $cz-page-background;
}
.coupon-tab {
:deep() {
.wd-tabs,
.wd-tabs__nav,
.wd-tabs__line {
background-color: transparent;
}
.wd-tabs__nav-item.is-active {
font-size: 32rpx !important;
}
}
}
</style>

View File

@ -1,4 +1,5 @@
<route lang="jsonc" type="page">{
"needLogin": true,
"layout": "default",
"style": {
"navigationStyle": "custom"
@ -9,9 +10,9 @@
<view>
<view class="mx-60rpx mt-20rpx">
<view class="text-[#303133] text-48rpx leading-80rpx font-600">
修改手机号码
{{ page.title }}
</view>
<view class="font-400 text-28rpx leading-44rpx text-[#6B7280] mt-12rpx">手机号一年内可修改2次</view>
<view class="font-400 text-28rpx leading-44rpx text-[#6B7280] mt-12rpx">{{ page.desc }}</view>
</view>
<view class="mt-106rpx mx-48rpx">
<wd-form ref="form" :model="model">
@ -31,7 +32,7 @@
</view>
</view>
<view class="mt-40rpx">
<view class="mt-40rpx" v-if="pageType == 'edit'">
<view class="font-400 text-30rpx text-[#606266] leading-44rpx">验证码</view>
<view class="mt-20rpx">
<wd-input type="text" placeholder="请输入验证码" v-model="model.code" inputmode="numeric" no-border custom-class="!bg-[#F6F7F8] !border !border-solid !border-[#EAECF0] !rounded-16rpx" custom-input-class="!px-32rpx !h-104rpx">
@ -58,15 +59,6 @@
<view class="h-90rpx leading-90rpx mx-60rpx rounded-8rpx text-center mt-112rpx bg-[#4C9F44] text-[#fff]" :class="disabled ? 'opacity-40' : ''" @click="mobile.handleToLogin">登录</view>
<view class="flex items-center mx-52rpx mt-56rpx" v-if="pageType === 'login'">
<view class="w-32rpx h-32rpx">
<wd-checkbox v-model="agree" @change="mobile.handleAgree" checked-color="#4C9F44" size="large"> </wd-checkbox>
</view>
<view class="font-400 text-26rpx leading-40rpx text-[#8F959E] ml-14rpx flex-1" @click="agree = !agree">
我已阅读并同意 <text class="text-[#4C9F44]" @click.stop="mobile.handleToService">服务协议</text> <text class="text-[#4C9F44]" @click.stop="mobile.handleToPrivacy">隐私政策</text>
</view>
</view>
<!-- 手机号修改成功 -->
<wd-popup v-model="showEditSuccessPopup" lock-scroll custom-style="border-radius: 32rpx 32rpx 0rpx 0rpx;" position="bottom">
<view class="relative pt-64rpx pb-74rpx">
@ -94,7 +86,7 @@
const disabled = ref<boolean>(true)
/** 页面 **/
let pageType = 'login' // 页面类型 login:登录 edit:修改手机号
const pageType = ref<string>('') // 页面类型 login:登录 edit:修改手机号
const page = ref<{title: string, desc: string}>({title: '其他手机号登录', desc: '请输入你要登录的手机号'})
const showEditSuccessPopup = ref<boolean>(false) // 显示手机号修改成功弹窗
const userId = ref<number>(0) // 用户ID修改手机号时需要传
@ -114,18 +106,18 @@
})
/** 结束 **/
/** 服务协议和隐私政策 **/
const agree = ref<boolean>(false)
/** 结束 **/
onLoad((args) => {
// 从个人登录页面进入
pageType.value = args.type
userId.value = Number(args.userId) || 0 // userId仅做测试使用实际请传真实用户ID
if (args.type === 'edit') {
userId.value = Number(args.userId) || 0 // userId仅做测试使用实际请传真实用户ID
page.value.title = '修改手机号'
page.value.desc = '手机号一年内可修改2次'
pageType = 'edit'
} else if (args.type === 'change') {
page.value.title = '修改绑定用户'
page.value.desc = '请输入新的手机号进行绑定'
}
})

View File

@ -1,4 +1,5 @@
<route lang="jsonc" type="page">{
"needLogin": true,
"layout": "default",
"style": {
"navigationStyle": "custom"

View File

@ -1,5 +1,6 @@
<route lang="jsonc" type="page">
{
"needLogin": true,
"layout": "default",
"style": {
"navigationStyle": "custom"
@ -76,7 +77,7 @@
image-mode="scaleToFill"
:action="action"
@success="Profile.handleUploadSuccess">
<wd-img width="64rpx" height="64rpx" :src="user.avatar" mode="aspectFill" round />
<wd-img width="64rpx" height="64rpx" :src="user.avatar || `${OSS}images/store/my/image1.png`" mode="aspectFill" round />
</wd-upload>
</view>
<wd-icon name="arrow-right" size="32rpx" color="#C0C4CC" />
@ -100,7 +101,7 @@
</view>
<!-- 修改手机号 -->
<view class="flex justify-between items-center mb-54rpx" @click="Profile.handleToEditMobile">
<view class="flex justify-between items-center mb-54rpx" @click="router.navigateTo('/bundle/profile/change-mobile?type=edit')">
<view class="font-400 text-[#303133] text-30rpx leading-42rpx">修改手机号</view>
<view class="flex justify-end">
<view class="flex items-center">
@ -116,31 +117,17 @@
<!-- 修改手机号 -->
<view class="flex justify-between items-center mb-54rpx" @click="router.navigateTo('/bundle/profile/change-password')">
<view class="font-400 text-[#303133] text-30rpx leading-42rpx">修改手机号</view>
<view class="flex justify-end">
<view class="flex items-center">
<view class="font-400 text-[#303133] text-30rpx leading-42rpx">
{{ user.nickname }}
</view>
<view>
<wd-icon name="arrow-right" size="32rpx" color="#C0C4CC" />
</view>
</view>
<view class="font-400 text-[#303133] text-30rpx leading-42rpx">修改密码</view>
<view>
<wd-icon name="arrow-right" size="32rpx" color="#C0C4CC" />
</view>
</view>
<!-- 修改绑定用户 -->
<view class="flex justify-between items-center" @click="router.navigateTo('/bundle/profile/change-password')">
<view class="flex justify-between items-center" @click="router.navigateTo('/bundle/profile/change-mobile?type=change')">
<view class="font-400 text-[#303133] text-30rpx leading-42rpx">修改绑定用户</view>
<view class="flex justify-end">
<view class="flex items-center">
<view class="font-400 text-[#303133] text-30rpx leading-42rpx">
{{ user.nickname }}
</view>
<view>
<wd-icon name="arrow-right" size="32rpx" color="#C0C4CC" />
</view>
</view>
<view>
<wd-icon name="arrow-right" size="32rpx" color="#C0C4CC" />
</view>
</view>
</view>
@ -164,7 +151,7 @@
// 上传文件
const fileList = ref<any[]>([])
const action = 'https://cz.stnav.com/api/upload/image' // 仅做测试使用,实际请换成真实上传接口
const action = import.meta.env.VITE_UPLOAD_BASEURL
// 修改昵称
const showEditNicknamePopup = ref<boolean>(false) // 是否显示退款详情弹出框
@ -195,17 +182,16 @@
onLoad(() => {
token.value = uni.getStorageSync('token')
// Profile.handleInit()
Profile.handleInit()
})
const Profile = {
/**
* 初始化用户信息
*/
handleInit: () => {
getUserInfo().then(res => {
user.value = res
})
handleInit: async () => {
const res = await getUserInfo()
user.value = res
},
/**
@ -221,7 +207,7 @@
const response = JSON.parse(e.file.response)
if (response.code) {
const avatarUrl = response.data.uri
await updateUserInfo({ field: 'avatar', value: avatarUrl })
await updateUserInfo({ avatar: avatarUrl })
user.value.avatar = avatarUrl
toast.info('头像上传成功')
} else {
@ -241,7 +227,7 @@
return
}
await updateUserInfo({ field: 'nickname', value: nickname.value })
await updateUserInfo({ nickname: nickname.value })
showEditNicknamePopup.value = false
user.value.nickname = nickname.value
toast.info('昵称修改成功')
@ -259,9 +245,9 @@
/**
* 退出
*/
handleLogout: () => {
handleLogout: async () => {
const userStore = useUserStore()
userStore.logout()
await userStore.logout()
if (!userStore.isLoggedIn) {
toast.info('退出成功')
router.reLaunch('/pages/my/my')

View File

@ -0,0 +1,103 @@
<template>
<wd-popup v-model="showPopup" lock-scroll custom-style="border-radius: 32rpx 32rpx 0rpx 0rpx;" position="bottom">
<view class="relative pb-78rpx">
<view class="absolute top-18rpx right-30rpx" @click="showPopup = false">
<wd-img width="60rpx" height='60rpx' :src="`${OSS}icon/icon_close.png`"></wd-img>
</view>
<view class="text-36rpx text-[#121212] leading-50rpx text-center pt-50rpx pb-40rpx">续订包间</view>
<view class="booking-time mx-60rpx">
<view class="text-32rpx leading-44rpx text-[#01000D] mb-28rpx">续订时间</view>
<view class="grid grid-cols-4 gap-20rpx">
<view
@click="RenewTime.handleSelectTime(item)"
v-for="(item, index) in timeList" :key="index"
class="w-148rpx h-60rpx text-center leading-60rpx bg-[#F7F7F7] rounded-8rpx text-28rpx text-[#606266]"
:class="currentTimeValue == item.value ? '!bg-[#4C9F44] text-white' : ''">
{{ item.label }}
</view>
</view>
</view>
<view class="mx-auto mt-130rpx w-630rpx h-90rpx leading-90rpx text-center bg-[#4C9F44] rounded-8rpx text-[#fff]" @click="RenewTime.handleConfirmSelectedTime">
确定续订
</view>
</view>
</wd-popup>
</template>
<script lang="ts" setup name="RenewTime">
import {toast} from '@/utils/toast'
const OSS = inject('OSS')
/**
* BookingTime 预约时间
* @description 茶室预约时间选择组件
*/
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
})
// 初始化时间
onMounted(() => {
})
// 日期相关
const currentTimeValue = ref<number>(0)
const timeList = ref<Array<{ label: string, value: number }>>([
{label: '1小时', value: 1},
{label: '2小时', value: 2},
{label: '3小时', value: 3},
{label: '4小时', value: 4},
{label: '5小时', value: 5},
{label: '6小时', value: 6},
])
const RenewTime = {
/**
* 选择时间
*/
handleSelectTime: (item: { label: string, value: number }) => {
currentTimeValue.value = item.value
},
/**
* 确认选择时间
*/
handleConfirmSelectedTime: () => {
if (currentTimeValue.value == 0) {
toast.info('请选择续订时间')
return
}
const selectedItem = timeList.value.find(item => item.value == currentTimeValue.value)
emit('selectedTime', selectedItem)
showPopup.value = false
}
}
const showPopup = computed({
get: () => props.modelValue,
set: (val: boolean) => emit('update:modelValue', val)
})
const emit = defineEmits(['update:modelValue', 'selectedTime'])
</script>
<script lang="ts">
export default {}
</script>
<style lang="scss" scoped>
.booking-time {
:deep() {
.wd-tabs__line {
background-color: #4C9F44 !important;
}
}
}
</style>

View File

@ -32,7 +32,7 @@ const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthenticati
}
catch (error) {
// 切换到登录页
await uni.reLaunch({ url: '/pages/login/login' })
await uni.reLaunch({ url: import.meta.env.VITE_LOGIN_URL })
throw error
}
},
@ -58,19 +58,13 @@ const alovaInstance = createAlova({
const { config } = method
const ignoreAuth = !config.meta?.ignoreAuth
console.log('ignoreAuth===>', ignoreAuth)
// 处理认证信息 自行处理认证问题
if (ignoreAuth) {
// const token = 'getToken()'
// if (!token) {
// throw new Error('[请求错误]:未登录')
// }
// method.config.headers.token = token;
const token = uni.getStorageSync('token')
if (!token) {
toast.info('请先登录')
router.switchTab('/pages/my/my', 500)
router.switchTab(import.meta.env.VITE_LOGIN_URL, 500)
throw new Error('[请求错误]:未登录')
}
@ -98,14 +92,6 @@ const alovaInstance = createAlova({
return response
}
// 处理 HTTP 状态码错误
// if (statusCode !== 200) {
// const errorMessage = ShowMessage(statusCode) || `HTTP请求错误[${statusCode}]`
// console.error('errorMessage===>', errorMessage)
// toast.error(errorMessage)
// throw new Error(`${errorMessage}${errMsg}`)
// }
// 处理业务逻辑错误
const { code, msg, data } = rawData as IResponse
if (code === ResultEnum.Unauthorized) {
@ -114,7 +100,7 @@ const alovaInstance = createAlova({
if (config.meta?.toast !== false) {
toast.info(msg)
router.switchTab('/pages/my/my', 1000)
router.switchTab(import.meta.env.VITE_LOGIN_URL, 1000)
}
throw new Error(`登录超时[${code}]${msg}`)
}

View File

@ -1,5 +1,6 @@
<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page -->
<route lang="jsonc" type="home">{
"needLogin": true,
"layout": "tabbar",
"style": {
// 'custom' 表示开启自定义导航栏,默认 'default'
@ -14,7 +15,7 @@
<wd-navbar safeAreaInsetTop :bordered="false" custom-style="background-color: transparent !important;">
<template #left>
<view class="flex items-center line-1 w-450rpx" @click="router.navigateTo('/bundle/account/switch')">
<view class="mr-10rpx font-400 leading-44rpx text-32rpx pl-10rpx line-1">茶址24小时智能茶室(中新店)</view>
<view class="mr-10rpx font-400 leading-44rpx text-32rpx pl-10rpx line-1">{{ useStore.defaultStore.name || '暂无门店信息' }}</view>
<wd-img width="14rpx" height="9rpx" :src="`${OSS}icon/icon_arrow_down.png`" />
</view>
</template>
@ -124,20 +125,12 @@
<script lang="ts" setup>
import { router } from '@/utils/tools'
import { getStoreList, getStoreDetails } from '@/api/store'
import { useStoreStore } from '@/store'
const OSS = inject('OSS')
const navbarHeight = inject('navbarHeight')
// 分页
const downOption = {
auto: true
}
const upOption = {
auto: true,
textNoMore: '~ 已经到底啦 ~', //无更多数据的提示
}
const keywords = ref<string>('')
const list = ref<Array<any>>([])
const useStore = useStoreStore()
// 扫码验券弹出框
const showScanMenu = ref<boolean>(false)
@ -153,16 +146,65 @@
}
])
// 门店列表
const storeList = ref<Array<any>>([])
const defaultStore = ref<{ id: number; name: string; index: number }>({
id: 0,
name: '',
index: 0
})
const store = ref<any>({})
onLoad(async() => {
onShow(() => {
// 初始化页面数据
Index.handleInit()
})
onLoad(async() => {
})
const Index = {
handleInit: async() => {
await Index.handleGetStoreList()
await Index.handleGetStoreDetails()
},
/**
* 获取门店列表
*/
handleGetStoreList: async() => {
console.log("🚀 ~ Index.handleGetStoreList:", 'Index.handleGetStoreLis123')
const storeLists = await getStoreList()
// 保证 storeList.value 一定为数组
storeList.value = Array.isArray(storeLists.list) ? storeLists.list : Object.values(storeLists.list || {})
console.log("🚀 ~ storeList.value:", storeList.value)
console.log("🚀 ~ storeList.value:", storeList.value.length)
if (storeList.value.length > 0) {
useStore.setStoreList(storeList.value)
// 如果没有设置默认门店的话则设置第一个门店为默认门店
console.log("🚀 ~ useStore.defaultStore:", useStore.defaultStore)
if (useStore.defaultStore.id == 0) {
useStore.setDefaultStore({
id: storeList.value[0].id,
name: storeList.value[0].name,
index: 0
})
}
}
},
/**
* 获取门店详情
*/
handleGetStoreDetails: async() => {
if (!defaultStore.value) return
const storeDetails = await getStoreDetails(useStore.defaultStore.id)
store.value = storeDetails.details
console.log("🚀 ~ storeDetails:", storeDetails)
},
/**
@ -193,6 +235,13 @@
}
})
},
/**
* 一键续订时间
*/
handleChooseRenewTime: (item) => {
console.log("🚀 ~ item:", item)
}
}
</script>

View File

@ -26,16 +26,17 @@
<view class="mt-20rpx">
<wd-input v-model="model.mobile" type="text" placeholder="请输入账号" inputmode="numeric" no-border
custom-class="!bg-[#F6F7F8] !rounded-16rpx"
custom-input-class="!px-32rpx !h-104rpx" @input="Login.handleInputMobile" />
custom-input-class="!px-32rpx !h-104rpx"/>
</view>
</view>
<view class="mt-40rpx">
<view class="font-400 text-30rpx text-[#606266] leading-44rpx">密码</view>
<view class="mt-20rpx">
<wd-input v-model="model.passowrd" type="safe-password" placeholder="请输入密码" no-border
<view class="mt-20rpx password-input">
<wd-input v-model="model.passowrd" show-password placeholder="请输入密码" no-border
custom-class="!bg-[#F6F7F8] !rounded-16rpx"
custom-input-class="!px-32rpx !h-104rpx" />
custom-input-class="!px-32rpx !h-104rpx">
</wd-input>
</view>
</view>
@ -51,152 +52,84 @@
</view>
</template>
<script lang="ts" setup>
import { mobile as testMobile } from '@/utils/test'
import { router } from '@/utils/tools'
import { useToast } from 'wot-design-uni'
import { mobile as testMobile } from '@/utils/test'
import { router } from '@/utils/tools'
import { useToast } from 'wot-design-uni'
import { useUserStore } from '@/store'
const OSS = inject('OSS')
const toast = useToast()
const disabled = ref<boolean>(true)
const OSS = inject('OSS')
const toast = useToast()
/** 页面 **/
let pageType = 'login' // 页面类型 login:登录 edit:修改手机号
const page = ref<{ title: string, desc: string }>({ title: '其他手机号登录', desc: '请输入你要登录的手机号' })
const showEditSuccessPopup = ref<boolean>(false) // 显示手机号修改成功弹窗
const userId = ref<number>(0) // 用户ID修改手机号时需要传
/** 表单相关 **/
const model = reactive<{
mobile: string
passowrd: string
}>({
mobile: '15005837859',
passowrd: '123456'
})
/** 验证码倒计时 **/
const countDownTime = ref<number>(1 * 60 * 1000) // 60s倒计时
const startCountDown = ref<boolean>(false) // 是否开始倒计时
const countDown = ref<any>(null) // 倒计时组件
/** 表单相关 **/
const model = reactive<{
mobile: string
passowrd: string
}>({
mobile: '',
passowrd: ''
})
/** 结束 **/
onLoad((args) => {
/** 服务协议和隐私政策 **/
const agree = ref<boolean>(false)
/** 结束 **/
})
onLoad((args) => {
// 从个人登录页面进入
if (args.type === 'edit') {
userId.value = Number(args.userId) || 0 // userId仅做测试使用实际请传真实用户ID
const Login = {
// 登录
handleToLogin: async () => {
// TODO 如果是edit的话就是修改手机号
if (!testMobile(model.mobile)) {
toast.info('请输入正确的账号')
return
}
page.value.title = '修改手机号'
page.value.desc = '手机号一年内可修改2次'
pageType = 'edit'
if (!model.passowrd) {
toast.info('请输入密码')
return
}
uni.showLoading({
title: '登录中...'
})
try {
const userStore = useUserStore()
const res = await userStore.mobileLogin(model.mobile, model.passowrd, 1, 1, 1)
uni.hideLoading()
toast.success('登录成功')
setTimeout(() => {
router.navigateBack()
}, 1000)
} catch (error) {
toast.info('登录失败,请稍后重试')
uni.hideLoading
return
}
}
}
})
const Login = {
// 验证手机号
handleInputMobile: (e: { value: string }) => {
model.mobile = e.value
disabled.value = !testMobile(model.mobile)
},
// 发送验证码
handleCountDown: () => {
if (disabled.value) {
toast.show({
iconClass: 'info-circle',
msg: '手机号码错误请重新输入',
direction: 'vertical'
})
return
}
startCountDown.value = true
nextTick(() => {
countDown.value?.start()
// 发送验证码请求
})
},
// 验证码倒计时结束
handleFinishCountDown: () => {
startCountDown.value = false
},
// 登录
handleToLogin: () => {
// TODO 如果是edit的话就是修改手机号
if (pageType === 'login' && !agree.value) {
toast.show({
iconClass: 'info-circle',
msg: '请同意服务协议和隐私政策',
direction: 'vertical'
})
return
}
if (!testMobile(model.mobile)) {
toast.show({
iconClass: 'info-circle',
msg: '手机号码错误请重新输入',
direction: 'vertical'
})
return
}
if (!model.code) {
toast.show({
iconClass: 'info-circle',
msg: '验证码错误',
direction: 'vertical'
})
return
}
},
// 获取手机号
handleGetPhoneNumber: (e: object) => {
console.log("🚀 ~ e:", e)
},
handleAgree: (e: any) => {
console.log('e', e)
},
// 跳转到服务协议页面
handleToService: () => {
disabled.value = !disabled.value
console.log("🚀 ~ disabled:", disabled)
},
// 跳转到隐私政策页面
handleToPrivacy: () => {
},
// 修改手机成功后返回
handleToBack: () => {
uni.navigateBack()
}
}
</script>
<style lang="scss">
page {
background-color: #fff;
}
page {
background-color: #fff;
}
.login-bg {
background-color: #fff;
background-image: url(#{$OSS}images/store/login/image1.png);
background-size: 100% 420rpx;
background-repeat: no-repeat;
}
.login-bg {
background-color: #fff;
background-image: url(#{$OSS}images/store/login/image1.png);
background-size: 100% 420rpx;
background-repeat: no-repeat;
}
.password-input {
:deep() {
.wd-input__icon {
padding-right: 20rpx !important;
background: transparent !important;
}
}
}
</style>

View File

@ -1,4 +1,5 @@
<route lang="jsonc" type="page">{
"needLogin": true,
"layout": "default",
"style": {
"navigationBarTitleText": "",

View File

@ -70,16 +70,14 @@ function formatAccount(account: string) {
onShow(() => {
const userStore = useUserStore()
isLogin.value = userStore.isLoggedIn
console.log('🚀 ~ isLogin.value:', 1)
console.log("🚀 ~ isLogin.value:", isLogin.value)
if (isLogin.value) {
console.log('🚀 ~ isLogin.value:', 3)
// 获取用户详情信息接口
getUserInfo().then((res) => {
user.value = res
})
}
else {
console.log('🚀 ~ isLogin.value:', 4)
Object.keys(user.value).forEach((key) => {
user.value[key] = ''
})
@ -88,8 +86,6 @@ onShow(() => {
onLoad(() => {
uni.$on('clearUser', () => {
console.log('🚀 ~ isLogin.value:', 2)
const userStore = useUserStore()
isLogin.value = userStore.isLoggedIn
@ -107,10 +103,9 @@ const My = {
// 跳转到个人信息
handleToProfile: () => {
if (!isLogin.value) {
router.navigateTo('/bundle/profile/profile')
}
else {
router.navigateTo('/pages/login/login')
} else {
router.navigateTo('/bundle/profile/profile')
}
},
@ -192,11 +187,11 @@ const My = {
</view>
<view class="relative z-10 ml-22rpx flex flex-1 items-center justify-between">
<view class="flex-1" @click="My.handleToProfile">
<view class="ml-8rpx flex items-center text-36rpx leading-50rpx" style="color: #fff;">
{{ isLogin ? user.nickname : '立即登录' }}
<view class="ml-8rpx flex items-center text-36rpx leading-50rpx text-[#fff]">
{{ isLogin ? user.nickname || '暂无昵称' : '立即登录' }}
<wd-icon v-if="isLogin" name="arrow-right" size="24rpx" color="#fff" class="ml-8rpx" />
</view>
<view v-if="isLogin" class="ml-8rpx mt-8rpx text-24rpx leading-34rpx" style="color: #fff;">
<view v-if="isLogin" class="ml-8rpx mt-8rpx text-24rpx leading-34rpx text-[#fff]">
账号: {{ formatAccount(user.account || user.mobile) }}
</view>
</view>

View File

@ -14,7 +14,7 @@
<view class="mt-38rpx">
<mescroll-body ref="mescrollItem0" @init="mescrollInit" @down="downCallback" @up="Renew.upCallback" :down="downOption" :up="upOption">
<view class="bg-white rounded-16rpx p-30rpx mx-32rpx relative">
<view class="absolute top-0 right-0 bg-[#4C9F44] text-[#fff] w-160rpx h-64rpx leading-64rpx text-center xd" @click="showBookTimePopup = true">
<view class="absolute top-0 right-0 bg-[#4C9F44] text-[#fff] w-160rpx h-64rpx leading-64rpx text-center xd" @click="showRenewTimePopup = true">
续单
</view>
<view class="flex items-center">
@ -37,8 +37,8 @@
<view class="bg-[#4C9F44] w-630rpx h-90rpx text-[#fff] text-center leading-90rpx rounded-8rpx mx-auto mt-50rpx">确定</view>
<!-- 选择预定时间 -->
<!-- <booking-time v-model="showBookTimePopup" :day="sevenDay" @selectedTime="Reserve.handleChooseReserveTime"></booking-time> -->
<!-- 选择续订时间 -->
<renew-time v-model="showRenewTimePopup" @selectedTime="Renew.handleChooseRenewTime"></renew-time>
</view>
</template>
@ -53,6 +53,10 @@
import type { ITeaSpecialistFuture7DaysResult } from '@/api/types/tea'
import { getNext7Days, renewTeaRoomOrder } from '@/api/tea-room'
// 续单
const showRenewTimePopup = ref<boolean>(false)
// mescroll
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom) // 调用mescroll的hook
const downOption = {
@ -150,6 +154,12 @@
// totalReserveMoney.value = Number(toTimes(params[3], order.value.room_price))
},
/**
* 一键续订时间
*/
handleChooseRenewTime: (item) => {
console.log("🚀 ~ item:", item)
}
}
</script>

View File

@ -15,3 +15,4 @@ export default store
// 模块统一导出
export * from './user'
export * from './store'

48
src/store/store.ts Normal file
View File

@ -0,0 +1,48 @@
import { defineStore } from 'pinia'
interface IDefaultStoreVo {
id: number
name: string
index: number
}
const defaultStoreState: IDefaultStoreVo = {
id: 0,
name: '',
index: 0,
}
export const useStoreStore = defineStore(
'store',
() => {
// 这里后续可添加店铺管理相关 state、action
const storeList = ref<Array<any>>([])
const defaultStore = ref<IDefaultStoreVo>({...defaultStoreState})
/**
* 设置门店列表
* @param stores
*/
const setStoreList = (stores: Array<any>) => {
storeList.value = stores
}
/**
* 设置默认选择的门店
* @param store
*/
const setDefaultStore = (store: IDefaultStoreVo) => {
defaultStore.value = store
}
return {
setStoreList,
storeList,
defaultStore,
setDefaultStore
}
},
{
persist: true,
},
)

View File

@ -54,8 +54,9 @@ export const useUserStore = defineStore(
const removeUserInfo = () => {
isLoggedIn.value = false
userInfo.value = { ...userInfoState }
uni.removeStorageSync('userInfo')
uni.removeStorageSync('token')
// 清除所有缓存
uni.clearStorageSync()
}
/**
* 获取用户信息
@ -89,9 +90,8 @@ export const useUserStore = defineStore(
/**
* 账号密码登录
*/
const mobileLogin = async (account: string, terminal: number, scene: number) => {
const res = await _mobileLogin({ account, terminal, scene})
console.log("🚀 ~ mobileLogin ~ res:", res)
const mobileLogin = async (account: string, password: string, scene: number, terminal: number, channel: number) => {
const res = await _mobileLogin({ account, password, scene, terminal, channel })
uni.setStorageSync('token', res.token)
await getUserInfo()
@ -103,11 +103,9 @@ export const useUserStore = defineStore(
* 退出登录 并 删除用户信息
*/
const logout = async () => {
// 清除所有缓存
uni.clearStorageSync()
_logout()
const res = await _logout()
removeUserInfo()
return res
}
/**
* 微信登录