feat: ui update

This commit is contained in:
2026-09-15 16:01:59 +08:00
parent 1a11816839
commit 26c392d612
89 changed files with 10377 additions and 4861 deletions
@@ -5,6 +5,7 @@ import { STORAGE_KEYS } from '../../utils/config'
import { formatRelativeTime } from '../../utils/format'
import { normalizePaged, mergePaged, hasMorePaged } from '../../utils/paged'
import { getTabBarInstance } from '../../utils/tabbar'
import { navScroll } from '../../utils/nav'
import { logger } from '../../utils/logger'
// 日志模块名
@@ -27,8 +28,13 @@ Page({
page: 1,
pageSize: 20,
hasMore: true,
// 滚动收缩:由 utils/nav.ts 的共享 handler 驱动
navScrolled: false,
},
// scroll-view 滚动 → 导航收缩为玻璃小标题
onNavScroll: navScroll,
onShow() {
// 未登录直接回登录页(幂等跳转),不再发出必然 401 的请求
if (!auth.isLoggedIn()) {
@@ -1,53 +1,64 @@
<view class="page page-flex">
<navigation-bar title="通知" />
<navigation-bar title="通知" scrolled="{{navScrolled}}" />
<scroll-view
scroll-y
class="scroll-body"
bindscrolltolower="onReachBottom"
>
<!-- 筛选 -->
<scroll-view scroll-x class="filter-scroll" show-scrollbar="{{false}}">
<view class="filter-row">
<scroll-view scroll-y class="scroll-body" bindscrolltolower="onReachBottom" bindscroll="onNavScroll">
<!-- 大标题页头 -->
<view class="head">
<view class="eyebrow">Notifications</view>
<view class="display">通知</view>
</view>
<!-- 下划线式筛选 -->
<view class="segbar">
<view class="seg">
<view
wx:for="{{filters}}"
wx:key="name"
class="filter-item {{activeFilter === index ? 'active' : ''}}"
class="seg-item {{activeFilter === index ? 'is-on' : ''}}"
data-index="{{index}}"
bindtap="onFilterTap"
>{{item.name}}</view>
</view>
</scroll-view>
</view>
<!-- 骨架屏 -->
<view wx:if="{{loading}}" class="nt-skel">
<view class="nt-skel-item" wx:for="{{[1, 2, 3]}}" wx:key="*this">
<view class="sk sk-ln" style="width: 52%;"></view>
<view class="sk sk-ln" style="width: 86%;"></view>
<view class="sk sk-ln" style="width: 30%;"></view>
</view>
</view>
<!-- 空态 -->
<empty-state
wx:if="{{!loading && !list.length}}"
wx:elif="{{!list.length}}"
icon="icon-bell"
title="还没有消息"
desc="穿搭被点赞、订单动态都会出现在这里"
/>
<!-- 列表 -->
<view class="list">
<!-- 列表:未读左侧黑竖条 + 黑字标题,已读降为 ink-3 -->
<view wx:else class="nt-list">
<view
class="n-card card {{item.is_read === 1 ? 'unread' : ''}}"
class="nt-item {{item.is_read === 1 ? 'is-unread' : ''}}"
wx:for="{{list}}"
wx:key="notification_uuid"
data-uuid="{{item.notification_uuid}}"
bindtap="onItemTap"
>
<view class="n-icon {{item.msg_type === 1 ? 'like' : item.msg_type === 2 ? 'order' : 'sys'}}">
<view class="nt-ic">
<view class="icon {{item.msg_type === 1 ? 'icon-heart' : item.msg_type === 2 ? 'icon-doc' : 'icon-bell'}}"></view>
</view>
<view class="n-body">
<view class="n-title-row">
<view wx:if="{{item.is_read === 1}}" class="n-dot"></view>
<text class="n-title {{item.is_read === 2 ? 'read' : ''}}">{{item.title}}</text>
</view>
<view class="n-content">{{item.content}}</view>
<view class="n-time">{{item._time}}</view>
<view class="nt-body">
<view class="nt-t">{{item.title}}</view>
<view class="nt-c">{{item.content}}</view>
<view class="nt-time num">{{item._time}}</view>
</view>
</view>
</view>
<view wx:if="{{list.length && !hasMore}}" class="foot-note">没有更多了</view>
<view class="gap-32"></view>
</scroll-view>
</view>
@@ -1,3 +1,4 @@
/** 通知列表:下划线筛选 + 未读黑竖条 + 发丝线分行 **/
.page-flex {
height: 100vh;
display: flex;
@@ -10,117 +11,104 @@
height: 0;
}
.filter-scroll {
background: #fff;
white-space: nowrap;
.segbar {
position: sticky;
top: 0;
z-index: 20;
margin-top: 36rpx;
background: var(--glass);
-webkit-backdrop-filter: saturate(180%) blur(20px);
backdrop-filter: saturate(180%) blur(20px);
border-bottom: 1rpx solid var(--hairline);
}
.filter-row {
display: inline-flex;
padding: 20rpx 24rpx;
.nt-skel {
padding: 40rpx var(--pad) 0;
display: flex;
flex-direction: column;
gap: 52rpx;
}
.filter-item {
flex-shrink: 0;
padding: 0 32rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30rpx;
font-size: 26rpx;
color: #3C3C43;
background: #F2F2F7;
margin-right: 16rpx;
.nt-skel-item {
display: flex;
flex-direction: column;
gap: 18rpx;
}
.filter-item.active {
background: #007AFF;
color: #fff;
.nt-list {
padding: 8rpx var(--pad) 0;
}
.list {
padding: 24rpx;
}
.n-card {
.nt-item {
position: relative;
display: flex;
align-items: flex-start;
padding: 28rpx;
margin-bottom: 20rpx;
gap: 26rpx;
padding: 36rpx 0;
border-bottom: 1rpx solid var(--hairline);
}
.n-icon {
width: 80rpx;
height: 80rpx;
/* 未读:左侧 4rpx 黑竖条 */
.nt-item.is-unread::before {
content: '';
position: absolute;
left: -20rpx;
top: 44rpx;
width: 4rpx;
height: 32rpx;
border-radius: 2rpx;
background: var(--ink);
}
.nt-ic {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: var(--fill);
color: var(--ink-2);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-right: 24rpx;
}
.n-icon.like {
background: #FFE8EC;
color: #FF3B30;
.nt-ic .icon {
width: 36rpx;
height: 36rpx;
}
.n-icon.order {
background: #E8F2FF;
color: #007AFF;
}
.n-icon.sys {
background: #F2F2F7;
color: #8E8E93;
}
.n-icon .icon {
width: 44rpx;
height: 44rpx;
}
.n-body {
.nt-body {
flex: 1;
min-width: 0;
}
.n-title-row {
display: flex;
align-items: center;
}
.n-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #007AFF;
margin-right: 12rpx;
flex-shrink: 0;
}
.n-title {
.nt-t {
font-size: 30rpx;
font-weight: 600;
color: #000;
}
.n-title.read {
color: #8E8E93;
font-weight: 500;
color: var(--ink-3);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.n-content {
.nt-item.is-unread .nt-t {
color: var(--ink);
font-weight: 600;
}
.nt-c {
margin-top: 10rpx;
font-size: 26rpx;
color: #3C3C43;
margin-top: 8rpx;
line-height: 1.6;
color: var(--ink-2);
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.n-time {
.nt-time {
margin-top: 12rpx;
font-size: 22rpx;
color: #C7C7CC;
margin-top: 8rpx;
color: var(--ink-4);
}