docs: 添加热门推荐模块前端设计

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
zheng020 2026-05-28 12:20:36 +08:00
parent 9a9f4d1b96
commit d1b52e324f

View File

@ -0,0 +1,339 @@
# 热门推荐模块前端设计
## 一、页面结构
```
┌──────────────────────────────────────┐
│ 热门推荐 │
├──────────────────────────────────────┤
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ │ │ │ │ │ │ │ ← 行1 │
│ └────┘ └────┘ └────┘ └────┘ │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ │ │ │ │ │ │ │ ← 行2 │
│ └────┘ └────┘ └────┘ └────┘ │
│ 🔄 刷新 查看更多 ›│
└──────────────────────────────────────┘
```
---
## 二、组件结构
### HotCategoryBlock.vue
**Props**:
```javascript
{
categoryType: String, // 后端返回的 type: "hot_recommend" / "hot_star_card" / "hot_badge" / "hot_poster"
title: String // 后端返回的标题: "热门推荐"
}
```
**状态**:
- `items: Array` — 作品列表
- `loading: Boolean` — 首次加载中(显示骨架屏)
- `refreshing: Boolean` — 刷新中(按钮旋转动画)
- `hasMore: Boolean` — 是否有更多可加载
**事件**:
- `cardClick(item)` — 点击卡片,跳转详情
---
## 三、样式规范
### 3.1 布局
| 属性 | 值 |
|------|-----|
| 区块间距 | 上下 `32rpx`,左右 `24rpx` |
| 网格 | 4列 × 2行间距 `16rpx` |
| 卡片宽 | `=(屏宽 - 48rpx - 48rpx) / 4` |
| 卡片高 | `卡片宽 × 1.3` |
| 圆角 | `16rpx` |
### 3.2 卡片样式
```css
.hot-card {
border-radius: 16rpx;
overflow: hidden;
position: relative;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10rpx);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
}
.hot-card-image {
width: 100%;
height: 100%;
display: block;
}
/* 底部渐变遮罩 */
.hot-card-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 64rpx;
background: linear-gradient(to top, rgba(0,0,0,0.6), transparent);
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 0 12rpx 12rpx;
}
.hot-card-user {
display: flex;
align-items: center;
}
.user-avatar {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
margin-right: 6rpx;
}
.user-name {
font-size: 20rpx;
color: #fff;
max-width: 120rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.hot-card-likes {
display: flex;
align-items: center;
}
.like-icon {
width: 20rpx;
height: 20rpx;
margin-right: 4rpx;
}
.like-count {
font-size: 20rpx;
color: #fff;
}
```
### 3.3 标题栏样式
```css
.block-title {
font-size: 30rpx;
font-weight: 600;
color: #fff;
padding: 0 24rpx 16rpx;
}
```
### 3.4 操作按钮样式
```css
.block-actions {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 16rpx 24rpx 0;
gap: 24rpx;
}
.refresh-btn {
display: flex;
align-items: center;
}
.refresh-btn .action-icon {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.7);
}
.refresh-btn.spinning .action-icon {
animation: spin 0.8s linear;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.more-btn {
display: flex;
align-items: center;
}
.more-text {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.7);
}
.more-arrow {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.7);
margin-left: 4rpx;
}
```
---
## 四、状态处理
| 状态 | 表现 |
|------|------|
| `loading=true` | 显示 8 个骨架屏卡片,操作按钮禁用 |
| `loading=false && items.length=0` | 空状态提示:「暂无{{title}}作品」 |
| `loading=false && items.length>0` | 正常显示 8 张卡片 |
| `refreshing=true` | 刷新按钮旋转动画,卡片 fade-out |
| `refreshing=false` | 刷新完成,卡片 fade-in |
---
## 五、骨架屏样式
```css
.skeleton-card {
border-radius: 16rpx;
background: #3a3a4a;
overflow: hidden;
position: relative;
}
.skeleton-shimmer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.1) 50%,
transparent 100%
);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
```
---
## 六、完整组件模板
```vue
<template>
<view class="hot-category-block">
<!-- 标题 -->
<text class="block-title">{{ title }}</text>
<!-- 网格区域 -->
<view v-if="loading" class="block-grid">
<view v-for="i in 8" :key="i" class="skeleton-card">
<view class="skeleton-shimmer"></view>
</view>
</view>
<view v-else-if="items.length === 0" class="empty-state">
<text class="empty-text">暂无{{ title }}作品</text>
</view>
<view v-else class="block-grid">
<view
v-for="(item, index) in items"
:key="item.asset_id || index"
class="hot-card"
@click="handleCardClick(item)"
>
<image class="hot-card-image" :src="item.cover_url" mode="aspectFill" />
<view class="hot-card-overlay">
<view class="hot-card-user">
<image class="user-avatar" :src="item.owner_avatar" mode="aspectFill" />
<text class="user-name">{{ item.owner_nickname }}</text>
</view>
<view class="hot-card-likes">
<image class="like-icon" src="/static/icon/heart-icon.png" mode="aspectFit" />
<text class="like-count">{{ formatCount(item.likes) }}</text>
</view>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="block-actions">
<view class="refresh-btn" :class="{ spinning: refreshing }" @click="handleRefresh">
<text class="action-icon"></text>
</view>
<view class="more-btn" @click="handleViewMore">
<text class="more-text">查看更多</text>
<text class="more-arrow"></text>
</view>
</view>
</view>
</template>
```
---
## 七、API 调用
```javascript
// 单个分类刷新
export function getHotInspirationFlowApi(type) {
return request({
url: '/api/v1/inspiration-flow/hot',
method: 'GET',
data: { type }
})
}
// 查看更多分页
export function getHotInspirationFlowMoreApi(type, cursor = '', limit = 20) {
return request({
url: '/api/v1/inspiration-flow/hot/more',
method: 'GET',
data: { type, cursor, limit }
})
}
```
---
## 八、hot-category-more.vue 页面
**路由参数**:
- `type` — 分类类型
- `title` — 标题URL 编码)
**页面结构**:
```
┌──────────────────────────────────────┐
│ ← 返回 热门星卡 │
├──────────────────────────────────────┤
│ [全部] [光栅卡] [镭射卡] [撕拉卡] [拍立得] │ ← 仅星卡显示
├──────────────────────────────────────┤
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ │ │ │ │ │ │ │ │
│ └────┘ └────┘ └────┘ └────┘ │
│ ... │
└──────────────────────────────────────┘
```
**星卡子标签**(仅 `hot_star_card` 显示):
| 子标签 | value | 说明 |
|-------|-------|------|
| 全部 | `all` | 全部星卡 |
| 光栅卡 | `raster` | 光栅卡类型 |
| 镭射卡 | `holographic` | 镭射卡类型 |
| 撕拉卡 | `tear_off` | 撕拉卡类型 |
| 拍立得 | `polaroid` | 拍立得类型 |