feat: add multi-source breed encyclopedia and two-hour refresh sessions
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
const { loadBreeds, groupBreeds } = require("../../utils/breeds");
|
||||
Page({
|
||||
data: {
|
||||
groups: [],
|
||||
query: "",
|
||||
loading: true,
|
||||
error: "",
|
||||
total: 0,
|
||||
initial: "",
|
||||
},
|
||||
onLoad() {
|
||||
this.load();
|
||||
},
|
||||
async load() {
|
||||
if (this.pending) return;
|
||||
this.pending = true;
|
||||
this.setData({ loading: true, error: "" });
|
||||
try {
|
||||
this.rows = await loadBreeds();
|
||||
this.filter();
|
||||
} catch (error) {
|
||||
this.setData({ error: error.message });
|
||||
} finally {
|
||||
this.pending = false;
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
filter() {
|
||||
let groups = groupBreeds(this.rows || [], this.data.query);
|
||||
if (this.data.initial)
|
||||
groups = groups.filter((g) => g.letter === this.data.initial);
|
||||
this.setData({
|
||||
groups,
|
||||
total: groups.reduce((n, g) => n + g.items.length, 0),
|
||||
});
|
||||
},
|
||||
search(e) {
|
||||
this.setData({ query: e.detail.value, initial: "" });
|
||||
this.filter();
|
||||
},
|
||||
letter(e) {
|
||||
this.setData({ initial: e.currentTarget.dataset.letter });
|
||||
this.filter();
|
||||
},
|
||||
open(e) {
|
||||
wx.navigateTo({
|
||||
url: "/pages/breed-detail/breed-detail?id=" + e.currentTarget.dataset.id,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
{"disableScroll":true,"usingComponents":{"tab-bar":"/components/tab-bar/index"}}
|
||||
@@ -0,0 +1,12 @@
|
||||
<page-layout id="page-layout" title="一起懂它更多">
|
||||
<view class="screen">
|
||||
<view class="knowledge-hero"><text class="eyebrow">肉垫小百科</text><view class="hero-title"><text>每个小伙伴</text><text>都有自己的模样</text></view><text class="hero-copy">从认识品种开始,慢慢读懂它。</text><view class="hero-book"><view class="book-middle"></view><view class="book-stripe"></view></view></view>
|
||||
<input class="knowledge-search" value="{{query}}" bindinput="search" placeholder="搜索犬种、常用名或拼音" maxlength="128" />
|
||||
<scroll-view class="alphabet-scroll" scroll-x enhanced show-scrollbar="{{false}}"><view class="alphabet"><text class="{{initial===''?'selected':''}}" data-letter="" bindtap="letter">全部</text><text wx:for="{{['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']}}" wx:key="*this" class="{{initial===item?'selected':''}}" data-letter="{{item}}" bindtap="letter">{{item}}</text></view></scroll-view>
|
||||
<view class="catalog-heading"><text>犬种百科</text><text class="catalog-count">{{total}} 个小伙伴</text></view>
|
||||
<view wx:if="{{loading}}" class="empty">正在打开小百科…</view>
|
||||
<view wx:elif="{{error}}" class="empty"><text>{{error}}</text><button class="secondary" bindtap="load">重新加载</button></view>
|
||||
<block wx:else><view wx:for="{{groups}}" wx:for-item="group" wx:key="letter"><view class="group-letter">{{group.letter}}</view><view wx:for="{{group.items}}" wx:key="id" class="breed-entry" data-id="{{item.id}}" bindtap="open"><view class="entry-letter">{{item.initial}}</view><view class="entry-copy"><text class="entry-name">{{item.name}}</text><text class="entry-alias">{{item.origin||item.aliases||item.english_name||'点开认识这位小伙伴'}}</text><text class="entry-status">{{item.has_details?'认识它的小性格':'资料整理中'}}</text></view><text class="entry-arrow">›</text></view></view><view wx:if="{{!total}}" class="empty">暂时没找到这个品种,换个名字试试吧。</view></block>
|
||||
</view>
|
||||
</page-layout>
|
||||
<tab-bar current="/pages/knowledge/knowledge" />
|
||||
@@ -0,0 +1,25 @@
|
||||
.knowledge-hero { position:relative;overflow:hidden;padding:34rpx;background:#eee8f7;border-radius:34rpx;color:#79658c; }
|
||||
.knowledge-hero .eyebrow {color:#9782aa;letter-spacing:1rpx;}
|
||||
.hero-title {font-size:37rpx;font-weight:600;line-height:1.5;margin:16rpx 0 12rpx;}
|
||||
.hero-copy {font-size:23rpx;}
|
||||
.hero-book {position:absolute;right:45rpx;top:70rpx;width:106rpx;height:94rpx;border:5rpx solid #b4a3c5;border-radius:20rpx 20rpx 8rpx 8rpx;transform:rotate(9deg);background:#fff9f380;}
|
||||
.book-middle {position:absolute;left:48rpx;height:100%;border-left:4rpx solid #b4a3c5;}
|
||||
.book-stripe {position:absolute;left:14rpx;right:14rpx;top:26rpx;height:24rpx;border-top:3rpx solid #b4a3c5;border-bottom:3rpx solid #b4a3c5;}
|
||||
.knowledge-search {height:92rpx;padding:0 28rpx;background:#fff;border-radius:24rpx;margin:28rpx 0 16rpx;font-size:26rpx;}
|
||||
.alphabet-scroll {width:100%;white-space:nowrap;}
|
||||
.alphabet {display:inline-flex;gap:10rpx;padding:4rpx 0 12rpx;}
|
||||
.alphabet text {display:inline-block;padding:10rpx 20rpx;border-radius:16rpx;color:#9d8779;background:#fff;}
|
||||
.alphabet .selected {color:#b95738;background:#ffeadc;}
|
||||
.catalog-heading {display:flex;align-items:center;justify-content:space-between;margin:30rpx 0 8rpx;font-size:32rpx;font-weight:600;}
|
||||
.catalog-count {font-size:23rpx;color:#9d8779;font-weight:400;}
|
||||
.group-letter {color:#b95738;font-size:29rpx;font-weight:600;padding:20rpx 8rpx 12rpx;}
|
||||
.breed-entry {display:flex;align-items:center;gap:20rpx;padding:26rpx;background:#fff;border-radius:26rpx;margin-bottom:14rpx;}
|
||||
.entry-letter {width:66rpx;height:66rpx;display:flex;align-items:center;justify-content:center;flex:none;background:#fff0e2;border-radius:22rpx;color:#ba7355;font-size:30rpx;}
|
||||
.entry-copy {flex:1;min-width:0;}
|
||||
.entry-name {display:block;font-size:27rpx;font-weight:600;}
|
||||
.entry-alias {display:block;color:#9d8779;font-size:21rpx;margin-top:6rpx;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}
|
||||
.entry-arrow {color:#bfa697;font-size:36rpx;}
|
||||
|
||||
.entry-status{display:block;font-size:19rpx;color:#bc9c85;margin-top:6rpx}
|
||||
|
||||
.hero-title>text{display:block}
|
||||
Reference in New Issue
Block a user