浏览代码

用户端页面优化

jiayubo 2 天之前
父节点
当前提交
2cb9df1a85

+ 102 - 76
components/its-calendar/its-calendar.vue

@@ -15,7 +15,7 @@
 					<view class="time_x" 
 						:class="{
 							'time_x_sty': item?.checked, 
-							'disabled-time': item?.disabled
+							'disabled-time': item?.disabled || item?.hasReservation === 1
 						}" 
 						v-for="(item, index) in timeHostArr[day_index]" 
 						:key="index"
@@ -27,6 +27,7 @@
 			</scroll-view>
 		</view>
 		<view class="calendar_footer">
+			{{ selectRange  }}
 			<view class="remark_content">{{remark}}</view>
 		</view>
 	</view>
@@ -69,7 +70,7 @@
 		watch: {
 			timeArr: {
 				handler(newVal) {
-					console.log(newVal, '>>>>>>>时间范围');
+					// console.log(newVal, '>>>>>>>时间范围');
 					let dateArr = newVal.map(item => {
 						let day = new Date(item)
 						const daysOfWeek = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
@@ -85,7 +86,7 @@
 			},
 			timeHostArr: {
 				handler(newVal) {
-					console.log(newVal, '>>>>>>>时间更新');
+					// console.log(newVal, '>>>>>>>时间更新');
 					// 当timeHostArr更新时,恢复之前的选择状态
 					if (newVal && newVal.length > 0) {
 						this.restoreSelections();
@@ -95,21 +96,62 @@
 			}
 		},
 		mounted() {
+			
+		},
+		computed: {
+			// 计算选中区域
+			selectRange() {
+				const reservations = this.timeHostArr[this.day_index]
+				console.log(reservations, '>>>>>reservations');
+				// console.log(JSON.stringify(current), '>>>>>current');
+				// return current
+				const result = [];
+				  let currentGroup = null;
+				
+				  for (const item of reservations) {
+				    if (item.checked) {
+				      // 遇到新的checked项,创建新组
+				      if (currentGroup) {
+				        result.push(currentGroup);
+				      }
+				      currentGroup = [item];
+				    } else if (currentGroup && item.disabled && item.hasReservation === 0) {
+				      // 如果当前有活跃的组,且符合disabled和hasReservation条件,加入当前组
+				      currentGroup.push(item);
+				    } else if (currentGroup) {
+				      // 不符合连续条件,结束当前组
+				      result.push(currentGroup);
+				      currentGroup = null;
+				    }
+				  }
+				
+				  // 添加最后一组(如果有)
+				  if (currentGroup) {
+				    result.push(currentGroup);
+				  }
+				  
+				  const timeRangeArr = result.map(arr => {
+					  return arr[0].hours + '-' +arr[arr.length -1].hours
+				  })
+				  
+				  
+				  return timeRangeArr;
+			}
 		},
 		methods: {
 			// 恢复选择状态
 			restoreSelections() {
-				console.log('>>>>>>执行了', this.selectedTimeSlots);
+				// console.log('>>>>>>执行了', this.selectedTimeSlots);
 				if (!this.timeHostArr[this.day_index]) return;
 				
-				console.log('>>>>>>执行了2', this.selectedTimeSlots);
+				// console.log('>>>>>>执行了2', this.selectedTimeSlots);
 				
 				// 遍历当前日期的时间槽
 				this.timeHostArr[this.day_index].forEach(slot => {
 					// 检查这个时间槽是否在之前被选中
 					const dateKey = this.timeArr[this.day_index];
-					console.log(dateKey, '>>>>dateKey');
-					console.log(this.selectedTimeSlots[dateKey], '>>>>this.selectedTimeSlots[dateKey]');
+					// console.log(dateKey, '>>>>dateKey');
+					// console.log(this.selectedTimeSlots[dateKey], '>>>>this.selectedTimeSlots[dateKey]');
 					if (this.selectedTimeSlots[dateKey] && 
 						this.selectedTimeSlots[dateKey].includes(slot.timeStamp)) {
 						slot.checked = true;
@@ -127,7 +169,7 @@
 							}
 						});
 						
-						
+		
 					}
 				});
 			},
@@ -175,29 +217,35 @@
 					}
 				}
 
-				// 3. 其他逻辑保持不变
+				// 3. 检查当前时间到结束是否有足够的时间段
 				const seconds = this.businessDuration  * this.minQuantity * 60;
 				const endTimestamp = (item.timeStamp + seconds);
+				
+				// 找出当前时间到服务结束时间之间的所有时间段
 				const filteredSlots = this.timeHostArr[this.day_index].filter(i => {
-				   return (i.timeStamp > item.timeStamp && 
-				          i.timeStamp <= endTimestamp)
+					return (i.timeStamp > item.timeStamp && i.timeStamp <= endTimestamp);
 				});
-				this.filteredSlots = filteredSlots
+				this.filteredSlots = filteredSlots;
 				 
-				 console.log(filteredSlots, '》》》》》》filteredSlots');
+				// 检查这些时间段中是否有已预约的时间
+				const hasReservedSlot = filteredSlots.some(slot => slot.hasReservation === 1);
+				if (hasReservedSlot) {
+					uni.showToast({ title: '所选时间段内有已预约时间,请选择其他时间', icon: 'none' });
+					return false;
+				}
 				 
 				// 时间差值(数组中的最后一项 - 当前点击项)
-				const timestampDifferenceValue = filteredSlots.length ? (filteredSlots[filteredSlots.length - 1].timeStamp - item.timeStamp) * 1000 : 0
+				const timestampDifferenceValue = filteredSlots.length ? (filteredSlots[filteredSlots.length - 1].timeStamp - item.timeStamp) * 1000 : 0;
 				
 				// 选择时间,后续服务时间是否充足,不充足结束逻辑执行 timeStamp
 				if (timestampDifferenceValue < durationMs) { // 所选时间差值 小于 服务时间值 结束执行
 					uni.showToast({ title: '所选时间的服务时间不充足!', icon: 'none' });
-					return false
+					return false;
 				}
-				 
+					
 				if (!item.checked) {
 					filteredSlots.forEach(v => {
-						v.disabled = true
+						v.disabled = true;
 					});
 					item.checked = true;
 					if (!this.selectedTimeSlots[currentDate]) {
@@ -206,7 +254,7 @@
 					this.selectedTimeSlots[currentDate].push(item.timeStamp);
 				} else {
 					filteredSlots.forEach(v => {
-						if (v.hasReservation !== 1) v.disabled = false
+						if (v.hasReservation !== 1) v.disabled = false;
 					});
 					item.checked = false;
 					if (this.selectedTimeSlots[currentDate]) {
@@ -220,25 +268,22 @@
 			},
 			
 			async handleTimeClick2() {
+				if (!this.upItem) return;
 				
-				let item = this.upItem
-				
-				// console.log(this.timeHostArr[this.day_index], '>>>this.timeHostArr[this.day_index]');
+				let item = this.upItem;
+				const currentDate = this.timeArr[this.day_index];
+				const durationMs = this.businessDuration * this.minQuantity * 60 * 1000;
+				const itemTime = item.timeStamp > 9999999999 ? item.timeStamp : item.timeStamp * 1000;
+				const slots = this.timeHostArr[this.day_index] || [];
 				
-				// 处理减法时 (选中状态重置)
+				// 保留之前的选择状态,只重置disabled状态
 				this.timeHostArr[this.day_index].forEach(s => {
-					 s.disabled = item.hasReservation === 1
+					if (s.hasReservation !== 1 && !s.checked) {
+						s.disabled = false;
+					}
 				});
-				// this.hosts(item);
-				
-				// console.log(this.timeArr, '.>>>>item1111');
-				
-				const durationMs = this.businessDuration  * this.minQuantity * 60 * 1000;
-				const itemTime = item.timeStamp > 9999999999 ? item.timeStamp : item.timeStamp * 1000;
-				const slots = this.timeHostArr[this.day_index] || [];
-				const currentDate = this.timeArr[this.day_index];
 				
-				// 1. 判断当前时间是否在任何已预约时间段的服务时长范围内
+				// 1. 检查是否与已预约时间冲突
 				let inReservedRange = false;
 				for (let slot of slots) {
 					if (slot.hasReservation === 1) {
@@ -256,57 +301,38 @@
 					return false;
 				}
 				
-				// 2. 判断当前点击时间与所有已选时间段的服务时长有无重叠(多选判断)
-				const selectedArr = this.selectedTimeSlots[currentDate] || [];
-				if (!item.checked) { // 只在选中时判断
-					for (let t of selectedArr) {
-						if (t === item.timeStamp) continue; // 跳过自己
-						const tStart = t > 9999999999 ? t : t * 1000;
-						const tEnd = tStart + durationMs;
-						if (
-							(itemTime >= tStart && itemTime < tEnd) ||
-							(itemTime < tStart && itemTime + durationMs > tStart)
-						) {
-							uni.showToast({ title: '时间段不在服务范围内', icon: 'none' });
-							return false;
-						}
-					}
-				}
-				
-				// 3. 其他逻辑保持不变
-				const seconds = this.businessDuration  * this.minQuantity * 60;
-				// console.log(this.businessDuration, this.minQuantity, '>>>>>9999');
+				// 2. 检查是否有足够的后续时间段
+				const seconds = this.businessDuration * this.minQuantity * 60;
 				const endTimestamp = (item.timeStamp + seconds);
-				// console.log(endTimestamp, '>>>>>>endTimestamp');
-				const filteredSlots = this.timeHostArr[this.day_index].filter(i => {
-				   return (i.timeStamp > item.timeStamp && 
-				          i.timeStamp <= endTimestamp)
-				 });
-				 this.filteredSlots = filteredSlots
-				 
-				 // console.log(filteredSlots, '》》》》》》filteredSlots');
-				 
-				// 时间差值(数组中的最后一项 - 当前点击项)
-				const timestampDifferenceValue = filteredSlots.length ? (filteredSlots[filteredSlots.length - 1].timeStamp - item.timeStamp) * 1000 : 0
-				
-				// 选择时间,后续服务时间是否充足,不充足结束逻辑执行 timeStamp
-				if (timestampDifferenceValue < durationMs) { // 所选时间差值 小于 服务时间值 结束执行
-					uni.showToast({ title: '所选时间的服务时间不充足!', icon: 'none' });
-					return false
-				}
 				
-				filteredSlots.forEach(v => {
-					v.disabled = true
+				// 找出从当前时间到结束时间之间的所有时间段
+				const filteredSlots = this.timeHostArr[this.day_index].filter(i => {
+					return (i.timeStamp > item.timeStamp && i.timeStamp <= endTimestamp);
 				});
+				this.filteredSlots = filteredSlots;
 				
-				console.log('>>>>>执行');
+				// 检查这些时间段中是否有已预约的时间
+				const hasReservedSlot = filteredSlots.some(slot => slot.hasReservation === 1);
+				if (hasReservedSlot) {
+					uni.showToast({ title: '所选时间段内有已预约时间,请选择其他时间', icon: 'none' });
+					return false;
+				}
 				
-				if (!this.selectedTimeSlots[currentDate]) {
-					this.selectedTimeSlots[currentDate] = [];
+				// 检查时间是否足够
+				const timestampDifferenceValue = filteredSlots.length ? (filteredSlots[filteredSlots.length - 1].timeStamp - item.timeStamp) * 1000 : 0;
+				if (timestampDifferenceValue < durationMs) {
+					uni.showToast({ title: '所选时间的服务时间不充足!', icon: 'none' });
+					return false;
 				}
-				this.selectedTimeSlots[currentDate].push(item.timeStamp);
 				
-				// this.hosts(item);
+				// 所有检查通过,更新disabled状态
+				// filteredSlots.forEach(v => {
+				// 	if (v.hasReservation !== 1 && !v.checked) {
+				// 		v.disabled = true;
+				// 	}
+				// });
+				
+				this.hosts(item);
 			},
 			
 			// 点击日期

+ 2 - 2
config.js

@@ -2,8 +2,8 @@
 const config = {
 	// baseUrl: 'https://vue.ruoyi.vip/prod-api',
 	//cloud后台网关地址
-	// baseUrl: 'http://192.168.100.95:9527',//嵘哥
-	baseUrl: 'http://192.168.100.101:9527',//龙哥
+	baseUrl: 'http://192.168.100.95:9527',//嵘哥
+	// baseUrl: 'http://192.168.100.101:9527',//龙哥
 	// baseUrl: 'https://zybooks.tech/prod-api',
 	mapKey:'KFEBZ-P2GKZ-A5PX4-7Q6Y7-KXOBF-XCB4C',
 	appName: '金邻助家',

+ 235 - 230
pages/login.vue

@@ -1,275 +1,280 @@
 <template>
-	<view class="normal-login-container">
-		<view class="logo-content align-center justify-center flex">
-			<image :src="imagePath" mode="aspectFit" style="width: 100rpx;height: 100rpx;"></image>
-			<text class="title">金邻助家</text>
-		</view>
-		<up-popup :show="show" mode="bottom" @close="close" @open="open">
-			<view class="popup-content">
-				<!-- 上方头像 -->
-				<up-avatar :src="src" class="avatar"></up-avatar>
-
-				<!-- 下方按钮 -->
-				<up-button type="error" shape="circle" class="button" @click="handleLogin">获取微信授权登录</up-button>
-			</view>
-			<view class="xieyi text-center">
-				<text class="text-grey1">登录即代表同意</text>
-				<text @click="handleUserAgrement" class="text-blue">《用户协议》</text>
-				<text @click="handlePrivacy" class="text-blue">《隐私协议》</text>
-			</view>
-		</up-popup>
-	</view>
+  <view class="normal-login-container">
+    <view class="logo-content">
+      <image :src="imagePath" mode="aspectFit" class="logo-image"></image>
+      <text class="title">金邻助家</text>
+    </view>
+
+    <image
+      src="/static/13779@1x.png"
+      mode="widthFix"
+      class="house-illustration"
+    ></image>
+
+    <view class="slogan-content">
+      <text class="slogan-text">着力打造全国居家服务行业标准</text>
+      <text class="slogan-text">和建立综合信用评价体系</text>
+    </view>
+
+    <!-- 波浪容器 -->
+    <view class="wave-container">
+      <image src="/static/Vector 1@1x.png" mode="widthFix" class="wave-img"></image>
+      <image src="/static/Vector 2@1x.png" mode="widthFix" class="wave-img"></image>
+    </view>
+
+    <view class="actions-container">
+      <up-button
+        custom-style="{ 'background-color': '#623F34', 'color': '#FFFFFF', 'border-radius': '25px', 'height': '50px', 'line-height': '50px', 'fontSize': '18px' }"
+        class="login-button"
+        @click="handleLogin"
+        >微信授权登录</up-button
+      >
+      <view class="xieyi text-center">
+        <text class="text-grey1">登录即代表同意</text>
+        <text @click="handleUserAgrement" class="text-blue">《用户协议》</text>
+        <text @click="handlePrivacy" class="text-blue">《隐私协议》</text>
+      </view>
+    </view>
+  </view>
 </template>
 
 <script setup>
-import {
-	ref,
-	reactive,
-	onMounted
-} from 'vue';
-import {
-	useRouter,
-	useRoute
-} from 'vue-router'; // 根据实际情况选择路由库
-import {
-	getCodeImg,
-	login
-} from '@/api/login';
-
-import store from "@/store"
+import { ref, reactive, onMounted } from 'vue'
+import { useRouter } from 'vue-router' // 根据实际情况选择路由库
+import store from '@/store'
 
-const imagePath = '/static/9efd1.png';
+const imagePath = '/static/9efd1.png' // Path to the logo image (red tree)
 
 // 获取全局配置
 // const globalConfig = getApp().globalData.config;
-const register = ref(false); // 用户注册开关
+const register = ref(false) // 用户注册开关
 const loginForm = reactive({
-	username: "",
-	password: "",
-	code: "",
-	uuid: ''
-});
-
-const codeUrl = ref("");
-const captchaEnabled = ref(true);
+  username: '',
+  password: '',
+  code: '',
+  uuid: '',
+})
 
+// const codeUrl = ref(""); // Not used in the new design
+// const captchaEnabled = ref(true); // Not used in the new design
 
-const router = useRouter();
-// 创建响应式数据  
-const show = ref(false);
-
-// 定义方法  
-function open() {
-	// 打开逻辑,比如设置 show 为 true  
-	show.value = true;
-}
+const router = useRouter()
 
-function close() {
-	// 关闭逻辑,设置 show 为 false  
-	show.value = false;
-}
-
-// 用户注册
+// 用户注册 - assuming this might be needed later, keeping it
 const handleUserRegister = () => {
-	router.push('/pages/register'); // 替换为实际的路由跳转逻辑
-};
+  router.push('/pages/register') // 替换为实际的路由跳转逻辑
+}
 
 // 隐私协议
 const handlePrivacy = () => {
-	uni.navigateTo({
-		url: '/pages_home/pages/login/index'
-	})
-};
+  uni.navigateTo({
+    url: '/pages_home/pages/login/index',
+  })
+}
 
 // 用户协议
 const handleUserAgrement = () => {
-	uni.navigateTo({
-		url: '/pages_home/pages/login/user'
-	})
-};
+  uni.navigateTo({
+    url: '/pages_home/pages/login/user',
+  })
+}
 
 // 登录方法
 const handleLogin = async () => {
-	uni.showLoading({
-		title: "登录中,请耐心等待..."
-	}); // 使用uni-app的loading方法替代$modal.loading
-	// 获取服务商信息
-	uni.getProvider({
-		service: "oauth",
-		success: (res) => {
-			console.log(res);
-		}
-	});
-
-	// 获取code
-	uni.login({
-		provider: 'weixin',
-		success: (res) => {
-			if (res.code == 500) {
-				uni.showLoading({
-					title: "系统暂未开发,敬请期待"
-				});
-			} else if (res.code == 400) {
-				uni.showLoading({
-					title: "系统暂未开放"
-				});
-			}
-			loginForm.code = res.code;
-			// 获取用户信息
-			uni.getUserInfo({
-				success: (res) => {
-					console.log("用户信息", res);
-				}
-			});
-
-			pwdLogin();
-
-			uni.hideLoading()
-		},
-	});
-};
+  uni.showLoading({
+    title: '登录中,请耐心等待...',
+  }) // 使用uni-app的loading方法替代$modal.loading
+  // 获取服务商信息
+  uni.getProvider({
+    service: 'oauth',
+    success: (res) => {
+      console.log(res)
+    },
+  })
+
+  // 获取code
+  uni.login({
+    provider: 'weixin',
+    success: (res) => {
+      if (res.code == 500) {
+        uni.showLoading({
+          title: '系统暂未开发,敬请期待',
+        })
+      } else if (res.code == 400) {
+        uni.showLoading({
+          title: '系统暂未开放',
+        })
+      }
+      loginForm.code = res.code
+      // 获取用户信息
+      uni.getUserInfo({
+        success: (res) => {
+          console.log('用户信息', res)
+        },
+      })
+
+      pwdLogin()
+
+      uni.hideLoading()
+    },
+  })
+}
 
 // 密码登录
 const pwdLogin = async () => {
-	if (!store) {
-		console.error("Store is not defined");
-		return;
-	}
-	store.dispatch('Login', loginForm).then(() => {
-		// uni.hideLoading(); // 关闭加载提示
-		loginSuccess();
-	})
-};
-
+  if (!store) {
+    console.error('Store is not defined')
+    return
+  }
+  store.dispatch('Login', loginForm).then(() => {
+    // uni.hideLoading(); // 关闭加载提示
+    loginSuccess()
+  })
+}
 
 // 登录成功后,处理函数
 const loginSuccess = () => {
-	store.dispatch('GetInfo').then((res) => {
-
-		console.log(store.state.user.userOrWorker, '>>>>99');
-		if (store.state.user.userOrWorker == 0) {
-			uni.reLaunch({
-				url: '/pages/UserSelection'
-			});
-			return
-		}
-		uni.setStorageSync('userType', store.state.user.userOrWorker);
-		uni.switchTab({
-			url: '/pages/index'
-		})
-
-	});
-};
+  store.dispatch('GetInfo').then((res) => {
+    console.log(store.state.user.userOrWorker, '>>>>99')
+    if (store.state.user.userOrWorker == 0) {
+      uni.reLaunch({
+        url: '/pages/UserSelection',
+      })
+      return
+    }
+    uni.setStorageSync('userType', store.state.user.userOrWorker)
+    uni.switchTab({
+      url: '/pages/index',
+    })
+  })
+}
 
-// 页面加载时获取验证码
+// 页面加载时
 onMounted(() => {
-	uni.setStorageSync('userType', 0);
-	open();
-});
+  uni.setStorageSync('userType', 0)
+  // open(); // Popup related, removed
+})
 </script>
 
-<style lang="scss">
+<style lang="scss" scoped>
 page {
-	background-color: #ffffff;
+  height: 100vh;
+  width: 100%;
 }
 
 .normal-login-container {
-	width: 100%;
-
-	.logo-content {
-		width: 100%;
-		font-size: 21px;
-		text-align: center;
-		padding-top: 25%;
-
-		image {
-			border-radius: 4px;
-		}
-
-		.title {
-			margin-left: 10px;
-		}
-	}
-
-	.login-form-content {
-		text-align: center;
-		margin: 20px auto;
-		margin-top: 15%;
-		width: 80%;
-
-		.input-item {
-			margin: 20px auto;
-			background-color: #f5f6f7;
-			height: 45px;
-			border-radius: 20px;
-
-			.icon {
-				font-size: 38rpx;
-				margin-left: 10px;
-				color: #999;
-			}
-
-			.input {
-				width: 100%;
-				font-size: 14px;
-				line-height: 20px;
-				text-align: left;
-				padding-left: 15px;
-			}
-
-		}
-
-		.login-btn {
-			margin-top: 40px;
-			height: 45px;
-		}
-
-		.reg {
-			margin-top: 15px;
-		}
-
-		.xieyi {
-			color: #333;
-			margin-top: 20px;
-		}
+  width: 100%;
+  height: 100vh;
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  // background: linear-gradient(180deg, #ffa485 0%, #f6b053 100%);
+  overflow: hidden;
+}
 
-		.login-code {
-			height: 38px;
-			float: right;
+.logo-content {
+  margin-top: 177rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  
+  .logo-image {
+    width: 90rpx;
+    height: 90rpx;
+    margin-bottom: 20rpx;
+  }
+  
+  .title {
+    font-family: PingFang SC;
+    font-size: 38rpx;
+    font-weight: 600;
+    line-height: 38rpx;
+    color: #ffffff;
+    text-align: center;
+  }
+}
 
-			.login-code-img {
-				height: 38px;
-				position: absolute;
-				margin-left: 10px;
-				width: 200rpx;
-			}
-		}
-	}
+.house-illustration {
+  width: 560rpx;
+  margin-top: 60rpx;
+  margin-bottom: 40rpx;
 }
 
-/* 弹性容器:垂直方向排列 */
-.popup-content {
-	display: flex;
-	flex-direction: column;
-	/* 上下布局 */
-	align-items: center;
-	/* 水平居中 */
-	padding: 30rpx;
-	/* 元素间距 */
-	gap: 30rpx;
+.slogan-content {
+  text-align: center;
+  
+  .slogan-text {
+    font-size: 28rpx;
+    color: #593931;
+    line-height: 38rpx;
+    display: block;
+  }
 }
 
-/* 头像样式 */
-.avatar {
-	width: 120rpx;
-	height: 160rpx;
+.actions-container {
+  width: 100%;
+  padding: 0 80rpx;
+  position: absolute;
+  bottom: 80rpx;
+  left: 0;
+  z-index: 2;
+  
+  .login-button {
+    width: 100%;
+    height: 88rpx;
+    line-height: 88rpx;
+    border-radius: 44rpx !important;
+    background-color: #623f34 !important;
+    color: #ffffff !important;
+    font-size: 32rpx !important;
+    font-weight: 400;
+  }
+  
+  .xieyi {
+    margin-top: 24rpx;
+    text-align: center;
+    
+    .text-grey1 {
+      font-size: 24rpx;
+      color: #333333;
+    }
+    
+    .text-blue {
+      font-size: 24rpx;
+      color: #1a88ff;
+      margin: 0 4rpx;
+    }
+  }
 }
 
-/* 按钮样式 */
-.button {
-	// width: 170rpx !important;
-	/* 覆盖默认宽度 */
-	margin-left: 0 !important;
-	/* 清除原代码中的 margin-left */
+/* 波浪区域样式 */
+.wave-container {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 300rpx;
+  overflow: hidden;
+  z-index: 1;
+
+  .wave-img {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+
+    &:first-child {
+      opacity: 0.4;
+      mix-blend-mode: multiply;
+    }
+
+    &:last-child {
+      transform: translateY(20rpx);
+    }
+  }
 }
-</style>
+
+</style>
+

+ 8 - 4
pages/mine.vue

@@ -97,6 +97,8 @@ import {
 import store from "@/store"
 import { getVolunteerAccountInfo, volunteerOrderStatistics } from "@/api/mine";
 import CustomTabBar from '@/components/CustomTabBar/index.vue'
+
+
 const userInfo = ref({
 	avatar: '/static/serverImg/mine/user.png'
 })
@@ -176,9 +178,10 @@ const adminList = ref(
 		{
 			name: '用户端',
 			iconName: 'account',
-			operate: () => {
+      operate: () => {
+        uni.setStorageSync('userType', 1);
 				uni.reLaunch({
-					url: '/pages/UserSelection'
+					url: '/pages/index'
 				});
 			}
 		},
@@ -211,11 +214,12 @@ const userList = ref([
 		iconName: 'kefu-ermai',
 	},
 	{
-		name: '志愿者',
+		name: '成为志愿者',
 		iconName: 'account',
 		operate: () => {
+			uni.setStorageSync('userType', 2);
 			uni.reLaunch({
-				url: '/pages/UserSelection'
+				url: '/pages/index'
 			});
 		}
 	}

+ 339 - 289
pages_classify/pages/orderItem/orderdetails.vue

@@ -1,296 +1,346 @@
 <template>
-	<view>
-		<view class="address-container">
-			<view class="address-header">
-				<!-- 左侧默认标签-->
-				<up-tag text="默认" type="error"></up-tag>
-
-				<!-- 中间收货人信息 -->
-				<view class="contact-info">
-					{{listData.address.name}}
-					{{listData.address.telephone}}
-				</view>
-
-				<!-- 右侧图标 -->
-				<up-icon name="arrow-right" class="arrow-icon"></up-icon>
-			</view>
-
-			<!-- 下方地址信息 -->
-			<view class="address-detail">
-				{{listData.address.provinceName}}
-				{{listData.address.cityName}}
-				{{listData.address.districtName}}
-			</view>
-		</view>
-
-		<view>
-			<up-card title="志愿者介绍" :head-style="{ height: '80rpx', padding: '20rpx',}">
-				<template #body>
-					<view class="card-container">
-						<image class="card-image" :src="listData.volunteerInfo.volunteerPicture" mode="aspectFill">
-						</image>
-
-						<view class="card-info">
-							<view class="info-item">{{listData.volunteerInfo.name}}</view>
-							<view class="info-item">类别:{{ listData.volunteerInfo.businessTierName }} </view>
-							<view class="Telephone">电话:{{listData.volunteerInfo.phonenumber}}</view>
-							<view class="info-item">住址:{{listData.volunteerInfo.city}}</view>
-						</view>
-
-						<view class="card-rating">4.5 评分</view>
-					</view>
-				</template>
-			</up-card>
-			<up-card title="技能介绍" :head-style="{ height: '80rpx', padding: '20rpx',}">
-				<template #body>
-					{{listData.volunteerInfo.skillDescribe}}
-				</template>
-			</up-card>
-			<up-card title="证书" :head-style="{ height: '80rpx', padding: '20rpx',}">
-				<template #body>
-					<view class="certificate">
-						<image v-for="item in certificationPictures" :key="item" :src="item" mode=""
-							style="width: 100%;" class="certificate-img"></image>
-					</view>
-				</template>
-			</up-card>
-		</view>
-
-		<view>
-			<up-list @scrolltolower="scrolltolower">
-				<up-list-item v-for="(item, index) in listData.secondOrderList" :key="index">
-					<view class="Wrap-top">
-						<text>第一节课</text>
-					</view>
-					<view class="list-item">
-						<image :src="listData.volunteerInfo.volunteerPicture" mode="aspectFill" class="item-image">
-						</image>
-						<view class="item-info">
-							<view class="info-line">
-								类别:{{ listData.volunteerInfo.projectName }}-{{ listData.volunteerInfo.serviceSubjectName }}
-							</view>
-							<text>开始日期:{{item.workDate}}</text>
-							<text>开始时间: {{item.workStartTime}}</text>
-						</view>
-						<view class="right-corner-container">
-							<text> {{dictSortMap[item.orderStatus]}}</text>
-							<up-button type="error" text="评论" size="mini" @click="handlButClick"
-								:customStyle="hadlClickError"></up-button>
-						</view>
-					</view>
-				</up-list-item>
-			</up-list>
-
-		</view>
-	</view>
+  <view>
+    <view class="address-container">
+      <view class="address-header">
+        <!-- 左侧默认标签-->
+        <up-tag text="默认" type="error"></up-tag>
+
+        <!-- 中间收货人信息 -->
+        <view class="contact-info">
+          {{ listData.cityName }}
+          {{ listData.telephone }}
+        </view>
+
+        <!-- 右侧图标 -->
+        <up-icon name="arrow-right" class="arrow-icon"></up-icon>
+      </view>
+
+      <!-- 下方地址信息 -->
+      <view class="address-detail">
+        {{ listData.provinceName }} {{ listData.cityName }}
+        {{ listData.districtName }} {{ listData.address }}
+      </view>
+    </view>
+
+    <view>
+      <up-card
+        title="服务信息"
+        :head-style="{ height: '80rpx', padding: '20rpx' }"
+      >
+        <template #body>
+          <view class="card-container">
+            <image
+              class="card-image"
+              :src="listData.volunteerPicture"
+              mode="aspectFill"
+            >
+            </image>
+
+            <view class="card-info">
+              <view class="info-item">服务类别:{{ listData.serviceCategory }}</view>
+              <view class="info-item">服务时长:{{ listData.serviceDuration}}分钟</view>
+              <view class="info-item">服务价格:{{ listData.serviceOnePrice }}</view>
+              <view class="info-item">服务数量:{{ listData.singleQuantity }}{{ listData.businessUnit }}</view>
+              <view class="info-item">服务类别:{{ listData.businessDescribe}}</view>
+            </view>
+
+            <view class="card-rating">4.5 评分</view>
+          </view>
+        </template>
+      </up-card>
+
+      <up-card
+        title="志愿者介绍"
+        :head-style="{ height: '80rpx', padding: '20rpx' }"
+      >
+        <template #body>
+          <view class="card-container">
+            <image
+              class="card-image"
+              :src="listData.volunteerPicture"
+              mode="aspectFill"
+            >
+            </image>
+
+            <view class="card-info">
+              <view class="info-item">{{ listData.volunteerName }}</view>
+              <view class="info-item">年龄:{{ listData.age }}</view>
+              <view class="Telephone">电话:{{ listData.phonenumber }}</view>
+              <view class="info-item">住址:{{ listData.address }}</view>
+            </view>
+
+            <view class="card-rating">4.5 评分</view>
+          </view>
+        </template>
+      </up-card>
+      <up-card
+        title="技能介绍"
+        :head-style="{ height: '80rpx', padding: '20rpx' }"
+      >
+        <template #body>
+          {{ listData.skillDescribe }}
+        </template>
+      </up-card>
+      <up-card title="证书" :head-style="{ height: '80rpx', padding: '20rpx' }">
+        <template #body>
+          <view class="certificate" v-if="listData.certificationPicture">
+            <image
+              :src="listData.certificationPicture"
+              mode=""
+              style="width: 100%"
+              class="certificate-img"
+            ></image>
+          </view>
+        </template>
+      </up-card>
+    </view>
+
+    <view>
+      <up-list @scrolltolower="scrolltolower">
+        <up-list-item
+          v-for="(item, index) in listData.secondOrderList"
+          :key="index"
+        >
+          <view class="Wrap-top">
+            <text>第{{ index + 1 }}节课</text>
+          </view>
+          <view class="list-item">
+            <image
+              :src="listData.volunteerPicture"
+              mode="aspectFill"
+              class="item-image"
+            >
+            </image>
+            <view class="item-info">
+              <view class="info-line">
+                服务类别:{{ item.serviceCategory }}
+              </view>
+              <text>服务价格:{{ item.serviceTotalPrice }}</text>
+              <text
+                >状态:{{
+                  dictSortMap[item.orderStatus] || item.orderStatus
+                }}</text
+              >
+            </view>
+            <view class="right-corner-container">
+              <text>
+                {{ dictSortMap[item.orderStatus] || item.orderStatus }}</text
+              >
+              <up-button
+                type="error"
+                text="评论"
+                size="mini"
+                @click="handlButClick(item)"
+                :customStyle="hadlClickError"
+              ></up-button>
+            </view>
+          </view>
+        </up-list-item>
+      </up-list>
+    </view>
+  </view>
 </template>
 
-
 <script setup>
-	import {
-		onLoad
-	} from '@dcloudio/uni-app'
-	import {
-		ref,
-		computed,
-		onMounted
-	} from "vue";
-	import {
-		orderInfomainOrderId
-	} from "@/api/userList.js";
-	import {
-		systemDictdaTalist
-	} from "@/api/userList.js"
-
-
-	const listData = ref(); //志愿者详情数据
-	const dataList = ref([])
-	const orderStatus = ref(0)
-	const score = ref(null)
-	const mainOrderId = ref(''); //志愿者ID
-
-	const certificationPictures = computed(() => {
-		if (listData.value.volunteerInfo.certificationPicture) {
-			return listData.value.volunteerInfo.certificationPicture.split(',')
-		}
-		return []
-	})
-
-	const dictSortMap = computed(() => {
-		let mapObj = {}
-		dataList.value.forEach((item => {
-			mapObj[item.dictValue] = item.dictLabel
-		}))
-		return mapObj
-	})
-
-	//获取用户订单列表状态
-	async function getData() {
-		try {
-			const res = await systemDictdaTalist().catch(err => {
-				console.error('接口请求失败:', err);
-				throw err; // 重新抛出以进入 catch 块
-			});
-			dataList.value = res.rows;
-		} catch (e) {
-			console.error('获取数据异常:', e); // 确保这里打印错误
-		}
-	}
-
-	const handlButClick = (item) => {
-		uni.navigateTo({
-			url: `/pages_classify/pages/orderItem/userComment?mainOrderId=${mainOrderId.value}&data=${encodeURIComponent(JSON.stringify(listData.value))}`
-		});
-	}
-
-	// 获取传递的参数
-	onLoad(async (options) => {
-		mainOrderId.value = options.mainOrderId;
-		const res = await orderInfomainOrderId(mainOrderId.value)
-		listData.value = res.data;
-	});
-
-	const hadlClickError = {
-		width: '150rpx',
-		height:'50rpx',
-		marginTop: '70rpx'
-	}
-	onMounted(() => {
-		getData()
-	})
+import { onLoad } from '@dcloudio/uni-app'
+import { ref, computed, onMounted } from 'vue'
+import { orderInfomainOrderId } from '@/api/userList.js'
+import { systemDictdaTalist } from '@/api/userList.js'
+
+const listData = ref({}) //志愿者详情数据
+const dataList = ref([])
+const orderStatus = ref(0)
+const score = ref(null)
+const mainOrderId = ref('') //志愿者ID
+
+// const certificationPictures = computed(() => {
+// 	if (listData.value.volunteerInfo.certificationPicture) {
+// 		return listData.value.volunteerInfo.certificationPicture.split(',')
+// 	}
+// 	return []
+// })
+
+const dictSortMap = computed(() => {
+  let mapObj = {}
+  dataList.value.forEach((item) => {
+    mapObj[item.dictValue] = item.dictLabel
+  })
+  return mapObj
+})
+
+//获取用户订单列表状态
+async function getData() {
+  try {
+    const res = await systemDictdaTalist().catch((err) => {
+      console.error('接口请求失败:', err)
+      throw err // 重新抛出以进入 catch 块
+    })
+    dataList.value = res.rows
+  } catch (e) {
+    console.error('获取数据异常:', e) // 确保这里打印错误
+  }
+}
+
+const handlButClick = (item) => {
+  uni.navigateTo({
+    url: `/pages_classify/pages/orderItem/userComment?mainOrderId=${
+      mainOrderId.value
+    }&secondOrderId=${item.secondOrderId}&data=${encodeURIComponent(
+      JSON.stringify(listData.value)
+    )}`,
+  })
+}
+
+// 获取传递的参数
+onLoad(async (options) => {
+  mainOrderId.value = options.mainOrderId
+  const res = await orderInfomainOrderId(mainOrderId.value)
+  console.log('API Response:', res)
+  listData.value = res.data
+  console.log('listData:', listData.value)
+})
+
+const hadlClickError = {
+  width: '150rpx',
+  height: '50rpx',
+  marginTop: '70rpx',
+}
+onMounted(() => {
+  getData()
+})
 </script>
 
 <style scoped>
-	.address-container {
-		padding: 20rpx;
-		border: 1rpx solid #eee;
-		border-radius: 10rpx;
-	}
-
-	.address-header {
-		display: flex;
-		align-items: center;
-		margin-bottom: 10rpx;
-	}
-
-	.contact-info {
-		flex: 1;
-		/* 占据剩余空间 */
-		font-size: 28rpx;
-		margin-left: 25rpx;
-	}
-
-	.arrow-icon {
-		margin-left: auto;
-		/* 将图标推到最右侧 */
-	}
-
-	.address-detail {
-		font-size: 26rpx;
-		color: #666;
-	}
-
-	.card-container {
-		display: flex;
-		position: relative;
-		padding: 20rpx;
-		align-items: flex-start;
-		background-color: #fff;
-		border-radius: 12rpx;
-	}
-
-	/* 左侧图片 */
-	.card-image {
-		width: 240rpx;
-		height: 340rpx;
-		border-radius: 12rpx;
-		margin-right: 30rpx;
-		flex-shrink: 0;
-	}
-
-	/* 中间信息区域 */
-	.card-info {
-		flex: 1;
-		padding-right: 100rpx;
-	}
-
-	/* 中间信息区域 */
-	.card-info {
-		flex: 1;
-		padding-right: 100rpx;
-	}
-
-	.Telephone {
-		white-space: nowrap;
-		margin-bottom: 24rpx;
-		font-size: 28rpx;
-		line-height: 1.6;
-		color: #333;
-	}
-
-	.info-item {
-		margin-bottom: 24rpx;
-		font-size: 28rpx;
-		line-height: 1.6;
-		color: #333;
-	}
-
-	/* 右上角评分 */
-	.card-rating {
-		position: absolute;
-		top: 20rpx;
-		right: 20rpx;
-		background-color: #f8f8f8;
-		padding: 6rpx 16rpx;
-		border-radius: 20rpx;
-		font-size: 24rpx;
-		color: #ff9900;
-		font-weight: bold;
-	}
-
-	/* 上课时间 */
-	.Wrap-top {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		padding: 24rpx 20rpx 0rpx 24rpx;
-	}
-
-	.list-item {
-		display: flex;
-		padding: 24rpx;
-		align-items: flex-start;
-		gap: 24rpx;
-		position: relative;
-	}
-
-	.item-image {
-		width: 160rpx;
-		height: 180rpx;
-		border-radius: 16rpx;
-		object-fit: cover;
-	}
-
-	.item-info {
-		flex: 1;
-		display: flex;
-		flex-direction: column;
-		gap: 14rpx;
-	}
-
-	.info-line {
-		font-size: 28rpx;
-		color: #333;
-		line-height: 1.6;
-	}
-
-	.right-corner-container {
-		display: flex;
-		flex-direction: column;
-		align-items: flex-end;
-		position: absolute;
-		right: 24rpx;
-		top: 24rpx;
-		gap: 10rpx;
-	}
-</style>
+.address-container {
+  padding: 20rpx;
+  border: 1rpx solid #eee;
+  border-radius: 10rpx;
+}
+
+.address-header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 10rpx;
+}
+
+.contact-info {
+  flex: 1;
+  /* 占据剩余空间 */
+  font-size: 28rpx;
+  margin-left: 25rpx;
+}
+
+.arrow-icon {
+  margin-left: auto;
+  /* 将图标推到最右侧 */
+}
+
+.address-detail {
+  font-size: 26rpx;
+  color: #666;
+}
+
+.card-container {
+  display: flex;
+  position: relative;
+  padding: 20rpx;
+  align-items: flex-start;
+  background-color: #fff;
+  border-radius: 12rpx;
+}
+
+/* 左侧图片 */
+.card-image {
+  width: 240rpx;
+  height: 340rpx;
+  border-radius: 12rpx;
+  margin-right: 30rpx;
+  flex-shrink: 0;
+}
+
+/* 中间信息区域 */
+.card-info {
+  flex: 1;
+  padding-right: 100rpx;
+}
+
+/* 中间信息区域 */
+.card-info {
+  flex: 1;
+  padding-right: 100rpx;
+}
+
+.Telephone {
+  white-space: nowrap;
+  margin-bottom: 24rpx;
+  font-size: 28rpx;
+  line-height: 1.6;
+  color: #333;
+}
+
+.info-item {
+  margin-bottom: 24rpx;
+  font-size: 28rpx;
+  line-height: 1.6;
+  color: #333;
+}
+
+/* 右上角评分 */
+.card-rating {
+  position: absolute;
+  top: 20rpx;
+  right: 20rpx;
+  background-color: #f8f8f8;
+  padding: 6rpx 16rpx;
+  border-radius: 20rpx;
+  font-size: 24rpx;
+  color: #ff9900;
+  font-weight: bold;
+}
+
+/* 上课时间 */
+.Wrap-top {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 24rpx 20rpx 0rpx 24rpx;
+}
+
+.list-item {
+  display: flex;
+  padding: 24rpx;
+  align-items: flex-start;
+  gap: 24rpx;
+  position: relative;
+}
+
+.item-image {
+  width: 160rpx;
+  height: 180rpx;
+  border-radius: 16rpx;
+  object-fit: cover;
+}
+
+.item-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 14rpx;
+}
+
+.info-line {
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.6;
+}
+
+.right-corner-container {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+  position: absolute;
+  right: 24rpx;
+  top: 24rpx;
+  gap: 10rpx;
+}
+</style>

+ 4 - 1
pages_home/pages/Volunteerside/goodsDetails.vue

@@ -114,10 +114,11 @@
           <up-text type="info" text="家庭教育"></up-text>
         </view>
         <view class="Wrap-info">
-          <text style="margin-left: 10rpx">服务次数:</text>
+          <text style="margin-left: 10rpx">上门服务次数:</text>
           <up-number-box
             :modelValue="singleQuantity"
             :min="listData.minQuantity"
+			:max="minQuantityMax"
             @change="valChange"
           ></up-number-box>
         </view>
@@ -368,6 +369,7 @@ const addressFlag = ref(false)
 const paymentMethod = ref(null) // Add payment method ref with default value 1 (wallet)
 const addressInfo = ref(null)
 const value = ref(1) // 将在onLoad中更新为listData.minQuantity
+const minQuantityMax = ref(99999) // 步进器最大值控制变量
 
 // Radio 单选框数据
 const radiolist1 = reactive([
@@ -514,6 +516,7 @@ const valChange = (obj) => {
   console.log(filteredSlots, '>>>>>filteredSlots')
 
   if (timestampDifferenceValue < durationMs) {
+	  minQuantityMax.value = obj.value - 1
     // 所选时间差值 小于 服务时间值 结束执行
     uni.showToast({ title: '所选时间的服务时间不充足!', icon: 'none' })
     return false

二进制
static/13779@1x.png


二进制
static/Frame@1x.png


二进制
static/Vector 1@1x.png


二进制
static/Vector 2@1x.png