feat: 整体页面优化,删除无用svg

This commit is contained in:
Blizzard
2026-02-14 08:32:47 +08:00
parent daea00ca60
commit cbbe82ef63
59 changed files with 1265 additions and 342 deletions
+21 -9
View File
@@ -10,24 +10,18 @@ Page({
onLoad(options) {
const eventChannel = this.getOpenerEventChannel();
let loadedFromEvent = false;
if (eventChannel && eventChannel.on) {
eventChannel.on('acceptDataFromOpenerPage', (res) => {
if (res.data) {
this.setPlantData(res.data);
loadedFromEvent = true;
}
});
}
if (options.id) {
// Give event channel a chance to fire
setTimeout(() => {
if (!loadedFromEvent && !this.data.plant) {
this.loadPlantDetail(options.id);
}
}, 100);
// Always fetch latest data (especially favorites status)
this.loadPlantDetail(options.id);
}
},
@@ -99,7 +93,8 @@ Page({
pestsDiseases: item.pestsDiseases || '',
commonPests,
classes: (item.classes || []).map(c => c.name),
imgList: item.imgList || []
imgList: item.imgList || [],
isFavorited: (item.hasStar === 1 || item.hasStar === '1')
};
this.setData({
@@ -108,6 +103,23 @@ Page({
});
},
toggleFavorite() {
if (!this.data.plant) return;
const { id, isFavorited } = this.data.plant;
const type = isFavorited ? 2 : 1;
request.get('/wiki/star', { id, type }).then(() => {
this.setData({
'plant.isFavorited': !isFavorited
});
wx.showToast({ title: type === 1 ? '已收藏' : '已取消', icon: 'success' });
}).catch(err => {
console.error('Toggle favorite failed', err);
wx.showToast({ title: '操作失败', icon: 'none' });
});
},
onSwiperChange(e) {
this.setData({
activeImageIndex: e.detail.current
+16 -2
View File
@@ -13,14 +13,24 @@
<view class="wd-counter" wx:if="{{swiperList.length > 0}}">
<text>{{activeImageIndex + 1}} / {{swiperList.length}}</text>
</view>
<!-- Share Button -->
<button class="header-share-btn" open-type="share">
<t-icon name="share" size="40rpx" color="#FFF" />
</button>
</view>
<!-- Plant Name Card -->
<view class="wd-name-card">
<view class="wd-name-row">
<text class="wd-name">{{plant.name}}</text>
<text class="wd-name" style="padding-right: 60rpx;">{{plant.name}}</text>
<text class="wd-scientific" wx:if="{{plant.latinName}}">{{plant.latinName}}</text>
</view>
<!-- Collect Button -->
<view class="card-collect-btn" bindtap="toggleFavorite">
<t-icon name="{{plant.isFavorited ? 'heart-filled' : 'heart'}}" size="52rpx" color="{{plant.isFavorited ? '#EF4444' : '#D1D5DB'}}" />
</view>
<view class="wd-badges" wx:if="{{plant.genus || plant.classes.length > 0}}">
<text class="wd-badge" wx:if="{{plant.genus}}">{{plant.genus}}</text>
<text class="wd-badge" wx:for="{{plant.classes}}" wx:key="*this">{{item}}</text>
@@ -37,6 +47,8 @@
<text class="wd-text">{{plant.growthHabit}}</text>
</view>
</view>
<!-- Basic Info -->
<view class="wd-section">
@@ -183,8 +195,10 @@
</view>
</view>
<view style="height: 120rpx;"></view>
<view style="height: 40rpx;"></view>
</scroll-view>
</view>
<!-- Loading -->
+43
View File
@@ -243,3 +243,46 @@ page {
justify-content: center;
background: #F4F6F0;
}
/* Header Share Button */
.header-share-btn {
position: absolute;
top: 24rpx;
right: 24rpx;
width: 72rpx;
height: 72rpx;
background: rgba(0,0,0,0.35);
backdrop-filter: blur(4px);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 20;
border: none;
padding: 0;
line-height: normal;
margin: 0;
}
.header-share-btn::after { border: none; }
.header-share-btn:active {
transform: scale(0.9);
background: rgba(0,0,0,0.5);
transition: transform 0.1s;
}
/* Card Collect Button */
.card-collect-btn {
position: absolute;
top: 32rpx;
right: 32rpx;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
z-index: 20;
}
.card-collect-btn:active {
transform: scale(0.9);
transition: transform 0.1s;
}
+32
View File
@@ -18,6 +18,7 @@ Page({
pageSize: 10,
isLoading: false,
hasMore: true,
scrollTop: 0,
// Modal State
showIdentifyModal: false
@@ -35,6 +36,10 @@ Page({
}
},
onTabItemTap() {
this.setData({ scrollTop: Math.random() * 0.01 });
},
// Fetch categories from API
fetchCategories() {
request.get('/wiki-class/list').then(res => {
@@ -84,6 +89,7 @@ Page({
genus: item.genus || '',
difficulty: item.difficulty || 0,
isHot: item.isHot === 1,
isFavorited: item.hasStar === 1,
image: (item.imgList && item.imgList.length > 0) ? item.imgList[0].url : '',
classes: (item.classes || []).map(c => c.name),
// Pass the full item for detail navigation
@@ -115,6 +121,31 @@ Page({
});
},
// Toggle Favorite
async toggleFavorite(e) {
const id = e.currentTarget.dataset.id;
const index = this.data.displayedList.findIndex(i => i.id === id);
if (index === -1) return;
const item = this.data.displayedList[index];
const type = item.isFavorited ? 2 : 1;
try {
// Attempting consistent API pattern
await request.get('/wiki/star', { id, type });
const key = `displayedList[${index}].isFavorited`;
this.setData({
[key]: !item.isFavorited
});
wx.showToast({ title: type === 1 ? '已收藏' : '已取消', icon: 'success' });
} catch (err) {
console.error('Toggle favorite failed', err);
wx.showToast({ title: '操作失败', icon: 'none' });
}
},
// Search Input Handler (debounced)
onSearchInput(e) {
const value = e.detail.value;
@@ -149,6 +180,7 @@ Page({
goToDetail(e) {
const item = e.currentTarget.dataset.item;
wx.navigateTo({
url: `/pages/wiki/detail/index?id=${item.id}`,
success: (res) => {
+26 -25
View File
@@ -16,38 +16,35 @@
bindscrolltolower="onReachBottom"
enhanced
show-scrollbar="{{false}}"
scroll-top="{{scrollTop}}"
>
<view class="search-section">
<t-search placeholder="搜索植物名称,如:龟背竹" value="{{searchQuery}}" bind:change="onSearchInput" shape="round" />
<view class="search-box-card">
<t-search placeholder="搜索植物名称,如:龟背竹" value="{{searchQuery}}" bind:change="onSearchInput" shape="round" t-class-input-container="search-input-bg" />
</view>
</view>
<!-- Dynamic Categories from API -->
<view class="category-scroll">
<t-tag
variant="{{activeCategory === 'all' ? 'dark' : 'outline'}}"
theme="{{activeCategory === 'all' ? 'primary' : 'default'}}"
shape="mark"
size="medium"
style="margin-right: 16rpx;"
bind:tap="setCategory"
<scroll-view class="category-scroll" scroll-x enable-flex show-scrollbar="{{false}}">
<view
class="category-item {{activeCategory === 'all' ? 'active' : ''}}"
bindtap="setCategory"
data-cat="all"
>
全部
</t-tag>
<t-tag
>
<text>全部</text>
</view>
<view
wx:for="{{categories}}"
wx:key="id"
variant="{{activeCategory === item.id ? 'dark' : 'outline'}}"
theme="{{activeCategory === item.id ? 'primary' : 'default'}}"
shape="mark"
size="medium"
style="margin-right: 16rpx;"
bind:tap="setCategory"
wx:key="id"
class="category-item {{activeCategory === item.id ? 'active' : ''}}"
bindtap="setCategory"
data-cat="{{item.id}}"
>
{{item.name}}
</t-tag>
</view>
>
<text>{{item.name}}</text>
</view>
<!-- Right spacer for scroll -->
<view style="width: 40rpx; flex-shrink: 0;"></view>
</scroll-view>
<view class="wiki-list">
<view wx:for="{{displayedList}}" wx:key="id" class="wiki-card" bindtap="goToDetail" data-item="{{item}}">
@@ -96,7 +93,11 @@
</t-tag>
</view>
</view>
<t-icon name="chevron-right" size="48rpx" color="#ccc" />
<!-- Favorite Heart Button -->
<view class="fav-action-btn" catchtap="toggleFavorite" data-id="{{item.id}}" style="padding: 16rpx; margin-right: -16rpx;">
<t-icon name="{{item.isFavorited ? 'heart-filled' : 'heart'}}" size="48rpx" color="{{item.isFavorited ? '#FA5151' : '#CCC'}}" />
</view>
</view>
</view>
+83 -5
View File
@@ -19,15 +19,71 @@
Usually easier to apply padding to the items or a wrapper inside scroll-view. */
.search-section {
padding: 20rpx 40rpx 0;
padding: 24rpx 40rpx 0;
margin-bottom: 32rpx;
}
.search-box-card {
background: #fff;
border-radius: 40rpx;
padding: 16rpx 20rpx;
box-shadow: 0 8rpx 24rpx rgba(85, 139, 47, 0.08); /* Green-tinted shadow */
}
/* Override TDesign Search */
.search-input-bg {
background: #F4F6F0 !important; /* Light green-grey */
border-radius: 32rpx !important;
height: 80rpx !important;
}
.t-search__input-container {
height: 80rpx !important;
}
/* Category Scroll */
.category-scroll {
display: flex;
flex-wrap: wrap;
padding: 0 40rpx;
margin-bottom: 48rpx;
display: flex;
white-space: nowrap;
padding-left: 40rpx;
margin-bottom: 40rpx;
height: 88rpx;
width: 100%;
box-sizing: border-box;
}
/* Hide scrollbar for webkit */
.category-scroll::-webkit-scrollbar {
display: none;
}
.category-item {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 36rpx;
height: 72rpx;
background: #fff;
border-radius: 36rpx;
margin-right: 24rpx;
font-size: 28rpx;
color: #546E7A;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04);
transition: all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);
flex-shrink: 0;
border: 2rpx solid transparent; /* Reserve border space */
}
.category-item:active {
transform: scale(0.95);
}
.category-item.active {
background: #558B2F;
color: #fff;
font-weight: 700;
box-shadow: 0 8rpx 20rpx rgba(85, 139, 47, 0.3);
border-color: #558B2F;
}
.wiki-list {
@@ -59,6 +115,28 @@
box-shadow: 0 8rpx 20rpx rgba(0,0,0,0.1);
flex-shrink: 0;
background: #f0f0f0;
position: relative;
}
.fav-icon-box {
position: absolute;
top: 10rpx;
right: 10rpx;
width: 56rpx;
height: 56rpx;
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(4px);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 5;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
}
.fav-icon-box:active {
transform: scale(0.9);
transition: transform 0.1s;
}
.wiki-image image { width: 100%; height: 100%; display: block; }
.wiki-image-placeholder {