feat: 浏览器自动化操作开发
This commit is contained in:
4
global.d.ts
vendored
4
global.d.ts
vendored
@@ -80,8 +80,8 @@ declare global {
|
||||
warn: (message: string, ...meta?: any[]) => void;
|
||||
error: (message: string, ...meta?: any[]) => void;
|
||||
},
|
||||
// 任务操作
|
||||
taskOperation: (params: any) => Promise<{success: boolean, error?: string}>,
|
||||
// 执行脚本
|
||||
executeScript: (options: any) => Promise<{success: boolean, error?: string}>,
|
||||
}
|
||||
|
||||
interface Window {
|
||||
|
||||
194
package-lock.json
generated
194
package-lock.json
generated
@@ -35,6 +35,8 @@
|
||||
"mitt": "^3.0.1",
|
||||
"openai": "^6.14.0",
|
||||
"pinia": "^2.3.1",
|
||||
"playwright": "^1.58.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"uuid": "^13.0.0",
|
||||
"vue": "^3.5.22",
|
||||
"vue-i18n": "^11.1.9",
|
||||
@@ -218,6 +220,28 @@
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ctrl/tinycolor": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
||||
@@ -2094,7 +2118,6 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
@@ -3003,6 +3026,30 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.12.tgz",
|
||||
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node16": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/cacheable-request": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
@@ -3128,7 +3175,6 @@
|
||||
"version": "24.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.2.tgz",
|
||||
"integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
@@ -3665,7 +3711,6 @@
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
@@ -3698,6 +3743,18 @@
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.3.5",
|
||||
"resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.5.tgz",
|
||||
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
@@ -3828,6 +3885,12 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
@@ -4590,6 +4653,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-dirname": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz",
|
||||
@@ -4844,6 +4913,15 @@
|
||||
"integrity": "sha512-Ckej0NS6jxQ4Po3OrSQBFddayRhTCic2DoCAG5zacOfOVB9P2Q5Xc5uL/nVa7ZVs+HdMnvUPzLFCB/JwpB6Csg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/diff/-/diff-4.0.4.tgz",
|
||||
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/dir-compare": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz",
|
||||
@@ -8299,6 +8377,12 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/make-fetch-happen": {
|
||||
"version": "10.2.1",
|
||||
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz",
|
||||
@@ -9671,6 +9755,50 @@
|
||||
"pathe": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.58.2",
|
||||
"resolved": "https://registry.npmmirror.com/playwright/-/playwright-1.58.2.tgz",
|
||||
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.58.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.58.2",
|
||||
"resolved": "https://registry.npmmirror.com/playwright-core/-/playwright-core-1.58.2.tgz",
|
||||
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright/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/plist": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
|
||||
@@ -11328,6 +11456,49 @@
|
||||
"code-block-writer": "^13.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmmirror.com/ts-node/-/ts-node-10.9.2.tgz",
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
"@tsconfig/node12": "^1.0.7",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"v8-compile-cache-lib": "^3.0.1",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-cwd": "dist/bin-cwd.js",
|
||||
"ts-node-esm": "dist/bin-esm.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": ">=1.2.50",
|
||||
"@swc/wasm": ">=1.2.50",
|
||||
"@types/node": "*",
|
||||
"typescript": ">=2.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@swc/wasm": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
@@ -11389,7 +11560,6 @@
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -11416,7 +11586,6 @@
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unimport": {
|
||||
@@ -11636,6 +11805,12 @@
|
||||
"uuid": "dist-node/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
@@ -12153,6 +12328,15 @@
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
||||
@@ -72,6 +72,8 @@
|
||||
"mitt": "^3.0.1",
|
||||
"openai": "^6.14.0",
|
||||
"pinia": "^2.3.1",
|
||||
"playwright": "^1.58.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"uuid": "^13.0.0",
|
||||
"vue": "^3.5.22",
|
||||
"vue-i18n": "^11.1.9",
|
||||
|
||||
@@ -53,8 +53,8 @@ export enum IPC_EVENTS {
|
||||
IS_DARK_THEME = 'is-dark-theme',
|
||||
THEME_MODE_UPDATED = 'theme-mode-updated',
|
||||
|
||||
// 任务操作
|
||||
TASK_OPERATION = 'task-operation',
|
||||
// 执行脚本
|
||||
EXECUTE_SCRIPT = 'execute-script',
|
||||
}
|
||||
|
||||
export const MAIN_WIN_SIZE = {
|
||||
|
||||
@@ -3,21 +3,23 @@ import { CONFIG_KEYS } from '@common/constants'
|
||||
import { setupMainWindow } from './wins';
|
||||
import started from 'electron-squirrel-startup'
|
||||
import configManager from '@main/service/config-service'
|
||||
import logManager from '@main/service/logger'
|
||||
import { runTaskOperationService } from '@main/process/runTaskOperationService'
|
||||
import log from 'electron-log';
|
||||
// import logManager from '@main/service/logger'
|
||||
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
if (started) {
|
||||
app.quit();
|
||||
}
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
logManager.error('uncaughtException', err);
|
||||
});
|
||||
// process.on('uncaughtException', (err) => {
|
||||
// logManager.error('uncaughtException', err);
|
||||
// });
|
||||
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
logManager.error('unhandledRejection', reason, promise);
|
||||
});
|
||||
// process.on('unhandledRejection', (reason, promise) => {
|
||||
// logManager.error('unhandledRejection', reason, promise);
|
||||
// });
|
||||
|
||||
app.whenReady().then(() => {
|
||||
setupMainWindow();
|
||||
@@ -33,7 +35,7 @@ app.whenReady().then(() => {
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin' && !configManager.get(CONFIG_KEYS.MINIMIZE_TO_TRAY)) {
|
||||
logManager.info('app closing due to all windows being closed');
|
||||
log.info('app closing due to all windows being closed');
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,2 +1,80 @@
|
||||
|
||||
export function runTaskOperationService() {}
|
||||
import { ipcMain } from 'electron';
|
||||
import { IPC_EVENTS } from '@common/constants';
|
||||
import { launchLocalChrome } from '@main/utils/chrome/launchLocalChrome'
|
||||
import { executeScriptService } from '@main/service/execute-script-service';
|
||||
import path from 'path'
|
||||
|
||||
export function runTaskOperationService() {
|
||||
const executeScriptServiceInstance = new executeScriptService();
|
||||
|
||||
ipcMain.handle(IPC_EVENTS.EXECUTE_SCRIPT, async (_event, options: any) => {
|
||||
try {
|
||||
/**
|
||||
* options参数包括:房型、日期范围
|
||||
* 房型:亲子房、雅致套房
|
||||
* 日期范围:2023-10-01至2023-10-07
|
||||
* 备注:操作的渠道有:飞猪、美团、抖音来客
|
||||
* 这里需要一个排队任务,用队列来处理各渠道的操作路径自动化,先将任务加入队列,然后按顺序执行脚本
|
||||
*/
|
||||
|
||||
await launchLocalChrome(options)
|
||||
const result = await executeScriptServiceInstance.executeScript(path.join(__dirname, '../../scripts/fg_trace.js'), options)
|
||||
|
||||
return { success: true, result };
|
||||
} catch (error: any) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// export function runTaskOperationService() {
|
||||
// ipcMain.handle(IPC_EVENTS.EXECUTE_SCRIPT, async (event, params) => {
|
||||
// logManager.info('Received task operation:', params);
|
||||
|
||||
// return new Promise((resolve, reject) => {
|
||||
// // 脚本路径
|
||||
// const scriptPath = path.join(__dirname, '../../scripts/fg_trace.js');
|
||||
|
||||
// const child = fork(scriptPath, [], {
|
||||
// stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
||||
// env: { ...process.env, ...params } // 传递环境变量
|
||||
// });
|
||||
|
||||
// let output = '';
|
||||
// let errorOutput = '';
|
||||
|
||||
// if (child.stdout) {
|
||||
// child.stdout.on('data', (data) => {
|
||||
// const msg = data.toString();
|
||||
// logManager.info(`[Task Script]: ${msg}`);
|
||||
// output += msg;
|
||||
// });
|
||||
// }
|
||||
|
||||
// if (child.stderr) {
|
||||
// child.stderr.on('data', (data) => {
|
||||
// const msg = data.toString();
|
||||
// logManager.error(`[Task Script Error]: ${msg}`);
|
||||
// errorOutput += msg;
|
||||
// });
|
||||
// }
|
||||
|
||||
// child.on('close', (code) => {
|
||||
// logManager.info(`Task script exited with code ${code}`);
|
||||
// if (code === 0) {
|
||||
// resolve({ success: true, output });
|
||||
// } else {
|
||||
// // 如果是因为模块找不到或语法错误退出,这里会捕获
|
||||
// reject(new Error(`Script exited with code ${code}. Error: ${errorOutput}`));
|
||||
// }
|
||||
// });
|
||||
|
||||
// child.on('error', (err) => {
|
||||
// logManager.error('Failed to start task script:', err);
|
||||
// reject(err);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
@@ -1,39 +1,10 @@
|
||||
import { chromium } from 'playwright';
|
||||
import { checkLoginStatus } from '@utils/checkLoginStatus';
|
||||
import dotenv from 'dotenv';
|
||||
import log from 'electron-log';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const checkLoginStatus = async (page) => {
|
||||
try {
|
||||
const currentUrl = await page.url();
|
||||
|
||||
log.info('current url==========>:', currentUrl);
|
||||
|
||||
const loginPagePatterns = ['/login', '/signin', '/auth'];
|
||||
const isLoginPage = loginPagePatterns.some(pattern => currentUrl.includes(pattern));
|
||||
|
||||
if(!isLoginPage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查页面内容中的关键字
|
||||
const pageContent = await page.content();
|
||||
const loginKeywords = ['退出', '房价房量管理'];
|
||||
const hasLoginKeyword = loginKeywords.some(keyword =>
|
||||
pageContent.includes(keyword)
|
||||
);
|
||||
|
||||
if (hasLoginKeyword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.connectOverCDP('http://localhost:9222');
|
||||
const context = browser.contexts()[0];
|
||||
@@ -116,17 +87,17 @@ const checkLoginStatus = async (page) => {
|
||||
* 2、筛选日期下存在没有安排的房型
|
||||
*/
|
||||
|
||||
await page.getByRole('textbox', { name: '-02-27' }).click();
|
||||
await page.getByText('27').nth(3).click();
|
||||
// await page.getByRole('textbox', { name: '-02-27' }).click();
|
||||
// await page.getByText('27').nth(3).click();
|
||||
// 开启房型,div:nth-child(动态变化的) > .boardRow___p2ZiO > div:nth-child(2) > div > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r
|
||||
await page.locator('div:nth-child(7) > div > div:nth-child(2) > div > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').first().click();
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(2) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(3) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(4) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(5) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
// await page.locator('div:nth-child(7) > div > div:nth-child(2) > div > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').first().click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(2) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(3) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(4) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(5) > .ant-spin-nested-loading > .ant-spin-container > div > div > .success___VQjXR > .bar___i4k4r').click();
|
||||
// 关闭房型,div:nth-child(动态变化的) > .boardRow___p2ZiO > div:nth-child(2) > div > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').first().click();
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(2) > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').click();
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(3) > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').click();
|
||||
await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(4) > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').first().click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(2) > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(3) > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').click();
|
||||
// await page.locator('div:nth-child(7) > .boardRow___p2ZiO > div:nth-child(2) > div:nth-child(4) > .ant-spin-nested-loading > .ant-spin-container > div > div > .error___IM8Yw > .bar___i4k4r').click();
|
||||
})();
|
||||
38
src/main/service/execute-script-service/index.ts
Normal file
38
src/main/service/execute-script-service/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { spawn } from 'child_process';
|
||||
import log from 'electron-log';
|
||||
|
||||
|
||||
export class executeScriptService extends EventEmitter {
|
||||
// 执行脚本
|
||||
async executeScript(scriptPath: string, options: object): Promise<{ success: boolean; message?: string; error?: string }> {
|
||||
try {
|
||||
const child = spawn('node', [scriptPath], {
|
||||
env: {
|
||||
...process.env,
|
||||
...options,
|
||||
}
|
||||
});
|
||||
|
||||
child.stdout.on('data', (data: Buffer) => {
|
||||
log.info(`stdout: ${data.toString()}`);
|
||||
});
|
||||
|
||||
child.stderr.on('data', (data: Buffer) => {
|
||||
log.info(`stderr: ${data.toString()}`);
|
||||
});
|
||||
|
||||
child.on('close', (code: number) => {
|
||||
log.info(`子进程退出,退出码 ${code}`);
|
||||
});
|
||||
|
||||
return { success: true, message: 'Node 脚本执行中' };
|
||||
} catch (error) {
|
||||
return { success: false, message: '运行 Node 脚本时出错' };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
31
src/main/utils/checkLoginStatus.ts
Normal file
31
src/main/utils/checkLoginStatus.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import log from 'electron-log';
|
||||
|
||||
export const checkLoginStatus = async (page: any) => {
|
||||
try {
|
||||
const currentUrl = await page.url();
|
||||
|
||||
log.info('current url==========>:', currentUrl);
|
||||
|
||||
const loginPagePatterns = ['/login', '/signin', '/auth'];
|
||||
const isLoginPage = loginPagePatterns.some(pattern => currentUrl.includes(pattern));
|
||||
|
||||
if(!isLoginPage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查页面内容中的关键字
|
||||
const pageContent = await page.content();
|
||||
const loginKeywords = ['退出', '房价房量管理'];
|
||||
const hasLoginKeyword = loginKeywords.some(keyword =>
|
||||
pageContent.includes(keyword)
|
||||
);
|
||||
|
||||
if (hasLoginKeyword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
17
src/main/utils/chrome/getChromePath.ts
Normal file
17
src/main/utils/chrome/getChromePath.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
// 启动本地Chrome
|
||||
export function getChromePath () {
|
||||
if (process.platform === 'win32') {
|
||||
// "C:\Program Files\Google\Chrome\Application\chrome.exe"
|
||||
return 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
||||
}
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
return 'google-chrome';
|
||||
}
|
||||
}
|
||||
7
src/main/utils/chrome/getProfileDir.ts
Normal file
7
src/main/utils/chrome/getProfileDir.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import path from "node:path";
|
||||
import { app } from 'electron';
|
||||
|
||||
// 多账号隔离
|
||||
export function getProfileDir (accountId: string) {
|
||||
return path.join(app.getPath('userData'), `profiles`, accountId);
|
||||
}
|
||||
21
src/main/utils/chrome/isChromeRunning.ts
Normal file
21
src/main/utils/chrome/isChromeRunning.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import http from 'http';
|
||||
|
||||
// Chrome是否已运行
|
||||
export async function isChromeRunning (): Promise<boolean> {
|
||||
try {
|
||||
return new Promise((resolve) => {
|
||||
const req = http.get('http://localhost:9222/json/version', (res: any) => {
|
||||
resolve(res.statusCode === 200);
|
||||
});
|
||||
|
||||
req.on('error', () => resolve(false));
|
||||
|
||||
req.setTimeout(1000, () => {
|
||||
req.destroy();
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
17
src/main/utils/chrome/isPortInUse.ts
Normal file
17
src/main/utils/chrome/isPortInUse.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import net from 'net';
|
||||
|
||||
// 检查端口占用
|
||||
export function isPortInUse (port: number) {
|
||||
return new Promise((resolve) => {
|
||||
const server = net.createServer();
|
||||
|
||||
server.once('error', (err: any) => resolve(true));
|
||||
|
||||
server.once('listening', () => {
|
||||
server.close();
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
server.listen(port);
|
||||
});
|
||||
}
|
||||
48
src/main/utils/chrome/launchLocalChrome.ts
Normal file
48
src/main/utils/chrome/launchLocalChrome.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { getChromePath } from './getChromePath';
|
||||
import { getProfileDir } from './getProfileDir';
|
||||
import { isPortInUse } from './isPortInUse';
|
||||
import { isChromeRunning } from './isChromeRunning';
|
||||
import { spawn } from 'child_process';
|
||||
import log from 'electron-log';
|
||||
|
||||
// 启动本地浏览器
|
||||
export async function launchLocalChrome (options: any) {
|
||||
const chromePath = getChromePath();
|
||||
|
||||
// 多账号隔离
|
||||
// const profileDir = getProfileDir(accountId);
|
||||
log.info(`Launching Chrome with user data dir: ${options}`);
|
||||
|
||||
// 检查端口是否被占用
|
||||
const portInUse = await isPortInUse(9222);
|
||||
|
||||
if (portInUse) {
|
||||
log.info('Chrome already running on port 9222, skip launching.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (await isChromeRunning()) {
|
||||
log.info('Chrome already running, skip launching.');
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const chromeProcess = spawn(chromePath as string, [
|
||||
'--remote-debugging-port=9222',
|
||||
'--window-size=1920,1080',
|
||||
'--window-position=0,0',
|
||||
'--no-first-run',
|
||||
'--no-default-browser-check'
|
||||
// `--user-data-dir=${profileDir}`,
|
||||
// '--window-maximized',
|
||||
], {
|
||||
detached: true,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
|
||||
chromeProcess.on('error', reject);
|
||||
|
||||
// 等浏览器起来
|
||||
resolve(0);
|
||||
});
|
||||
}
|
||||
@@ -56,8 +56,8 @@ const api: WindowApi = {
|
||||
error: (message: string, ...meta: any[]) => ipcRenderer.send(IPC_EVENTS.LOG_ERROR, message, ...meta),
|
||||
},
|
||||
|
||||
// 任务操作
|
||||
taskOperation: (params: any) => ipcRenderer.invoke(IPC_EVENTS.TASK_OPERATION, params),
|
||||
// 执行脚本
|
||||
executeScript: (params: any) => ipcRenderer.invoke(IPC_EVENTS.EXECUTE_SCRIPT, params),
|
||||
}
|
||||
|
||||
contextBridge.exposeInMainWorld('api', api)
|
||||
@@ -8,7 +8,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择日期" prop="date">
|
||||
<el-date-picker v-model="form.date" type="date" value-format="YYYY-MM-DD" placeholder="请选择日期"
|
||||
<el-date-picker v-model="ranger" type="daterange" value-format="YYYY-MM-DD" placeholder="请选择日期"
|
||||
style="width: 100%">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
@@ -29,17 +29,19 @@ const isVisible = ref(false)
|
||||
const title = ref('')
|
||||
const form = ref({
|
||||
roomType: '',
|
||||
date: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
operation: '',
|
||||
})
|
||||
const rules = ref({
|
||||
roomType: [
|
||||
{ required: true, message: '请选择房型', trigger: 'blur' },
|
||||
],
|
||||
date: [
|
||||
{ required: true, message: '请选择日期', trigger: 'blur' },
|
||||
ranger: [
|
||||
{ required: true, message: '请选择日期范围', trigger: 'blur' },
|
||||
],
|
||||
})
|
||||
const ranger = ref([])
|
||||
|
||||
// 打开弹窗
|
||||
const open = ({ type }: taskCenterItem) => {
|
||||
@@ -56,7 +58,9 @@ const close = () => {
|
||||
// 重置form
|
||||
const reset = () => {
|
||||
form.value.roomType = ''
|
||||
form.value.date = ''
|
||||
form.value.startTime = ''
|
||||
form.value.endTime = ''
|
||||
ranger.value = []
|
||||
}
|
||||
|
||||
// 取消操作
|
||||
@@ -68,8 +72,13 @@ const cancel = () => {
|
||||
// 确认操作
|
||||
const confirm = () => {
|
||||
close()
|
||||
form.value.startTime = ranger.value[0]
|
||||
form.value.endTime = ranger.value[1]
|
||||
console.log(form.value)
|
||||
window.api.taskOperation(form.value)
|
||||
/**
|
||||
* 坑:传给进程的参数不能是ref包裹的reactive对象
|
||||
*/
|
||||
window.api.executeScript({ ...form.value })
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"@assets/*": ["src/assets/*"],
|
||||
"@common/*": ["src/common/*"],
|
||||
"@service/*": ["src/main/service/*"],
|
||||
"@locales/*": ["locales/*"]
|
||||
"@locales/*": ["locales/*"],
|
||||
"@utils/*": ["src/main/utils/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export default defineConfig( async () => {
|
||||
'@renderer': resolve(__dirname, './src/renderer'),
|
||||
'@locales': resolve(__dirname, 'locales'),
|
||||
"@service": resolve(__dirname, "./src/main/service"),
|
||||
"@utils": resolve(__dirname, "./src/main/utils"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user