feat: 样式修改
This commit is contained in:
@@ -8,13 +8,23 @@ App({
|
||||
// Send res.code to backend to swap for openId, sessionKey, unionId
|
||||
if (res.code) {
|
||||
request.get('/auth/miniLogin', { code: res.code }).then(data => {
|
||||
// Assuming the token is in data.token or data itself
|
||||
const token = data.token || data;
|
||||
// Response structure based on user input: { user: {...}, token: "...", expiresAt: ... }
|
||||
// Note: request.js might return data.user directly if it unwraps 'data'
|
||||
// But looking at previous request.js usage, it seems to return the 'data' field of the response.
|
||||
// Let's handle both cases safely.
|
||||
|
||||
const token = data.token;
|
||||
const user = data.user;
|
||||
|
||||
if (token && typeof token === 'string') {
|
||||
wx.setStorageSync('token', token);
|
||||
console.log('Login successful, token stored');
|
||||
if (user) {
|
||||
wx.setStorageSync('userInfo', user);
|
||||
this.globalData.userInfo = user;
|
||||
}
|
||||
console.log('Login successful, user info stored');
|
||||
} else {
|
||||
console.warn('Login response did not contain a valid token string', data);
|
||||
console.warn('Login response did not contain a valid token', data);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('Login failed', err);
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"pages/plant-detail/edit/index",
|
||||
"pages/plant-detail/index",
|
||||
"pages/wiki/detail/index",
|
||||
"pages/wiki/identify/index"
|
||||
"pages/wiki/identify/index",
|
||||
"pages/profile/identify-history/index"
|
||||
],
|
||||
"window": {
|
||||
"backgroundTextStyle": "light",
|
||||
|
||||
@@ -4,7 +4,7 @@ page {
|
||||
--primary-light: #9CCC65;
|
||||
--primary-dark: #33691E;
|
||||
--secondary: #8D6E63;
|
||||
--bg-garden: #F1F8E9;
|
||||
--bg-garden: #F4F6F0;
|
||||
--bg-card: rgba(255, 255, 255, 0.9);
|
||||
--text-main: #263238;
|
||||
--text-muted: #78909C;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** pages/community/create/index.wxss **/
|
||||
page {
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
background: #F4F6F0;
|
||||
}
|
||||
|
||||
.create-post-page {
|
||||
|
||||
@@ -125,8 +125,9 @@
|
||||
</scroll-view>
|
||||
|
||||
<!-- Floating Action Button -->
|
||||
<view class="fab" bindtap="goToCreatePost">
|
||||
<t-icon name="add" size="48rpx" color="#fff" />
|
||||
<view class="floating-add-btn" bindtap="goToCreatePost">
|
||||
<t-icon name="add" size="40rpx" color="#FFF" />
|
||||
<text>发布动态</text>
|
||||
</view>
|
||||
|
||||
<!-- Comment Input Mask -->
|
||||
|
||||
+13
-11
@@ -5,7 +5,7 @@ page {
|
||||
}
|
||||
|
||||
.community-page {
|
||||
background-color: #fff;
|
||||
background-color: #F4F6F0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -298,25 +298,27 @@ page {
|
||||
}
|
||||
|
||||
/* Floating Action Button */
|
||||
.fab {
|
||||
.floating-add-btn {
|
||||
position: fixed;
|
||||
right: 40rpx;
|
||||
bottom: 200rpx;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
background: linear-gradient(135deg, #689F38, #558B2F);
|
||||
border-radius: 50%;
|
||||
bottom: 60rpx;
|
||||
background: #558B2F;
|
||||
color: white;
|
||||
padding: 24rpx 40rpx;
|
||||
border-radius: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
box-shadow: 0 12rpx 32rpx rgba(85, 139, 47, 0.4);
|
||||
z-index: 100;
|
||||
transition: all 0.2s;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.fab:active {
|
||||
.floating-add-btn:active {
|
||||
transform: scale(0.92);
|
||||
box-shadow: 0 6rpx 16rpx rgba(85, 139, 47, 0.3);
|
||||
box-shadow: 0 4rpx 16rpx rgba(85, 139, 47, 0.2);
|
||||
}
|
||||
|
||||
/* WeChat Style Action Container */
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "我的花园",
|
||||
"usingComponents": {
|
||||
"t-fab": "tdesign-miniprogram/fab/fab",
|
||||
"t-popup": "tdesign-miniprogram/popup/popup",
|
||||
"t-input": "tdesign-miniprogram/input/input",
|
||||
"t-button": "tdesign-miniprogram/button/button",
|
||||
|
||||
@@ -5,7 +5,7 @@ page {
|
||||
}
|
||||
|
||||
.add-plant-page {
|
||||
background-color: #F5F7F5;
|
||||
background-color: #F4F6F0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -15,7 +15,7 @@ page {
|
||||
.page-content {
|
||||
height: calc(100vh - 140rpx - env(safe-area-inset-bottom));
|
||||
padding: 24rpx 32rpx;
|
||||
background: #F5F7F5;
|
||||
background: #F4F6F0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
/>
|
||||
<view class="header-gradient"></view>
|
||||
|
||||
<!-- Custom Carousel Indicators -->
|
||||
<view class="carousel-indicators">
|
||||
<view wx:for="{{swiperImages}}" wx:key="index" class="carousel-dot {{index === activeImageIndex ? 'active' : ''}}"></view>
|
||||
<!-- Image Counter -->
|
||||
<view class="carousel-counter" wx:if="{{swiperImages.length > 0}}">
|
||||
<text>{{activeImageIndex + 1}} / {{swiperImages.length}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -56,29 +56,21 @@ page {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* Carousel Indicators */
|
||||
.carousel-indicators {
|
||||
/* Image Counter Badge */
|
||||
.carousel-counter {
|
||||
position: absolute;
|
||||
bottom: 100rpx;
|
||||
right: 48rpx;
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
color: white;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
padding: 6rpx 18rpx;
|
||||
border-radius: 12rpx;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.carousel-dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.carousel-dot.active {
|
||||
background: white;
|
||||
width: 24rpx;
|
||||
border-radius: 8rpx;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
.header-info {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import request from '../../../utils/request';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
records: [],
|
||||
loading: true,
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
hasMore: true,
|
||||
expandedId: '', // Track which card is expanded
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadRecords();
|
||||
},
|
||||
|
||||
async loadRecords() {
|
||||
this.setData({ loading: true });
|
||||
try {
|
||||
const res = await request.post('/classify/myClassifyLog', {
|
||||
page: this.data.page,
|
||||
pageSize: this.data.pageSize,
|
||||
});
|
||||
const list = (res.list || []).map(item => this._transformRecord(item));
|
||||
this.setData({
|
||||
records: this.data.page === 1 ? list : [...this.data.records, ...list],
|
||||
total: res.total || 0,
|
||||
hasMore: list.length >= this.data.pageSize,
|
||||
loading: false,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Load identify history failed', err);
|
||||
this.setData({ loading: false });
|
||||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
_transformRecord(item) {
|
||||
const allResults = item.allResults || [];
|
||||
const topResult = allResults[0] || {};
|
||||
const otherResults = allResults.slice(1);
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
time: this._formatTime(item.createdAt),
|
||||
dateStr: item.createdAtStr || '',
|
||||
topName: topResult.name || '未知植物',
|
||||
topScore: topResult.score ? Math.round(topResult.score * 100) : 0,
|
||||
topImage: topResult.baike_info?.image_url || '',
|
||||
topDesc: topResult.baike_info?.description || '',
|
||||
topBaikeUrl: topResult.baike_info?.baike_url || '',
|
||||
otherResults: otherResults.map(r => ({
|
||||
name: r.name || '未知',
|
||||
score: r.score ? Math.round(r.score * 100) : 0,
|
||||
hasInfo: !!r.baike_info,
|
||||
})),
|
||||
};
|
||||
},
|
||||
|
||||
toggleExpand(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
this.setData({
|
||||
expandedId: this.data.expandedId === id ? '' : id,
|
||||
});
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
if (!this.data.hasMore || this.data.loading) return;
|
||||
this.setData({ page: this.data.page + 1 }, () => {
|
||||
this.loadRecords();
|
||||
});
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.setData({ page: 1, hasMore: true }, () => {
|
||||
this.loadRecords().then(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_formatTime(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
const now = new Date();
|
||||
const diffMs = now - d;
|
||||
const diffMin = Math.floor(diffMs / 60000);
|
||||
if (diffMin < 1) return '刚刚';
|
||||
if (diffMin < 60) return diffMin + '分钟前';
|
||||
const diffHour = Math.floor(diffMin / 60);
|
||||
if (diffHour < 24) return diffHour + '小时前';
|
||||
const diffDay = Math.floor(diffHour / 24);
|
||||
if (diffDay < 7) return diffDay + '天前';
|
||||
|
||||
const month = (d.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = d.getDate().toString().padStart(2, '0');
|
||||
const hour = d.getHours().toString().padStart(2, '0');
|
||||
const min = d.getMinutes().toString().padStart(2, '0');
|
||||
return `${month}-${day} ${hour}:${min}`;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"navigationBarTitleText": "识别记录",
|
||||
"usingComponents": {
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-image": "tdesign-miniprogram/image/image",
|
||||
"t-empty": "tdesign-miniprogram/empty/empty",
|
||||
"t-loading": "tdesign-miniprogram/loading/loading"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<view class="history-page">
|
||||
|
||||
<!-- Loading -->
|
||||
<view wx:if="{{loading && records.length === 0}}" class="loading-wrap">
|
||||
<t-loading theme="circular" size="48rpx" text="加载中..." />
|
||||
</view>
|
||||
|
||||
<!-- Empty -->
|
||||
<view wx:elif="{{!loading && records.length === 0}}" class="empty-wrap">
|
||||
<view class="empty-icon">
|
||||
<t-icon name="scan" size="120rpx" color="#D1D5DB" />
|
||||
</view>
|
||||
<text class="empty-title">暂无识别记录</text>
|
||||
<text class="empty-hint">去百科页面拍照识别植物吧</text>
|
||||
</view>
|
||||
|
||||
<!-- Record List -->
|
||||
<view wx:else class="record-list">
|
||||
<view wx:for="{{records}}" wx:key="id" class="record-card" bindtap="toggleExpand" data-id="{{item.id}}">
|
||||
|
||||
<!-- Card Header -->
|
||||
<view class="card-header">
|
||||
<view class="card-thumb">
|
||||
<t-image
|
||||
wx:if="{{item.topImage}}"
|
||||
src="{{item.topImage}}"
|
||||
mode="aspectFill"
|
||||
width="120rpx"
|
||||
height="120rpx"
|
||||
shape="round"
|
||||
/>
|
||||
<view wx:else class="thumb-placeholder">
|
||||
<t-icon name="image" size="48rpx" color="#D1D5DB" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-info">
|
||||
<view class="card-name-row">
|
||||
<text class="card-name">{{item.topName}}</text>
|
||||
<view class="score-badge" style="background: {{item.topScore >= 80 ? '#E8F5E9' : item.topScore >= 50 ? '#FFF8E1' : '#FBE9E7'}}; color: {{item.topScore >= 80 ? '#2E7D32' : item.topScore >= 50 ? '#F57F17' : '#D84315'}}">
|
||||
{{item.topScore}}%
|
||||
</view>
|
||||
</view>
|
||||
<text class="card-time">{{item.time}}</text>
|
||||
<view wx:if="{{item.otherResults.length > 0}}" class="other-hint">
|
||||
<text>还可能是: </text>
|
||||
<text wx:for="{{item.otherResults}}" wx:for-item="other" wx:key="name" class="other-name">{{other.name}}{{index < item.otherResults.length - 1 ? '、' : ''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="expand-arrow {{expandedId === item.id ? 'expanded' : ''}}">
|
||||
<t-icon name="chevron-down" size="32rpx" color="#C5C5C5" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Expanded Detail -->
|
||||
<view wx:if="{{expandedId === item.id}}" class="card-detail">
|
||||
<!-- Description -->
|
||||
<view wx:if="{{item.topDesc}}" class="detail-desc">
|
||||
<text class="desc-text">{{item.topDesc}}</text>
|
||||
</view>
|
||||
|
||||
<!-- All Results -->
|
||||
<view class="detail-results">
|
||||
<text class="detail-label">识别结果排名</text>
|
||||
<view class="result-bars">
|
||||
<!-- Top result -->
|
||||
<view class="result-bar-item">
|
||||
<text class="bar-name">{{item.topName}}</text>
|
||||
<view class="bar-track">
|
||||
<view class="bar-fill top" style="width: {{item.topScore}}%"></view>
|
||||
</view>
|
||||
<text class="bar-score">{{item.topScore}}%</text>
|
||||
</view>
|
||||
<!-- Other results -->
|
||||
<view wx:for="{{item.otherResults}}" wx:for-item="other" wx:key="name" class="result-bar-item">
|
||||
<text class="bar-name">{{other.name}}</text>
|
||||
<view class="bar-track">
|
||||
<view class="bar-fill" style="width: {{other.score}}%"></view>
|
||||
</view>
|
||||
<text class="bar-score">{{other.score}}%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-meta">
|
||||
<t-icon name="time" size="24rpx" color="#9CA3AF" />
|
||||
<text class="meta-text">{{item.dateStr}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- Load More -->
|
||||
<view wx:if="{{loading && records.length > 0}}" class="load-more">
|
||||
<t-loading theme="circular" size="36rpx" text="加载更多..." />
|
||||
</view>
|
||||
<view wx:elif="{{!hasMore && records.length > 0}}" class="no-more">
|
||||
<text>— 没有更多了 —</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
@@ -0,0 +1,278 @@
|
||||
/* pages/profile/identify-history/index.wxss */
|
||||
|
||||
.history-page {
|
||||
min-height: 100vh;
|
||||
background: #F4F6F0;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Loading & Empty */
|
||||
.loading-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 200rpx;
|
||||
}
|
||||
|
||||
.empty-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 200rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
background: #F3F4F6;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.empty-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #6B7280;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
font-size: 26rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* Record List */
|
||||
.record-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
padding-bottom: 60rpx;
|
||||
}
|
||||
|
||||
.record-card {
|
||||
background: #fff;
|
||||
border-radius: 28rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.02);
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.record-card:active {
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* Card Header */
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.card-thumb {
|
||||
flex-shrink: 0;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.thumb-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #F3F4F6;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.card-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.card-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.score-badge {
|
||||
flex-shrink: 0;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.card-time {
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.other-hint {
|
||||
font-size: 22rpx;
|
||||
color: #9CA3AF;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.other-name {
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.expand-arrow {
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
padding: 8rpx;
|
||||
}
|
||||
|
||||
.expand-arrow.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Card Detail (Expanded) */
|
||||
.card-detail {
|
||||
margin-top: 28rpx;
|
||||
padding-top: 28rpx;
|
||||
border-top: 2rpx solid #F3F4F6;
|
||||
animation: fadeSlideDown 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeSlideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-16rpx);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Description */
|
||||
.detail-desc {
|
||||
background: #F4F6F0;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.desc-text {
|
||||
font-size: 26rpx;
|
||||
line-height: 1.7;
|
||||
color: #4B5563;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 4;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Result Bars */
|
||||
.detail-results {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #6B7280;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.result-bars {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.result-bar-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.bar-name {
|
||||
width: 120rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bar-track {
|
||||
flex: 1;
|
||||
height: 16rpx;
|
||||
background: #F3F4F6;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bar-fill {
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
background: linear-gradient(90deg, #A5D6A7, #66BB6A);
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.bar-fill.top {
|
||||
background: linear-gradient(90deg, #66BB6A, #388E3C);
|
||||
}
|
||||
|
||||
.bar-score {
|
||||
width: 80rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #6B7280;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Meta */
|
||||
.detail-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding-top: 16rpx;
|
||||
}
|
||||
|
||||
.meta-text {
|
||||
font-size: 22rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* Load More */
|
||||
.load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 32rpx 0;
|
||||
}
|
||||
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 32rpx 0;
|
||||
font-size: 24rpx;
|
||||
color: #D1D5DB;
|
||||
}
|
||||
+290
-74
@@ -1,52 +1,163 @@
|
||||
// pages/profile/index.js
|
||||
import { MOCK_FAVORITES, MOCK_BADGES, MOCK_POSTS } from '../../utils/mockData';
|
||||
import request from '../../utils/request';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
Page({
|
||||
data: {
|
||||
view: 'profile', // profile, favorites, posts, badges
|
||||
favTab: 'all', // all, plant, article
|
||||
postsTab: 'published', // published, drafts
|
||||
view: 'profile', // profile, favorites, posts, about
|
||||
|
||||
// User Info
|
||||
userName: '植物爱好者',
|
||||
userAvatar: '',
|
||||
userLevel: '', // Reserved for future level system
|
||||
userLevelTag: '', // e.g. 'Lv.4 资深植人'
|
||||
|
||||
// Stats
|
||||
plantCount: 0,
|
||||
taskDoneCount: 0,
|
||||
postCount: 0,
|
||||
|
||||
// Favorites
|
||||
favTab: 'all',
|
||||
favorites: [],
|
||||
filteredFavorites: [],
|
||||
|
||||
// Posts
|
||||
postsTab: 'published',
|
||||
myPublishedPosts: [],
|
||||
myDrafts: [],
|
||||
badges: []
|
||||
|
||||
// App version
|
||||
appVersion: '1.0.0'
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({
|
||||
favorites: MOCK_FAVORITES,
|
||||
badges: MOCK_BADGES
|
||||
});
|
||||
this.filterFavorites();
|
||||
onLoad() {
|
||||
this.loadUserInfo();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (typeof this.getTabBar === 'function' &&
|
||||
this.getTabBar()) {
|
||||
this.getTabBar().setData({
|
||||
selected: 4 // Index 4 is Profile
|
||||
})
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
this.getTabBar().setData({ selected: 4 });
|
||||
}
|
||||
|
||||
// Refresh posts data
|
||||
this.loadMyPosts();
|
||||
this.loadDrafts();
|
||||
},
|
||||
|
||||
// ======== User Info ========
|
||||
loadUserInfo() {
|
||||
// Try to get from globalData or storage
|
||||
const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo');
|
||||
if (userInfo && userInfo.name) {
|
||||
this.setData({
|
||||
userName: userInfo.name || '植物爱好者',
|
||||
userAvatar: userInfo.avatarUrl || userInfo.avatar || ''
|
||||
});
|
||||
return; // Use cached data, no API call
|
||||
}
|
||||
|
||||
// Only fetch from backend if no cached info
|
||||
request.get('/user/info').then(user => {
|
||||
if (!user) return;
|
||||
const avatarUrl = user.avatar ? user.avatar.url : '';
|
||||
this.setData({
|
||||
userName: user.name || '植物爱好者',
|
||||
userAvatar: avatarUrl
|
||||
});
|
||||
const info = {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
avatarUrl: avatarUrl,
|
||||
account: user.account,
|
||||
phone: user.phone,
|
||||
avatarId: user.avatarId
|
||||
};
|
||||
app.globalData.userInfo = info;
|
||||
wx.setStorageSync('userInfo', info);
|
||||
}).catch(() => { });
|
||||
},
|
||||
|
||||
// ======== Stats ========
|
||||
loadStats() {
|
||||
// Fetch plant count
|
||||
request.post('/plant/page', { current: 1, pageSize: 1 }).then(res => {
|
||||
this.setData({ plantCount: res.total || 0 });
|
||||
}).catch(() => { });
|
||||
|
||||
// Fetch post count - user's own posts
|
||||
request.post('/post/page', { current: 1, pageSize: 1, onlyMine: true }).then(res => {
|
||||
this.setData({ postCount: res.total || 0 });
|
||||
}).catch(() => { });
|
||||
|
||||
// Fetch completed tasks count
|
||||
request.get('/plant/taskCount').then(res => {
|
||||
this.setData({ taskDoneCount: res || 0 });
|
||||
}).catch(() => { });
|
||||
},
|
||||
|
||||
// ======== Navigation ========
|
||||
setView(e) {
|
||||
const view = e.currentTarget.dataset.view;
|
||||
this.setData({ view });
|
||||
|
||||
if (view === 'favorites') {
|
||||
this.loadFavorites();
|
||||
} else if (view === 'posts') {
|
||||
this.loadMyPosts();
|
||||
this.loadDrafts();
|
||||
}
|
||||
},
|
||||
|
||||
goBack() {
|
||||
this.setData({ view: 'profile' });
|
||||
},
|
||||
|
||||
// ======== Favorites ========
|
||||
loadFavorites() {
|
||||
// TODO: Call favorites API when available
|
||||
// request.get('/user/favorites').then(...)
|
||||
this.filterFavorites();
|
||||
},
|
||||
|
||||
onFavTabChange(e) {
|
||||
this.setData({ favTab: e.detail.value }, () => {
|
||||
this.filterFavorites();
|
||||
});
|
||||
},
|
||||
|
||||
filterFavorites() {
|
||||
const { favorites, favTab } = this.data;
|
||||
const filtered = favorites.filter(item => {
|
||||
if (favTab === 'all') return true;
|
||||
return item.type === favTab;
|
||||
});
|
||||
this.setData({ filteredFavorites: filtered });
|
||||
},
|
||||
|
||||
// ======== Posts ========
|
||||
loadMyPosts() {
|
||||
// Get published posts by current user
|
||||
const myPosts = MOCK_POSTS.filter(p => p.user === '我的花园');
|
||||
this.setData({ myPublishedPosts: myPosts });
|
||||
request.post('/post/page', { current: 1, pageSize: 50, onlyMine: true }).then(res => {
|
||||
const records = res.records || res.list || [];
|
||||
const posts = records.map(item => {
|
||||
const publisher = item.publisher || {};
|
||||
const imgList = item.imgList || [];
|
||||
return {
|
||||
id: item.id,
|
||||
content: item.content || '',
|
||||
time: this._formatTime(item.createdAt || item.createTime),
|
||||
images: imgList.map(img => img.url),
|
||||
likes: item.likeList || [],
|
||||
comments: item.commentList || []
|
||||
};
|
||||
});
|
||||
this.setData({ myPublishedPosts: posts });
|
||||
}).catch(() => {
|
||||
this.setData({ myPublishedPosts: [] });
|
||||
});
|
||||
},
|
||||
|
||||
loadDrafts() {
|
||||
// Load drafts from storage
|
||||
try {
|
||||
const draft = wx.getStorageSync('post_draft');
|
||||
if (draft && (draft.content || (draft.images && draft.images.length > 0))) {
|
||||
// Convert single draft to array for consistency
|
||||
this.setData({
|
||||
myDrafts: [{
|
||||
id: 'draft_1',
|
||||
@@ -63,39 +174,10 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
setView(e) {
|
||||
const view = e.currentTarget.dataset.view;
|
||||
this.setData({ view });
|
||||
|
||||
// Refresh data when entering posts view
|
||||
if (view === 'posts') {
|
||||
this.loadMyPosts();
|
||||
this.loadDrafts();
|
||||
}
|
||||
},
|
||||
|
||||
onFavTabChange(e) {
|
||||
const tab = e.detail.value;
|
||||
this.setData({ favTab: tab }, () => {
|
||||
this.filterFavorites();
|
||||
});
|
||||
},
|
||||
|
||||
onPostsTabChange(e) {
|
||||
const tab = e.detail.value;
|
||||
this.setData({ postsTab: tab });
|
||||
this.setData({ postsTab: e.detail.value });
|
||||
},
|
||||
|
||||
filterFavorites() {
|
||||
const { favorites, favTab } = this.data;
|
||||
const filtered = favorites.filter(item => {
|
||||
if (favTab === 'all') return true;
|
||||
return item.type === favTab;
|
||||
});
|
||||
this.setData({ filteredFavorites: filtered });
|
||||
},
|
||||
|
||||
// Delete a published post
|
||||
deletePost(e) {
|
||||
const postId = e.currentTarget.dataset.id;
|
||||
wx.showModal({
|
||||
@@ -103,42 +185,176 @@ Page({
|
||||
content: '确定要删除这条动态吗?',
|
||||
confirmColor: '#EF5350',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// Remove from MOCK_POSTS
|
||||
const idx = MOCK_POSTS.findIndex(p => p.id === postId);
|
||||
if (idx > -1) {
|
||||
MOCK_POSTS.splice(idx, 1);
|
||||
}
|
||||
if (!res.confirm) return;
|
||||
wx.showLoading({ title: '删除中...' });
|
||||
request.get('/post/delete', { id: postId }).then(() => {
|
||||
wx.hideLoading();
|
||||
this.loadMyPosts();
|
||||
wx.showToast({ title: '已删除', icon: 'success' });
|
||||
}
|
||||
}).catch(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '删除失败', icon: 'none' });
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Edit a draft
|
||||
editDraft(e) {
|
||||
// Navigate to create page, which will load the draft
|
||||
wx.navigateTo({
|
||||
url: '/pages/community/create/index'
|
||||
});
|
||||
editDraft() {
|
||||
wx.navigateTo({ url: '/pages/community/create/index' });
|
||||
},
|
||||
|
||||
// Delete a draft
|
||||
deleteDraft(e) {
|
||||
deleteDraft() {
|
||||
wx.showModal({
|
||||
title: '删除草稿',
|
||||
content: '确定要删除这份草稿吗?',
|
||||
confirmColor: '#EF5350',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
wx.removeStorageSync('post_draft');
|
||||
} catch (e) { }
|
||||
if (!res.confirm) return;
|
||||
try { wx.removeStorageSync('post_draft'); } catch (e) { }
|
||||
this.setData({ myDrafts: [] });
|
||||
wx.showToast({ title: '已删除', icon: 'success' });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// ======== Menu Actions ========
|
||||
goToIdentifyHistory() {
|
||||
wx.navigateTo({ url: '/pages/profile/identify-history/index' });
|
||||
},
|
||||
|
||||
goToNotificationSettings() {
|
||||
// Open WeChat notification settings
|
||||
wx.openSetting({
|
||||
success: (res) => {
|
||||
console.log('Settings opened', res);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
goToAbout() {
|
||||
this.setData({ view: 'about' });
|
||||
},
|
||||
|
||||
goToAgreement() {
|
||||
// TODO: Navigate to agreement page or show inline
|
||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||
},
|
||||
|
||||
goToPrivacy() {
|
||||
// TODO: Navigate to privacy page or show inline
|
||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||
},
|
||||
|
||||
// ======== Profile Editor Popup ========
|
||||
openProfileEditor() {
|
||||
this.setData({
|
||||
showProfileEditor: true,
|
||||
tempAvatar: '',
|
||||
tempNickname: this.data.userName === '植物爱好者' ? '' : this.data.userName
|
||||
});
|
||||
},
|
||||
|
||||
closeProfileEditor() {
|
||||
this.setData({ showProfileEditor: false });
|
||||
},
|
||||
|
||||
onProfilePopupChange(e) {
|
||||
if (!e.detail.visible) {
|
||||
this.setData({ showProfileEditor: false });
|
||||
}
|
||||
},
|
||||
|
||||
// WeChat native chooseAvatar callback
|
||||
onChooseAvatar(e) {
|
||||
const avatarUrl = e.detail.avatarUrl;
|
||||
if (avatarUrl) {
|
||||
this.setData({ tempAvatar: avatarUrl });
|
||||
}
|
||||
},
|
||||
|
||||
onNicknameInput(e) {
|
||||
this.setData({ tempNickname: e.detail.value });
|
||||
},
|
||||
|
||||
onNicknameBlur(e) {
|
||||
// WeChat nickname type may return value on blur
|
||||
if (e.detail.value) {
|
||||
this.setData({ tempNickname: e.detail.value });
|
||||
}
|
||||
},
|
||||
|
||||
async saveProfile() {
|
||||
const { tempAvatar, tempNickname } = this.data;
|
||||
|
||||
if (!tempAvatar && !tempNickname) {
|
||||
wx.showToast({ title: '请选择头像或输入昵称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
wx.showLoading({ title: '保存中...', mask: true });
|
||||
|
||||
try {
|
||||
const updatePayload = {};
|
||||
|
||||
// 1. Upload avatar if changed
|
||||
if (tempAvatar) {
|
||||
const data = await request.upload(tempAvatar);
|
||||
const fileData = data?.file || {};
|
||||
if (fileData.id) {
|
||||
updatePayload.avatar_id = fileData.id;
|
||||
// Update local display
|
||||
this.setData({ userAvatar: fileData.url || tempAvatar });
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Set name if provided
|
||||
if (tempNickname) {
|
||||
updatePayload.name = tempNickname;
|
||||
this.setData({ userName: tempNickname });
|
||||
}
|
||||
|
||||
// 3. Call update API
|
||||
if (Object.keys(updatePayload).length > 0) {
|
||||
await request.post('/user/update', updatePayload);
|
||||
}
|
||||
|
||||
wx.hideLoading();
|
||||
this.setData({ showProfileEditor: false });
|
||||
wx.showToast({ title: '资料已更新', icon: 'success' });
|
||||
|
||||
// Update globalData
|
||||
const userInfo = app.globalData.userInfo || {};
|
||||
if (updatePayload.name) userInfo.name = updatePayload.name;
|
||||
if (updatePayload.avatar_id) userInfo.avatarId = updatePayload.avatar_id;
|
||||
app.globalData.userInfo = userInfo;
|
||||
} catch (err) {
|
||||
wx.hideLoading();
|
||||
console.error('Save profile failed', err);
|
||||
wx.showToast({ title: '保存失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// ======== Utilities ========
|
||||
_formatTime(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
const now = new Date();
|
||||
const diffMs = now - d;
|
||||
const diffMin = Math.floor(diffMs / 60000);
|
||||
if (diffMin < 1) return '刚刚';
|
||||
if (diffMin < 60) return diffMin + '分钟前';
|
||||
const diffHour = Math.floor(diffMin / 60);
|
||||
if (diffHour < 24) return diffHour + '小时前';
|
||||
const diffDay = Math.floor(diffHour / 24);
|
||||
if (diffDay < 7) return diffDay + '天前';
|
||||
|
||||
const month = (d.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = d.getDate().toString().padStart(2, '0');
|
||||
return `${month}-${day}`;
|
||||
},
|
||||
|
||||
// ======== Reserved: Future Level/Badge System ========
|
||||
// These methods will be implemented when the backend supports level/badge APIs
|
||||
// loadLevelInfo() { request.get('/user/level').then(...) },
|
||||
// loadBadges() { request.get('/user/badges').then(...) },
|
||||
})
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
{
|
||||
"navigationBarTitleText": "个人中心",
|
||||
"disableScroll": true,
|
||||
"usingComponents": {
|
||||
"t-grid": "tdesign-miniprogram/grid/grid",
|
||||
"t-grid-item": "tdesign-miniprogram/grid-item/grid-item",
|
||||
"t-cell": "tdesign-miniprogram/cell/cell",
|
||||
"t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
|
||||
"t-avatar": "tdesign-miniprogram/avatar/avatar",
|
||||
"t-image": "tdesign-miniprogram/image/image",
|
||||
"t-tag": "tdesign-miniprogram/tag/tag",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-badge": "tdesign-miniprogram/badge/badge",
|
||||
"t-progress": "tdesign-miniprogram/progress/progress"
|
||||
"t-tabs": "tdesign-miniprogram/tabs/tabs",
|
||||
"t-tab-panel": "tdesign-miniprogram/tab-panel/tab-panel",
|
||||
"t-button": "tdesign-miniprogram/button/button",
|
||||
"t-popup": "tdesign-miniprogram/popup/popup"
|
||||
}
|
||||
}
|
||||
+203
-123
@@ -1,117 +1,77 @@
|
||||
<wxs src="../../utils/tools.wxs" module="tools" />
|
||||
<view class="profile-page">
|
||||
<!-- Sub-views handled by conditional rendering to match prototype single-page feel -->
|
||||
|
||||
<!-- FAVORITES VIEW -->
|
||||
<view wx:if="{{view === 'favorites'}}" class="favorites-page info-view-anim">
|
||||
<view class="back-nav sticky-nav">
|
||||
<t-button variant="text" icon="arrow-left" bind:tap="setView" data-view="profile">我的收藏</t-button>
|
||||
<!-- ======== FAVORITES VIEW ======== -->
|
||||
<view wx:if="{{view === 'favorites'}}" class="sub-view info-view-anim">
|
||||
<view class="sub-nav" bindtap="goBack">
|
||||
<t-icon name="chevron-left" size="40rpx" />
|
||||
<text class="sub-nav-title">我的收藏</text>
|
||||
</view>
|
||||
|
||||
<t-tabs value="{{favTab}}" bind:change="onFavTabChange" theme="card">
|
||||
<t-tab-panel label="全部" value="all" />
|
||||
<t-tab-panel label="植物" value="plant" />
|
||||
<t-tab-panel label="文章" value="article" />
|
||||
</t-tabs>
|
||||
<view class="category-filter">
|
||||
<view class="filter-chip {{favTab === 'all' ? 'active' : ''}}" bindtap="onFavTabChange" data-value="all">全部</view>
|
||||
<view class="filter-chip {{favTab === 'plant' ? 'active' : ''}}" bindtap="onFavTabChange" data-value="plant">植物</view>
|
||||
<view class="filter-chip {{favTab === 'article' ? 'active' : ''}}" bindtap="onFavTabChange" data-value="article">文章</view>
|
||||
</view>
|
||||
|
||||
<view class="tab-content">
|
||||
<view class="fav-grid">
|
||||
<block wx:if="{{filteredFavorites.length > 0}}">
|
||||
<scroll-view scroll-y class="sub-scroll">
|
||||
<view wx:if="{{filteredFavorites.length > 0}}" class="fav-grid">
|
||||
<view wx:for="{{filteredFavorites}}" wx:key="id" class="fav-card">
|
||||
<t-image src="{{item.image}}" class="fav-img" mode="aspectFill" width="100%" height="240rpx" />
|
||||
<t-image src="{{item.image}}" mode="aspectFill" width="100%" height="240rpx" class="fav-img" />
|
||||
<view class="fav-info">
|
||||
<text class="fav-name">{{item.name}}</text>
|
||||
<view class="fav-meta-row">
|
||||
<t-icon name="{{item.type === 'plant' ? 'heart' : 'book'}}" size="32rpx" color="#90A4AE" />
|
||||
<t-icon name="{{item.type === 'plant' ? 'heart' : 'book'}}" size="28rpx" color="#90A4AE" />
|
||||
<text class="fav-type">{{item.meta}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="empty-state">
|
||||
<t-icon name="star" size="64rpx" color="#ccc" />
|
||||
<text style="margin-top: 16rpx;">暂无收藏内容</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<view wx:else class="empty-state">
|
||||
<text class="empty-text">暂无收藏内容</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- POSTS VIEW -->
|
||||
<view wx:elif="{{view === 'posts'}}" class="posts-page-detail info-view-anim">
|
||||
<view class="back-nav sticky-nav">
|
||||
<t-button variant="text" icon="arrow-left" bind:tap="setView" data-view="profile">我的发布</t-button>
|
||||
<!-- ======== POSTS VIEW ======== -->
|
||||
<view wx:elif="{{view === 'posts'}}" class="sub-view info-view-anim">
|
||||
<view class="sub-nav" bindtap="goBack">
|
||||
<t-icon name="chevron-left" size="40rpx" />
|
||||
<text class="sub-nav-title">我的发布</text>
|
||||
</view>
|
||||
|
||||
<!-- Tabs for Published / Drafts -->
|
||||
<t-tabs value="{{postsTab}}" bind:change="onPostsTabChange" theme="card">
|
||||
<t-tab-panel label="已发布" value="published" />
|
||||
<t-tab-panel label="草稿箱" value="drafts" />
|
||||
</t-tabs>
|
||||
|
||||
<!-- Published Posts -->
|
||||
<view wx:if="{{postsTab === 'published'}}" class="my-posts-list">
|
||||
<block wx:if="{{myPublishedPosts.length > 0}}">
|
||||
<scroll-view scroll-y class="sub-scroll">
|
||||
<view wx:for="{{myPublishedPosts}}" wx:key="id" class="my-post-card">
|
||||
<view class="my-post-time">{{item.time}}</view>
|
||||
<view class="my-post-content-wrap">
|
||||
<text class="post-text">{{item.content}}</text>
|
||||
<view wx:if="{{item.images.length > 0}}" class="my-post-images">
|
||||
<t-image wx:for="{{item.images}}" wx:for-item="img" wx:key="*this" src="{{img}}" mode="aspectFill" width="160rpx" height="160rpx" style="margin-right: 16rpx; display: inline-block; border-radius: 8rpx;" />
|
||||
<t-image wx:for="{{item.images}}" wx:for-item="img" wx:key="*this"
|
||||
src="{{img}}" mode="aspectFill" width="140rpx" height="140rpx"
|
||||
shape="round" />
|
||||
</view>
|
||||
<view class="my-post-footer">
|
||||
<view class="footer-item"><t-icon name="heart" size="32rpx" /> <text>{{item.likes.length}}</text></view>
|
||||
<view class="footer-item"><t-icon name="chat" size="32rpx" /> <text>{{item.comments.length}}</text></view>
|
||||
<view class="footer-item delete-btn" bindtap="deletePost" data-id="{{item.id}}"><t-icon name="delete" size="32rpx" color="#EF5350" /></view>
|
||||
<view class="footer-item"><t-icon name="heart" size="28rpx" /> <text>{{item.likes.length}}</text></view>
|
||||
<view class="footer-item"><t-icon name="chat" size="28rpx" /> <text>{{item.comments.length}}</text></view>
|
||||
<view class="footer-item" catchtap="deletePost" data-id="{{item.id}}" style="margin-left:auto; color: #EF5350;">
|
||||
<t-icon name="delete" size="28rpx" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view wx:else class="empty-state">
|
||||
<t-icon name="file-copy" size="64rpx" color="#ccc" />
|
||||
<text style="margin-top: 16rpx;">暂无已发布的动态</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- Draft Posts -->
|
||||
<view wx:if="{{postsTab === 'drafts'}}" class="my-posts-list">
|
||||
<block wx:if="{{myDrafts.length > 0}}">
|
||||
<view wx:for="{{myDrafts}}" wx:key="id" class="my-post-card draft-card">
|
||||
<view class="draft-badge">草稿</view>
|
||||
<view class="my-post-content-wrap">
|
||||
<text class="post-text">{{item.content || '(无文字内容)'}}</text>
|
||||
<view wx:if="{{item.images.length > 0}}" class="my-post-images">
|
||||
<t-image wx:for="{{item.images}}" wx:for-item="img" wx:key="*this" src="{{img}}" mode="aspectFill" width="160rpx" height="160rpx" style="margin-right: 16rpx; display: inline-block; border-radius: 8rpx;" />
|
||||
</view>
|
||||
<view class="my-post-footer">
|
||||
<view class="footer-item edit-btn" bindtap="editDraft" data-index="{{index}}">
|
||||
<t-icon name="edit" size="32rpx" color="#558B2F" />
|
||||
<text style="color: #558B2F;">编辑</text>
|
||||
</view>
|
||||
<view class="footer-item delete-btn" bindtap="deleteDraft" data-index="{{index}}">
|
||||
<t-icon name="delete" size="32rpx" color="#EF5350" />
|
||||
<text style="color: #EF5350;">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view wx:else class="empty-state">
|
||||
<t-icon name="file-add" size="64rpx" color="#ccc" />
|
||||
<text style="margin-top: 16rpx;">暂无草稿</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- ======== BADGES VIEW ======== -->
|
||||
<view wx:elif="{{view === 'badges'}}" class="sub-view info-view-anim">
|
||||
<view class="sub-nav" bindtap="goBack">
|
||||
<t-icon name="chevron-left" size="40rpx" />
|
||||
<text class="sub-nav-title">成就徽章</text>
|
||||
</view>
|
||||
|
||||
<!-- BADGES VIEW -->
|
||||
<view wx:elif="{{view === 'badges'}}" class="badges-page info-view-anim">
|
||||
<view class="back-nav sticky-nav">
|
||||
<t-button variant="text" icon="arrow-left" bind:tap="setView" data-view="profile">成就徽章</t-button>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="badges-content">
|
||||
<scroll-view scroll-y class="sub-scroll">
|
||||
<!-- Level Card -->
|
||||
<view class="level-card-large">
|
||||
<view class="level-card-bg"></view>
|
||||
<view class="level-header">
|
||||
<view class="level-info-large">
|
||||
<text class="level-label">当前等级</text>
|
||||
@@ -119,82 +79,202 @@
|
||||
</view>
|
||||
<t-icon name="trophy" size="80rpx" color="#FFD700" />
|
||||
</view>
|
||||
|
||||
<view class="level-progress-section">
|
||||
<view class="progress-text">
|
||||
<text>经验值</text>
|
||||
<text>350 / 500</text>
|
||||
</view>
|
||||
<t-progress percentage="70" theme="plump" color="#FFD700" track-color="rgba(255,255,255,0.3)" />
|
||||
<view class="level-progress-bar-bg">
|
||||
<view class="level-progress-bar-fill" style="width: 70%;"></view>
|
||||
</view>
|
||||
<text class="next-level-tip">距离 Lv.5 园艺大师 还需 150 经验</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section-title-badges">所有徽章 (3/6)</view>
|
||||
<t-grid column="{{3}}" gutter="24rpx">
|
||||
<t-grid-item wx:for="{{badges}}" wx:key="id" text="{{item.name}}" description="{{item.desc}}" image="{{item.unlocked ? '/assets/icons/'+item.icon+'.png' : '/assets/icons/lock.png'}}" />
|
||||
<!-- TDesign grid item image might need full path or use slot for svg if needed, using png for now -->
|
||||
</t-grid>
|
||||
|
||||
<view class="badges-grid">
|
||||
<view wx:for="{{badges}}" wx:key="id" class="badge-item {{item.unlocked ? 'unlocked' : 'locked'}}">
|
||||
<view class="badge-icon-circle" style="background: {{item.unlocked ? item.color + '20' : '#F5F5F5'}}">
|
||||
<t-icon wx:if="{{item.unlocked}}" name="{{item.iconName}}" size="48rpx" color="{{item.color}}" />
|
||||
<t-icon wx:else name="lock-on" size="40rpx" color="#BDBDBD" />
|
||||
</view>
|
||||
<text class="badge-name">{{item.name}}</text>
|
||||
<text class="badge-desc">{{item.desc}}</text>
|
||||
<text wx:if="{{item.progress}}" class="badge-progress">{{item.progress}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- MAIN PROFILE VIEW -->
|
||||
<!-- ======== ABOUT VIEW ======== -->
|
||||
<view wx:elif="{{view === 'about'}}" class="sub-view info-view-anim">
|
||||
<view class="sub-nav" bindtap="goBack">
|
||||
<t-icon name="chevron-left" size="40rpx" />
|
||||
<text class="sub-nav-title">关于我们</text>
|
||||
</view>
|
||||
<scroll-view scroll-y class="sub-scroll">
|
||||
<view class="about-section">
|
||||
<view class="about-logo-area">
|
||||
<view class="about-logo">
|
||||
<t-icon name="flower" size="72rpx" color="#558B2F" />
|
||||
</view>
|
||||
<text class="about-app-name">植物护理助手</text>
|
||||
<text class="about-version">版本 {{appVersion}}</text>
|
||||
</view>
|
||||
<view class="about-desc">
|
||||
<text>一款专注于家庭植物养护的小程序。帮助你记录植物成长、制定养护计划、识别未知植物,与花友们分享养花心得。</text>
|
||||
</view>
|
||||
<view class="about-footer">
|
||||
<text class="about-copyright">© 2026 Sundynix · All Rights Reserved</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- ======== MAIN PROFILE VIEW ======== -->
|
||||
<view wx:else class="main-profile-view">
|
||||
<!-- Header -->
|
||||
<view class="profile-header">
|
||||
<view class="user-main">
|
||||
<view class="user-avatar">
|
||||
<t-avatar image="https://api.dicebear.com/7.x/avataaars/svg?seed=Lucky" size="large" />
|
||||
<view class="user-avatar" bindtap="openProfileEditor">
|
||||
<t-avatar wx:if="{{userAvatar}}" image="{{userAvatar}}" size="120rpx" />
|
||||
<t-avatar wx:else icon="user" size="120rpx" />
|
||||
</view>
|
||||
<view class="user-text">
|
||||
<text class="user-name">布偶猫园长</text>
|
||||
<t-tag theme="warning" variant="light" size="small">Lv.4 资深植人</t-tag>
|
||||
<view class="user-text" bindtap="openProfileEditor">
|
||||
<view class="user-name">{{userName}}</view>
|
||||
<view class="level-badge">Lv.4 资深植人</view>
|
||||
</view>
|
||||
</view>
|
||||
<t-icon name="setting" size="48rpx" />
|
||||
<view class="settings-btn" bindtap="goToNotificationSettings">
|
||||
<t-icon name="setting" size="40rpx" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="profile-content">
|
||||
<view class="stats-grid">
|
||||
<view class="stat-col">
|
||||
<text class="stat-num">12</text>
|
||||
<!-- Stats Card (Fixed) -->
|
||||
<view class="stats-section">
|
||||
<view class="stats-card">
|
||||
<view class="stat-item">
|
||||
<text class="stat-num">{{plantCount}}</text>
|
||||
<text class="stat-label">植物</text>
|
||||
</view>
|
||||
<view class="stat-col">
|
||||
<text class="stat-num">328</text>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-num">{{taskDoneCount}}</text>
|
||||
<text class="stat-label">养护</text>
|
||||
</view>
|
||||
<view class="stat-col">
|
||||
<text class="stat-num">15</text>
|
||||
<text class="stat-label">关注</text>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-num">{{postCount}}</text>
|
||||
<text class="stat-label">动态</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="profile-content" enhanced show-scrollbar="{{false}}">
|
||||
<!-- Menu -->
|
||||
<view class="profile-menu">
|
||||
<t-cell-group title="常用功能" theme="card">
|
||||
<t-cell title="我的收藏" hover arrow bind:tap="setView" data-view="favorites">
|
||||
<t-icon slot="left-icon" name="star" color="#FFA000" style="margin-right: 16rpx;" />
|
||||
</t-cell>
|
||||
<t-cell title="我的发布" hover arrow bind:tap="setView" data-view="posts">
|
||||
<t-icon slot="left-icon" name="file-copy" color="#1976D2" style="margin-right: 16rpx;" />
|
||||
</t-cell>
|
||||
<t-cell title="识别记录" hover arrow>
|
||||
<t-icon slot="left-icon" name="scan" color="#388E3C" style="margin-right: 16rpx;" />
|
||||
</t-cell>
|
||||
<t-cell title="成就徽章" note="已获 3 个" hover arrow bind:tap="setView" data-view="badges">
|
||||
<t-icon slot="left-icon" name="control-platform" color="#AB47BC" style="margin-right: 16rpx;" />
|
||||
</t-cell>
|
||||
</t-cell-group>
|
||||
|
||||
<t-cell-group title="更多服务" theme="card" style="margin-top: 24rpx;">
|
||||
<t-cell title="帮助与反馈" hover arrow>
|
||||
<t-icon slot="left-icon" name="help-circle" color="#757575" style="margin-right: 16rpx;" />
|
||||
</t-cell>
|
||||
</t-cell-group>
|
||||
<view class="menu-group-title">常用功能</view>
|
||||
|
||||
<view class="menu-item" bindtap="setView" data-view="favorites">
|
||||
<view class="menu-left">
|
||||
<view class="menu-icon-bg" style="background: #FFF3E0">
|
||||
<t-icon name="star" size="36rpx" color="#FF9800" />
|
||||
</view>
|
||||
<text class="menu-text">我的收藏</text>
|
||||
</view>
|
||||
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
|
||||
</view>
|
||||
|
||||
<!-- Spacer -->
|
||||
<view style="height: 40rpx;"></view>
|
||||
<view class="menu-item" bindtap="setView" data-view="posts">
|
||||
<view class="menu-left">
|
||||
<view class="menu-icon-bg" style="background: #E3F2FD">
|
||||
<t-icon name="file-copy" size="36rpx" color="#2196F3" />
|
||||
</view>
|
||||
<text class="menu-text">我的发布</text>
|
||||
</view>
|
||||
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
|
||||
</view>
|
||||
|
||||
<view class="menu-item" bindtap="goToIdentifyHistory">
|
||||
<view class="menu-left">
|
||||
<view class="menu-icon-bg" style="background: #E8F5E9">
|
||||
<t-icon name="scan" size="36rpx" color="#4CAF50" />
|
||||
</view>
|
||||
<text class="menu-text">识别记录</text>
|
||||
</view>
|
||||
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
|
||||
</view>
|
||||
|
||||
<view class="menu-item" bindtap="setView" data-view="badges">
|
||||
<view class="menu-left">
|
||||
<view class="menu-icon-bg" style="background: #F3E5F5">
|
||||
<t-icon name="award" size="36rpx" color="#9C27B0" />
|
||||
</view>
|
||||
<text class="menu-text">成就徽章</text>
|
||||
</view>
|
||||
<view class="menu-right-info">
|
||||
<text class="menu-badge-text">已获 3 个</text>
|
||||
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-group-title" style="margin-top: 32rpx;">更多服务</view>
|
||||
|
||||
<view class="menu-item" bindtap="goToAbout">
|
||||
<view class="menu-left">
|
||||
<view class="menu-icon-bg" style="background: #F5F5F5">
|
||||
<t-icon name="help-circle" size="36rpx" color="#616161" />
|
||||
</view>
|
||||
<text class="menu-text">帮助与关于</text>
|
||||
</view>
|
||||
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view style="height: 100rpx;"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- Profile Edit Popup -->
|
||||
<t-popup visible="{{showProfileEditor}}" placement="bottom" bind:visible-change="onProfilePopupChange">
|
||||
<view class="profile-edit-popup">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">编辑资料</text>
|
||||
<view class="popup-close" bindtap="closeProfileEditor">
|
||||
<t-icon name="close" size="40rpx" color="#999" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="edit-row" bindtap="onChooseAvatar">
|
||||
<text class="edit-row-label">头像</text>
|
||||
<view class="edit-row-right">
|
||||
<t-avatar
|
||||
wx:if="{{tempAvatar || userAvatar}}"
|
||||
image="{{tempAvatar || userAvatar}}"
|
||||
size="96rpx"
|
||||
/>
|
||||
<t-avatar wx:else icon="user" size="96rpx" />
|
||||
<t-icon name="chevron-right" size="32rpx" color="#C5C5C5" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="edit-row">
|
||||
<text class="edit-row-label">昵称</text>
|
||||
<input
|
||||
class="nickname-input"
|
||||
type="text"
|
||||
placeholder="请输入昵称"
|
||||
placeholder-style="color: #C5C5C5;"
|
||||
value="{{tempNickname}}"
|
||||
bindinput="onNicknameInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="edit-actions">
|
||||
<t-button theme="primary" block shape="round" bind:tap="saveProfile">保存</t-button>
|
||||
</view>
|
||||
</view>
|
||||
</t-popup>
|
||||
|
||||
</view>
|
||||
|
||||
+578
-104
@@ -1,15 +1,49 @@
|
||||
/** pages/profile/index.wxss **/
|
||||
|
||||
.profile-page {
|
||||
background-color: #F4F6F0;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
background: #F4F6F0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
/* ======== Sub-view Navigation ======== */
|
||||
.sub-view {
|
||||
background: #F4F6F0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sub-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
padding: 30rpx 24rpx;
|
||||
background: #fff;
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.sub-nav-title {
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
.sub-scroll {
|
||||
flex: 1;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 80rpx;
|
||||
}
|
||||
|
||||
.info-view-anim {
|
||||
animation: slideInRight 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
animation: slideInRight 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
@@ -17,133 +51,573 @@
|
||||
to { transform: translateX(0); opacity: 1; }
|
||||
}
|
||||
|
||||
.sticky-nav {
|
||||
position: sticky; top: 0; z-index: 100; background: white;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
padding: 20rpx;
|
||||
/* ======== Category Filter (Custom Chips) ======== */
|
||||
.category-filter {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
padding: 0 24rpx 16rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.tab-content { padding: 32rpx; }
|
||||
.filter-chip {
|
||||
padding: 8rpx 24rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 40rpx;
|
||||
font-size: 26rpx;
|
||||
color: #6B7280;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
/* Favorites Grid */
|
||||
.filter-chip.active {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
/* ======== Favorites Grid ======== */
|
||||
.fav-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 24rpx;
|
||||
margin-top: 24rpx;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.fav-card {
|
||||
background: white;
|
||||
border-radius: 24rpx;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.fav-img { width: 100%; display: block; background: #f0f0f0; }
|
||||
|
||||
.fav-info { padding: 20rpx; }
|
||||
.fav-name { font-size: 28rpx; font-weight: 700; color: #37474F; margin-bottom: 12rpx; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.fav-meta-row { display: flex; align-items: center; gap: 8rpx; }
|
||||
.fav-type { font-size: 20rpx; color: #90A4AE; }
|
||||
|
||||
.empty-state {
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||
padding: 80rpx 0; color: #B0BEC5; font-size: 28rpx;
|
||||
.fav-img {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
/* Posts View */
|
||||
.my-posts-list { padding: 40rpx; }
|
||||
.my-post-card { display: flex; gap: 24rpx; margin-bottom: 48rpx; position: relative; }
|
||||
.my-post-time { font-size: 24rpx; color: #B0BEC5; width: 140rpx; flex-shrink: 0; text-align: right; }
|
||||
.my-post-content-wrap { flex: 1; border-left: 4rpx solid #ECEFF1; padding-left: 24rpx; padding-bottom: 24rpx; }
|
||||
.my-post-images { margin: 16rpx 0; white-space: nowrap; overflow-x: auto; }
|
||||
.my-post-footer { display: flex; gap: 32rpx; margin-top: 16rpx; }
|
||||
.footer-item { display: flex; align-items: center; gap: 8rpx; font-size: 24rpx; color: #78909C; }
|
||||
|
||||
/* Draft Card */
|
||||
.draft-card {
|
||||
background: #FFFDE7;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx;
|
||||
margin-left: 0;
|
||||
.fav-info {
|
||||
padding: 16rpx 20rpx;
|
||||
}
|
||||
|
||||
.draft-card .my-post-content-wrap {
|
||||
border-left: 4rpx solid #FFC107;
|
||||
}
|
||||
|
||||
.draft-badge {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #FFC107;
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 8rpx 0 8rpx 0;
|
||||
.fav-name {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Action Buttons */
|
||||
.edit-btn, .delete-btn {
|
||||
cursor: pointer;
|
||||
.fav-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.edit-btn:active, .delete-btn:active {
|
||||
opacity: 0.7;
|
||||
.fav-type {
|
||||
font-size: 22rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* Badges View */
|
||||
.badges-content { padding: 40rpx; background: white; height: 100%; }
|
||||
/* ======== Posts Styles (Refined) ======== */
|
||||
.my-post-card {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.my-post-time {
|
||||
width: 100rpx;
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
font-weight: 500;
|
||||
padding-top: 8rpx;
|
||||
flex-shrink: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.my-post-content-wrap {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
padding: 24rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.02);
|
||||
}
|
||||
|
||||
.post-text {
|
||||
font-size: 28rpx;
|
||||
line-height: 1.5;
|
||||
color: #1F2937;
|
||||
margin-bottom: 16rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.my-post-images {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 16rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.my-post-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 32rpx;
|
||||
border-top: 1rpx solid #F3F4F6;
|
||||
padding-top: 16rpx;
|
||||
}
|
||||
|
||||
.footer-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* ======== Badges View ======== */
|
||||
.level-card-large {
|
||||
background: linear-gradient(135deg, #FFF3E0 0%, #FFE0B2 100%);
|
||||
background: linear-gradient(135deg, #2c3e50 0%, #4ca1af 100%);
|
||||
border-radius: 40rpx;
|
||||
padding: 48rpx;
|
||||
margin-bottom: 60rpx;
|
||||
color: #E65100;
|
||||
}
|
||||
|
||||
.level-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 40rpx; }
|
||||
.level-label { font-size: 26rpx; opacity: 0.8; display: block; }
|
||||
.level-value { font-size: 48rpx; font-weight: 800; display: block; }
|
||||
|
||||
.level-progress-section { }
|
||||
.progress-text { display: flex; justify-content: space-between; font-size: 24rpx; font-weight: 600; margin-bottom: 12rpx; }
|
||||
.next-level-tip { font-size: 22rpx; margin-top: 16rpx; display: block; opacity: 0.8; }
|
||||
|
||||
.section-title-badges { font-size: 32rpx; font-weight: 700; color: #333; margin-bottom: 32rpx; }
|
||||
|
||||
/* Basic TDesign Grid Item styling override if needed */
|
||||
.t-grid-item__content { padding: 24rpx 0 !important; }
|
||||
|
||||
/* Main Profile */
|
||||
.main-profile-view { display: flex; flex-direction: column; height: 100%; }
|
||||
|
||||
.profile-header {
|
||||
padding: 40rpx 48rpx;
|
||||
background: white;
|
||||
display: flex; justify-content: space-between; align-items: flex-start;
|
||||
}
|
||||
|
||||
.user-main { display: flex; align-items: center; gap: 32rpx; }
|
||||
.user-text { display: flex; flex-direction: column; gap: 12rpx; }
|
||||
.user-name { font-size: 40rpx; font-weight: 800; color: var(--text-main); }
|
||||
|
||||
.stats-grid {
|
||||
display: flex; justify-content: space-around;
|
||||
padding: 40rpx;
|
||||
margin: 24rpx 40rpx;
|
||||
background: white;
|
||||
border-radius: 32rpx;
|
||||
color: white;
|
||||
margin-bottom: 48rpx;
|
||||
box-shadow: 0 20rpx 40rpx rgba(44, 62, 80, 0.2);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.level-card-bg {
|
||||
position: absolute;
|
||||
top: -100rpx;
|
||||
right: -100rpx;
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.level-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 40rpx;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.level-info-large {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.level-label {
|
||||
font-size: 24rpx;
|
||||
opacity: 0.8;
|
||||
letter-spacing: 2rpx;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.level-value {
|
||||
font-size: 48rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.level-progress-section {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 26rpx;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: 600;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.level-progress-bar-bg {
|
||||
height: 16rpx;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: 2rpx solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.level-progress-bar-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #FFD700, #FDB931);
|
||||
border-radius: 8rpx;
|
||||
box-shadow: 0 0 12rpx rgba(255, 215, 0, 0.4);
|
||||
}
|
||||
|
||||
.next-level-tip {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255,255,255,0.7);
|
||||
display: block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.section-title-badges {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
margin-bottom: 32rpx;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.badges-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.badge-item {
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.02);
|
||||
}
|
||||
|
||||
.stat-col { display: flex; flex-direction: column; align-items: center; gap: 4rpx; }
|
||||
.stat-num { font-size: 36rpx; font-weight: 800; color: var(--text-main); }
|
||||
.stat-label { font-size: 22rpx; color: #90A4AE; }
|
||||
|
||||
.profile-menu {
|
||||
padding: 0 32rpx;
|
||||
.badge-item.locked {
|
||||
background: #F8F9FA;
|
||||
border: 2rpx dashed #E5E7EB;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.badge-icon-circle {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.badge-name {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #374151;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.badge-desc {
|
||||
font-size: 20rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.badge-progress {
|
||||
margin-top: 12rpx;
|
||||
font-size: 20rpx;
|
||||
background: #F3F4F6;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
|
||||
/* ======== Main Profile View ======== */
|
||||
.main-profile-view {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
background: linear-gradient(180deg, #E8F5E9 0%, #FFFFFF 100%);
|
||||
padding: 32rpx 40rpx;
|
||||
/* Extra padding top handled by structure relative to status bar usually,
|
||||
but standard padding is fine here */
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom-left-radius: 48rpx;
|
||||
border-bottom-right-radius: 48rpx;
|
||||
box-shadow: 0 8rpx 30rpx rgba(0,0,0,0.02);
|
||||
margin-bottom: 24rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 32rpx;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
border-radius: 50%;
|
||||
border: 6rpx solid #fff;
|
||||
box-shadow: 0 8rpx 20rpx rgba(0,0,0,0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.user-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 40rpx;
|
||||
font-weight: 800;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.level-badge {
|
||||
align-self: flex-start;
|
||||
font-size: 22rpx;
|
||||
background: #DCEDC8;
|
||||
color: #33691E;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.settings-btn {
|
||||
padding: 16rpx;
|
||||
}
|
||||
|
||||
.profile-content {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
padding: 0 32rpx;
|
||||
padding-bottom: 120rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Hide all scrollbars globally on this page */
|
||||
.profile-page ::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
}
|
||||
|
||||
.profile-page scroll-view {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.stats-section {
|
||||
padding: 0 32rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Stats Card */
|
||||
.stats-card {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
padding: 40rpx 0;
|
||||
border-radius: 32rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.02);
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.stat-num {
|
||||
font-size: 40rpx;
|
||||
font-weight: 800;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
width: 2rpx;
|
||||
height: 60%;
|
||||
background: #F3F4F6;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/* Profile Menu */
|
||||
.profile-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.menu-group-title {
|
||||
font-size: 26rpx;
|
||||
color: #9CA3AF;
|
||||
font-weight: 600;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
background: #fff;
|
||||
padding: 32rpx;
|
||||
border-radius: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.015);
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
background: #FAFAFA;
|
||||
}
|
||||
|
||||
.menu-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.menu-icon-bg {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.menu-right-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.menu-badge-text {
|
||||
font-size: 26rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
/* Edit Popup Styles */
|
||||
.profile-edit-popup {
|
||||
background: #fff;
|
||||
border-radius: 40rpx 40rpx 0 0;
|
||||
padding: 0 48rpx;
|
||||
padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40rpx 0 20rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 800;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.popup-close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 40rpx;
|
||||
}
|
||||
|
||||
/* Edit Form Rows */
|
||||
.edit-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 32rpx 0;
|
||||
border-bottom: 2rpx solid #F3F4F6;
|
||||
}
|
||||
|
||||
.edit-row-label {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.edit-row-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.nickname-input {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #111827;
|
||||
text-align: right;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.edit-actions {
|
||||
padding-top: 60rpx;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/* About Section */
|
||||
.about-section {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.about-logo-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 60rpx;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.about-logo {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
background: linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%);
|
||||
border-radius: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 12rpx 32rpx rgba(85, 139, 47, 0.1);
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.about-app-name {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
.about-version {
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.about-desc {
|
||||
background: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 24rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 1.7;
|
||||
color: #4B5563;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.02);
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #F8F9FA;
|
||||
background-color: #F4F6F0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
+37
-45
@@ -5,63 +5,75 @@ Page({
|
||||
data: {
|
||||
plant: null,
|
||||
activeImageIndex: 0,
|
||||
swiperList: []
|
||||
swiperList: [],
|
||||
},
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
loadPlantDetail(id) {
|
||||
// Fetch detail via wiki/page with specific ID
|
||||
// Since there's no /wiki/detail endpoint, we use /wiki/page to get it
|
||||
request.post('/wiki/page', {
|
||||
current: 1,
|
||||
pageSize: 1,
|
||||
id: id
|
||||
}).then(res => {
|
||||
const data = res || {};
|
||||
const list = data.list || [];
|
||||
const item = list.length > 0 ? list[0] : null;
|
||||
request.get('/wiki/detail', { id: id }).then(res => {
|
||||
const item = res || null;
|
||||
|
||||
if (!item) {
|
||||
wx.showToast({ title: '未找到该植物', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Set Page Title
|
||||
this.setPlantData(item);
|
||||
}).catch(err => {
|
||||
console.error('Load plant detail failed', err);
|
||||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||||
});
|
||||
},
|
||||
|
||||
setPlantData(item) {
|
||||
if (!item) return;
|
||||
|
||||
wx.setNavigationBarTitle({ title: item.name });
|
||||
|
||||
// Prepare swiper list from imgList
|
||||
// Prepare swiper list
|
||||
const swiperList = (item.imgList || []).map(img => img.url);
|
||||
|
||||
// Parse pest/disease list
|
||||
// Parse lists
|
||||
const commonPests = item.pestsDiseases
|
||||
? item.pestsDiseases.split(',').map(s => s.trim()).filter(Boolean)
|
||||
: [];
|
||||
|
||||
// Parse aliases
|
||||
const aliasesList = item.aliases
|
||||
? item.aliases.split(/[,,、]/).map(s => s.trim()).filter(Boolean)
|
||||
: [];
|
||||
|
||||
// Parse reproduction methods
|
||||
const reproductionList = item.reproductionMethod
|
||||
? item.reproductionMethod.split(/[,,、]/).map(s => s.trim()).filter(Boolean)
|
||||
: [];
|
||||
|
||||
// Difficulty label
|
||||
const diffLabels = { 1: '简单', 2: '中等', 3: '较难', 4: '困难', 5: '专家' };
|
||||
|
||||
// Map API data to display model
|
||||
const plant = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
latinName: item.latinName || '',
|
||||
aliases: item.aliases || '',
|
||||
aliasesList: aliasesList,
|
||||
aliasesList,
|
||||
genus: item.genus || '',
|
||||
distributionArea: item.distributionArea || '',
|
||||
difficulty: item.difficulty || 0,
|
||||
@@ -70,49 +82,29 @@ Page({
|
||||
lifeCycle: item.lifeCycle || '',
|
||||
growthHabit: item.growthHabit || '',
|
||||
reproductionMethod: item.reproductionMethod || '',
|
||||
reproductionList: reproductionList,
|
||||
|
||||
// Light
|
||||
reproductionList,
|
||||
lightIntensity: item.lightIntensity || '',
|
||||
lightType: item.lightType || '',
|
||||
|
||||
// Temperature
|
||||
optimalTempPeriod: item.optimalTempPeriod || '',
|
||||
|
||||
// Morphology
|
||||
stem: item.stem || '',
|
||||
foliageType: item.foliageType || '',
|
||||
foliageColor: item.foliageColor || '',
|
||||
foliageShape: item.foliageShape || '',
|
||||
height: item.height || 0,
|
||||
|
||||
// Flowering
|
||||
floweringPeriod: item.floweringPeriod || '',
|
||||
floweringColor: item.floweringColor || '',
|
||||
floweringShape: item.floweringShape || '',
|
||||
flowerDiameter: item.flowerDiameter || 0,
|
||||
|
||||
// Fruit
|
||||
fruit: item.fruit || '',
|
||||
|
||||
// Pests
|
||||
pestsDiseases: item.pestsDiseases || '',
|
||||
commonPests: commonPests,
|
||||
|
||||
// Classes
|
||||
commonPests,
|
||||
classes: (item.classes || []).map(c => c.name),
|
||||
|
||||
// Images
|
||||
imgList: item.imgList || []
|
||||
};
|
||||
|
||||
this.setData({
|
||||
plant: plant,
|
||||
swiperList: swiperList
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error('Load plant detail failed', err);
|
||||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||||
plant,
|
||||
swiperList
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -1,55 +1,45 @@
|
||||
<!--pages/wiki/detail/index.wxml-->
|
||||
<view class="wiki-detail" wx:if="{{plant}}">
|
||||
<!-- Header Area -->
|
||||
<!-- Image Carousel -->
|
||||
<view class="wd-header">
|
||||
<view class="wd-gallery-container">
|
||||
<t-swiper
|
||||
t-class="custom-swiper"
|
||||
current="{{activeImageIndex}}"
|
||||
bind:change="onSwiperChange"
|
||||
height="500rpx"
|
||||
height="480rpx"
|
||||
list="{{swiperList}}"
|
||||
navigation="{{ { type: '' } }}"
|
||||
/>
|
||||
<view class="wd-gradient-overlay"></view>
|
||||
<view class="wd-counter" wx:if="{{swiperList.length > 0}}">
|
||||
<text>{{activeImageIndex + 1}} / {{swiperList.length}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Custom Indicators -->
|
||||
<view class="wd-indicators" wx:if="{{swiperList.length > 1}}">
|
||||
<view
|
||||
wx:for="{{swiperList}}"
|
||||
wx:key="index"
|
||||
class="wd-dot {{index === activeImageIndex ? 'active' : ''}}"
|
||||
></view>
|
||||
</view>
|
||||
|
||||
<!-- Header Overlay Info -->
|
||||
<view class="wd-overlay">
|
||||
<view class="wd-title">
|
||||
<!-- Plant Name Card -->
|
||||
<view class="wd-name-card">
|
||||
<view class="wd-name-row">
|
||||
<text class="wd-name">{{plant.name}}</text>
|
||||
<text class="wd-scientific">{{plant.latinName}}</text>
|
||||
<text class="wd-scientific" wx:if="{{plant.latinName}}">{{plant.latinName}}</text>
|
||||
</view>
|
||||
<view class="wd-badges">
|
||||
<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>
|
||||
<text class="wd-badge">难度: {{plant.difficultyLabel}}</text>
|
||||
</view>
|
||||
<text class="wd-badge difficulty">难度: {{plant.difficultyLabel}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Content Area -->
|
||||
<view class="wd-content-wrapper">
|
||||
<!-- Content Scroll -->
|
||||
<scroll-view class="wd-content" scroll-y enhanced show-scrollbar="{{false}}">
|
||||
|
||||
<!-- Growth Habit Section -->
|
||||
<section class="wd-section" wx:if="{{plant.growthHabit}}">
|
||||
<!-- Growth Habit -->
|
||||
<view class="wd-section" wx:if="{{plant.growthHabit}}">
|
||||
<view class="wd-card">
|
||||
<text class="wd-text">{{plant.growthHabit}}</text>
|
||||
</view>
|
||||
</section>
|
||||
</view>
|
||||
|
||||
<!-- Basic Info Section -->
|
||||
<section class="wd-section">
|
||||
<!-- Basic Info -->
|
||||
<view class="wd-section">
|
||||
<view class="section-title">
|
||||
<t-icon name="info-circle" size="40rpx" color="#558B2F" />
|
||||
<text>基础档案</text>
|
||||
@@ -74,40 +64,35 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</section>
|
||||
</view>
|
||||
|
||||
<!-- Care Guide Section -->
|
||||
<section class="wd-section">
|
||||
<!-- Care Guide -->
|
||||
<view class="wd-section">
|
||||
<view class="section-title">
|
||||
<t-icon name="sunny" size="40rpx" color="#558B2F" />
|
||||
<text>养护指南</text>
|
||||
</view>
|
||||
<view class="wd-card">
|
||||
<!-- Light -->
|
||||
<view class="requirement-item" wx:if="{{plant.lightIntensity}}">
|
||||
<view class="req-icon">
|
||||
<t-icon name="sunny" size="40rpx" color="#558B2F" />
|
||||
<view class="req-icon light">
|
||||
<t-icon name="sunny" size="40rpx" color="#F59E0B" />
|
||||
</view>
|
||||
<view class="req-content">
|
||||
<text class="req-title">光照</text>
|
||||
<text class="req-desc">{{plant.lightIntensity}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Temperature -->
|
||||
<view class="requirement-item" wx:if="{{plant.optimalTempPeriod}}">
|
||||
<view class="req-icon">
|
||||
<t-icon name="pin" size="40rpx" color="#558B2F" />
|
||||
<view class="req-icon temp">
|
||||
<t-icon name="pin" size="40rpx" color="#EF4444" />
|
||||
</view>
|
||||
<view class="req-content">
|
||||
<text class="req-title">适宜温度</text>
|
||||
<text class="req-desc">{{plant.optimalTempPeriod}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Reproduction -->
|
||||
<view class="requirement-item" wx:if="{{plant.reproductionMethod}}">
|
||||
<view class="req-icon">
|
||||
<view class="req-icon repro">
|
||||
<t-icon name="fork-node" size="40rpx" color="#558B2F" />
|
||||
</view>
|
||||
<view class="req-content">
|
||||
@@ -116,10 +101,10 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</section>
|
||||
</view>
|
||||
|
||||
<!-- Morphology Section -->
|
||||
<section class="wd-section" wx:if="{{plant.stem || plant.foliageShape || plant.foliageColor}}">
|
||||
<!-- Morphology -->
|
||||
<view class="wd-section" wx:if="{{plant.stem || plant.foliageShape || plant.foliageColor}}">
|
||||
<view class="section-title">
|
||||
<t-icon name="tree-round-dot" size="40rpx" color="#558B2F" />
|
||||
<text>形态特征</text>
|
||||
@@ -144,10 +129,10 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</section>
|
||||
</view>
|
||||
|
||||
<!-- Flowering Section -->
|
||||
<section class="wd-section" wx:if="{{plant.floweringPeriod || plant.floweringColor}}">
|
||||
<!-- Flowering -->
|
||||
<view class="wd-section" wx:if="{{plant.floweringPeriod || plant.floweringColor}}">
|
||||
<view class="section-title">
|
||||
<t-icon name="flower" size="40rpx" color="#558B2F" />
|
||||
<text>开花信息</text>
|
||||
@@ -172,10 +157,10 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</section>
|
||||
</view>
|
||||
|
||||
<!-- Fruit Section -->
|
||||
<section class="wd-section" wx:if="{{plant.fruit}}">
|
||||
<!-- Fruit -->
|
||||
<view class="wd-section" wx:if="{{plant.fruit}}">
|
||||
<view class="section-title">
|
||||
<t-icon name="apple" size="40rpx" color="#558B2F" />
|
||||
<text>果实</text>
|
||||
@@ -183,12 +168,12 @@
|
||||
<view class="wd-card">
|
||||
<text class="wd-text">{{plant.fruit}}</text>
|
||||
</view>
|
||||
</section>
|
||||
</view>
|
||||
|
||||
<!-- Pests & Diseases Section -->
|
||||
<section class="wd-section" wx:if="{{plant.commonPests.length > 0}}">
|
||||
<!-- Pests -->
|
||||
<view class="wd-section" wx:if="{{plant.commonPests.length > 0}}">
|
||||
<view class="section-title">
|
||||
<t-icon name="error-circle" size="40rpx" color="#558B2F" />
|
||||
<t-icon name="error-circle" size="40rpx" color="#EF4444" />
|
||||
<text>常见病虫害</text>
|
||||
</view>
|
||||
<view class="wd-card">
|
||||
@@ -196,15 +181,13 @@
|
||||
<text wx:for="{{plant.commonPests}}" wx:key="*this" class="pest-tag">{{item}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</section>
|
||||
</view>
|
||||
|
||||
<!-- Bottom Spacer -->
|
||||
<view style="height: 100rpx;"></view>
|
||||
<view style="height: 120rpx;"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Loading State -->
|
||||
<!-- Loading -->
|
||||
<view wx:if="{{!plant}}" class="wiki-detail-loading">
|
||||
<t-loading theme="circular" size="64rpx" text="加载中..." />
|
||||
</view>
|
||||
|
||||
+109
-187
@@ -3,201 +3,139 @@
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #F9FAFB;
|
||||
background: #F4F6F0;
|
||||
}
|
||||
|
||||
/* Page Layout */
|
||||
page {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Hide Scrollbar Globally */
|
||||
::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
scroll-view ::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
/* Header Area */
|
||||
/* ======== Image Carousel ======== */
|
||||
.wd-header {
|
||||
height: 500rpx;
|
||||
position: relative;
|
||||
background: #000;
|
||||
flex-shrink: 0;
|
||||
background: #E8E8E8;
|
||||
}
|
||||
|
||||
/* Content Wrapper handles the flex growth and positioning overlap */
|
||||
.wd-content-wrapper {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
margin-top: -32rpx;
|
||||
z-index: 20;
|
||||
overflow: hidden; /* Ensure scroll-view is contained */
|
||||
}
|
||||
|
||||
/* Content Scroll View fills the wrapper */
|
||||
.wd-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Force override TDesign swiper radius */
|
||||
.custom-swiper {
|
||||
border-radius: 0 !important;
|
||||
overflow: hidden;
|
||||
--td-swiper-radius: 0px !important;
|
||||
}
|
||||
|
||||
.custom-swiper .t-swiper {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
t-swiper {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.wd-gallery-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wd-gradient-overlay {
|
||||
.wd-counter {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 240rpx;
|
||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7), transparent);
|
||||
pointer-events: none;
|
||||
bottom: 20rpx;
|
||||
right: 24rpx;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
color: white;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
padding: 6rpx 18rpx;
|
||||
border-radius: 12rpx;
|
||||
z-index: 20;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
/* ======== Name Card ======== */
|
||||
.wd-name-card {
|
||||
background: white;
|
||||
padding: 32rpx 36rpx 28rpx;
|
||||
margin: 0 0 24rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.wd-indicators {
|
||||
position: absolute;
|
||||
bottom: 24rpx;
|
||||
right: 24rpx;
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.wd-dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.wd-dot.active {
|
||||
background: white;
|
||||
width: 24rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.wd-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 32rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
pointer-events: none;
|
||||
z-index: 20;
|
||||
.wd-name-row {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.wd-name {
|
||||
font-size: 56rpx;
|
||||
color: #FFFFFF;
|
||||
display: block;
|
||||
font-size: 48rpx;
|
||||
font-weight: 800;
|
||||
margin-bottom: 8rpx;
|
||||
color: #1F2937;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.wd-scientific {
|
||||
font-size: 32rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #9CA3AF;
|
||||
font-style: italic;
|
||||
font-family: serif;
|
||||
margin-bottom: 24rpx;
|
||||
font-family: Georgia, 'Times New Roman', serif;
|
||||
}
|
||||
|
||||
.wd-badges {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
gap: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.wd-badge {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(4px);
|
||||
background: #F0F7EB;
|
||||
color: #558B2F;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 20rpx;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wd-badge.difficulty {
|
||||
background: #FFF8E1;
|
||||
color: #F57F17;
|
||||
}
|
||||
|
||||
/* ======== Scrollable Content ======== */
|
||||
.wd-content {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/* ======== Sections ======== */
|
||||
.wd-section {
|
||||
margin-bottom: 32rpx;
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
|
||||
/* First section specific override: Adjust padding and background to create the seamless rounded look */
|
||||
.wd-section:first-child {
|
||||
padding: 0;
|
||||
margin-bottom: 48rpx;
|
||||
}
|
||||
|
||||
.wd-section:first-child .wd-card {
|
||||
border-top-left-radius: 40rpx;
|
||||
border-top-right-radius: 40rpx;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
padding: 48rpx 32rpx;
|
||||
box-shadow: none; /* Seamless blend */
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20rpx); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
margin-bottom: 28rpx;
|
||||
padding: 0 28rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 24rpx;
|
||||
padding-left: 8rpx;
|
||||
gap: 14rpx;
|
||||
margin-bottom: 20rpx;
|
||||
padding-left: 4rpx;
|
||||
}
|
||||
|
||||
.section-title text {
|
||||
font-size: 34rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
/* ======== Cards ======== */
|
||||
.wd-card {
|
||||
background: white;
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx 32rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.wd-text {
|
||||
font-size: 30rpx;
|
||||
line-height: 1.6;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.7;
|
||||
color: #4B5563;
|
||||
}
|
||||
|
||||
/* ======== Info Grid ======== */
|
||||
.wd-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 32rpx;
|
||||
gap: 28rpx 32rpx;
|
||||
}
|
||||
|
||||
.wd-stat-item {
|
||||
@@ -207,62 +145,72 @@ t-swiper {
|
||||
}
|
||||
|
||||
.wd-label {
|
||||
font-size: 24rpx;
|
||||
font-size: 22rpx;
|
||||
color: #9CA3AF;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.wd-value {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.wd-card {
|
||||
background: white;
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.02);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
/* Requirement Items (Compact) */
|
||||
/* ======== Requirement Items ======== */
|
||||
.requirement-item {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
padding-bottom: 24rpx;
|
||||
padding: 24rpx 0;
|
||||
border-bottom: 2rpx solid #F3F4F6;
|
||||
}
|
||||
|
||||
.requirement-item:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.requirement-item:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.req-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: #F1F8E9;
|
||||
border-radius: 20rpx;
|
||||
width: 84rpx;
|
||||
height: 84rpx;
|
||||
border-radius: 22rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.req-icon.light {
|
||||
background: #FFFBEB;
|
||||
}
|
||||
|
||||
.req-icon.temp {
|
||||
background: #FEF2F2;
|
||||
}
|
||||
|
||||
.req-icon.repro {
|
||||
background: #F0FDF4;
|
||||
}
|
||||
|
||||
.req-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.req-title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.req-desc {
|
||||
@@ -271,7 +219,7 @@ t-swiper {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* FAQ / Pests */
|
||||
/* ======== Pest Tags ======== */
|
||||
.pest-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -283,41 +231,15 @@ t-swiper {
|
||||
color: #DC2626;
|
||||
padding: 12rpx 24rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.care-tips-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.tip-item {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.tip-dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
background: #558B2F;
|
||||
margin-top: 14rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
font-size: 28rpx;
|
||||
color: #4B5563;
|
||||
line-height: 1.5;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ======== Loading ======== */
|
||||
.wiki-detail-loading {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #F9FAFB;
|
||||
background: #F4F6F0;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.identify-page {
|
||||
min-height: 100vh;
|
||||
background: #F5F7F5;
|
||||
background: #F4F6F0;
|
||||
}
|
||||
|
||||
/* ========== Shared State Container ========== */
|
||||
|
||||
+4
-1
@@ -150,7 +150,10 @@ Page({
|
||||
goToDetail(e) {
|
||||
const item = e.currentTarget.dataset.item;
|
||||
wx.navigateTo({
|
||||
url: `/pages/wiki/detail/index?id=${item.id}`
|
||||
url: `/pages/wiki/detail/index?id=${item.id}`,
|
||||
success: (res) => {
|
||||
res.eventChannel.emit('acceptDataFromOpenerPage', { data: item.raw });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"t-search": "tdesign-miniprogram/search/search",
|
||||
"t-tag": "tdesign-miniprogram/tag/tag",
|
||||
"t-image": "tdesign-miniprogram/image/image",
|
||||
"t-fab": "tdesign-miniprogram/fab/fab",
|
||||
"t-popup": "tdesign-miniprogram/popup/popup",
|
||||
"t-cell": "tdesign-miniprogram/cell/cell",
|
||||
"t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
|
||||
|
||||
@@ -113,7 +113,10 @@
|
||||
<view style="height: 160rpx;"></view>
|
||||
</scroll-view>
|
||||
|
||||
<t-fab icon="scan" text="植物识别" bind:click="openIdentifyModal" aria-label="植物识别"></t-fab>
|
||||
<view class="floating-add-btn" bindtap="openIdentifyModal">
|
||||
<t-icon name="scan" size="40rpx" color="#FFF" />
|
||||
<text>植物识别</text>
|
||||
</view>
|
||||
|
||||
<!-- Identify Popup -->
|
||||
<t-popup visible="{{showIdentifyModal}}" bind:visible-change="onPopupVisibleChange" placement="bottom">
|
||||
|
||||
+26
-2
@@ -3,7 +3,7 @@
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #F9FAFB;
|
||||
background-color: #F4F6F0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -101,6 +101,30 @@
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* Floating Action Button */
|
||||
.floating-add-btn {
|
||||
position: fixed;
|
||||
right: 40rpx;
|
||||
bottom: 60rpx;
|
||||
background: #558B2F;
|
||||
color: white;
|
||||
padding: 24rpx 40rpx;
|
||||
border-radius: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
box-shadow: 0 12rpx 32rpx rgba(85, 139, 47, 0.4);
|
||||
z-index: 1000;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.floating-add-btn:active {
|
||||
transform: scale(0.92);
|
||||
box-shadow: 0 4rpx 16rpx rgba(85, 139, 47, 0.2);
|
||||
}
|
||||
|
||||
/* Popup Styles */
|
||||
.popup-content {
|
||||
background: white;
|
||||
@@ -144,7 +168,7 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
background: #F9FAFB;
|
||||
background: #F4F6F0;
|
||||
border-radius: 32rpx;
|
||||
padding: 40rpx 24rpx;
|
||||
transition: all 0.2s;
|
||||
|
||||
+6
-6
@@ -72,12 +72,12 @@ class WxRequest {
|
||||
}
|
||||
} else {
|
||||
// Handle non-200 HTTP errors
|
||||
this.handleError({ errMsg: `HTTP Error: ${statusCode}`, ...res });
|
||||
this.handleError({ ...res, errMsg: `HTTP Error: ${statusCode}` });
|
||||
reject(res);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
this.handleError({ errMsg: 'Network Error', ...err });
|
||||
this.handleError({ ...err, errMsg: 'Network Error' });
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
@@ -154,12 +154,12 @@ class WxRequest {
|
||||
reject(finalData);
|
||||
}
|
||||
} else {
|
||||
this.handleError({ errMsg: `HTTP Error: ${statusCode}`, ...res });
|
||||
this.handleError({ ...res, errMsg: `HTTP Error: ${statusCode}` });
|
||||
reject(res);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
this.handleError({ errMsg: 'Upload Network Error', ...err });
|
||||
this.handleError({ ...err, errMsg: 'Upload Network Error' });
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
@@ -215,12 +215,12 @@ class WxRequest {
|
||||
reject(finalData);
|
||||
}
|
||||
} else {
|
||||
this.handleError({ errMsg: `HTTP Error: ${statusCode}`, ...res });
|
||||
this.handleError({ ...res, errMsg: `HTTP Error: ${statusCode}` });
|
||||
reject(res);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
this.handleError({ errMsg: 'Upload Network Error', ...err });
|
||||
this.handleError({ ...err, errMsg: 'Upload Network Error' });
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user