feat 搭建架构骨架
This commit is contained in:
138
src/views/profile/favorites.vue
Normal file
138
src/views/profile/favorites.vue
Normal 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>
|
||||
Reference in New Issue
Block a user