save
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
node_modules/*
|
||||
~$*
|
||||
@@ -0,0 +1,11 @@
|
||||
## 开票业务
|
||||
excle 结算状态过滤
|
||||
登录
|
||||
总进度
|
||||
|
||||
|
||||
|
||||
## 避免锁屏
|
||||
打开目录:D:\Cheney\2\geely-kaipiao\
|
||||
地址栏删空,输入 cmd,打开黑框。
|
||||
输入命令:bun.exe keep-awake.js
|
||||
+8
-2
@@ -62,7 +62,13 @@ function readTeamIds() {
|
||||
const teamIds = [];
|
||||
for (const row of rows) {
|
||||
const val = row['团号'];
|
||||
if (val && /^TEAM-\d+$/.test(String(val).trim())) teamIds.push(String(val).trim());
|
||||
const kaipiaoStatus = row['开票状态'];
|
||||
if (!val || !/^TEAM-\d+$/.test(String(val).trim())) continue;
|
||||
if (kaipiaoStatus && String(kaipiaoStatus).trim() !== '未开票') {
|
||||
console.log(` ⚠ ${String(val).trim()} 开票状态: "${kaipiaoStatus}",跳过`);
|
||||
continue;
|
||||
}
|
||||
teamIds.push(String(val).trim());
|
||||
}
|
||||
return teamIds;
|
||||
}
|
||||
@@ -168,4 +174,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('Error:', err); process.exit(1); });
|
||||
main().catch(err => { console.error('Error:', err); process.exit(1); });
|
||||
|
||||
Generated
+164
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"name": "geely-kaipiao",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "geely-kaipiao",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"playwright": "^1.61.0",
|
||||
"xlsx": "^0.18.5"
|
||||
}
|
||||
},
|
||||
"node_modules/adler-32": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
|
||||
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/cfb": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
|
||||
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"crc-32": "~1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/codepage": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz",
|
||||
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/crc-32": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
|
||||
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"crc32": "bin/crc32.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/frac": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
|
||||
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.61.0",
|
||||
"resolved": "https://registry.npmmirror.com/playwright/-/playwright-1.61.0.tgz",
|
||||
"integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.61.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.61.0",
|
||||
"resolved": "https://registry.npmmirror.com/playwright-core/-/playwright-core-1.61.0.tgz",
|
||||
"integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/ssf": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
|
||||
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"frac": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/wmf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
|
||||
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/word": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
|
||||
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx": {
|
||||
"version": "0.18.5",
|
||||
"resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
|
||||
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"cfb": "~1.2.1",
|
||||
"codepage": "~1.15.0",
|
||||
"crc-32": "~1.2.1",
|
||||
"ssf": "~0.11.2",
|
||||
"wmf": "~1.0.1",
|
||||
"word": "~0.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"xlsx": "bin/xlsx.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
const XLSX = require('xlsx');
|
||||
const path = require('path');
|
||||
|
||||
// 读取 Excel 文件(项目根目录)
|
||||
const filePath = path.join(__dirname, '新建 XLSX 工作表.xlsx');
|
||||
const workbook = XLSX.readFile(filePath);
|
||||
|
||||
// 目标 sheet
|
||||
const sheetName = '2026';
|
||||
const sheet = workbook.Sheets[sheetName];
|
||||
|
||||
if (!sheet) {
|
||||
console.error(`Sheet "${sheetName}" 不存在`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 将 sheet 转为 JSON 数组(以第一行为表头)
|
||||
const rows = XLSX.utils.sheet_to_json(sheet, { defval: null });
|
||||
|
||||
// 查找"团号"列(兼容表头可能的空格差异)
|
||||
const headerRow = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: null })[0];
|
||||
const tuanHaoIndex = headerRow.findIndex(h => h && String(h).trim() === '团号');
|
||||
|
||||
if (tuanHaoIndex === -1) {
|
||||
console.error('未找到"团号"列');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 提取所有 TEAM-xxxx 格式的 ID
|
||||
const teamIds = [];
|
||||
for (const row of rows) {
|
||||
const val = row['团号'];
|
||||
if (val && /^TEAM-\d+$/.test(String(val).trim())) {
|
||||
teamIds.push(String(val).trim());
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`找到 ${teamIds.length} 个 TEAM ID:`);
|
||||
teamIds.forEach(id => console.log(id));
|
||||
@@ -0,0 +1,65 @@
|
||||
const { chromium } = require('playwright');
|
||||
const path = require('path');
|
||||
|
||||
const LOGIN_URL = 'https://superstar.geelytravel.com/new-tmc/login';
|
||||
const STATE_PATH = process.env.STATE_PATH || path.resolve(__dirname, 'state.json');
|
||||
const USER_AGENT =
|
||||
process.env.USER_AGENT ||
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
||||
|
||||
async function run() {
|
||||
// 1. 启动本地 Chrome 浏览器,并添加排除自动化检测的参数
|
||||
const browser = await chromium.launch({
|
||||
headless: false,
|
||||
channel: 'chrome',
|
||||
args: [
|
||||
'--disable-blink-features=AutomationControlled',
|
||||
'--start-maximized',
|
||||
],
|
||||
});
|
||||
|
||||
// 2. 设置上下文,伪造 User-Agent
|
||||
const context = await browser.newContext({
|
||||
noViewport: true,
|
||||
userAgent: USER_AGENT,
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
// 3. 访问登录页
|
||||
await page.goto(LOGIN_URL);
|
||||
|
||||
// 输入信息:如需自动填写,可通过环境变量 USERNAME / PASSWORD 传入
|
||||
if (process.env.USERNAME) {
|
||||
await page.getByPlaceholder('用户名').fill(process.env.USERNAME);
|
||||
}
|
||||
|
||||
if (process.env.PASSWORD) {
|
||||
await page.getByPlaceholder('密码').fill(process.env.PASSWORD);
|
||||
}
|
||||
|
||||
// 4. 进入暂停状态,此时手动滑动验证码并完成登录
|
||||
console.log('请在浏览器中手动完成滑块验证,登录进入系统首页后回到终端按 Enter...');
|
||||
await page.pause();
|
||||
|
||||
// 5. 关键:等待页面跳转完成,确保已进入登录后的状态
|
||||
// 如需按业务页面确认登录成功,可打开下面一行并按实际 URL 片段调整。
|
||||
// await page.waitForURL('**/report/**', { timeout: 60000 });
|
||||
|
||||
// 额外等待 3 秒,确保 Cookie 和 LocalStorage 完整写入内存
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 6. 保存状态
|
||||
await context.storageState({ path: STATE_PATH });
|
||||
console.log(`登录状态已保存至:${STATE_PATH}`);
|
||||
} finally {
|
||||
await context.close();
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
+270
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
const { exec } = require('child_process');
|
||||
|
||||
const CHECK_INTERVAL = 30 * 1000; // 每 30 秒检查一次
|
||||
const IDLE_LIMIT = 60 * 1000; // 空闲超过 60 秒则触发
|
||||
|
||||
// 封装执行 PowerShell 的方法(使用 UTF-16LE 编码避免引号转义问题)
|
||||
function runPs(script) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const encoded = Buffer.from(script, 'utf16le').toString('base64');
|
||||
exec(`powershell -NoProfile -EncodedCommand "${encoded}"`, (err, stdout) => {
|
||||
if (err) reject(err);
|
||||
else resolve(stdout.trim());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前系统空闲毫秒数
|
||||
async function getIdleTime() {
|
||||
const ps = `
|
||||
Add-Type @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public class IdleChecker {
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
|
||||
public struct LASTINPUTINFO {
|
||||
public uint cbSize;
|
||||
public uint dwTime;
|
||||
}
|
||||
public static uint GetIdleMilliseconds() {
|
||||
LASTINPUTINFO lii = new LASTINPUTINFO();
|
||||
lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
|
||||
GetLastInputInfo(ref lii);
|
||||
return (uint)Environment.TickCount - lii.dwTime;
|
||||
}
|
||||
}
|
||||
"@
|
||||
[IdleChecker]::GetIdleMilliseconds()
|
||||
`;
|
||||
const result = await runPs(ps);
|
||||
return parseInt(result, 10);
|
||||
}
|
||||
|
||||
// 模拟按下 F15 键(无任何副作用)
|
||||
async function pressF15() {
|
||||
const ps = `
|
||||
$wshell = New-Object -ComObject wscript.shell;
|
||||
$wshell.SendKeys('{F15}');
|
||||
`;
|
||||
await runPs(ps);
|
||||
}
|
||||
|
||||
console.log('✅ 防锁屏脚本已启动 (PowerShell 模式)');
|
||||
console.log(`⏱️ 检测到空闲 ${IDLE_LIMIT/1000} 秒后,自动模拟按键防止锁屏。`);
|
||||
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const idleMs = await getIdleTime();
|
||||
if (idleMs > IDLE_LIMIT) {
|
||||
console.log(`🔄 已空闲 ${Math.round(idleMs/1000)} 秒,模拟 F15 重置计时器...`);
|
||||
await pressF15();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('⚠️ 执行出错:', e.message);
|
||||
}
|
||||
}, CHECK_INTERVAL);
|
||||
|
||||
// 按 Ctrl+C 退出时提示
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n🛑 脚本已停止');
|
||||
process.exit(0);
|
||||
});
|
||||
Reference in New Issue
Block a user