feat: migrate static pages to native tabbar
This commit is contained in:
153
packages/tcm/pages/assets/index.js
Normal file
153
packages/tcm/pages/assets/index.js
Normal file
@@ -0,0 +1,153 @@
|
||||
const { createTcmAssetPageData } = require('../../../../utils/static-ux/tcm')
|
||||
const { resolveKind } = require('../../../../utils/static-ux/shared')
|
||||
const { ROUTES, openStaticRoute } = require('../../../../utils/static-ux/route-map')
|
||||
|
||||
const ASSET_KIND_LABELS = Object.freeze({
|
||||
notes: '笔记',
|
||||
bookshelf: '书架',
|
||||
favorites: '收藏',
|
||||
history: '历史'
|
||||
})
|
||||
|
||||
const ASSET_ITEMS = Object.freeze({
|
||||
notes: [
|
||||
{
|
||||
key: 'note-1',
|
||||
title: '阴阳学习摘记',
|
||||
subtitle: '来自《黄帝内经素问》静态演示卡片',
|
||||
description: '把阴阳作为纲领来理解脏腑、经络与病机的对应关系。',
|
||||
route: `${ROUTES.tcm.bookDetail}?scene=classic-a`
|
||||
},
|
||||
{
|
||||
key: 'note-2',
|
||||
title: '脾虚湿困辨证提要',
|
||||
subtitle: '辨证分析里的高频主题',
|
||||
description: '先看脾运失健,再看湿困中焦的症状组合。',
|
||||
route: `${ROUTES.tcm.bianzheng}?scene=result`
|
||||
}
|
||||
],
|
||||
bookshelf: [
|
||||
{
|
||||
key: 'book-1',
|
||||
title: '黄帝内经素问',
|
||||
subtitle: '已加入静态书架',
|
||||
description: '继续阅读:上古天真论',
|
||||
route: `${ROUTES.tcm.bookDetail}?scene=classic-a`
|
||||
},
|
||||
{
|
||||
key: 'book-2',
|
||||
title: '伤寒论',
|
||||
subtitle: '已加入静态书架',
|
||||
description: '继续阅读:太阳病篇',
|
||||
route: `${ROUTES.tcm.bookDetail}?scene=classic-b`
|
||||
}
|
||||
],
|
||||
favorites: [
|
||||
{
|
||||
key: 'favorite-1',
|
||||
title: '经络总览卡片',
|
||||
subtitle: '已收藏条目',
|
||||
description: '保留为静态收藏示例,后续再接新的收藏体系。',
|
||||
route: `${ROUTES.tcm.placeholder}?kind=about`
|
||||
},
|
||||
{
|
||||
key: 'favorite-2',
|
||||
title: '命理解读入口',
|
||||
subtitle: '跨域收藏示例',
|
||||
description: '当前用于展示从中医域跳到命理域的 UI 连接。',
|
||||
route: ROUTES.mingli.interpret
|
||||
}
|
||||
],
|
||||
history: [
|
||||
{
|
||||
key: 'history-1',
|
||||
title: 'AI答疑: 什么是气虚?',
|
||||
subtitle: '最近浏览',
|
||||
description: '返回 AI 页查看静态问答入口。',
|
||||
route: ROUTES.tabs.ai
|
||||
},
|
||||
{
|
||||
key: 'history-2',
|
||||
title: '典籍阅读: 上古天真论',
|
||||
subtitle: '最近阅读',
|
||||
description: '回到典籍阅读页继续浏览。',
|
||||
route: `${ROUTES.tcm.section}?scene=reader-a`
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const ASSET_EMPTY_COPY = Object.freeze({
|
||||
notes: {
|
||||
title: '还没有学习笔记',
|
||||
description: '后续接入新后端后,这里会汇总你的静态摘录与标注。'
|
||||
},
|
||||
bookshelf: {
|
||||
title: '书架还是空的',
|
||||
description: '可以先从典籍页进入静态详情,再决定如何组织新的书架逻辑。'
|
||||
},
|
||||
favorites: {
|
||||
title: '还没有收藏内容',
|
||||
description: '本轮只保留收藏区块的 UI 结构,不迁移旧收藏模型。'
|
||||
},
|
||||
history: {
|
||||
title: '还没有浏览记录',
|
||||
description: '继续浏览典籍、AI 或易学页后,后续可在这里接入新的记录源。'
|
||||
}
|
||||
})
|
||||
|
||||
function cloneItems(items) {
|
||||
return items.map(item => ({ ...item }))
|
||||
}
|
||||
|
||||
function createFilterItems(kinds) {
|
||||
return kinds.map(kind => ({
|
||||
key: kind,
|
||||
label: ASSET_KIND_LABELS[kind],
|
||||
route: `${ROUTES.tcm.assets}?kind=${kind}`
|
||||
}))
|
||||
}
|
||||
|
||||
function createTcmAssetsPageData(rawKind) {
|
||||
const baseData = createTcmAssetPageData(rawKind)
|
||||
const items = cloneItems(ASSET_ITEMS[baseData.activeKind] || [])
|
||||
const emptyCopy = ASSET_EMPTY_COPY[baseData.activeKind]
|
||||
|
||||
return {
|
||||
title: baseData.title,
|
||||
activeKind: baseData.activeKind,
|
||||
filterItems: createFilterItems(baseData.kinds),
|
||||
items,
|
||||
emptyTitle: emptyCopy.title,
|
||||
emptyDescription: emptyCopy.description
|
||||
}
|
||||
}
|
||||
|
||||
function showNavigate(route) {
|
||||
openStaticRoute(route, wx)
|
||||
}
|
||||
|
||||
Page({
|
||||
data: createTcmAssetsPageData('notes'),
|
||||
|
||||
onLoad(options) {
|
||||
this.setData(
|
||||
createTcmAssetsPageData(
|
||||
resolveKind(options.kind, ['notes', 'bookshelf', 'favorites', 'history'], 'notes')
|
||||
)
|
||||
)
|
||||
},
|
||||
|
||||
handleFilterTap(event) {
|
||||
const { kind } = event.currentTarget.dataset
|
||||
|
||||
this.setData(createTcmAssetsPageData(kind))
|
||||
},
|
||||
|
||||
handleEntryTap(event) {
|
||||
showNavigate(event.currentTarget.dataset.route)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
createTcmAssetsPageData
|
||||
}
|
||||
5
packages/tcm/pages/assets/index.json
Normal file
5
packages/tcm/pages/assets/index.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"navigationBarTitleText": "学习资产",
|
||||
"navigationBarBackgroundColor": "#f8ecd8",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
36
packages/tcm/pages/assets/index.wxml
Normal file
36
packages/tcm/pages/assets/index.wxml
Normal file
@@ -0,0 +1,36 @@
|
||||
<view class="asset-page">
|
||||
<view class="asset-page__header">
|
||||
<text class="asset-page__title">{{title}}</text>
|
||||
</view>
|
||||
|
||||
<view class="asset-page__filters">
|
||||
<view
|
||||
class="asset-page__filter {{activeKind === item.key ? 'asset-page__filter--active' : ''}}"
|
||||
wx:for="{{filterItems}}"
|
||||
wx:key="key"
|
||||
data-kind="{{item.key}}"
|
||||
bindtap="handleFilterTap"
|
||||
>
|
||||
<text class="asset-page__filter-label">{{item.label}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{items.length}}" class="asset-page__list">
|
||||
<view
|
||||
class="asset-card"
|
||||
wx:for="{{items}}"
|
||||
wx:key="key"
|
||||
data-route="{{item.route}}"
|
||||
bindtap="handleEntryTap"
|
||||
>
|
||||
<text class="asset-card__title">{{item.title}}</text>
|
||||
<text class="asset-card__subtitle">{{item.subtitle}}</text>
|
||||
<text class="asset-card__description">{{item.description}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="asset-page__empty">
|
||||
<text class="asset-page__empty-title">{{emptyTitle}}</text>
|
||||
<text class="asset-page__empty-description">{{emptyDescription}}</text>
|
||||
</view>
|
||||
</view>
|
||||
80
packages/tcm/pages/assets/index.wxss
Normal file
80
packages/tcm/pages/assets/index.wxss
Normal file
@@ -0,0 +1,80 @@
|
||||
page {
|
||||
min-height: 100%;
|
||||
background: linear-gradient(180deg, #faf3e8 0%, #f1e9dd 100%);
|
||||
}
|
||||
|
||||
.asset-page {
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
padding: 28rpx 20rpx 72rpx;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(177, 130, 74, 0.14) 0%, rgba(177, 130, 74, 0) 24%),
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.54) 0%, rgba(255, 249, 240, 0) 38%);
|
||||
}
|
||||
|
||||
.asset-page__header {
|
||||
padding: 8rpx 0 22rpx;
|
||||
}
|
||||
|
||||
.asset-page__title {
|
||||
display: block;
|
||||
color: #2f1f12;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 56rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.asset-page__filters {
|
||||
margin: 0 -6rpx 14rpx;
|
||||
}
|
||||
|
||||
.asset-page__filter {
|
||||
display: inline-block;
|
||||
padding: 6rpx;
|
||||
}
|
||||
|
||||
.asset-page__filter-label {
|
||||
display: block;
|
||||
padding: 14rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(111, 66, 22, 0.08);
|
||||
color: #6f4216;
|
||||
font-size: 24rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.asset-page__filter--active .asset-page__filter-label {
|
||||
background: linear-gradient(135deg, #a56a31 0%, #7c4b1d 100%);
|
||||
color: #fff7eb;
|
||||
}
|
||||
|
||||
.asset-card,
|
||||
.asset-page__empty {
|
||||
margin-top: 16rpx;
|
||||
padding: 26rpx;
|
||||
border: 1rpx solid rgba(118, 83, 42, 0.08);
|
||||
border-radius: 32rpx;
|
||||
background: rgba(255, 250, 242, 0.92);
|
||||
box-shadow: 0 18rpx 42rpx rgba(86, 58, 25, 0.08);
|
||||
}
|
||||
|
||||
.asset-card__title,
|
||||
.asset-page__empty-title {
|
||||
display: block;
|
||||
color: #2c2419;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.asset-card__subtitle,
|
||||
.asset-card__description,
|
||||
.asset-page__empty-description {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
color: #7c705e;
|
||||
font-size: 26rpx;
|
||||
line-height: 1.7;
|
||||
}
|
||||
Reference in New Issue
Block a user