feat: 整体页面优化,删除无用svg
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user