187
									
								
								ele/auto-meal-complete.user.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								ele/auto-meal-complete.user.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,187 @@
 | 
				
			|||||||
 | 
					// ==UserScript==
 | 
				
			||||||
 | 
					// @name         饿了么自动出餐
 | 
				
			||||||
 | 
					// @namespace    https://circlecloud.ltd/
 | 
				
			||||||
 | 
					// @version      0.1
 | 
				
			||||||
 | 
					// @description  自动出餐
 | 
				
			||||||
 | 
					// @author       MiaoWoo
 | 
				
			||||||
 | 
					// @match        https://melody.shop.ele.me/app/shop/**/order__processing
 | 
				
			||||||
 | 
					// @icon         https://www.google.com/s2/favicons?sz=64&domain=ele.me
 | 
				
			||||||
 | 
					// @updateURL    https://git.yumc.pw/502647092/UserScript/raw/branch/master/ele/auto-meal-complete.user.js
 | 
				
			||||||
 | 
					// @downloadURL  https://git.yumc.pw/502647092/UserScript/raw/branch/master/ele/auto-meal-complete.user.js
 | 
				
			||||||
 | 
					// @grant        none
 | 
				
			||||||
 | 
					// ==/UserScript==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function () {
 | 
				
			||||||
 | 
					    'use strict';
 | 
				
			||||||
 | 
					    function generateRandomString(length) {
 | 
				
			||||||
 | 
					        var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
 | 
				
			||||||
 | 
					        var result = '';
 | 
				
			||||||
 | 
					        var charactersLength = characters.length;
 | 
				
			||||||
 | 
					        for (var i = 0; i < length; i++) {
 | 
				
			||||||
 | 
					            result += characters.charAt(Math.floor(Math.random() * charactersLength));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function getRequestId() {
 | 
				
			||||||
 | 
					        return generateRandomString(32) + "|" + Date.now()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function convertSecondsToMinutesSeconds(seconds) {
 | 
				
			||||||
 | 
					        var minutes = Math.floor(seconds / 60);
 | 
				
			||||||
 | 
					        var remainingSeconds = seconds % 60;
 | 
				
			||||||
 | 
					        return minutes + "分" + remainingSeconds + "秒";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function getShopId() {
 | 
				
			||||||
 | 
					        return parseInt(localStorage.shopId)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function getShopMeta() {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            "appVersion": "1.0.0",
 | 
				
			||||||
 | 
					            "appName": "melody",
 | 
				
			||||||
 | 
					            "ksid": localStorage.ksid,
 | 
				
			||||||
 | 
					            "shopId": getShopId()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function request(service, method, params) {
 | 
				
			||||||
 | 
					        let payload = {
 | 
				
			||||||
 | 
					            "service": service,
 | 
				
			||||||
 | 
					            "method": method,
 | 
				
			||||||
 | 
					            "params": params,
 | 
				
			||||||
 | 
					            "id": getRequestId(),
 | 
				
			||||||
 | 
					            "metas": getShopMeta(),
 | 
				
			||||||
 | 
					            "ncp": "2.0.0"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return fetch("https://app-api.shop.ele.me/fulfill/weborder/" + method + "/?method=" + service + "." + method, {
 | 
				
			||||||
 | 
					            "headers": {
 | 
				
			||||||
 | 
					                "accept": "application/json, text/plain, */*",
 | 
				
			||||||
 | 
					                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
 | 
				
			||||||
 | 
					                "content-type": "application/json;charset=UTF-8",
 | 
				
			||||||
 | 
					                "sec-ch-ua": "\"Microsoft Edge\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"",
 | 
				
			||||||
 | 
					                "sec-ch-ua-platform": "\"Windows\"",
 | 
				
			||||||
 | 
					                "sec-fetch-mode": "cors",
 | 
				
			||||||
 | 
					                "sec-fetch-site": "same-site",
 | 
				
			||||||
 | 
					                "x-eleme-requestid": payload.id,
 | 
				
			||||||
 | 
					                "x-shard": "shopid=" + payload.metas.shopId
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "referrer": "https://napos-order-pc.faas.ele.me/",
 | 
				
			||||||
 | 
					            "referrerPolicy": "strict-origin-when-cross-origin",
 | 
				
			||||||
 | 
					            "body": JSON.stringify(payload),
 | 
				
			||||||
 | 
					            "method": "POST",
 | 
				
			||||||
 | 
					            "mode": "cors",
 | 
				
			||||||
 | 
					            "credentials": "omit"
 | 
				
			||||||
 | 
					        }).then(r => r.json())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function queryInProcessOrders() {
 | 
				
			||||||
 | 
					        return request('OrderWebService', 'queryInProcessOrders', {
 | 
				
			||||||
 | 
					            "shopId": getShopId(),
 | 
				
			||||||
 | 
					            "queryType": "ALL",
 | 
				
			||||||
 | 
					            // "queryType": "COOKING"
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    async function mealComplete(orderId, cookTime) {
 | 
				
			||||||
 | 
					        let result = await request('ShipmentService', 'mealComplete', {
 | 
				
			||||||
 | 
					            "shopId": getShopId(),
 | 
				
			||||||
 | 
					            "orderId": orderId
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        debug('订单 ' + orderId + ' 上报出餐结束.')
 | 
				
			||||||
 | 
					        ele.submitOrders.push({ orderId, cookTime })
 | 
				
			||||||
 | 
					        if (ele.submitOrders.length > ele.maxLogOrderLength)
 | 
				
			||||||
 | 
					            ele.submitOrders = ele.submitOrders.slice(ele.submitOrders.length - ele.maxLogOrderLength)
 | 
				
			||||||
 | 
					        await updateOrders()
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    async function checkCooking() {
 | 
				
			||||||
 | 
					        if (!ele.processOrders) return
 | 
				
			||||||
 | 
					        for (const cook of ele.processOrders) {
 | 
				
			||||||
 | 
					            let orderId = cook.id
 | 
				
			||||||
 | 
					            if (!cook.mealPreparationInfo || cook.mealPreparationInfo.mealComplete) continue
 | 
				
			||||||
 | 
					            // 骑手到店 并且大于最小上报时长 直接上报出餐
 | 
				
			||||||
 | 
					            let cookTime = (Date.now() - new Date(cook.activeTime).getTime()) / 1000
 | 
				
			||||||
 | 
					            let leftTime = cook.mealPreparationInfo.commonShowTime
 | 
				
			||||||
 | 
					            if (cook.deliveryInfo.distTraceView.traceView.status == '骑士已到店'
 | 
				
			||||||
 | 
					                && cook.mealPreparationInfo.minMealCompleteTimeCount < 0
 | 
				
			||||||
 | 
					                && leftTime < ele.autoSubmitLeftTimeWhenOnShop) {
 | 
				
			||||||
 | 
					                debug('订单 ' + orderId + ' 骑手到店 且剩余时间 ' + leftTime + 's 小于 ' + ele.autoSubmitLeftTimeWhenOnShop + 's 模拟提交出餐.')
 | 
				
			||||||
 | 
					                return mealComplete(orderId, cookTime)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (leftTime < ele.autoSubmitLeftTime) {
 | 
				
			||||||
 | 
					                // 大于最小上报时长 并且距离上报超时不足120秒 直接上报出餐
 | 
				
			||||||
 | 
					                debug('订单 ' + orderId + ' 骑手未到店 且剩余时间 ' + leftTime + 's 小于 ' + ele.autoSubmitLeftTimeWhenOnShop + 's 模拟提交出餐.')
 | 
				
			||||||
 | 
					                return mealComplete(orderId, cookTime)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            debug('订单 ' + orderId + ' 还剩 ' + cook.mealPreparationInfo.commonShowTime + 's 上报超时.')
 | 
				
			||||||
 | 
					            cook.mealPreparationInfo.minMealCompleteTimeCount -= 5
 | 
				
			||||||
 | 
					            cook.mealPreparationInfo.commonShowTime -= 5
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    async function updateOrders() {
 | 
				
			||||||
 | 
					        let orders = await queryInProcessOrders()
 | 
				
			||||||
 | 
					        ele.autoCheckTime = Date.now() / 1000
 | 
				
			||||||
 | 
					        ele.processOrders = orders.result || []
 | 
				
			||||||
 | 
					        debug('更新订单数据 目前进行中订单: ' + ele.processOrders.length + '个')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function debug(msg) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            ele.logs.push('[' + (new Date().toLocaleTimeString()) + '] ' + msg)
 | 
				
			||||||
 | 
					            if (ele.logs.length > ele.maxLogLength)
 | 
				
			||||||
 | 
					                ele.logs = ele.logs.slice(ele.logs.length - ele.maxLogLength)
 | 
				
			||||||
 | 
					            let title = '饿了么自动出餐 By MiaoWoo </br>'
 | 
				
			||||||
 | 
					            let configInfo = '当前配置: </br><div class="ant-alert-content">'
 | 
				
			||||||
 | 
					                + '骑手到店 提前 ' + ele.autoSubmitLeftTimeWhenOnShop + 's 出餐 '
 | 
				
			||||||
 | 
					                + '骑手未到店 提前 ' + ele.autoSubmitLeftTime + 's 出餐</br>'
 | 
				
			||||||
 | 
					                + '</div>'
 | 
				
			||||||
 | 
					            let submitInfo = '已自动出餐的订单信息: </br><div class="ant-alert-content">'
 | 
				
			||||||
 | 
					                + (ele.submitOrders.length
 | 
				
			||||||
 | 
					                    ? ele.submitOrders.map(o => '订单: ' + o.orderId + ' 出餐用时 ' + convertSecondsToMinutesSeconds(o.cookTime)).join('</br>')
 | 
				
			||||||
 | 
					                    : '当前没有自动出餐的订单.')
 | 
				
			||||||
 | 
					                + '</div>'
 | 
				
			||||||
 | 
					            let orderInfo = '进行中的订单信息: </br><div class="ant-alert-content">'
 | 
				
			||||||
 | 
					                + (ele.processOrders.length
 | 
				
			||||||
 | 
					                    ? ele.processOrders.map(o => '订单: ' + o.id + ' 出餐状态 ' + (o.mealPreparationInfo.mealComplete ? '已出餐' : '未出餐') + ' 配送状态 ' + o.deliveryInfo.distTraceView.traceView.status).join('</br>')
 | 
				
			||||||
 | 
					                    : '当前没有进行中的订单.')
 | 
				
			||||||
 | 
					                + '</div>'
 | 
				
			||||||
 | 
					            let logs = '运行日志: </br><div class="ant-alert-content">'
 | 
				
			||||||
 | 
					                + ele.logs.join('</br>')
 | 
				
			||||||
 | 
					                + '</div>'
 | 
				
			||||||
 | 
					            window.appContainerNoticeBar.innerHTML = '<div style="flex: 1 1 0%;">'
 | 
				
			||||||
 | 
					                + title + '</br>'
 | 
				
			||||||
 | 
					                + configInfo + '</br>'
 | 
				
			||||||
 | 
					                + submitInfo + '</br>'
 | 
				
			||||||
 | 
					                + orderInfo + '</br>'
 | 
				
			||||||
 | 
					                + '</div>'
 | 
				
			||||||
 | 
					                + '<div style="flex: 1 1 0%;">'
 | 
				
			||||||
 | 
					                + logs
 | 
				
			||||||
 | 
					                + '</div>'
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            console.log(msg)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    async function main() {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					            window.appContainerNoticeBar = document.getElementById('app-container-notice-bar')
 | 
				
			||||||
 | 
					            window.appContainerNoticeBar.style.marginLeft = '35px'
 | 
				
			||||||
 | 
					            window.appContainerNoticeBar.style.marginTop = '20px'
 | 
				
			||||||
 | 
					            window.appContainerNoticeBar.style.display = 'flex'
 | 
				
			||||||
 | 
					            updateOrders()
 | 
				
			||||||
 | 
					        }, 5000)
 | 
				
			||||||
 | 
					        setInterval(() => { checkCooking() }, 5000)
 | 
				
			||||||
 | 
					        setInterval(() => { updateOrders() }, 30000)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var ele = {
 | 
				
			||||||
 | 
					        logs: [],
 | 
				
			||||||
 | 
					        maxLogLength: 15,
 | 
				
			||||||
 | 
					        maxLogOrderLength: 5,
 | 
				
			||||||
 | 
					        orderStatus: {},
 | 
				
			||||||
 | 
					        processOrders: [],
 | 
				
			||||||
 | 
					        submitOrders: [],
 | 
				
			||||||
 | 
					        autoCheckTask: undefined,
 | 
				
			||||||
 | 
					        autoSubmitLeftTime: 180,
 | 
				
			||||||
 | 
					        autoSubmitLeftTimeWhenOnShop: 300,
 | 
				
			||||||
 | 
					        debug: debug,
 | 
				
			||||||
 | 
					        updateOrders: updateOrders,
 | 
				
			||||||
 | 
					        checkCooking: checkCooking,
 | 
				
			||||||
 | 
					        mealComplete: mealComplete,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    window.ele = ele
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
		Reference in New Issue
	
	Block a user