Huanyi 15 часов назад
Родитель
Сommit
3e6c2067bd
3 измененных файлов с 102 добавлено и 28 удалено
  1. 2 2
      manifest.json
  2. 85 22
      pages/index/index.vue
  3. 15 4
      pages/service/detail/index.vue

+ 2 - 2
manifest.json

@@ -2,8 +2,8 @@
     "name" : "好萌友",
     "appid" : "__UNI__F19BBAD",
     "description" : "宠物服务商家端",
-    "versionName" : "1.2.1",
-    "versionCode" : 45,
+    "versionName" : "1.2.3",
+    "versionCode" : 47,
     "transformPx" : false,
     "app-plus" : {
         "privacy" : {

+ 85 - 22
pages/index/index.vue

@@ -17,31 +17,31 @@
 		<view class="main-nav-section">
 			<view class="nav-container">
 				<!-- 左侧大按钮: 宠物接送 -->
-				<view class="nav-card large-card">
+				<view class="nav-card large-card" @click="goToServiceDetail(transportService)">
 					<image src="/static/images/pickup-dropoff.png" class="card-bg" mode="aspectFill"></image>
 					<view class="card-info">
-						<text class="card-title">宠物接送</text>
-						<text class="card-desc">支持单操/往返服务</text>
+						<text class="card-title">{{ transportService?.name || '宠物接送' }}</text>
+						<text class="card-desc">{{ transportService?.remark || '支持单程/往返服务' }}</text>
 					</view>
 				</view>
 
 				<!-- 右侧分栏 -->
 				<view class="right-stack">
 					<!-- 右上: 上门喂遛 -->
-					<view class="nav-card small-card">
+					<view class="nav-card small-card" @click="goToServiceDetail(feedingService)">
 						<image src="/static/images/feed-walk.png" class="card-bg" mode="aspectFill"></image>
 						<view class="card-info">
-							<text class="card-title">上门喂遛</text>
-							<text class="card-desc">每次上门基础费用</text>
+							<text class="card-title">{{ feedingService?.name || '上门喂遛' }}</text>
+							<text class="card-desc">{{ feedingService?.remark || '每次上门基础费用' }}</text>
 						</view>
 					</view>
-					
+
 					<!-- 右下: 上门洗护 -->
-					<view class="nav-card small-card">
+					<view class="nav-card small-card" @click="goToServiceDetail(washingService)">
 						<image src="/static/images/laundry-clean.png" class="card-bg" mode="aspectFill"></image>
 						<view class="card-info">
-							<text class="card-title">上门洗护</text>
-							<text class="card-desc">每次上门基础费用</text>
+							<text class="card-title">{{ washingService?.name || '上门洗护' }}</text>
+							<text class="card-desc">{{ washingService?.remark || '每次上门基础费用' }}</text>
 						</view>
 					</view>
 				</view>
@@ -82,7 +82,8 @@
 						<text class="text-p">欢迎您选择由重庆盈锐文化传播有限公司运营的“好萌友”!我们非常重视您的个人信息和隐私保护。</text>
 						<text class="text-p">在您使用“好萌友”产品及相关服务前,请仔细阅读并同意</text>
 						<text class="text-link-active" @click="goToPrivacy">《好萌友隐私政策》</text>
-						<text class="text-p">,以了解我们如何收集、使用、共享及保护您的个人信息,包括收集您的设备制造商、设备型号、设备标识符(OAID/VAID/AAID等)等相关信息。</text>
+						<text
+							class="text-p">,以了解我们如何收集、使用、共享及保护您的个人信息,包括收集您的设备制造商、设备型号、设备标识符(OAID/VAID/AAID等)等相关信息。</text>
 						<text class="text-p">为了给您提供宠物接送、上门服务等核心功能,我们会请求定位、相机、相册及剪切板等权限。如果您同意,请点击“同意并继续”开始使用我们的服务。</text>
 					</view>
 				</scroll-view>
@@ -96,12 +97,44 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, computed, onMounted } from 'vue'
 import customTabbar from '@/components/custom-tabbar/index.vue'
+import { listAll } from '@/api/service/list'
 
 const showPrivacyModal = ref(false)
+const transportService = ref(null)
+const feedingService = ref(null)
+const washingService = ref(null)
+
+const SERVICE_IDS = {
+	transport: '2026540079472181250',
+	feeding: '2026541504596017154',
+	washing: '2026542038396735489'
+}
+
+const fetchServices = async () => {
+	try {
+		const res = await listAll()
+		const list = Array.isArray(res) ? res : (res?.data || res?.rows || [])
+		transportService.value = list.find(item => String(item.id) === SERVICE_IDS.transport) || null
+		feedingService.value = list.find(item => String(item.id) === SERVICE_IDS.feeding) || null
+		washingService.value = list.find(item => String(item.id) === SERVICE_IDS.washing) || null
+	} catch (err) {
+		console.error('获取首页服务数据失败:', err)
+	}
+}
+
+const goToServiceDetail = (service) => {
+	if (!service || !service.id) {
+		uni.showToast({ title: '服务暂不可用', icon: 'none' })
+		return
+	}
+	uni.setStorageSync('currentService', service)
+	uni.navigateTo({ url: `/pages/service/detail/index?serviceId=${service.id}&buyFlag=false` })
+}
 
 onMounted(() => {
+	fetchServices()
 	const agreed = uni.getStorageSync('privacy_agreed')
 	if (!agreed) {
 		showPrivacyModal.value = true
@@ -129,7 +162,7 @@ const handleAccept = () => {
 		title: '已同意隐私政策',
 		icon: 'success'
 	})
-	
+
 	// 同意协议后,若没有 Token 则在一秒后重定向跳转至登录界面
 	const token = uni.getStorageSync('token')
 	if (!token) {
@@ -184,6 +217,7 @@ const handleRefuse = () => {
 	position: relative;
 	width: 100%;
 }
+
 .header-bg {
 	width: 100%;
 	display: block;
@@ -193,6 +227,7 @@ const handleRefuse = () => {
 .notice-section {
 	padding: 20rpx 32rpx;
 }
+
 .notice-bar {
 	display: flex;
 	align-items: center;
@@ -201,11 +236,13 @@ const handleRefuse = () => {
 	padding: 16rpx 24rpx;
 	gap: 16rpx;
 }
+
 .notice-icon {
 	width: 40rpx;
 	height: 40rpx;
 	flex-shrink: 0;
 }
+
 .notice-text {
 	font-size: 24rpx;
 	color: #e6a23c;
@@ -216,9 +253,11 @@ const handleRefuse = () => {
 .main-nav-section {
 	padding: 10rpx 32rpx;
 }
+
 .nav-container {
 	display: flex;
-	height: 280rpx; /* 将之前较高的 380rpx 调低,使整体按钮高度变矮 */
+	height: 280rpx;
+	/* 将之前较高的 380rpx 调低,使整体按钮高度变矮 */
 	gap: 20rpx;
 }
 
@@ -247,12 +286,14 @@ const handleRefuse = () => {
 .large-card {
 	flex: 1;
 }
+
 .right-stack {
 	flex: 1;
 	display: flex;
 	flex-direction: column;
 	gap: 20rpx;
 }
+
 .small-card {
 	flex: 1;
 }
@@ -264,10 +305,19 @@ const handleRefuse = () => {
 	margin-bottom: 4rpx;
 	display: block;
 }
+
 /* 根据图片色系微调文字颜色以匹配 UI 稿 */
-.large-card .card-title { color: #d35400; }
-.right-stack .small-card:first-child .card-title { color: #2c5ba7; }
-.right-stack .small-card:last-child .card-title { color: #c0392b; }
+.large-card .card-title {
+	color: #d35400;
+}
+
+.right-stack .small-card:first-child .card-title {
+	color: #2c5ba7;
+}
+
+.right-stack .small-card:last-child .card-title {
+	color: #c0392b;
+}
 
 .card-desc {
 	font-size: 20rpx;
@@ -277,12 +327,15 @@ const handleRefuse = () => {
 
 /* ====== 中间横幅 @Author: Antigravity ====== */
 .middle-section {
-	padding: 10rpx 0; /* 缩小自身上下间距 */
+	padding: 10rpx 0;
+	/* 缩小自身上下间距 */
 	display: flex;
 	justify-content: center;
 }
+
 .middle-image {
-	width: 65%; /* 进一步缩小宽度到 65% */
+	width: 65%;
+	/* 进一步缩小宽度到 65% */
 	border-radius: 20rpx;
 	display: block;
 }
@@ -292,10 +345,13 @@ const handleRefuse = () => {
 	display: flex;
 	justify-content: center;
 	align-items: center;
-	padding: 10rpx 32rpx 20rpx; /* 控制绿色横幅的 padding 以对齐上方 */
+	padding: 10rpx 32rpx 20rpx;
+	/* 控制绿色横幅的 padding 以对齐上方 */
 }
+
 .symbol-img {
-	width: 100%; /* 中间的标志(绿色大横幅)完美等宽于三个按钮 */
+	width: 100%;
+	/* 中间的标志(绿色大横幅)完美等宽于三个按钮 */
 	border-radius: 20rpx;
 	display: block;
 }
@@ -306,6 +362,7 @@ const handleRefuse = () => {
 	display: flex;
 	justify-content: center;
 }
+
 .hand-wrapper {
 	position: relative;
 	width: 100%;
@@ -313,10 +370,12 @@ const handleRefuse = () => {
 	justify-content: center;
 	align-items: center;
 }
+
 .hand-img {
 	width: 100%;
 	display: block;
 }
+
 .hand-text-content {
 	position: absolute;
 	top: 50%;
@@ -327,11 +386,13 @@ const handleRefuse = () => {
 	align-items: center;
 	gap: 12rpx;
 }
+
 .hand-title {
 	font-size: 28rpx;
 	color: #333;
 	font-weight: bold;
 }
+
 .hand-subtitle {
 	font-size: 24rpx;
 	color: #999;
@@ -370,6 +431,7 @@ const handleRefuse = () => {
 		opacity: 0;
 		transform: scale(0.9);
 	}
+
 	to {
 		opacity: 1;
 		transform: scale(1);
@@ -430,6 +492,7 @@ const handleRefuse = () => {
 	border-radius: 44rpx;
 	border: none;
 	font-weight: 600;
+
 	&::after {
 		border: none;
 	}
@@ -446,9 +509,9 @@ const handleRefuse = () => {
 	border: none;
 	font-weight: 700;
 	box-shadow: 0 8rpx 20rpx rgba(255, 149, 0, 0.2);
+
 	&::after {
 		border: none;
 	}
 }
-
 </style>

+ 15 - 4
pages/service/detail/index.vue

@@ -56,7 +56,7 @@
 		</view>
 
 		<!-- 底部操作栏 -->
-		<view class="footer-bar safe-bottom">
+		<view class="footer-bar safe-bottom" v-if="canBuy">
 			<button class="buy-btn" @click="goToOrderApply">立即预约</button>
 		</view>
 	</view>
@@ -69,10 +69,14 @@ import { onLoad } from '@dcloudio/uni-app'
 
 const activeTab = ref('intro')
 const serviceInfo = ref(null)
+const canBuy = ref(true)
 
 const defaultHeroImg = 'https://images.unsplash.com/photo-1544568100-847a948585b9?q=80&w=600&auto=format&fit=crop'
 
 onLoad((options) => {
+	if (options.buyFlag === 'false') {
+		canBuy.value = false
+	}
 	const storedService = uni.getStorageSync('currentService')
 	if (storedService) {
 		serviceInfo.value = storedService
@@ -164,7 +168,7 @@ const goToOrderApply = () => {
 .service-detail-page {
 	background-color: #f5f5f5;
 	min-height: 100vh;
-	padding-bottom: 160rpx;
+	padding-bottom: 40rpx;
 }
 
 .hero-section {
@@ -396,6 +400,7 @@ const goToOrderApply = () => {
 	height: auto !important;
 	display: block;
 }
+
 .rich-container table,
 .rich-container pre,
 .rich-container code {
@@ -403,11 +408,17 @@ const goToOrderApply = () => {
 	overflow-x: auto;
 	word-break: break-word;
 }
+
 .rich-container p {
 	margin-bottom: 12px;
 }
-.rich-container h1, .rich-container h2, .rich-container h3,
-.rich-container h4, .rich-container h5, .rich-container h6 {
+
+.rich-container h1,
+.rich-container h2,
+.rich-container h3,
+.rich-container h4,
+.rich-container h5,
+.rich-container h6 {
 	margin-top: 16px;
 	margin-bottom: 8px;
 	line-height: 1.4;