docs: 添加热门推荐模块前端实现计划
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d1b52e324f
commit
19bfce1b65
802
docs/superpowers/plans/2026-05-28-热门推荐模块前端实现计划.md
Normal file
802
docs/superpowers/plans/2026-05-28-热门推荐模块前端实现计划.md
Normal file
@ -0,0 +1,802 @@
|
||||
# 热门推荐模块前端实现计划
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 在广场页面集成4个热门分类区块,每个区块显示8张高点赞作品,支持刷新和查看更多
|
||||
|
||||
**Architecture:** 使用 Vue 3 Composition API + uni-app,通过 API 批量获取4个分类数据,单独分类刷新,查看更多跳转新页面
|
||||
|
||||
**Tech Stack:** uni-app + Vue 3 + SCSS
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
frontend/pages/square/
|
||||
├── square.vue # 修改:集成4个HotCategoryBlock
|
||||
├── components/
|
||||
│ └── HotCategoryBlock.vue # 新增:单个热门分类区块组件
|
||||
└── hot-category-more.vue # 新增:热门分类查看更多页面
|
||||
|
||||
frontend/utils/
|
||||
└── api.js # 修改:新增3个API方法
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API 变更
|
||||
|
||||
**新增 3 个 API**(在 `api.js` 末尾添加):
|
||||
|
||||
1. `getHotInspirationFlowBatchApi()` — 批量获取4个分类
|
||||
2. `getHotInspirationFlowApi(type)` — 单个分类刷新
|
||||
3. `getHotInspirationFlowMoreApi(type, cursor, limit)` — 查看更多分页
|
||||
|
||||
---
|
||||
|
||||
## 实现步骤
|
||||
|
||||
### Task 1: 添加 API 方法
|
||||
|
||||
**文件:**
|
||||
- 修改: `frontend/utils/api.js`
|
||||
|
||||
- [ ] **Step 1: 在 api.js 末尾添加3个API方法**
|
||||
|
||||
```javascript
|
||||
// ==================== 热门推荐相关接口 ====================
|
||||
|
||||
// 批量获取热门分类(页面初始化)
|
||||
export function getHotInspirationFlowBatchApi() {
|
||||
return request({
|
||||
url: '/api/v1/inspiration-flow/hot/batch',
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
|
||||
// 单个分类刷新
|
||||
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 }
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 提交**
|
||||
|
||||
```bash
|
||||
git add frontend/utils/api.js
|
||||
git commit -m "feat: 新增热门推荐API方法"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 创建 HotCategoryBlock.vue 组件
|
||||
|
||||
**文件:**
|
||||
- 创建: `frontend/pages/square/components/HotCategoryBlock.vue`
|
||||
|
||||
- [ ] **Step 1: 创建组件文件**
|
||||
|
||||
```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 }"
|
||||
:disabled="refreshing || loading"
|
||||
@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>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { getHotInspirationFlowApi } from '@/utils/api.js'
|
||||
|
||||
const props = defineProps({
|
||||
categoryType: { type: String, required: true },
|
||||
title: { type: String, required: true }
|
||||
})
|
||||
|
||||
const emit = defineEmits(['cardClick'])
|
||||
|
||||
const items = ref([])
|
||||
const loading = ref(false)
|
||||
const refreshing = ref(false)
|
||||
|
||||
const formatCount = (count) => {
|
||||
if (!count) return '0'
|
||||
if (count >= 10000) return (count / 10000).toFixed(1) + 'w'
|
||||
if (count >= 1000) return (count / 1000).toFixed(1) + 'k'
|
||||
return count.toString()
|
||||
}
|
||||
|
||||
const handleCardClick = (item) => {
|
||||
emit('cardClick', item)
|
||||
}
|
||||
|
||||
const handleRefresh = async () => {
|
||||
if (refreshing.value || loading.value) return
|
||||
refreshing.value = true
|
||||
try {
|
||||
const res = await getHotInspirationFlowApi(props.categoryType)
|
||||
if (res.code === 200 && res.data?.items) {
|
||||
items.value = res.data.items
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[HotCategoryBlock] 刷新失败', e)
|
||||
} finally {
|
||||
refreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleViewMore = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/square/hot-category-more?type=${props.categoryType}&title=${encodeURIComponent(props.title)}`
|
||||
})
|
||||
}
|
||||
|
||||
// 外部调用:设置数据
|
||||
const setItems = (newItems) => {
|
||||
items.value = newItems
|
||||
}
|
||||
|
||||
// 外部调用:设置加载状态
|
||||
const setLoading = (status) => {
|
||||
loading.value = status
|
||||
}
|
||||
|
||||
defineExpose({ setItems, setLoading })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hot-category-block {
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.block-title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.block-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hot-card {
|
||||
width: 48%;
|
||||
aspect-ratio: 1 / 1.3;
|
||||
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);
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 300rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 骨架屏 */
|
||||
.skeleton-card {
|
||||
width: 48%;
|
||||
aspect-ratio: 1 / 1.3;
|
||||
border-radius: 16rpx;
|
||||
background: #3a3a4a;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.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%); }
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.block-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-top: 8rpx;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.refresh-btn[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 提交**
|
||||
|
||||
```bash
|
||||
git add frontend/pages/square/components/HotCategoryBlock.vue
|
||||
git commit -m "feat: 新增HotCategoryBlock组件"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 创建 hot-category-more.vue 页面
|
||||
|
||||
**文件:**
|
||||
- 创建: `frontend/pages/square/hot-category-more.vue`
|
||||
- 创建: `frontend/pages/square/hot-category-more.vue` 的 json 配置
|
||||
|
||||
**pages.json 添加:**
|
||||
```json
|
||||
{
|
||||
"path": "pages/square/hot-category-more",
|
||||
"style": {
|
||||
"navigationBarTitleText": "热门推荐",
|
||||
"navigationBarBackgroundColor": "#1a1a2e",
|
||||
"navigationBarTextStyle": "white",
|
||||
"backgroundColor": "#1a1a2e"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 1: 创建 hot-category-more.vue 页面**
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view class="hot-more-page">
|
||||
<!-- 子标签(仅星卡显示) -->
|
||||
<view v-if="isStarCard" class="sub-tabs">
|
||||
<scroll-view scroll-x :show-scrollbar="false">
|
||||
<view class="sub-tab-list">
|
||||
<view
|
||||
v-for="tab in starCardSubTabs"
|
||||
:key="tab.value"
|
||||
class="sub-tab-item"
|
||||
:class="{ active: activeSubTab === tab.value }"
|
||||
@click="handleSubTabChange(tab.value)"
|
||||
>
|
||||
<text class="sub-tab-text">{{ tab.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 网格列表 -->
|
||||
<view class="more-grid">
|
||||
<view
|
||||
v-for="(item, index) in items"
|
||||
:key="item.asset_id || index"
|
||||
class="more-card"
|
||||
@click="handleCardClick(item)"
|
||||
>
|
||||
<image class="more-card-image" :src="item.cover_url" mode="aspectFill" />
|
||||
<view class="more-card-overlay">
|
||||
<view class="more-card-user">
|
||||
<image class="user-avatar" :src="item.owner_avatar" mode="aspectFill" />
|
||||
<text class="user-name">{{ item.owner_nickname }}</text>
|
||||
</view>
|
||||
<view class="more-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 v-if="loading" class="loading-more">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
<view v-if="noMore && items.length > 0" class="no-more">
|
||||
<text class="no-more-text">没有更多了</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getHotInspirationFlowMoreApi } from '@/utils/api.js'
|
||||
|
||||
const type = ref('')
|
||||
const title = ref('')
|
||||
const activeSubTab = ref('all')
|
||||
const items = ref([])
|
||||
const cursor = ref('')
|
||||
const loading = ref(false)
|
||||
const noMore = ref(false)
|
||||
|
||||
const starCardSubTabs = [
|
||||
{ label: '全部', value: 'all' },
|
||||
{ label: '光栅卡', value: 'raster' },
|
||||
{ label: '镭射卡', value: 'holographic' },
|
||||
{ label: '撕拉卡', value: 'tear_off' },
|
||||
{ label: '拍立得', value: 'polaroid' }
|
||||
]
|
||||
|
||||
const isStarCard = computed(() => type.value === 'hot_star_card')
|
||||
|
||||
onLoad((options) => {
|
||||
type.value = options.type || ''
|
||||
title.value = decodeURIComponent(options.title || '热门推荐')
|
||||
uni.setNavigationBarTitle({ title: title.value })
|
||||
loadData()
|
||||
})
|
||||
|
||||
const formatCount = (count) => {
|
||||
if (!count) return '0'
|
||||
if (count >= 10000) return (count / 10000).toFixed(1) + 'w'
|
||||
if (count >= 1000) return (count / 1000).toFixed(1) + 'k'
|
||||
return count.toString()
|
||||
}
|
||||
|
||||
const loadData = async () => {
|
||||
if (loading.value || noMore.value) return
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getHotInspirationFlowMoreApi(type.value, cursor.value)
|
||||
if (res.code === 200 && res.data?.items) {
|
||||
const newItems = res.data.items.map(item => ({
|
||||
...item,
|
||||
id: item.asset_id
|
||||
}))
|
||||
items.value = [...items.value, ...newItems]
|
||||
cursor.value = res.data.cursor || ''
|
||||
noMore.value = !res.data.has_more
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[hot-category-more] 加载失败', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const loadMore = () => {
|
||||
loadData()
|
||||
}
|
||||
|
||||
const handleSubTabChange = (tab) => {
|
||||
activeSubTab.value = tab
|
||||
items.value = []
|
||||
cursor.value = ''
|
||||
noMore.value = false
|
||||
loadData()
|
||||
}
|
||||
|
||||
const handleCardClick = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/asset-detail/asset-detail?asset_id=${item.asset_id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hot-more-page {
|
||||
min-height: 100vh;
|
||||
background: #1a1a2e;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.sub-tabs {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.sub-tab-list {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
|
||||
.sub-tab-item {
|
||||
padding: 12rpx 24rpx;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
|
||||
.sub-tab-item.active {
|
||||
background: linear-gradient(135deg, #F0E4B1, #F08399);
|
||||
}
|
||||
|
||||
.sub-tab-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.sub-tab-item.active .sub-tab-text {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.more-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.more-card {
|
||||
width: 48%;
|
||||
margin-bottom: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(10rpx);
|
||||
}
|
||||
|
||||
.more-card-image {
|
||||
width: 100%;
|
||||
height: 340rpx;
|
||||
}
|
||||
|
||||
.more-card-overlay {
|
||||
padding: 16rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.more-card-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.more-card-likes {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.like-icon {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
|
||||
.like-count {
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.loading-more,
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 32rpx 0;
|
||||
}
|
||||
|
||||
.loading-text,
|
||||
.no-more-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 提交**
|
||||
|
||||
```bash
|
||||
git add frontend/pages/square/hot-category-more.vue
|
||||
git commit -m "feat: 新增热门分类查看更多页面"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 修改 square.vue 集成 HotCategoryBlock
|
||||
|
||||
**文件:**
|
||||
- 修改: `frontend/pages/square/square.vue`
|
||||
|
||||
- [ ] **Step 1: 在 script setup 中添加引入和状态**
|
||||
|
||||
```javascript
|
||||
import HotCategoryBlock from './components/HotCategoryBlock.vue'
|
||||
import { getHotInspirationFlowBatchApi } from '@/utils/api.js'
|
||||
|
||||
// 热门分类状态
|
||||
const hotCategories = ref([])
|
||||
const hotCategoryRefs = ref({})
|
||||
|
||||
// 批量加载热门分类
|
||||
const loadHotCategories = async () => {
|
||||
try {
|
||||
const res = await getHotInspirationFlowBatchApi()
|
||||
if (res.code === 200 && res.data?.categories) {
|
||||
hotCategories.value = res.data.categories
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[square] 加载热门分类失败', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新单个分类
|
||||
const handleHotCategoryRefresh = async (categoryType) => {
|
||||
const ref = hotCategoryRefs.value[categoryType]
|
||||
if (ref) {
|
||||
await ref.handleRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
// 点击热门卡片
|
||||
const handleHotCardClick = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/asset-detail/asset-detail?asset_id=${item.asset_id}`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在 onMounted 中调用 loadHotCategories**
|
||||
|
||||
```javascript
|
||||
onMounted(() => {
|
||||
const info = uni.getSystemInfoSync()
|
||||
screenWidth.value = info.windowWidth
|
||||
screenHeight.value = info.windowHeight
|
||||
|
||||
resetSquare()
|
||||
loadBannerActivities()
|
||||
loadHotCategories() // 新增
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 在模板的 CreationGrid 之前添加4个 HotCategoryBlock**
|
||||
|
||||
```html
|
||||
<!-- 热门分类区块 -->
|
||||
<view
|
||||
v-for="category in hotCategories"
|
||||
:key="category.type"
|
||||
class="hot-category-wrapper"
|
||||
>
|
||||
<HotCategoryBlock
|
||||
:ref="el => { if(el) hotCategoryRefs[category.type] = el }"
|
||||
:categoryType="category.type"
|
||||
:title="category.title"
|
||||
@cardClick="handleHotCardClick"
|
||||
/>
|
||||
</view>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 添加样式**
|
||||
|
||||
```css
|
||||
/* 热门分类区块 */
|
||||
.hot-category-wrapper {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add frontend/pages/square/square.vue
|
||||
git commit -m "feat: 集成4个热门分类区块到广场页面"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 添加 pages.json 路由配置
|
||||
|
||||
**文件:**
|
||||
- 修改: `frontend/pages.json`
|
||||
|
||||
- [ ] **Step 1: 在 pages.json 添加 hot-category-more 页面配置**
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "pages/square/hot-category-more",
|
||||
"style": {
|
||||
"navigationBarTitleText": "热门推荐",
|
||||
"navigationBarBackgroundColor": "#1a1a2e",
|
||||
"navigationBarTextStyle": "white",
|
||||
"backgroundColor": "#1a1a2e"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 提交**
|
||||
|
||||
```bash
|
||||
git add frontend/pages.json
|
||||
git commit -m "feat: 添加热门分类查看更多页面路由"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 验证清单
|
||||
|
||||
- [ ] API 方法添加成功
|
||||
- [ ] HotCategoryBlock 组件渲染正常
|
||||
- [ ] 4个分类区块正确显示
|
||||
- [ ] 刷新按钮旋转动画正常
|
||||
- [ ] 查看更多跳转正常
|
||||
- [ ] hot-category-more 页面子标签正常(星卡分类)
|
||||
- [ ] 分页加载正常
|
||||
- [ ] 空状态显示正常
|
||||
Loading…
Reference in New Issue
Block a user