// pages/plant-detail/edit/index.js import request from '../../../utils/request'; import { CARE_TASK_ICONS } from '../../../utils/constant'; Page({ data: { plantId: '', newPlantName: '', newPlantLocation: '', newPlantDate: '', newPlantImage: null, isLocalImage: false, uploadedImageId: '', potMaterial: '', potSize: '', sunlight: '', plantingMaterial: '', newCareTasks: [], scrollIntoViewId: '', showActionSheet: false, actionSheetItems: [ { label: '拍照', value: 'camera' }, { label: '从相册选取', value: 'album' } ], careTaskIcons: [], showIconPicker: false, currentEditingTaskId: null }, onLoad(options) { const { id } = options; if (!id) { wx.navigateBack(); return; } this.setData({ plantId: id, careTaskIcons: CARE_TASK_ICONS }); const eventChannel = this.getOpenerEventChannel(); let hasReceivedData = false; if (eventChannel) { eventChannel.on('acceptDataFromOpenerPage', (data) => { if (data && data.plant) { hasReceivedData = true; this.renderPlantUI(data.plant); } }); } const isFromDetail = options.source === 'detail'; setTimeout(() => { if (!hasReceivedData) this.fetchPlantDetail(id); }, isFromDetail ? 2000 : 0); }, fetchPlantDetail(id) { request.get('/plant/detail', { id }).then(plant => { this.renderPlantUI(plant); }).catch(err => { console.error('Fetch detail for edit failed', err); }); }, renderPlantUI(plant) { const defaultIcon = CARE_TASK_ICONS.find(i => i.id === 'water') || CARE_TASK_ICONS[0]; let tasks = []; if (plant.careSchedule) { tasks = plant.careSchedule.map(cp => ({ id: cp.id, name: cp.name, period: cp.period, taskIcon: cp.taskIcon, isNew: false, _original: { name: cp.name, period: cp.period, icon: JSON.stringify(cp.taskIcon || {}) } })); } else if (plant.carePlans) { tasks = plant.carePlans.map(cp => { let iconObj = defaultIcon; if (typeof cp.icon === 'string' && cp.icon.startsWith('{')) { try { iconObj = JSON.parse(cp.icon); } catch (e) { } } const iconStr = JSON.stringify(iconObj); return { id: cp.id, name: cp.name, period: cp.period, taskIcon: iconObj, isNew: false, _original: { name: cp.name, period: cp.period, icon: iconStr } }; }); } let imageUrl = '', imageId = ''; if (plant.imgList && plant.imgList.length > 0) { imageUrl = plant.imgList[0].url || ''; imageId = plant.imgList[0].id || ''; } let adoptionDate = plant.plantTime || ''; if (adoptionDate.includes('T')) adoptionDate = adoptionDate.split('T')[0]; this.setData({ newPlantName: plant.name || '', newPlantLocation: plant.placement || '', newPlantDate: adoptionDate, newPlantImage: imageUrl, uploadedImageId: imageId, potMaterial: plant.potMaterial || '', potSize: plant.potSize || '', sunlight: plant.sunlight || '', plantingMaterial: plant.plantingMaterial || '', newCareTasks: tasks }); // Store original base fields for change detection this._originalPlant = { name: plant.name || '', placement: plant.placement || '', potMaterial: plant.potMaterial || '', potSize: plant.potSize || '', sunlight: plant.sunlight || '', plantingMaterial: plant.plantingMaterial || '' }; }, handleBack() { wx.navigateBack(); }, // ======== Image Upload ======== showActionSheet() { this.setData({ showActionSheet: true }); }, onActionSheetCancel() { this.setData({ showActionSheet: false }); }, onActionSheetSelected(e) { const { value } = e.detail.selected; this.handleImageUpload(value); this.setData({ showActionSheet: false }); }, handleImageUpload(sourceType) { wx.chooseMedia({ count: 1, mediaType: ['image'], sourceType: [sourceType], camera: 'back', success: (res) => { const tempFilePath = res.tempFiles[0].tempFilePath; this.setData({ newPlantImage: tempFilePath, isLocalImage: true }); wx.showLoading({ title: '上传中...' }); request.upload(tempFilePath).then(data => { wx.hideLoading(); const fileData = data?.file || {}; if (fileData.id) { this.setData({ uploadedImageId: fileData.id, newPlantImage: fileData.url }); } }).catch(() => { wx.hideLoading(); wx.showToast({ title: '上传失败', icon: 'none' }); }); } }); }, // ======== Form Inputs ======== onNameInput(e) { this.setData({ newPlantName: e.detail.value }); }, onLocationInput(e) { this.setData({ newPlantLocation: e.detail.value }); }, onDateChange(e) { this.setData({ newPlantDate: e.detail.value }); }, onPotMaterialInput(e) { this.setData({ potMaterial: e.detail.value }); }, onPotSizeInput(e) { this.setData({ potSize: e.detail.value }); }, onSunlightInput(e) { this.setData({ sunlight: e.detail.value }); }, onPlantingMaterialInput(e) { this.setData({ plantingMaterial: e.detail.value }); }, // ======== Care Plan: Local Add ======== handleAddCareTask() { const defaultIcon = CARE_TASK_ICONS.find(i => i.id === 'other') || CARE_TASK_ICONS[0]; const tasks = [...this.data.newCareTasks, { id: 'new_' + Date.now(), name: '', period: 7, iconId: 'other', taskIcon: defaultIcon, isNew: true // Mark as new, not yet saved to backend }]; this.setData({ newCareTasks: tasks, scrollIntoViewId: '' }, () => { setTimeout(() => { this.setData({ scrollIntoViewId: 'care-list-bottom' }); }, 50); }); }, // ======== Care Plan: Delete ======== handleRemoveCareTask(e) { const id = e.currentTarget.dataset.id; const task = this.data.newCareTasks.find(t => t.id === id); // New (unsaved) tasks: just remove locally if (task && task.isNew) { const tasks = this.data.newCareTasks.filter(t => t.id !== id); this.setData({ newCareTasks: tasks }); return; } // Existing tasks: confirm then call API wx.showModal({ title: '确认删除', content: '确定要删除这个养护事项吗?', confirmColor: '#EF5350', success: (res) => { if (!res.confirm) return; wx.showLoading({ title: '删除中...' }); request.get('/plant/plan/delete', { id: id }).then(() => { wx.hideLoading(); const tasks = this.data.newCareTasks.filter(t => t.id !== id); this.setData({ newCareTasks: tasks }); wx.showToast({ title: '已删除', icon: 'success' }); }).catch(err => { wx.hideLoading(); console.error('Delete care plan failed', err); }); } }); }, // ======== Care Task Inline Editing ======== onTaskNameInput(e) { const { id } = e.currentTarget.dataset; const tasks = this.data.newCareTasks.map(t => t.id === id ? { ...t, name: e.detail.value } : t ); this.setData({ newCareTasks: tasks }); }, onTaskFreqInput(e) { const { id } = e.currentTarget.dataset; const raw = e.detail.value; const val = raw === '' ? '' : (parseInt(raw) || ''); const tasks = this.data.newCareTasks.map(t => t.id === id ? { ...t, period: val } : t ); this.setData({ newCareTasks: tasks }); }, // ======== Icon Picker ======== showIconPickerForTask(e) { this.setData({ showIconPicker: true, currentEditingTaskId: e.currentTarget.dataset.id }); }, hideIconPicker() { this.setData({ showIconPicker: false, currentEditingTaskId: null }); }, selectIcon(e) { const iconId = e.currentTarget.dataset.iconid; const { currentEditingTaskId, careTaskIcons, newCareTasks } = this.data; const selectedIcon = careTaskIcons.find(i => i.id === iconId); if (selectedIcon && currentEditingTaskId) { const updatedTasks = newCareTasks.map(t => { if (t.id === currentEditingTaskId) { return { ...t, iconId, taskIcon: selectedIcon, name: t.name || selectedIcon.name }; } return t; }); this.setData({ newCareTasks: updatedTasks, showIconPicker: false, currentEditingTaskId: null }); } }, // ======== Save All ======== handleSavePlant() { const { plantId, newPlantName, newPlantLocation, potMaterial, potSize, sunlight, plantingMaterial, newCareTasks } = this.data; if (!newPlantName) { wx.showToast({ title: '请输入植物名称', icon: 'none' }); return; } // Validate all care task periods for (const task of newCareTasks) { const p = parseInt(task.period); if (!p || p < 1) { wx.showToast({ title: `"${task.name || '未命名事项'}" 的周期天数不合法`, icon: 'none' }); return; } if (!task.name) { wx.showToast({ title: '请填写所有养护事项名称', icon: 'none' }); return; } } // Split tasks into existing and new const existingTasks = newCareTasks.filter(t => !t.isNew); const newTasks = newCareTasks.filter(t => t.isNew); // Only include MODIFIED existing tasks in carePlans const modifiedPlans = existingTasks.filter(task => { if (!task._original) return false; const currentIcon = JSON.stringify(task.taskIcon || {}); return task.name !== task._original.name || parseInt(task.period) !== task._original.period || currentIcon !== task._original.icon; }).map(task => ({ id: String(task.id), name: task.name, period: parseInt(task.period) || 1, icon: JSON.stringify(task.taskIcon || {}), targetAction: (task.taskIcon && task.taskIcon.targetAction) ? task.taskIcon.targetAction : '' })); // Build payload for /plant/update (UpdateMyPlant struct) const updatePayload = { id: plantId, name: newPlantName, placement: newPlantLocation || '', potMaterial: potMaterial || '', potSize: potSize || '', sunlight: sunlight || '', plantingMaterial: plantingMaterial || '', carePlans: modifiedPlans }; // Build payload for /plant/plan/add if there are new tasks (AddPlans struct) const addPayload = newTasks.length > 0 ? { carePlan: newTasks.map(task => ({ plantId: plantId, name: task.name, period: parseInt(task.period) || 1, icon: JSON.stringify(task.taskIcon || {}), targetAction: (task.taskIcon && task.taskIcon.targetAction) ? task.taskIcon.targetAction : '' })) } : null; // Check if base fields changed const orig = this._originalPlant || {}; const baseChanged = newPlantName !== orig.name || (newPlantLocation || '') !== orig.placement || (potMaterial || '') !== orig.potMaterial || (potSize || '') !== orig.potSize || (sunlight || '') !== orig.sunlight || (plantingMaterial || '') !== orig.plantingMaterial; const needUpdate = baseChanged || modifiedPlans.length > 0; const needAdd = addPayload !== null; if (!needUpdate && !needAdd) { wx.showToast({ title: '没有修改', icon: 'none' }); return; } wx.showLoading({ title: '保存中...' }); const promises = []; if (needUpdate) { promises.push(request.post('/plant/update', updatePayload)); } if (needAdd) { promises.push(request.post('/plant/plan/add', addPayload)); } Promise.all(promises).then(() => { wx.hideLoading(); wx.showToast({ title: '保存成功', icon: 'success' }); setTimeout(() => { wx.navigateBack(); }, 1000); }).catch(err => { wx.hideLoading(); console.error('Save failed', err); }); }, })