Browse Source

合同相关,分享课程等

学习?学个屁 1 week ago
parent
commit
6ece045bc1

+ 1 - 1
src/components/sunui-upimg/sunui-upimg.vue

@@ -36,7 +36,7 @@ export default {
 		// 服务器url
 		url: {
 			type: String,
-			default: 'http://192.168.0.11:8080/jeecg-boot/sys/common/upload'
+			default: 'http://192.168.1.34:8080/jeecg-boot/sys/common/upload'
 		},
 		// 上传样式宽高
 		upload_img_wh: {

+ 35 - 3
src/pages/index/attestation/index.vue

@@ -64,6 +64,7 @@ const formData = ref({
 	idCardBackImg: '',
 	realNameImg: '',
 	realNameStatus: null,//0未实名,1实名
+	userId: cache.get('SHARER_ID') || null,
 })
 
 const frontImg = ref('')
@@ -89,11 +90,42 @@ const chooseImage = (e) => {
 	});
 }
 
-const handleChange = (e) => {
-	formData.value.realNameImg = e.join(',');
+const handleChange = async (e) => {
+	try {
+		const imageUrl = e.join(','); // 获取网络图片URL
+		const downloadRes = await uni.downloadFile({ url: imageUrl });
+		if (downloadRes.statusCode !== 200) {
+			throw new Error('图片下载失败');
+		}
+		let quality = 80;
+		let compressRes = await uni.compressImage({
+			src: downloadRes.tempFilePath,
+			quality
+		});
+		let fileInfo = await uni.getFileInfo({ filePath: compressRes.tempFilePath });
+		while (fileInfo.size >= 200 * 1024 && quality > 10) {
+			quality -= 10;
+			compressRes = await uni.compressImage({
+				src: downloadRes.tempFilePath,
+				quality
+			});
+			fileInfo = await uni.getFileInfo({ filePath: compressRes.tempFilePath });
+		}
+		uploadImage(compressRes.tempFilePath, (url) => {
+			formData.value.realNameImg = url;
+			console.log('上传图片返回的地址:', formData.value.realNameImg);
+		});
+	} catch (error) {
+		console.error('图片处理失败:', error);
+		formData.value.realNameImg = imageUrl;
+		console.log('上传图片返回的地址:', formData.value.realNameImg);
+	}
 }
 
+// 图片压缩处理
+
 const submit = () => {
+	console.log(formData.value.realNameImg, '本人图片');
 	if (!formData.value.idCardFrontImg) return TipsUtils.tips_toast('请上传人像面');
 	if (!formData.value.idCardBackImg) return TipsUtils.tips_toast('请上传国徽面');
 	if (!formData.value.fullName) return TipsUtils.tips_toast('请输入姓名');
@@ -133,7 +165,7 @@ const getFaceRecognition = () => {
 						flipSideImg.value = ''
 						uni.navigateBack()
 					})
-				}else{
+				} else {
 					TipsUtils.tips_toast('人脸核身失败')
 				}
 			},

+ 1 - 1
src/pages/index/commentsSuccess/index.vue

@@ -16,7 +16,7 @@
 	import { ref } from 'vue'
 	const check_comments = () => {
 		uni.navigateTo({
-			url: '/pages/index/commentsDetail/index'
+			url: '/pages/mine/mineComments/index'
 		})
 	}
 	

+ 50 - 33
src/pages/index/courseDetail/index.vue

@@ -9,7 +9,7 @@
 		<view :style="{ height: (statusBarHeight + 70) + 'px' }"></view>
 		<scroll-view class="header-swiper content" scroll-x="true" :show-scrollbar="false">
 			<view class="swiper-inner">
-				<block v-if="courseDetailInfo.video">
+				<block v-if="courseDetailInfo?.video">
 					<video v-for="(item, index) in videoList" :key="index" :src="item"></video>
 				</block>
 				<image @click="_previewImage(bannerList, item)" v-for="(item, index) in bannerList" :key="index"
@@ -21,25 +21,26 @@
 	<view class="header-info">
 		<view class="c-price-info">
 			<view class="price-info">
-				<view class="new-price">¥{{ courseDetailInfo.sellingPrice.toFixed(2) }}</view>
-				<view class="old-price">¥{{ courseDetailInfo.originalPrice.toFixed(2) }}</view>
+				<view class="new-price">¥{{ courseDetailInfo?.sellingPrice.toFixed(2) }}</view>
+				<view class="old-price" v-if="courseDetailInfo?.originalPrice">¥{{
+					courseDetailInfo?.originalPrice.toFixed(2) }}</view>
 			</view>
-			<view class="sales">年售{{ courseDetailInfo.sales }}</view>
+			<view class="sales">年售{{ courseDetailInfo?.sales }}</view>
 		</view>
 		<view class="c-name">
-			{{ courseDetailInfo.name }}
+			{{ courseDetailInfo?.name }}
 		</view>
 		<view class="c-detail-info">
-			<view class="c-time">课时:{{ courseDetailInfo.startTime }}-{{ courseDetailInfo.endTime }}</view>
+			<view class="c-time">课时:{{ courseDetailInfo?.startTime }}-{{ courseDetailInfo?.endTime }}</view>
 			<view class="c-address" @click="openMap">
-				<view class="">上课地点:{{ courseDetailInfo.address }} | {{ courseDetailInfo.km.toFixed(2) }} km</view>
+				<view class="">上课地点:{{ courseDetailInfo?.address }} | {{ courseDetailInfo?.km.toFixed(2) }} km</view>
 				<zzx-icon name="ashRight" size="10"></zzx-icon>
 			</view>
 			<view class="c-instructor">
 				<view class="c-instructor-title">授课教练:</view>
 				<view class="c-instructor-name">
-					<image :src="courseDetailInfo.instructorAvatar" mode=""></image>
-					<view class="">{{ courseDetailInfo.instructorName }}</view>
+					<image :src="courseDetailInfo?.instructorAvatar" mode=""></image>
+					<view class="">{{ courseDetailInfo?.instructorName }}</view>
 				</view>
 			</view>
 		</view>
@@ -57,13 +58,13 @@
 		</uv-sticky>
 		<view class="c-tabbar">
 			<view class="c-tabbar-detail" id="detail">
-				<rich-text :nodes="courseDetailInfo.details"></rich-text>
+				<rich-text :nodes="courseDetailInfo?.details"></rich-text>
 			</view>
 			<view class="c-notice" id="notice">
 				<view class="title">购买须知</view>
 				<view class="tips-text">
 					<view class="text">
-						<rich-text :nodes="courseDetailInfo.reminder"></rich-text>
+						<rich-text :nodes="courseDetailInfo?.reminder"></rich-text>
 					</view>
 					<!-- <view class="more">
 						<text>查看更多</text>
@@ -74,12 +75,12 @@
 			<view class="c-schedule" id="schedule">
 				<view class="title">课程表</view>
 				<view class="list-card">
-					<view class="card-title">总共{{ courseDetailInfo.courseDetail.length }}节</view>
-					<view class="schedule-list" v-for="item in courseDetailInfo.courseDetail" :key="item.id">
+					<view class="card-title">总共{{ courseDetailInfo?.courseDetail?.length }}节</view>
+					<view class="schedule-list" v-for="item in courseDetailInfo?.courseDetail" :key="item.id">
 						<view class="time">
 							<text>{{ item.startTime }}-{{ item.endTime }}</text>
 						</view>
-						<view class="name">{{ item.name }}</view>
+						<view class="name">{{ item?.name }}</view>
 					</view>
 					<!-- <view class="more">
 						<text>查看更多</text>
@@ -120,7 +121,7 @@
 						</view>
 					</scroll-view>
 				</view>
-				<view class="not-data" v-if="!appraiseList.records.length">暂无评价数据</view>
+				<view class="not-data" v-if="!appraiseList?.records?.length">暂无评价数据</view>
 			</view>
 		</view>
 	</view>
@@ -129,12 +130,13 @@
 		<view class="c-share">
 			<zzx-icon name="share"></zzx-icon>
 			<view class="">分享</view>
+			<button class="g-share-btn" open-type="share"></button>
 		</view>
 		<view class="c-buy-btn">
 			<view class="buy" v-if="type == 3" @click="toOrderPage(0)">
 				<view class="buy-text">抢购</view>
 				<view class="buy-price">
-					<text>¥{{ courseDetailInfo.sellingPrice }}</text>
+					<text>¥{{ courseDetailInfo?.sellingPrice }}</text>
 					<text>省10</text>
 				</view>
 			</view>
@@ -142,11 +144,11 @@
 				<view class="buy" @click="toOrderPage(0)">
 					<view class="buy-text">直接购买</view>
 					<view class="buy-price">
-						<text>¥{{ courseDetailInfo.sellingPrice }}</text>
-						<text>省10</text>
+						<text>¥{{ courseDetailInfo?.sellingPrice }}</text>
+						<text>省{{ (courseDetailInfo?.originalPrice - courseDetailInfo?.sellingPrice) }}</text>
 					</view>
 				</view>
-				<view class="gratis" @click="toOrderPage(1)">
+				<view class="gratis" @click="toOrderPage(1)" v-if="courseDetailInfo?.hasDiscount">
 					免费试听
 				</view>
 			</block>
@@ -159,7 +161,7 @@ import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
 import { RouterUtils, _previewImage, TipsUtils } from '@/utils/util';
 import { http } from '@/utils/http'
 import zzxNavbar from '@/components/zzx-navbar/zzx-navbar.vue';
-import { onLoad, onPageScroll } from '@dcloudio/uni-app';
+import { onLoad, onPageScroll, onShareAppMessage } from '@dcloudio/uni-app';
 import { useCacheStore } from '@/stores/cache'
 const statusBarHeight = ref(0);
 const sectionTops = ref<number[]>([]);
@@ -175,7 +177,23 @@ onLoad((option) => {
 	courseId.value = option.id
 	type.value = option.type
 	appraiseFormData.value.siteId = option.id
+	if (option.type == 'sharecourse') {
+		cache.set('COURSE_ID', courseDetailInfo.value.id)
+	}
+})
+
+onShareAppMessage((res) => {
+	if (res.from === 'button') {// 来自页面内分享按钮
+		console.log(res.target)
+	}
+	return {
+		title: `邀请您报名《${courseDetailInfo.value.name}》`,
+		path: `/pages/index/courseDetail/index?id=${courseDetailInfo.value.id}&type=sharecourse`,
+		imageUrl: courseDetailInfo.value.cover,
+
+	}
 })
+
 onMounted(() => {
 	get_navheight()
 	nextTick(() => {
@@ -185,12 +203,12 @@ onMounted(() => {
 	getFindByOrderPage()
 })
 
-const openMap=()=>{
+const openMap = () => {
 	uni.openLocation({
 		latitude: courseDetailInfo.value.latitude,
 		longitude: courseDetailInfo.value.longitude,
 		name: courseDetailInfo.value.name,
-		address:courseDetailInfo.value.address,
+		address: courseDetailInfo.value.address,
 		success: function () {
 			console.log('success');
 		}
@@ -272,17 +290,7 @@ const scrollToTop = () => {
 }
 
 const toOrderPage = (buyType: number) => {
-	uni.requestSubscribeMessage({
-		tmplIds: ['Yi1Z1IKRwgF6-mpiFcOUTvavc4TUAsfsLynK_3Yu350','NPlIBEwBDPX23J3Jip0CwYUU4vF9ZlcK8U1d6Gs4yrM'],
-		success(res) {
-			TipsUtils.tips_toast('订阅成功')
-			RouterUtils.to_page(`/pages/index/gymPay/index?courseId=${courseId.value}&type=${type.value}&orderType=2&buyType=${buyType}`)
-		},
-		fail(err) {
-			RouterUtils.to_page(`/pages/index/gymPay/index?courseId=${courseId.value}&type=${type.value}&orderType=2&buyType=${buyType}`)
-			console.log(err, '订阅消息失败')
-		}
-	})
+	RouterUtils.to_page(`/pages/index/gymPay/index?courseId=${courseId.value}&type=${type.value}&orderType=2&buyType=${buyType}`)
 }
 
 // 获取评价
@@ -735,6 +743,15 @@ const fixImgStyle = (html: string) => {
 		font-size: 28rpx;
 		color: #222222;
 		text-align: center;
+		position: relative;
+
+		.g-share-btn {
+			position: absolute;
+			width: 80rpx;
+			height: 90rpx;
+			top: -12rpx;
+			opacity: 0;
+		}
 	}
 
 	.c-buy-btn {

+ 1 - 1
src/pages/index/detail/components/appraise.vue

@@ -46,7 +46,7 @@ const props = withDefaults(defineProps<Props>(), {
 });
 const check_detail = () => {
 	uni.navigateTo({
-		url: '/pages/index/commentsDetail/index'
+		url: '/pages/mine/mineComments/index'
 	})
 }
 </script>

+ 41 - 5
src/pages/index/eventsRegister/index.vue

@@ -1,5 +1,6 @@
 <template>
-	<zs-tabs type="underline" :menus="['个人赛项目', '团队赛项目']" activeColor="#222222" @change="changeTab"></zs-tabs>
+	<!-- 类型type 0-个人,1团队 -->
+	<zs-tabs type="underline" :menus="menusItems" activeColor="#222222" @change="changeTab"></zs-tabs>
 	<view class="content">
 		<view class="r-card-list">
 			<view class="r-title">选择报名项目</view>
@@ -133,7 +134,7 @@
 	<view style="height: 140rpx;"></view>
 	<view class="r-submit-pay">
 		<view class="r-price">
-			<view class="price"><text>¥</text>{{ totalPrice }}</view>
+			<view class="price"><text>¥</text>{{ totalPrice.toFixed(2) }}</view>
 			<view class="r-check-detail">
 				<view class="">查看明细</view>
 				<zzx-icon name="up" size="12"></zzx-icon>
@@ -164,7 +165,7 @@
 <script lang="ts" setup>
 import { ref, onMounted, computed } from 'vue';
 import { http } from '@/utils/http';
-import { RouterUtils, TipsUtils, idCardHide } from '@/utils/util';
+import { RouterUtils, TipsUtils, idCardHide,debounce } from '@/utils/util';
 import { onLoad } from '@dcloudio/uni-app';
 import zsTabs from "@/components/zzx-tabs/zzx-tabs.vue";
 import { useCacheStore } from '@/stores/cache';
@@ -298,11 +299,15 @@ const teamsEvents = ref([]) // 团队赛项目
 const aptitudesList = ref([]) // 资质列表
 const insureIdList = ref([])  // 保险列表
 const insurePrice = ref() // 保险价格
+const menusItems=ref([])
 const get_eventsInfoDetail = () => {
 	http.get('/game/findByGameId', { data: { id: eventId.value }, loading: true }).then((res: any) => {
 		individualEvents.value = res.result.gamePriceRulesTypeVOList.filter((item: any) => item.type == 0)
 		teamsEvents.value = res.result.gamePriceRulesTypeVOList.filter((item: any) => item.type == 1)
 		aptitudesList.value = res.result.aptitudesList
+		menusItems.value= res.result.gamePriceRulesTypeVOList.map((e)=>{
+			return e.typeName
+		})
 		res.result.insureIdList.map((item: any) => {
 			item.insuranceObvious = JSON.parse(item.insuranceObvious)
 			item.insuranceObvious = [item.insuranceObvious]
@@ -389,7 +394,7 @@ let orderFormData = ref({
 		certificationDTOS: []
 	}
 })
-const submitOrder = () => {
+const submitOrderImpl = () => {
 	if (!peopleNum.value) return TipsUtils.tips_toast('请选择项目')
 	if (!userData.value) return TipsUtils.tips_toast('请添加用户信息')
 	if (selectTabs.value == 1) {
@@ -407,10 +412,41 @@ const submitOrder = () => {
 	if (!insureData.value || insureData.value.length === 0) {
 		delete data.insureOrderInfoForm;
 	}
+	// orPayOrder0-免费/试听 1-调起支付
 	http.post('/order/createOrder', data, { loading: true }).then((res) => {
-		RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${res.result.orderId}&orderType=${orderFormData.value.orderType}`)
+		getOrderQuery(res.result.orderCode,res.result.orderId)
 	})
 }
+const submitOrder = debounce(submitOrderImpl, 500)
+
+// code编码 "100001支付成功";"100002查询失败"; "100003查询中 "; "100004支付失败"
+const getOrderQuery = (orderCode: string,orderId:string, retryCount = 0) => {
+    http.get('/order/orderQuery', { data: { orderCode: orderCode }, loading: true }).then((res) => {
+        if (res.result == '100001') {
+            RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${orderId}&orderType=${orderFormData.value.orderType}`)
+        } else if (retryCount <= 3) {
+            setTimeout(() => {
+                getOrderQuery(orderCode,orderId, retryCount + 1)
+            }, 1000)
+        } else {
+            if (res.result == '100003') {
+                console.log('查询中,但已达到最大查询次数')
+            } else if (res.result == '100002') {
+                console.log('查询失败')
+            } else if (res.result == '100004') {
+                console.log('支付失败')
+				TipsUtils.tips_toast('支付失败')
+            }
+        }
+    }).catch((error) => {
+        console.error('查询订单失败:', error)
+        if (retryCount < 2) { 
+            setTimeout(() => {
+                getOrderQuery(orderCode,orderId, retryCount + 1)
+            }, 1000)
+        }
+    })
+}
 </script>
 
 <style lang="less" scoped>

+ 34 - 3
src/pages/index/gymDetail/components/popup.vue

@@ -133,7 +133,7 @@
 <script lang="ts" setup>
 import { ref, onMounted, computed, watch,nextTick } from 'vue';
 import { http } from '@/utils/http'
-import { TipsUtils, phoneHide, RouterUtils } from '@/utils/util';
+import { TipsUtils, phoneHide, RouterUtils,debounce } from '@/utils/util';
 interface Props {
 	listData?: any;
 	itemList?: any;
@@ -269,11 +269,42 @@ const orderFormData = ref({
 	productIds: null,
 	amount: null,
 })
-const submitOrder = () => {
+const submitOrderImpl = () => {
 	http.post('/order/createOrder', orderFormData.value, { loading: true }).then((res) => {
-		RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${res.result.orderId}&orderType=${orderFormData.value.orderType}`)
+		getOrderQuery(res.result.orderCode,res.result.orderId)
 	})
 }
+
+const submitOrder = debounce(submitOrderImpl, 500)
+
+// code编码 "100001支付成功";"100002查询失败"; "100003查询中 "; "100004支付失败"
+const getOrderQuery = (orderCode: string,orderId: string, retryCount = 0) => {
+    http.get('/order/orderQuery', { data: { orderCode: orderCode }, loading: true }).then((res) => {
+        if (res.result == '100001') {
+            		RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${orderId}&orderType=${orderFormData.value.orderType}`)
+        } else if (retryCount <= 3) {
+            setTimeout(() => {
+                getOrderQuery(orderCode,orderId, retryCount + 1)
+            }, 1000)
+        } else {
+            if (res.result == '100003') {
+                console.log('查询中,但已达到最大查询次数')
+            } else if (res.result == '100002') {
+                console.log('查询失败')
+            } else if (res.result == '100004') {
+                console.log('支付失败')
+				TipsUtils.tips_toast('支付失败')
+            }
+        }
+    }).catch((error) => {
+        console.error('查询订单失败:', error)
+        if (retryCount < 2) { 
+            setTimeout(() => {
+                getOrderQuery(orderCode,orderId, retryCount + 1)
+            }, 1000)
+        }
+    })
+}
 </script>
 
 <style lang="less" scoped>

+ 125 - 48
src/pages/index/gymPay/index.vue

@@ -5,9 +5,12 @@
 			<view class="g-shoping-info" v-if="previewCourseInfo">
 				<image class="shoping-img" :src="previewCourseInfo.cover" mode=""></image>
 				<view class="shoping-info">
-					<view class="name">{{ previewCourseInfo.placeName||previewCourseInfo.name }}</view>
+					<view class="name">{{ previewCourseInfo.placeName || previewCourseInfo.name }}</view>
 					<view class="price-info">
-						<view class="price"><text class="mini-text">¥</text>{{ previewCourseInfo?.sellingPrice.toFixed(2) }}</view>
+						<!-- previewCourseInfo?.originalPrice字段用来判断是课程订单还是场地订单 -->
+						<view class="price"><text class="mini-text">¥</text>{{ previewCourseInfo?.originalPrice ?
+							previewCourseInfo?.originalPrice : previewCourseInfo?.sellingPrice.toFixed(2)
+						}}</view>
 						<view class="price-stepper">
 							<view class="minus" @click="minusNum">-</view>
 							<input v-model="countTotal" disabled type="number" />
@@ -18,8 +21,11 @@
 			</view>
 			<view class="g-shoping-total">
 				<view class="total-price">
-					<view class="">商品总价(共1件)</view>
-					<view class="">¥{{ previewCourseInfo?.sellingPrice.toFixed(2) }}</view>
+					<view class="">商品总价(共{{ countTotal }}件)</view>
+					<view class="">¥{{
+						previewCourseInfo?.originalPrice ? (previewCourseInfo?.originalPrice * countTotal).toFixed(2) :
+							previewCourseInfo?.sellingPrice.toFixed(2)
+							* countTotal }}</view>
 				</view>
 				<view class="total-price">
 					<view class="">
@@ -27,12 +33,23 @@
 						<text v-if="buyType == 0 || placeId">团购优惠</text>
 					</view>
 					<view class="">-¥
-						<text v-if="buyType == 0 || !placeId">{{ previewCourseInfo?.discountPrice }}</text>
-						<text v-else>{{ (previewCourseInfo?.originalPrice - previewCourseInfo?.sellingPrice).toFixed(2) }}</text>
+						<!-- <text v-if="buyType == 0 || !placeId">{{ previewCourseInfo?.discountPrice }}</text> -->
+						<text v-if="buyType == 1">{{ previewCourseInfo?.sellingPrice.toFixed(2) }}</text>
+						<text v-else>{{
+							previewCourseInfo?.originalPrice ? (previewCourseInfo?.originalPrice -
+								previewCourseInfo?.sellingPrice.toFixed(2)) * countTotal : ((previewCourseInfo?.sellingPrice
+									-
+									previewCourseInfo?.totalPrice.toFixed(2))) * countTotal }}</text>
 					</view>
 				</view>
 			</view>
-			<view class="subtotal">小计 ¥{{previewCourseInfo?.discountPrice?totalPriceDisplay-previewCourseInfo?.discountPrice:totalPriceDisplay }}</view>
+			<view class="subtotal">小计 ¥
+				<text v-if="buyType == 1">0.00</text>
+				<text v-else>{{ previewCourseInfo?.originalPrice ? (previewCourseInfo?.sellingPrice *
+					countTotal).toFixed(2) :
+					(previewCourseInfo?.sellingPrice.toFixed(2) - (previewCourseInfo?.sellingPrice -
+						previewCourseInfo?.totalPrice.toFixed(2))) * countTotal }}</text>
+			</view>
 		</view>
 		<!-- 课程进入 -->
 		<view class="r-insurance" v-for="item in insureIdList" :key="item.id">
@@ -58,8 +75,8 @@
 					</view>
 				</view>
 			</view>
-			<view class="line" v-if="insureData.length > 0"></view>
-			<blcok v-if="insureData.length > 0">
+			<view class="line" v-if="insureData.length > 0 && insureId == item.id"></view>
+			<blcok v-if="insureData.length > 0 && insureId == item.id">
 				<view class="r-insurance-adduser" v-for="(insureUser, index) in insureData" :key="index">
 					<view class="r-adduser-btn">
 						<view class="r-celar" @click="clearUser">清除</view>
@@ -76,7 +93,7 @@
 						</view>
 						<view class="r-userinfo-item">
 							<view class="r-item-title">生效时间</view>
-							<view class="r-item-info">{{ insureUser.slectObj.day }}天({{ insureUser.startDate }}-{{
+							<view class="r-item-info">{{ insureUser.slectObj.insureDay }}天({{ insureUser.startDate }}-{{
 								insureUser.endDate }})
 							</view>
 						</view>
@@ -118,7 +135,8 @@
 					<rich-text :nodes="previewCourseInfo?.reminder"></rich-text>
 				</view>
 			</view>
-			<view class="use-tips-more" @click="RouterUtils.to_page(`/pages/index/useNotice/index?reminder=${previewCourseInfo?.reminder}`)">
+			<view class="use-tips-more"
+				@click="RouterUtils.to_page(`/pages/index/useNotice/index?reminder=${previewCourseInfo?.reminder}`)">
 				<view class="more-text">查看更多</view>
 				<view class="use-line"></view>
 			</view>
@@ -139,15 +157,29 @@
 		<view class="footer footer-box">
 			<view class="footer-price">
 				<view class="total-price">合计:</view>
-				<view class="price"><text class="mini-text">¥</text>
-					<text>{{ previewCourseInfo?.discountPrice?totalPriceDisplay-previewCourseInfo?.discountPrice:totalPriceDisplay }}</text>
+				<view class="price">
+					<text class="mini-text">¥</text>
+					<text>{{
+						previewCourseInfo?.originalPrice ? (previewCourseInfo?.originalPrice * countTotal).toFixed(2) :
+							((previewCourseInfo?.sellingPrice
+								|| 0) * countTotal + totalInsurePrice).toFixed(2) }}</text>
+				</view>
+				<view class="discount">优惠¥
+					<text v-if="buyType == 1">{{ previewCourseInfo?.sellingPrice.toFixed(2) }}</text>
+					<text v-else>{{ previewCourseInfo?.originalPrice ? previewCourseInfo?.originalPrice :
+						((previewCourseInfo?.sellingPrice - previewCourseInfo?.totalPrice.toFixed(2))) * countTotal
+					}}</text>
 				</view>
-				<view class="discount">优惠¥{{ previewCourseInfo?.totalDiscount }}</view>
 			</view>
 			<view class="footer-btn" @click="submitOrder">
 				<button>
 					<view class="btn-price">
-						<text> ¥{{ previewCourseInfo?.discountPrice?totalPriceDisplay-previewCourseInfo?.discountPrice:totalPriceDisplay  }}</text>
+						<text v-if="buyType == 1">0.00</text>
+						<text v-else>
+							¥{{ previewCourseInfo?.originalPrice ? (previewCourseInfo?.sellingPrice *
+								countTotal).toFixed(2) :
+								(((previewCourseInfo?.sellingPrice || 0) - ((previewCourseInfo?.sellingPrice || 0) -
+									(previewCourseInfo?.totalPrice || 0))) * countTotal + totalInsurePrice).toFixed(2) }}</text>
 					</view>
 					<view class="btn-price">立即支付</view>
 				</button>
@@ -174,9 +206,11 @@
 
 <script lang="ts" setup>
 import { ref, onMounted, computed } from 'vue';
-import { onLoad } from '@dcloudio/uni-app';
-import { RouterUtils, TipsUtils, idCardHide } from '@/utils/util';
+import { onLoad, onShareAppMessage } from '@dcloudio/uni-app';
+import { RouterUtils, TipsUtils, idCardHide,debounce } from '@/utils/util';
 import { http } from '@/utils/http'
+import { useCacheStore } from '@/stores/cache'
+const cache = useCacheStore()
 const insurePopup = ref()
 const select_insurance = ref(false)
 const loadType = ref(1)
@@ -192,29 +226,17 @@ onLoad((options) => {
 	orderFormData.value.orFreeOrder = options.buyType
 	orderFormData.value.amount = 1
 })
-// 优化价格计算,合并保险价格
-const totalPrice = computed(() => {
-	let basePrice = 0;
-	if (previewCourseInfo.value) {
-		if (previewCourseInfo.value.totalPrice) {
-			basePrice = Number(previewCourseInfo.value.totalPrice) * Number(countTotal.value);
-		} else if (previewCourseInfo.value.sellingPrice) {
-			basePrice = Number(previewCourseInfo.value.sellingPrice) * Number(countTotal.value);
-		}
-	}
-	let insureTotal = 0;
-	if (Array.isArray(insureData.value) && insureData.value.length > 0) {
-		insureTotal = insureData.value.reduce((sum, item) => {
-			const price = Number(item.totalPrice) || 0;
-			return sum + price;
-		}, 0);
-	}
-	return basePrice + insureTotal;
-});
 
-const totalPriceDisplay = computed(() => {
-	return totalPrice.value.toFixed(2);
-});
+onShareAppMessage((res) => {
+	if (res.from === 'button') {// 来自页面内分享按钮
+		console.log(res.target)
+	}
+	return {
+		title: '邀请您加入',
+		path: `pages/index/userList/index?userId=${cache.get('USER_INFO').id}`
+	}
+})
+
 onMounted(() => {
 	if (placeId.value) {
 		getEventsDetail()
@@ -250,7 +272,9 @@ const deleteUser = async (e) => {
 }
 
 const priceDataListData = ref([])
+const insureId = ref()
 const gotoInsuracePage = (e1: any, e2: any) => {
+	insureId.value = e1.id
 	getFindByType(e1.insuranceName)
 	priceDataListData.value = e2
 	orderFormData.value.insureOrderInfoForm.insureId = e1.id
@@ -310,6 +334,16 @@ const getInsureData = () => {
 		}
 	})
 }
+// 计算保费
+const totalInsurePrice = computed(() => {
+	if (!insureData.value || insureData.value.length === 0) {
+		return 0;
+	}
+	if (insureData.value.length === 1) {
+		return parseFloat(insureData.value[0].totalPrice) || 0;
+	}
+	return insureData.value.reduce((total, insure) => total + (parseFloat(insure.totalPrice) || 0), 0);
+});
 
 const clearUser = async () => {
 	let res: any = await TipsUtils.tips_alert('确定清除投保人信息吗?', true)
@@ -328,9 +362,9 @@ const minusNum = () => {
 
 const addNum = () => {
 	if (buyType.value == 1) return TipsUtils.tips_toast('试听课程不支持多个购买')
-	if(courseId.value){
-	get_checkCourseLimitNum(countTotal.value + 1)
-	}else{
+	if (courseId.value) {
+		get_checkCourseLimitNum(countTotal.value + 1)
+	} else {
 		countTotal.value++
 	}
 }
@@ -368,7 +402,7 @@ const toRefuse = () => {
 let orderFormData = ref({
 	type: null,
 	orderType: null,
-	orFreeOrder: 1,
+	orFreeOrder: null, //0正常 1试听
 	productIds: null,
 	amount: null,
 	familyIds: '',
@@ -380,12 +414,12 @@ let orderFormData = ref({
 		familyMembersIds: '',
 	}
 })
-const submitOrder = () => {
+const submitOrderImpl = () => {
 	orderFormData.value.amount = countTotal.value
 	if (!placeId.value) {
 		if (!userData.value) return TipsUtils.tips_toast('请添加用户信息')
 		if (userData.value.length < countTotal.value) return TipsUtils.tips_toast(`请至少选择${countTotal.value}人`)
-		if(userData.value.length > countTotal.value) return TipsUtils.tips_toast(`最多选择${countTotal.value}人`)
+		if (userData.value.length > countTotal.value) return TipsUtils.tips_toast(`最多选择${countTotal.value}人`)
 		orderFormData.value.orderType = 5
 		orderFormData.value.type = 2
 	} else {
@@ -396,11 +430,54 @@ const submitOrder = () => {
 	if (!insureData.value || insureData.value.length === 0) {
 		delete data.insureOrderInfoForm;
 	}
-	if(!userData||userData.value.length === 0){
+	if (!userData || userData.value.length === 0) {
 		delete data.familyIds
 	}
-	http.post('/order/createOrder', data, { loading: true }).then((res) => {
-		RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${res.result.orderId}&orderType=${orderFormData.value.orderType}`)
+	uni.requestSubscribeMessage({
+		tmplIds: ['Yi1Z1IKRwgF6-mpiFcOUTvavc4TUAsfsLynK_3Yu350', 'NPlIBEwBDPX23J3Jip0CwYUU4vF9ZlcK8U1d6Gs4yrM'],
+		success(res) {
+			TipsUtils.tips_toast('订阅成功')
+			http.post('/order/createOrder', data, { loading: true }).then((res) => {
+				getOrderQuery(res.result.orderCode,res.result.orderId)
+			})
+		},
+		fail(err) {
+			console.log(err, '订阅消息失败')
+			http.post('/order/createOrder', data, { loading: true }).then((res) => {
+				getOrderQuery(res.result.orderCode,res.result.orderId)
+			})
+		}
+	})
+}
+
+const submitOrder = debounce(submitOrderImpl, 500)
+
+// code编码 "100001支付成功";"100002查询失败"; "100003查询中 "; "100004支付失败"
+const getOrderQuery = (orderCode: string,orderId:string, retryCount = 0) => {
+	http.get('/order/orderQuery', { data: { orderCode: orderCode }, loading: true }).then((res) => {
+		if (res.result == '100001') {
+			RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${orderId}&orderType=${orderFormData.value.orderType}`)
+		} else if (retryCount <= 3) {
+			setTimeout(() => {
+				getOrderQuery(orderCode,orderId, retryCount + 1)
+			}, 1000)
+		} else {
+			if (res.result == '100003') {
+				console.log('查询中,但已达到最大查询次数')
+			} else if (res.result == '100002') {
+				console.log('查询失败')
+			} else if (res.result == '100004') {
+				console.log('支付失败')
+				TipsUtils.tips_toast('支付失败')
+			}
+		}
+	}).catch((error) => {
+		console.error('查询订单失败:', error)
+		if (retryCount < 2) {
+			setTimeout(() => {
+				getOrderQuery(orderCode,orderId, retryCount + 1)
+			}, 1000)
+		}
 	})
 }
 </script>

+ 12 - 2
src/pages/index/index.vue

@@ -17,7 +17,7 @@
 		</view>
 		<view class="content" style="padding-top:180rpx;">
 			<view class="header-search">
-				<zzx-icon name="search" size="18"></zzx-icon>
+				<zzx-icon name="search" size="18" style="margin-left: 10rpx;margin-top: 4rpx;"></zzx-icon>
 				<swiper class="i-search-swiper" :vertical="true" :circular="true" :autoplay="true" :interval="5000"
 					:duration="1000" @click="gotoPage('/pages/index/search/index')" @change="transitionChange">
 					<swiper-item v-for="(item, index) in searchList" :key="item.id">
@@ -169,7 +169,7 @@
 							<view class="price">¥{{ (course.sellingPrice).toFixed(2) || '0.00' }}</view>
 							<view class="name textHidden">{{ course.name }}</view>
 						</view>
-						<view class="num">已售{{ item.count || '0' }}</view>
+						<view class="num">已售{{ course.count || '0' }}</view>
 					</view>
 					<view class="more" @click="gotoPage(`/pages/index/instructorDetail/index?id=${item.id}`)">更多课程
 					</view>
@@ -263,6 +263,12 @@ const get_logininfo = (item: string) => {
 		get_searchList()
 		get_userinfo()
 		TipsUtils.tips_toast('登录成功')
+		if (cache.get('SHARER_ID') && token.value) {
+			gotoPage('/pages/index/userList/index')
+		}
+		if (cache.get('COURSE_ID') && token.value) {
+			gotoPage(`/pages/index/courseDetail/index?id=${cache.get('COURSE_ID')}`)
+		}
 	})
 }
 
@@ -321,6 +327,7 @@ const getAddressInfo = () => {
 			longitude: cache.get('LON')
 		},
 		success: function (res: any) {
+			console.log(res, '逆解析成功');
 			addressName.value = res.result.address
 		},
 		fail: function (err: any) {
@@ -586,12 +593,14 @@ const searchInfoBtn = () => {
 	display: flex;
 	align-items: center;
 	justify-content: space-between;
+	gap: 20rpx;
 	margin-top: 20rpx;
 
 	.commonweal {
 		background: #C8FF0C;
 		border-radius: 32rpx;
 		padding: 20rpx;
+		width: 350rpx;
 
 		.commonweal-title {
 			display: flex;
@@ -643,6 +652,7 @@ const searchInfoBtn = () => {
 		background: #AB7BFF;
 		border-radius: 32rpx;
 		padding: 20rpx;
+		width: 350rpx;
 
 		.audition-title {
 			display: flex;

+ 1 - 1
src/pages/index/insure/index.vue

@@ -68,7 +68,7 @@
       <view class="detail-item">
         <view class="item-title">生效天数</view>
         <view class="item-text">
-          <text v-if="slectObj">{{ slectObj.day || '0' }}天</text>
+          <text v-if="slectObj">{{ slectObj.insureDay || '0' }}天</text>
           <text v-else>--</text>
         </view>
       </view>

+ 2 - 3
src/pages/index/search/index.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="content">
 		<view class="header-search">
-			<zzx-icon name="search" size="18"></zzx-icon>
+			<zzx-icon name="search" size="18" style="margin-top: 2rpx;margin-left: 20rpx;"></zzx-icon>
 			<input type="text" v-model="searchText" placeholder="搜索俱乐部名称" />
 			<view class="search-btn" @click="to_search">
 				搜索
@@ -74,7 +74,6 @@
 		background: #F6F6F6;
 		width: 700rpx;
 		border-radius: 40rpx;
-		padding: 0 20rpx;
 		&>input {
 			width: 670rpx;
 			font-weight: bold;
@@ -83,7 +82,7 @@
 		}
 
 		.search-btn {
-			width: 144rpx;
+			width: 200rpx;
 			height: 52rpx;
 			background: #222222;
 			border-radius: 28rpx;

+ 98 - 12
src/pages/index/submitOrder/index.vue

@@ -24,8 +24,10 @@
 			<view class="s-title">选择时段</view>
 			<view class="select-card-list">
 				<scroll-view class="scroll-view_H" scroll-x="true">
-					<view class="item-card" :style="{ background: `${check_index == index ? '#F0FFBB' : '#F6F6F6'}` }"
-						v-for="(item, index) in timeList?.timeSlot" @click="check_item(item, index)">
+					<view class="item-card" :style="{
+						background: `${check_index == index ? '#F0FFBB' : shouldGrayOut(item.endTime) ? '#E0E0E0' : '#F6F6F6'}`,
+						opacity: shouldGrayOut(item.endTime) ? 0.6 : 1
+					}" v-for="(item, index) in timeList?.timeSlot" @click="!shouldGrayOut(item.endTime) && check_item(item, index)">
 						<view class="time">{{ item.name }}</view>
 						<view class="allowance">余{{ item.inventory }}</view>
 						<view class="price">¥{{ item.price || '0.00' }}</view>
@@ -75,7 +77,7 @@
 						</view>
 						<view class="r-userinfo-item">
 							<view class="r-item-title">生效时间</view>
-							<view class="r-item-info">{{ insureUser.slectObj.day }}天({{ insureUser.startDate }}-{{
+							<view class="r-item-info">{{ insureUser.slectObj.insureDay }}天({{ insureUser.startDate }}-{{
 								insureUser.endDate }})
 							</view>
 						</view>
@@ -94,6 +96,7 @@
 					<zzx-icon name="wechat" size="16"></zzx-icon>
 					<view style="margin-bottom: 8rpx;">邀请微信好友</view>
 					<zzx-icon name="ashRight" size="12"></zzx-icon>
+					<button class="g-share-btn" open-type="share"></button>
 				</view>
 			</view>
 			<!-- <view class="user-tags">张三</view> -->
@@ -132,15 +135,28 @@
 
 <script lang="ts" setup>
 import { ref, onMounted } from 'vue';
-import { RouterUtils, TipsUtils, idCardHide } from '@/utils/util';
-import { onLoad, onPageScroll } from '@dcloudio/uni-app';
+import { RouterUtils, TipsUtils, idCardHide,debounce } from '@/utils/util';
+import { onLoad, onShareAppMessage } from '@dcloudio/uni-app';
 import { http } from '@/utils/http'
+import { useCacheStore } from '@/stores/cache'
+const cache = useCacheStore()
 const calendar = ref();
 const check_index = ref(0);
 onLoad((option) => {
 	placeId.value = option.id
 	orderFormData.value.productIds = option.id
 })
+
+onShareAppMessage((res) => {
+	if (res.from === 'button') {// 来自页面内分享按钮
+		console.log(res.target)
+	}
+	return {
+		title: '邀请您加入',
+		path: `pages/index/userList/index?userId=${cache.get('USER_INFO').id}`
+	}
+})
+
 onMounted(() => {
 	get_previewTIme()
 	get_userData()
@@ -161,7 +177,26 @@ const open_calendar = (e, i) => {
 // 日历回调确认
 const confirm = (e) => {
 	get_previewOrderPlaceSchool(e.fulldate)
+	 selIndex.value = -1
 }
+
+// 置灰处理
+const shouldGrayOut = (endTime: string) => {
+	// 只有当选中的日期是今天时才检查时间是否过期
+	if (dateList.value && dateList.value[selIndex.value] && dateList.value[selIndex.value].namedDay === '今天') {
+		return isTimeExpired(endTime);
+	}
+	return false;
+}
+
+const isTimeExpired = (endTime: string) => {
+	if (!endTime) return false;
+	const now = new Date();
+	const currentTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
+	// 比较时间
+	return currentTime > endTime;
+}
+
 const rulesId = ref()
 const check_item = (e, i) => {
 	check_index.value = i
@@ -186,8 +221,20 @@ const insurePrice = ref() // 保险价格
 const get_previewOrderPlaceSchool = (startTime) => {
 	http.get('/order/previewOrderPlaceSchool', { data: { placeId: placeId.value, startTime: startTime }, loading: true }).then((res) => {
 		timeList.value = res.result
-		rulesId.value = res.result.timeSlot[0].id
-		orderFormData.value.productIds = res.result.timeSlot[0].id
+		let defaultIndex = 0
+		if (res.result.timeSlot && res.result.timeSlot.length > 0) {
+			for (let i = 0; i < res.result.timeSlot.length; i++) {
+				if (!isTimeExpired(res.result.timeSlot[i].endTime)) {
+					defaultIndex = i
+					break
+				}
+			}
+			check_index.value = defaultIndex
+			rulesId.value = res.result.timeSlot[defaultIndex].id
+			orderFormData.value.productIds = res.result.timeSlot[defaultIndex].id
+		}
+
+		// 处理保险相关数据
 		res.result.insureIdList.map((item: any) => {
 			item.insuranceObvious = JSON.parse(item.insuranceObvious)
 			item.insuranceObvious = [item.insuranceObvious]
@@ -260,7 +307,7 @@ const toRefuse = () => {
 const userData = ref([])
 const get_userData = () => {
 	uni.$on('userData', function (data) {
-		console.log(data,'携带用户');
+		console.log(data, '携带用户');
 		userData.value = data
 		if (data.length > 0) {
 			let familyIds = data.map(item => item.id)
@@ -292,8 +339,8 @@ let orderFormData = ref({
 		familyMembersIds: '',
 	}
 })
-const submitBooking = () => {
-	if(userData.value.length === 0) return TipsUtils.tips_toast('请添加成员')
+const submitOrderImpl = () => {
+	if (userData.value.length === 0) return TipsUtils.tips_toast('请添加成员')
 	let data = { ...orderFormData.value };
 	if (!insureData.value || insureData.value.length === 0) {
 		delete data.insureOrderInfoForm;
@@ -303,15 +350,46 @@ const submitBooking = () => {
 			tmplIds: ['WSJjc9I24ijtr3EyNVXjEvTQm0gIECW9ABYVFcegOwM'],
 			success(su) {
 				TipsUtils.tips_toast('订阅成功')
-				RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${res.result.orderId}&orderType=${orderFormData.value.orderType}`)
+				getOrderQuery(res.result.orderCode,res.result.orderId)
 			},
 			fail(err) {
-				RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${res.result.orderId}&orderType=${orderFormData.value.orderType}`)
+				getOrderQuery(res.result.orderCode,res.result.orderId)
 				console.log(err, '订阅消息失败')
 			}
 		})
 	})
 }
+
+const submitBooking = debounce(submitOrderImpl, 500)  //防抖
+
+// code编码 "100001支付成功";"100002查询失败"; "100003查询中 "; "100004支付失败"
+const getOrderQuery = (orderCode: string,orderId: string, retryCount = 0) => {
+	http.get('/order/orderQuery', { data: { orderCode: orderCode }, loading: true }).then((res) => {
+		if (res.result == '100001') {
+			RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${orderId}&orderType=${orderFormData.value.orderType}`)
+		} else if (retryCount <= 3) {
+			setTimeout(() => {
+				getOrderQuery(orderCode,orderId, retryCount + 1)
+			}, 1000)
+		} else {
+			if (res.result == '100003') {
+				console.log('查询中,但已达到最大查询次数')
+			} else if (res.result == '100002') {
+				console.log('查询失败')
+			} else if (res.result == '100004') {
+				console.log('支付失败')
+				TipsUtils.tips_toast('支付失败')
+			}
+		}
+	}).catch((error) => {
+		console.error('查询订单失败:', error)
+		if (retryCount < 2) {
+			setTimeout(() => {
+				getOrderQuery(orderCode,orderId, retryCount + 1)
+			}, 1000)
+		}
+	})
+}
 </script>
 
 <style lang="less" scoped>
@@ -614,6 +692,14 @@ const submitBooking = () => {
 			gap: 8rpx;
 			font-size: 24rpx;
 			color: #AAAAAA;
+			position: relative;
+
+			.g-share-btn {
+				position: absolute;
+				width: 200rpx;
+				height: 60rpx;
+				opacity: 0;
+			}
 		}
 	}
 

+ 106 - 14
src/pages/index/toBeUsed/index.vue

@@ -12,9 +12,9 @@
 			<view class="title">{{ orderDetailInfo?.orderStatus }}</view>
 			<view style="display: flex;gap: 10rpx;">
 				<view class="time" v-for="item in orderDetailInfo?.proInfoList" :key="item.id">
-					<text style="color: #FB5B5B;" v-if="item.type != 7">{{ item.userName }}</text>
-					<text v-if="orderDetailInfo?.orderStatus && item.type != 7">{{ orderDetailInfo?.orderStatus + ';'
-					}}</text>
+					<text style="color: #FB5B5B;" v-if="item.type != 6">{{ item.userName }}</text>
+					<!-- 0-待付款 1-待使用 2-已使用 3-已到期 4-已取消 5-退款中 6已退款 -->
+					<text v-if="item.type != 6">{{ getStatusText(item.orderStatus) }}</text>
 					<!-- <text v-if="orderDetailInfo?.orderStatus == '待使用'">,请按课表到上课地点按时上课。</text> -->
 				</view>
 			</view>
@@ -37,7 +37,8 @@
 				<view class="text">场次</view>
 				<view class="">
 					<view class="time-box" v-for="item in orderDetailInfo?.proInfoList" :key="item.id">
-						<view class="time" v-if="item.type!=7">{{ item.useDateStr }} {{ item.frameTimeStr }} {{ item.productName }}</view>
+						<view class="time" v-if="item.type != 6">{{ item.useDateStr }} {{ item.frameTimeStr }} {{
+							item.productName }}</view>
 						<view class="status" v-if="orderPageInfo?.orderType == 1">已退款</view>
 					</view>
 				</view>
@@ -95,12 +96,13 @@
 				</view>
 			</view>
 			<view class="t-invite" v-if="orderPageInfo?.orderType == 5">
+				<button class="g-share-btn" open-type="share"></button>
 				邀请好友报名
 			</view>
 		</view>
 		<!-- 待使用展示 -->
 		<view class="t-qrcode-card"
-			v-if="orderPageInfo?.orderType == 2 || orderPageInfo?.orderType == 0 || orderPageInfo?.orderType == 5 || orderPageInfo?.orderType == 1 || orderPageInfo?.orderType == 3 || orderPageInfo?.orderType == 4">
+			v-if="orderPageInfo?.orderType == 2 || orderPageInfo?.orderType == 5 || orderPageInfo?.orderType == 1 || orderPageInfo?.orderType == 3 || orderPageInfo?.orderType == 4">
 			<block v-if="orderDetailInfo?.orSchoolCourse != 1">
 				<view class="qrcode-box">
 					<view class="item-qrcode">
@@ -112,13 +114,17 @@
 			<view v-else style="color: #222;font-size: 26rpx;">通过学校门口闸机时,通过人脸自动核验</view>
 			<view class="t-todeused">
 				<view class="todeused">
-					<view class="text">待使用</view>
+					<view class="text">{{ orderDetailInfo?.orderStatus }}</view>
 					<view class="time" v-if="orderDetailInfo?.appCourses?.endTime || orderDetailInfo?.endTime">{{
 						orderDetailInfo?.appCourses?.endTime || orderDetailInfo?.endTime }} 到期</view>
 				</view>
+				<!-- 0-待付款 1-待使用 2-已使用 3-已到期 4-已取消 5-退款中 6已退款 -->
 				<view class="order-num" v-for="item in orderDetailInfo?.proInfoList" :key="item.id">
-					<text v-if="item.type != 7">{{ item.ticketNo }}&nbsp;&nbsp; {{ item.userName }}</text>
-					<zzx-icon v-if="item.type != 7" name="ashRight" size="12"></zzx-icon>
+					<text v-if="item.type != 6">{{ item.ticketNo }}&nbsp;&nbsp; {{ item.userName }}</text>
+					<zzx-icon v-if="item.type != 6" name="ashRight" size="12"></zzx-icon>
+					<view v-if="item.type != 6" class="t-use-status">{{ getStatusText(item.orderStatus) }}</view>
+					<!-- 体育馆包场和无固定场 -->
+					<!-- <view>申请退款</view> -->
 				</view>
 			</view>
 		</view>
@@ -225,7 +231,8 @@
 					</view>
 					<view class="item-sign">
 						<view class="sign-title">已签署:</view>
-						<view class="sign-name" v-for="item in signList" :key="item.id">{{ item.fullName }}</view>
+						<view class="sign-name" v-for="item in signList" :key="item.id" @click="checkItemSign(item)">{{
+							item.fullName }}</view>
 					</view>
 				</view>
 			</view>
@@ -285,7 +292,7 @@
 			<view class="morefeatures-btn">查看成绩</view>
 		</view>
 		<!-- 已使用展示 -->
-		<view class="appraise-btn" v-if="orderPageInfo?.orderType != 3"
+		<view class="appraise-btn" v-if="orderPageInfo?.orderType != 3 && orderDetailInfo?.orderStatus == '已使用'"
 			@click="RouterUtils.to_page(`/pages/index/writeComments/index?siteId=${orderDetailInfo?.addressSiteId}&orderId=${orderDetailInfo?.id}`)">
 			写评价
 		</view>
@@ -378,10 +385,9 @@
 <script lang="ts" setup>
 import { ref, onMounted } from 'vue';
 import { TipsUtils, RouterUtils, DateUtils, _previewImage } from '@/utils/util'
-import { onLoad } from '@dcloudio/uni-app';
+import { onLoad, onShow, onShareAppMessage } from '@dcloudio/uni-app';
 import { http } from '@/utils/http'
 import zsLoading from '@/components/zzx-loading/zzx-loading.vue'
-
 const qrcode = ref();
 const pricePopup = ref()  //价格
 const refundPopup = ref()  //退款
@@ -391,9 +397,37 @@ onLoad((option) => {
 	orderPageInfo.value = option
 	console.log(option, '路由参数');
 })
-onMounted(() => {
+onShow(() => {
 	getOrderDetailInfo()
 })
+onShareAppMessage((res) => {
+	if (res.from === 'button') {// 来自页面内分享按钮
+		console.log(res.target)
+	}
+	return {
+		title: `邀请您报名《${orderDetailInfo?.value.appCourses?.name}》`,
+		path: `/pages/index/courseDetail/index?id=${orderDetailInfo?.value.appCourses?.id}`,
+		imageUrl: orderDetailInfo?.value.appCourses?.cover,
+	}
+})
+
+onMounted(() => {
+})
+
+// 子订单状态映射
+const statusMap = {
+	0: '待付款',
+	1: '待使用',
+	2: '已使用',
+	3: '已到期',
+	4: '已取消',
+	5: '退款中'
+}
+
+// 获取状态文本的函数
+const getStatusText = (status: number): string => {
+	return statusMap[status as keyof typeof statusMap] || ''
+}
 const download_qrcode = () => { //下载二维码,增加授权判断
 	// #ifdef MP-WEIXIN
 	uni.authorize({
@@ -559,11 +593,49 @@ const getQueryWaitSignList = (orderId: string) => {
 	})
 }
 
-
+// 签署未完成
 const checkSign = (e: any) => {
 	get_UserIdentityInfo(e.familyId)
 }
 
+// 已签署
+const checkItemSign = (item: any) => {
+	console.log(item);
+	http.get('/esign/fileDownloadUrl', { data: { signFlowId: item.signFlowId }, loading: true }).then((res) => {
+		uni.downloadFile({
+			url: res.result[0].downloadUrl,
+			timeout: 30000,
+			success: function (res) {
+				if (res.statusCode === 200) {
+					uni.openDocument({
+						filePath: res.tempFilePath,
+						fileType: 'pdf',
+						showMenu: true,
+						success: function (res) {
+							console.log('打开文档成功');
+						},
+						fail: function (err) {
+							console.log('打开文档失败', err);
+							uni.saveFile({
+								tempFilePath: res.tempFilePath,
+								success: function (saveRes) {
+									console.log('文件保存成功', saveRes.savedFilePath);
+								}
+							});
+						}
+					});
+				} else {
+					console.error('下载失败,状态码:', res.statusCode);
+				}
+			},
+			fail: function (err) {
+				console.error('下载失败', err);
+			}
+		});
+	});
+}
+
+
 // 查询授权
 const get_UserIdentityInfo = (familyId: string) => {
 	http.get('/esign/getUserIdentityInfo', { data: { familyId: familyId }, loading: true }).then((res) => {
@@ -882,6 +954,15 @@ const getSignUrl = (signFlowId: string) => {
 		font-size: 28rpx;
 		color: #FDD143;
 		text-align: center;
+		position: relative;
+
+		.g-share-btn {
+			position: absolute;
+			top: -10rpx;
+			width: 600rpx;
+			height: 60rpx;
+			opacity: 0;
+		}
 	}
 }
 
@@ -954,6 +1035,17 @@ const getSignUrl = (signFlowId: string) => {
 			&>text {
 				margin-bottom: 8rpx;
 			}
+
+			.t-use-status {
+				width: 100rpx;
+				height: 40rpx;
+				background: #C8FF0C;
+				border-radius: 8rpx;
+				font-size: 24rpx;
+				color: #222222;
+				text-align: center;
+				line-height: 40rpx;
+			}
 		}
 	}
 

+ 3 - 3
src/pages/index/training/index.vue

@@ -11,7 +11,7 @@
 			<view :class="sel_btn===index?'distance':'score'" v-for="(item,index) in selectList" :key="index"
 				@click="select_btn(item,index)">{{item.text}}</view>
 		</view>
-		<block v-if="courseList.length>1">
+		<block v-if="courseList.length>0">
 			<view class="t-card-list" v-for="item in courseList" :key="item.id" @click="RouterUtils.to_page(`/pages/index/courseDetail/index?id=${item.id}`)">
 				<view class="t-courseImg">
 					<image :src="item.cover" mode=""></image>
@@ -19,8 +19,8 @@
 				<view class="t-course">
 					<view class="c-title textHidden">{{item.name}}</view>
 					<view class="c-address" v-if="item.km">{{item.address}} | {{item.km.toFixed(2)}}km</view>
-					<view class="c-price">¥{{ item.sellingPrice.toFixed(2) }}
-						<text v-if="item.priceType==0"
+					<view class="c-price" v-if="item.sellingPrice">¥{{ item.sellingPrice.toFixed(2) }}
+						<text v-if="item.priceType==0&&item.originalPrice"
 							style="font-size: 22rpx;color: #AAAAAA;text-decoration: line-through;">¥{{ item.originalPrice.toFixed(2) }}</text>
 					</view>
 					<view class="c-ratio">已售{{item.saleNum||'0'}} {{item.goodRate}}%好评</view>

+ 18 - 4
src/pages/index/userList/index.vue

@@ -37,7 +37,7 @@
 import { ref, onMounted, computed } from 'vue';
 import { http } from '@/utils/http';
 import { useCacheStore } from '@/stores/cache'
-import { onShow,onLoad, onReachBottom } from '@dcloudio/uni-app';
+import { onShow, onLoad, onReachBottom, onShareAppMessage } from '@dcloudio/uni-app';
 import { RouterUtils, idCardHide } from '@/utils/util';
 const cache = useCacheStore()
 const userList = ref()
@@ -49,22 +49,35 @@ const userinfo = computed(() => {
 const selectType = ref()
 const nameText = ref()
 onLoad((options) => {
+	console.log('邀请好友页面load信息:', options);
 	selectType.value = options.type
-	// console.log('options', options);
 	nameText.value = options.name
 	if (options.name) {
 		uni.setNavigationBarTitle({
 			title: options.name
 		});
 	}
+	if (options.userId) {
+    console.log('用户通过分享卡片进入,分享者ID:', options.userId)
+    cache.set('SHARER_ID', options.userId)
+  }
 })
-onShow(()=>{
+onShow(() => {
 	get_userList()
 })
 onReachBottom(() => {
 	pageNo.value++
 	get_userList()
 })
+onShareAppMessage((res) => {
+	if (res.from === 'button') {// 来自页面内分享按钮
+		console.log(res.target)
+	}
+	return {
+		title: '邀请您加入',
+		path: `pages/index/userList/index?userId=${cache.get('USER_INFO').id}`
+	}
+})
 onMounted(() => {
 })
 
@@ -149,6 +162,7 @@ const confirmSelect = () => {
 		// flex-direction: column;  换行	
 		gap: 10rpx;
 		position: relative;
+
 		&>view {
 			font-size: 28rpx;
 			color: #222222;
@@ -157,7 +171,7 @@ const confirmSelect = () => {
 		.g-share-btn {
 			position: absolute;
 			width: 300rpx;
-			height:110rpx;
+			height: 110rpx;
 			opacity: 0;
 		}
 	}

+ 113 - 96
src/pages/mine/mineComments/index.vue

@@ -6,7 +6,7 @@
 		<view class="m-comments-card" v-for="item in commentsList" :key="item.id">
 			<view class="m-comments-name">
 				<zzx-icon name="venue-icon4" size="14"></zzx-icon>
-				<view class="name">{{item.departName}}</view>
+				<view class="name textHidden">{{ item.siteName }}</view>
 				<zzx-icon name="ashRight" size="12"></zzx-icon>
 			</view>
 			<view class="line"></view>
@@ -15,145 +15,162 @@
 					<view class="user-header">
 						<image :src="item.avatar" mode=""></image>
 					</view>
-					<view class="user-name">{{item.username}}</view>
+					<view class="user-name textHidden">{{ item.username }}</view>
 				</view>
-				<view class="user-time">{{item.createTime}}</view>
+				<view class="user-time">{{ item.createTime }}</view>
 			</view>
 			<view class="m-star">
-				<view class="star">{{item.score.toFixed(1)}}</view>
+				<view class="star">{{ item.score.toFixed(1) }}</view>
 				<uni-rate :readonly="true" size="16" :value="item.score" />
 			</view>
 			<view class="m-comments">
-				{{item.evaluateContent}}
+				{{ item.evaluateContent }}
 			</view>
-			<view class="user-picture">
+			<view class="user-picture" v-if="item.imageList.length > 0">
 				<scroll-view class="scroll-view_H" scroll-x="true">
-					<view class="scroll-view-item_H" v-for="(iamge,index) in item.imageList" :key="index">
-						<image @click="_previewImage(item.imageList,iamge)" :src="iamge" mode=""></image>
+					<view class="scroll-view-item_H" v-for="(iamge, index) in item.imageList" :key="index">
+						<image @click="_previewImage(item.imageList, iamge)" :src="iamge" mode=""></image>
 					</view>
 				</scroll-view>
 			</view>
 			<view class="f-merchants-reply" v-if="item.replyContent">
 				<view class="merchants">商家回复</view>
 				<view class="reply">
-					<text :class="[switchOpen?'':'textHidden']">{{item.replyContent}}</text>
-					<text class="open-colse" @click="switchOpen=!switchOpen">{{switchOpen?'收起':'展开'}}</text>
+					<text :class="[switchOpen ? '' : 'textHidden']">{{ item.replyContent }}</text>
+					<text class="open-colse" @click="switchOpen = !switchOpen">{{ switchOpen ? '收起' : '展开' }}</text>
 				</view>
 			</view>
 		</view>
+		<zs-empty v-if="commentsList?.length === 0" />
 	</view>
 </template>
 
 <script lang="ts" setup>
-	import { ref, onMounted, computed } from 'vue'
-	import { RouterUtils, TipsUtils,_previewImage } from '@/utils/util';
-	import { http } from '@/utils/http'
-	import zzxNavbar from '@/components/zzx-navbar/zzx-navbar.vue';
-	const commentsList=ref()
-	const switchOpen=ref(false)
-	onMounted(()=>{
-		get_findByPage()
+import { ref, onMounted } from 'vue'
+import { _previewImage } from '@/utils/util';
+import { http } from '@/utils/http'
+import zsEmpty from '@/components/zs-empty/index.vue';
+import zzxNavbar from '@/components/zzx-navbar/zzx-navbar.vue';
+const commentsList = ref()
+const switchOpen = ref(false)
+onMounted(() => {
+	get_findByPage()
+})
+const get_findByPage = () => {
+	http.get('/my/evaluate/findByPage', { data: { pageNo: 1, pageSize: 10 }, loading: true }).then((res) => {
+		commentsList.value = res.result.records
 	})
-	const get_findByPage=()=>{
-		http.get('/my/evaluate/findByPage',{data:{pageNo:1,pageSize:10}}).then((res)=>{
-			commentsList.value=res.result.records
-		})
-	}
+}
 </script>
 
 <style lang="less" scoped>
-	.m-comments-card {
-		padding: 20rpx;
-		background: #FFFFFF;
-		border-radius: 32rpx;
-		margin-top: 20rpx;
+.m-comments-card {
+	padding: 20rpx;
+	background: #FFFFFF;
+	border-radius: 32rpx;
+	margin-top: 20rpx;
 
-		.m-comments-name {
-			display: flex;
-			align-items: center;
-			gap: 16rpx;
-			margin-bottom: 20rpx;
+	.m-comments-name {
+		display: flex;
+		align-items: center;
+		gap: 16rpx;
+		margin-bottom: 20rpx;
 
-			.name {
-				font-size: 28rpx;
-				color: #222222;
-			}
+		.name {
+			width: 600rpx;
+			font-size: 28rpx;
+			color: #222222;
 		}
-		.m-user-info{
+	}
+
+	.m-user-info {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.user-info {
 			display: flex;
 			align-items: center;
-			justify-content: space-between;
-			.user-info{
-				display: flex;
-				align-items: center;
-				gap: 16rpx;
-				.user-header{
-					&>image{
-						width: 60rpx;
-						height: 60rpx;
-						border-radius: 50%;
-					}
-				}
-				.user-name{
-					font-weight: bold;
-					font-size: 24rpx;
-					color: #222222;
+			gap: 16rpx;
+
+			.user-header {
+				&>image {
+					width: 60rpx;
+					height: 60rpx;
+					border-radius: 50%;
 				}
 			}
-			.user-time{
+
+			.user-name {
+				width: 340rpx;
+				font-weight: bold;
 				font-size: 24rpx;
-				color: #AAAAAA;
+				color: #222222;
 			}
 		}
-		.m-star{
-			display: flex;
-			align-items: center;
-			gap: 20rpx;
+
+		.user-time {
 			font-size: 24rpx;
 			color: #AAAAAA;
 		}
-		.m-comments{
-			margin-top: 20rpx;
-			font-size: 28rpx;
-			color: #222222;
-		}
-		.user-picture{
-			margin-top: 20rpx;
-			.scroll-view_H{
-				.scroll-view-item_H{
-					&>image{
-						width: 160rpx;
-						height: 160rpx;
-						border-radius: 8rpx;
-						margin-right: 20rpx;
-					}
+	}
+
+	.m-star {
+		display: flex;
+		align-items: center;
+		gap: 20rpx;
+		font-size: 24rpx;
+		color: #AAAAAA;
+	}
+
+	.m-comments {
+		margin-top: 20rpx;
+		font-size: 28rpx;
+		color: #222222;
+	}
+
+	.user-picture {
+		margin-top: 20rpx;
+
+		.scroll-view_H {
+			.scroll-view-item_H {
+				&>image {
+					width: 160rpx;
+					height: 160rpx;
+					border-radius: 8rpx;
+					margin-right: 20rpx;
 				}
 			}
 		}
-		.f-merchants-reply{
+	}
+
+	.f-merchants-reply {
+		display: flex;
+		gap: 12rpx;
+		background: #F6F6F6;
+		border-radius: 16rpx;
+		padding: 20rpx;
+		margin-top: 20rpx;
+		transition: all .3s;
+
+		.merchants {
+			width: 100rpx;
+			height: 40rpx;
+			font-size: 24rpx;
+			color: #AAAAAA;
+		}
+
+		.reply {
+			width: 520rpx;
+			font-size: 24rpx;
+			color: #222222;
 			display: flex;
-			gap: 12rpx;
-			background: #F6F6F6;
-			border-radius: 16rpx;
-			padding: 20rpx;
-			margin-top: 20rpx;
-			transition: all .3s;
-			.merchants{
-				width: 100rpx;
-				height: 40rpx;
-				font-size: 24rpx;
+
+			.open-colse {
 				color: #AAAAAA;
-			}
-			.reply{
-				width: 520rpx;
-				font-size: 24rpx;
-				color: #222222;
-				display: flex;
-				.open-colse{
-					color: #AAAAAA;
-					width:120rpx;
-				}
+				width: 120rpx;
 			}
 		}
 	}
+}
 </style>

+ 8 - 0
src/pages/mine/orderInfo/index.vue

@@ -97,12 +97,16 @@ onLoad((option) => {
 	selected.value = option.selIndex
 	if (selected.value == 0) {
 		orderFormData.value.orderStatus = null
+		orderFormData.value.orAfterSale = 0
 	} else if (selected.value == 1) {
 		orderFormData.value.orderStatus = 0
+		orderFormData.value.orAfterSale = 0
 	} else if (selected.value == 2) {
 		orderFormData.value.orderStatus = 1
+		orderFormData.value.orAfterSale = 0
 	} else if (selected.value == 3) {
 		orderFormData.value.orderStatus = 2
+		orderFormData.value.orAfterSale = 0
 	} else if (selected.value == 4) {
 		orderFormData.value.orderStatus = null
 		orderFormData.value.orAfterSale = 1
@@ -121,11 +125,15 @@ const selectedItem = (i) => {
 	selected.value = i
 	if (selected.value == 0) {
 		orderFormData.value.orderStatus = null
+		orderFormData.value.orAfterSale = 0
 	} else if (selected.value == 1) {
 		orderFormData.value.orderStatus = 0
+		orderFormData.value.orAfterSale = 0
 	} else if (selected.value == 2) {
+		orderFormData.value.orAfterSale = 0
 		orderFormData.value.orderStatus = 1
 	} else if (selected.value == 3) {
+		orderFormData.value.orAfterSale = 0
 		orderFormData.value.orderStatus = 2
 	} else if (selected.value == 4) {
 		orderFormData.value.orderStatus = null

+ 1 - 1
src/utils/common/upload.ts

@@ -4,7 +4,7 @@ import { useCacheStore } from '@/stores/cache'
 export function uploadImage(tempFilePath: string, onSuccess?: (url: string) => void, onFail?: (err: any) => void) {
     const cache = useCacheStore()
     uni.uploadFile({
-        url: 'http://192.168.0.11:8080/jeecg-boot/sys/common/upload',
+        url: 'http://192.168.1.34:8080/jeecg-boot/sys/common/upload',
         filePath: tempFilePath,
         name: 'file',
         header: {

+ 2 - 2
src/utils/http/index.ts

@@ -179,8 +179,8 @@ export class HttpClient {
 
 // 创建实例
 export const http = new HttpClient({
-  // baseURL: 'http://192.168.1.34:8080/jeecg-boot/app',
-  baseURL: 'http://192.168.1.166:8080/jeecg-boot/app',
+  baseURL: 'http://192.168.1.34:8080/jeecg-boot/app',
+  // baseURL: 'http://192.168.1.166:8080/jeecg-boot/app',
   // baseURL: 'http://192.168.0.11:8080/jeecg-boot/app',
   headers: {
     'Content-Type': 'application/json'

+ 26 - 4
src/utils/util/index.ts

@@ -88,7 +88,7 @@ export class RouterUtils {
 	static to_page(path: string) {
 		if (!uni.getStorageSync('TOKEN')) {
 			TipsUtils.tips_alert('请先登录~', true).then((res) => {
-				console.log(res,'res');
+				console.log(res, 'res');
 				if (res.confirm) {
 					uni.switchTab({
 						url: '/pages/index/index'
@@ -243,6 +243,28 @@ export const phoneHide = (phone: any) => {
  * @returns 
  */
 export const fixImgStyle = (html: string) => {
-		if (!html) return html;
-		return html.replace(/<img/gi, '<img style="max-width:100%;height:auto;display:block;"');
-	};
+	if (!html) return html;
+	return html.replace(/<img/gi, '<img style="max-width:100%;height:auto;display:block;"');
+}
+
+/**
+ * 防抖函数
+ * @param fn 需要防抖的函数
+ * @param delay 延迟时间,单位毫秒
+ * @returns 返回防抖处理后的函数
+ */
+export function debounce<T extends (...args: any[]) => any>(
+	fn: T,
+	delay: number
+): (...args: Parameters<T>) => void {
+	let timer: ReturnType<typeof setTimeout> | null = null
+
+	return function (this: any, ...args: Parameters<T>): void {
+		if (timer) clearTimeout(timer)
+
+		timer = setTimeout(() => {
+			fn.apply(this, args)
+			timer = null
+		}, delay)
+	}
+}