完善功能

This commit is contained in:
wangxiaowei
2025-11-29 20:50:19 +08:00
parent 67c8e8e016
commit d38d4419d9
20 changed files with 403 additions and 98 deletions

View File

@ -2,17 +2,21 @@
import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
import { navigateToInterceptor } from '@/router/interceptor'
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
import { LOCATION_DEFAULT_CITY, LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG, LOCATION_LAT_KEY, LOCATION_LNG_KEY, LOCATION_CITY_KEY } from '@/hooks/useLocation'
onLaunch((options) => {
// 处理直接进入页面路由的情况如h5直接输入路由、微信小程序分享后进入等
// https://github.com/unibest-tech/unibest/issues/192
console.log('App Launch', options)
if (options?.path) {
navigateToInterceptor.invoke({ url: `/${options.path}` })
}
else {
navigateToInterceptor.invoke({ url: '/' })
}
// uni.setStorageSync(LOCATION_LAT_KEY, LOCATION_DEFAULT_LAT)
// uni.setStorageSync(LOCATION_LNG_KEY, LOCATION_DEFAULT_LNG)
// uni.setStorageSync(LOCATION_CITY_KEY, LOCATION_DEFAULT_CITY)
})
onShow((options) => {
console.log('App Show', options)

View File

@ -10,6 +10,37 @@ import type {
} from '@/api/types/tea-room'
import type { ITeaSpecialistFuture7DaysResult, ITeaSpecialistOrderDetailsResult } from '@/api/types/tea'
/**
* 经纬度转换为城市
*/
export interface ILocationToCityParams {
latitude: number
longitude: number
}
export function getLocationToCity(data: ILocationToCityParams) {
return http.Post<{
message: string
result: {
ad_info: {
province: string
city: string
district: string
adcode: string
},
location: {
lat: number
lng: number
}
}
}>('/api/common/cityAddress',
data,
{
meta: { ignoreAuth: true }
}
)
}
/**
* 获取门店列表
*/
@ -296,7 +327,7 @@ export function getTeaRoomPackageOrderDetail(data: ITeaRoomPackageOrderDetailPar
export interface ICalculateTeaRoomPriceParams {
room_id: number // 房间id
coupon_id: number // 优惠券id
group_id: number // 团购券id
group_coupon_id: number // 团购券id
nums: number // 提交的小时数
}

View File

@ -114,6 +114,8 @@ export interface ITeaRoomPackageOrderDetailsResult {
order_status: number
dtime: string
pay_dtime: string
coupon_code?: string,
coupon_code_img?: string,
group: {
id: number
title: string

View File

@ -132,3 +132,20 @@ export interface IGetUserMoneyLogParams {
export function getUserMoneyLog(data: IGetUserMoneyLogParams) {
return http.Post<IOrderListResult>('/api/user/moneyLogList', data)
}
/**
* 修改用户信息
*/
export interface IUpdateUserInfoParams {
field: string,
value: string | number
}
export function updateUserInfo(data: IUpdateUserInfoParams) {
return http.Post('/api/user/setInfo', data)
}
/**
* 上传头像
*/

View File

@ -195,12 +195,13 @@
<view class="bg-white rounded-16rpx p-30rpx">
<view class="flex items-center">
<view class="mr-30rpx">
<wd-img width="190rpx" height="190rpx" :src="`${OSS}images/home/home_image5.png`" mode="scaleToFill"></wd-img>
<!-- <wd-img width="190rpx" height="190rpx" :src="`${OSS}images/home/home_image5.png`" mode="scaleToFill"></wd-img> -->
<wd-img width="190rpx" height="190rpx" :src="comboOrder.group.img" mode="scaleToFill" v-if="orderType === OrderSource.Combo"></wd-img>
</view>
<view class="flex-1">
<!-- 非茶艺师退款 -->
<view class="flex justify-between items-center" @click="AfterSales.handleToCombo" v-if="orderType !== OrderSource.TeaSpecialist">
<view class="font-bold text-30rpx leading-42rpx text-[#303133] mr-10rpx w-362rpx line-1">这是团购套餐的可以点击进 </view>
<view class="flex justify-between items-center" @click="handleToTGComboHooks(storeId, comboId)" v-if="orderType === OrderSource.TeaSpecialist">
<view class="font-bold text-30rpx leading-42rpx text-[#303133] mr-10rpx w-362rpx line-1">{{ comboOrder.group.title }} </view>
<wd-icon name="chevron-right" size="32rpx"></wd-icon>
</view>
<!-- 茶艺师退款 -->
@ -209,8 +210,8 @@
<view class="text-[#909399] text-26rpx leading-36rpx">324.22</view>
</view>
<view class="flex justify-between items-center text-26rpx leading-36rpx text-[#909399] mt-18rpx">
<view>3小时</view>
<view>x1</view>
<view v-if="orderType === OrderSource.Combo">{{ comboOrder.group.hour }}小时</view>
<view v-if="orderType === OrderSource.Combo">x1</view>
</view>
<!-- 茶艺师退显示车马费-->
<view class="flex justify-between items-center text-26rpx leading-36rpx text-[#909399] mt-18rpx" v-if="orderType === OrderSource.TeaSpecialist">
@ -219,7 +220,7 @@
</view>
<view class="text-[#606266] text-right mt-26rpx">
<text class="text-24rpx leading-34rpx mr-12rpx">实付</text>
<text class="tetx-32rpx leading-36rpx">29.32</text>
<text class="tetx-32rpx leading-36rpx">{{ comboOrder.order_amount }}</text>
<wd-icon name="chevron-right" size="32rpx"></wd-icon>
</view>
</view>
@ -299,6 +300,9 @@
<script lang="ts" setup>
import { OrderStatusTitle, PersonalReasonMap, MerchantReasonMap, ReasonMap, OrderSource, OrderStatus } from '@/utils/order'
import {toast} from '@/utils/toast'
import type { ITeaRoomPackageOrderDetailsResult } from '@/api/types/tea-room'
import { getTeaRoomPackageOrderDetail } from '@/api/tea-room'
import { handleToTGComboHooks } from '@/hooks/useOrder'
/** 表单相关 **/
const reasonText = ref<string>('') // 显示售后原因文本
@ -331,15 +335,69 @@
const orderType = ref<string>('') // 订单类型:团购、抖音、茶艺师退款
const orderStatus = ref<string>('') // 订单状态:待使用、退款等
// 订单
const orderId = ref<number>(0)
const storeId = ref<number>(0)
const comboId = ref<number>(0)
// 团购套餐
const comboOrder = ref<ITeaRoomPackageOrderDetailsResult>({
pay: 0,
pay_way_title: '',
order_amount: '',
order_sn: '',
order_status: 0,
dtime: '',
pay_dtime: '',
group: {
id: 0,
title: '',
img: '',
hour: '',
},
store: {
id: 0,
address: '',
latitude: '',
longitude: '',
name: '',
image: '',
contact_phone: '',
store_id: 0,
distance: '',
operation_type: 1
}
})
onLoad((args) => {
// 这里暂时使用 OrderSource.Combo 这个,因为平台团购类型下面都是有共同的售后
title.value = OrderStatusTitle[OrderSource.Combo][args.orderStatus] || '订单详情'
orderId.value = Number(args.orderId)
orderType.value = args.orderType
orderStatus.value = args.orderStatus
storeId.value = Number(args.storeId)
comboId.value = Number(args.comboId)
if (orderType.value === OrderSource.Combo) {
// 获取团购套餐订单详情
AfterSales.handleInitComboDetails()
}
})
const AfterSales = {
/**
* 获取套餐详情
*/
handleInitComboDetails: async () => {
const res = await getTeaRoomPackageOrderDetail({
id: orderId.value,
latitude: uni.getStorageSync('latitude'),
longitude: uni.getStorageSync('longitude')
})
comboOrder.value = res.details
},
handleToCombo: () => {
toast.info('跳转到套餐详情')
},

View File

@ -16,6 +16,13 @@
<view class="text-[#909399] text-26rpx leading-36rpx mx-102rpx mb-40rpx">
<!-- <text v-if="orderStatus === OrderStatus.ToUse">请在2025.12.31()前使用</text> -->
<text v-if="orderStatus === TeaRoomPackageOrderStatus.Used">感谢购买期待再次光临</text>
<view v-if="orderStatus === TeaRoomPackageOrderStatus.Refunded" class="text-center mt-14rpx">
<view class="text-40rpx text-[#303133] leading-56rpx">
<view>退款成功{{ order.order_amount }}</view>
</view>
<view class="text-28rpx text-[#606266] leading-54rpx mt-20rpx">谢谢您的信任我们一定会做的更好</view>
<view class="text-24rpx text-[#606266] leading-34rpx mt-12rpx">2025年4月13日 18:22</view>
</view>
</view>
<view class="">
@ -27,7 +34,7 @@
<wd-img width="190rpx" height="190rpx" :src="order.group.img" mode="scaleToFill"></wd-img>
</view>
<view class="flex-1">
<view class="flex justify-between items-center" @click="OrderDetail.handleToCombo">
<view class="flex justify-between items-center" @click="handleToTGComboHooks(order.store.id, order.group.id)">
<view class="font-bold text-30rpx leading-42rpx text-[#303133] mr-10rpx w-362rpx line-1">{{ order.group.title }}</view>
<wd-icon name="chevron-right" size="32rpx"></wd-icon>
</view>
@ -42,18 +49,29 @@
</view>
</view>
</view>
<!-- 平台团购直营店待使用 -->
<view class="mt-30rpx font-500 leading-48rpx">
<view class="mt-30rpx font-500 leading-48rpx" v-if="order.store.operation_type === StoreType.Direct">
<!-- <view class="text-26rpx text-[#606266]">有效期2025.04.04-2025.12.31</view> -->
<view class="text-28rpx text-[#303133] mt-18rpx">
<text class="mr-20rpx">券码 1052 4258 5654 125</text>
<text class="text-[#4C9F44]">复制</text>
<text class="mr-20rpx">券码 {{ order.coupon_code }}</text>
<text class="text-[#4C9F44]" @click="copy(order.coupon_code)">复制</text>
</view>
</view>
<!-- 平台团购加盟店待使用 -->
<view class="mt-30rpx font-500 leading-48rpx" v-if="order.store.operation_type === StoreType.Franchise">
<view class="px-30rpx mt-60rpx">
<view class="text-center">
<wd-img width="230rpx" height="230rpx" :src="order.coupon_code_img"></wd-img>
</view>
<view class="text-28rpx text-[#303133] mt-32rpx text-center">
<text class="mr-20rpx">券码 {{ order.coupon_code }}</text>
<text class="text-[#4C9F44]" @click="copy(order.coupon_code)">复制</text>
</view>
</view>
</view>
</view>
</view>
<!-- 已使用下显示 -->
<view class="mx-30rpx coupon-bg" v-if="orderStatus === TeaRoomPackageOrderStatus.Used">
<view class="flex items-center px-30rpx pt-30rpx pb-40rpx">
@ -121,7 +139,8 @@
<!-- 操作按钮 -->
<view class="w-full fixed bottom-0 left-0 right-0 bg-white h-152rpx">
<view class="mt-34rpx">
<!-- 直营店 -->
<view class="mt-34rpx" v-if="order.store.operation_type == StoreType.Direct">
<!-- 待使用 -->
<view class="text-32rpx leading-44rpx flex items-center justify-center leading-90rpx text-center" v-if="orderStatus === TeaRoomPackageOrderStatus.ToUse">
<view class="w-330rpx h-90rpx bg-[#F6F7F8] rounded-8rpx text-[#303133] mr-30rpx" @click="OrderDetail.handleToRefund">申请退款</view>
@ -132,6 +151,26 @@
<view class="text-32rpx leading-44rpx flex items-center justify-center leading-90rpx text-center" v-if="orderStatus === TeaRoomPackageOrderStatus.Used">
<view class="w-630rpx h-90rpx bg-[#4C9F44] rounded-8rpx text-[#fff]">再次预定</view>
</view>
<!-- 已退款 -->
<view class="text-32rpx leading-44rpx flex items-center justify-center leading-90rpx text-center" v-if="orderStatus === TeaRoomPackageOrderStatus.Refunded">
<view class="w-330rpx h-90rpx bg-[#F6F7F8] rounded-8rpx text-[#303133] mr-30rpx" @click="OrderDetail.handleCallPhone">联系商家</view>
<view class="w-330rpx h-90rpx bg-[#F6F7F8] rounded-8rpx text-[#303133]" @click="OrderDetail.handleCallPhone">联系平台</view>
</view>
</view>
<!-- 加盟店 -->
<view class="mt-34rpx" v-if="order.store.operation_type === StoreType.Franchise && orderStatus !== TeaRoomPackageOrderStatus.Used">
<!-- 待使用 -->
<view class="text-32rpx leading-44rpx flex items-center justify-center leading-90rpx text-center" v-if="orderStatus === TeaRoomPackageOrderStatus.ToUse">
<view class="w-660rpx h-90rpx bg-[#F6F7F8] rounded-8rpx text-[#303133]" @click="OrderDetail.handleToRefund">申请退款</view>
</view>
<!-- 已退款 -->
<view class="text-32rpx leading-44rpx flex items-center justify-center leading-90rpx text-center" v-if="orderStatus === TeaRoomPackageOrderStatus.Refunded">
<view class="w-330rpx h-90rpx bg-[#F6F7F8] rounded-8rpx text-[#303133] mr-30rpx" @click="OrderDetail.handleCallPhone">联系商家</view>
<view class="w-330rpx h-90rpx bg-[#F6F7F8] rounded-8rpx text-[#303133]" @click="OrderDetail.handleCallPhone">联系平台</view>
</view>
</view>
</view>
</view>
@ -142,10 +181,11 @@
import { getTeaRoomPackageOrderDetail } from '@/api/tea-room'
import type { ITeaRoomPackageOrderDetailsResult } from '@/api/types/tea-room'
import { toast } from '@/utils/toast'
import { handleToTeaRoomStoreHooks } from '@/hooks/useOrder'
import { handleToTRStoreHooks, handleToTGComboHooks } from '@/hooks/useOrder'
import { router, copy } from '@/utils/tools'
import { ReserveServiceCategory } from '@/utils/order'
import UseStore from '@/components/UseStore.vue'
import { StoreType } from '@/utils/tea'
const OSS = inject('OSS')
@ -163,6 +203,8 @@
order_status: 0,
dtime: '',
pay_dtime: '',
coupon_code: '',
coupon_code_img: '',
group: {
id: 0,
title: '',
@ -212,18 +254,11 @@
orderStatus.value = order.value.order_status
},
/**
* 跳转到套餐详情
*/
handleToCombo: () => {
router.navigateTo(`/bundle/tea-room/detail?teaRoomId=${order.value.store.id}&id=${order.value.group.id}&type=${ReserveServiceCategory.GroupBuying}`)
},
/**
* 跳转到包间详情
*/
handleToRoom: () => {
handleToTeaRoomStoreHooks(order.value.store.id, order.value.store.store_id)
handleToTRStoreHooks(order.value.store.id, order.value.store.store_id)
},
/**
@ -252,7 +287,7 @@
* 跳转到申请退款页面
*/
handleToRefund: () => {
router.navigateTo(`/bundle/order/after-sales/after-sales?orderId=${orderId.value}&type=${OrderSource.Combo}&orderStatus=${OrderStatus.AfterSaleApply}`)
router.navigateTo(`/bundle/order/after-sales/after-sales?orderId=${orderId.value}&storeId=${order.value.store.id}&comboId=${order.value.group.id}&orderType=${OrderSource.Combo}&orderStatus=${OrderStatus.AfterSaleApply}`)
},
/**

View File

@ -297,7 +297,7 @@
</view>
<view class="flex-1 flex justify-between items-center relative">
<view class="">
<view class="text-[#303133] text-30rpx leading-40rpx line-2" @click="handleToTeaRoomStoreHooks(order.store_msg.id, order.store_msg.operation_type)">{{ order.store_msg.name }}</view>
<view class="text-[#303133] text-30rpx leading-40rpx line-2" @click="handleToTRStoreHooks(order.store_msg.id, order.store_msg.operation_type)">{{ order.store_msg.name }}</view>
<view class="mt-26rpx text-[#909399] text-24rpx leading-34rpx">距您{{ order.distance }}km</view>
<view class="flex items-center mt-14rpx">
<view class="mr-8rpx">
@ -387,7 +387,7 @@
import { useMessage } from 'wot-design-uni'
import {toast} from '@/utils/toast'
import { getTeaRoomOrderDetail } from '@/api/tea-room'
import { handleTRCancelOrderHooks, handleTRToPayHooks } from '@/hooks/useOrder'
import { handleTRCancelOrderHooks, handleTRToPayHooks, handleToTRStoreHooks } from '@/hooks/useOrder'
import type { ITeaSpecialistOrderDetailsResult } from '@/api/types/tea'
import { router } from '@/utils/tools'
import { ReserveServiceCategory, OrderType } from '@/utils/order'
@ -642,7 +642,7 @@
* 跳转到对对应室的详情页
*/
handleToStore: () => {
handleToTeaRoomStoreHooks(order.value.store_id, order.value.store_msg.operation_type)
handleToTRStoreHooks(order.value.store_id, order.value.store_msg.operation_type)
},
/**

View File

@ -71,10 +71,12 @@
<view class="flex items-center">
<view class="mr-10rpx">
<wd-upload
:header="{'token': token}"
:file-list="fileList"
:limit="1"
image-mode="scaleToFill"
:action="action">
:action="action"
@success="Profile.handleUploadSuccess">
<wd-img width="64rpx" height="64rpx" :src="user.avatar" mode="aspectFill" round />
</wd-upload>
</view>
@ -123,17 +125,17 @@
<script lang="ts" setup>
import {toast} from '@/utils/toast'
import { getUserInfo } from '@/api/user'
import { getUserInfo, updateUserInfo } from '@/api/user'
import type { IUserResult } from '@/api/types/user'
import { useUserStore } from '@/store'
import { router } from '@/utils/tools'
import { useUserStore } from '@/store'
const OSS = inject('OSS')
const showLogoutPopup = ref<boolean>(false) // 是否显示退出登录弹出框
// 上传文件
const fileList = ref<any[]>([])
const action = 'https://www.mocky.io/v2/5cc8019d300000980a055e76' // 仅做测试使用,实际请换成真实上传接口
const action = 'https://cz.stnav.com/api/upload/image' // 仅做测试使用,实际请换成真实上传接口
// 修改昵称
const showEditNicknamePopup = ref<boolean>(false) // 是否显示退款详情弹出框
@ -159,7 +161,11 @@
version: ""
})
const token = ref<string>('') // 用户token
onLoad(() => {
token.value = uni.getStorageSync('token')
Profile.handleInit()
})
@ -181,15 +187,34 @@
console.log("🚀 ~ e:", e)
},
handleUploadSuccess: async (e: any) => {
try {
const response = JSON.parse(e.file.response)
if (response.code) {
const avatarUrl = response.data.uri
await updateUserInfo({ field: 'avatar', value: avatarUrl })
user.value.avatar = avatarUrl
toast.info('头像上传成功')
} else {
throw new Error('上传失败')
}
} catch (error) {
toast.info('上传失败')
}
},
/**
* 保存昵称
*/
handleSaveNickname: () => {
handleSaveNickname: async () => {
if (!nickname.value) {
toast.info('请输入昵称')
return
}
await updateUserInfo({ field: 'nickname', value: nickname.value })
showEditNicknamePopup.value = false
user.value.nickname = nickname.value
toast.info('昵称修改成功')
},

View File

@ -34,6 +34,10 @@
<view>优惠券</view>
<view>-{{ bill.coupon }}</view>
</view>
<view class="flex justify-between items-center text-24rpx text-[#909399] leading-34rpx mt-16rpx">
<view>团购券</view>
<view>-{{ bill.groupCoupon || 0 }}</view>
</view>
<view class="flex justify-between items-center text-24rpx text-[#909399] leading-34rpx mt-16rpx">
<view>会员八折</view>
<view>-{{ bill.discount }}</view>
@ -149,7 +153,7 @@
</view>
</view>
<view class="mr-30rpx">
<wd-button custom-class='!bg-[#4C9F44] !rounded-8rpx !h-70rpx' @click="ChooseRoomReserve.handleReserve">立即预定</wd-button>
<wd-button custom-class='!bg-[#4C9F44] !rounded-8rpx !h-70rpx' @click="ChooseRoomReserve.handleSubmitOrder">立即预定</wd-button>
</view>
</view>
</view>
@ -200,6 +204,7 @@
// 团购优惠券ID
const groupCouponId = ref<number>(0)
const groupCouponOrderId = ref<number>(0)
const groupCoupon = ref<any>({})
const groupCouponHour = ref<number>(0) // 团购券可以抵消几个小时的时间
@ -215,7 +220,7 @@
const selectedCoupon = ref<{id: number, name: string}>({id: 0, name: ''})
// 计算费用明细 service(服务费) groupCoupon(团购优惠券)
const bill = ref<{service: any, groupCoupon: any, discount: number, totalDiscount: number, coupon: number, total: number}>({
const bill = ref<{service: any, groupCoupon: number, discount: number, totalDiscount: number, coupon: number, total: number}>({
service: {
total: 0,
unitPrice: 0,
@ -226,10 +231,7 @@
startHour: '',
endHour: ''
},
groupCoupon: {
hour: 0,
total: 0
},
groupCoupon: 0,
discount: 0,
totalDiscount: 0,
coupon: 0,
@ -247,6 +249,7 @@
id.value = Number(args.id)
teaRoomPrice.value = Number(args.price) || 0
groupCouponId.value = Number(args.groupCouponId) || 0
groupCouponOrderId.value = Number(args.groupCouponOrderId) || 0
ChooseRoomReserve.handleInitReserveRoom()
// 获取用户需求详
@ -355,7 +358,7 @@
end_time: bill.value.service.endHour,
user_coupon_id: selectedCoupon.value.id || 0,
hours: bill.value.service.num,
group_coupon_id: groupCouponId.value
group_coupon_id: groupCouponOrderId.value
})
uni.hideLoading()
@ -391,13 +394,14 @@
const res = await calculateTeaRoomPrice({
room_id: id.value,
coupon_id: selectedCoupon.value.id || 0,
group_id: bill.value.service.num > 0 ? groupCouponId.value : 0,
group_coupon_id: bill.value.service.num > 0 ? groupCouponOrderId.value : 0,
nums: bill.value.service.num,
})
bill.value.service.total = res.details.room_price // 茶室价格
bill.value.discount = res.details.discount_room_price // 茶室总价
bill.value.totalDiscount = res.details.discount_all_price // 总优惠
bill.value.groupCoupon = res.details.group_price // 团购优惠
bill.value.total = res.details.order_amount // 订单金额
}
}

View File

@ -89,6 +89,7 @@
// 订单
const teaRoomId = ref<number>(0)
const groupCouponId = ref<number>(0)
const groupCouponOrderId = ref<number>(0)
const orderStatus = ref<number>(0) // 订单状态:待使用、退款等
const order = ref<ITeaRoomPackageOrderDetailsResult>({
pay: 0,
@ -124,6 +125,7 @@
onLoad((args) => {
groupCouponId.value = args.groupCouponId
groupCouponOrderId.value = args.groupCouponOrderId
teaRoomId.value = Number(args.teaRoomId)
// 获取订单详情
@ -256,8 +258,7 @@
toast.info('请选择包间')
return
}
router.navigateTo(`/bundle/tea-room/choose-room-reserve?groupCouponId=${groupCouponId.value}&storeId=${teaRoomId.value}&id=${couponRoomId.value}&type=${ReserveServiceCategory.ReserveRoom}&price=${couponRoomPrice.value}`)
router.navigateTo(`/bundle/tea-room/choose-room-reserve?groupCouponId=${groupCouponId.value}&groupCouponOrderId=${groupCouponOrderId.value}&storeId=${teaRoomId.value}&id=${couponRoomId.value}&type=${ReserveServiceCategory.ReserveRoom}&price=${couponRoomPrice.value}`)
}
}
</script>

View File

@ -440,8 +440,7 @@
selectedCoupon.value = {id: params.coupon.user_coupon_id, name: `${params.coupon.name}${params.coupon.coupon_price}` }
bill.value.coupon = params.coupon.coupon_price
} else {
selectedGroupCoupon.value = {id: params.coupon.group_id, name: `团购券-${params.coupon.tea_store_group.title}` }
console.log("🚀 ~ selectedGroupCoupon.value:", selectedGroupCoupon.value.name)
selectedGroupCoupon.value = {id: params.coupon.id, name: `团购券-${params.coupon.tea_store_group.title}` }
bill.value.groupCoupon = params.coupon.coupon_price
}
@ -532,14 +531,14 @@
const res = await calculateTeaRoomPrice({
room_id: id.value,
coupon_id: selectedCoupon.value.id || 0,
group_id: selectedGroupCoupon.value.id,
group_coupon_id: selectedGroupCoupon.value.id,
nums: bill.value.service.num,
})
bill.value.service.total = res.details.room_price // 茶室价格
bill.value.discount = res.details.discount_room_price // 茶室总价
bill.value.totalDiscount = res.details.discount_all_price // 总优惠
bill.value.groupCoupon = res.details.group_price // 优惠
bill.value.groupCoupon = res.details.group_price // 团购优惠
bill.value.total = res.details.order_amount // 订单金额
}
}

View File

@ -8,7 +8,7 @@
</view>
<view class="flex-1 flex justify-between items-center relative">
<view class="">
<view class="text-[#303133] text-30rpx leading-40rpx line-2" @click="handleToTeaRoomStoreHooks(store.id, store.operation_type)">{{ store.name }}</view>
<view class="text-[#303133] text-30rpx leading-40rpx line-2" @click="handleToTRStoreHooks(store.id, store.operation_type)">{{ store.name }}</view>
<view class="mt-26rpx text-[#909399] text-24rpx leading-34rpx">距您{{ store.distance }}km</view>
<view class="flex items-center mt-14rpx">
<view class="mr-8rpx">
@ -31,6 +31,8 @@
</template>
<script lang="ts" setup name="UseStore">
import { handleToTRStoreHooks } from '@/hooks/useOrder'
/**
* UseStore 适用门店
* @description 用于展示适用门店信息

View File

@ -222,7 +222,7 @@
import { OrderSource, OrderStatus, TeaRoomOrderStatus, TeaRoomPackageOrderStatus } from '@/utils/order'
import { useMessage } from 'wot-design-uni'
import { toast } from '@/utils/toast'
import { handleTRCancelOrderHooks, handleTRDeleteOrderHooks, handleTRToPayHooks, handleToTeaRoomStoreHooks, handleTGOrderRefundHooks } from '@/hooks/useOrder'
import { handleTRCancelOrderHooks, handleTRDeleteOrderHooks, handleTRToPayHooks, handleToTRStoreHooks, handleTGOrderRefundHooks } from '@/hooks/useOrder'
import { StoreType } from '@/utils/tea'
import { router } from '@/utils/tools'
@ -264,7 +264,7 @@
* 跳转到对对应室的详情页
*/
handleToStore: () => {
handleToTeaRoomStoreHooks(props.order.store_id, props.order.operation_type)
handleToTRStoreHooks(props.order.store_id, props.order.operation_type)
},
/**
@ -273,7 +273,7 @@
handleOrderRefund: (source: string) => {
switch (source) {
case OrderSource.Combo:
router.navigateTo(`/bundle/order/after-sales/after-sales?orderId=${props.order.id}&type=${OrderSource.Combo}&orderStatus=${OrderStatus.AfterSaleApply}`)
router.navigateTo(`/bundle/order/after-sales/after-sales?orderId=${props.order.id}&storeId=${props.order.store_id}&comboId=${props.order.group_id}&orderType=${OrderSource.Combo}&orderStatus=${OrderStatus.AfterSaleApply}`)
break;
default:
break;
@ -284,7 +284,7 @@
* 使用套餐
*/
handleUsePackage: () => {
router.navigateTo(`/bundle/tea-room/choose-room?groupCouponId=${props.order.group_id}&teaRoomId=${props.order.store_id}`)
router.navigateTo(`/bundle/tea-room/choose-room?groupCouponId=${props.order.group_id}&groupCouponOrderId=${props.order.id}&teaRoomId=${props.order.store_id}`)
},
/**

View File

@ -1,19 +1,23 @@
const LOCATION_EXPIRE_MS = 30 * 24 * 60 * 60 * 1000 // 定位缓存30天
const LOCATION_DENY_INTERVAL = 60 * 60 * 1000 // 未授权定位弹窗间隔1小时
import { getLocationToCity } from '@/api/tea-room'
const LOCATION_EXPIRE_MS = 2 * 60 * 1000 // 定位缓存30天
const LOCATION_DENY_INTERVAL = 1 * 60 * 1000 // 未授权定位弹窗间隔1小时
export const LOCATION_EXPIRE_KEY = 'location_expire_time' // 定位缓存KEY
export const LOCATION_DEFAULT_CITY = '上海市' // 默认城市
export const LOCATION_DEFAULT_LAT = 34.757975 // 上海经度
export const LOCATION_DEFAULT_LNG = 113.665412 // 上海纬度
export const LOCATION_DEFAULT_LAT = 31.230393 // 上海经度
export const LOCATION_DEFAULT_LNG = 121.473629 // 上海纬度
export const LOCATION_DENY_TIME_KEY = 'location_deny_time' // 未授权定位重新授权时间KEY
export const LOCATION_CITY_KEY = 'city' // 城市缓存KEY
export const LOCATION_LAT_KEY = 'latitude' // 城市缓存KEY
export const LOCATION_LNG_KEY = 'longitude' // 城市缓存KEY
// 检查过期时间
export function handleCheckLocationCacheHooks() {
const expire = uni.getStorageSync(LOCATION_EXPIRE_KEY)
if (expire && Date.now() > expire) {
uni.removeStorageSync('latitude')
uni.removeStorageSync('longitude')
uni.removeStorageSync(LOCATION_LAT_KEY)
uni.removeStorageSync(LOCATION_LNG_KEY)
uni.removeStorageSync(LOCATION_EXPIRE_KEY)
return false
}
@ -22,8 +26,8 @@ export function handleCheckLocationCacheHooks() {
// 设置经纬度缓存
export function handleSetLocationCacheHooks(lat: number, lng: number) {
uni.setStorageSync('latitude', lat)
uni.setStorageSync('longitude', lng)
uni.setStorageSync(LOCATION_LAT_KEY, lat)
uni.setStorageSync(LOCATION_LNG_KEY, lng)
uni.setStorageSync(LOCATION_EXPIRE_KEY, Date.now() + LOCATION_EXPIRE_MS)
}
@ -31,13 +35,13 @@ export function handleSetLocationCacheHooks(lat: number, lng: number) {
export async function handleEnsureLocationAuthHooks() {
// 1. 检查缓存
if (handleCheckLocationCacheHooks()) {
const lat = uni.getStorageSync('latitude')
const lng = uni.getStorageSync('longitude')
const lat = uni.getStorageSync(LOCATION_LAT_KEY)
const lng = uni.getStorageSync(LOCATION_LNG_KEY)
if (lat && lng) return { lat, lng }
}
// 2. 获取定位
return new Promise<{ lat: number, lng: number }>((resolve) => {
return new Promise<{ lat: number, lng: number, }>((resolve) => {
uni.authorize({
scope: 'scope.userLocation',
success() {
@ -45,12 +49,12 @@ export async function handleEnsureLocationAuthHooks() {
type: 'gcj02',
success(res) {
handleSetLocationCacheHooks(res.latitude, res.longitude)
resolve({ lat: res.latitude, lng: res.longitude })
resolve({ lat: res.latitude, lng: res.longitude})
},
fail() {
// 定位失败,返回默认上海
handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG})
}
})
},
@ -151,6 +155,32 @@ export function setLocationCity(city: string) {
uni.setStorageSync(LOCATION_CITY_KEY, city)
}
/**
* 经纬度转换为城市
* @returns
*/
export async function handleGetLocationCity(lat: number, lng: number) {
try {
console.log("🚀 ~ handleGetLocationCity ~ res:", lat, lng)
const res = await getLocationToCity({ latitude: lat, longitude: lng })
if (res.message == "Success") {
const params = {
latitude: res.result.location.lat,
longitude: res.result.location.lng,
city: res.result.ad_info.city
}
setLocationCity(params.city)
// uni.$emit('locationUpdate', params) // 通知页面
return params
} else {
setLocationCity(LOCATION_DEFAULT_CITY)
}
} catch (error) {
setLocationCity(LOCATION_DEFAULT_CITY)
}
}
// 检查是否需要弹授权框
function shouldShowAuthModal() {
const lastDeny = uni.getStorageSync(LOCATION_DENY_TIME_KEY)

View File

@ -6,6 +6,7 @@ import {
confirmTeaRoomOrder
} from '@/api/tea-room'
import { OrderType } from '@/utils/order'
import { ReserveServiceCategory } from '@/utils/order'
/**
* 包间-取消订单
@ -43,7 +44,7 @@ export function handleTRToPayHooks(orderId: number, teaRoomName: string, storeId
})
setTimeout(() => {
router.navigateTo(`/pages/cashier/cashier?from=${OrderType.TeaRoomOrder}&orderId=${orderId}&teaRoomName=${teaRoomName}&storeId=${storeId}`)
router.navigateTo(`/pages/cashier/cashier?from=${OrderType.TeaRoomOrder}&orderId=${orderId}&name=${teaRoomName}&storeId=${storeId}&isGroupBuying=0`)
}, 800)
} catch (error) {
toast.info('订单提交失败,请稍后重试')
@ -96,6 +97,18 @@ export async function handleTRConfirmOrderHooks(orderId: number) {
// }
// }
/**
* 跳转到茶室店铺
* @param storeId 门店ID
* @param operationType 门店类型1-直营 2-加盟
*/
export function handleToTRStoreHooks(storeId: number, operationType: number) {
router.navigateTo(`/bundle/tea-room/room?id=${storeId}&type=${operationType}`)
}
/*************************************************************套餐***********************************************************************/
/**
* 平台团购套餐-订单退款
*/
@ -110,11 +123,12 @@ export async function handleTGOrderRefundHooks(orderId: number) {
// }
}
/**
* 跳转到茶室店铺
* 跳转到套餐详情
* @param storeId 门店ID
* @param operationType 门店类型1-直营 2-加盟
* @param id 套餐ID
*/
export function handleToTeaRoomStoreHooks(storeId: number, operationType: number) {
router.navigateTo(`/bundle/tea-room/room?id=${storeId}&type=${operationType}`)
export function handleToTGComboHooks(storeId: number, id: number) {
router.navigateTo(`/bundle/tea-room/detail?storeId=${storeId}&id=${id}&type=${ReserveServiceCategory.GroupBuying}`)
}

View File

@ -91,6 +91,7 @@
{
"path": "pages/city/city",
"type": "page",
"needLogin": true,
"layout": "tabbar",
"style": {
"navigationStyle": "default",

View File

@ -197,7 +197,7 @@
money.value = Number(res.details.order_amount)
// 一键续订价格
renewPrice.value = Number(res.details.renew_dtime.renew_price) || 0
renewPrice.value = Number(res.details?.renew_dtime?.renew_price) || 0
},
/**

View File

@ -1,5 +1,6 @@
<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page -->
<route lang="jsonc" type="page">{
"needLogin": true,
"layout": "tabbar",
"style": {
// 'custom' 表示开启自定义导航栏,默认 'default'
@ -21,7 +22,7 @@
<view class="mt-40rpx">
<view class="bg-[#F8F9FA] rounded-28rpx w-162rpx h-56rpx text-[#606266] flex items-center justify-center">
<wd-img width="28rpx" height="28rpx" :src="`${OSS}icon/icon_location2.png`"></wd-img>
<view class="text-26rpx text-[#606266] leading-36rpx">上海市</view>
<view class="text-26rpx text-[#606266] leading-36rpx">{{ city || LOCATION_DEFAULT_CITY }}</view>
</view>
</view>
</view>
@ -29,7 +30,10 @@
<view class="mt-50rpx mx-30rpx">
<view class="text-[#333] leading-42rpx text-30rpx font-bold">已开通城市</view>
<view class="mt-40rpx grid grid-cols-4 gap-20rpx w-full">
<view class="bg-[#F8F9FA] rounded-28rpx h-56rpx text-[#606266] flex items-center justify-center" v-for="(item, index) in openCityList" :key="index">
<view class="bg-[#F8F9FA] rounded-28rpx h-56rpx text-[#606266] flex items-center justify-center"
v-for="(item, index) in openCityList" :key="index"
@click="City.handleChooseCity(item)"
>
<wd-img width="28rpx" height="28rpx" :src="`${OSS}icon/icon_location2.png`"></wd-img>
<view class="text-26rpx text-[#606266] leading-36rpx">{{ item.name }}</view>
</view>
@ -41,12 +45,14 @@
<script lang="ts" setup>
import { router } from '@/utils/tools'
import { getOpenCityList } from '@/api/tea-room'
import { LOCATION_CITY_KEY, LOCATION_LAT_KEY, LOCATION_LNG_KEY } from '@/hooks/useLocation'
const OSS = inject('OSS')
// 经纬度
const latitude = ref<number>(0)
const longitude = ref<number>(0)
const city = ref<string>('')
// 已开通城市列表
const openCityList = ref<Array<any>>([])
@ -62,8 +68,27 @@
const City = {
handleInit: async () => {
city.value = uni.getStorageSync(LOCATION_CITY_KEY)
const res = await getOpenCityList()
openCityList.value = res.list
},
/**
* 选择城市
*/
handleChooseCity: (item: any) => {
const params = {
latitude: item.latitude,
longitude: item.longitude,
city: item.name
}
uni.$emit('locationUpdate', params)
uni.setStorageSync(LOCATION_LAT_KEY, item.latitude)
uni.setStorageSync(LOCATION_LNG_KEY, item.longitude)
uni.setStorageSync(LOCATION_CITY_KEY, item.name)
router.navigateBack()
}
}

View File

@ -14,7 +14,7 @@
<wd-navbar safeAreaInsetTop :bordered="false" custom-style="background-color: transparent !important;">
<template #left>
<view class="flex items-center line-1 w-130rpx" @click="Index.handleToCity">
<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">{{ city || LOCATION_DEFAULT_CITY }}</view>
<wd-img width="14rpx" height="9rpx" :src="`${OSS}icon/icon_arrow_down.png`" />
</view>
</template>
@ -110,7 +110,7 @@
import { router } from '@/utils/tools'
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js"
import { LOCATION_DENY_TIME_KEY, handleEnsureLocationAuthHooks } from '@/hooks/useLocation'
import { LOCATION_DENY_TIME_KEY, handleEnsureLocationAuthHooks, LOCATION_DEFAULT_CITY, handleGetLocationCity, LOCATION_CITY_KEY } from '@/hooks/useLocation'
import { getHomeBannerList } from '@/api/home'
import { getHomeTeaStoreList } from '@/api/tea-room'
import { useUserStore } from '@/store'
@ -133,17 +133,28 @@
}
const latitude = ref<number>(0)
const longitude = ref<number>(0)
const city = ref<string>('')
const keywords = ref<string>('')
const list = ref<Array<any>>([])
onShow(async() => {
// 等到onLoad执行完毕且获取到授权KEY后才执行定位授权检查
let lastLocation = { lat: 0, lng: 0 }
onShow(async () => {
if (uni.getStorageSync(LOCATION_DENY_TIME_KEY)) {
const location = await checkLocationAuthWithModal()
if (location) {
latitude.value = location.lat
longitude.value = location.lng
Index.handleResetSearch()
// 只有经纬度变化时才刷新
if (location.lat !== lastLocation.lat || location.lng !== lastLocation.lng) {
const loc = await handleGetLocationCity(location.lat, location.lng)
city.value = loc.city
latitude.value = location.lat
longitude.value = location.lng
lastLocation.lat = location.lat
lastLocation.lng = location.lng
console.log("🚀 ~ city.value:", 'xxxxx', city.value)
Index.handleResetSearch()
}
}
}
})
@ -156,10 +167,16 @@
const { lat, lng } = await handleEnsureLocationAuthHooks()
latitude.value = lat
longitude.value = lng
Index.handleResetSearch()
const location = await handleGetLocationCity(lat, lng)
city.value = location.city
latitude.value = location.latitude
longitude.value = location.longitude
Index.handleResetSearch()
})
const Index = {
/**
* 茶室门店列表
@ -177,16 +194,22 @@
search: keywords.value,
user_id: userId
}
uni.showLoading({ title: '加载中...' })
getHomeTeaStoreList(filter).then( res => {
console.log("🚀 ~ res:", res)
const curPageData = res.list || [] // 当前页数据
if(mescroll.num == 1) list.value = [] // 第一页需手动制空列表
list.value = list.value.concat(curPageData) //追加新数据
mescroll.endSuccess(curPageData.length, Boolean(res.more))
}).catch(() => {
mescroll.endErr() // 请求失败, 结束加载
})
try {
getHomeTeaStoreList(filter).then( res => {
const curPageData = res.list || [] // 当前页数据
if(mescroll.num == 1) list.value = [] // 第一页需手动制空列表
list.value = list.value.concat(curPageData) //追加新数据
mescroll.endSuccess(curPageData.length, Boolean(res.more))
}).catch(() => {
mescroll.endErr() // 请求失败, 结束加载
})
uni.hideLoading()
} catch (error) {
uni.hideLoading()
}
},
/**
@ -202,6 +225,15 @@
* 跳转城市选择
*/
handleToCity: () => {
uni.$on('locationUpdate', params => {
console.log("🚀 ~ params:", params)
uni.$off('locationUpdate')
city.value = params.city
latitude.value = params.latitude
longitude.value = params.longitude
Index.handleResetSearch()
})
router.navigateTo(`/pages/city/city?lat=${latitude.value}&lng=${longitude.value}`)
},
@ -229,6 +261,8 @@
* 重置搜索
*/
handleResetSearch: () => {
console.log("🚀 ~ location:", 456)
list.value = []
getMescroll().resetUpScroll()
},
@ -244,6 +278,23 @@
fail: res => {
}
})
},
/**
* 更新定位信息
*/
handleLocationUpdate: (params: any) => {
console.log("🚀 ~ locationUpdate:")
if (
city.value !== params.city ||
latitude.value !== params.latitude ||
longitude.value !== params.longitude
) {
city.value = params.city
latitude.value = params.latitude
longitude.value = params.longitude
Index.handleResetSearch()
}
}
}
</script>

View File

@ -262,14 +262,16 @@ export const TeaRoomOrderStatusValue: Record<TeaRoomOrderStatusText, string | nu
// 包间订单状态数字(根据UI图还缺已退款、待接单、售后中、售后完成)
export enum TeaRoomPackageOrderStatus {
ToUse = 0, // 待付款
Used = 1, // 待使用
Refunded = 2, // 已使用
Pending = 0, // 待付款
ToUse = 1, // 待使用
Used = 2, // 已使用
Refunded = 3, // 已退款
}
// 套餐订单状态文本
export enum TeaRoomPackageOrderStatusText {
All = 'all', // 全部
Pending = 'pending', // 待付款
ToUse = 'toUse', // 待使用
Used = 'used', // 已使用
Refunded = 'refunded', // 已退款
@ -278,13 +280,17 @@ export enum TeaRoomPackageOrderStatusText {
// 套餐订单状态文本对应值
export const TeaRoomPackageOrderStatusValue: Record<TeaRoomPackageOrderStatusText, string | number> = {
[TeaRoomPackageOrderStatusText.All]: '',
[TeaRoomPackageOrderStatusText.ToUse]: 0,
[TeaRoomPackageOrderStatusText.Used]: 1,
[TeaRoomPackageOrderStatusText.Refunded]: 2,
[TeaRoomPackageOrderStatusText.Pending]: 0,
[TeaRoomPackageOrderStatusText.ToUse]: 1,
[TeaRoomPackageOrderStatusText.Used]: 2,
[TeaRoomPackageOrderStatusText.Refunded]: 3,
}
// 状态内容映射
export const TeaRoomPackageOrderStatusTextValue: Record<TeaRoomPackageOrderStatus, any> = {
[TeaRoomPackageOrderStatus.Pending]: {
title: '待付款'
},
[TeaRoomPackageOrderStatus.ToUse]: {
title: '待使用'
},