feat:消息中心和案例库
This commit is contained in:
@@ -1,41 +1,259 @@
|
||||
<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="placeholder-page">
|
||||
<text class="placeholder-page__title">
|
||||
项目中心
|
||||
</text>
|
||||
<text class="placeholder-page__desc">
|
||||
功能开发中
|
||||
</text>
|
||||
<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 '@/styles/variables.scss';
|
||||
|
||||
.placeholder-page {
|
||||
.project-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: $color-bg-section;
|
||||
}
|
||||
|
||||
.project-center__header {
|
||||
flex-shrink: 0;
|
||||
padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 0;
|
||||
background: $color-bg-page;
|
||||
}
|
||||
|
||||
.placeholder-page__title {
|
||||
.project-center__title {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: $color-text-primary;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholder-page__desc {
|
||||
margin-top: 16rpx;
|
||||
.project-center__search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 72rpx;
|
||||
margin-top: 24rpx;
|
||||
padding: 0 24rpx;
|
||||
background: $color-bg-section;
|
||||
border-radius: 36rpx;
|
||||
}
|
||||
|
||||
.project-center__search-icon {
|
||||
flex-shrink: 0;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.project-center__search-input {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: $color-text-primary;
|
||||
}
|
||||
|
||||
.project-center__search-placeholder {
|
||||
color: $color-text-placeholder;
|
||||
}
|
||||
|
||||
.project-center__tabs {
|
||||
margin-top: 24rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.project-center__tabs-inner {
|
||||
display: inline-flex;
|
||||
gap: 32rpx;
|
||||
padding-right: 24rpx;
|
||||
}
|
||||
|
||||
.project-center__tab {
|
||||
flex-shrink: 0;
|
||||
padding-bottom: 12rpx;
|
||||
font-size: 28rpx;
|
||||
color: $color-text-secondary;
|
||||
|
||||
&--active {
|
||||
font-weight: 600;
|
||||
color: $color-text-primary;
|
||||
border-bottom: 4rpx solid $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.project-center__toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 0 24rpx;
|
||||
}
|
||||
|
||||
.project-center__count {
|
||||
font-size: 24rpx;
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
|
||||
.project-center__filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.project-center__filter-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.project-center__filter-text {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.project-center__scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.project-center__list {
|
||||
padding: 0 24rpx calc(140rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user