feat: implement miniapp C-group pages with real API calls and design tokens
This commit is contained in:
@@ -1 +1,76 @@
|
||||
Page({data:{categories:['推荐','认识自己','沟通成长','关系经营','婚恋反诈'],active:0,articles:[{id:'1',title:'第一次见面,怎样自然地开始交流',category:'沟通成长',read:'5分钟'},{id:'2',title:'建立健康关系,需要怎样的边界',category:'关系经营',read:'6分钟'},{id:'3',title:'警惕以投资为名的婚恋骗局',category:'婚恋反诈',read:'4分钟'}]},select(e){this.setData({active:e.currentTarget.dataset.index})},open(e){wx.navigateTo({url:'/pages/content-detail/content-detail?id='+e.currentTarget.dataset.id})}})
|
||||
const api = require('../../utils/api')
|
||||
|
||||
const formatDate = (value) => {
|
||||
if (!value) return ''
|
||||
const date = new Date(value)
|
||||
if (Number.isNaN(date.getTime())) return ''
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${date.getFullYear()}-${month}-${day}`
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
categories: [{ id: '', name: '推荐' }],
|
||||
activeCategoryId: '',
|
||||
articles: [],
|
||||
loading: true,
|
||||
loadError: false,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadPage()
|
||||
},
|
||||
|
||||
async loadPage() {
|
||||
this.setData({ loading: true, loadError: false })
|
||||
try {
|
||||
const [categories, articles] = await Promise.all([
|
||||
api.get('/content/categories'),
|
||||
api.get('/content/articles'),
|
||||
])
|
||||
this.setData({
|
||||
categories: [{ id: '', name: '推荐' }, ...(categories || [])],
|
||||
articles: this.normalizeArticles(articles || [], categories || []),
|
||||
loading: false,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('加载婚恋课堂失败', error)
|
||||
this.setData({ loading: false, loadError: true })
|
||||
}
|
||||
},
|
||||
|
||||
normalizeArticles(articles, categories) {
|
||||
const categoryNames = new Map(categories.map((item) => [item.id, item.name]))
|
||||
return articles.map((item) => ({
|
||||
...item,
|
||||
categoryName: categoryNames.get(item.categoryId) || '婚恋课堂',
|
||||
publishAtText: formatDate(item.publishAt || item.createdAt),
|
||||
}))
|
||||
},
|
||||
|
||||
async select(e) {
|
||||
const categoryId = e.currentTarget.dataset.id || ''
|
||||
if (categoryId === this.data.activeCategoryId) return
|
||||
this.setData({ activeCategoryId: categoryId, loading: true, loadError: false })
|
||||
try {
|
||||
const articles = await api.get('/content/articles', categoryId ? { categoryId } : undefined)
|
||||
this.setData({
|
||||
articles: this.normalizeArticles(articles || [], this.data.categories),
|
||||
loading: false,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('加载课堂分类失败', error)
|
||||
this.setData({ loading: false, loadError: true })
|
||||
}
|
||||
},
|
||||
|
||||
open(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
if (id) wx.navigateTo({ url: `/pages/content-detail/content-detail?id=${id}` })
|
||||
},
|
||||
|
||||
onRetry() {
|
||||
this.loadPage()
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
{"navigationBarTitleText":"婚恋课堂","backgroundColor":"#FAFAF8"}
|
||||
{
|
||||
"navigationBarTitleText": "婚恋课堂",
|
||||
"backgroundColor": "#F4F5FA",
|
||||
"usingComponents": {
|
||||
"ui-service-hero": "/components/service-hero/index",
|
||||
"ui-loading": "/components/loading/index",
|
||||
"ui-empty": "/components/empty/index",
|
||||
"ui-error-state": "/components/error-state/index"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,19 @@
|
||||
<view class="service-page reference-page"><view class="hero"><text class="eyebrow">婚恋课堂</text><text class="hero-title">认真学习,更好地相遇</text><text class="hero-desc">提供真实、克制、可实践的关系成长与安全知识。</text></view><scroll-view scroll-x style="white-space:nowrap;padding:24rpx 32rpx;box-sizing:border-box"><text wx:for="{{categories}}" wx:key="*this" data-index="{{index}}" bindtap="select" class="tag {{active===index ? '' : 'warning'}}">{{item}}</text></scroll-view><view class="content"><view wx:for="{{articles}}" wx:key="id" class="article-card" data-id="{{item.id}}" bindtap="open"><view class="article-cover"><text>{{item.category}}</text></view><view class="article-body"><text class="article-title">{{item.title}}</text><text class="article-meta">{{item.category}} · 阅读约 {{item.read}}</text></view></view></view></view>
|
||||
<view class="content-page app-page reference-page">
|
||||
<ui-service-hero eyebrow="学习成长 · 认真相遇" title="婚恋课堂" subtitle="学习成长,收获更好的自己" image-src="/assets/covers/classroom-default.jpg" tone="rose" />
|
||||
<scroll-view scroll-x class="content-categories">
|
||||
<view class="content-category-row"><view wx:for="{{categories}}" wx:key="id" data-id="{{item.id}}" bindtap="select" class="content-category {{activeCategoryId === item.id ? 'active' : ''}}">{{item.name}}</view></view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="content-list">
|
||||
<ui-loading wx:if="{{loading}}" mode="skeleton" rows="4" />
|
||||
<ui-error-state wx:elif="{{loadError}}" title="暂时无法加载课堂内容" description="请检查网络后重试" bind:retry="onRetry" />
|
||||
<view wx:elif="{{articles.length}}">
|
||||
<view wx:for="{{articles}}" wx:key="id" class="content-card" data-id="{{item.id}}" bindtap="open">
|
||||
<image class="content-cover" src="{{item.coverFileId || '/assets/covers/classroom-default.jpg'}}" mode="aspectFill" />
|
||||
<view class="content-card__body"><text class="content-card__category">{{item.categoryName}}</text><text class="content-card__title">{{item.title}}</text><text wx:if="{{item.summary}}" class="content-card__summary">{{item.summary}}</text><view class="content-card__meta"><text>浏览 {{item.viewCount || 0}}</text><text>{{item.publishAtText}}</text></view></view>
|
||||
<image class="content-card__arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
<ui-empty wx:else illustration="default" title="暂无课堂内容" description="公益内容正在准备中,请稍后再来" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
@import "../../styles/service-page.wxss";
|
||||
@import "../../styles/service-page.wxss";
|
||||
.content-page{min-height:100vh;padding-bottom:40rpx;background:#F4F5FA}.content-categories{padding:24rpx 0;white-space:nowrap}.content-category-row{display:inline-flex;gap:12rpx;padding:0 24rpx}.content-category{padding:11rpx 22rpx;border-radius:24rpx;background:#fff;color:#767D96;font-size:21rpx;box-shadow:0 6rpx 18rpx rgba(35,35,95,.05)}.content-category.active{background:linear-gradient(135deg,var(--mini-accent-coral),var(--mini-accent-pink));color:#fff;font-weight:650}.content-list{padding:0 24rpx}.content-card{display:flex;align-items:center;overflow:hidden;min-height:150rpx;margin-bottom:16rpx;border-radius:24rpx;background:#fff;box-shadow:0 8rpx 26rpx rgba(35,35,95,.06)}.content-cover{width:176rpx;height:150rpx;flex:none}.content-card__body{display:flex;flex:1;min-width:0;flex-direction:column;padding:16rpx}.content-card__category{align-self:flex-start;padding:4rpx 10rpx;border-radius:12rpx;background:#FFF0F5;color:var(--mini-accent-pink);font-size:17rpx}.content-card__title{overflow:hidden;margin-top:8rpx;color:#283056;font-size:24rpx;font-weight:650;white-space:nowrap;text-overflow:ellipsis}.content-card__summary{overflow:hidden;margin-top:5rpx;color:#83899F;font-size:18rpx;white-space:nowrap;text-overflow:ellipsis}.content-card__meta{display:flex;gap:18rpx;margin-top:9rpx;color:#9A9EB0;font-size:17rpx}.content-card__arrow{width:24rpx;height:24rpx;margin-right:16rpx;flex:none}
|
||||
|
||||
Reference in New Issue
Block a user