feat: 调整样式

This commit is contained in:
Blizzard
2026-02-14 11:31:44 +08:00
parent cbbe82ef63
commit d6f781a666
42 changed files with 827 additions and 293 deletions
+24
View File
@@ -0,0 +1,24 @@
Page({
data: {
appVersion: '1.0.0'
},
onLoad() {
const accountInfo = wx.getAccountInfoSync();
if (accountInfo && accountInfo.miniProgram) {
this.setData({
appVersion: accountInfo.miniProgram.version || '1.0.0'
});
}
},
openDoc(e) {
if (wx.openPrivacyContract) {
wx.openPrivacyContract({
fail: () => {
wx.showToast({ title: '无法打开协议', icon: 'none' });
}
});
} else {
wx.showToast({ title: '当前微信版本不支持查看', icon: 'none' });
}
}
});
+8
View File
@@ -0,0 +1,8 @@
{
"navigationBarTitleText": "关于植趣",
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-cell": "tdesign-miniprogram/cell/cell",
"t-cell-group": "tdesign-miniprogram/cell-group/cell-group"
}
}
+25
View File
@@ -0,0 +1,25 @@
<view class="about-container">
<view class="logo-section">
<view class="logo-bg">
<t-icon name="flower" size="80rpx" color="#558B2F" />
</view>
<text class="app-title">植趣</text>
<text class="app-version">Version {{appVersion}}</text>
</view>
<view class="desc-content">
一款专注于家庭植物养护的小程序。帮助你记录植物成长、制定养护计划、识别未知植物,与花友们分享养花心得。
</view>
<view class="menu-list">
<t-cell-group theme="card">
<t-cell title="用户协议" arrow hover bind:click="openDoc" data-type="terms" left-icon="file-copy" />
</t-cell-group>
</view>
<view class="footer-spacer"></view>
<view class="footer">
<text class="copyright">© 2026 Sundynix · All Rights Reserved</text>
</view>
</view>
+69
View File
@@ -0,0 +1,69 @@
page {
background: #F4F6F0;
}
.about-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 48rpx 32rpx;
min-height: 100vh;
box-sizing: border-box;
}
.logo-section {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 64rpx;
margin-bottom: 48rpx;
}
.logo-bg {
width: 160rpx;
height: 160rpx;
background: #fff;
border-radius: 32rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 32rpx rgba(85, 139, 47, 0.1);
margin-bottom: 24rpx;
}
.app-title {
font-size: 40rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
}
.app-version {
font-size: 24rpx;
color: #999;
}
.desc-content {
font-size: 28rpx;
color: #666;
line-height: 1.6;
text-align: center;
margin-bottom: 64rpx;
padding: 0 40rpx;
}
.menu-list {
width: 100%;
}
.footer-spacer {
flex: 1;
}
.footer {
padding: 32rpx 0;
}
.copyright {
font-size: 22rpx;
color: #ccc;
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"navigationBarTitleText": "成就徽章",
"navigationBarTitleText": "等级徽章",
"navigationBarBackgroundColor": "#F4F6F0",
"navigationBarTextStyle": "black",
"usingComponents": {
+3 -3
View File
@@ -24,7 +24,7 @@
<view class="click-hint">点击查看等级详情 ></view>
</view>
<view class="section-title-badges">我的成就</view>
<view class="section-title-badges">我的徽章</view>
<view class="badge-wall-entry" bindtap="openBadgeWall">
<view class="entry-bg-bloom"></view>
@@ -33,8 +33,8 @@
<t-icon name="achievement" size="56rpx" color="#FFD700" />
</view>
<view class="wall-entry-text">
<text class="entry-title">成就徽章墙</text>
<text class="entry-desc">查看所有成就与收集进度</text>
<text class="entry-title">徽章墙</text>
<text class="entry-desc">查看所有徽章与收集进度</text>
</view>
</view>
<view class="wall-entry-right">
+1
View File
@@ -0,0 +1 @@
Page({});
+6
View File
@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "兑换中心",
"usingComponents": {
"t-empty": "tdesign-miniprogram/empty/empty"
}
}
+3
View File
@@ -0,0 +1,3 @@
<view class="exchange-page">
<t-empty icon="info-circle-filled" description="兑换中心功能正在开发中,敬请期待" />
</view>
+9
View File
@@ -0,0 +1,9 @@
page {
background: #F4F6F0;
}
.exchange-page {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
+128 -15
View File
@@ -2,33 +2,146 @@ import request from '../../../utils/request';
Page({
data: {
favTab: 'all',
favTab: 'all', // 'all', 'plant', 'post'
favorites: [],
filteredFavorites: []
current: 1,
pageSize: 10,
hasMore: true,
isLoading: false
},
onLoad() {
this.loadFavorites();
},
loadFavorites() {
// TODO: Call API
this.filterFavorites();
this.fetchFavorites(true);
},
onFavTabChange(e) {
const val = e.currentTarget.dataset.value;
if (val === this.data.favTab) return;
this.setData({ favTab: val }, () => {
this.filterFavorites();
this.fetchFavorites(true);
});
},
filterFavorites() {
const { favorites, favTab } = this.data;
const filtered = favorites.filter(item => {
if (favTab === 'all') return true;
return item.type === favTab;
fetchFavorites(reset = false) {
if (this.data.isLoading) return;
if (!reset && !this.data.hasMore) return;
this.setData({ isLoading: true });
const current = reset ? 1 : this.data.current;
let classType = 0;
if (this.data.favTab === 'plant') classType = 1;
if (this.data.favTab === 'post') classType = 2;
request.post('/profile/star', {
current,
pageSize: this.data.pageSize,
class: classType
}).then(res => {
const list = res.list || [];
const total = res.total || 0;
const mappedList = list.map(wrapper => {
const type = wrapper.type; // 1=Wiki, 2=Post
const isPlant = type === 1;
const entity = isPlant ? wrapper.wiki : wrapper.post;
if (!entity) return null;
// Image Extraction
let image = '';
if (entity.imgList && entity.imgList.length > 0) {
image = entity.imgList[0].url;
}
if (isPlant) {
return {
id: entity.id,
type: 'plant',
name: entity.name,
latinName: entity.latinName,
difficultyLabel: this.getDifficultyLabel(entity.difficulty),
image: image
};
} else {
// Post
return {
id: entity.id,
type: 'post',
content: entity.content,
postImage: image,
avatar: entity.publisher && entity.publisher.avatar ? entity.publisher.avatar : '', // Publisher is null in sample
nickname: entity.publisher && entity.publisher.nickname ? entity.publisher.nickname : '花友',
time: wrapper.createdAtStr
};
}
}).filter(item => item !== null);
if (reset) {
this.setData({
favorites: mappedList,
current: 2,
hasMore: mappedList.length < total,
isLoading: false
});
} else {
this.setData({
favorites: [...this.data.favorites, ...mappedList],
current: current + 1,
hasMore: (this.data.favorites.length + mappedList.length) < total,
isLoading: false
});
}
}).catch(err => {
console.error('Fetch favorites failed', err);
this.setData({ isLoading: false });
});
this.setData({ filteredFavorites: filtered });
},
getDifficultyLabel(level) {
const labels = { 1: '简单', 2: '中等', 3: '较难', 4: '困难', 5: '专家' };
return labels[level] || '未知';
},
onSwipeClick(e) {
// Handle Delete
// Data item is bound to the swipe-cell or passed via dataset
// If bind:click is on swipe-cell, e.target might not have the item if not set.
// We set data-item on swipe-cell.
const item = e.currentTarget.dataset.item;
const { id, type } = item;
const apiPath = type === 'plant' ? '/wiki/star' : '/post/star';
wx.showModal({
title: '提示',
content: '确定要取消收藏吗?',
success: (modRes) => {
if (modRes.confirm) {
request.get(apiPath, { id, type: 2 }).then(() => {
wx.showToast({ title: '已删除', icon: 'success' });
// Remove from list
const newList = this.data.favorites.filter(i => i.id !== id);
this.setData({ favorites: newList });
}).catch(err => {
console.error('Delete favorite failed', err);
wx.showToast({ title: '删除失败', icon: 'none' });
});
}
}
});
},
goToDetail(e) {
const item = e.currentTarget.dataset.item;
if (item.type === 'plant') {
wx.navigateTo({ url: `/pages/wiki/detail/index?id=${item.id}` });
} else {
wx.showToast({ title: '暂不支持查看动态详情', icon: 'none' });
}
},
onReachBottom() {
this.fetchFavorites(false);
}
});
+5 -1
View File
@@ -2,6 +2,10 @@
"navigationBarTitleText": "我的收藏",
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-image": "tdesign-miniprogram/image/image"
"t-image": "tdesign-miniprogram/image/image",
"t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell",
"t-tag": "tdesign-miniprogram/tag/tag",
"t-avatar": "tdesign-miniprogram/avatar/avatar",
"t-loading": "tdesign-miniprogram/loading/loading"
}
}
+60 -14
View File
@@ -1,27 +1,73 @@
<view class="favorites-page">
<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 class="filter-chip {{favTab === 'plant' ? 'active' : ''}}" bindtap="onFavTabChange" data-value="plant">百科</view>
<view class="filter-chip {{favTab === 'post' ? 'active' : ''}}" bindtap="onFavTabChange" data-value="post">动态</view>
</view>
<scroll-view scroll-y class="fav-scroll" enhanced show-scrollbar="{{false}}">
<view wx:if="{{filteredFavorites.length > 0}}" class="fav-grid">
<view wx:for="{{filteredFavorites}}" wx:key="id" class="fav-card">
<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="28rpx" color="#90A4AE" />
<text class="fav-type">{{item.meta}}</text>
<scroll-view
scroll-y
class="fav-scroll"
enhanced
show-scrollbar="{{false}}"
bindscrolltolower="onReachBottom"
>
<view wx:if="{{favorites.length > 0}}" class="fav-list">
<t-swipe-cell wx:for="{{favorites}}" wx:key="id">
<view class="fav-item" bindtap="goToDetail" data-item="{{item}}">
<!-- Render Wiki Plant -->
<block wx:if="{{item.type === 'plant'}}">
<t-image src="{{item.image}}" mode="aspectFill" class="fav-img plant-img" width="160rpx" height="160rpx" />
<view class="fav-info">
<text class="fav-title">{{item.name}}</text>
<text class="fav-subtitle">{{item.latinName}}</text>
<view class="fav-meta">
<t-tag size="small" variant="light" theme="success">植物百科</t-tag>
<text wx:if="{{item.difficultyLabel}}" class="meta-diff">难度: {{item.difficultyLabel}}</text>
</view>
</view>
</block>
<!-- Render Community Post -->
<block wx:else>
<t-image
src="{{item.postImage || item.avatar}}"
mode="aspectFill"
class="fav-img post-img"
width="160rpx" height="160rpx"
/>
<view class="fav-info">
<text class="fav-title post-title">{{item.content || '无标题'}}</text>
<view class="fav-user-row">
<t-avatar image="{{item.avatar}}" size="small" />
<text class="user-nickname">{{item.nickname}}</text>
</view>
<view class="fav-meta">
<t-tag size="small" variant="light" theme="primary">社区动态</t-tag>
<text class="meta-time">{{item.time}}</text>
</view>
</view>
</block>
</view>
</view>
</view>
<view slot="right" class="delete-btn" catchtap="onSwipeClick" data-item="{{item}}">
<text>删除</text>
</view>
</t-swipe-cell>
</view>
<view wx:else class="empty-state">
<!-- Empty State -->
<view wx:elif="{{!isLoading}}" class="empty-state">
<t-icon name="star" size="80rpx" color="#E0E0E0" style="margin-bottom: 24rpx;" />
<text class="empty-text">暂无收藏内容</text>
</view>
<!-- Loading State -->
<view class="loading-footer" wx:if="{{isLoading}}">
<t-loading theme="circular" size="40rpx" text="加载中..." />
</view>
<view wx:if="{{!hasMore && favorites.length > 0}}" class="no-more-text">没有更多了</view>
<view style="height: 60rpx;"></view>
</scroll-view>
</view>
+95 -23
View File
@@ -12,6 +12,7 @@
display: flex;
gap: 16rpx;
margin-bottom: 24rpx;
flex-shrink: 0;
}
.filter-chip {
@@ -26,10 +27,10 @@
}
.filter-chip.active {
background: #333;
background: #558B2F;
color: #fff;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
box-shadow: 0 4rpx 12rpx rgba(85, 139, 47, 0.2);
}
.fav-scroll {
@@ -38,47 +39,91 @@
width: 100%;
}
.fav-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20rpx;
}
.fav-card {
background: white;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.03);
.fav-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.fav-item {
background: white;
border-radius: 20rpx;
padding: 24rpx;
display: flex;
gap: 24rpx;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.02);
}
.fav-item:active {
background: #fafafa;
}
.fav-img {
width: 160rpx;
height: 160rpx;
border-radius: 16rpx;
flex-shrink: 0;
background: #f0f0f0;
}
.fav-info {
padding: 16rpx 20rpx;
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
min-width: 0;
height: 160rpx;
}
.fav-name {
display: block;
font-size: 28rpx;
.fav-title {
font-size: 30rpx;
font-weight: 600;
color: #1F2937;
margin-bottom: 8rpx;
margin-bottom: 4rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.4;
}
.fav-meta-row {
.fav-subtitle {
font-size: 24rpx;
color: #9CA3AF;
font-style: italic;
margin-bottom: auto; /* Push meta down */
display: block;
}
.fav-user-row {
display: flex;
align-items: center;
gap: 8rpx;
gap: 12rpx;
margin-bottom: auto; /* Push meta down */
margin-top: 8rpx;
}
.fav-type {
.user-nickname {
font-size: 24rpx;
color: #6B7280;
}
.fav-meta {
display: flex;
align-items: center;
gap: 16rpx;
margin-top: 12rpx;
}
.meta-diff {
font-size: 22rpx;
color: #F59E0B;
background: #FFFBEB;
padding: 4rpx 12rpx;
border-radius: 8rpx;
}
.meta-time {
font-size: 22rpx;
color: #9CA3AF;
}
@@ -96,3 +141,30 @@
color: #9CA3AF;
margin-top: 16rpx;
}
.loading-footer {
padding: 32rpx;
display: flex;
justify-content: center;
}
.no-more-text {
text-align: center;
padding: 32rpx;
color: #ccc;
font-size: 24rpx;
}
.delete-btn {
background-color: #EF4444;
color: white;
width: 140rpx;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 500;
border-top-right-radius: 20rpx;
border-bottom-right-radius: 20rpx;
}
+24
View File
@@ -80,6 +80,30 @@ Page({
});
},
deleteLog(e) {
const id = e.currentTarget.dataset.id;
wx.showModal({
title: '提示',
content: '确定要删除这条识别记录吗?',
confirmColor: '#EF5350',
success: (res) => {
if (res.confirm) {
wx.showLoading({ title: '删除中' });
request.post('/classify/deleteClassifyLog', { ids: [id] }).then(() => {
wx.hideLoading();
wx.showToast({ title: '删除成功', icon: 'success' });
const newRecords = this.data.records.filter(r => r.id !== id);
this.setData({ records: newRecords });
}).catch(err => {
wx.hideLoading();
console.error('Delete log failed', err);
wx.showToast({ title: '删除失败', icon: 'none' });
});
}
}
});
},
_formatTime(dateStr) {
if (!dateStr) return '';
const d = new Date(dateStr);
@@ -4,6 +4,7 @@
"t-icon": "tdesign-miniprogram/icon/icon",
"t-image": "tdesign-miniprogram/image/image",
"t-empty": "tdesign-miniprogram/empty/empty",
"t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell",
"t-loading": "tdesign-miniprogram/loading/loading"
}
}
+75 -67
View File
@@ -16,80 +16,88 @@
<!-- Record List -->
<view wx:else class="record-list">
<view wx:for="{{records}}" wx:key="id" class="record-card" bindtap="toggleExpand" data-id="{{item.id}}">
<t-swipe-cell wx:for="{{records}}" wx:key="id" class="record-swipe-cell">
<view 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}}%
<!-- 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>
<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 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>
</view>
<view class="detail-meta">
<t-icon name="time" size="24rpx" color="#9CA3AF" />
<text class="meta-text">{{item.dateStr}}</text>
</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>
</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>
<view slot="right" class="delete-action" catchtap="deleteLog" data-id="{{item.id}}">
<view class="delete-btn">
<t-icon name="delete" size="40rpx" color="#fff" />
</view>
</view>
</t-swipe-cell>
<!-- Load More -->
<view wx:if="{{loading && records.length > 0}}" class="load-more">
+20
View File
@@ -276,3 +276,23 @@
font-size: 24rpx;
color: #D1D5DB;
}
.delete-action {
display: flex;
align-items: center;
justify-content: center;
width: 140rpx;
height: 100%;
padding-left: 20rpx;
}
.delete-btn {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: #EF5350;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(239, 83, 80, 0.4);
}
+9 -2
View File
@@ -1,5 +1,6 @@
// pages/profile/index.js
import request from '../../utils/request';
import { calculateDaysSince } from '../../utils/dateUtil';
const app = getApp();
@@ -78,7 +79,9 @@ Page({
userLevelTag: levelTag,
// EXP / Sunlight
userExp: res.currentSunlight || 0
userExp: res.currentSunlight || 0,
userSunlight: res.currentSunlight || 0,
joinedDays: calculateDaysSince(res.createdAt)
});
// Update global cache
@@ -111,6 +114,10 @@ Page({
},
// ======== Menu Actions ========
goToExchange() {
wx.navigateTo({ url: '/pages/profile/exchange/index' });
},
goToIdentifyHistory() {
wx.navigateTo({ url: '/pages/profile/identify-history/index' });
},
@@ -129,7 +136,7 @@ Page({
},
goToAbout() {
this.setData({ view: 'about' });
wx.navigateTo({ url: '/pages/profile/about/index' });
},
openDoc(e) {
+41 -67
View File
@@ -1,39 +1,7 @@
<view class="profile-page">
<!-- ======== ABOUT VIEW ======== -->
<view wx:if="{{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-menu-list">
<view class="about-menu-item" bindtap="openDoc" data-type="terms">
<text>用户协议</text>
<t-icon name="chevron-right" size="36rpx" color="#CCC" />
</view>
</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">
<view class="main-profile-view">
<!-- Header -->
<view class="profile-header">
<view class="user-main">
@@ -41,9 +9,20 @@
<t-avatar wx:if="{{userAvatar}}" image="{{userAvatar}}" size="120rpx" />
<t-avatar wx:else icon="user" size="120rpx" />
</view>
<view class="user-text" bindtap="openProfileEditor">
<view class="user-name">{{userName}}</view>
<view class="level-badge">{{userLevelTag || 'Lv.0 园艺新手'}}</view>
<view class="user-text">
<view class="user-name" bindtap="openProfileEditor">{{userName}}</view>
<view class="level-badge" bindtap="goToBadges">{{userLevelTag || 'Lv.0 园艺新手'}}</view>
<view class="user-sun-days">
<view class="sun-days-item">
<t-icon name="sunny" size="24rpx" color="#FBC02D" />
<text>{{userSunlight}} 阳光</text>
</view>
<view class="sun-days-divider"></view>
<view class="sun-days-item">
<t-icon name="calendar" size="24rpx" color="#66BB6A" />
<text>加入 {{joinedDays}} 天</text>
</view>
</view>
</view>
</view>
<view class="settings-btn" bindtap="goToNotificationSettings">
@@ -52,30 +31,38 @@
</view>
<!-- 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-divider"></view>
<view class="stat-item">
<text class="stat-num">{{taskDoneCount}}</text>
<text class="stat-label">养护次数</text>
</view>
<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}}" scroll-top="{{scrollTop}}">
<!-- Menu -->
<view class="profile-menu">
<view class="menu-group-title">常用功能</view>
<view class="menu-item" bindtap="goToExchange">
<view class="menu-left">
<view class="menu-icon-bg" style="background: #FCE4EC">
<t-icon name="gift" size="36rpx" color="#E91E63" />
</view>
<text class="menu-text">兑换中心</text>
</view>
<view class="menu-right-info">
<text class="menu-badge-text">开发中</text>
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
</view>
</view>
<view class="menu-item" bindtap="goToBadges">
<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">
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
</view>
</view>
<view class="menu-item" bindtap="goToFavorites">
<view class="menu-left">
<view class="menu-icon-bg" style="background: #FFF3E0">
@@ -106,19 +93,6 @@
<t-icon name="chevron-right" size="36rpx" color="#ccc" />
</view>
<view class="menu-item" bindtap="goToBadges">
<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">
+38 -41
View File
@@ -344,8 +344,10 @@
border-bottom-left-radius: 48rpx;
border-bottom-right-radius: 48rpx;
box-shadow: 0 8rpx 30rpx rgba(0,0,0,0.02);
margin-bottom: 24rpx;
margin-bottom: 0;
flex-shrink: 0;
position: relative;
z-index: 102;
}
.user-main {
@@ -385,6 +387,32 @@
font-weight: 600;
}
.user-sun-days {
display: flex;
align-items: center;
gap: 16rpx;
background: rgba(255,255,255,0.6);
padding: 4rpx 16rpx;
border-radius: 20rpx;
align-self: flex-start;
border: 1rpx solid rgba(0,0,0,0.05);
}
.sun-days-item {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 22rpx;
color: #555;
font-weight: 500;
}
.sun-days-divider {
width: 2rpx;
height: 18rpx;
background: #DDD;
}
.settings-btn {
padding: 16rpx;
}
@@ -408,46 +436,7 @@
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 {
@@ -460,7 +449,15 @@
font-size: 26rpx;
color: #9CA3AF;
font-weight: 600;
margin-left: 12rpx;
position: sticky;
top: 0;
z-index: 100;
background: #F4F6F0;
/* negative margin to cover side padding of parent */
margin: 0 -32rpx;
padding: 44rpx 32rpx 16rpx 44rpx; /* 32rpx padding + 12rpx visual indent */
}
.menu-item {
+2 -1
View File
@@ -3,6 +3,7 @@
"disableScroll": true,
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-image": "tdesign-miniprogram/image/image"
"t-image": "tdesign-miniprogram/image/image",
"t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell"
}
}
+22 -18
View File
@@ -12,25 +12,29 @@
<view wx:if="{{myPublishedPosts.length > 0}}" class="posts-list">
<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">
<view class="post-header" wx:if="{{item.hasReviewed !== undefined}}">
<view class="status-tag pending" wx:if="{{item.hasReviewed === 0}}">待审核</view>
<view class="status-tag success" wx:if="{{item.hasReviewed === 1}}">已发布</view>
</view>
<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="140rpx" height="140rpx"
shape="round" />
</view>
<view class="my-post-footer">
<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" />
<t-swipe-cell class="post-swipe-cell">
<view class="my-post-content-wrap">
<view class="post-header" wx:if="{{item.hasReviewed !== undefined}}">
<view class="status-tag pending" wx:if="{{item.hasReviewed === 0}}">待审核</view>
<view class="status-tag success" wx:if="{{item.hasReviewed === 1}}">已发布</view>
</view>
<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="140rpx" height="140rpx"
shape="round" />
</view>
<view class="my-post-footer">
<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>
</view>
</view>
</view>
<view slot="right" class="delete-action" catchtap="deletePost" data-id="{{item.id}}">
<view class="delete-btn">
<t-icon name="delete" size="40rpx" color="#fff" />
</view>
</view>
</t-swipe-cell>
</view>
</view>
<view wx:else class="empty-state">
+25 -1
View File
@@ -161,10 +161,34 @@
/* Hide Scrollbar Globally */
::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
display: none;
}
.post-swipe-cell {
flex: 1;
min-width: 0;
}
.delete-action {
display: flex;
align-items: center;
justify-content: center;
width: 140rpx;
height: 100%;
padding-left: 20rpx;
}
.delete-btn {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: #EF5350;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(239, 83, 80, 0.4);
}