فهرست منبع

```
feat(attestation): 实名认证流程优化

- 移除身份证上传组件,简化实名认证界面
- 集成新的实名认证SDK,更新导入方式
- 添加用户实名状态检查逻辑,区分已实名和未实名用户
- 重构人脸识别流程,优化用户体验
- 将用户添加逻辑提取为独立函数

fix(searchPage): 搜索页面样式和数据展示修复

- 修复模板中条件判断的语法错误
- 更新评论数量显示逻辑,从固定值改为动态数据
- 优化代码格式化,统一条件判断的空格格式

chore(userList): 类型定义优化

- 为 onLoad 钩子函数参数添加类型定义

feat(orderInfo): 订单管理功能增强

- 添加取消预约功能,支持学校订单类型的取消操作
- 新增 cancelReserve 方法处理预约取消逻辑

chore(http): 环境配置调整

- 切换到生产环境API地址,注释本地开发地址
```

zouzexu 1 هفته پیش
والد
کامیت
5c84fd87c9

+ 36 - 37
src/pages/index/attestation/index.vue

@@ -5,22 +5,6 @@
 			<view class="title">实名认证</view>
 			<view class="text">用于身份实名核验,反洗钱,资料将严格保密</view>
 		</view>
-		<!-- <view class="a-idcard-box">
-			<view class="front" v-if="frontImg != ''" @click="chooseImage(1)">
-				<image :src="frontImg" mode=""></image>
-			</view>
-			<view class="front bg-image" @click="chooseImage(1)" v-else>
-				<zzx-icon name="upload" size="30"></zzx-icon>
-				<view class="">上传人像面</view>
-			</view>
-			<view class="flip-side" v-if="flipSideImg != ''" @click="chooseImage(2)">
-				<image :src="flipSideImg" mode=""></image>
-			</view>
-			<view class="flip-side bg-image" v-else @click="chooseImage(2)">
-				<zzx-icon name="upload" size="30"></zzx-icon>
-				<view class="">上传国徽面</view>
-			</view>
-		</view> -->
 		<view class="a-form">
 			<view class="form-item">
 				<view class="">真实姓名</view>
@@ -66,7 +50,7 @@ import { ref } from 'vue';
 import { onLoad } from '@dcloudio/uni-app';
 import { http } from '@/utils/http';
 import { TipsUtils, ValidateUtils, idCardHide, phoneHide } from '@/utils/util';
-import { startEid } from '@/pages/mp_ecard_sdk/main'
+import * as eidSdk from '@/pages/mp_ecard_sdk/main'
 import { uploadImage } from '@/utils/common/upload'
 import { useCacheStore } from '@/stores/cache'
 const cache = useCacheStore()
@@ -157,7 +141,7 @@ const handleChange = async (e) => {
 		});
 	} catch (error) {
 		console.error('图片处理失败:', error);
-		TipsUtils.tips_toast('图片处理失败,请重新上传:', error.errMsg);
+		// TipsUtils.tips_toast(error.errMsg);
 		formData.value.realNameImg = imageUrl;
 		console.log('上传图片返回的地址:', formData.value.realNameImg);
 	}
@@ -185,7 +169,7 @@ const checkImageSizeBeforeSubmit = async () => {
 			return;
 		}
 		// 如果图片大小符合要求,则继续进行人脸识别流程
-		getFaceRecognition();
+		queryUserIsRealName();
 	} catch (error) {
 		console.error('图片大小检查失败:', error);
 		TipsUtils.tips_toast('图片检查失败,请重新上传');
@@ -209,21 +193,32 @@ const editSubmit = () => {
 
 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('请输入姓名');
 	if (!ValidateUtils.validateIdCard(formData.value.identityCard)) return TipsUtils.tips_toast('身份证号码格式不正确');
 	if (!ValidateUtils.validatePhone(formData.value.phone)) return TipsUtils.tips_toast('手机号格式不正确');
 	if (!formData.value.realNameImg) return TipsUtils.tips_toast('请上传本人近期高清、无遮挡照片');
 	checkImageSizeBeforeSubmit()
 }
-
 // 开始身份验证
 const verifyToken = ref('')
+const queryUserIsRealName = () => {
+	http.post('/my/familyMembers/realNameAuthentication', {
+		name: formData.value.fullName,
+		idCard: formData.value.identityCard
+	}).then((res) => {
+		if (res.result === false) {
+			getFaceRecognition()  //false代表未实名,继续人脸识别流程
+		} else if (res.result === true) {
+			formData.value.realNameStatus = 1;
+			addUser()  //true代表已实名,添加用户
+		}
+	})
+}
+
 const getFaceRecognition = () => {
 	http.get('/user/faceRecognition', { data: { idCard: formData.value.identityCard, name: formData.value.fullName } }).then(res => {
 		verifyToken.value = JSON.parse(res.result).EidToken
-		startEid({
+		eidSdk.startEid({
 			data: {
 				token: verifyToken.value,
 				needJumpPage: true
@@ -237,20 +232,7 @@ const getFaceRecognition = () => {
 					if (res.result.ErrCode == '0') {
 						formData.value.realNameStatus = 1;
 						verifyToken.value = token;
-						http.post('/my/familyMembers/addFamilyMembers', { ...formData.value }, { loading: true }).then((res) => {
-							TipsUtils.tips_toast(res.message)
-							formData.value.fullName = ''
-							formData.value.identityCard = ''
-							formData.value.phone = ''
-							formData.value.idCardFrontImg = ''
-							formData.value.idCardBackImg = ''
-							formData.value.realNameImg = ''
-							frontImg.value = ''
-							flipSideImg.value = ''
-							setTimeout(() => {
-								uni.navigateBack()
-							}, 500)
-						})
+						addUser()
 					} else {
 						TipsUtils.tips_toast(res.result.LiveMsg || '核身失败,请重新核身')
 					}
@@ -259,6 +241,23 @@ const getFaceRecognition = () => {
 		});
 	})
 }
+
+const addUser = () => {
+	http.post('/my/familyMembers/addFamilyMembers', { ...formData.value }, { loading: true }).then((res) => {
+		TipsUtils.tips_toast(res.message)
+		formData.value.fullName = ''
+		formData.value.identityCard = ''
+		formData.value.phone = ''
+		formData.value.idCardFrontImg = ''
+		formData.value.idCardBackImg = ''
+		formData.value.realNameImg = ''
+		frontImg.value = ''
+		flipSideImg.value = ''
+		setTimeout(() => {
+			uni.navigateBack()
+		}, 500)
+	})
+}
 </script>
 
 <style lang="less" scoped>

+ 368 - 362
src/pages/index/searchPage/index.vue

@@ -8,39 +8,42 @@
 			</view>
 		</view>
 		<view class="venue-navbar">
-			<view class="navbar-list" v-for="(item,index) in navbarList" :key="index" @click="select_nav(item)">
-				<view class="list-text">{{item.title}}</view>
-				<image :src="sel_index==index?'/static/notsel-icon.png':'/static/select-icon.png'" mode=""></image>
+			<view class="navbar-list" v-for="(item, index) in navbarList" :key="index" @click="select_nav(item)">
+				<view class="list-text">{{ item.title }}</view>
+				<image :src="sel_index == index ? '/static/notsel-icon.png' : '/static/select-icon.png'" mode="">
+				</image>
 			</view>
 		</view>
 	</view>
 	<view class="content">
 		<view class="select-btn">
-			<view :class="sel_btn===index?'distance':'score'" v-for="(item,index) in selectList" :key="index"
-				@click="select_btn(item,index)">{{item.text}}</view>
+			<view :class="sel_btn === index ? 'distance' : 'score'" v-for="(item, index) in selectList" :key="index"
+				@click="select_btn(item, index)">{{ item.text }}</view>
 		</view>
-		<view class="s-search-list"  v-if="!searchLoading">
+		<view class="s-search-list" v-if="!searchLoading">
 			<!-- 场地 -->
-			<view v-if="sel_index==0">
-				<!-- pages/index/gymDetail/index -->
-				<view class="s-venue-card" v-for="(venue,index) in searchList" :key="venue.id" @click="venue.type==0?RouterUtils.to_page(`/pages/index/detail/index?id=${venue.id}`):RouterUtils.to_page(`/pages/index/gymDetail/index?id=${venue.id}`)">
+			<view v-if="sel_index == 0">
+				<view class="s-venue-card" v-for="(venue, index) in searchList" :key="venue.id"
+					@click="venue.type == 0 ? RouterUtils.to_page(`/pages/index/detail/index?id=${venue.id}`) : RouterUtils.to_page(`/pages/index/gymDetail/index?id=${venue.id}`)">
 					<view class="s-venue-info">
 						<view class="venue-img">
 							<image :src="venue.cover" mode=""></image>
 						</view>
 						<view class="venue-info">
-							<view class="name">{{venue.name}}</view>
+							<view class="name">{{ venue.name }}</view>
 							<view class="appraise">
 								<zzx-icon name="star" size="12"></zzx-icon>
-								<view class="app-text"><text style="color: #FDD143	;">{{venue.goodRate||0}}</text> | 37条评论</view>
+								<view class="app-text"><text style="color: #FDD143	;">{{ venue.goodRate || 0 }}</text> |
+									{{ venue.comments || 0 }}条评论</view>
 							</view>
-							<view class="address">{{venue.address}} | {{venue.km}}km</view>
+							<view class="address">{{ venue.address }} | {{ venue.km }}km</view>
 							<view class="tags-box">
-								<view class="tags" v-for="(tags,index) in venue.category" :key="index">{{tags}}</view>
+								<view class="tags" v-for="(tags, index) in venue.category" :key="index">{{ tags }}
+								</view>
 							</view>
 						</view>
 					</view>
-<!-- 					<view class="s-course-list" v-for="item in 2">
+					<!-- 					<view class="s-course-list" v-for="item in 2">
 						<view class="course-name">
 							<view class="price">¥25.6</view>
 							<view class="name">室内小班篮球培训课时</view>
@@ -50,8 +53,9 @@
 				</view>
 			</view>
 			<!-- 培训 -->
-			<view v-if="sel_index==1">
-				<view class="s-training-card" v-for="(venue,index) in searchList" :key="venue.id" @click="RouterUtils.to_page(`/pages/index/courseDetail/index?id=${venue.id}`)">
+			<view v-if="sel_index == 1">
+				<view class="s-training-card" v-for="(venue, index) in searchList" :key="venue.id"
+					@click="RouterUtils.to_page(`/pages/index/courseDetail/index?id=${venue.id}`)">
 					<view class="training-box">
 						<view class="training-img">
 							<image class="t-img" :src="venue.cover" mode="">
@@ -60,15 +64,15 @@
 						<view class="training-info">
 							<view class="training-name">
 								<!-- <view class="t-tags">公益课</view> -->
-								<view class="t-name textHidden">{{venue.name}}</view>
+								<view class="t-name textHidden">{{ venue.name }}</view>
 							</view>
 							<!-- <view class="tips">促进青少年长高</view> -->
 							<view class="t-price">
-								<view class="price"><text class="mini-text">¥</text>{{venue.originalPrice}}</view>
+								<view class="price"><text class="mini-text">¥</text>{{ venue.originalPrice }}</view>
 								<!-- <view class="price-tips">不支持退款</view> -->
 							</view>
-							<view class="sales">已售{{venue.sales}} {{venue.goodRate||'0'}}%好评</view>
-							<view class="address">{{venue.address}} | {{venue.km}}km</view>
+							<view class="sales">已售{{ venue.sales }} {{ venue.goodRate || '0' }}%好评</view>
+							<view class="address">{{ venue.address }} | {{ venue.km }}km</view>
 						</view>
 					</view>
 					<view class="tags-img">
@@ -77,431 +81,433 @@
 				</view>
 			</view>
 			<!-- 赛事 -->
-			<view v-if="sel_index==2">
+			<view v-if="sel_index == 2">
 				<events :listData="searchList" />
 			</view>
 			<!-- 教练 -->
-			<view v-if="sel_index==3">
+			<view v-if="sel_index == 3">
 				<instructor :listData="searchList" />
 			</view>
 		</view>
 		<zs-loading v-else></zs-loading>
-		<zs-empty v-if="searchList.length<1&&!searchLoading"></zs-empty>
+		<zs-empty v-if="searchList.length < 1 && !searchLoading"></zs-empty>
 	</view>
 </template>
 
 <script lang="ts" setup>
-	import { ref, onMounted } from 'vue';
-	import { onLoad,onReachBottom } from '@dcloudio/uni-app';
-	import { http } from '@/utils/http'
-	import {RouterUtils,TipsUtils} from '@/utils/util'
-	import { useCacheStore } from '@/stores/cache'
-	import events from './components/events.vue'
-	import instructor from './components/instructor.vue'
-	import zsEmpty from '@/components/zs-empty/index.vue'
-	import zsLoading from '@/components/zzx-loading/zzx-loading.vue'
-	const cache = useCacheStore()
-	const selectList = ref()
-	const sel_index = ref(0);
-	const sel_btn = ref(0);
-	const keyword = ref();
-	const venueType=ref()
-	const searchList=ref();
-	const navbarList = ref([{title: '场地',value: 0,tagsVal:'0-1'},{title: '培训',value: 1,tagsVal:'1-1'},{title: '赛事',value: 2,tagsVal:'2-1'},{title: '教练',value: 3,tagsVal:'3-1'}]);
-	onLoad((options) => {
-		keyword.value = options.keyword
-		venueType.value=options.venueType
-		console.log(options);
-	})
-	onReachBottom(()=>{
-		current.value++
-		get_searchInfo(tagsVal.value||'0-1')
-	})
-	onMounted(() => {
-		if(venueType.value){
-			get_searchInfo(venueType.value)
-		}else{
-			get_searchInfo('0-1')
-		}
-		// get_dictItems()
-		get_dictType(0)
-	})
-	const select_btn = (e,i) => {
-		searchLoading.value=true
-		sel_btn.value = i
-		get_searchInfo(e.value)
-	}
-	const select_nav = (e) => {
-		searchLoading.value=true
-		sel_index.value = e.value
-		tagsVal.value=e.tagsVal
-		sel_btn.value=0
-		searchList.value=[]
-		get_dictType(e.value || 0)
-		get_searchInfo(e.tagsVal)
-	}
-
-	// 查询分类
-	const get_dictType = (type : number) => {
-		http.get('/common/getDictItems', { data: { dictCode: 'search_type' } }).then(res => {
-			let arr = []
-			res.result.forEach((item) => {
-				let value = parseInt(item.value.split('-')[0])
-				if (type == value){
-					return arr.push(item)
-				}
-			})
-			selectList.value=arr
-		})
-	}
-	
-	const tagsVal=ref()
-	const to_search=()=>{
-		if(keyword.value=='') return TipsUtils.tips_toast('请输入搜索内容')
-		searchLoading.value=true
-		get_searchInfo(tagsVal.value||'0-1')
+import { ref, onMounted } from 'vue';
+import { onLoad, onReachBottom } from '@dcloudio/uni-app';
+import { http } from '@/utils/http'
+import { RouterUtils, TipsUtils } from '@/utils/util'
+import { useCacheStore } from '@/stores/cache'
+import events from './components/events.vue'
+import instructor from './components/instructor.vue'
+import zsEmpty from '@/components/zs-empty/index.vue'
+import zsLoading from '@/components/zzx-loading/zzx-loading.vue'
+const cache = useCacheStore()
+const selectList = ref()
+const sel_index = ref(0);
+const sel_btn = ref(0);
+const keyword = ref();
+const venueType = ref()
+const searchList = ref();
+const navbarList = ref([{ title: '场地', value: 0, tagsVal: '0-1' }, { title: '培训', value: 1, tagsVal: '1-1' }, { title: '赛事', value: 2, tagsVal: '2-1' }, { title: '教练', value: 3, tagsVal: '3-1' }]);
+onLoad((options) => {
+	keyword.value = options.keyword
+	venueType.value = options.venueType
+	console.log(options);
+})
+onReachBottom(() => {
+	current.value++
+	get_searchInfo(tagsVal.value || '0-1')
+})
+onMounted(() => {
+	if (venueType.value) {
+		get_searchInfo(venueType.value)
+	} else {
+		get_searchInfo('0-1')
 	}
-	
-	const searchLoading=ref(true)
-	const current=ref(1)
-	const get_searchInfo = (tagsVal) => {
-		http.post('/home/search', { keyword: keyword.value, size: 10, current:current.value, venueType:String(tagsVal), longitude: cache.get('LON')||0, latitude: cache.get('LAT')||0 }).then((res) => {
-			searchLoading.value=false
-			if(current.value==1){
-				searchList.value=res.result.records
-			}else{
-				searchList.value=[...searchList.value,...res.result.records]
+	// get_dictItems()
+	get_dictType(0)
+})
+const select_btn = (e, i) => {
+	searchLoading.value = true
+	sel_btn.value = i
+	get_searchInfo(e.value)
+}
+const select_nav = (e) => {
+	searchLoading.value = true
+	sel_index.value = e.value
+	tagsVal.value = e.tagsVal
+	sel_btn.value = 0
+	searchList.value = []
+	get_dictType(e.value || 0)
+	get_searchInfo(e.tagsVal)
+}
+
+// 查询分类
+const get_dictType = (type: number) => {
+	http.get('/common/getDictItems', { data: { dictCode: 'search_type' } }).then(res => {
+		let arr = []
+		res.result.forEach((item) => {
+			let value = parseInt(item.value.split('-')[0])
+			if (type == value) {
+				return arr.push(item)
 			}
 		})
-	}
+		selectList.value = arr
+	})
+}
+
+const tagsVal = ref()
+const to_search = () => {
+	if (keyword.value == '') return TipsUtils.tips_toast('请输入搜索内容')
+	searchLoading.value = true
+	get_searchInfo(tagsVal.value || '0-1')
+}
+
+const searchLoading = ref(true)
+const current = ref(1)
+const get_searchInfo = (tagsVal) => {
+	http.post('/home/search', { keyword: keyword.value, size: 10, current: current.value, venueType: String(tagsVal), longitude: cache.get('LON') || 0, latitude: cache.get('LAT') || 0 }).then((res) => {
+		searchLoading.value = false
+		if (current.value == 1) {
+			searchList.value = res.result.records
+		} else {
+			searchList.value = [...searchList.value, ...res.result.records]
+		}
+	})
+}
 </script>
 
 <style lang="less" scoped>
-	.s-header {
-		background: #fff;
-		padding: 20rpx;
+.s-header {
+	background: #fff;
+	padding: 20rpx;
+
+	.header-search {
+		display: flex;
+		align-items: center;
+		gap: 10rpx;
+		background: #F6F6F6;
+		width: 680rpx;
+		height: 60rpx;
+		border-radius: 40rpx;
+		padding-left: 20rpx;
+
+		&>input {
+			width: 670rpx;
+			font-weight: bold;
+			font-size: 24rpx;
+		}
+
+		.search-btn {
+			width: 144rpx;
+			height: 52rpx;
+			background: #222222;
+			border-radius: 28rpx;
+			font-weight: bold;
+			font-size: 28rpx;
+			color: #C8FF0C;
+			line-height: 52rpx;
+			text-align: center;
+		}
+	}
+
+	.venue-navbar {
+		margin-top: 32rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
 
-		.header-search {
+		.navbar-list {
 			display: flex;
 			align-items: center;
 			gap: 10rpx;
-			background: #F6F6F6;
-			width: 680rpx;
-			height: 60rpx;
-			border-radius: 40rpx;
-			padding-left: 20rpx;
-			&>input {
-				width: 670rpx;
-				font-weight: bold;
-				font-size: 24rpx;
-			}
 
-			.search-btn {
-				width: 144rpx;
-				height: 52rpx;
-				background: #222222;
-				border-radius: 28rpx;
+			.list-text {
 				font-weight: bold;
 				font-size: 28rpx;
-				color: #C8FF0C;
-				line-height: 52rpx;
-				text-align: center;
+				color: #222222;
 			}
-		}
-
-		.venue-navbar {
-			margin-top: 32rpx;
-			display: flex;
-			align-items: center;
-			justify-content: space-around;
-
-			.navbar-list {
-				display: flex;
-				align-items: center;
-				gap: 10rpx;
 
-				.list-text {
-					font-weight: bold;
-					font-size: 28rpx;
-					color: #222222;
-				}
-
-				&>image {
-					width: 30rpx;
-					height: 30rpx;
-				}
+			&>image {
+				width: 30rpx;
+				height: 30rpx;
 			}
 		}
 	}
+}
+
+.content {
+	.select-btn {
+		display: flex;
+		align-items: center;
+		gap: 20rpx;
+		margin-top: 20rpx;
+
+		.distance {
+			width: 92rpx;
+			height: 48rpx;
+			background: #222222;
+			border-radius: 8rpx;
+			font-size: 28rpx;
+			color: #C8FF0C;
+			line-height: 48rpx;
+			text-align: center;
+		}
 
-	.content {
-		.select-btn {
-			display: flex;
-			align-items: center;
-			gap: 20rpx;
-			margin-top: 20rpx;
-
-			.distance {
-				width: 92rpx;
-				height: 48rpx;
-				background: #222222;
-				border-radius: 8rpx;
-				font-size: 28rpx;
-				color: #C8FF0C;
-				line-height: 48rpx;
-				text-align: center;
-			}
-
-			.score {
-				width: 92rpx;
-				height: 48rpx;
-				background: #FFFFFF;
-				border-radius: 8rpx;
-				font-size: 28rpx;
-				color: #AAAAAA;
-				height: 48rpx;
-				line-height: 48rpx;
-				text-align: center;
-			}
+		.score {
+			width: 92rpx;
+			height: 48rpx;
+			background: #FFFFFF;
+			border-radius: 8rpx;
+			font-size: 28rpx;
+			color: #AAAAAA;
+			height: 48rpx;
+			line-height: 48rpx;
+			text-align: center;
 		}
+	}
 
-		.s-search-list {
-			.s-venue-card {
-				margin-top: 20rpx;
-				background: #FFFFFF;
-				border-radius: 32rpx;
-				padding: 20rpx;
+	.s-search-list {
+		.s-venue-card {
+			margin-top: 20rpx;
+			background: #FFFFFF;
+			border-radius: 32rpx;
+			padding: 20rpx;
 
-				.s-venue-info {
-					display: flex;
-					align-items: center;
-					gap: 20rpx;
+			.s-venue-info {
+				display: flex;
+				align-items: center;
+				gap: 20rpx;
 
-					.venue-img {
-						&>image {
-							width: 200rpx;
-							height: 200rpx;
-							border-radius: 32rpx;
-						}
+				.venue-img {
+					&>image {
+						width: 200rpx;
+						height: 200rpx;
+						border-radius: 32rpx;
 					}
+				}
 
-					.venue-info {
-						.name {
-							font-weight: 800;
-							font-size: 32rpx;
-							color: #222222;
-						}
-
-						.appraise {
-							display: flex;
-							align-items: center;
-							margin-top: 16rpx;
+				.venue-info {
+					.name {
+						font-weight: 800;
+						font-size: 32rpx;
+						color: #222222;
+					}
 
-							.app-text {
-								font-size: 24rpx;
-								color: #AAAAAA;
-							}
-						}
+					.appraise {
+						display: flex;
+						align-items: center;
+						margin-top: 16rpx;
 
-						.address {
-							margin-top: 12rpx;
+						.app-text {
 							font-size: 24rpx;
-							color: #222222;
-						}
-
-						.tags-box {
-							margin-top: 16rpx;
-							display: flex;
-							align-items: center;
-							gap: 12rpx;
-							flex-wrap: wrap;
-							.tags {
-								width: 92rpx;
-								height: 36rpx;
-								background: #F5F5F5;
-								border-radius: 8rpx;
-								font-size: 22rpx;
-								color: #AAAAAA;
-								line-height: 36rpx;
-								text-align: center;
-							}
+							color: #AAAAAA;
 						}
 					}
-				}
 
-				.s-course-list {
-					display: flex;
-					align-items: center;
-					justify-content: space-between;
-					margin-top: 20rpx;
+					.address {
+						margin-top: 12rpx;
+						font-size: 24rpx;
+						color: #222222;
+					}
 
-					.course-name {
+					.tags-box {
+						margin-top: 16rpx;
 						display: flex;
 						align-items: center;
-						gap: 20rpx;
-						font-weight: bold;
-						font-size: 28rpx;
-
-						.price {
-							color: #FB5B5B;
-						}
-
-						.name {
-							color: #222222;
+						gap: 12rpx;
+						flex-wrap: wrap;
+
+						.tags {
+							width: 92rpx;
+							height: 36rpx;
+							background: #F5F5F5;
+							border-radius: 8rpx;
+							font-size: 22rpx;
+							color: #AAAAAA;
+							line-height: 36rpx;
+							text-align: center;
 						}
 					}
-
-					.sales {
-						font-size: 24rpx;
-						color: #AAAAAA;
-					}
 				}
 			}
 
-			.s-training-card {
+			.s-course-list {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
 				margin-top: 20rpx;
-				background: #FFFFFF;
-				border-radius: 32rpx;
-				padding: 20rpx;
-				position: relative;
 
-				.training-box {
+				.course-name {
 					display: flex;
 					align-items: center;
 					gap: 20rpx;
+					font-weight: bold;
+					font-size: 28rpx;
 
-					.training-img {
-						position: relative;
+					.price {
+						color: #FB5B5B;
+					}
 
-						.t-img {
-							width: 200rpx;
-							height: 200rpx;
-							border-radius: 32rpx;
-						}
+					.name {
+						color: #222222;
+					}
+				}
 
-						.img-tags {
-							position: absolute;
-							left: -20rpx;
-							top: 0;
-							width: 113rpx;
-						}
+				.sales {
+					font-size: 24rpx;
+					color: #AAAAAA;
+				}
+			}
+		}
 
-						.tags-text {
-							position: absolute;
-							font-size: 18rpx;
-							color: #FFFFFF;
-							top: 14rpx;
-							left: 0;
-						}
+		.s-training-card {
+			margin-top: 20rpx;
+			background: #FFFFFF;
+			border-radius: 32rpx;
+			padding: 20rpx;
+			position: relative;
 
-						.s-downtime {
-							position: absolute;
-							display: flex;
-							bottom: 20rpx;
-							left: 18rpx;
-
-							.hours {
-								width: 40rpx;
-								height: 40rpx;
-								background: rgba(200, 255, 12, 0.5);
-								border-radius: 8rpx;
-								font-weight: 800;
-								font-size: 22rpx;
-								color: #222222;
-								line-height: 40rpx;
-								text-align: center;
-							}
-
-							.unit {
-								width: 20rpx;
-								font-weight: 800;
-								font-size: 22rpx;
-								color: #222222;
-								line-height: 40rpx;
-								text-align: center;
-							}
-						}
+			.training-box {
+				display: flex;
+				align-items: center;
+				gap: 20rpx;
+
+				.training-img {
+					position: relative;
+
+					.t-img {
+						width: 200rpx;
+						height: 200rpx;
+						border-radius: 32rpx;
 					}
 
-					.training-info {
-						.training-name {
-							display: flex;
-							align-items: center;
-							gap: 8rpx;
-
-							.t-tags {
-								width: 92rpx;
-								height: 36rpx;
-								background: #4DD951;
-								border-radius: 8rpx;
-								font-size: 22rpx;
-								color: #FFFFFF;
-								text-align: center;
-								line-height: 36rpx;
-							}
-
-							.t-name {
-								width: 360rpx;
-								font-weight: 800;
-								font-size: 32rpx;
-								color: #222222;
-							}
-						}
+					.img-tags {
+						position: absolute;
+						left: -20rpx;
+						top: 0;
+						width: 113rpx;
+					}
 
-						.tips {
+					.tags-text {
+						position: absolute;
+						font-size: 18rpx;
+						color: #FFFFFF;
+						top: 14rpx;
+						left: 0;
+					}
+
+					.s-downtime {
+						position: absolute;
+						display: flex;
+						bottom: 20rpx;
+						left: 18rpx;
+
+						.hours {
+							width: 40rpx;
+							height: 40rpx;
+							background: rgba(200, 255, 12, 0.5);
+							border-radius: 8rpx;
+							font-weight: 800;
 							font-size: 22rpx;
-							color: #AAAAAA;
+							color: #222222;
+							line-height: 40rpx;
+							text-align: center;
 						}
 
-						.t-price {
-							display: flex;
-							align-items: center;
-							gap: 12rpx;
-
-							.price {
-								font-weight: 800;
-								font-size: 32rpx;
-								color: #FB5B5B;
-							}
-
-							.price-tips {
-								margin-top: 8rpx;
-								width: 176rpx;
-								height: 42rpx;
-								background: linear-gradient(90deg, #C8FF0C 0%, #F2FFC7 79%, rgba(255, 255, 255, 0) 100%);
-								border-radius: 28rpx;
-								font-size: 22rpx;
-								color: #222222;
-								line-height: 42rpx;
-								text-align: center;
-							}
+						.unit {
+							width: 20rpx;
+							font-weight: 800;
+							font-size: 22rpx;
+							color: #222222;
+							line-height: 40rpx;
+							text-align: center;
 						}
+					}
+				}
 
-						.sales {
-							margin-top: 8rpx;
+				.training-info {
+					.training-name {
+						display: flex;
+						align-items: center;
+						gap: 8rpx;
+
+						.t-tags {
+							width: 92rpx;
+							height: 36rpx;
+							background: #4DD951;
+							border-radius: 8rpx;
 							font-size: 22rpx;
+							color: #FFFFFF;
+							text-align: center;
+							line-height: 36rpx;
+						}
+
+						.t-name {
+							width: 360rpx;
+							font-weight: 800;
+							font-size: 32rpx;
 							color: #222222;
 						}
+					}
+
+					.tips {
+						font-size: 22rpx;
+						color: #AAAAAA;
+					}
+
+					.t-price {
+						display: flex;
+						align-items: center;
+						gap: 12rpx;
+
+						.price {
+							font-weight: 800;
+							font-size: 32rpx;
+							color: #FB5B5B;
+						}
 
-						.address {
+						.price-tips {
 							margin-top: 8rpx;
+							width: 176rpx;
+							height: 42rpx;
+							background: linear-gradient(90deg, #C8FF0C 0%, #F2FFC7 79%, rgba(255, 255, 255, 0) 100%);
+							border-radius: 28rpx;
 							font-size: 22rpx;
 							color: #222222;
+							line-height: 42rpx;
+							text-align: center;
 						}
 					}
-				}
 
-				.tags-img {
-					position: absolute;
-					right: 0;
-					bottom: 0;
+					.sales {
+						margin-top: 8rpx;
+						font-size: 22rpx;
+						color: #222222;
+					}
 
-					.enroll-tags {
-						width: 161rpx;
+					.address {
+						margin-top: 8rpx;
+						font-size: 22rpx;
+						color: #222222;
 					}
 				}
+			}
+
+			.tags-img {
+				position: absolute;
+				right: 0;
+				bottom: 0;
 
+				.enroll-tags {
+					width: 161rpx;
+				}
 			}
+
 		}
 	}
+}
 </style>

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

@@ -55,7 +55,7 @@ const userinfo = computed(() => {
 })
 const selectType = ref()
 const nameText = ref()
-onLoad((options) => {
+onLoad((options: any) => {
 	console.log('邀请好友页面load信息:', options);
 	selectType.value = options.type
 	nameText.value = options.name

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

@@ -74,6 +74,8 @@
 			<!-- 待付款 -->
 			<view class="o-order-btn">
 				<view class="cancel-btn" v-if="item?.orderStatus == 0" @click.stop="cancelOrder(item)">取消订单</view>
+				<view class="cancel-btn" v-if="item?.orderType == 0 && item.orderStatus == 1"
+					@click.stop="cancelReserve(item)">取消预约</view>
 				<view class="pay-btn" v-if="item?.orderStatus == 0" @click.stop="submitPay(item)">付款</view>
 				<!-- 售后/退款 -->
 				<view class="pay-btn"
@@ -346,6 +348,16 @@ const cancelOrder = async (e: any) => {
 	}
 }
 
+const cancelReserve = async (e: any) => {
+	let res: any = await TipsUtils.tips_alert('确定取消预约吗?', true)
+	if (res.confirm) {
+		http.put(`/order/cancelSchoolOrder?orderId=${e.orderId}`, {}, { loading: true }).then((res: any) => {
+			TipsUtils.tips_toast('预约已取消')
+			getOrderList()
+		})
+	}
+}
+
 onUnmounted(() => {
 	orderList.value.forEach(item => {
 		if (item.timer) {

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

@@ -179,10 +179,10 @@ export class HttpClient {
 
 // 创建实例
 export const http = new HttpClient({
-  baseURL: 'http://192.168.0.217:8080/jeecg-boot/app',
+  // baseURL: 'http://192.168.0.217:8080/jeecg-boot/app',
   // baseURL: 'http://192.168.1.166:8080/jeecg-boot/app',
   // baseURL: 'http://192.168.0.11:8080/jeecg-boot/app',
-  // baseURL: 'https://api.qlapp.cn/jeecgboot/app', //生产
+  baseURL: 'https://api.qlapp.cn/jeecgboot/app', //生产
   headers: {
     'Content-Type': 'application/json'
   }