Bladeren bron

优化溯源码展示逻辑

yawuga 1 maand geleden
bovenliggende
commit
76334634c3
1 gewijzigde bestanden met toevoegingen van 217 en 80 verwijderingen
  1. 217 80
      pages/trace/detail.vue

+ 217 - 80
pages/trace/detail.vue

@@ -10,71 +10,79 @@
 			<!-- 顶部留白:兼容 iOS 刘海 -->
 			<view class="safeTop" />
 
-			<!-- 轻品牌页头:极克制、无导航栏,让独立扫码页有品牌收口 -->
-			<view class="brandPageHeader">
-				<view class="brandPageHeaderInner">
-					<text class="brandPageHeaderName">佳友厚苑</text>
-					<view class="brandPageHeaderDot" />
-					<text class="brandPageHeaderLabel">官方溯源 品质可验</text>
-				</view>
+		<!-- 品牌页头:任何状态下均显示 -->
+		<view class="brandPageHeader">
+			<view class="brandPageHeaderInner">
+				<text class="brandPageHeaderName">佳友厚苑</text>
+				<view class="brandPageHeaderDot" />
+				<text class="brandPageHeaderLabel">官方溯源 品质可验</text>
 			</view>
+		</view>
+
+		<!-- ===== 加载中状态 ===== -->
+		<view v-if="!traceLoaded" class="loadingState">
+			<text class="loadingText">溯源信息加载中…</text>
+		</view>
 
+		<!-- ===== 数据加载完成后:正常态 / 异常态 ===== -->
+		<view v-else class="mainContent">
+			<!-- 正常态:已发布 -->
+			<view v-if="canShowTraceContent">
+			<!-- Hero 首屏:商品图 + 品牌氛围 + 商品信息面板 -->
 			<view class="hero">
-			<!-- 完整首屏大卡:品牌信任区 + 商品信息面板 -->
-			<view class="heroCard">
-				<!-- Hero 视觉区:商品图 + 品牌氛围 -->
-				<view class="heroBg">
-					<!-- 优先商品图,没有则用农场图 -->
-					<image
-						class="heroImage"
-						:src="traceDetail.product?.image || traceDetail.farm?.image"
-						mode="aspectFill"
-					/>
-					<!-- 底部大字号水印,营造品牌氛围 -->
-					<view class="heroBrandAnchor">
-						<text class="heroBrandAnchorText">JIAYOU</text>
+				<view class="heroCard">
+					<!-- Hero 视觉区:商品图 + 品牌氛围 -->
+					<view class="heroBg">
+						<image
+							class="heroImage"
+							:src="traceDetail.product?.image || traceDetail.farm?.image"
+							mode="aspectFill"
+						/>
+						<!-- 底部大字号水印,营造品牌氛围 -->
+						<view class="heroBrandAnchor">
+							<text class="heroBrandAnchorText">JIAYOU</text>
+						</view>
+						<!-- 光感层:多层次渐变 + 景深 + 底部暗化 -->
+						<view class="heroMask" />
 					</view>
-					<!-- 光感层:多层次渐变 + 景深 + 底部暗化 -->
-					<view class="heroMask" />
-				</view>
 
-				<!-- 商品信息面板:嵌入 Hero 底部,与 Hero 自然过渡 -->
-				<view v-if="traceDetail.product?.name" class="heroInfoPanel">
-					<view class="infoPanelInner">
-						<view class="sectionHeader">
-							<view class="sectionHeaderLeft">
-								<text class="sectionEn">Product</text>
-								<text class="sectionTitle">商品信息</text>
-							</view>
-							<view v-if="traceDetail.batch?.statusBadge" class="trustBadge" :class="traceDetail.batch.statusBadge.type">
-								<!-- 认证徽章 SVG:双圆环 + 对勾,图标主视觉,文字辅助 -->
-								<svg class="trustBadgeIcon" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
-									<circle cx="10" cy="10" r="9" stroke="rgba(27,71,42,0.38)" stroke-width="0.9" />
-									<circle cx="10" cy="10" r="5.5" stroke="rgba(27,71,42,0.22)" stroke-width="0.7" />
-									<path d="M6.6 10.4L9.1 12.9L13.8 8" stroke="rgba(27,71,42,0.8)" stroke-width="1.15" stroke-linecap="round" stroke-linejoin="round" />
-								</svg>
-								<text class="trustBadgeText">{{ traceDetail.batch.statusBadge.text }}</text>
+					<!-- 商品信息面板:嵌入 Hero 底部,与 Hero 自然过渡 -->
+					<view class="heroInfoPanel">
+						<view class="infoPanelInner">
+							<view class="sectionHeader">
+								<view class="sectionHeaderLeft">
+									<text class="sectionEn">Product</text>
+									<text class="sectionTitle">商品信息</text>
+								</view>
+								<view v-if="traceDetail.batch?.statusBadge" class="trustBadge" :class="traceDetail.batch.statusBadge.type">
+									<!-- 认证徽章 SVG:双圆环 + 对勾,图标主视觉,文字辅助 -->
+									<svg class="trustBadgeIcon" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+										<circle cx="10" cy="10" r="9" stroke="rgba(27,71,42,0.38)" stroke-width="0.9" />
+										<circle cx="10" cy="10" r="5.5" stroke="rgba(27,71,42,0.22)" stroke-width="0.7" />
+										<path d="M6.6 10.4L9.1 12.9L13.8 8" stroke="rgba(27,71,42,0.8)" stroke-width="1.15" stroke-linecap="round" stroke-linejoin="round" />
+									</svg>
+									<text class="trustBadgeText">{{ traceDetail.batch.statusBadge.text }}</text>
+								</view>
 							</view>
-						</view>
 
-						<view class="infoPanelBody">
-							<text class="infoPanelName">{{ traceDetail.product.name }}</text>
+							<view class="infoPanelBody">
+								<text class="infoPanelName">{{ traceDetail.product.name }}</text>
 
-							<view v-if="traceDetail.product.spec" class="infoPanelSpec">
-								<view class="specDot" />
-								<text class="specText">{{ traceDetail.product.spec }}</text>
-							</view>
+								<view v-if="traceDetail.product.spec" class="infoPanelSpec">
+									<view class="specDot" />
+									<text class="specText">{{ traceDetail.product.spec }}</text>
+								</view>
 
-							<view v-if="traceDetail.product?.intro" class="infoPanelIntro">
-								<text>{{ traceDetail.product.intro }}</text>
+								<view v-if="traceDetail.product?.intro" class="infoPanelIntro">
+									<text>{{ traceDetail.product.intro }}</text>
+								</view>
 							</view>
 						</view>
 					</view>
 				</view>
 			</view>
-		</view>
 
-		<scroll-view class="content" scroll-y>
+			<scroll-view class="content" scroll-y>
 			<!-- 溯源信息卡:融合溯源结论 + 批次核心信息 -->
 			<view v-if="traceDetail.batch?.exists && traceDetail.traceConclusionCard" class="card cardLevel1 cardConclusion">
 				<view class="sectionHeader">
@@ -458,24 +466,6 @@
 				</view>
 			</view>
 
-
-			<!-- 批次不存在/已下线的说明 -->
-			<view v-else-if="traceDetail.batch?.statusBadge" class="card soft cardLevel1 cardBatchState">
-				<view class="sectionHeader">
-					<view class="sectionHeaderLeft">
-						<text class="sectionEn">Batch</text>
-						<text class="sectionTitle">当前批次状态</text>
-					</view>
-					<view class="statusBadge" :class="traceDetail.batch.statusBadge.type">
-						{{ traceDetail.batch.statusBadge.text }}
-					</view>
-				</view>
-				<view class="emptyText">{{ traceDetail.batch?.emptyMessage || '该批次暂不可查询' }}</view>
-				<view class="btnRow">
-					<button class="primaryBtn" @click="goBackToPurchase">返回购买渠道</button>
-				</view>
-			</view>
-
 			<!-- 检测报告:横向卡片列表 -->
 			<view v-if="traceDetail.batch?.exists" class="card cardLevel2 cardCredential">
 				<view class="sectionHeader">
@@ -604,6 +594,21 @@
 				<view class="traceFooterBrand">佳友厚苑 · 安心之选</view>
 			</view>
 		</scroll-view>
+		</view>
+
+		<!-- ===== 异常态:待发布 / 已下线 / 无效批次 ===== -->
+		<view v-if="!canShowTraceContent">
+			<view class="abnormalStateCard">
+				<view class="sectionHeader">
+					<view class="sectionHeaderLeft">
+						<text class="sectionEn">Status</text>
+						<text class="sectionTitle">暂无相关溯源码信息</text>
+					</view>
+				</view>
+				<view class="emptyText">{{ traceDetail.batch?.emptyMessage || '未找到对应溯源码信息,请确认二维码是否正确。' }}</view>
+			</view>
+		</view>
+		</view>
 	</view>
 </template>
 
@@ -623,6 +628,8 @@ import Jessibuca from '@/components/common/jessibuca.vue'
 // 例如:/pages/trace/detail?state=reportPending
 // 加载状态
 const loading = ref(false)
+// 数据首次加载完成标记(用于区分"加载中"与"加载后异常态")
+const traceLoaded = ref(false)
 // 数据存储
 const traceInfo = ref(null)
 const routeOptions = ref({})
@@ -711,12 +718,16 @@ const MOCK_TRACE_DETAILS = {
 			intro: ''
 		},
 			batch: {
+			status: '',
+			statusText: '',
 			exists: false,
 			statusBadge: { text: '', type: '' },
 			no: '',
 			plantStartTime: '2026-03-01',
 			harvestTime: '',
-			packTime: ''
+			packTime: '',
+			emptyTitle: '暂无相关溯源码信息',
+			emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
 		},
 		report: {
 			status: '',
@@ -835,12 +846,16 @@ reportPending: {
 			intro: ''
 		},
 		batch: {
+			status: '',
+			statusText: '',
 			exists: false,
 			statusBadge: { text: '', type: '' },
 			no: '',
 			plantStartTime: '',
 			harvestTime: '',
-			packTime: ''
+			packTime: '',
+			emptyTitle: '暂无相关溯源码信息',
+			emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
 		},
 		report: {
 			status: '',
@@ -878,12 +893,16 @@ reportPending: {
 			intro: ''
 		},
 		batch: {
+			status: '',
+			statusText: '',
 			exists: false,
 			statusBadge: { text: '', type: '' },
 			no: '',
 			plantStartTime: '',
 			harvestTime: '',
-			packTime: ''
+			packTime: '',
+			emptyTitle: '暂无相关溯源码信息',
+			emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
 		},
 		report: {
 			status: '',
@@ -923,10 +942,16 @@ reportPending: {
 			intro: ''
 		},
 		batch: {
+			status: '',
+			statusText: '',
 			exists: false,
 			statusBadge: { text: '', type: '' },
+			no: '',
 			plantStartTime: '',
-			emptyMessage: ''
+			harvestTime: '',
+			packTime: '',
+			emptyTitle: '暂无相关溯源码信息',
+			emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
 		},
 		report: null,
 		certificate: null,
@@ -952,10 +977,16 @@ reportPending: {
 			intro: ''
 		},
 		batch: {
+			status: '',
+			statusText: '',
 			exists: false,
 			statusBadge: { text: '', type: '' },
+			no: '',
 			plantStartTime: '',
-			emptyMessage: ''
+			harvestTime: '',
+			packTime: '',
+			emptyTitle: '暂无相关溯源码信息',
+			emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
 		},
 		report: null,
 		certificate: null,
@@ -1158,8 +1189,10 @@ onLoad((opts) => {
 			})
 	}
 const loadData = async (batchId) => {
+  // 重置首次加载标记,确保请求开始时不会误判为"已加载"
+  traceLoaded.value = false
   loading.value = true
-  
+
   try {
     // 调用接口
     const res = await getTraceDetail(batchId)
@@ -1171,6 +1204,8 @@ const loadData = async (batchId) => {
   } finally {
     // 无论成功失败都关闭 loading
     loading.value = false
+    // 标记数据已完成首次加载
+    traceLoaded.value = true
   }
 }
 // 视频播放错误处理
@@ -1672,6 +1707,68 @@ const loadData = async (batchId) => {
 		console.warn('未获取到视频流地址')
 		return ''
 	})
+	// ===== 批次状态判断 =====
+	// 爱智农后台状态:1=待发布, 2=已发布, 3=已下线
+	const BATCH_STATUS_PENDING = '1'
+	const BATCH_STATUS_PUBLISHED = '2'
+	const BATCH_STATUS_OFFLINED = '3'
+
+	// 获取当前批次状态值
+	const batchStatus = computed(() => {
+		const data = traceInfo.value
+		if (!data) return ''
+		const s = String(data.status)
+		if ([BATCH_STATUS_PENDING, BATCH_STATUS_PUBLISHED, BATCH_STATUS_OFFLINED].includes(s)) {
+			return s
+		}
+		return ''
+	})
+
+	// 是否可展示完整溯源内容(仅已发布状态)
+	const canShowTraceContent = computed(() => batchStatus.value === BATCH_STATUS_PUBLISHED)
+
+	// 各状态布尔值
+	const isBatchPending = computed(() => batchStatus.value === BATCH_STATUS_PENDING)
+	const isBatchPublished = computed(() => batchStatus.value === BATCH_STATUS_PUBLISHED)
+	const isBatchOfflined = computed(() => batchStatus.value === BATCH_STATUS_OFFLINED)
+	const isBatchUnavailable = computed(() => !canShowTraceContent.value)
+
+	// 各状态文案映射
+	const batchStatusTextMap = {
+		[BATCH_STATUS_PENDING]: '待发布',
+		[BATCH_STATUS_PUBLISHED]: '已发布',
+		[BATCH_STATUS_OFFLINED]: '已下线'
+	}
+
+	// 各状态 badge 映射
+	const batchStatusBadgeMap = {
+		[BATCH_STATUS_PENDING]: { text: '待发布', type: 'wait' },
+		[BATCH_STATUS_PUBLISHED]: { text: '检验合格', type: 'ok' },
+		[BATCH_STATUS_OFFLINED]: { text: '已下线', type: 'muted' },
+		_invalid: { text: '未找到', type: 'muted' }
+	}
+
+	// 各状态异常态文案
+	const batchEmptyMessageMap = {
+		[BATCH_STATUS_PENDING]: '当前批次暂未开放查询,相关溯源内容暂不对外展示。',
+		[BATCH_STATUS_OFFLINED]: '当前批次已下线,相关溯源内容暂不对外展示。',
+		_invalid: '未找到对应溯源码信息,请确认二维码是否正确。'
+	}
+
+	// 获取当前状态对应的 badge
+	const getCurrentStatusBadge = () => {
+		const s = batchStatus.value
+		if (!s) return batchStatusBadgeMap._invalid
+		return batchStatusBadgeMap[s] || batchStatusBadgeMap._invalid
+	}
+
+	// 获取当前状态对应的异常态文案
+	const getCurrentEmptyMessage = () => {
+		const s = batchStatus.value
+		if (!s) return batchEmptyMessageMap._invalid
+		return batchEmptyMessageMap[s] || batchEmptyMessageMap._invalid
+	}
+
 const traceDetail = computed(() => {
 	// 如果没有真实数据,返回 mock 数据
 	if (!traceInfo.value) {
@@ -1712,16 +1809,16 @@ const traceDetail = computed(() => {
 			intro: data.farmIntro || ''
 		},
 		batch: {
-			exists: data.status === '2', // status 为 '2' 表示批次正常,已上线
-			statusBadge: data.status === '2' 
-				? { text: '检验合格', type: 'ok' }
-				: { text: '批次不存在', type: 'muted' },
+			status: batchStatus.value,
+			statusText: batchStatusTextMap[batchStatus.value] || '未找到',
+			exists: canShowTraceContent.value,
+			statusBadge: getCurrentStatusBadge(),
 			no: data.batchNo || '',
-			// 临时前端演示:始终显示固定种植时间
 			plantStartTime: '2026-03-01',
 			harvestTime: data.produceDate || '',
 			packTime: data.packageDate || '',
-			emptyMessage: data.status !== '2' ? '未找到对应溯源批次信息。请确认二维码是否为佳友厚苑正品批次。' : ''
+			emptyTitle: '暂无相关溯源码信息',
+			emptyMessage: getCurrentEmptyMessage()
 		},
 		report: {
 			status: data.reports && data.reports.length > 0 ? 'uploaded' : 'pending',
@@ -2531,6 +2628,46 @@ function previewDoc(kind, index) {
 	padding: 20rpx 0 40rpx;
 }
 
+/* 加载中状态:轻量提示,不闪异常态 */
+.loadingState {
+	margin: 40rpx 24rpx;
+	padding: 60rpx 32rpx;
+	border-radius: 36rpx;
+	background: rgba(252, 250, 244, 0.76);
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+
+.loadingText {
+	font-size: 24rpx;
+	font-weight: 400;
+	color: rgba(84, 106, 93, 0.65);
+	letter-spacing: 0.02em;
+}
+
+/* 异常态空状态卡:与页面整体风格一致的轻量提示 */
+.abnormalStateCard {
+	margin: 40rpx 24rpx;
+	padding: 40rpx 32rpx;
+	border-radius: 36rpx;
+	background: rgba(252, 250, 244, 0.76);
+	box-shadow:
+		0 16rpx 40rpx rgba(38, 41, 32, 0.07),
+		0 1rpx 0 rgba(255, 255, 255, 0.5) inset;
+}
+
+.abnormalStateCard .sectionHeader {
+	margin-bottom: 20rpx;
+}
+
+.abnormalStateCard .emptyText {
+	font-size: 24rpx;
+	line-height: 1.8;
+	color: rgba(54, 66, 57, 0.7);
+	margin-top: 16rpx;
+}
+
 /* 基础卡片:半透明玻璃质感 */
 .card {
 	margin: 0 24rpx 22rpx;