瀏覽代碼

用户端列表下拉刷新/订单地址回显选择

贾宇博 3 周之前
父節點
當前提交
5821a800a4

+ 2 - 1
api/volunteerDetailsApi/details.js

@@ -43,10 +43,11 @@ export function getDetailsvolunteerId(data) {
 
 
 // 获取志愿者列表信息
-export function volunteerinfolist() {
+export function volunteerinfolist(params) {
   return request({
     url: '/core/volunteer/info/list',
     method: 'get',
+	params:params
   })
 }
 

+ 2 - 1
components/Services/services.vue

@@ -55,13 +55,14 @@
 			default: () => []
 		}
 	});
-	
+
 	const goToDetail = async (item) => {
 		const params = {
 			volunteerId: item.volunteerId, // 获取 volunteerId
 			serviceCategory: item.serviceCategory, // 获取 serviceCategory
 			businessManagementId: item.businessManagementId, //获取 businessManagementId
 		};
+		
 		uni.navigateTo({
 			url: `/pages_home/pages/Volunteerside/goodsDetails?params=${JSON.stringify(params)}`
 		});

+ 1 - 0
pages.json

@@ -67,6 +67,7 @@
 					"path": "pages/details/index",
 					"style": {
 						"navigationBarTitleText": "注册详情"
+						
 					}
 				},
 				{

+ 66 - 55
pages/index.vue

@@ -35,15 +35,10 @@
 			<ServIces :leftList="leftList" :rightList="rightList" v-if="userType == 1"></ServIces>
 			<RankingList v-if="userType === 2" />
 		</view>
-		
-		<up-loadmore
-			style="margin-top: 40rpx;"
-			:status="loadmoreInfo.status" 
-			:loadmoreText="loadmoreInfo.loadingText" 
-			:loadingText="loadmoreInfo.loadmoreText" 
-			:nomoreText="loadmoreInfo.nomoreText"
-			@loadmore="handleLoadmore"
-		/>
+
+		<up-loadmore style="margin-top: 40rpx;margin-bottom: 40rpx;" :status="loadmoreInfo.status"
+			:loadmoreText="loadmoreInfo.loadmoreTex" :loadingText="loadmoreInfo.loadingText"
+			:nomoreText="loadmoreInfo.nomoreText" @loadmore="handleLoadmore" />
 
 
 	</view>
@@ -57,7 +52,8 @@
 	} from 'vue';
 	import {
 		onLoad,
-		onShow
+		onShow,
+		onReachBottom
 	} from "@dcloudio/uni-app";
 	import RankingList from '@/pages/common/rankingList/index.vue';
 	import ServIces from "@/components/Services/services.vue"
@@ -67,7 +63,9 @@
 	import {
 		volunteerinfolist,
 	} from "@/api/volunteerDetailsApi/details.js"
-	import { slideshow } from '@/api/home.js'
+	import {
+		slideshow
+	} from '@/api/home.js'
 
 	const listData = ref([])
 	const leftList = ref([])
@@ -80,54 +78,52 @@
 	})
 	const list3 = ref([]);
 
-	const hotList = [
-		{
+	const hotList = [{
 			key: 1,
 			icon: '/static/img/构建.png',
 			name: '专业辅导',
-			text:'与家长协同制定成长计划',
+			text: '与家长协同制定成长计划',
 		},
 		{
 			key: 2,
 			icon: '/static/img/构建.png',
 			name: '暖心陪护',
-			text:'倾听烦恼、缓解孤独感',
+			text: '倾听烦恼、缓解孤独感',
 		},
 	]
-	const hotList2 = [
-		{
+	const hotList2 = [{
 			key: 1,
 			icon: '/static/img/构建.png',
 			name: '专业辅导',
-			text:'与家长协同制定成长计划',
+			text: '与家长协同制定成长计划',
 		},
 		{
 			key: 2,
 			icon: '/static/img/构建.png',
 			name: '暖心陪护',
-			text:'倾听烦恼、缓解孤独感',
+			text: '倾听烦恼、缓解孤独感',
 		},
 		{
 			key: 3,
 			icon: '/static/img/构建.png',
 			name: '专业辅导',
-			text:'与家长协同制定成长计划',
+			text: '与家长协同制定成长计划',
 		},
 		{
 			key: 4,
 			icon: '/static/img/构建.png',
 			name: '暖心陪护',
-			text:'倾听烦恼、缓解孤独感',
+			text: '倾听烦恼、缓解孤独感',
 		},
 	]
-	
+
 	// 分页
 	const pages = ref({
 		current: 1,
 		pageSize: 10,
 		total: 0
 	})
-	
+
 	const loadmoreInfo = ref({
 		status: 'loadmore',
 		loadingText: '努力加载中...',
@@ -135,59 +131,75 @@
 		nomoreText: '已经到底啦~'
 	})
 
+	// 加载更多
+	async function handleLoadmore(e) {
+		if (pages.value.current < Math.ceil(pages.value.total / pages.value.pageSize)) {
+			pages.value.current += 1;
+			loadmoreInfo.value.status = 'loading';
+			await getList();
+		} else {
+			loadmoreInfo.value.status = 'nomore';
+		}
+	}
+
 	const getList = async () => {
 		try {
-			loadmoreInfo.value.status = 'loading'
-			
-			const res = await volunteerinfolist();
-			
-			
+			loadmoreInfo.value.status = 'loading';
+
+			// 请求时传递分页参数
+			const res = await volunteerinfolist({
+				pageNumber: pages.value.current, // 当前页码
+				pageSize: pages.value.pageSize // 每页大小
+			});
+
+			console.log(res, '>>>>>>>res');
+
 			if (!res || !res.rows) {
 				return;
 			}
-			
+
 			// 判断是否已经到了最后一页
-			if (pages.value.current >= Math.ceil(res.total/pages.value.pageSize)) {
-				loadmoreInfo.value.status = 'nomore'
+			if (pages.value.current >= Math.ceil(res.total / pages.value.pageSize)) {
+				loadmoreInfo.value.status = 'nomore';
 			} else {
-				loadmoreInfo.value.status = 'loadmore'
+				loadmoreInfo.value.status = 'loadmore';
 			}
-			
-			
-			listData.value.push(...res.rows)
-			
 
-			let leftArr = [];
-			let rightArr = [];
-
-			listData.value.forEach((item, index) => {
-				index % 2 !== 0 ? leftArr.push(item) : rightArr.push(item);
+			// 将数据分成左右两列
+			res.rows.forEach((item, index) => {
+				index % 2 !== 0 ? leftList.value.push(item) : rightList.value.push(item);
 			});
 
-			leftList.value = leftArr;
-			rightList.value = rightArr;
 			pages.value.total = res.total;
 		} catch (error) {
-			listData.value = []
-			pages.value.total = 0
+			leftList.value = [];
+			rightList.value = [];
+			loadmoreInfo.value.status = 'loadmore';
+			pages.value.total = 0;
 			console.error('Error fetching data:', error);
-		} finally {
-			loadmoreInfo.value.status = 'loadmore'
 		}
 	};
 
-	const getBanners = async() => {
+	const getBanners = async () => {
 		try {
-			const res =await slideshow(7);
-			if(res.code === 200 && res.data.picture){
+			const res = await slideshow(7);
+			if (res.code === 200 && res.data.picture) {
 				list3.value = res.data.picture.split(',');
 			}
 		} catch (error) {
-			console.log('error',error);
-			
+			console.log('error', error);
+
 		}
 	}
 
+	onReachBottom(() => {
+		if (pages.value.current < Math.ceil(pages.value.total / pages.value.pageSize)) {
+			pages.value.current = pages.value.current + 1
+			loadmoreInfo.value.status = 'nomore'
+			getList()
+		}
+	})
+
 	onShow(() => {
 		getList()
 		getBanners();
@@ -231,14 +243,13 @@
 		padding: 12px 16px;
 		display: grid;
 		grid-template-columns: repeat(2, 1fr);
-				/* 3 列,每列等宽 */
+		/* 3 列,每列等宽 */
 		gap: 32rpx;
+
 		.hot-item {
 			.hot-item {
 				padding: 12px 16px;
 			}
 		}
 	}
-
-
 </style>

+ 171 - 0
pages_home/components/volunteerSide/adresss.vue

@@ -0,0 +1,171 @@
+	<template>
+		<view class="box">
+			<!-- <view class="" @click="handleChane">
+				改变
+			</view> -->
+			<up-radio-group v-model="radioValue" @change="handleChane">
+				<view v-for="(item, index) in dataList" :key="index" class="address-item">
+					<!-- 左侧单选框 -->
+					<view class="radio-group">
+						<up-radio shape="circle" activeColor="red" :name="item.addressId"></up-radio>
+					</view>
+
+					<!-- 中间内容区(自动伸缩) -->
+					<view class="content-wrapper">
+						<view class="address-line">
+							<text class="address-text">
+								{{ item.provinceName }}{{ item.cityName }}{{ item.districtName }}
+							</text>
+						</view>
+						<view class="contact-info">
+							<text class="name">{{ item.name }}</text>
+							<text class="phone">{{ item.telephone }}</text>
+						</view>
+					</view>
+
+					<!-- 右侧编辑图标(固定宽度) -->
+					<view class="edit-icon" @click="hadlClickTo(item)">
+						<up-icon name="edit-pen" size="16"></up-icon>
+					</view>
+				</view>
+			</up-radio-group>
+		</view>
+	</template>
+
+	<script setup>
+		import {
+			onMounted,
+			ref
+		} from 'vue'
+		import {
+			addressList
+		} from "@/api/userSettings.js"
+
+		const radioValue = ref(null)
+		const dataList = ref([])
+		const total = ref(0)
+		const addressId = ref('')
+		const onLoadOptions = ref({})
+
+
+		const getListData = async () => {
+			const res = await addressList()
+			dataList.value = res.rows
+			total.value = res.total
+		}
+		
+		const props = defineProps({
+			modelValue: {
+				type: Boolean,
+				default: false
+			},
+			addressInfo: {
+				type: Object,
+				default: () => {}
+			},
+		})
+		const emits = defineEmits([
+			'update:modelValue',
+			'update:addressInfo'
+		])
+
+		function handleChane(addressId, item) {
+			console.log('当前选中的 addressId:', addressId);
+			const selectedItem = dataList.value.find(item => item.addressId === addressId);
+			 console.log('准备发送的数据:', JSON.stringify(selectedItem));
+			emits('update:modelValue', false)
+
+
+			emits('update:addressInfo',selectedItem)
+		}
+
+		onMounted(() => {
+			getListData()
+		})
+	</script>
+
+	<style lang="scss">
+		.box {
+			height: 100vh;
+			width: 100vw;
+			position: fixed;
+			top: 0;
+			left: 0;
+			z-index: 999999;
+			background: #f0f0f0;
+		}
+		
+		
+		.address-list {
+			padding: 20rpx;
+		}
+		
+		.header {
+			display: flex;
+			justify-content: flex-end;
+			align-items: center;
+			margin-bottom: 20rpx;
+		}
+		
+		.add-item {
+			display: flex;
+			align-items: center;
+		}
+		
+		.add-item image {
+			width: 40rpx;
+			height: 40rpx;
+			margin-right: 8rpx;
+		}
+		
+		.add-item text {
+			font-size: 25rpx;
+			color: crimson;
+		}
+		
+		.address-item {
+			display: flex;
+			align-items: flex-start;
+			padding: 24rpx 0;
+			border-bottom: 1rpx solid #f0f0f0;
+		}
+		
+		.radio-group {
+			flex-shrink: 0;
+			/* 禁止压缩 */
+			margin-right: 20rpx;
+		}
+		
+		.content-wrapper {
+			flex: 1;
+			min-width: 0;
+		}
+		
+		.edit-icon {
+			flex-shrink: 0;
+			margin-left: 330rpx;
+			padding: 8rpx;
+		}
+		
+		.address-text {
+			display: inline-block;
+			max-width: 100%;
+			font-size: 32rpx;
+			font-weight: 500;
+			white-space: nowrap;
+			overflow: hidden;
+			text-overflow: ellipsis;
+		}
+		
+		.contact-info {
+			display: flex;
+			gap: 20rpx;
+			margin-top: 8rpx;
+		}
+		
+		.name,
+		.phone {
+			font-size: 28rpx;
+			color: #666;
+		}
+	</style>

+ 181 - 49
pages_home/pages/Volunteerside/goodsDetails.vue

@@ -96,16 +96,47 @@
 
 		<!-- 第二个弹框-->
 		<up-popup v-model:show="showSecond">
-			<view @click="jumpToAddressSelect">
+			<view>
 				<up-cell-group>
-						<up-cell icon="setting-fill" title="请选择服务地址"></up-cell>
-					
-					</up-cell-group>
+					<view @click="jumpToAddressSelect" style="display: flex; align-items: center; padding: 10px;">
+						<up-icon name="more-dot-fill" size="16" />
+
+						<view v-if="selectedAddress" style="margin-left: 8px; flex: 1;">
+							<view class="address-display">
+								<text class="address-line">
+									{{ selectedAddress.provinceName }}{{ selectedAddress.cityName }}{{ selectedAddress.districtName }}
+								</text>
+								<view class="contact-info">
+									<text class="contact-name">{{ selectedAddress.name }}</text>
+									<text class="contact-phone">{{ selectedAddress.telephone }}</text>
+								</view>
+							</view>
+						</view>
+						<text v-else style="margin-left: 8px; font-size: 14px;">请选择服务地址</text>
+					</view>
+					<view class="card-container" v-for="(item, index) in computeClickTime" :key="index">
+						<image class="card-image" :src="listData.volunteerPicture" mode="aspectFill"></image>
+						<view class="card-content"> <!-- Content container -->
+							<view class="info-item">服务项目:{{listData.projectName}}</view>
+							<view class="Telephone">服务时长:{{listData.businessDuration}}</view>
+							<view class="date">日期:{{item.date}}</view>
+							<view class="time">
+								时间:
+								<span v-for="(i,ind) in item.timeArr" :key="ind">
+									{{i}} &nbsp;&nbsp;&nbsp;
+								</span>
+							</view>
+						</view>
+					</view>
+				</up-cell-group>
 			</view>
 			<view class="Wrap-detils-btn">
-				<up-button type="primary" shape="circle" @click="closeSecond">取消</up-button>
-				<up-button type="error" shape="circle" @click="handleSecond">立即预约¥{{ computeMoney }}</up-button>
+				<up-button type="primary" shape="circle" :customStyle="wrapqx" @click="closeSecond">取消</up-button>
+				<up-button type="error" shape="circle" :customStyle="wrapqx" @click="handleSecond">
+					购买¥{{ computeMoney }}
+				</up-button>
 			</view>
+
 		</up-popup>
 
 
@@ -164,6 +195,10 @@
 			</view>
 		</up-popup>
 
+		<view v-if="addressFlag" class="box">
+			<addressComponent :modelValue="addressFlag" @update:modelValue="val => addressFlag = val"
+				:addressInfo="addressInfo" @update:addressInfo="handleAddressUpdate"></addressComponent>
+		</view>
 	</view>
 </template>
 
@@ -187,6 +222,7 @@
 
 	import itsCalendar from '@/components/its-calendar/its-calendar.vue';
 	import uniDatetimePickerMy from "@/uni_modules/lic-uni-datetime-picker/components/lic-uni-datetime-picker/lic-uni-datetime-picker.vue"
+	import addressComponent from "@/pages_home/components/volunteerSide/adresss.vue"
 
 	const src = ref('http://pic2.sc.chinaz.com/Files/pic/pic9/202002/hpic2119_s.jpg')
 	const businessPrice = ref() //价格
@@ -208,23 +244,25 @@
 	const showSecond = ref(false) //第二层弹框
 	const showThird = ref(false) //第二层弹框
 	const showSum = ref(false);
-	const showNotify = ref(false) //支付成功提示
 	const remark = ref('') //备注
 	const radiovalue1 = ref('苹果');
 	// Radio 单选框数据
 	const radiolist1 = reactive([{
-			name: '',
-			disabled: false,
-		},
+		name: '',
+		disabled: false,
+	}, ]);
+
+	const selectedAddress = ref(null);
+	const addressFlag = ref(false)
+
+	const addressInfo = ref(null)
 
-	]);
-	
 	// 详情底部立即购买弹框
 	const buttonClick = (e) => {
 		show.value = true; // 打开弹框
 	};
 
-	// 第一层弹框
+	// 详情页第一层弹框
 	function open() {
 		show.value = true;
 	}
@@ -233,33 +271,33 @@
 		// 关闭逻辑,设置 show 为 false  
 		show.value = false;
 	}
+	
 	// 第一个弹框逻辑
 	const handleBuy = () => {
 		show.value = false; // 关闭第一个弹框
 		showSecond.value = true; // 打开第二个弹框
 	};
 
-	// 第二层弹框
-	function openSecond() {
-		showSecond.value = true;
-	}
+	
 	// 第二层弹框取消
 	function closeSecond() {
 		// 关闭逻辑,设置 show 为 false  
 		showSecond.value = false;
 		show.value = true; // 打开第一个弹框
 	}
-
-	// 第三层弹框
-	function openSum() {
-		// 打开逻辑,比如设置 show 为 true  
+	
+	// 第二层弹框打开第三层
+	function handleSecond() {
 		showSum.value = true;
 	}
+	
+	// 第三层弹框
+	// function openSum() {
+	// 	// 打开逻辑,比如设置 show 为 true  
+	// 	showSum.value = true;
+	// }
 
-	function closeSum() {
-		showSum.value = false;
-	}
-
+	
 
 	const handlCancel = () => {
 		show.value = false; // 关闭第一个弹框
@@ -267,13 +305,16 @@
 		totalTimes.value = 0; // 重置点击次数
 	}
 
+	const jumpToAddressSelect = () => {
+		addressFlag.value = true;
+	};
 
-	const jumpToAddressSelect = () =>{
-		uni.navigateTo({
-			url:'/pages_mine/pages/selectAddress/index'
-		})
-	}
-
+	// 新增:处理子组件传回的地址数据
+	const handleAddressUpdate = (newAddress) => {
+		selectedAddress.value = newAddress;
+		addressFlag.value = false; // 关闭选择器
+		console.log('selectedAddress更新后:', JSON.stringify(selectedAddress.value)); // 添加这行
+	};
 	// 详情底部底部数据
 	const options = ref([{
 			icon: 'headphones',
@@ -317,7 +358,7 @@
 			volunteerId: id,
 			serviceCategory: categoy,
 			businessManagementId: manage
-		} = params;
+		} = params
 		volunteerId.value = id;
 		serviceCategory.value = categoy;
 		businessManagementId.value = manage;
@@ -410,6 +451,9 @@
 		});
 
 		totalTimes.value = selectedTimes.value.length; // 更新点击次数
+
+
+		console.log(selectedTimes.value, '>>>>>selectedTimes.value');
 	}
 
 	// 立即购买显示时执行
@@ -424,6 +468,26 @@
 	const computeMoney = computed(() => {
 		return totalTimes.value * businessPrice.value
 	})
+	const computeClickTime = computed(() => {
+		let timeArr = []
+		let nyr = selectedTimes.value.map(item => {
+			return item.date
+		})
+
+		let nyrSet = Array.from(new Set(nyr)).map(item => {
+			return {
+				date: item,
+				timeArr: []
+			}
+		})
+		selectedTimes.value.forEach(item => {
+			nyrSet.forEach(i => {
+				if (item.date == i.date) i.timeArr.push(item.time)
+			})
+		})
+		console.log(nyrSet, '>>>>>nyrSet');
+		return nyrSet
+	})
 
 	const certificationPictures = computed(() => {
 		if (listData.value.certificationPicture) {
@@ -450,20 +514,8 @@
 				businessManagementId: businessManagementId.value,
 				volunteerInfoId: listData.value.volunteerInfoId,
 			},
-			workDateList: [
-				// {
-				// 	workDate: currentDate.value,//需要传获取到的时间,就是某个月份
-				// }
-			]
+			workDateList: []
 		};
-
-
-		// currentDate.value.length && (new Set(currentDate.value)).forEach((item) => {
-		// 	orderData.workDateList.push({
-		// 		workDate: item,
-		// 		workStartTime: currentTime.value,
-		// 	})
-		// })
 		// 转换所有选择的时间
 		selectedTimes.value.forEach(item => {
 			orderData.workDateList.push({
@@ -472,13 +524,9 @@
 			});
 		});
 
-
-
-
 		try {
 			const res = await ordersCreateOrder(orderData);
 			if (res.code == 200) {
-				showNotify.value = true
 				uni.reLaunch({
 					url: '/pages/index'
 				});
@@ -494,6 +542,16 @@
 </script>
 
 <style scoped>
+	.box {
+		height: 100vh;
+		width: 100vw;
+		position: fixed;
+		top: 0;
+		left: 0;
+		z-index: 999999;
+		background: red;
+	}
+
 	.card-container {
 		display: flex;
 		position: relative;
@@ -702,4 +760,78 @@
 	.certificate-img {
 		margin-bottom: 24rpx;
 	}
+
+
+	/* 第二层弹框 */
+	.card-container {
+		display: flex;
+		flex-direction: row;
+		align-items: flex-start;
+		padding: 10px;
+	}
+
+	.card-image {
+		width: 100px;
+		/* Adjust as needed */
+		height: 100px;
+		/* Adjust as needed */
+		border-radius: 8px;
+		margin-right: 15px;
+		object-fit: cover;
+	}
+
+	.card-content {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.info-item,
+	.Telephone,
+	.date,
+	.time {
+		margin-bottom: 5px;
+		font-size: 14px;
+		color: #333;
+	}
+
+	.time span {
+		margin-right: 8px;
+	}
+
+
+	.address-line {
+		font-size: 14px;
+		line-height: 20rpx;
+		/* 行高20rpx */
+		color: #333;
+		/* 深色文字 */
+		display: block;
+		/* 确保独占一行 */
+		margin-bottom: 30rpx;
+		/* 下边距30rpx */
+	}
+
+	/* 联系人信息容器 */
+	.contact-info {
+		display: flex;
+		gap: 20rpx;
+		/* 姓名和电话之间的间距 */
+	}
+
+	/* 姓名样式 */
+	.contact-name {
+		font-size: 12px;
+		color: #999;
+		/* 灰色文字 */
+		line-height: 20rpx;
+	}
+
+	/* 电话样式 */
+	.contact-phone {
+		font-size: 12px;
+		color: #999;
+		/* 灰色文字 */
+		line-height: 20rpx;
+	}
 </style>

+ 18 - 5
pages_mine/pages/selectAddress/index.vue

@@ -8,13 +8,13 @@
 			</view>
 		</view>
 
-		<up-radio-group v-model="radioValue">
+		<up-radio-group v-model="radioValue" @change="handleRadioChange">
 			<view v-for="(item, index) in dataList" :key="index" class="address-item">
 				<!-- 左侧单选框 -->
 				<view class="radio-group">
 					<up-radio shape="circle" activeColor="red" :name="item.addressId"></up-radio>
 				</view>
-			
+
 				<!-- 中间内容区(自动伸缩) -->
 				<view class="content-wrapper">
 					<view class="address-line">
@@ -50,12 +50,14 @@
 	const dataList = ref([])
 	const total = ref(0)
 	const addressId = ref('')
+	
 	const getListData = async () => {
 		const res = await addressList()
 		dataList.value = res.rows
 		total.value = res.total
 		console.log(dataList.value, '>>>>>dataList.value');
 	}
+	const onLoadOptions = ref({})
 
 	const hadlClickTo = (item) => {
 		const {
@@ -81,13 +83,24 @@
 			url: `/pages_mine/pages/selectAddress/edit?${params}`
 		});
 	};
-	
-	const handlHeader = ()=>{
+
+	const handlHeader = () => {
 		uni.navigateTo({
 			url: `/pages_mine/pages/setupUser/Address`
 		});
 	}
 
+
+	const handleRadioChange = (addressId,item) => {
+		console.log('当前选中的 addressId:', addressId);
+		  const selectedItem = dataList.value.find(item => item.addressId === addressId);
+		  console.log('选中项完整数据:', selectedItem);
+	};
+	
+	// onLoad((options) => {
+	// 	onLoadOptions.value = JSON.parse(decodeURIComponent(options.onLoadOptions));
+	// })
+	
 	onMounted(() => {
 		getListData()
 	})
@@ -166,4 +179,4 @@
 		font-size: 28rpx;
 		color: #666;
 	}
-</style>
+</style>