修改组件和接口返回信息
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_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是否需要配置代理
|
||||
VITE_APP_PROXY=false
|
||||
VITE_APP_PROXY_PREFIX = '/api'
|
||||
|
||||
# 第二个请求地址 (目前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,
|
||||
minified: true,
|
||||
},
|
||||
requiredPrivateInfos: ["getLocation" ],
|
||||
optimization: {
|
||||
subPackages: true,
|
||||
},
|
||||
// styleIsolation: 'shared',
|
||||
usingComponents: true,
|
||||
// __usePrivacyCheck__: true,
|
||||
permission: {
|
||||
'scope.userLocation' : {
|
||||
desc : "我们需要获取您的位置,以方便推荐附近茶室给您"
|
||||
}
|
||||
},
|
||||
},
|
||||
'mp-alipay': {
|
||||
usingComponents: true,
|
||||
|
||||
@ -3,9 +3,14 @@
|
||||
*/
|
||||
export interface IUserInfoVo {
|
||||
id: number
|
||||
username: string
|
||||
nickname: string
|
||||
avatar: 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 { toast } from '@/utils/toast'
|
||||
import { ContentTypeEnum, ResultEnum, ShowMessage } from './tools/enum'
|
||||
import { useUserStore } from '@/store'
|
||||
import { router } from '@/utils/tools'
|
||||
|
||||
// 配置动态Tag
|
||||
export const API_DOMAINS = {
|
||||
@ -59,11 +61,22 @@ const alovaInstance = createAlova({
|
||||
console.log('ignoreAuth===>', 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) {
|
||||
toast.info('请先登录')
|
||||
router.switchTab('/pages/my/my', 500)
|
||||
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
|
||||
// if (code !== ResultEnum.Success) {
|
||||
// if (config.meta?.toast !== false) {
|
||||
// toast.warning(message)
|
||||
// }
|
||||
// throw new Error(`请求错误[${code}]:${message}`)
|
||||
// }
|
||||
const { code, msg, data } = rawData as IResponse
|
||||
if (code === ResultEnum.Unauthorized) {
|
||||
useUserStore().removeUserInfo()
|
||||
|
||||
if (config.meta?.toast !== false) {
|
||||
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
|
||||
}),
|
||||
|
||||
@ -11,7 +11,7 @@ export type CustomRequestOptions = UniApp.RequestOptions & {
|
||||
export interface IResponse<T = any> {
|
||||
code: number | string
|
||||
data: T
|
||||
message: string
|
||||
msg: string
|
||||
status: string | number
|
||||
}
|
||||
|
||||
|
||||
@ -90,8 +90,16 @@
|
||||
"minified": true
|
||||
},
|
||||
"usingComponents": true,
|
||||
"requiredPrivateInfos": [
|
||||
"getLocation"
|
||||
],
|
||||
"optimization": {
|
||||
"subPackages": true
|
||||
},
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "我们需要获取您的位置,以方便推荐附近工厂给您"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mp-alipay": {
|
||||
|
||||
@ -13,13 +13,13 @@
|
||||
<view class="home-bg w-[100%] fixed top-0 left-0 z-100">
|
||||
<wd-navbar safeAreaInsetTop :bordered="false" custom-style="background-color: transparent !important;">
|
||||
<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>
|
||||
<wd-img width="14rpx" height="9rpx" :src="`${OSS}icon/icon_arrow_down.png`" />
|
||||
</view>
|
||||
</template>
|
||||
<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"
|
||||
placeholderStyle="text-align:left;padding-left: 24rpx;line-heigt: 44rpx;color: #C9C9C9; font-size: 32rpx;font-weight: normal;">
|
||||
</wd-search>
|
||||
@ -32,7 +32,7 @@
|
||||
<view class="mt-32rpx mx-30rpx">
|
||||
<wd-swiper value-key="image" height="240rpx" indicatorPosition="bottom-left"
|
||||
: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 class="mt-40rpx flex items-center h-36rpx mx-30rpx">
|
||||
@ -56,9 +56,9 @@
|
||||
</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">
|
||||
<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">
|
||||
<wd-img width="110rpx" height="110rpx" :src="`${OSS}images/home/home_image4.png`"/>
|
||||
</view>
|
||||
@ -108,7 +108,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
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 navbarHeight = inject('navbarHeight')
|
||||
@ -120,14 +121,18 @@
|
||||
`${OSS}images/banner1.png`
|
||||
])
|
||||
const current = ref<number>(0)
|
||||
/** 结束 **/
|
||||
|
||||
// 分页
|
||||
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: () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/city/city'
|
||||
|
||||
@ -10,12 +10,19 @@ import {
|
||||
} from '@/api/login'
|
||||
import { toast } from '@/utils/toast'
|
||||
|
||||
const defaultAvatar = 'https://shchazhi.oss-cn-hangzhou.aliyuncs.com/fronted/icon/icon_avatar.png'
|
||||
|
||||
// 初始化状态
|
||||
const userInfoState: IUserInfoVo = {
|
||||
id: 0,
|
||||
username: '',
|
||||
avatar: '/static/images/default-avatar.png',
|
||||
nickname: '',
|
||||
avatar: defaultAvatar,
|
||||
token: '',
|
||||
sn: '',
|
||||
account: '',
|
||||
channel: 0,
|
||||
is_new_user: 1,
|
||||
mobile: ''
|
||||
}
|
||||
|
||||
export const useUserStore = defineStore(
|
||||
@ -31,7 +38,7 @@ export const useUserStore = defineStore(
|
||||
val.avatar = userInfoState.avatar
|
||||
}
|
||||
else {
|
||||
val.avatar = 'https://oss.laf.run/ukw0y1-site/avatar.jpg?feige'
|
||||
val.avatar = defaultAvatar
|
||||
}
|
||||
userInfo.value = val
|
||||
}
|
||||
@ -103,6 +110,8 @@ export const useUserStore = defineStore(
|
||||
getUserInfo,
|
||||
setUserAvatar,
|
||||
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