Files
cz-app/src/pages/project-center/index.vue
2026-09-14 17:09:25 +08:00

150 lines
4.2 KiB
Vue

<script setup lang="ts">
import { computed, ref } from 'vue'
import AppTabBar from '@/components/AppTabBar.vue'
import { DEFAULT_CASE_FILTER } from '@/constants/case-library'
import {
PROJECT_CATEGORIES,
PROJECT_CENTER_LIST,
} from '@/constants/project-center'
import filterIcon from '@/static/icons/icon-filter.svg'
import type { CaseFilterValues } from '@/types/case-library'
import type { ProjectCategory } from '@/types/project-center'
import { cloneCaseFilter, matchCaseFilter } from '@/utils/case-filter'
import CaseFilterPanel from '../case-library/components/CaseFilterPanel.vue'
import ProjectCenterCard from './components/ProjectCenterCard.vue'
const keyword = ref('')
const activeCategory = ref<ProjectCategory>('全部')
const projectList = ref(PROJECT_CENTER_LIST.map(item => ({ ...item })))
const filterVisible = ref(false)
const appliedFilter = ref<CaseFilterValues>(cloneCaseFilter(DEFAULT_CASE_FILTER))
const filteredProjects = computed(() => {
const text = keyword.value.trim()
return projectList.value.filter((item) => {
const matchCategory = activeCategory.value === '全部' || item.category === activeCategory.value
const matchKeyword = !text
|| item.title.includes(text)
|| item.category.includes(text)
|| item.projectNo.includes(text)
|| item.status.includes(text)
|| item.industry.includes(text)
const matchFilter = matchCaseFilter(item, appliedFilter.value)
return matchCategory && matchKeyword && matchFilter
})
})
function handleSelectCategory(category: ProjectCategory) {
activeCategory.value = category
}
function handleOpenFilter() {
filterVisible.value = true
}
function handleCloseFilter() {
filterVisible.value = false
}
function handleConfirmFilter(value: CaseFilterValues) {
appliedFilter.value = cloneCaseFilter(value)
}
function handleViewDetail(id: string) {
uni.navigateTo({
url: `/pages/project-center/detail/index?id=${encodeURIComponent(id)}`,
})
}
</script>
<template>
<view class="project-center">
<view class="project-center__header">
<text class="project-center__title">
项目中心
</text>
<view class="project-center__search">
<image
class="project-center__search-icon"
src="/static/icons/icon-search.svg"
mode="aspectFit"
/>
<input
v-model="keyword"
class="project-center__search-input"
placeholder="搜索案例标题、描述、标签..."
placeholder-class="project-center__search-placeholder"
>
</view>
<scroll-view
class="project-center__tabs"
scroll-x
:show-scrollbar="false"
>
<view class="project-center__tabs-inner">
<text
v-for="category in PROJECT_CATEGORIES"
:key="category"
class="project-center__tab"
:class="{ 'project-center__tab--active': activeCategory === category }"
@tap="handleSelectCategory(category)"
>
{{ category }}
</text>
</view>
</scroll-view>
<view class="project-center__toolbar">
<text class="project-center__count">
共 {{ filteredProjects.length }}
</text>
<view
class="project-center__filter"
@tap="handleOpenFilter"
>
<image
class="project-center__filter-icon"
:src="filterIcon"
mode="aspectFit"
/>
<text class="project-center__filter-text">
筛选
</text>
</view>
</view>
</view>
<scroll-view
class="project-center__scroll"
scroll-y
:show-scrollbar="false"
>
<view class="project-center__list">
<ProjectCenterCard
v-for="item in filteredProjects"
:key="item.id"
:item="item"
@detail="handleViewDetail"
/>
</view>
</scroll-view>
<AppTabBar active="project" />
<CaseFilterPanel
:visible="filterVisible"
:cases="projectList"
:value="appliedFilter"
@close="handleCloseFilter"
@confirm="handleConfirmFilter"
/>
</view>
</template>
<style scoped lang="scss">
@import './index.scss';
</style>