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
|
||||||
+7
-1
@@ -62,7 +62,13 @@ function readTeamIds() {
|
|||||||
const teamIds = [];
|
const teamIds = [];
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
const val = row['团号'];
|
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;
|
return teamIds;
|
||||||
}
|
}
|
||||||
|
|||||||
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