feat: 调整脚本功能
This commit is contained in:
@@ -220,8 +220,8 @@
|
|||||||
#### 3.5 添加脚本模板和默认脚本
|
#### 3.5 添加脚本模板和默认脚本
|
||||||
- **内容**:
|
- **内容**:
|
||||||
- 提供常用模板(点击元素、输入文本、等待页面加载)
|
- 提供常用模板(点击元素、输入文本、等待页面加载)
|
||||||
- 预置参考图中的示例脚本(change model、pause、pause resume 等)作为 `.mjs` 文件放置到 `electron/scripts/seed/` 目录
|
- 预置参考图中的示例脚本(change model、pause、pause resume 等)作为 `.mjs` 文件放置到 `electron/scripts/` 目录
|
||||||
- 应用首次启动或检测到 `electron/scripts/` 为空时,将 seed 目录下的示例脚本复制/同步到主目录,并注册到元数据索引
|
- 应用首次启动或检测到 `electron/scripts/` 为空时,直接将 `electron/scripts/` 目录下的 `.mjs` 示例脚本注册到元数据索引
|
||||||
- 用户通过面板删除默认脚本时,直接删除对应的 `.mjs` 文件及索引条目
|
- 用户通过面板删除默认脚本时,直接删除对应的 `.mjs` 文件及索引条目
|
||||||
- **依赖**:script-store-service
|
- **依赖**:script-store-service
|
||||||
- **预估工时**:3 小时
|
- **预估工时**:3 小时
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
- 录制功能至少能生成可运行的 Playwright 代码并正确落盘
|
- 录制功能至少能生成可运行的 Playwright 代码并正确落盘
|
||||||
- 面板中的"测试"或"运行"按钮能直接执行 `electron/scripts/` 目录下的真实脚本文件
|
- 面板中的"测试"或"运行"按钮能直接执行 `electron/scripts/` 目录下的真实脚本文件
|
||||||
- 脚本执行输出完整呈现在日志面板
|
- 脚本执行输出完整呈现在日志面板
|
||||||
- 默认脚本从 `electron/scripts/seed/` 同步后可正常加载和运行
|
- 默认脚本从 `electron/scripts/` 同步后可正常加载和运行
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -414,11 +414,7 @@
|
|||||||
electron/
|
electron/
|
||||||
└── scripts/
|
└── scripts/
|
||||||
├── scripts.meta.json # 脚本元数据索引(名称、启用状态、渠道等)
|
├── scripts.meta.json # 脚本元数据索引(名称、启用状态、渠道等)
|
||||||
├── change-model.mjs # 默认示例脚本(由 seed/ 自动同步)
|
├── change-model.mjs # 默认示例脚本(自动同步)
|
||||||
├── pause.mjs
|
|
||||||
├── pause-resume.mjs
|
|
||||||
└── seed/ # 预置种子脚本目录(应用自带,只读模板源)
|
|
||||||
├── change-model.mjs
|
|
||||||
├── pause.mjs
|
├── pause.mjs
|
||||||
└── pause-resume.mjs
|
└── pause-resume.mjs
|
||||||
|
|
||||||
|
|||||||
@@ -1488,7 +1488,6 @@ class executeScriptService extends events.EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const META_FILENAME = "scripts.meta.json";
|
const META_FILENAME = "scripts.meta.json";
|
||||||
const SEED_DIR = "seed";
|
|
||||||
function getScriptsDir$1() {
|
function getScriptsDir$1() {
|
||||||
return electron.app.isPackaged ? path.join(__dirname, "scripts") : path.join(process.cwd(), "electron/scripts");
|
return electron.app.isPackaged ? path.join(__dirname, "scripts") : path.join(process.cwd(), "electron/scripts");
|
||||||
}
|
}
|
||||||
@@ -1541,18 +1540,14 @@ function seedScripts() {
|
|||||||
if (fs.existsSync(metaPath)) {
|
if (fs.existsSync(metaPath)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const seedDir = path.join(scriptsDir, SEED_DIR);
|
if (!fs.existsSync(scriptsDir)) {
|
||||||
if (!fs.existsSync(seedDir)) {
|
log.info("[script-store-service] Scripts directory does not exist, skipping seed.");
|
||||||
log.info("[script-store-service] Seed directory does not exist, skipping seed.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const meta = { scripts: [] };
|
const meta = { scripts: [] };
|
||||||
const seedFiles = fs.readdirSync(seedDir).filter((f) => f.endsWith(".mjs"));
|
const scriptFiles = fs.readdirSync(scriptsDir).filter((f) => f.endsWith(".mjs"));
|
||||||
for (const file of seedFiles) {
|
for (const file of scriptFiles) {
|
||||||
const seedPath = path.join(seedDir, file);
|
|
||||||
const destPath = path.join(scriptsDir, file);
|
|
||||||
try {
|
try {
|
||||||
fs.copyFileSync(seedPath, destPath);
|
|
||||||
const name = file.replace(/\.mjs$/, "");
|
const name = file.replace(/\.mjs$/, "");
|
||||||
const now = (/* @__PURE__ */ new Date()).toISOString();
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
||||||
meta.scripts.push({
|
meta.scripts.push({
|
||||||
@@ -1566,7 +1561,7 @@ function seedScripts() {
|
|||||||
updatedAt: now
|
updatedAt: now
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.warn("[script-store-service] Failed to copy seed file", file, err);
|
log.warn("[script-store-service] Failed to seed script", file, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeMeta(meta);
|
writeMeta(meta);
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import { chromium } from 'playwright';
|
|
||||||
import { preparePage, safeDisconnectBrowser } from './common/tabs.js';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
|
|
||||||
const { page } = await preparePage(browser, {
|
|
||||||
targetUrl: 'about:blank',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example: navigate and click an element
|
|
||||||
// await page.goto('https://example.com');
|
|
||||||
// await page.click('text=Change Model');
|
|
||||||
|
|
||||||
console.log('Change model script executed');
|
|
||||||
|
|
||||||
await safeDisconnectBrowser(browser);
|
|
||||||
process.exit(0);
|
|
||||||
})();
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { chromium } from 'playwright';
|
|
||||||
import { preparePage, safeDisconnectBrowser } from './common/tabs.js';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
|
|
||||||
const { page } = await preparePage(browser, {
|
|
||||||
targetUrl: 'about:blank',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example: fill a form and submit
|
|
||||||
// await page.fill('input[name="username"]', 'test');
|
|
||||||
// await page.click('button[type="submit"]');
|
|
||||||
|
|
||||||
console.log('Pause resume script executed');
|
|
||||||
|
|
||||||
await safeDisconnectBrowser(browser);
|
|
||||||
process.exit(0);
|
|
||||||
})();
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { chromium } from 'playwright';
|
|
||||||
import { preparePage, safeDisconnectBrowser } from './common/tabs.js';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
|
|
||||||
const { page } = await preparePage(browser, {
|
|
||||||
targetUrl: 'about:blank',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example: wait for a specific element or timeout
|
|
||||||
// await page.waitForSelector('[data-testid="status-paused"]');
|
|
||||||
// await page.waitForTimeout(2000);
|
|
||||||
|
|
||||||
console.log('Pause script executed');
|
|
||||||
|
|
||||||
await safeDisconnectBrowser(browser);
|
|
||||||
process.exit(0);
|
|
||||||
})();
|
|
||||||
@@ -1,34 +1,54 @@
|
|||||||
{
|
{
|
||||||
"scripts": [
|
"scripts": [
|
||||||
{
|
{
|
||||||
"id": "seed-change-model",
|
"id": "script-dy-hot-spring-trace",
|
||||||
"name": "change-model",
|
"name": "抖音温泉房态追踪",
|
||||||
"description": "",
|
"description": "抖音生活服务平台温泉房型房态自动化追踪脚本",
|
||||||
"filename": "change-model.mjs",
|
"filename": "dy_hot_spring_trace.js",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"channel": "common",
|
"channel": "douyin",
|
||||||
"createdAt": "2026-04-12T05:27:08.543Z",
|
"createdAt": "2026-04-09T19:29:52.000Z",
|
||||||
"updatedAt": "2026-04-12T05:27:08.543Z"
|
"updatedAt": "2026-04-09T19:29:52.000Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "seed-pause-resume",
|
"id": "script-dy-hotel-trace",
|
||||||
"name": "pause-resume",
|
"name": "抖音酒店房态追踪",
|
||||||
"description": "",
|
"description": "抖音生活服务平台酒店房型房态自动化追踪脚本",
|
||||||
"filename": "pause-resume.mjs",
|
"filename": "dy_hotel_trace.js",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"channel": "common",
|
"channel": "douyin",
|
||||||
"createdAt": "2026-04-12T05:27:08.544Z",
|
"createdAt": "2026-04-09T19:29:52.000Z",
|
||||||
"updatedAt": "2026-04-12T05:27:08.544Z"
|
"updatedAt": "2026-04-09T19:29:52.000Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "seed-pause",
|
"id": "script-fg-trace",
|
||||||
"name": "pause",
|
"name": "飞猪房态追踪",
|
||||||
"description": "",
|
"description": "飞猪平台房型房态自动化追踪脚本",
|
||||||
"filename": "pause.mjs",
|
"filename": "fg_trace.js",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"channel": "common",
|
"channel": "fliggy",
|
||||||
"createdAt": "2026-04-12T05:27:08.544Z",
|
"createdAt": "2026-04-09T19:35:34.000Z",
|
||||||
"updatedAt": "2026-04-12T05:27:08.544Z"
|
"updatedAt": "2026-04-09T19:35:34.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "script-mt-trace",
|
||||||
|
"name": "美团房态追踪",
|
||||||
|
"description": "美团平台房型房态自动化追踪脚本",
|
||||||
|
"filename": "mt_trace.js",
|
||||||
|
"enabled": true,
|
||||||
|
"channel": "meituan",
|
||||||
|
"createdAt": "2026-04-09T19:29:52.000Z",
|
||||||
|
"updatedAt": "2026-04-09T19:29:52.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "script-open-all-channel",
|
||||||
|
"name": "打开所有渠道",
|
||||||
|
"description": "一键打开所有配置渠道页面的通用脚本",
|
||||||
|
"filename": "open_all_channel.js",
|
||||||
|
"enabled": true,
|
||||||
|
"channel": "",
|
||||||
|
"createdAt": "2026-04-09T19:29:52.000Z",
|
||||||
|
"updatedAt": "2026-04-09T19:29:52.000Z"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { chromium } from 'playwright';
|
|
||||||
import { preparePage, safeDisconnectBrowser } from './common/tabs.js';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
|
|
||||||
const { page } = await preparePage(browser, {
|
|
||||||
targetUrl: 'about:blank',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example: navigate and click an element
|
|
||||||
// await page.goto('https://example.com');
|
|
||||||
// await page.click('text=Change Model');
|
|
||||||
|
|
||||||
console.log('Change model script executed');
|
|
||||||
|
|
||||||
await safeDisconnectBrowser(browser);
|
|
||||||
process.exit(0);
|
|
||||||
})();
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { chromium } from 'playwright';
|
|
||||||
import { preparePage, safeDisconnectBrowser } from './common/tabs.js';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
|
|
||||||
const { page } = await preparePage(browser, {
|
|
||||||
targetUrl: 'about:blank',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example: fill a form and submit
|
|
||||||
// await page.fill('input[name="username"]', 'test');
|
|
||||||
// await page.click('button[type="submit"]');
|
|
||||||
|
|
||||||
console.log('Pause resume script executed');
|
|
||||||
|
|
||||||
await safeDisconnectBrowser(browser);
|
|
||||||
process.exit(0);
|
|
||||||
})();
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { chromium } from 'playwright';
|
|
||||||
import { preparePage, safeDisconnectBrowser } from './common/tabs.js';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
|
|
||||||
const { page } = await preparePage(browser, {
|
|
||||||
targetUrl: 'about:blank',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example: wait for a specific element or timeout
|
|
||||||
// await page.waitForSelector('[data-testid="status-paused"]');
|
|
||||||
// await page.waitForTimeout(2000);
|
|
||||||
|
|
||||||
console.log('Pause script executed');
|
|
||||||
|
|
||||||
await safeDisconnectBrowser(browser);
|
|
||||||
process.exit(0);
|
|
||||||
})();
|
|
||||||
@@ -10,7 +10,6 @@ import type {
|
|||||||
} from '@lib/script-types';
|
} from '@lib/script-types';
|
||||||
|
|
||||||
const META_FILENAME = 'scripts.meta.json';
|
const META_FILENAME = 'scripts.meta.json';
|
||||||
const SEED_DIR = 'seed';
|
|
||||||
|
|
||||||
function getScriptsDir(): string {
|
function getScriptsDir(): string {
|
||||||
return app.isPackaged
|
return app.isPackaged
|
||||||
@@ -79,20 +78,16 @@ function seedScripts(): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const seedDir = path.join(scriptsDir, SEED_DIR);
|
if (!fs.existsSync(scriptsDir)) {
|
||||||
if (!fs.existsSync(seedDir)) {
|
log.info('[script-store-service] Scripts directory does not exist, skipping seed.');
|
||||||
log.info('[script-store-service] Seed directory does not exist, skipping seed.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta: ScriptsMeta = { scripts: [] };
|
const meta: ScriptsMeta = { scripts: [] };
|
||||||
const seedFiles = fs.readdirSync(seedDir).filter((f) => f.endsWith('.mjs'));
|
const scriptFiles = fs.readdirSync(scriptsDir).filter((f) => f.endsWith('.mjs'));
|
||||||
|
|
||||||
for (const file of seedFiles) {
|
for (const file of scriptFiles) {
|
||||||
const seedPath = path.join(seedDir, file);
|
|
||||||
const destPath = path.join(scriptsDir, file);
|
|
||||||
try {
|
try {
|
||||||
fs.copyFileSync(seedPath, destPath);
|
|
||||||
const name = file.replace(/\.mjs$/, '');
|
const name = file.replace(/\.mjs$/, '');
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
meta.scripts.push({
|
meta.scripts.push({
|
||||||
@@ -106,7 +101,7 @@ function seedScripts(): void {
|
|||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.warn('[script-store-service] Failed to copy seed file', file, err);
|
log.warn('[script-store-service] Failed to seed script', file, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,6 +249,8 @@ async function confirmDelete(id: string) {
|
|||||||
confirmButtonText: t('common.delete', 'Delete'),
|
confirmButtonText: t('common.delete', 'Delete'),
|
||||||
cancelButtonText: t('common.cancel', 'Cancel'),
|
cancelButtonText: t('common.cancel', 'Cancel'),
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
|
lockScroll: false,
|
||||||
|
closeOnClickModal: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
await store.deleteScript(id);
|
await store.deleteScript(id);
|
||||||
|
|||||||
Reference in New Issue
Block a user