《航空经理4》小助手,点击网页上方的启动脚本即可运行
// ==UserScript==
// @name AM4_Assistant
// @namespace http://tampermonkey.net/
// @version v2024.12.15
// @description 《航空经理4》小助手,点击网页上方的启动脚本即可运行
// @author JasonWong
// @match *://*.www.airlinemanager.com/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
function toggleSettingsPopup() {
const popup = document.getElementById('settingsPopup');
popup.style.display = popup.style.display === 'none' ? 'block' : 'none';
}
function saveSettings() {
const fuelAmount = document.getElementById('fuelAmountInput').value;
const fuelPriceThreshold = document.getElementById('fuelPriceThresholdInput').value;
const co2Amount = document.getElementById('co2AmountInput').value;
const co2PriceThreshold = document.getElementById('co2PriceThresholdInput').value;
// 保存到 localStorage
localStorage.setItem('fuelAmount', fuelAmount);
localStorage.setItem('fuelPriceThreshold', fuelPriceThreshold);
localStorage.setItem('co2Amount', co2Amount);
localStorage.setItem('co2PriceThreshold', co2PriceThreshold);
console.log('设置已保存');
toggleSettingsPopup(); // 关闭弹窗
}
// 随机延迟函数(返回一个 Promise,延迟随机时间)
function randomDelay(min = 500, max = 1000) {
const delay = Math.floor(Math.random() * (max - min + 1)) + min; // 随机延迟
return new Promise(resolve => setTimeout(resolve, delay));
}
// 等待关闭按钮加载
async function waitForCloseButton() {
return new Promise(resolve => {
const interval = setInterval(() => {
const closeButton = document.querySelector('.glyphicons.glyphicons-remove.med-icon.opa.opa-rotate');
if (closeButton) {
console.log('找到关闭窗口按钮');
clearInterval(interval); // 停止轮询
resolve(closeButton); // 返回找到的按钮
} else {
console.log('关闭窗口按钮尚未加载,继续等待...');
}
}, 500); // 每隔 500 毫秒检查一次
});
}
// 点击关闭窗口按钮
async function clickCloseButton() {
const closeButton = await waitForCloseButton(); // 等待关闭按钮加载
console.log('准备点击关闭窗口按钮');
closeButton.click();
await randomDelay(); // 添加随机延迟
// 如果关闭按钮的点击无效,尝试直接调用 closePop()
if (typeof closePop === 'function') {
console.log('调用 closePop 函数关闭窗口');
closePop();
} else {
console.log('未找到 closePop 函数');
}
}
// 点击按钮的通用函数
async function clickButtonById(buttonId) {
const button = document.getElementById(buttonId);
if (button) {
console.log(`找到按钮:${buttonId},准备点击`);
button.click();
await randomDelay(); // 添加随机延迟
} else {
console.log(`未找到按钮:${buttonId}`);
}
}
// 点击 Fuel 按钮
async function clickFuelButton() {
// 使用 querySelector 精确匹配 Finance 按钮
const financeButton = document.querySelector('div.menu-btn-new[onclick*="fuel.php"]');
if (financeButton) {
console.log('找到 Fuel 按钮,准备点击');
financeButton.click(); // 点击按钮
await randomDelay(); // 添加随机延迟
} else {
console.log('未找到 Fuel 按钮');
}
}
// 点击 Maintenance 按钮
async function clickMaintenanceButton() {
// 使用 querySelector 精确匹配 Maintenance 按钮
const financeButton = document.querySelector('div.menu-btn-new[onclick*="maintenance_main.php"]');
if (financeButton) {
console.log('找到 Maintenance 按钮,准备点击');
financeButton.click(); // 点击按钮
await randomDelay(); // 添加随机延迟
} else {
console.log('未找到 Maintenance 按钮');
}
}
// 点击 Finance 按钮
async function clickFinanceButton() {
// 使用 querySelector 精确匹配 Finance 按钮
const financeButton = document.querySelector('div.menu-btn-new[onclick*="finances.php"]');
if (financeButton) {
console.log('找到 Finance 按钮,准备点击');
financeButton.click(); // 点击按钮
await randomDelay(); // 添加随机延迟
} else {
console.log('未找到 Finance 按钮');
}
}
// 点击 Bulk Repair 按钮
async function clickRepairButton() {
console.log('查找 Bulk Repair 按钮...');
// 使用 querySelector 精确匹配目标按钮
const repairButton = document.querySelector('button.btn.btn-outline-primary.btn-xs-real.mt-1[onclick*="maint_plan_repair_bulk.php"]');
if (repairButton) {
console.log('找到 Bulk Repair 按钮,准备点击');
repairButton.click(); // 点击按钮
await randomDelay(); // 添加随机延迟
console.log('已点击 Bulk Repair 按钮');
} else {
console.log('未找到 Bulk Repair 按钮');
}
}
async function selectRepairPercentage() {
console.log('正在选择维修百分比为 60%...');
// 获取下拉菜单元素
const repairDropdown = document.getElementById('repairPct');
if (repairDropdown) {
// 设置下拉菜单的值为 "60"
repairDropdown.value = "60";
console.log('已选择维修百分比为 60%');
// 触发 change 事件以确保选择生效
const event = new Event('change', { bubbles: true });
repairDropdown.dispatchEvent(event);
} else {
console.log('未找到维修百分比的下拉菜单');
}
}
// 点击 Plan Bulk Repair 按钮
async function clickPlanBulkRepairButton() {
console.log('查找 Plan bulk repair 按钮...');
// 使用 querySelector 精确匹配目标按钮
const bulkRepairButton = document.querySelector('button.btn.btn-danger.btn-xs-real[onclick*="maint_plan_do.php?type=bulkRepair"][onclick*="pct=60"]');
if (bulkRepairButton) {
console.log('找到 Plan bulk repair 按钮,准备点击');
bulkRepairButton.click(); // 点击按钮
await randomDelay(); // 添加随机延迟
console.log('已点击 Plan bulk repair 按钮');
} else {
console.log('未找到 Plan bulk repair 按钮');
}
}
// 点击 Bulk Check 按钮
async function clickCheckButton() {
console.log('查找 Bulk Check 按钮...');
// 使用 querySelector 精确匹配目标按钮
const repairButton = document.querySelector('button.btn.btn-outline-primary.btn-xs-real.mt-1[onclick*="maint_plan_check_bulk.php"]');
if (repairButton) {
console.log('找到 Bulk Check 按钮,准备点击');
repairButton.click(); // 点击按钮
await randomDelay(); // 添加随机延迟
console.log('已点击 Bulk Check 按钮');
} else {
console.log('未找到 Bulk Check 按钮');
}
}
async function clickLowHoursElementsAndCheck() {
console.log("查找前五个框中 'text-danger' 小于 20 的元素...");
// 获取所有框框元素
const elements = document.querySelectorAll('.bg-white.col-sm-6.text-center.border.p-2.opa.opa-check');
let count = 0; // 计数器,用于限制操作前五个框框
let clicked = false; // 标志变量,记录是否至少点击了一个框框
for (const element of elements) {
// 检查是否已处理五个框框
if (count >= 5) break;
// 获取框框中具有 `text-danger` 类的 <b> 标签
const textDangerElement = element.querySelector('.text-danger');
if (textDangerElement) {
const value = parseInt(textDangerElement.textContent.trim(), 10); // 获取 <b> 标签的数字值
if (value < 20) {
console.log(`找到 'text-danger' 小于 20 的框,值为 ${value},准备点击...`);
element.click(); // 点击框框
count++; // 增加计数
clicked = true; // 至少点击了一个框框,将标志变量设置为 true
await randomDelay(); // 添加随机延迟,避免操作过快
}
}
}
if (clicked) {
console.log("至少点击了一个框,准备点击 'Plan bulk check' 按钮...");
await clickButtonById('bulk-check-btn'); // 如果至少点击了一个框,点击按钮
} else {
console.log("未找到符合条件的框,跳过点击 'Plan bulk check' 按钮...");
}
console.log("操作完成!");
}
// 检查燃油价格并购买燃油
async function checkAndPurchaseFuel() {
console.log('检测燃油价格...');
// 获取用户设置
const fuelAmount = localStorage.getItem('fuelAmount') || '3000000';
const fuelPriceThreshold = parseFloat(localStorage.getItem('fuelPriceThreshold') || '480');
// 获取当前价格(从 HTML 中提取)
const priceElement = document.querySelector('.col-6.p-2 .text-danger b');
if (priceElement) {
const priceText = priceElement.textContent.trim();
const price = parseFloat(priceText.replace('$', '').replace(',', ''));
console.log(`当前燃油价格为:$${price}`);
if (price < fuelPriceThreshold) {
console.log(`燃油价格低于 $${fuelPriceThreshold},准备购买...`);
const amountInput = document.getElementById('amountInput');
if (amountInput) {
amountInput.value = fuelAmount;
console.log(`已输入购买数量:${fuelAmount}`);
}
const purchaseButton = document.querySelector('.btn.btn-danger.btn-xs.btn-block.w-100');
if (purchaseButton) {
purchaseButton.click();
console.log('已点击购买按钮');
}
} else {
console.log(`燃油价格高于 $${fuelPriceThreshold},跳过购买操作`);
}
}
}
// 检查碳价格并购买碳
async function checkAndPurchaseCO2() {
console.log('检测碳价格...');
// 获取用户设置
const co2Amount = localStorage.getItem('co2Amount') || '2000000';
const co2PriceThreshold = parseFloat(localStorage.getItem('co2PriceThreshold') || '108');
// 获取当前价格(从 HTML 中提取)
const priceElement = document.querySelector('.col-6.p-2 .text-danger b');
if (priceElement) {
const priceText = priceElement.textContent.trim();
const price = parseFloat(priceText.replace('$', '').replace(',', ''));
console.log(`当前碳价格为:$${price}`);
if (price < co2PriceThreshold) {
console.log(`碳价格低于 $${co2PriceThreshold},准备购买...`);
const amountInput = document.getElementById('amountInput');
if (amountInput) {
amountInput.value = co2Amount;
console.log(`已输入购买数量:${co2Amount}`);
}
const purchaseButton = document.querySelector('.btn.btn-danger.btn-xs.btn-block.w-100');
if (purchaseButton) {
purchaseButton.click();
console.log('已点击购买按钮');
}
} else {
console.log(`碳价格高于 $${co2PriceThreshold},跳过购买操作`);
}
}
}
// 点击 "Increase airline reputation" 的函数
async function clickAirlineReputation() {
console.log('查找 "Increase airline reputation"...');
// 获取所有的 <tr> 元素
const rows = document.querySelectorAll('table.table tbody tr');
// 遍历 <tr> 元素,查找包含 "Increase airline reputation" 的行
for (let row of rows) {
if (row.innerText.includes('Increase airline reputation')) {
console.log('找到目标行,准备点击...');
row.click(); // 点击目标行
await randomDelay(); // 添加随机延迟
return; // 点击后退出函数
}
}
console.log('未找到 "Increase airline reputation" 的行');
}
async function select24Hours() {
console.log('选择 24 Hours ...');
const dSelector = document.getElementById('dSelector'); // 获取 <select> 元素
if (dSelector) {
dSelector.value = "6"; // 设置值为 "6"(对应 24 Hours)
console.log('已选择 24 Hours');
// 触发 change 事件,确保页面更新选择
const event = new Event('change', { bubbles: true });
dSelector.dispatchEvent(event);
} else {
console.log('未找到 dSelector 下拉菜单');
}
}
// 点击 "Increase airline reputation" 的函数
async function clickEcoFriendly() {
console.log('查找 "Eco-friendly"...');
// 获取所有的 <tr> 元素
const rows = document.querySelectorAll('table.table tbody tr');
// 遍历 <tr> 元素,查找包含 "Eco-friendly" 的行
for (let row of rows) {
if (row.innerText.includes('Eco-friendly')) {
console.log('找到目标行,准备点击...');
row.click(); // 点击目标行
await randomDelay(); // 添加随机延迟
return; // 点击后退出函数
}
}
console.log('未找到 "Increase airline reputation" 的行');
}
async function clickEcoMarketingButton() {
console.log('查找 Eco Marketing 按钮...');
// 使用 querySelector 根据 onclick 属性定位按钮
const ecoMarketingButton = document.querySelector('button.btn.btn-xs.btn-danger[onclick*="marketing_new.php?type=5"]');
if (ecoMarketingButton) {
console.log('找到 Eco Marketing 按钮,准备点击...');
ecoMarketingButton.click(); // 触发点击事件
await randomDelay(); // 添加随机延迟
console.log('已点击 Eco Marketing 按钮');
} else {
console.log('未找到 Eco Marketing 按钮');
}
}
// 主逻辑函数
async function runScript() {
console.log('脚本正在运行...');
// 任务一:增加航空声誉
// 第一步:点击 Finance 按钮
await clickFinanceButton();
await randomDelay(); // 再次添加随机延迟
await clickButtonById('popBtn2');
await randomDelay(); // 再次添加随机延迟
await clickButtonById('newCampaign');
await randomDelay(); // 再次添加随机延迟
await clickAirlineReputation();
await randomDelay(); // 再次添加随机延迟
//await clickButtonById('dSelector');
await randomDelay(); // 再次添加随机延迟
await select24Hours(); // 选择 24 Hours
await randomDelay(); // 添加随机延迟
await clickButtonById('c4Btn');
await randomDelay(); // 再次添加随机延迟
await clickButtonById('popBtn2');
await randomDelay(); // 再次添加随机延迟
await clickButtonById('newCampaign');
await randomDelay(); // 再次添加随机延迟
await clickEcoFriendly();
await randomDelay(); // 再次添加随机延迟
await clickEcoMarketingButton(); // 点击 Eco Marketing 按钮
await randomDelay();
await clickCloseButton();
await randomDelay(); // 再次添加随机延迟
// 任务二:将所有飞机离场
// 第一步:点击 mapRoutes 按钮
await clickButtonById('mapRoutes');
// 第二步:检查并点击 departAll 按钮
const departAllButton = document.getElementById('departAll');
if (departAllButton) {
await randomDelay(); // 添加随机延迟
console.log('找到 departAll 按钮,准备点击');
departAllButton.click();
//点击关闭窗口按钮
await randomDelay(); // 再次添加随机延迟
await clickCloseButton();
} else {
console.log('未找到 departAll 按钮');
await randomDelay(); // 再次添加随机延迟
await clickCloseButton();
}
await randomDelay(); // 再次添加随机延迟
// 任务三:补充燃油和碳配额
await clickFuelButton();
await randomDelay(); // 再次添加随机延迟
await checkAndPurchaseFuel();
await randomDelay(); // 再次添加随机延迟
await clickButtonById('popBtn2');
await randomDelay(); // 再次添加随机延迟
await checkAndPurchaseCO2();
await randomDelay(); // 再次添加随机延迟
await clickCloseButton();
await randomDelay(); // 再次添加随机延迟
// 任务四:自动A检及维护
await clickMaintenanceButton()
await randomDelay(); // 再次添加随机延迟
await clickButtonById('popBtn2');
await randomDelay(); // 再次添加随机延迟
await clickRepairButton()
await randomDelay(); // 再次添加随机延迟
await clickButtonById('repairPct');
await randomDelay(); // 再次添加随机延迟
await selectRepairPercentage();
await randomDelay(); // 再次添加随机延迟
await clickPlanBulkRepairButton();
await randomDelay(); // 再次添加随机延迟
await clickButtonById('popBtn2');
await randomDelay(); // 再次添加随机延迟
await clickCheckButton();
await clickLowHoursElementsAndCheck();
await randomDelay(); // 再次添加随机延迟
await clickCloseButton();
}
// 脚本运行状态
let isRunning = false; // 当前是否正在运行脚本
let intervalId = null; // 用于存储 setInterval 的 ID
// 启动脚本函数
async function startScript() {
console.log('脚本已启动,每1分钟运行一次');
isRunning = true;
updateButtonText(); // 更新按钮文字
await runScript(); // 立即运行一次主逻辑
let countdown = 60; // 倒计时初始值(1分钟 = 60秒)
// 每秒更新倒计时
const countdownInterval = setInterval(() => {
if (!isRunning) {
clearInterval(countdownInterval); // 如果脚本停止,清除倒计时更新
return;
}
// 计算分钟和秒
const minutes = Math.floor(countdown / 60); // 这里始终为 0,因为倒计时只有 1分钟
const seconds = countdown % 60;
// 更新倒计时显示
countdownDisplay.textContent = `下次运行: ${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
// 倒计时减少
countdown--;
if (countdown < 0) {
clearInterval(countdownInterval); // 倒计时结束时清除计时器
}
}, 1000); // 每秒更新一次
intervalId = setInterval(async () => {
countdown = 60; // 重置倒计时为 1分钟
await runScript(); // 每 1 分钟运行一次主逻辑
}, 60000); // 设置为 1 分钟
}
// 停止脚本函数
function stopScript() {
console.log('脚本已停止');
clearInterval(intervalId); // 停止 setInterval
isRunning = false;
updateButtonText(); // 更新按钮文字
countdownDisplay.textContent = '脚本已停止'; // 停止时更新倒计时显示
}
// 更新按钮文字
function updateButtonText() {
const button = document.getElementById('startScriptButton');
button.textContent = isRunning ? '停止脚本' : '启动脚本'; // 根据运行状态更新文字
}
// 在页面顶部添加启动按钮
const button = document.createElement('button');
button.id = 'startScriptButton';
button.textContent = '启动脚本'; // 初始状态为启动脚本
button.style.position = 'fixed';
button.style.top = '10px';
button.style.left = '50%';
button.style.transform = 'translateX(-50%)';
button.style.zIndex = '9999';
button.style.padding = '10px 20px';
button.style.backgroundColor = '#007bff';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
button.style.fontSize = '16px';
button.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
document.body.appendChild(button);
// 在页面顶部添加齿轮按钮
const gearButton = document.createElement('button');
gearButton.id = 'gearButton';
gearButton.textContent = '⚙️'; // 齿轮图标
gearButton.style.position = 'fixed';
gearButton.style.top = '10px';
gearButton.style.left = 'calc(50% - 100px)'; // 位于启动按钮左边
gearButton.style.transform = 'translateX(-50%)';
gearButton.style.zIndex = '9999';
gearButton.style.padding = '10px 20px';
gearButton.style.backgroundColor = '#28a745';
gearButton.style.color = 'white';
gearButton.style.border = 'none';
gearButton.style.borderRadius = '5px';
gearButton.style.cursor = 'pointer';
gearButton.style.fontSize = '16px';
gearButton.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
document.body.appendChild(gearButton);
// 齿轮按钮点击事件,打开设置弹窗
gearButton.addEventListener('click', toggleSettingsPopup);
// 启动按钮的点击事件
button.addEventListener('click', () => {
if (isRunning) {
stopScript(); // 如果脚本正在运行,就停止
} else {
startScript(); // 如果脚本未运行,就启动
}
});
// 创建设置弹窗
const settingsPopup = document.createElement('div');
settingsPopup.id = 'settingsPopup';
settingsPopup.style.position = 'fixed';
settingsPopup.style.top = '50%';
settingsPopup.style.left = '50%';
settingsPopup.style.transform = 'translate(-50%, -50%)';
settingsPopup.style.zIndex = '10000';
settingsPopup.style.padding = '20px';
settingsPopup.style.backgroundColor = 'white';
settingsPopup.style.border = '1px solid #ccc';
settingsPopup.style.borderRadius = '10px';
settingsPopup.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.2)';
settingsPopup.style.display = 'none'; // 初始隐藏
// 弹窗内容
settingsPopup.innerHTML = `
<h3>设置</h3>
<label>
燃油购买数量:
<input type="number" id="fuelAmountInput" value="3000000" style="width: 100%; margin-bottom: 10px;">
</label>
<label>
燃油购买价格阈值:
<input type="number" id="fuelPriceThresholdInput" value="420" style="width: 100%; margin-bottom: 10px;">
</label>
<label>
碳购买数量:
<input type="number" id="co2AmountInput" value="2000000" style="width: 100%; margin-bottom: 10px;">
</label>
<label>
碳购买价格阈值:
<input type="number" id="co2PriceThresholdInput" value="108" style="width: 100%; margin-bottom: 10px;">
</label>
<button id="saveSettingsButton" style="padding: 10px 20px; background-color: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer;">保存设置</button>
<button id="closeSettingsButton" style="padding: 10px 20px; background-color: #dc3545; color: white; border: none; border-radius: 5px; cursor: pointer; margin-left: 10px;">关闭</button>
`;
document.body.appendChild(settingsPopup);
// 在页面顶部添加倒计时区域
const countdownDisplay = document.createElement('div');
countdownDisplay.id = 'countdownDisplay';
countdownDisplay.textContent = '下次运行: 1:00'; // 初始倒计时设置为 1 分钟
countdownDisplay.style.position = 'fixed';
countdownDisplay.style.top = '10px';
countdownDisplay.style.left = 'calc(50% + 142px)'; // 位于启动按钮右边
countdownDisplay.style.transform = 'translateX(-50%)';
countdownDisplay.style.zIndex = '9999';
countdownDisplay.style.padding = '10px 20px';
countdownDisplay.style.backgroundColor = '#6c757d';
countdownDisplay.style.color = 'white';
countdownDisplay.style.border = 'none';
countdownDisplay.style.borderRadius = '5px';
countdownDisplay.style.cursor = 'default';
countdownDisplay.style.fontSize = '16px';
countdownDisplay.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
document.body.appendChild(countdownDisplay);
// 保存和关闭按钮事件
document.getElementById('saveSettingsButton').addEventListener('click', saveSettings);
document.getElementById('closeSettingsButton').addEventListener('click', toggleSettingsPopup);
})();