281 lines
8.6 KiB
JavaScript
281 lines
8.6 KiB
JavaScript
// pages/plant-detail/index.js
|
|
import request from '../../utils/request';
|
|
|
|
Page({
|
|
data: {
|
|
currentPlant: null,
|
|
activeImageIndex: 0,
|
|
activeTab: 'care',
|
|
careLogs: [],
|
|
displayCareLogs: [],
|
|
displayCareLimit: 5,
|
|
records: [],
|
|
displayRecords: [],
|
|
displayRecordLimit: 5,
|
|
swiperImages: [],
|
|
|
|
// Growth Modal
|
|
showGrowthModal: false,
|
|
newRecordType: 'growth',
|
|
newRecordContent: '',
|
|
newRecordImage: ''
|
|
},
|
|
|
|
onLoad(options) {
|
|
if (options.id) {
|
|
this.initData(options.id);
|
|
}
|
|
},
|
|
|
|
onShow() {
|
|
if (this.data.currentPlant && this.data.currentPlant.id) {
|
|
this.initData(this.data.currentPlant.id);
|
|
}
|
|
},
|
|
|
|
initData(id) {
|
|
request.get('/plant/detail', { id }).then(plant => {
|
|
const swiperImages = plant.imgList.map(img => {
|
|
return img.url;
|
|
});
|
|
// Parse carePlans icon if it's a string
|
|
const carePlans = (plant.carePlans || []).map(cp => {
|
|
let iconObj = {};
|
|
if (typeof cp.icon === 'string' && cp.icon.startsWith('{')) {
|
|
try {
|
|
iconObj = JSON.parse(cp.icon);
|
|
} catch (e) {
|
|
console.error('Parse icon error', e);
|
|
}
|
|
}
|
|
return { ...cp, taskIcon: iconObj };
|
|
});
|
|
|
|
this.setData({
|
|
currentPlant: {
|
|
...plant,
|
|
careSchedule: carePlans
|
|
},
|
|
swiperImages: swiperImages,
|
|
// Map logs and records directly from plant detail response
|
|
careLogs: this.processLogs(plant.careRecords || []),
|
|
records: (plant.growthRecords || plant.recordList || []).map(item => ({
|
|
id: item.id,
|
|
date: item.createdAtStr ? item.createdAtStr.split(' ')[0] : '',
|
|
type: item.recordType || 'growth',
|
|
title: item.title,
|
|
content: item.content,
|
|
image: (item.imgList && item.imgList.length > 0) ? item.imgList[0].url : ''
|
|
}))
|
|
});
|
|
|
|
this.updateDisplayLogs();
|
|
this.updateDisplayRecords();
|
|
|
|
}).catch(err => {
|
|
console.error('Fetch detail failed', err);
|
|
});
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
processLogs(logs) {
|
|
return logs.map(log => {
|
|
// Handle time format (e.g., 2025-02-02 10:00:00)
|
|
const timeStr = log.createdAtStr || log.opTime || log.createTime || '';
|
|
let dateStr = timeStr;
|
|
let timeOnly = '';
|
|
|
|
if (timeStr.includes(' ')) {
|
|
const parts = timeStr.split(' ');
|
|
dateStr = parts[0];
|
|
timeOnly = parts[1].substring(0, 5); // HH:mm
|
|
}
|
|
|
|
const dateParts = dateStr.split('-');
|
|
const month = dateParts.length > 1 ? dateParts[1] : '';
|
|
const day = dateParts.length > 2 ? dateParts[2] : '';
|
|
|
|
// Map icon properties from icon JSON
|
|
let type = 'other';
|
|
let taskIcon = 'assignment'; // Default TDesign icon
|
|
let iconColor = '#8D6E63';
|
|
let iconBgColor = '#EFEBE9';
|
|
|
|
if (log.icon && typeof log.icon === 'string' && log.icon.startsWith('{')) {
|
|
try {
|
|
const iconObj = JSON.parse(log.icon);
|
|
if (iconObj.id) type = iconObj.id;
|
|
if (iconObj.icon) taskIcon = iconObj.icon;
|
|
if (iconObj.color) iconColor = iconObj.color;
|
|
if (iconObj.bgColor) iconBgColor = iconObj.bgColor;
|
|
} catch (e) { }
|
|
} else if (log.opType) {
|
|
type = log.opType;
|
|
}
|
|
|
|
// Use name directly if available
|
|
const typeLabel = log.name || this.getCareTypeLabel(type);
|
|
|
|
return {
|
|
...log,
|
|
day: day,
|
|
month: month,
|
|
time: timeOnly,
|
|
type: type,
|
|
typeLabel: typeLabel,
|
|
remark: log.remark || log.content || '',
|
|
taskIcon: taskIcon,
|
|
iconColor: iconColor,
|
|
iconBgColor: iconBgColor
|
|
};
|
|
});
|
|
},
|
|
|
|
getCareTypeLabel(type) {
|
|
const map = {
|
|
water: '浇水',
|
|
fertilize: '施肥',
|
|
prune: '修剪',
|
|
repot: '换盆',
|
|
pesticide: '除虫',
|
|
sun: '晒太阳',
|
|
other: '养护'
|
|
};
|
|
return map[type] || '日常养护';
|
|
},
|
|
|
|
updateDisplayLogs() {
|
|
this.setData({
|
|
displayCareLogs: this.data.careLogs.slice(0, this.data.displayCareLimit)
|
|
});
|
|
},
|
|
|
|
onSwiperChange(e) {
|
|
this.setData({ activeImageIndex: e.detail.current });
|
|
},
|
|
|
|
switchTab(e) {
|
|
const tab = e.currentTarget.dataset.tab;
|
|
if (tab) {
|
|
this.setData({ activeTab: tab });
|
|
}
|
|
},
|
|
|
|
// Prevent background scroll when modal is open
|
|
preventTouchMove() {
|
|
return false;
|
|
},
|
|
|
|
toggleCareLimit() {
|
|
const newLimit = this.data.displayCareLimit + 5;
|
|
this.setData({ displayCareLimit: newLimit });
|
|
this.updateDisplayLogs();
|
|
},
|
|
|
|
updateDisplayRecords() {
|
|
this.setData({
|
|
displayRecords: this.data.records.slice(0, this.data.displayRecordLimit)
|
|
});
|
|
},
|
|
|
|
toggleRecordLimit() {
|
|
const newLimit = this.data.displayRecordLimit + 5;
|
|
this.setData({ displayRecordLimit: newLimit });
|
|
this.updateDisplayRecords();
|
|
},
|
|
|
|
// Navigate to Edit Page with EventChannel
|
|
handleOpenEditModal() {
|
|
if (this.data.currentPlant && this.data.currentPlant.id) {
|
|
wx.navigateTo({
|
|
url: `/pages/plant-detail/edit/index?id=${this.data.currentPlant.id}&source=detail`,
|
|
success: (res) => {
|
|
// Send current data to the opened page
|
|
res.eventChannel.emit('acceptDataFromOpenerPage', {
|
|
plant: this.data.currentPlant
|
|
});
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// Growth Record Logic
|
|
openGrowthModal() {
|
|
this.setData({
|
|
showGrowthModal: true,
|
|
newRecordContent: '',
|
|
newRecordType: 'growth',
|
|
newRecordImage: ''
|
|
});
|
|
},
|
|
onGrowthPopupVisibleChange(e) { this.setData({ showGrowthModal: e.detail.visible }); },
|
|
closeGrowthModal() { this.setData({ showGrowthModal: false }); },
|
|
|
|
setRecordType(e) {
|
|
const type = e.currentTarget.dataset.type;
|
|
if (e.detail.checked) {
|
|
this.setData({ newRecordType: type });
|
|
}
|
|
},
|
|
setRecordTypeByTap(e) {
|
|
const type = e.currentTarget.dataset.type;
|
|
this.setData({ newRecordType: type });
|
|
},
|
|
onRecordContentInput(e) { this.setData({ newRecordContent: e.detail.value }); },
|
|
|
|
handleChooseRecordImage() {
|
|
wx.chooseMedia({
|
|
count: 1,
|
|
mediaType: ['image'],
|
|
sourceType: ['album', 'camera'],
|
|
success: (res) => {
|
|
this.setData({
|
|
newRecordImage: res.tempFiles[0].tempFilePath
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
handleRemoveRecordImage() {
|
|
this.setData({ newRecordImage: '' });
|
|
},
|
|
|
|
handlePreviewRecordImage(e) {
|
|
const src = e.currentTarget.dataset.src;
|
|
const fullPath = (src.indexOf('http') === 0 || src.indexOf('wxfile') === 0) ? src : `/assets/${src}`;
|
|
|
|
wx.previewImage({
|
|
current: fullPath,
|
|
urls: [fullPath]
|
|
});
|
|
},
|
|
|
|
handleAddRecord() {
|
|
if (!this.data.newRecordContent.trim()) return;
|
|
|
|
const mapTitle = { growth: '生长记录', repot: '换盆记录', pest: '病虫害记录', other: '日常记录' };
|
|
const now = new Date();
|
|
const dateStr = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')}`;
|
|
|
|
const record = {
|
|
id: Date.now().toString(),
|
|
date: dateStr,
|
|
type: this.data.newRecordType,
|
|
title: mapTitle[this.data.newRecordType],
|
|
content: this.data.newRecordContent,
|
|
image: this.data.newRecordImage
|
|
};
|
|
|
|
this.setData({
|
|
records: [record, ...this.data.records],
|
|
showGrowthModal: false
|
|
});
|
|
this.updateDisplayRecords();
|
|
|
|
wx.showToast({ title: '记录成功', icon: 'success' });
|
|
}
|
|
})
|