Files
cz-web/src/views/home/cpns/HomeCaseShowcase.vue
2026-10-13 15:34:55 +08:00

233 lines
5.0 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.
<script setup lang="ts">
import { computed } from 'vue'
import { ref } from 'vue'
import type { BusinessType } from '@/types/api'
import type { Case } from '@/types/business/cases'
interface Props {
cases: Case[]
}
const props = defineProps<Props>()
const emit = defineEmits<{ categoryChange: [category: BusinessType | 'all'] }>()
const activeCategory = ref<BusinessType | 'all'>('all')
const categories: Array<{ label: string; value: BusinessType | 'all' }> = [
{ label: '全部', value: 'all' },
{ label: '互联网软件', value: 'internet' },
{ label: '硬件电路', value: 'hardware' },
{ label: '物联网全案', value: 'iot' },
{ label: '生产制造', value: 'manufacturing' },
]
function switchCategory(value: BusinessType | 'all'): void {
activeCategory.value = value
emit('categoryChange', value)
}
const visibleCases = computed<Case[]>(() => props.cases.slice(0, 4))
</script>
<template>
<section class="home-cases">
<div class="home-cases__head">
<h3 class="home-cases__title">案例库精选</h3>
<div class="home-cases__tabs">
<button
v-for="cat in categories"
:key="cat.value"
class="home-cases__tab"
:class="{ 'is-active': activeCategory === cat.value }"
@click="switchCategory(cat.value)"
>
{{ cat.label }}
</button>
</div>
<RouterLink to="/cases" class="home-cases__more link">
查看全部 >
</RouterLink>
</div>
<div class="home-cases__grid">
<article
v-for="item in visibleCases"
:key="item.id"
class="home-cases__card"
@click="$router.push(`/cases/${item.id}`)"
>
<div class="home-cases__cover">
<img
v-if="item.cover"
v-lazy="item.cover"
class="home-cases__img"
:alt="item.title"
/>
<div v-else class="home-cases__img home-cases__img--placeholder" />
</div>
<div class="home-cases__body">
<h4 class="home-cases__name">
{{ item.title }}
</h4>
<ul class="home-cases__meta">
<li>客户类型:{{ item.clientType }}</li>
<li>所属行业:{{ item.industry }}</li>
<li>规模:{{ item.scale }}</li>
<li>项目周期:{{ item.duration }}</li>
<li>服务团队:{{ item.teamSize }}人</li>
<li>完成时间:{{ item.finishDate }}</li>
</ul>
<span class="home-cases__view">查看详情&gt;</span>
</div>
</article>
</div>
</section>
</template>
<style lang="less" scoped>
.home-cases {
padding: @spacing-xl;
border: none;
border-radius: @radius-base;
background: @white;
&__head {
.flex(row, flex-start, center);
gap: @spacing-lg;
margin-bottom: @spacing-lg;
}
&__title {
font-size: @font-size-xl;
font-weight: 600;
color: @home-ink;
}
&__tabs {
.flex(row, center);
gap: @spacing-lg;
}
&__tab {
position: relative;
height: auto;
padding: 0;
border: 0;
background: transparent;
color: @home-ink;
font-size: @font-size-md;
font-weight: 500;
transition: color 0.2s;
&.is-active {
background: transparent;
color: @home-tab-active;
&::after {
content: '';
position: absolute;
right: 0;
bottom: -8px;
left: 0;
height: 2px;
background: @primary-color;
}
}
}
&__more {
margin-left: auto;
font-size: @font-size-md;
}
&__grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: @spacing-lg;
}
&__card {
overflow: hidden;
min-width: 0;
min-height: 220px;
box-sizing: border-box;
border: 1px solid @border-color;
border-radius: @radius-base;
background: @white;
box-shadow: none;
cursor: pointer;
transition:
transform 0.2s,
box-shadow 0.2s,
border-color 0.2s;
&:hover {
border-color: @primary-color;
box-shadow: @shadow-base;
transform: translateY(-2px);
.home-cases__view {
color: @primary-color;
}
}
}
&__cover {
position: relative;
height: 88px;
overflow: hidden;
}
&__img {
width: 100%;
height: 100%;
object-fit: cover;
&--placeholder {
background: linear-gradient(135deg, @primary-light, @bg-color);
}
}
&__body {
padding: 0 20px 10px 20px;
}
&__name {
margin: 21px 0 0;
font-size: @font-size-md;
font-weight: 500;
line-height: 22px;
color: @home-body;
.multi-ellipsis(1);
}
&__meta {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 0 @spacing-lg;
margin-top: 20px;
font-size: 13px;
line-height: 20px;
color: @home-body;
li {
.ellipsis();
}
}
&__view {
display: block;
width: fit-content;
margin: 6px 0 0 auto;
padding: 0;
border: 0;
color: @primary-strong;
font-size: 13px;
line-height: 15px;
transition: color 0.2s;
}
}
</style>