修改组件和接口返回信息
This commit is contained in:
15
env/.env
vendored
15
env/.env
vendored
@ -10,13 +10,22 @@ VITE_APP_PUBLIC_BASE=/
|
|||||||
# 登录页面
|
# 登录页面
|
||||||
VITE_LOGIN_URL = '/pages/login/login'
|
VITE_LOGIN_URL = '/pages/login/login'
|
||||||
# 第一个请求地址
|
# 第一个请求地址
|
||||||
VITE_SERVER_BASEURL = 'https://mnp.zhuzhuda.cn'
|
VITE_SERVER_BASEURL = 'https://cz.stnav.com'
|
||||||
|
|
||||||
VITE_UPLOAD_BASEURL = 'https://mnp.zhuzhuda.cn/upload'
|
VITE_UPLOAD_BASEURL = 'https://cz.stnav.com/upload'
|
||||||
|
|
||||||
# h5是否需要配置代理
|
# h5是否需要配置代理
|
||||||
VITE_APP_PROXY=false
|
VITE_APP_PROXY=false
|
||||||
VITE_APP_PROXY_PREFIX = '/api'
|
VITE_APP_PROXY_PREFIX = '/api'
|
||||||
|
|
||||||
# 第二个请求地址 (目前alova中可以使用)
|
# 第二个请求地址 (目前alova中可以使用)
|
||||||
VITE_API_SECONDARY_URL = 'https://mnp.zhuzhuda.cn'
|
VITE_SERVER_BASEURL = 'https://cz.stnav.com'
|
||||||
|
|
||||||
|
# 默认地址
|
||||||
|
VITE_DEFAULT_LONGITUDE = 113.665412
|
||||||
|
VITE_DEFAULT_LATITUDE = 34.757975
|
||||||
|
VITE_DEFAULT_ADDRESS = '上海市'
|
||||||
|
VITE_DEFAULT_LOCATION_EXPIRE_MS = 30 * 24 * 60 * 60 * 1000 # 30天
|
||||||
|
VITE_DEFAULT_LOCATION_EXPIRE_KEY = 'location_expire_time'
|
||||||
|
VITE_DEFAULT_LOCATION_DENY_TIME_KEY = 'location_deny_time'
|
||||||
|
VITE_DEFAULT_LOCATION_DENY_INTERVAL = 60 * 60 * 1000 # 1小时
|
||||||
@ -124,12 +124,18 @@ export default defineManifestConfig({
|
|||||||
es6: true,
|
es6: true,
|
||||||
minified: true,
|
minified: true,
|
||||||
},
|
},
|
||||||
|
requiredPrivateInfos: ["getLocation" ],
|
||||||
optimization: {
|
optimization: {
|
||||||
subPackages: true,
|
subPackages: true,
|
||||||
},
|
},
|
||||||
// styleIsolation: 'shared',
|
// styleIsolation: 'shared',
|
||||||
usingComponents: true,
|
usingComponents: true,
|
||||||
// __usePrivacyCheck__: true,
|
// __usePrivacyCheck__: true,
|
||||||
|
permission: {
|
||||||
|
'scope.userLocation' : {
|
||||||
|
desc : "我们需要获取您的位置,以方便推荐附近茶室给您"
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'mp-alipay': {
|
'mp-alipay': {
|
||||||
usingComponents: true,
|
usingComponents: true,
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import { API_DOMAINS, http } from '@/http/alova'
|
import { API_DOMAINS, http } from '@/http/alova'
|
||||||
|
|
||||||
export interface IFoo {
|
export interface IFoo {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function foo() {
|
export function foo() {
|
||||||
return http.Get<IFoo>('/foo', {
|
return http.Get<IFoo>('/foo', {
|
||||||
params: {
|
params: {
|
||||||
name: '菲鸽',
|
name: '菲鸽',
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
meta: { domain: API_DOMAINS.SECONDARY }, // 用于切换请求地址
|
meta: { domain: API_DOMAINS.SECONDARY }, // 用于切换请求地址
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +5,10 @@ import { http } from '@/http/http'
|
|||||||
* 登录表单
|
* 登录表单
|
||||||
*/
|
*/
|
||||||
export interface ILoginForm {
|
export interface ILoginForm {
|
||||||
username: string
|
username: string
|
||||||
password: string
|
password: string
|
||||||
code: string
|
code: string
|
||||||
uuid: string
|
uuid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,7 +16,7 @@ export interface ILoginForm {
|
|||||||
* @returns ICaptcha 验证码
|
* @returns ICaptcha 验证码
|
||||||
*/
|
*/
|
||||||
export function getCode() {
|
export function getCode() {
|
||||||
return http.get<ICaptcha>('/user/getCode')
|
return http.get<ICaptcha>('/user/getCode')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,35 +24,35 @@ export function getCode() {
|
|||||||
* @param loginForm 登录表单
|
* @param loginForm 登录表单
|
||||||
*/
|
*/
|
||||||
export function login(loginForm: ILoginForm) {
|
export function login(loginForm: ILoginForm) {
|
||||||
return http.post<IUserLogin>('/user/login', loginForm)
|
return http.post<IUserLogin>('/user/login', loginForm)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户信息
|
* 获取用户信息
|
||||||
*/
|
*/
|
||||||
export function getUserInfo() {
|
export function getUserInfo() {
|
||||||
return http.get<IUserInfoVo>('/user/info')
|
return http.get<IUserInfoVo>('/user/info')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出登录
|
* 退出登录
|
||||||
*/
|
*/
|
||||||
export function logout() {
|
export function logout() {
|
||||||
return http.get<void>('/user/logout')
|
return http.get<void>('/user/logout')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改用户信息
|
* 修改用户信息
|
||||||
*/
|
*/
|
||||||
export function updateInfo(data: IUpdateInfo) {
|
export function updateInfo(data: IUpdateInfo) {
|
||||||
return http.post('/user/updateInfo', data)
|
return http.post('/user/updateInfo', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改用户密码
|
* 修改用户密码
|
||||||
*/
|
*/
|
||||||
export function updateUserPassword(data: IUpdatePassword) {
|
export function updateUserPassword(data: IUpdatePassword) {
|
||||||
return http.post('/user/updatePassword', data)
|
return http.post('/user/updatePassword', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,13 +60,13 @@ export function updateUserPassword(data: IUpdatePassword) {
|
|||||||
* @returns Promise 包含微信登录凭证(code)
|
* @returns Promise 包含微信登录凭证(code)
|
||||||
*/
|
*/
|
||||||
export function getWxCode() {
|
export function getWxCode() {
|
||||||
return new Promise<UniApp.LoginRes>((resolve, reject) => {
|
return new Promise<UniApp.LoginRes>((resolve, reject) => {
|
||||||
uni.login({
|
uni.login({
|
||||||
provider: 'weixin',
|
provider: 'weixin',
|
||||||
success: res => resolve(res),
|
success: res => resolve(res),
|
||||||
fail: err => reject(new Error(err)),
|
fail: err => reject(new Error(err)),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,5 +79,5 @@ export function getWxCode() {
|
|||||||
* @returns Promise 包含登录结果
|
* @returns Promise 包含登录结果
|
||||||
*/
|
*/
|
||||||
export function wxLogin(data: { code: string }) {
|
export function wxLogin(data: { code: string }) {
|
||||||
return http.post<IUserLogin>('/user/wxLogin', data)
|
return http.post<IUserLogin>('/user/wxLogin', data)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,14 @@
|
|||||||
*/
|
*/
|
||||||
export interface IUserInfoVo {
|
export interface IUserInfoVo {
|
||||||
id: number
|
id: number
|
||||||
username: string
|
nickname: string
|
||||||
avatar: string
|
avatar: string
|
||||||
token: string
|
token: string
|
||||||
|
sn: string
|
||||||
|
account: string
|
||||||
|
channel: number
|
||||||
|
is_new_user: number
|
||||||
|
mobile: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
125
src/components/Pay.vue
Normal file
125
src/components/Pay.vue
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<view class="pay-radio">
|
||||||
|
<wd-radio-group v-model="pay" shape="dot" checked-color="#4C9F44" @change="Pay.handleChangePay">
|
||||||
|
<block v-for="(item, index) in PayList" :key="index">
|
||||||
|
<wd-radio :value="item.value">
|
||||||
|
<view
|
||||||
|
class="flex justify-between items-center"
|
||||||
|
v-if="!(hidePlatformBalance && item.type === PayCategory.PlatformBalance) && !(hideStoreBalance && item.type === PayCategory.StoreBalance) && !(hideWechat && item.type === PayCategory.WeChatPay)"
|
||||||
|
>
|
||||||
|
<view class="flex items-center">
|
||||||
|
<wd-img width="50rpx" height="50rpx" :src="`${OSS}${item.icon}`"></wd-img>
|
||||||
|
<view class="ml-20rpx text-30rpx text-[#303133] leading-42rpx">{{ item.name }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="absolute right-0 top-6rpx right-60rpx" v-if="item.type !== PayCategory.WeChatPay">可用{{ userInfo.user_money }}</view>
|
||||||
|
</wd-radio>
|
||||||
|
</block>
|
||||||
|
</wd-radio-group>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="RechargeBtn">
|
||||||
|
/**
|
||||||
|
* Pay 支付组件
|
||||||
|
* @description 用于展示支付
|
||||||
|
*/
|
||||||
|
import { PayList as OriginPayList, PayCategory, PayValue } from '@/utils/pay'
|
||||||
|
import { IUserInfoResult } from '@/api/types/user'
|
||||||
|
import { getUserInfo } from '@/api/user'
|
||||||
|
|
||||||
|
const OSS = inject('OSS')
|
||||||
|
const pay = ref<number>() // 支付方式
|
||||||
|
|
||||||
|
// 当前用户信息
|
||||||
|
const userInfo = reactive<IUserInfoResult>({
|
||||||
|
account: '',
|
||||||
|
avatar: '',
|
||||||
|
create_time: '',
|
||||||
|
has_auth: false,
|
||||||
|
has_password: false,
|
||||||
|
id: 0,
|
||||||
|
mobile: '',
|
||||||
|
nickname: '',
|
||||||
|
real_name: '',
|
||||||
|
sex: '',
|
||||||
|
sn: 0,
|
||||||
|
user_money: '',
|
||||||
|
version: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 获取个人用户信息
|
||||||
|
const userRes = await getUserInfo()
|
||||||
|
Object.assign(userInfo, userRes || {})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
// 是否隐藏平台余额支付
|
||||||
|
hidePlatformBalance: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
// 是否隐藏门店余额支付
|
||||||
|
hideStoreBalance: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
// 是否隐藏微信支付
|
||||||
|
hideWechat: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定义emit事件
|
||||||
|
const emit = defineEmits(['pay'])
|
||||||
|
|
||||||
|
const Pay = {
|
||||||
|
// 支付方式改变
|
||||||
|
handleChangePay(e: {value: number}) {
|
||||||
|
emit('pay', e.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PayList = computed(() => {
|
||||||
|
return OriginPayList.filter(item => {
|
||||||
|
if (props.hidePlatformBalance && item.type === PayCategory.PlatformBalance) return false
|
||||||
|
if (props.hideStoreBalance && item.type === PayCategory.StoreBalance) return false
|
||||||
|
if (props.hideWechat && item.type === PayCategory.WeChatPay) return false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(PayList, (list) => {
|
||||||
|
if (list.length > 0) {
|
||||||
|
pay.value = list[0].value
|
||||||
|
emit('pay', pay.value )
|
||||||
|
} else {
|
||||||
|
pay.value = undefined
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.pay-radio {
|
||||||
|
:deep() {
|
||||||
|
.wd-radio {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-radio:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
54
src/components/TeaSpecialistLevel.vue
Normal file
54
src/components/TeaSpecialistLevel.vue
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-168rpx h-40rpx relative mr-44rpx">
|
||||||
|
<view class="absolute left-0 top-0 h-36rpx flex items-start">
|
||||||
|
<!-- 金牌茶艺师 -->
|
||||||
|
<wd-img :src="levelMap[level].icon" width="36rpx" height="36rpx"></wd-img>
|
||||||
|
</view>
|
||||||
|
<view class="bg-[#F0F6EF] text-[#006C2D] font-400 text-22rpx leading-32rpx rounded-4rpx text-center w-150rpx ml-18rpx pb-4rpx">{{ levelMap[level].text }}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="TeaSpecialistLevel">
|
||||||
|
/**
|
||||||
|
* TeaSpecialistLevel 茶艺师等级
|
||||||
|
* @description 用于展示茶艺师等级
|
||||||
|
*/
|
||||||
|
|
||||||
|
const OSS = inject('OSS')
|
||||||
|
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
level: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 茶艺师等级对应的icon和文字
|
||||||
|
const levelMap = {
|
||||||
|
gold: {
|
||||||
|
icon: `${OSS}icon/icon_gold_medal.png`,
|
||||||
|
text: '金牌茶艺师'
|
||||||
|
},
|
||||||
|
senior: {
|
||||||
|
icon: `${OSS}icon/icon_senior_medal.png`,
|
||||||
|
text: '高级茶艺师'
|
||||||
|
},
|
||||||
|
intermediate: {
|
||||||
|
icon: `${OSS}icon/icon_intermediate_medal.png`,
|
||||||
|
text: '中级茶艺师'
|
||||||
|
},
|
||||||
|
junior: {
|
||||||
|
icon: `${OSS}icon/icon_junior_medal.png`,
|
||||||
|
text: '初级茶艺师'
|
||||||
|
},
|
||||||
|
enthusiast: {
|
||||||
|
icon: `${OSS}icon/icon_enthusiast_medal.png`,
|
||||||
|
text: '茶艺爱好者'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
82
src/hooks/useLocation.ts
Normal file
82
src/hooks/useLocation.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { router } from '@/utils/tools'
|
||||||
|
|
||||||
|
|
||||||
|
const LOCATION_EXPIRE_KEY = import.meta.env.VITE_DEFAULT_LOCATION_EXPIRE_KEY // 定位缓存KEY
|
||||||
|
const LOCATION_EXPIRE_MS = import.meta.env.VITE_DEFAULT_LOCATION_EXPIRE_MS // 30天
|
||||||
|
const LOCATION_DEFAULT_CITY = import.meta.env.VITE_DEFAULT_ADDRESS // 默认城市
|
||||||
|
const LOCATION_DEFAULT_LAT = import.meta.env.VITE_DEFAULT_LATITUDE // 上海经度
|
||||||
|
const LOCATION_DEFAULT_LNG = import.meta.env.VITE_DEFAULT_LONGITUDE // 上海纬度
|
||||||
|
const LOCATION_DENY_TIME_KEY = import.meta.env.VITE_DEFAULT_LOCATION_DENY_TIME_KEY
|
||||||
|
const LOCATION_DENY_INTERVAL = import.meta.env.VITE_DEFAULT_LOCATION_DENY_INTERVAL
|
||||||
|
|
||||||
|
// 检查过期时间
|
||||||
|
export function handleCheckLocationCacheHooks() {
|
||||||
|
const expire = uni.getStorageSync(LOCATION_EXPIRE_KEY)
|
||||||
|
if (expire && Date.now() > expire) {
|
||||||
|
uni.removeStorageSync('latitude')
|
||||||
|
uni.removeStorageSync('longitude')
|
||||||
|
uni.removeStorageSync(LOCATION_EXPIRE_KEY)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置经纬度缓存
|
||||||
|
export function handleSetLocationCacheHooks(lat: number, lng: number) {
|
||||||
|
uni.setStorageSync('latitude', lat)
|
||||||
|
uni.setStorageSync('longitude', lng)
|
||||||
|
uni.setStorageSync(LOCATION_EXPIRE_KEY, Date.now() + LOCATION_EXPIRE_MS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化经纬度
|
||||||
|
export async function handleEnsureLocationAuthHooks() {
|
||||||
|
// 1. 检查缓存
|
||||||
|
if (handleCheckLocationCacheHooks()) {
|
||||||
|
const lat = uni.getStorageSync('latitude')
|
||||||
|
const lng = uni.getStorageSync('longitude')
|
||||||
|
if (lat && lng) return { lat, lng }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取定位
|
||||||
|
return new Promise<{ lat: number, lng: number }>((resolve) => {
|
||||||
|
uni.authorize({
|
||||||
|
scope: 'scope.userLocation',
|
||||||
|
success() {
|
||||||
|
uni.getLocation({
|
||||||
|
type: 'gcj02',
|
||||||
|
success(res) {
|
||||||
|
handleSetLocationCacheHooks(res.latitude, res.longitude)
|
||||||
|
resolve({ lat: res.latitude, lng: res.longitude })
|
||||||
|
},
|
||||||
|
fail() {
|
||||||
|
// 定位失败,返回默认上海
|
||||||
|
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fail() {
|
||||||
|
// 用户拒绝授权
|
||||||
|
if (shouldShowAuthModal()) {
|
||||||
|
uni.setStorageSync(LOCATION_DENY_TIME_KEY, Date.now())
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '需要获取您的地理位置,请授权定位服务',
|
||||||
|
showCancel: false,
|
||||||
|
success: () => {
|
||||||
|
// 可引导用户去设置页面
|
||||||
|
uni.openSetting({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 返回默认上海
|
||||||
|
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否需要弹授权框
|
||||||
|
function shouldShowAuthModal() {
|
||||||
|
const lastDeny = uni.getStorageSync(LOCATION_DENY_TIME_KEY)
|
||||||
|
return !lastDeny || (Date.now() - lastDeny > LOCATION_DENY_INTERVAL)
|
||||||
|
}
|
||||||
@ -6,6 +6,8 @@ import { createServerTokenAuthentication } from 'alova/client'
|
|||||||
import VueHook from 'alova/vue'
|
import VueHook from 'alova/vue'
|
||||||
import { toast } from '@/utils/toast'
|
import { toast } from '@/utils/toast'
|
||||||
import { ContentTypeEnum, ResultEnum, ShowMessage } from './tools/enum'
|
import { ContentTypeEnum, ResultEnum, ShowMessage } from './tools/enum'
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
import { router } from '@/utils/tools'
|
||||||
|
|
||||||
// 配置动态Tag
|
// 配置动态Tag
|
||||||
export const API_DOMAINS = {
|
export const API_DOMAINS = {
|
||||||
@ -59,11 +61,22 @@ const alovaInstance = createAlova({
|
|||||||
console.log('ignoreAuth===>', ignoreAuth)
|
console.log('ignoreAuth===>', ignoreAuth)
|
||||||
// 处理认证信息 自行处理认证问题
|
// 处理认证信息 自行处理认证问题
|
||||||
if (ignoreAuth) {
|
if (ignoreAuth) {
|
||||||
const token = 'getToken()'
|
// const token = 'getToken()'
|
||||||
|
// if (!token) {
|
||||||
|
// throw new Error('[请求错误]:未登录')
|
||||||
|
// }
|
||||||
|
// method.config.headers.token = token;
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { token } = userStore.userInfo as unknown as IUserInfo
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
toast.info('请先登录')
|
||||||
|
router.switchTab('/pages/my/my', 500)
|
||||||
throw new Error('[请求错误]:未登录')
|
throw new Error('[请求错误]:未登录')
|
||||||
}
|
}
|
||||||
// method.config.headers.token = token;
|
|
||||||
|
method.config.headers.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理动态域名
|
// 处理动态域名
|
||||||
@ -96,13 +109,29 @@ const alovaInstance = createAlova({
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// 处理业务逻辑错误
|
// 处理业务逻辑错误
|
||||||
const { code, message, data } = rawData as IResponse
|
const { code, msg, data } = rawData as IResponse
|
||||||
// if (code !== ResultEnum.Success) {
|
if (code === ResultEnum.Unauthorized) {
|
||||||
// if (config.meta?.toast !== false) {
|
useUserStore().removeUserInfo()
|
||||||
// toast.warning(message)
|
|
||||||
// }
|
if (config.meta?.toast !== false) {
|
||||||
// throw new Error(`请求错误[${code}]:${message}`)
|
toast.info(msg)
|
||||||
// }
|
router.switchTab('/pages/my/my', 1000)
|
||||||
|
}
|
||||||
|
throw new Error(`登录超时[${code}]:${msg}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code === ResultEnum.Success) {
|
||||||
|
if (config.meta?.toast !== false && msg) {
|
||||||
|
if (msg !== '查询成功') toast.info(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code !== ResultEnum.Success) {
|
||||||
|
if (config.meta?.toast !== false) {
|
||||||
|
toast.warning(msg)
|
||||||
|
}
|
||||||
|
throw new Error(`请求错误[${code}]:${msg}`)
|
||||||
|
}
|
||||||
// 处理成功响应,返回业务数据
|
// 处理成功响应,返回业务数据
|
||||||
return data
|
return data
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export type CustomRequestOptions = UniApp.RequestOptions & {
|
|||||||
export interface IResponse<T = any> {
|
export interface IResponse<T = any> {
|
||||||
code: number | string
|
code: number | string
|
||||||
data: T
|
data: T
|
||||||
message: string
|
msg: string
|
||||||
status: string | number
|
status: string | number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -90,8 +90,16 @@
|
|||||||
"minified": true
|
"minified": true
|
||||||
},
|
},
|
||||||
"usingComponents": true,
|
"usingComponents": true,
|
||||||
|
"requiredPrivateInfos": [
|
||||||
|
"getLocation"
|
||||||
|
],
|
||||||
"optimization": {
|
"optimization": {
|
||||||
"subPackages": true
|
"subPackages": true
|
||||||
|
},
|
||||||
|
"permission": {
|
||||||
|
"scope.userLocation": {
|
||||||
|
"desc": "我们需要获取您的位置,以方便推荐附近工厂给您"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mp-alipay": {
|
"mp-alipay": {
|
||||||
|
|||||||
@ -13,13 +13,13 @@
|
|||||||
<view class="home-bg w-[100%] fixed top-0 left-0 z-100">
|
<view class="home-bg w-[100%] fixed top-0 left-0 z-100">
|
||||||
<wd-navbar safeAreaInsetTop :bordered="false" custom-style="background-color: transparent !important;">
|
<wd-navbar safeAreaInsetTop :bordered="false" custom-style="background-color: transparent !important;">
|
||||||
<template #left>
|
<template #left>
|
||||||
<view class="flex items-center line-1 w-130rpx" @click="home.toCity">
|
<view class="flex items-center line-1 w-130rpx" @click="Index.toCity">
|
||||||
<view class="mr-10rpx font-400 leading-44rpx text-32rpx pl-10rpx line-1">上海市</view>
|
<view class="mr-10rpx font-400 leading-44rpx text-32rpx pl-10rpx line-1">上海市</view>
|
||||||
<wd-img width="14rpx" height="9rpx" :src="`${OSS}icon/icon_arrow_down.png`" />
|
<wd-img width="14rpx" height="9rpx" :src="`${OSS}icon/icon_arrow_down.png`" />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<view class="search-box flex items-center ml-26rpx" @click="home.toSearch">
|
<view class="search-box flex items-center ml-26rpx" @click="Index.toSearch">
|
||||||
<wd-search placeholder="搜索茶址名称" hide-cancel disabled :placeholder-left="true"
|
<wd-search placeholder="搜索茶址名称" hide-cancel disabled :placeholder-left="true"
|
||||||
placeholderStyle="text-align:left;padding-left: 24rpx;line-heigt: 44rpx;color: #C9C9C9; font-size: 32rpx;font-weight: normal;">
|
placeholderStyle="text-align:left;padding-left: 24rpx;line-heigt: 44rpx;color: #C9C9C9; font-size: 32rpx;font-weight: normal;">
|
||||||
</wd-search>
|
</wd-search>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<view class="mt-32rpx mx-30rpx">
|
<view class="mt-32rpx mx-30rpx">
|
||||||
<wd-swiper value-key="image" height="240rpx" indicatorPosition="bottom-left"
|
<wd-swiper value-key="image" height="240rpx" indicatorPosition="bottom-left"
|
||||||
:indicator="{ type: 'dots-bar' }" :list="swiperList" v-model:current="current"
|
:indicator="{ type: 'dots-bar' }" :list="swiperList" v-model:current="current"
|
||||||
@click="home.handleClick" @change="home.onChange" mode="aspectFit"></wd-swiper>
|
@click="Index.handleClick" @change="Index.onChange" mode="aspectFit"></wd-swiper>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="mt-40rpx flex items-center h-36rpx mx-30rpx">
|
<view class="mt-40rpx flex items-center h-36rpx mx-30rpx">
|
||||||
@ -56,9 +56,9 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view>
|
<view>
|
||||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="home.upCallback" top="28rpx"
|
<mescroll-body @init="mescrollInit" @down="downCallback" @up="Index.upCallback" top="28rpx"
|
||||||
:fixed="true">
|
:fixed="true">
|
||||||
<view class="relative p-20rp mb-24rpx" v-for="(item, index) in 100" :key="index" @click="home.handleToReserveRoom(item)">
|
<view class="relative p-20rp mb-24rpx" v-for="(item, index) in 100" :key="index" @click="Index.handleToReserveRoom(item)">
|
||||||
<view class="absolute top--28rpx left-0 z-1">
|
<view class="absolute top--28rpx left-0 z-1">
|
||||||
<wd-img width="110rpx" height="110rpx" :src="`${OSS}images/home/home_image4.png`"/>
|
<wd-img width="110rpx" height="110rpx" :src="`${OSS}images/home/home_image4.png`"/>
|
||||||
</view>
|
</view>
|
||||||
@ -108,7 +108,8 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||||
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";
|
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js"
|
||||||
|
import { handleEnsureLocationAuthHooks } from '@/hooks/useLocation'
|
||||||
|
|
||||||
const OSS = inject('OSS')
|
const OSS = inject('OSS')
|
||||||
const navbarHeight = inject('navbarHeight')
|
const navbarHeight = inject('navbarHeight')
|
||||||
@ -120,14 +121,18 @@
|
|||||||
`${OSS}images/banner1.png`
|
`${OSS}images/banner1.png`
|
||||||
])
|
])
|
||||||
const current = ref<number>(0)
|
const current = ref<number>(0)
|
||||||
/** 结束 **/
|
|
||||||
|
|
||||||
|
// 分页
|
||||||
const { mescrollInit, downCallback } = useMescroll(onPageScroll, onReachBottom) // 调用mescroll的hook
|
const { mescrollInit, downCallback } = useMescroll(onPageScroll, onReachBottom) // 调用mescroll的hook
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad(async() => {
|
||||||
|
// 获取用户经纬度(带缓存和授权逻辑)
|
||||||
|
const { lat, lng } = await handleEnsureLocationAuthHooks()
|
||||||
|
// 你可以在这里根据经纬度做后续处理,比如请求附近门店等
|
||||||
|
console.log('当前定位:', lat, lng)
|
||||||
})
|
})
|
||||||
|
|
||||||
const home = {
|
const Index = {
|
||||||
toCity: () => {
|
toCity: () => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/city/city'
|
url: '/pages/city/city'
|
||||||
|
|||||||
@ -10,12 +10,19 @@ import {
|
|||||||
} from '@/api/login'
|
} from '@/api/login'
|
||||||
import { toast } from '@/utils/toast'
|
import { toast } from '@/utils/toast'
|
||||||
|
|
||||||
|
const defaultAvatar = 'https://shchazhi.oss-cn-hangzhou.aliyuncs.com/fronted/icon/icon_avatar.png'
|
||||||
|
|
||||||
// 初始化状态
|
// 初始化状态
|
||||||
const userInfoState: IUserInfoVo = {
|
const userInfoState: IUserInfoVo = {
|
||||||
id: 0,
|
id: 0,
|
||||||
username: '',
|
nickname: '',
|
||||||
avatar: '/static/images/default-avatar.png',
|
avatar: defaultAvatar,
|
||||||
token: '',
|
token: '',
|
||||||
|
sn: '',
|
||||||
|
account: '',
|
||||||
|
channel: 0,
|
||||||
|
is_new_user: 1,
|
||||||
|
mobile: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = defineStore(
|
export const useUserStore = defineStore(
|
||||||
@ -31,7 +38,7 @@ export const useUserStore = defineStore(
|
|||||||
val.avatar = userInfoState.avatar
|
val.avatar = userInfoState.avatar
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val.avatar = 'https://oss.laf.run/ukw0y1-site/avatar.jpg?feige'
|
val.avatar = defaultAvatar
|
||||||
}
|
}
|
||||||
userInfo.value = val
|
userInfo.value = val
|
||||||
}
|
}
|
||||||
@ -103,6 +110,8 @@ export const useUserStore = defineStore(
|
|||||||
getUserInfo,
|
getUserInfo,
|
||||||
setUserAvatar,
|
setUserAvatar,
|
||||||
logout,
|
logout,
|
||||||
|
setUserInfo,
|
||||||
|
removeUserInfo
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
26
src/utils/teaSpecialist.ts
Normal file
26
src/utils/teaSpecialist.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 茶艺师等级枚举
|
||||||
|
export enum TeaSpecialistLevel {
|
||||||
|
Gold = '金牌茶艺师',
|
||||||
|
Senior = '高级茶艺师',
|
||||||
|
Intermediate = '中级茶艺师',
|
||||||
|
Junior = '初级茶艺师',
|
||||||
|
Enthusiast = '茶艺爱好者'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单来源对应名称
|
||||||
|
export const TeaSpecialistLevelValue = {
|
||||||
|
['金牌茶艺师']: 'gold',
|
||||||
|
['高级茶艺师']: 'senior',
|
||||||
|
['中级茶艺师']: 'intermediate',
|
||||||
|
['初级茶艺师']: 'junior',
|
||||||
|
['茶艺爱好者']: 'enthusiast',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 茶艺师对象结构
|
||||||
|
export const TeaSpecialistLevels = [
|
||||||
|
{ id: 1, value: 'gold', label: TeaSpecialistLevel.Gold},
|
||||||
|
{ id: 2, value: 'senior', label: TeaSpecialistLevel.Senior },
|
||||||
|
{ id: 3, value: 'intermediate', label: TeaSpecialistLevel.Intermediate },
|
||||||
|
{ id: 4, value: 'junior', label: TeaSpecialistLevel.Junior },
|
||||||
|
{ id: 5, value: 'enthusiast', label: TeaSpecialistLevel.Enthusiast }
|
||||||
|
];
|
||||||
125
src/utils/tools.ts
Normal file
125
src/utils/tools.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import Decimal from 'decimal.js'
|
||||||
|
import { allowedNodeEnvironmentFlags } from 'process';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面跳转方法
|
||||||
|
* @param url 跳转地址
|
||||||
|
* @param time 延迟时间(毫秒),默认0
|
||||||
|
*/
|
||||||
|
export const router = {
|
||||||
|
//跳转至非table页面
|
||||||
|
navigateTo: (url: string, time = 0) => {
|
||||||
|
setTimeout(function() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url
|
||||||
|
})
|
||||||
|
}, time);
|
||||||
|
},
|
||||||
|
|
||||||
|
//跳转至 table
|
||||||
|
switchTab: (url: string, time = 0) => {
|
||||||
|
setTimeout(function() {
|
||||||
|
uni.switchTab({
|
||||||
|
url
|
||||||
|
})
|
||||||
|
}, time);
|
||||||
|
},
|
||||||
|
|
||||||
|
//返回上页面
|
||||||
|
navigateBack: (delta: number = 1, time = 0) => {
|
||||||
|
setTimeout(function() {
|
||||||
|
uni.navigateBack({
|
||||||
|
delta
|
||||||
|
})
|
||||||
|
}, time);
|
||||||
|
},
|
||||||
|
|
||||||
|
//关闭当前所有页面跳转至非table页面
|
||||||
|
reLaunch: (url: string, time = 0) => {
|
||||||
|
setTimeout(function() {
|
||||||
|
uni.reLaunch({
|
||||||
|
url
|
||||||
|
})
|
||||||
|
}, time);
|
||||||
|
},
|
||||||
|
|
||||||
|
//关闭当前页面跳转至非table页面
|
||||||
|
redirectTo: (url: string, time = 0) => {
|
||||||
|
setTimeout(function() {
|
||||||
|
uni.redirectTo({
|
||||||
|
url
|
||||||
|
})
|
||||||
|
}, time);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 乘法,避免浮点数精度问题,不进行四舍五入,直接截断
|
||||||
|
* @param num1 乘数1
|
||||||
|
* @param num2 乘数2
|
||||||
|
* @returns 乘积
|
||||||
|
*/
|
||||||
|
export function toTimes(num1: number, num2: number) {
|
||||||
|
const value1 = new Decimal(num1)
|
||||||
|
const value2 = new Decimal(num2)
|
||||||
|
const result = value1.times(value2).toDecimalPlaces(2, Decimal.ROUND_DOWN)
|
||||||
|
console.log("🚀 ~ toPlus ~ result:", result)
|
||||||
|
|
||||||
|
return result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加法,避免浮点数精度问题,不进行四舍五入,直接截断
|
||||||
|
* @param args 任意数量的加数
|
||||||
|
* @returns 求和结果字符串,保留2位小数(向下截断)
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 加法,支持对象参数(如 {0: '128', 1: '128'}),避免浮点数精度问题,不进行四舍五入,直接截断
|
||||||
|
* @param args 任意数量的加数或对象
|
||||||
|
* @returns 求和结果字符串,保留2位小数(向下截断)
|
||||||
|
*/
|
||||||
|
export function toPlus(...args: any[]): string {
|
||||||
|
// 支持 toPlus({0: '128', 1: '128'}) 或 toPlus('128', '128')
|
||||||
|
let arr: any[] = []
|
||||||
|
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
|
||||||
|
// 传入的是对象,取所有值
|
||||||
|
arr = Object.values(args[0])
|
||||||
|
} else {
|
||||||
|
arr = args
|
||||||
|
}
|
||||||
|
let sum = new Decimal(0)
|
||||||
|
for (const num of arr) {
|
||||||
|
// 自动转为数字
|
||||||
|
const n = Number(num)
|
||||||
|
if (!isNaN(n)) {
|
||||||
|
sum = sum.plus(new Decimal(n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 截断2位小数,不四舍五入
|
||||||
|
const result = sum.toDecimalPlaces(2, Decimal.ROUND_DOWN)
|
||||||
|
return result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 减法,支持对象参数(如 {0: '128', 1: '28'}),避免浮点数精度问题,不进行四舍五入,直接截断
|
||||||
|
* @param args 任意数量的被减数和减数或对象
|
||||||
|
* @returns 结果字符串,保留2位小数(向下截断)
|
||||||
|
*/
|
||||||
|
export function toMinus(...args: any[]): string {
|
||||||
|
// 支持 toMinus({0: '128', 1: '28'}) 或 toMinus('128', '28')
|
||||||
|
let arr: any[] = []
|
||||||
|
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
|
||||||
|
arr = Object.values(args[0])
|
||||||
|
} else {
|
||||||
|
arr = args
|
||||||
|
}
|
||||||
|
if (arr.length === 0) return '0.00'
|
||||||
|
let result = new Decimal(Number(arr[0]) || 0)
|
||||||
|
for (let i = 1; i < arr.length; i++) {
|
||||||
|
const n = Number(arr[i])
|
||||||
|
if (!isNaN(n)) {
|
||||||
|
result = result.minus(new Decimal(n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toDecimalPlaces(2, Decimal.ROUND_DOWN).toString()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user