344 lines
13 KiB
Vue
344 lines
13 KiB
Vue
<template>
|
|
<div>
|
|
<!-- 页面标题 -->
|
|
<HeroBanner
|
|
:title="$t('cases.hero.title')"
|
|
:subtitle="$t('cases.hero.subtitle')"
|
|
/>
|
|
|
|
<!-- 案例筛选 -->
|
|
<section class="py-10">
|
|
<div class="container">
|
|
<div class="bg-white p-6 rounded-lg shadow-md">
|
|
<div class="flex flex-wrap items-center justify-between gap-4">
|
|
<div class="flex flex-wrap items-center gap-4">
|
|
<span class="text-gray-700 font-medium">{{ $t('cases.filter.byIndustry') }}</span>
|
|
<div class="flex flex-wrap gap-2">
|
|
<button
|
|
v-for="industry in industries"
|
|
:key="industry"
|
|
@click="toggleIndustryFilter(industry)"
|
|
:class="[
|
|
'px-4 py-2 rounded-full text-sm',
|
|
selectedIndustries.includes(industry)
|
|
? 'bg-secondary text-white'
|
|
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
|
]"
|
|
>
|
|
{{ industry }}
|
|
</button>
|
|
<button
|
|
@click="clearIndustryFilters"
|
|
class="px-4 py-2 rounded-full text-sm bg-gray-100 text-gray-700 hover:bg-gray-200"
|
|
>
|
|
{{ $t('cases.filter.all') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<span class="text-gray-700 font-medium mr-4">{{ $t('cases.filter.sortBy') }}</span>
|
|
<select
|
|
v-model="sortBy"
|
|
class="px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-secondary focus:border-transparent"
|
|
>
|
|
<option value="latest">{{ $t('cases.filter.latest') }}</option>
|
|
<option value="default">{{ $t('cases.filter.default') }}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- 案例列表 -->
|
|
<section class="py-12">
|
|
<div class="container">
|
|
<div v-if="filteredCases.length === 0" class="text-center py-16">
|
|
<i class="fas fa-search text-4xl text-gray-300 mb-4"></i>
|
|
<p class="text-xl text-gray-500">{{ $t('cases.noResults.text') }}</p>
|
|
<button @click="clearIndustryFilters" class="mt-4 text-secondary hover:text-secondary/90">
|
|
{{ $t('cases.noResults.clearFilters') }}
|
|
</button>
|
|
</div>
|
|
|
|
<div v-else class="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
<div
|
|
v-for="(case_item, index) in filteredCases"
|
|
:key="index"
|
|
class="bg-white rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1"
|
|
>
|
|
<div class="h-48 bg-gray-200 relative overflow-hidden">
|
|
<div class="absolute top-0 right-0 bg-secondary text-white px-3 py-1 text-sm">
|
|
{{ $t(case_item.industry) }}
|
|
</div>
|
|
</div>
|
|
<div class="p-6">
|
|
<h3 class="text-2xl font-semibold mb-4">{{ $t(case_item.titleKey) }}</h3>
|
|
<p class="text-gray-600 mb-6">{{ $t(case_item.summaryKey) }}</p>
|
|
<div class="flex justify-between items-center">
|
|
<button @click="openCaseDetail(case_item)" class="text-secondary hover:text-secondary/90 flex items-center">
|
|
{{ $t('cases.caseDetail.readDetails') }}
|
|
<i class="fas fa-arrow-right ml-2"></i>
|
|
</button>
|
|
<span class="text-sm text-gray-500">{{ case_item.date }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- 案例详情弹窗 -->
|
|
<div v-if="selectedCase" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
|
<div class="bg-white rounded-lg max-w-4xl w-full max-h-[90vh] overflow-y-auto">
|
|
<div class="p-6 border-b">
|
|
<div class="flex justify-between items-center">
|
|
<h3 class="text-2xl font-bold">{{ $t(selectedCase.titleKey) }}</h3>
|
|
<button @click="selectedCase = null" class="text-gray-500 hover:text-gray-700">
|
|
<i class="fas fa-times text-xl"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="flex flex-wrap gap-2 mb-6">
|
|
<span class="px-3 py-1 bg-secondary/10 text-secondary text-sm rounded-full">
|
|
{{ $t(selectedCase.industry) }}
|
|
</span>
|
|
<span class="px-3 py-1 bg-gray-100 text-gray-700 text-sm rounded-full">
|
|
{{ selectedCase.date }}
|
|
</span>
|
|
</div>
|
|
|
|
<h4 class="text-xl font-semibold mb-4">{{ $t('cases.caseDetail.background') }}</h4>
|
|
<p class="text-gray-600 mb-6">{{ $t(selectedCase.backgroundKey) }}</p>
|
|
|
|
<h4 class="text-xl font-semibold mb-4">{{ $t('cases.caseDetail.challenges') }}</h4>
|
|
<ul class="list-disc pl-5 mb-6 space-y-2">
|
|
<li v-for="(challenge, idx) in selectedCase.challenges" :key="idx" class="text-gray-600">
|
|
{{ $t(challenge) }}
|
|
</li>
|
|
</ul>
|
|
|
|
<h4 class="text-xl font-semibold mb-4">{{ $t('cases.caseDetail.solution') }}</h4>
|
|
<p class="text-gray-600 mb-4">{{ $t(selectedCase.solutionKey) }}</p>
|
|
|
|
<h4 class="text-xl font-semibold mb-4">{{ $t('cases.caseDetail.results') }}</h4>
|
|
<ul class="list-disc pl-5 mb-6 space-y-2">
|
|
<li v-for="(result, idx) in selectedCase.results" :key="idx" class="text-gray-600">
|
|
{{ $t(result) }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="p-6 border-t bg-gray-50">
|
|
<div class="flex justify-end">
|
|
<button @click="selectedCase = null" class="px-4 py-2 bg-gray-200 text-gray-700 rounded hover:bg-gray-300">
|
|
{{ $t('cases.caseDetail.close') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 联系我们 -->
|
|
<section class="py-16 bg-primary text-white">
|
|
<div class="container text-center">
|
|
<h2 class="text-4xl font-bold mb-6">{{ $t('cases.contact.title') }}</h2>
|
|
<p class="text-xl mb-8 max-w-2xl mx-auto leading-relaxed">{{ $t('cases.contact.subtitle') }}</p>
|
|
<NuxtLink to="/contact" class="inline-flex items-center bg-white text-black px-8 py-4 rounded-lg hover:bg-gray-100 transition-colors duration-300 text-lg font-semibold">
|
|
{{ $t('cases.contact.button') }}
|
|
<i class="fas fa-arrow-right ml-2"></i>
|
|
</NuxtLink>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
const { t } = useI18n();
|
|
|
|
// 所有行业标签
|
|
const industries = [
|
|
t('cases.industries.finance'),
|
|
t('cases.industries.ecommerce'),
|
|
t('cases.industries.manufacturing'),
|
|
t('cases.industries.healthcare'),
|
|
t('cases.industries.education'),
|
|
t('cases.industries.government'),
|
|
t('cases.industries.media'),
|
|
t('cases.industries.logistics')
|
|
];
|
|
|
|
// 筛选和排序状态
|
|
const selectedIndustries = ref<string[]>([]);
|
|
const sortBy = ref('default');
|
|
const selectedCase = ref<any>(null);
|
|
|
|
// 客户案例数据
|
|
const caseStudies = [
|
|
{
|
|
titleKey: 'cases.caseStudies.ecommerce.title',
|
|
industry: 'cases.caseStudies.ecommerce.industry',
|
|
date: '2023-05-15',
|
|
summaryKey: 'cases.caseStudies.ecommerce.summary',
|
|
backgroundKey: 'cases.caseStudies.ecommerce.background',
|
|
challenges: [
|
|
'cases.caseStudies.ecommerce.challenges[0]',
|
|
'cases.caseStudies.ecommerce.challenges[1]',
|
|
'cases.caseStudies.ecommerce.challenges[2]',
|
|
'cases.caseStudies.ecommerce.challenges[3]'
|
|
],
|
|
solutionKey: 'cases.caseStudies.ecommerce.solution',
|
|
results: [
|
|
'cases.caseStudies.ecommerce.results[0]',
|
|
'cases.caseStudies.ecommerce.results[1]',
|
|
'cases.caseStudies.ecommerce.results[2]',
|
|
'cases.caseStudies.ecommerce.results[3]',
|
|
'cases.caseStudies.ecommerce.results[4]'
|
|
]
|
|
},
|
|
{
|
|
titleKey: 'cases.caseStudies.finance.title',
|
|
industry: 'cases.caseStudies.finance.industry',
|
|
date: '2023-03-20',
|
|
summaryKey: 'cases.caseStudies.finance.summary',
|
|
backgroundKey: 'cases.caseStudies.finance.background',
|
|
challenges: [
|
|
'cases.caseStudies.finance.challenges[0]',
|
|
'cases.caseStudies.finance.challenges[1]',
|
|
'cases.caseStudies.finance.challenges[2]',
|
|
'cases.caseStudies.finance.challenges[3]'
|
|
],
|
|
solutionKey: 'cases.caseStudies.finance.solution',
|
|
results: [
|
|
'cases.caseStudies.finance.results[0]',
|
|
'cases.caseStudies.finance.results[1]',
|
|
'cases.caseStudies.finance.results[2]',
|
|
'cases.caseStudies.finance.results[3]',
|
|
'cases.caseStudies.finance.results[4]'
|
|
]
|
|
},
|
|
{
|
|
titleKey: 'cases.caseStudies.healthcare.title',
|
|
industry: 'cases.caseStudies.healthcare.industry',
|
|
date: '2022-11-10',
|
|
summaryKey: 'cases.caseStudies.healthcare.summary',
|
|
backgroundKey: 'cases.caseStudies.healthcare.background',
|
|
challenges: [
|
|
'cases.caseStudies.healthcare.challenges[0]',
|
|
'cases.caseStudies.healthcare.challenges[1]',
|
|
'cases.caseStudies.healthcare.challenges[2]',
|
|
'cases.caseStudies.healthcare.challenges[3]'
|
|
],
|
|
solutionKey: 'cases.caseStudies.healthcare.solution',
|
|
results: [
|
|
'cases.caseStudies.healthcare.results[0]',
|
|
'cases.caseStudies.healthcare.results[1]',
|
|
'cases.caseStudies.healthcare.results[2]',
|
|
'cases.caseStudies.healthcare.results[3]',
|
|
'cases.caseStudies.healthcare.results[4]'
|
|
]
|
|
},
|
|
{
|
|
titleKey: 'cases.caseStudies.manufacturing.title',
|
|
industry: 'cases.caseStudies.manufacturing.industry',
|
|
date: '2022-09-05',
|
|
summaryKey: 'cases.caseStudies.manufacturing.summary',
|
|
backgroundKey: 'cases.caseStudies.manufacturing.background',
|
|
challenges: [
|
|
'cases.caseStudies.manufacturing.challenges[0]',
|
|
'cases.caseStudies.manufacturing.challenges[1]',
|
|
'cases.caseStudies.manufacturing.challenges[2]',
|
|
'cases.caseStudies.manufacturing.challenges[3]'
|
|
],
|
|
solutionKey: 'cases.caseStudies.manufacturing.solution',
|
|
results: [
|
|
'cases.caseStudies.manufacturing.results[0]',
|
|
'cases.caseStudies.manufacturing.results[1]',
|
|
'cases.caseStudies.manufacturing.results[2]',
|
|
'cases.caseStudies.manufacturing.results[3]',
|
|
'cases.caseStudies.manufacturing.results[4]'
|
|
]
|
|
},
|
|
{
|
|
titleKey: 'cases.caseStudies.logistics.title',
|
|
industry: 'cases.caseStudies.logistics.industry',
|
|
date: '2022-07-15',
|
|
summaryKey: 'cases.caseStudies.logistics.summary',
|
|
backgroundKey: 'cases.caseStudies.logistics.background',
|
|
challenges: [
|
|
'cases.caseStudies.logistics.challenges[0]',
|
|
'cases.caseStudies.logistics.challenges[1]',
|
|
'cases.caseStudies.logistics.challenges[2]',
|
|
'cases.caseStudies.logistics.challenges[3]'
|
|
],
|
|
solutionKey: 'cases.caseStudies.logistics.solution',
|
|
results: [
|
|
'cases.caseStudies.logistics.results[0]',
|
|
'cases.caseStudies.logistics.results[1]',
|
|
'cases.caseStudies.logistics.results[2]',
|
|
'cases.caseStudies.logistics.results[3]',
|
|
'cases.caseStudies.logistics.results[4]'
|
|
]
|
|
},
|
|
{
|
|
titleKey: 'cases.caseStudies.education.title',
|
|
industry: 'cases.caseStudies.education.industry',
|
|
date: '2022-05-08',
|
|
summaryKey: 'cases.caseStudies.education.summary',
|
|
backgroundKey: 'cases.caseStudies.education.background',
|
|
challenges: [
|
|
'cases.caseStudies.education.challenges[0]',
|
|
'cases.caseStudies.education.challenges[1]',
|
|
'cases.caseStudies.education.challenges[2]',
|
|
'cases.caseStudies.education.challenges[3]'
|
|
],
|
|
solutionKey: 'cases.caseStudies.education.solution',
|
|
results: [
|
|
'cases.caseStudies.education.results[0]',
|
|
'cases.caseStudies.education.results[1]',
|
|
'cases.caseStudies.education.results[2]',
|
|
'cases.caseStudies.education.results[3]',
|
|
'cases.caseStudies.education.results[4]'
|
|
]
|
|
}
|
|
];
|
|
|
|
// 行业筛选方法
|
|
const toggleIndustryFilter = (industry: string) => {
|
|
if (selectedIndustries.value.includes(industry)) {
|
|
selectedIndustries.value = selectedIndustries.value.filter(item => item !== industry);
|
|
} else {
|
|
selectedIndustries.value.push(industry);
|
|
}
|
|
};
|
|
|
|
// 清除筛选条件
|
|
const clearIndustryFilters = () => {
|
|
selectedIndustries.value = [];
|
|
};
|
|
|
|
// 打开案例详情
|
|
const openCaseDetail = (case_item: any) => {
|
|
selectedCase.value = case_item;
|
|
};
|
|
|
|
// 根据筛选条件和排序获取案例列表
|
|
const filteredCases = computed(() => {
|
|
let result = [...caseStudies];
|
|
|
|
// 应用行业筛选
|
|
if (selectedIndustries.value.length > 0) {
|
|
result = result.filter(item => selectedIndustries.value.includes(item.industry));
|
|
}
|
|
|
|
// 应用排序
|
|
if (sortBy.value === 'latest') {
|
|
result.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
}
|
|
|
|
return result;
|
|
});
|
|
</script> |