feat:消息中心和案例库

This commit is contained in:
李伊帆
2026-09-14 10:32:21 +08:00
parent 173cd6b975
commit f5d634bbaf
41 changed files with 3484 additions and 48 deletions

View File

@@ -0,0 +1,96 @@
<script setup lang="ts">
import type { StatusNotificationItem } from '@/types/status-notification'
defineProps<{
item: StatusNotificationItem
icon: string
}>()
</script>
<template>
<view class="status-notification-item">
<image
class="status-notification-item__icon"
:src="icon"
mode="aspectFit"
/>
<view class="status-notification-item__content">
<view class="status-notification-item__row">
<text class="status-notification-item__title">
{{ item.title }}
</text>
<text class="status-notification-item__time">
{{ item.time }}
</text>
</view>
<text class="status-notification-item__preview">
{{ item.preview }}
</text>
</view>
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.status-notification-item {
display: flex;
align-items: flex-start;
width: 100%;
box-sizing: border-box;
padding: 24rpx 32rpx;
background: $color-bg-page;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
}
.status-notification-item__icon {
flex-shrink: 0;
width: 88rpx;
height: 88rpx;
margin-right: 24rpx;
}
.status-notification-item__content {
flex: 1;
min-width: 0;
padding-top: 4rpx;
}
.status-notification-item__row {
display: flex;
align-items: center;
justify-content: space-between;
}
.status-notification-item__title {
font-size: 30rpx;
font-weight: 600;
color: $color-text-primary;
}
.status-notification-item__time {
flex-shrink: 0;
margin-left: 16rpx;
font-size: 24rpx;
color: $color-text-secondary;
}
.status-notification-item__preview {
margin-top: 8rpx;
min-height: 78rpx;
font-size: 26rpx;
line-height: 1.5;
color: $color-text-secondary;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

View File

@@ -0,0 +1,182 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import {
STATUS_NOTIFICATION_ICON,
STATUS_NOTIFICATION_LIST,
} from '@/constants/status-notification'
import type { StatusNotificationItem } from '@/types/status-notification'
import { navigateBackWithFallback } from '@/utils/navigate-back'
import StatusNotificationItemCard from './components/StatusNotificationItem.vue'
const keyword = ref('')
const notificationList = ref<StatusNotificationItem[]>(
STATUS_NOTIFICATION_LIST.map(item => ({ ...item })),
)
const filteredList = computed(() => {
const text = keyword.value.trim()
if (!text)
return notificationList.value
return notificationList.value.filter(item =>
item.title.includes(text) || item.preview.includes(text),
)
})
function handleBack() {
navigateBackWithFallback('/pages/message-center/index')
}
function handleReadAll() {
notificationList.value = notificationList.value.map(item => ({
...item,
unread: false,
}))
uni.showToast({ title: '已全部标为已读', icon: 'none' })
}
</script>
<template>
<view class="status-notification">
<view class="status-notification__header">
<view
class="status-notification__back"
@tap="handleBack"
>
<image
class="status-notification__back-icon"
src="/static/icons/icon-back.svg"
mode="aspectFit"
/>
</view>
<text class="status-notification__title">
状态通知
</text>
<text
class="status-notification__read-all"
@tap="handleReadAll"
>
全部已读
</text>
</view>
<view class="status-notification__search">
<image
class="status-notification__search-icon"
src="/static/icons/icon-search.svg"
mode="aspectFit"
/>
<input
v-model="keyword"
class="status-notification__search-input"
placeholder="搜索案例标题、描述、标签..."
placeholder-class="status-notification__search-placeholder"
>
</view>
<scroll-view
class="status-notification__scroll"
scroll-y
:show-scrollbar="false"
>
<view class="status-notification__list">
<StatusNotificationItemCard
v-for="item in filteredList"
:key="item.id"
:item="item"
:icon="STATUS_NOTIFICATION_ICON"
/>
</view>
</scroll-view>
</view>
</template>
<style scoped lang="scss">
@import '@/styles/variables.scss';
.status-notification {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
background: $color-bg-page;
}
.status-notification__header {
position: relative;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: calc(var(--status-bar-height, 44px) + 60rpx) 32rpx 28rpx;
background: $color-bg-page;
}
.status-notification__back {
position: absolute;
left: 32rpx;
bottom: 28rpx;
display: flex;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
}
.status-notification__back-icon {
width: 40rpx;
height: 40rpx;
}
.status-notification__title {
font-size: 36rpx;
font-weight: 600;
color: $color-text-primary;
}
.status-notification__read-all {
position: absolute;
right: 32rpx;
bottom: 28rpx;
font-size: 26rpx;
color: $color-text-secondary;
}
.status-notification__search {
display: flex;
align-items: center;
flex-shrink: 0;
height: 72rpx;
margin: 0 32rpx 16rpx;
padding: 0 24rpx;
background: $color-bg-section;
border-radius: 36rpx;
}
.status-notification__search-icon {
flex-shrink: 0;
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
}
.status-notification__search-input {
flex: 1;
font-size: 26rpx;
color: $color-text-primary;
}
.status-notification__search-placeholder {
color: $color-text-placeholder;
}
.status-notification__scroll {
flex: 1;
min-height: 0;
}
.status-notification__list {
width: 100%;
padding-bottom: env(safe-area-inset-bottom);
}
</style>