254 lines
5.8 KiB
Vue
254 lines
5.8 KiB
Vue
<template>
|
|
<view class="verify-page">
|
|
|
|
<image class="bg-image" src="/static/square/squearbj.png" mode="aspectFill"></image>
|
|
|
|
<view class="nav-bar">
|
|
<view class="nav-back" @tap="goBack">←</view>
|
|
<text class="nav-title">周边验真</text>
|
|
</view>
|
|
|
|
<view v-if="loading" class="loading">
|
|
<text>加载中…</text>
|
|
</view>
|
|
|
|
<view v-else-if="error" class="error">
|
|
<text>{{ error }}</text>
|
|
<button @tap="loadData">重试</button>
|
|
</view>
|
|
|
|
<view v-else-if="data" class="content">
|
|
<view class="header">
|
|
<image class="thumb" :src="data.image || '/static/nft/collection.png'" mode="aspectFit" />
|
|
<view class="badge"><text>✓ 已通过验真</text></view>
|
|
</view>
|
|
|
|
<view class="info-card">
|
|
<view v-for="row in infoRows" :key="row.label" class="info-row">
|
|
<text class="info-label">{{ row.label }}</text>
|
|
<text class="info-value" :class="{ 'info-hash': row.hash }">{{ row.value || '—' }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="tip-row">
|
|
<text class="tip-icon">💡</text>
|
|
<text class="tip-text">加入前请对比实物,确认一致后再添加</text>
|
|
</view>
|
|
|
|
<button class="mint-btn" :loading="submitting" :disabled="submitting" @tap="handleAddToCollection">
|
|
加入我的藏品
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from 'vue'
|
|
import { onLoad } from '@dcloudio/uni-app'
|
|
import { getPeripheralByCodeApi, mintToMyCollectionApi } from '@/utils/api.js'
|
|
|
|
const code = ref('')
|
|
const data = ref(null)
|
|
const loading = ref(true)
|
|
const error = ref('')
|
|
const submitting = ref(false)
|
|
|
|
onLoad((options) => {
|
|
// ★ 优先用 code 查(mint 前也能查)
|
|
if (options.code) {
|
|
code.value = String(options.code)
|
|
loadData()
|
|
return
|
|
}
|
|
// 兼容老路径:asset_id
|
|
if (options.assetId) {
|
|
code.value = String(options.assetId)
|
|
loadData()
|
|
return
|
|
}
|
|
error.value = '二维码数据无效'
|
|
loading.value = false
|
|
})
|
|
|
|
const infoRows = computed(() => {
|
|
if (!data.value) return []
|
|
const d = data.value
|
|
console.log('infoRows data:', d)
|
|
return [
|
|
{ label: '周边编号', value: d.code || '—' },
|
|
{ label: '品牌', value: d.brand },
|
|
{ label: '公司', value: d.company },
|
|
{ label: '链上哈希', value: d.hash, hash: true },
|
|
{ label: '验证次数', value: `${d.verify_count} 次` },
|
|
{ label: '验证人', value: d.verifier },
|
|
{ label: '首次验证', value: formatDate(d.verified_at) },
|
|
// 周边素材类型(后端 omitempty,空时 d.material_type 为 undefined)
|
|
// { label: '素材类型', value: (d.material_type && d.material_type.trim()) || 'new' }
|
|
]
|
|
})
|
|
|
|
function goBack() {
|
|
uni.navigateBack({ delta: 1, fail: () => uni.switchTab({ url: '/pages/square/square' }) })
|
|
}
|
|
|
|
async function loadData() {
|
|
loading.value = true
|
|
error.value = ''
|
|
try {
|
|
// ★ 用 code 查 peripheral_info(周边未铸时也能查)
|
|
const res = await getPeripheralByCodeApi(code.value)
|
|
if (!res || !res.data) throw new Error(res?.message || '此物品暂无验真信息')
|
|
data.value = res.data
|
|
} catch (e) {
|
|
error.value = e.message || '加载失败'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function handleAddToCollection() {
|
|
if (submitting.value) return
|
|
submitting.value = true
|
|
try {
|
|
const res = await mintToMyCollectionApi(code.value)
|
|
// console.log('mintToMyCollectionApi res:', res)
|
|
uni.showToast({ title: '已加入我的藏品', icon: 'success' })
|
|
setTimeout(() => {
|
|
uni.navigateTo({
|
|
url: `/pages/asset-detail/asset-detail?asset_id=${res.data?.asset_id}`
|
|
})
|
|
}, 800)
|
|
} catch (e) {
|
|
uni.showToast({ title: e.message || '添加失败', icon: 'none' })
|
|
} finally {
|
|
submitting.value = false
|
|
}
|
|
}
|
|
|
|
function formatDate(ts) {
|
|
if (!ts) return ''
|
|
const d = new Date(ts * 1000)
|
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.verify-page {
|
|
/* background: #0a0a0a; */
|
|
min-height: 100vh;
|
|
padding: 24rpx;
|
|
|
|
}
|
|
|
|
/* 背景图片 */
|
|
.bg-image {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 120%;
|
|
z-index: 0;
|
|
}
|
|
|
|
.nav-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 88rpx;
|
|
padding: 0 24rpx;
|
|
color: #fff;
|
|
position: relative;
|
|
top: 96rpx;
|
|
z-index: 1;
|
|
}
|
|
|
|
.nav-back {
|
|
font-size: 40rpx;
|
|
padding-right: 24rpx;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.nav-title {
|
|
flex: 1;
|
|
text-align: center;
|
|
font-size: 32rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.loading,
|
|
.error {
|
|
color: #aaa;
|
|
text-align: center;
|
|
padding: 80rpx 0;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.content {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.header {
|
|
/* display: flex;
|
|
align-items: center;
|
|
justify-content: center; */
|
|
margin-top: 64rpx;
|
|
}
|
|
|
|
.info-card {
|
|
/* background: #1a1a1a; */
|
|
border-radius: 16rpx;
|
|
padding: 24rpx;
|
|
margin-top: 24rpx;
|
|
}
|
|
|
|
.info-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 16rpx 0;
|
|
/* border-bottom: 1rpx solid #2a2a2a; */
|
|
}
|
|
|
|
.info-row:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.info-label {
|
|
color: rgba(255, 255, 255, 0.7);
|
|
font-size: 26rpx;
|
|
}
|
|
|
|
.info-value {
|
|
color: #fff;
|
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.7);
|
|
font-size: 28rpx;
|
|
width: 60%;
|
|
word-break: break-all;
|
|
text-align: left;
|
|
}
|
|
|
|
.info-value.info-hash {
|
|
font-family: monospace;
|
|
font-size: 22rpx;
|
|
color: #3ddc84;
|
|
}
|
|
|
|
.tip-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8rpx;
|
|
padding: 24rpx 8rpx;
|
|
color: #888;
|
|
font-size: 26rpx;
|
|
}
|
|
|
|
.mint-btn {
|
|
background: linear-gradient(135deg, rgba(255, 222, 8, 0.49) 0%, rgba(252, 100, 102, 1) 61.1%, rgba(244, 88, 104, 1) 100%);
|
|
box-shadow: inset 0 0.03125rem 0 rgba(255, 255, 255, 0.45), 2px 2px 4px 0px #f2151578;
|
|
color: #fff;
|
|
border-radius: 100rpx;
|
|
margin-top: 32rpx;
|
|
font-weight: 600;
|
|
}
|
|
</style> |