feat: 整体页面优化,删除无用svg
This commit is contained in:
+101
-13
@@ -7,11 +7,20 @@ Page({
|
||||
groupedTasks: [],
|
||||
progress: 0,
|
||||
completingTask: null,
|
||||
remark: ''
|
||||
remark: '',
|
||||
remarkPlaceholder: '',
|
||||
scrollTop: 0,
|
||||
|
||||
// Reward Modals
|
||||
showLevelUpModal: false,
|
||||
levelUpData: null,
|
||||
showBadgeModal: false,
|
||||
badgeData: null
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.fetchTodayTasks();
|
||||
this._popupQueue = [];
|
||||
},
|
||||
|
||||
onShow() {
|
||||
@@ -23,6 +32,42 @@ Page({
|
||||
this.fetchTodayTasks();
|
||||
},
|
||||
|
||||
// ... (fetchTodayTasks, processTaskData Omitted) ...
|
||||
|
||||
// Reward Queue Processing
|
||||
processPopupQueue() {
|
||||
if (this._popupQueue.length === 0) return;
|
||||
|
||||
const next = this._popupQueue[0];
|
||||
if (next.type === 'level') {
|
||||
this.setData({
|
||||
levelUpData: next.data,
|
||||
showLevelUpModal: true
|
||||
});
|
||||
} else if (next.type === 'badge') {
|
||||
this.setData({
|
||||
badgeData: next.data,
|
||||
showBadgeModal: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
closeLevelUpModal() {
|
||||
this.setData({ showLevelUpModal: false });
|
||||
this._popupQueue.shift();
|
||||
setTimeout(() => {
|
||||
this.processPopupQueue();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
closeBadgeModal() {
|
||||
this.setData({ showBadgeModal: false });
|
||||
this._popupQueue.shift();
|
||||
setTimeout(() => {
|
||||
this.processPopupQueue();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
fetchTodayTasks() {
|
||||
request.get('/plant/todayTask').then(res => {
|
||||
// Check if res is array (list of PlantTaskVO)
|
||||
@@ -45,12 +90,7 @@ Page({
|
||||
// Parse Image
|
||||
let imageUrl = '';
|
||||
if (plant.imgList && plant.imgList.length > 0) {
|
||||
let url = plant.imgList[0].url;
|
||||
if (url && !url.startsWith('http') && !url.startsWith('/') && !url.startsWith('wxfile')) {
|
||||
imageUrl = '/assets/' + url;
|
||||
} else {
|
||||
imageUrl = url;
|
||||
}
|
||||
imageUrl = plant.imgList[0].url || '';
|
||||
}
|
||||
|
||||
const plantGroup = {
|
||||
@@ -149,9 +189,36 @@ Page({
|
||||
handleTaskClick(e) {
|
||||
const task = e.currentTarget.dataset.task;
|
||||
if (task.isCompleted) return;
|
||||
|
||||
// Compute placeholder based on task type or name
|
||||
let placeholder = '添加备注 (可选)...';
|
||||
// Get name from taskIcon first, then name.
|
||||
// name from backend is usually the name (e.g. "浇水").
|
||||
const typeRaw = (task.taskIcon ? task.taskIcon.name : task.name) || '';
|
||||
const typeStr = typeRaw.toLowerCase();
|
||||
|
||||
if (typeStr.includes('浇水')) {
|
||||
placeholder = '例如:浇了 200ml 水...';
|
||||
} else if (typeStr.includes('施肥')) {
|
||||
placeholder = '例如:施了通用液肥...';
|
||||
} else if (typeStr.includes('修剪')) {
|
||||
placeholder = '例如:修剪了枯叶和黄叶...';
|
||||
} else if (typeStr.includes('换盆')) {
|
||||
placeholder = '例如:更换了陶盆,加了底肥...';
|
||||
} else if (typeStr.includes('换土')) {
|
||||
placeholder = '例如:更换了新配方土...';
|
||||
} else if (typeStr.includes('喷雾')) {
|
||||
placeholder = '例如:给叶面喷了水...';
|
||||
} else if (typeStr.includes('用药') || typeStr.includes('虫')) {
|
||||
placeholder = '例如:喷洒了杀虫剂...';
|
||||
} else if (typeStr.includes('晒太阳') || typeStr.includes('日照')) {
|
||||
placeholder = '例如:晒了 2 小时太阳...';
|
||||
}
|
||||
|
||||
this.setData({
|
||||
completingTask: task,
|
||||
remark: ''
|
||||
remark: '',
|
||||
remarkPlaceholder: placeholder
|
||||
});
|
||||
},
|
||||
|
||||
@@ -172,16 +239,29 @@ Page({
|
||||
const taskId = this.data.completingTask.id;
|
||||
const remark = this.data.remark || '';
|
||||
|
||||
// Optimistic Update immediately for better feel?
|
||||
// Or wait for server? Wait is safer.
|
||||
wx.showLoading({ title: '提交中...', mask: true });
|
||||
|
||||
request.post('/plant/completeTask', {
|
||||
taskId: taskId,
|
||||
remark: remark
|
||||
}).then(() => {
|
||||
}).then(res => {
|
||||
wx.hideLoading();
|
||||
|
||||
// Handle Rewards
|
||||
const queue = [];
|
||||
// Check if res has level up or badge data
|
||||
// Note: res is already data.data from request.js
|
||||
if (res && res.isLevelUp && res.currentLevel) {
|
||||
queue.push({ type: 'level', data: res.currentLevel });
|
||||
}
|
||||
|
||||
// Check for Badge using IsGetBadge flag (allowing for casing variance)
|
||||
if (res && (res.IsGetBadge === true || res.isGetBadge === true) && res.newBadge) {
|
||||
queue.push({ type: 'badge', data: res.newBadge });
|
||||
}
|
||||
|
||||
this._popupQueue = queue;
|
||||
|
||||
// Optimistic UI Update Logic
|
||||
const groups = this.data.groupedTasks;
|
||||
let updated = false;
|
||||
@@ -208,10 +288,14 @@ Page({
|
||||
showSunshine: true
|
||||
});
|
||||
|
||||
// Hide Animation after duration
|
||||
// Hide Animation after duration and Start showing modals
|
||||
setTimeout(() => {
|
||||
this.setData({ showSunshine: false });
|
||||
}, 3000);
|
||||
// Show rewards after sunshine animation
|
||||
if (this._popupQueue.length > 0) {
|
||||
this.processPopupQueue();
|
||||
}
|
||||
}, 1000); // 1.0s delay usually covers animation
|
||||
|
||||
// Sync with backend silently
|
||||
this.fetchTodayTasks();
|
||||
@@ -227,5 +311,9 @@ Page({
|
||||
wx.switchTab({
|
||||
url: '/pages/garden/index'
|
||||
});
|
||||
},
|
||||
|
||||
onTabItemTap() {
|
||||
this.setData({ scrollTop: Math.random() * 0.01 });
|
||||
}
|
||||
})
|
||||
|
||||
+45
-3
@@ -44,7 +44,7 @@
|
||||
<t-button theme="primary" size="large" shape="round" bind:tap="gotoGarden" class="empty-btn">去看看花园</t-button>
|
||||
</view>
|
||||
|
||||
<scroll-view wx:else scroll-y class="task-list" enhanced show-scrollbar="{{false}}">
|
||||
<scroll-view wx:else scroll-y class="task-list" enhanced show-scrollbar="{{false}}" scroll-top="{{scrollTop}}">
|
||||
<view wx:for="{{groupedTasks}}" wx:key="plantName" class="plant-task-card {{item.hasOverdue ? 'has-overdue' : ''}}">
|
||||
<view class="card-header-row">
|
||||
<view class="plant-info-brief">
|
||||
@@ -85,7 +85,7 @@
|
||||
</view>
|
||||
|
||||
<!-- Complete Task Popup -->
|
||||
<t-popup visible="{{completingTask}}" bind:visible-change="onPopupVisibleChange" placement="center">
|
||||
<t-popup visible="{{completingTask}}" bind:visible-change="onPopupVisibleChange" placement="center" close-on-overlay-click="{{false}}">
|
||||
<view class="modal-card">
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">确认完成任务</text>
|
||||
@@ -110,7 +110,7 @@
|
||||
<text class="remark-label">添加记录备注 (可选)</text>
|
||||
<textarea
|
||||
class="remark-input"
|
||||
placeholder="例如:浇了500ml水..."
|
||||
placeholder="{{remarkPlaceholder}}"
|
||||
value="{{remark}}"
|
||||
bindinput="onRemarkInput"
|
||||
fixed="{{true}}"
|
||||
@@ -131,6 +131,48 @@
|
||||
</view>
|
||||
</t-popup>
|
||||
|
||||
<!-- Level Up Modal -->
|
||||
<t-popup visible="{{showLevelUpModal}}" bind:visible-change="closeLevelUpModal" placement="center" close-on-overlay-click="{{false}}">
|
||||
<view class="reward-modal">
|
||||
<view class="reward-floating-icon level-icon-bg">
|
||||
<t-icon name="chart-bar" size="80rpx" color="#fff" />
|
||||
</view>
|
||||
<view class="reward-content">
|
||||
<text class="reward-title">恭喜升级!</text>
|
||||
<view class="reward-level-tag">
|
||||
<text>Lv.{{levelUpData.level}} {{levelUpData.title}}</text>
|
||||
</view>
|
||||
<view class="reward-desc-box" wx:if="{{levelUpData.perks}}">
|
||||
<text style="font-weight: bold; display: block; margin-bottom: 8rpx; color: #EF6C00;">解锁特权</text>
|
||||
<text>{{levelUpData.perks}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="reward-btn-container">
|
||||
<t-button t-class="reward-btn btn-level" size="large" block bindtap="closeLevelUpModal">太棒了</t-button>
|
||||
</view>
|
||||
</view>
|
||||
</t-popup>
|
||||
|
||||
<!-- New Badge Modal -->
|
||||
<t-popup visible="{{showBadgeModal}}" bind:visible-change="closeBadgeModal" placement="center" close-on-overlay-click="{{false}}">
|
||||
<view class="reward-modal">
|
||||
<view class="reward-floating-icon badge-icon-bg">
|
||||
<image class="reward-badge-img-large" src="{{badgeData.icon.url}}" mode="aspectFit" wx:if="{{badgeData.icon && badgeData.icon.url}}" />
|
||||
<t-icon name="medal" size="80rpx" color="#fff" wx:else />
|
||||
</view>
|
||||
<view class="reward-content">
|
||||
<text class="reward-title">解锁新徽章!</text>
|
||||
<text class="reward-level-tag" style="background: #E3F2FD; color: #1565C0; border-color: #BBDEFB;">{{badgeData.name}}</text>
|
||||
<view class="reward-desc-box">
|
||||
<text>{{badgeData.description}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="reward-btn-container">
|
||||
<t-button t-class="reward-btn btn-badge" size="large" block bindtap="closeBadgeModal">收入囊中</t-button>
|
||||
</view>
|
||||
</view>
|
||||
</t-popup>
|
||||
|
||||
<!-- Sunshine Animation Layer -->
|
||||
<view class="sunshine-layer" wx:if="{{showSunshine}}">
|
||||
<view class="sunshine-pkg">
|
||||
|
||||
@@ -864,3 +864,142 @@
|
||||
0% { transform: translateY(20rpx); opacity: 0; }
|
||||
100% { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
|
||||
/* Reward Modals - Enhanced */
|
||||
.reward-modal {
|
||||
background: #fff;
|
||||
width: 580rpx;
|
||||
border-radius: 40rpx;
|
||||
padding-top: 100rpx; /* Space for floating icon */
|
||||
padding-bottom: 40rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
overflow: visible; /* Allow floating elements */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-shadow: 0 24rpx 64rpx rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Background decorator inside modal (top curve) */
|
||||
.reward-modal::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 200rpx;
|
||||
background: linear-gradient(180deg, #F5F5F5 0%, #FFFFFF 100%);
|
||||
border-radius: 40rpx 40rpx 0 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Floating Icon Wrapper */
|
||||
.reward-floating-icon {
|
||||
position: absolute;
|
||||
top: -80rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 16rpx 32rpx rgba(0,0,0,0.15);
|
||||
z-index: 2;
|
||||
background: white; /* Fallback */
|
||||
}
|
||||
|
||||
.level-icon-bg {
|
||||
background: linear-gradient(135deg, #FFB74D, #EF6C00);
|
||||
border: 8rpx solid #fff;
|
||||
}
|
||||
|
||||
.badge-icon-bg {
|
||||
background: linear-gradient(135deg, #64B5F6, #1565C0);
|
||||
border: 8rpx solid #fff;
|
||||
}
|
||||
|
||||
/* Actual Image/Icon */
|
||||
.reward-badge-img-large {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
filter: drop-shadow(0 4rpx 8rpx rgba(0,0,0,0.2));
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.reward-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
padding: 0 48rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.reward-title {
|
||||
font-size: 44rpx;
|
||||
font-weight: 900;
|
||||
color: #263238;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
/* Level Styles */
|
||||
.reward-level-tag {
|
||||
background: #FFF3E0;
|
||||
color: #EF6C00;
|
||||
padding: 8rpx 24rpx;
|
||||
border-radius: 32rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
border: 2rpx solid #FFE0B2;
|
||||
}
|
||||
|
||||
/* Description Box */
|
||||
.reward-desc-box {
|
||||
background: #FAFAFA;
|
||||
border: 2rpx solid #F5F5F5;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
width: 100%;
|
||||
color: #546E7A;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.6;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Button */
|
||||
.reward-btn-container {
|
||||
width: 100%;
|
||||
padding: 0 48rpx;
|
||||
margin-top: 40rpx;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Custom Button Style override */
|
||||
.reward-btn {
|
||||
border-radius: 48rpx !important;
|
||||
font-weight: 700 !important;
|
||||
font-size: 32rpx !important;
|
||||
height: 96rpx !important;
|
||||
box-shadow: 0 12rpx 24rpx rgba(255, 152, 0, 0.3); /* Default orange shadow */
|
||||
}
|
||||
|
||||
.btn-level {
|
||||
background: linear-gradient(90deg, #FF9800, #F57C00) !important;
|
||||
color: white !important;
|
||||
box-shadow: 0 12rpx 24rpx rgba(245, 124, 0, 0.4) !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.btn-badge {
|
||||
background: linear-gradient(90deg, #42A5F5, #1976D2) !important;
|
||||
color: white !important;
|
||||
box-shadow: 0 12rpx 24rpx rgba(25, 118, 210, 0.4) !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user