167 lines
4.0 KiB
Vue
167 lines
4.0 KiB
Vue
<!-- 页面:成功案例库(Cases) -->
|
||
<script setup lang="ts">
|
||
import { onMounted } from 'vue'
|
||
import { storeToRefs } from 'pinia'
|
||
import { useRouter } from 'vue-router'
|
||
import { PaginationBar } from '@/components'
|
||
import { useCasesStore } from '@/stores/modules/cases'
|
||
import type { CaseQuery } from '@/types/business/cases'
|
||
import CasesFilter from './cpns/CasesFilter.vue'
|
||
import CasesSearchBar from './cpns/CasesSearchBar.vue'
|
||
import CasesGrid from './cpns/CasesGrid.vue'
|
||
|
||
const router = useRouter()
|
||
const casesStore = useCasesStore()
|
||
const { query, list, total, previewTotal, typeOptions, industryOptions, scaleOptions, caseTotal }
|
||
= storeToRefs(casesStore)
|
||
|
||
function onUpdateQuery(next: CaseQuery): void {
|
||
casesStore.setQuery(next)
|
||
}
|
||
|
||
function onUpdateKeyword(keyword: string): void {
|
||
casesStore.setQuery({ ...query.value, keyword })
|
||
}
|
||
|
||
function onSearch(): void {
|
||
void casesStore.search()
|
||
}
|
||
|
||
function onReset(): void {
|
||
void casesStore.resetQuery()
|
||
}
|
||
|
||
function onToggleFavoriteOnly(): void {
|
||
void casesStore.toggleFavoriteOnly()
|
||
}
|
||
|
||
function onFavorite(id: string): void {
|
||
void casesStore.toggleFavorite(id)
|
||
}
|
||
|
||
function onPageChange(page: number): void {
|
||
void casesStore.changePage(page)
|
||
}
|
||
|
||
function onViewDetail(id: string): void {
|
||
void router.push(`/cases/${id}`)
|
||
}
|
||
|
||
onMounted(() => {
|
||
void Promise.all([casesStore.fetchCategories(), casesStore.fetchCases()])
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div class="cases">
|
||
<header class="cases__hero">
|
||
<div class="container cases__hero-inner">
|
||
<h1 class="cases__title">
|
||
成功案例库
|
||
</h1>
|
||
<p class="cases__slogan">
|
||
海量软硬件研发与量产落地真实案例,借鉴成熟实践,降低项目试错成本。
|
||
</p>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="container cases__body">
|
||
<CasesFilter
|
||
:query="query"
|
||
:type-options="typeOptions"
|
||
:industry-options="industryOptions"
|
||
:scale-options="scaleOptions"
|
||
:case-total="caseTotal"
|
||
:preview-total="previewTotal"
|
||
@update:query="onUpdateQuery"
|
||
@search="onSearch"
|
||
@reset="onReset"
|
||
/>
|
||
|
||
<div class="cases__main">
|
||
<CasesSearchBar
|
||
:keyword="query.keyword"
|
||
:favorite-only="query.favoriteOnly"
|
||
@update:keyword="onUpdateKeyword"
|
||
@search="onSearch"
|
||
@reset="onReset"
|
||
@toggle-favorite-only="onToggleFavoriteOnly"
|
||
/>
|
||
|
||
<CasesGrid
|
||
:cases="list"
|
||
:total="total"
|
||
@view="onViewDetail"
|
||
@favorite="onFavorite"
|
||
/>
|
||
|
||
<div class="cases__pager">
|
||
<PaginationBar
|
||
:page="query.page"
|
||
:page-size="query.pageSize"
|
||
:total="total"
|
||
@page-change="onPageChange"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style lang="less" scoped>
|
||
.cases {
|
||
padding-bottom: 78px;
|
||
|
||
&__hero {
|
||
height: 179px;
|
||
box-sizing: border-box;
|
||
padding-top: 32px;
|
||
background: @white;
|
||
}
|
||
|
||
// 设计稿 #31:hero 标题 x=112、副标题 x=112;
|
||
// 主体筛选栏 x=70、右侧操作区右边界 1850。两套留白并存,
|
||
// 所以 hero 内容单独内缩,不动全局 .container 的 70px 留白。
|
||
&__hero-inner {
|
||
padding-left: 112px;
|
||
padding-right: 112px;
|
||
}
|
||
|
||
&__title {
|
||
margin: 0;
|
||
font-size: 36px;
|
||
font-weight: 700;
|
||
line-height: 52px;
|
||
color: @cases-hero-title;
|
||
}
|
||
|
||
&__slogan {
|
||
margin: 15px 0 0;
|
||
font-size: 24px;
|
||
font-weight: 500;
|
||
line-height: 37px;
|
||
color: @cases-muted;
|
||
}
|
||
|
||
&__body {
|
||
.flex(row, flex-start, flex-start);
|
||
gap: 20px;
|
||
padding-top: 20px;
|
||
}
|
||
|
||
&__main {
|
||
// 设计稿:右侧操作区 x=606 w=1244(右边界 1850,与筛选栏区留白 70 对称)。
|
||
// mixin 签名是 .flex(direction; justify; align),第三参才是 align-items。
|
||
// 纵向排列时 justify 无意义,align 用 stretch 让子项撑满 1244。
|
||
.flex(column, flex-start, stretch);
|
||
flex: 1;
|
||
min-width: 0;
|
||
gap: 24px;
|
||
}
|
||
|
||
&__pager {
|
||
.flex(row, flex-end);
|
||
}
|
||
}
|
||
</style>
|