import { getOrderInfo, getOrderLogs, uploadFile, clockIn, getAnomalyList } from '@/api/fulfiller' import { getServiceList, getServiceDetail } from '@/api/service' import { getDictDataByType } from '@/api/system/dict/index' import { getPetDetail } from '@/api/archieves/pet/index' export default { data() { return { orderId: null, pageLoading: true, // 页面数据加载中 orderType: 1, orderStatus: 2, serviceId: null, // 当前订单的服务类型ID petId: null, // 当前订单关联的宠物ID petDetail: null, // 宠物档案详情 // 从后端 clockInRemark 解析出的打卡步骤列表 // 格式: [{step:1, title:'到达打卡', remark:'照片视频二选一即可'}, ...] clockInSteps: [], // 当前应执行的打卡信息(从 clockInSteps 中取出) currentClockIn: null, currentStep: 0, orderDetail: { type: 1, price: '0.00', timeLabel: '服务时间', time: '', petAvatar: '/static/dog.png', petName: '', petBreed: '', serviceTag: '', startLocation: '', startAddress: '', endLocation: '', endAddress: '', serviceContent: '', remark: '', orderNo: '', createTime: '', progressLogs: [] }, serviceList: [], showPetModal: false, currentPetInfo: {}, showNavModal: false, navTargetPointType: '', showUploadModal: false, modalMediaList: [], modalRemark: '', showSumModal: false, sumContent: '', sumDate: '', sumSigner: '张*哥', showPetRemarkInput: false, petRemarkText: '', showAnomalyModal: false, anomalyList: [], anomalyTypeDict: [] } }, computed: { // 从 clockInSteps 中提取 title 数组作为打卡步骤名(内部逻辑用) steps() { if (this.clockInSteps.length > 0) { return this.clockInSteps.map(s => s.title) } // 兜底:如果 clockInSteps 未加载则使用默认 return this.orderType === 1 ? ['到达打卡', '确认出发', '送达打卡'] : ['到达打卡', '开始服务', '服务结束'] }, // 顶部进度条展示用:已接单 -> 各打卡步骤 -> 订单完成 progressSteps() { return ['已接单', ...this.steps, '订单完成'] }, // 进度条当前激活索引(= currentStep + 1,因为首位是"已接单") progressIndex() { // 已接单是第0步,始终已完成;打卡步骤从索引1开始 return this.currentStep + 1 }, displayStatusText() { if (this.currentStep >= this.steps.length) return '已完成'; // 判断是否在服务中 if (this.currentStep > 0) { return this.orderType === 1 ? '配送中' : '服务中'; } return this.orderType === 1 ? '待接送' : '待服务'; }, currentStatusText() { return this.currentStep >= this.steps.length ? '已完成' : this.steps[this.currentStep]; }, // 按钮文本:使用 clockInSteps 中对应步骤的 title currentTaskTitle() { if (this.currentStep >= this.steps.length) return '订单已完成'; if (this.currentClockIn) { return this.currentClockIn.title; } return this.steps[this.currentStep] || '打卡'; }, // 任务描述小字:使用 clockInSteps 中对应步骤的 remark currentTaskDesc() { if (this.currentStep >= this.steps.length) return '感谢您的服务,请注意休息'; if (this.currentClockIn && this.currentClockIn.remark) { return this.currentClockIn.remark; } return '请按要求提交照片或视频及备注'; } }, async onLoad(options) { if (options.id) { this.orderId = options.id } this.pageLoading = true try { // 先加载字典 await this.loadAnomalyTypeDict() // 先获取服务列表(用于匹配服务类型名称等) await this.loadServiceList() // 获取订单详情(内部会拿到 serviceId,然后加载服务详情获取 clockInRemark) await this.loadOrderDetail() } finally { this.pageLoading = false } }, methods: { async loadServiceList() { try { const res = await getServiceList() this.serviceList = res.data || [] } catch (err) { console.error('获取服务类型失败:', err) } }, /** * 根据服务类型ID获取服务详情,解析 clockInRemark 为打卡步骤 */ async loadServiceDetail(serviceId) { try { const res = await getServiceDetail(serviceId) const serviceInfo = res.data if (serviceInfo && serviceInfo.clockInRemark) { try { const parsed = JSON.parse(serviceInfo.clockInRemark) if (Array.isArray(parsed) && parsed.length > 0) { this.clockInSteps = parsed console.log('解析打卡步骤:', this.clockInSteps) } } catch (parseErr) { console.error('解析 clockInRemark 失败:', parseErr) } } } catch (err) { console.error('获取服务类型详情失败:', err) } }, async loadOrderDetail() { if (!this.orderId) { console.log('订单ID缺失') uni.showToast({ title: '订单ID缺失', icon: 'none' }) return } try { console.log('请求订单详情,ID:', this.orderId) const res = await getOrderInfo(this.orderId) console.log('订单详情响应:', res) const order = res.data if (!order) { console.log('订单数据为空') uni.showToast({ title: '订单不存在', icon: 'none' }) return } console.log('订单数据:', order) this.serviceId = order.service this.petId = order.usrPet || null this.transformOrderData(order) // 根据订单的服务类型ID获取服务详情(含 clockInRemark) if (this.serviceId) { await this.loadServiceDetail(this.serviceId) } // 加载宠物档案详情 if (this.petId) { await this.loadPetDetail(this.petId) } // 加载订单日志并根据 step 确定当前进度 await this.loadOrderLogs() } catch (err) { console.error('获取订单详情失败:', err) uni.showToast({ title: '加载失败', icon: 'none' }) } }, async loadOrderLogs() { try { const res = await getOrderLogs(this.orderId) const logs = res.data || [] console.log('订单日志:', logs) // 渲染进度日志列表 const progressLogs = logs.filter(log => log.logType === 1) this.orderDetail.progressLogs = progressLogs.map(log => ({ status: log.title || '', time: log.createTime || '', medias: log.photoUrls || [], remark: log.content || '' })) // 根据打卡日志的 step 确定下一步骤 // 查找最新的一条打卡日志(logType=1),取其 step,下一步为 step+1 const validLogs = logs.filter(log => log.logType === 1 && log.step !== undefined && log.step !== null) .sort((a, b) => new Date(b.createTime).getTime() - new Date(a.createTime).getTime()) if (validLogs.length > 0) { const latestLog = validLogs[0] const latestStep = latestLog.step console.log('最新打卡日志 step:', latestStep) // 在 clockInSteps 中找到该 step 对应的索引,然后 +1 得到下一步 const stepIndex = this.clockInSteps.findIndex(s => s.step === latestStep) if (stepIndex >= 0) { this.currentStep = stepIndex + 1 } else { // 兜底:直接按 step 值推算 this.currentStep = latestStep } } else { this.currentStep = 0 } // 更新当前打卡信息 this.updateCurrentClockIn() console.log('根据最新日志推算的当前步骤:', this.currentStep, '当前打卡信息:', this.currentClockIn) } catch (err) { console.error('获取订单日志失败:', err) } }, /** * 根据 currentStep 更新当前打卡信息 */ updateCurrentClockIn() { if (this.currentStep < this.clockInSteps.length) { this.currentClockIn = this.clockInSteps[this.currentStep] } else { this.currentClockIn = null } }, transformOrderData(order) { const mode = order.mode || 0 const isRoundTrip = mode === 1 this.orderType = isRoundTrip ? 1 : 2 this.orderStatus = order.status || 2 this.orderDetail = { type: this.orderType, price: (order.price / 100).toFixed(2), timeLabel: isRoundTrip ? '取货时间' : '服务时间', time: order.serviceTime || '', petAvatar: '/static/dog.png', petName: order.petName || order.contact || '', petBreed: order.breed || '', serviceTag: order.groupPurchasePackageName || '', startLocation: order.fromAddress || '', startAddress: order.fromAddress || '', endLocation: (order.contact || '') + ' ' + (order.contactPhoneNumber || ''), endAddress: order.toAddress || '', serviceContent: '', remark: '', orderNo: order.code || 'T' + order.id, createTime: order.serviceTime || '', progressLogs: [ { status: '您已接单', time: order.serviceTime || '' } ] } }, /** * 根据宠物ID获取宠物档案详情 */ async loadPetDetail(petId) { try { const res = await getPetDetail(petId) const pet = res.data if (pet) { this.petDetail = pet // 同步更新订单详情中的宠物信息 this.orderDetail.petAvatar = pet.avatarUrl || '/static/dog.png' this.orderDetail.petName = pet.name || this.orderDetail.petName this.orderDetail.petBreed = pet.breed || this.orderDetail.petBreed console.log('宠物档案:', pet) } } catch (err) { console.error('获取宠物档案失败:', err) } }, /** * 加载异常记录列表 */ async loadAnomalyList() { if (!this.orderId) return try { const res = await getAnomalyList(this.orderId) const list = res.data || [] // 过滤和转换 this.anomalyList = list.map(item => { // 映射类型 const dict = this.anomalyTypeDict.find(d => d.value === item.type) return { ...item, typeLabel: dict ? dict.label : item.type, // 确保有图片数组供展示,如果后端没返 photoUrls,尝试兼容 photoUrls: item.photoUrls || [] } }) } catch (err) { console.error('获取异常列表失败:', err) } }, async loadAnomalyTypeDict() { try { const res = await getDictDataByType('flf_anamaly_type') this.anomalyTypeDict = res.data.map(item => ({ label: item.dictLabel, value: item.dictValue })) } catch (err) { console.error('获取异常字典失败:', err) } }, openAnomalyModal() { this.showAnomalyModal = true this.loadAnomalyList() }, closeAnomalyModal() { this.showAnomalyModal = false }, getAnomalyStatusLabel(status) { const map = { 0: '待审核', 1: '已通过', 2: '已驳回' } return map[status] || '未知' }, updateStepByStatus() { if (this.orderStatus === 2) { this.currentStep = 0 } else if (this.orderStatus === 3) { this.currentStep = 1 } else if (this.orderStatus === 5) { this.currentStep = this.steps.length - 1 } else { this.currentStep = 0 } }, showPetProfile() { const pet = this.petDetail if (pet) { // 使用后端返回的真实宠物数据 this.currentPetInfo = { petAvatar: pet.avatarUrl || '/static/dog.png', petName: pet.name || '', petBreed: pet.breed || '', petGender: pet.gender === 1 ? 'M' : (pet.gender === 2 ? 'F' : ''), petAge: pet.age ? pet.age + '岁' : '未知', petWeight: pet.weight ? pet.weight + 'kg' : '未知', petPersonality: pet.personality || pet.cutePersonality || '无', petHobby: '', petRemark: pet.remark || '无', petTags: (pet.tags || []).map(t => t.name), petLogs: [], // 额外信息 petSize: pet.size || '', petIsSterilized: pet.isSterilized, petHealthStatus: pet.healthStatus || '', petAllergies: pet.allergies || '', petMedicalHistory: pet.medicalHistory || '', petVaccineStatus: pet.vaccineStatus || '', ownerName: pet.ownerName || '', ownerPhone: pet.ownerPhone || '' } } else { // 兜底:如果宠物档案未加载成功,使用订单中的基本信息 this.currentPetInfo = { ...this.orderDetail, petGender: '', petAge: '未知', petWeight: '未知', petPersonality: '无', petHobby: '', petRemark: '无', petTags: [], petLogs: [] } } this.showPetModal = true }, closePetProfile() { this.showPetModal = false; }, openPetRemarkInput() { this.petRemarkText = ''; this.showPetRemarkInput = true; }, closePetRemarkInput() { this.showPetRemarkInput = false; }, submitPetRemark() { if (!this.petRemarkText.trim()) { uni.showToast({ title: '备注内容不能为空', icon: 'none' }); return; } const now = new Date(); const date = `${now.getFullYear()}/${String(now.getMonth() + 1).padStart(2, '0')}/${String(now.getDate()).padStart(2, '0')}`; if (!this.currentPetInfo.petLogs) { this.currentPetInfo.petLogs = []; } this.currentPetInfo.petLogs.unshift({ date: date, content: this.petRemarkText, recorder: '张*哥' }); this.closePetRemarkInput(); uni.showToast({ title: '备注已添加', icon: 'success' }); }, goToAnomaly() { uni.navigateTo({ url: '/pages/orders/anomaly?orderId=' + (this.orderDetail.orderNo || '') }); }, callPhone() { uni.makePhoneCall({ phoneNumber: '18900008451' }); }, openNavigation(type) { this.navTargetPointType = type; this.showNavModal = true; }, closeNavModal() { this.showNavModal = false; }, chooseMap(mapType) { let pointType = this.navTargetPointType; let name = pointType === 'start' ? this.orderDetail.startLocation : this.orderDetail.endLocation; let address = pointType === 'start' ? this.orderDetail.startAddress : this.orderDetail.endAddress; this.showNavModal = false; uni.openLocation({ latitude: 30.52, // Mock lat longitude: 114.31, // Mock lng name: name || '目的地', address: address || '默认地址', success: function () { console.log('打开导航成功: ' + mapType); } }); }, openUploadModal() { this.modalMediaList = []; this.modalRemark = ''; this.showUploadModal = true; }, closeUploadModal() { this.showUploadModal = false; }, handleConfirmUpload() { console.log('handleConfirmUpload被调用'); this.confirmUploadModal(); }, async chooseModalMedia() { console.log('chooseModalMedia被调用'); uni.chooseImage({ count: 5 - this.modalMediaList.length, success: async (res) => { console.log('选择图片成功,文件路径:', res.tempFilePaths); uni.showLoading({ title: '上传中...' }); try { for (const filePath of res.tempFilePaths) { console.log('上传文件:', filePath); const uploadRes = await uploadFile(filePath); console.log('上传响应:', uploadRes); if (uploadRes.code === 200) { this.modalMediaList.push({ url: uploadRes.data.url, ossId: uploadRes.data.ossId, localPath: filePath }); console.log('上传成功,url:', uploadRes.data.url); } } uni.hideLoading(); console.log('当前modalMediaList:', this.modalMediaList); uni.showToast({ title: '上传成功', icon: 'success' }); } catch (err) { uni.hideLoading(); console.error('上传失败:', err); uni.showToast({ title: '上传失败', icon: 'none' }); } }, fail: (err) => { console.error('选择图片失败:', err); } }); }, removeModalMedia(index) { this.modalMediaList.splice(index, 1); }, getCurrentTime() { const now = new Date(); const y = now.getFullYear(); const m = String(now.getMonth() + 1).padStart(2, '0'); const d = String(now.getDate()).padStart(2, '0'); const h = String(now.getHours()).padStart(2, '0'); const min = String(now.getMinutes()).padStart(2, '0'); return `${y}/${m}/${d} ${h}:${min}`; }, async confirmUploadModal() { console.log('confirmUploadModal被调用,文件数量:', this.modalMediaList.length); if (this.modalMediaList.length === 0) { uni.showToast({ title: '请上传至少一张图片或视频', icon: 'none' }); return; } try { uni.showLoading({ title: '提交中...' }); const uploadedMedias = this.modalMediaList.map(item => item.url); const ossIds = this.modalMediaList.map(item => item.ossId); console.log('准备打卡,ossIds:', ossIds); // 使用 clockInSteps 中对应步骤的 step 值作为打卡 type const clockInType = this.currentClockIn ? this.currentClockIn.step : (this.currentStep + 1); const clockInData = { orderId: this.orderId, photos: ossIds, content: this.modalRemark || '', type: clockInType, title: this.currentTaskTitle }; console.log('打卡数据:', clockInData); await clockIn(clockInData); uni.hideLoading(); this.closeUploadModal(); uni.showToast({ title: '打卡成功', icon: 'success' }); await this.loadOrderDetail(); } catch (err) { uni.hideLoading(); console.error('打卡失败:', err); uni.showToast({ title: '打卡失败,请重试', icon: 'none' }); } }, copyOrderNo() { uni.setClipboardData({ data: this.orderDetail.orderNo, success: () => { uni.showToast({ title: '复制成功', icon: 'none' }); } }); }, openSumModal() { // 初始化日期 const now = new Date(); const y = now.getFullYear(); const m = String(now.getMonth() + 1).padStart(2, '0'); const d = String(now.getDate()).padStart(2, '0'); this.sumDate = `${y}/${m}/${d}`; // 预设服务内容模板 if (!this.sumContent) { this.sumContent = '1. 精神/身体状态:\n' + '2. 进食/饮水:\n' + '3. 排泤情况:\n' + '4. 卫生情况:\n' + '5. 互动情况:\n' + '6. 特殊情况/备注:'; } this.showSumModal = true; }, closeSumModal() { this.showSumModal = false; }, submitSumModal() { if (!this.sumContent.trim()) { uni.showToast({ title: '请填写服务内容', icon: 'none' }); return; } this.closeSumModal(); uni.showToast({ title: '小结已提交', icon: 'success' }); } } }