Files
jinshen-website/app/pages/productions/[...slug].vue
R2m1liA 92c5a3baab style: 调整代码格式
- 根据ESLint文件规范格式化app文件夹中的代码
2025-09-15 17:02:04 +08:00

277 lines
6.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="page-container">
<div v-if="production">
<!-- 面包屑导航 -->
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item class="text-md opacity-50">
<NuxtLink :to="$localePath('/')">{{
$t("navigation.home")
}}</NuxtLink>
</el-breadcrumb-item>
<el-breadcrumb-item class="text-md opacity-50">
<NuxtLink :to="$localePath('/productions')">{{
$t("navigation.productions")
}}</NuxtLink>
</el-breadcrumb-item>
<el-breadcrumb-item class="text-md opactiy-50">{{
production.title
}}</el-breadcrumb-item>
</el-breadcrumb>
<!-- 产品详情内容 -->
<div class="production-header">
<div class="production-image">
<el-image
v-if="production.production_images.length <= 1"
:src="useStrapiMedia(production?.cover?.url || '')"
:alt="production.title"
fit="contain"
/>
<el-carousel
v-else
class="production-carousel"
height="500px"
:autoplay="false"
:loop="false"
arrow="always"
>
<el-carousel-item
v-for="(item, index) in production.production_images || []"
:key="index"
>
<div class="production-carousel-item">
<el-image
:src="useStrapiMedia(item.url || '')"
:alt="item.alternativeText || production.title"
fit="contain"
lazy
/>
<p v-if="item.caption" class="production-image-caption">
{{ item.caption }}
</p>
</div>
</el-carousel-item>
</el-carousel>
</div>
<div class="production-info">
<h1>{{ production.title }}</h1>
<p class="summary">{{ production.summary }}</p>
</div>
</div>
<!-- 产品详细描述 -->
<div class="production-content">
<el-tabs v-model="activeName" class="production-tabs" stretch>
<el-tab-pane label="产品详情" name="details">
<markdown-renderer :content="production.production_details || ''" />
</el-tab-pane>
<el-tab-pane label="技术规格" name="specs">
<spec-table :data="production.production_specs" />
</el-tab-pane>
<el-tab-pane label="常见问题" name="faq">
<question-list :questions="production.questions" />
</el-tab-pane>
<el-tab-pane label="相关文档" name="documents">
<document-list
:documents="
production.production_documents.map((item) => item.document) ||
[]
"
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
<!-- 加载状态 -->
<div v-else-if="pending" class="loading">
<el-skeleton style="--el-skeleton-circle-size: 400px">
<template #template>
<el-skeleton-item variant="circle" />
</template>
</el-skeleton>
<el-skeleton :rows="5" animated />
</div>
<!-- 未找到产品 -->
<div v-else class="not-found">
<el-result
icon="warning"
:title="$t('product-not-found')"
:sub-title="$t('product-not-found-desc')"
>
<template #extra>
<el-button type="primary" @click="$router.push('/productions')">
{{ $t("back-to-productions") }}
</el-button>
</template>
</el-result>
</div>
</div>
</template>
<script setup lang="ts">
const route = useRoute();
const { findOne } = useStrapi();
const { getStrapiLocale } = useLocalizations();
const strapiLocale = getStrapiLocale();
const production = ref<Production | null>(null);
const pending = ref(true);
const activeName = ref("details"); // 默认选中概览标签
// 获取路由参数slug 或 id
const documentId = computed(() => route.params.slug as string);
onMounted(async () => {
try {
const response = await findOne<Production>(
"productions",
documentId.value,
{
populate: {
production_specs: {
populate: "*",
},
production_images: {
populate: "*",
},
cover: {
populate: "*",
},
questions: {
populate: "*",
},
production_documents: {
populate: "document",
},
},
locale: strapiLocale,
}
);
if (response.data) {
const item = response.data;
production.value = {
...item,
};
console.log("Fetched production:", production.value);
}
} catch (error) {
console.error("Failed to fetch production:", error);
} finally {
pending.value = false;
}
});
// SEO
useHead({
title: computed(() => production.value?.title || "Product Detail"),
meta: [
{
name: "description",
content: computed(() => production.value?.summary || ""),
},
],
});
</script>
<style scoped>
.page-container {
min-height: 80vh;
max-width: 1200px;
margin: 0 auto;
}
.breadcrumb {
padding: 2rem;
}
.production-header {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 3rem;
}
.production-image .el-image {
position: relative;
width: 100%;
height: 500px;
border-radius: 8px;
}
.production-image-caption {
position: absolute;
bottom: 10px;
/* left: 10%; */
background-color: rgba(0, 0, 0, 0.2);
border-radius: 5px;
padding: 5px 10px;
text-align: center;
color: white;
font-size: 0.8rem;
}
.production-carousel :deep(.el-carousel__button) {
/* 指示器按钮样式 */
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #475669;
transition: all 0.3s ease;
}
.production-info h1 {
margin-top: 2rem;
margin-bottom: 1rem;
font-size: 2rem;
}
.summary {
color: var(--el-color-info);
font-size: 1rem;
line-height: 1.6;
margin-bottom: 2rem;
}
.production-tabs ::v-deep(.el-tabs__nav) {
min-width: 30%;
float: right;
}
.production-tabs ::v-deep(.el-tabs__content) {
padding: 10px;
}
.production-content h2 {
color: var(--el-text-color-primary);
margin: 0;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
margin-top: 1rem;
}
.not-found {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.production-header {
grid-template-columns: 1fr;
gap: 2rem;
}
.production-info h1 {
font-size: 2rem;
}
}
</style>