feat 搭建架构骨架

This commit is contained in:
Ironsp
2026-09-24 09:09:47 +08:00
parent dd9f6b77a4
commit 7a2efa3fea
180 changed files with 18967 additions and 9 deletions

View File

@@ -0,0 +1,138 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import { FilterPanel, PaginationBar } from '@/components'
import type { BusinessType } from '@/types/api'
import { useProfileStore } from '@/stores/modules/profile'
import FavoritesGrid from './cpns/FavoritesGrid.vue'
interface CategoryOption {
key: BusinessType | 'all'
label: string
}
const CATEGORY_OPTIONS: CategoryOption[] = [
{ key: 'all', label: '全部' },
{ key: 'internet', label: '互联网软件' },
{ key: 'hardware', label: '硬件电路' },
{ key: 'iot', label: '物联网全案' },
{ key: 'manufacturing', label: '生产制造' },
]
const router = useRouter()
const profileStore = useProfileStore()
const { favorites, favoritesTotal, favoritesCounts, favoritesQuery } = storeToRefs(profileStore)
// 本地搜索条件(搜索/重置时同步进 store)
const keyword = ref('')
const category = ref<BusinessType | 'all'>('all')
function countOf(key: BusinessType | 'all'): number {
if (key === 'all') return favoritesTotal.value
return favoritesCounts.value[key] ?? 0
}
function onSearch(): void {
void profileStore.searchFavorites({ keyword: keyword.value, category: category.value })
}
function onReset(): void {
keyword.value = ''
category.value = 'all'
void profileStore.resetFavorites()
}
function onSelectCategory(key: BusinessType | 'all'): void {
category.value = key
void profileStore.searchFavorites({ keyword: keyword.value, category: key })
}
function onPageChange(page: number): void {
void profileStore.changeFavoritesPage(page)
}
function onViewDetail(id: string): void {
void router.push(`/cases/${id}`)
}
onMounted(() => {
keyword.value = favoritesQuery.value.keyword
category.value = favoritesQuery.value.category
void Promise.all([profileStore.fetchFavorites(), profileStore.fetchFavoritesCounts()])
})
</script>
<template>
<div class="favorites-page">
<FilterPanel
v-model:keyword="keyword"
keyword-placeholder="搜索收藏案例标题"
@search="onSearch"
@reset="onReset"
/>
<div class="favorites-page__categories">
<button
v-for="item in CATEGORY_OPTIONS"
:key="item.key"
class="favorites-page__cat"
:class="{ 'is-active': category === item.key }"
@click="onSelectCategory(item.key)"
>
{{ item.label }}({{ countOf(item.key) }})
</button>
</div>
<FavoritesGrid :cases="favorites" @view="onViewDetail" />
<PaginationBar
:page="favoritesQuery.page"
:page-size="favoritesQuery.pageSize"
:total="favoritesTotal"
@page-change="onPageChange"
/>
</div>
</template>
<style lang="less" scoped>
.favorites-page {
.flex(column, flex-start);
gap: @spacing-base;
width: 100%;
&__categories {
.flex(row, flex-start);
flex-wrap: wrap;
gap: @spacing-sm;
width: 100%;
padding: @spacing-base @spacing-lg;
border-radius: @radius-lg;
background: @white;
box-shadow: @shadow-base;
}
&__cat {
height: 32px;
padding: 0 @spacing-base;
border: 1px solid @border-color;
border-radius: @radius-round;
background: @white;
color: @text-color;
font-size: @font-size-sm;
transition: all 0.2s;
&:hover {
border-color: @primary-color;
color: @primary-color;
}
&.is-active {
border-color: @primary-color;
background: @primary-light;
color: @primary-color;
font-weight: 600;
}
}
}
</style>