feat(h5): 材料详情页(三块展示)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-04-27 08:57:07 +08:00
parent 5ff8874139
commit 050a1840ec
1 changed files with 133 additions and 2 deletions

View File

@ -1,2 +1,133 @@
<script setup>defineOptions({ name: 'MaterialDetail' })</script>
<template><div class="p-4">MaterialDetail 占位</div></template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import NavBar from '@/components/NavBar.vue'
import Chip from '@/components/Chip.vue'
import StarLevel from '@/components/StarLevel.vue'
import Skeleton from '@/components/Skeleton.vue'
import { fetchMaterialDetail } from '@/api/material'
defineOptions({ name: 'MaterialDetail' })
const props = defineProps({ id: [String, Number] })
const data = ref(null)
const loading = ref(true)
onMounted(async () => {
try { data.value = await fetchMaterialDetail(props.id) }
finally { loading.value = false }
})
const importanceTone = (lv) => lv === '核心' ? 'danger' : lv === '优先' ? 'info' : 'neutral'
const d = (v) => (v == null || v === '') ? '—' : v
const costLabel = (v) => v == null ? '—' : `${v > 0 ? '+' : ''}${Number(v)}%`
const location = computed(() => {
const x = data.value
if (!x) return ''
return [x.factory_province_name, x.factory_city_name].filter(Boolean).join(' · ')
})
</script>
<template>
<div class="min-h-screen pb-8">
<NavBar :title="data?.name || '材料详情'" />
<template v-if="loading">
<div class="p-4 space-y-3">
<Skeleton class="h-40" />
<Skeleton class="h-60" />
<Skeleton class="h-40" />
</div>
</template>
<template v-else-if="data">
<img v-if="data.brochure" :src="data.brochure" class="w-full aspect-video object-cover bg-surface-warm" />
<section class="mx-4 mt-4 p-4 bg-white rounded-card shadow-card">
<h2 class="text-sm font-semibold text-neutral-500 mb-3">材料信息</h2>
<div class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-sm">
<span class="text-muted">材料名称</span><span>{{ d(data.name) }}</span>
<span class="text-muted">材料大类</span><span>{{ d(data.major_category_display) }}</span>
<span class="text-muted">细分种类</span><span>{{ d(data.material_category) }}</span>
<span class="text-muted">材料子类</span><span>{{ d(data.material_subcategory) }}</span>
<span class="text-muted">阶段</span><span>{{ d(data.stage_display) }}</span>
<span class="text-muted">重要等级</span>
<span>
<Chip v-if="data.importance_level" :tone="importanceTone(data.importance_level)">{{ data.importance_level }}</Chip>
<span v-else></span>
</span>
<span class="text-muted">规格型号</span><span>{{ d(data.spec) }}</span>
<span class="text-muted">符合标准</span><span>{{ d(data.standard) }}</span>
<span class="text-muted">应用场景</span>
<span class="flex flex-wrap gap-1">
<Chip v-for="a in (data.application_scene_display || [])" :key="a" tone="brand">{{ a }}</Chip>
<span v-if="!(data.application_scene_display||[]).length"></span>
</span>
<span class="text-muted">替代类型</span><span>{{ d(data.replace_type_display) }}</span>
<span class="text-muted">连接方式</span><span>{{ d(data.connection_method) }}</span>
<span class="text-muted">施工工艺</span><span>{{ d(data.construction_method) }}</span>
<span class="text-muted">竞争优势</span>
<span class="flex flex-wrap gap-1">
<Chip v-for="a in (data.advantage_display || [])" :key="a" tone="brand">{{ a }}</Chip>
<span v-if="!(data.advantage_display||[]).length"></span>
</span>
<span class="text-muted">成本对比</span><span class="tnum" :class="data.cost_compare < 0 ? 'text-brand font-medium' : ''">{{ costLabel(data.cost_compare) }}</span>
</div>
<div v-if="data.application_desc" class="mt-4 pt-3 border-t border-line">
<div class="text-muted text-xs mb-1">应用说明</div>
<div class="text-sm whitespace-pre-wrap">{{ data.application_desc }}</div>
</div>
<div v-if="data.advantage_desc" class="mt-3">
<div class="text-muted text-xs mb-1">优势说明</div>
<div class="text-sm whitespace-pre-wrap">{{ data.advantage_desc }}</div>
</div>
<div v-if="data.cost_desc" class="mt-3">
<div class="text-muted text-xs mb-1">成本说明</div>
<div class="text-sm whitespace-pre-wrap">{{ data.cost_desc }}</div>
</div>
<div v-if="data.limit_condition" class="mt-3">
<div class="text-muted text-xs mb-1">限制条件</div>
<div class="text-sm whitespace-pre-wrap">{{ data.limit_condition }}</div>
</div>
<div class="mt-4 pt-3 border-t border-line grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-sm items-center">
<span class="text-muted">质量等级</span><StarLevel :value="data.quality_level || 0" />
<span class="text-muted">耐久等级</span><StarLevel :value="data.durability_level || 0" />
<span class="text-muted">环保等级</span><StarLevel :value="data.eco_level || 0" />
<span class="text-muted">低碳等级</span><StarLevel :value="data.carbon_level || 0" />
<span class="text-muted font-medium">综合评分</span><StarLevel :value="data.score_level || 0" />
</div>
</section>
<section class="mx-4 mt-4 p-4 bg-white rounded-card shadow-card">
<h2 class="text-sm font-semibold text-neutral-500 mb-3">品牌与供应商</h2>
<div class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-sm">
<span class="text-muted">品牌</span><span>{{ d(data.brand_name) }}</span>
<span class="text-muted">供应商简称</span><span>{{ d(data.factory_short_name) }}</span>
<span class="text-muted">供应商全称</span><span>{{ d(data.factory_name) }}</span>
<span class="text-muted">合作模式</span><span>{{ d(data.factory_cooperation_mode_display) }}</span>
<span class="text-muted">-</span><span>{{ d(location) }}</span>
<span class="text-muted">对接人</span><span>{{ d(data.contact_person) }}</span>
<span class="text-muted">联系方式</span>
<span>
<a v-if="data.contact_phone" :href="`tel:${data.contact_phone}`" class="text-brand">{{ data.contact_phone }}</a>
<span v-else></span>
</span>
</div>
</section>
<section class="mx-4 mt-4 p-4 bg-white rounded-card shadow-card">
<h2 class="text-sm font-semibold text-neutral-500 mb-3">案例信息</h2>
<div class="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-sm">
<span class="text-muted">落地项目</span><span>{{ d(data.landing_project) }}</span>
<span class="text-muted">经办人</span><span>{{ d(data.handler) }}</span>
<span class="text-muted">备注</span><span>{{ d(data.remark) }}</span>
</div>
<div v-if="data.cases" class="mt-3">
<div class="text-muted text-xs mb-1">案例</div>
<div class="text-sm whitespace-pre-wrap">{{ data.cases }}</div>
</div>
</section>
</template>
</div>
</template>