|
@@ -10,71 +10,79 @@
|
|
|
<!-- 顶部留白:兼容 iOS 刘海 -->
|
|
<!-- 顶部留白:兼容 iOS 刘海 -->
|
|
|
<view class="safeTop" />
|
|
<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>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ===== 加载中状态 ===== -->
|
|
|
|
|
+ <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="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>
|
|
|
- <!-- 光感层:多层次渐变 + 景深 + 底部暗化 -->
|
|
|
|
|
- <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>
|
|
|
|
|
|
|
|
|
|
- <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>
|
|
|
</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 v-if="traceDetail.batch?.exists && traceDetail.traceConclusionCard" class="card cardLevel1 cardConclusion">
|
|
|
<view class="sectionHeader">
|
|
<view class="sectionHeader">
|
|
@@ -458,24 +466,6 @@
|
|
|
</view>
|
|
</view>
|
|
|
</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 v-if="traceDetail.batch?.exists" class="card cardLevel2 cardCredential">
|
|
|
<view class="sectionHeader">
|
|
<view class="sectionHeader">
|
|
@@ -604,6 +594,21 @@
|
|
|
<view class="traceFooterBrand">佳友厚苑 · 安心之选</view>
|
|
<view class="traceFooterBrand">佳友厚苑 · 安心之选</view>
|
|
|
</view>
|
|
</view>
|
|
|
</scroll-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>
|
|
</view>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -623,6 +628,8 @@ import Jessibuca from '@/components/common/jessibuca.vue'
|
|
|
// 例如:/pages/trace/detail?state=reportPending
|
|
// 例如:/pages/trace/detail?state=reportPending
|
|
|
// 加载状态
|
|
// 加载状态
|
|
|
const loading = ref(false)
|
|
const loading = ref(false)
|
|
|
|
|
+// 数据首次加载完成标记(用于区分"加载中"与"加载后异常态")
|
|
|
|
|
+const traceLoaded = ref(false)
|
|
|
// 数据存储
|
|
// 数据存储
|
|
|
const traceInfo = ref(null)
|
|
const traceInfo = ref(null)
|
|
|
const routeOptions = ref({})
|
|
const routeOptions = ref({})
|
|
@@ -711,12 +718,16 @@ const MOCK_TRACE_DETAILS = {
|
|
|
intro: ''
|
|
intro: ''
|
|
|
},
|
|
},
|
|
|
batch: {
|
|
batch: {
|
|
|
|
|
+ status: '',
|
|
|
|
|
+ statusText: '',
|
|
|
exists: false,
|
|
exists: false,
|
|
|
statusBadge: { text: '', type: '' },
|
|
statusBadge: { text: '', type: '' },
|
|
|
no: '',
|
|
no: '',
|
|
|
plantStartTime: '2026-03-01',
|
|
plantStartTime: '2026-03-01',
|
|
|
harvestTime: '',
|
|
harvestTime: '',
|
|
|
- packTime: ''
|
|
|
|
|
|
|
+ packTime: '',
|
|
|
|
|
+ emptyTitle: '暂无相关溯源码信息',
|
|
|
|
|
+ emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
|
|
|
},
|
|
},
|
|
|
report: {
|
|
report: {
|
|
|
status: '',
|
|
status: '',
|
|
@@ -835,12 +846,16 @@ reportPending: {
|
|
|
intro: ''
|
|
intro: ''
|
|
|
},
|
|
},
|
|
|
batch: {
|
|
batch: {
|
|
|
|
|
+ status: '',
|
|
|
|
|
+ statusText: '',
|
|
|
exists: false,
|
|
exists: false,
|
|
|
statusBadge: { text: '', type: '' },
|
|
statusBadge: { text: '', type: '' },
|
|
|
no: '',
|
|
no: '',
|
|
|
plantStartTime: '',
|
|
plantStartTime: '',
|
|
|
harvestTime: '',
|
|
harvestTime: '',
|
|
|
- packTime: ''
|
|
|
|
|
|
|
+ packTime: '',
|
|
|
|
|
+ emptyTitle: '暂无相关溯源码信息',
|
|
|
|
|
+ emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
|
|
|
},
|
|
},
|
|
|
report: {
|
|
report: {
|
|
|
status: '',
|
|
status: '',
|
|
@@ -878,12 +893,16 @@ reportPending: {
|
|
|
intro: ''
|
|
intro: ''
|
|
|
},
|
|
},
|
|
|
batch: {
|
|
batch: {
|
|
|
|
|
+ status: '',
|
|
|
|
|
+ statusText: '',
|
|
|
exists: false,
|
|
exists: false,
|
|
|
statusBadge: { text: '', type: '' },
|
|
statusBadge: { text: '', type: '' },
|
|
|
no: '',
|
|
no: '',
|
|
|
plantStartTime: '',
|
|
plantStartTime: '',
|
|
|
harvestTime: '',
|
|
harvestTime: '',
|
|
|
- packTime: ''
|
|
|
|
|
|
|
+ packTime: '',
|
|
|
|
|
+ emptyTitle: '暂无相关溯源码信息',
|
|
|
|
|
+ emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
|
|
|
},
|
|
},
|
|
|
report: {
|
|
report: {
|
|
|
status: '',
|
|
status: '',
|
|
@@ -923,10 +942,16 @@ reportPending: {
|
|
|
intro: ''
|
|
intro: ''
|
|
|
},
|
|
},
|
|
|
batch: {
|
|
batch: {
|
|
|
|
|
+ status: '',
|
|
|
|
|
+ statusText: '',
|
|
|
exists: false,
|
|
exists: false,
|
|
|
statusBadge: { text: '', type: '' },
|
|
statusBadge: { text: '', type: '' },
|
|
|
|
|
+ no: '',
|
|
|
plantStartTime: '',
|
|
plantStartTime: '',
|
|
|
- emptyMessage: ''
|
|
|
|
|
|
|
+ harvestTime: '',
|
|
|
|
|
+ packTime: '',
|
|
|
|
|
+ emptyTitle: '暂无相关溯源码信息',
|
|
|
|
|
+ emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
|
|
|
},
|
|
},
|
|
|
report: null,
|
|
report: null,
|
|
|
certificate: null,
|
|
certificate: null,
|
|
@@ -952,10 +977,16 @@ reportPending: {
|
|
|
intro: ''
|
|
intro: ''
|
|
|
},
|
|
},
|
|
|
batch: {
|
|
batch: {
|
|
|
|
|
+ status: '',
|
|
|
|
|
+ statusText: '',
|
|
|
exists: false,
|
|
exists: false,
|
|
|
statusBadge: { text: '', type: '' },
|
|
statusBadge: { text: '', type: '' },
|
|
|
|
|
+ no: '',
|
|
|
plantStartTime: '',
|
|
plantStartTime: '',
|
|
|
- emptyMessage: ''
|
|
|
|
|
|
|
+ harvestTime: '',
|
|
|
|
|
+ packTime: '',
|
|
|
|
|
+ emptyTitle: '暂无相关溯源码信息',
|
|
|
|
|
+ emptyMessage: '未找到对应溯源码信息,请确认二维码是否正确。'
|
|
|
},
|
|
},
|
|
|
report: null,
|
|
report: null,
|
|
|
certificate: null,
|
|
certificate: null,
|
|
@@ -1158,8 +1189,10 @@ onLoad((opts) => {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
const loadData = async (batchId) => {
|
|
const loadData = async (batchId) => {
|
|
|
|
|
+ // 重置首次加载标记,确保请求开始时不会误判为"已加载"
|
|
|
|
|
+ traceLoaded.value = false
|
|
|
loading.value = true
|
|
loading.value = true
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
// 调用接口
|
|
// 调用接口
|
|
|
const res = await getTraceDetail(batchId)
|
|
const res = await getTraceDetail(batchId)
|
|
@@ -1171,6 +1204,8 @@ const loadData = async (batchId) => {
|
|
|
} finally {
|
|
} finally {
|
|
|
// 无论成功失败都关闭 loading
|
|
// 无论成功失败都关闭 loading
|
|
|
loading.value = false
|
|
loading.value = false
|
|
|
|
|
+ // 标记数据已完成首次加载
|
|
|
|
|
+ traceLoaded.value = true
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// 视频播放错误处理
|
|
// 视频播放错误处理
|
|
@@ -1672,6 +1707,68 @@ const loadData = async (batchId) => {
|
|
|
console.warn('未获取到视频流地址')
|
|
console.warn('未获取到视频流地址')
|
|
|
return ''
|
|
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(() => {
|
|
const traceDetail = computed(() => {
|
|
|
// 如果没有真实数据,返回 mock 数据
|
|
// 如果没有真实数据,返回 mock 数据
|
|
|
if (!traceInfo.value) {
|
|
if (!traceInfo.value) {
|
|
@@ -1712,16 +1809,16 @@ const traceDetail = computed(() => {
|
|
|
intro: data.farmIntro || ''
|
|
intro: data.farmIntro || ''
|
|
|
},
|
|
},
|
|
|
batch: {
|
|
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 || '',
|
|
no: data.batchNo || '',
|
|
|
- // 临时前端演示:始终显示固定种植时间
|
|
|
|
|
plantStartTime: '2026-03-01',
|
|
plantStartTime: '2026-03-01',
|
|
|
harvestTime: data.produceDate || '',
|
|
harvestTime: data.produceDate || '',
|
|
|
packTime: data.packageDate || '',
|
|
packTime: data.packageDate || '',
|
|
|
- emptyMessage: data.status !== '2' ? '未找到对应溯源批次信息。请确认二维码是否为佳友厚苑正品批次。' : ''
|
|
|
|
|
|
|
+ emptyTitle: '暂无相关溯源码信息',
|
|
|
|
|
+ emptyMessage: getCurrentEmptyMessage()
|
|
|
},
|
|
},
|
|
|
report: {
|
|
report: {
|
|
|
status: data.reports && data.reports.length > 0 ? 'uploaded' : 'pending',
|
|
status: data.reports && data.reports.length > 0 ? 'uploaded' : 'pending',
|
|
@@ -2531,6 +2628,46 @@ function previewDoc(kind, index) {
|
|
|
padding: 20rpx 0 40rpx;
|
|
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 {
|
|
.card {
|
|
|
margin: 0 24rpx 22rpx;
|
|
margin: 0 24rpx 22rpx;
|