feat: 新增任务操作功能
This commit is contained in:
2
global.d.ts
vendored
2
global.d.ts
vendored
@@ -80,6 +80,8 @@ declare global {
|
|||||||
warn: (message: string, ...meta?: any[]) => void;
|
warn: (message: string, ...meta?: any[]) => void;
|
||||||
error: (message: string, ...meta?: any[]) => void;
|
error: (message: string, ...meta?: any[]) => void;
|
||||||
},
|
},
|
||||||
|
// 任务操作
|
||||||
|
taskOperation: (params: any) => Promise<{success: boolean, error?: string}>,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|||||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -32,6 +32,7 @@
|
|||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"log4js": "^6.9.1",
|
"log4js": "^6.9.1",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
"openai": "^6.14.0",
|
"openai": "^6.14.0",
|
||||||
"pinia": "^2.3.1",
|
"pinia": "^2.3.1",
|
||||||
"uuid": "^13.0.0",
|
"uuid": "^13.0.0",
|
||||||
@@ -8640,6 +8641,12 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mitt": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"log4js": "^6.9.1",
|
"log4js": "^6.9.1",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
"openai": "^6.14.0",
|
"openai": "^6.14.0",
|
||||||
"pinia": "^2.3.1",
|
"pinia": "^2.3.1",
|
||||||
"uuid": "^13.0.0",
|
"uuid": "^13.0.0",
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ export enum IPC_EVENTS {
|
|||||||
GET_THEME_MODE = 'get-theme-mode',
|
GET_THEME_MODE = 'get-theme-mode',
|
||||||
IS_DARK_THEME = 'is-dark-theme',
|
IS_DARK_THEME = 'is-dark-theme',
|
||||||
THEME_MODE_UPDATED = 'theme-mode-updated',
|
THEME_MODE_UPDATED = 'theme-mode-updated',
|
||||||
|
|
||||||
|
// 任务操作
|
||||||
|
TASK_OPERATION = 'task-operation',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MAIN_WIN_SIZE = {
|
export const MAIN_WIN_SIZE = {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { setupMainWindow } from './wins';
|
|||||||
import started from 'electron-squirrel-startup'
|
import started from 'electron-squirrel-startup'
|
||||||
import configManager from '@main/service/config-service'
|
import configManager from '@main/service/config-service'
|
||||||
import logManager from '@main/service/logger'
|
import logManager from '@main/service/logger'
|
||||||
|
import { runTaskOperationService } from '@main/process/runTaskOperationService'
|
||||||
|
|
||||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||||
if (started) {
|
if (started) {
|
||||||
@@ -20,6 +21,11 @@ process.on('unhandledRejection', (reason, promise) => {
|
|||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
setupMainWindow();
|
setupMainWindow();
|
||||||
|
|
||||||
|
// 开启任务操作子进程
|
||||||
|
runTaskOperationService()
|
||||||
|
|
||||||
|
// 开启subagent子进程
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quit when all windows are closed, except on macOS. There, it's common
|
// Quit when all windows are closed, except on macOS. There, it's common
|
||||||
|
|||||||
0
src/main/process/runAgentService.ts
Normal file
0
src/main/process/runAgentService.ts
Normal file
2
src/main/process/runTaskOperationService.ts
Normal file
2
src/main/process/runTaskOperationService.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
export function runTaskOperationService() {}
|
||||||
7
src/main/service/task-operation/index.ts
Normal file
7
src/main/service/task-operation/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { ipcMain } from 'electron'
|
||||||
|
import { IPC_EVENTS } from '@common/constants'
|
||||||
|
import { spawn } from 'child_process'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function runTaskOperationService() {}
|
||||||
@@ -54,7 +54,10 @@ const api: WindowApi = {
|
|||||||
info: (message: string, ...meta: any[]) => ipcRenderer.send(IPC_EVENTS.LOG_INFO, message, ...meta),
|
info: (message: string, ...meta: any[]) => ipcRenderer.send(IPC_EVENTS.LOG_INFO, message, ...meta),
|
||||||
warn: (message: string, ...meta: any[]) => ipcRenderer.send(IPC_EVENTS.LOG_WARN, message, ...meta),
|
warn: (message: string, ...meta: any[]) => ipcRenderer.send(IPC_EVENTS.LOG_WARN, message, ...meta),
|
||||||
error: (message: string, ...meta: any[]) => ipcRenderer.send(IPC_EVENTS.LOG_ERROR, message, ...meta),
|
error: (message: string, ...meta: any[]) => ipcRenderer.send(IPC_EVENTS.LOG_ERROR, message, ...meta),
|
||||||
}
|
},
|
||||||
|
|
||||||
|
// 任务操作
|
||||||
|
taskOperation: (params: any) => ipcRenderer.invoke(IPC_EVENTS.TASK_OPERATION, params),
|
||||||
}
|
}
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('api', api)
|
contextBridge.exposeInMainWorld('api', api)
|
||||||
@@ -4,7 +4,8 @@ export interface taskCenterItem {
|
|||||||
title: string
|
title: string
|
||||||
desc: string,
|
desc: string,
|
||||||
id: string,
|
id: string,
|
||||||
icon: string
|
icon: string,
|
||||||
|
type: 'sale' | 'close' | 'open'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const taskCenterList: taskCenterItem[] = [
|
export const taskCenterList: taskCenterItem[] = [
|
||||||
@@ -12,18 +13,21 @@ export const taskCenterList: taskCenterItem[] = [
|
|||||||
title: '每日销售数据',
|
title: '每日销售数据',
|
||||||
desc: '分析用于销售渠道每日数据汇总及简要展示',
|
desc: '分析用于销售渠道每日数据汇总及简要展示',
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
icon: '销'
|
icon: '销',
|
||||||
|
type: 'sale'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '关渠道房型',
|
title: '关渠道房型',
|
||||||
desc: '关闭销售渠道下的指定房型',
|
desc: '关闭销售渠道下的指定房型',
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
icon: '关'
|
icon: '关',
|
||||||
|
type: 'close'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '开渠道房型',
|
title: '开渠道房型',
|
||||||
desc: '开启销售渠道下的指定房型',
|
desc: '开启销售渠道下的指定房型',
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
icon: '开'
|
icon: '开',
|
||||||
|
type: 'open'
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
7
src/renderer/utils/emitter.ts
Normal file
7
src/renderer/utils/emitter.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import mitt from 'mitt'
|
||||||
|
|
||||||
|
const emitter = mitt();
|
||||||
|
|
||||||
|
(window as any).emitter = emitter
|
||||||
|
|
||||||
|
export default emitter
|
||||||
@@ -69,8 +69,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch, nextTick } from 'vue'
|
import { onMounted, onUnmounted, ref, watch, nextTick } from "vue";
|
||||||
import { onMounted, onUnmounted } from "vue";
|
|
||||||
import { WebSocketManager } from "@common/WebSocketManager";
|
import { WebSocketManager } from "@common/WebSocketManager";
|
||||||
import { MessageRole, ChatMessage } from "./model/ChatModel";
|
import { MessageRole, ChatMessage } from "./model/ChatModel";
|
||||||
import { IdUtils } from "@common/index";
|
import { IdUtils } from "@common/index";
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
<div class="flex-1 pb-6">
|
<div class="flex-1 pb-6">
|
||||||
<div class="flex justify-between items-center py-4">
|
<div class="flex justify-between items-center py-4">
|
||||||
<h3 class="text-base font-semibold">任务中心</h3>
|
<h3 class="text-base font-semibold">任务中心</h3>
|
||||||
<a class="text-[#3b82f6] text-[13px] cursor-pointer">
|
<!-- <a class="text-[#3b82f6] text-[13px] cursor-pointer">
|
||||||
编辑
|
编辑
|
||||||
</a>
|
</a> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-4 max-[800px]:grid-cols-1">
|
<div class="grid grid-cols-2 gap-4 max-[800px]:grid-cols-1">
|
||||||
<div v-for="item in taskList" :key="item.id" class="flex gap-3 items-start p-3.5
|
<div v-for="item in taskList" :key="item.id" class="flex gap-3 items-start p-3.5
|
||||||
rounded-[10px] border border-[#dfeaf6] bg-white cursor-pointer">
|
rounded-[10px] border border-[#dfeaf6] bg-white cursor-pointer" @click="handleTaskItem(item)">
|
||||||
<div class="w-11 h-11 bg-[#EFF6FF] rounded-lg
|
<div class="w-11 h-11 bg-[#EFF6FF] rounded-lg
|
||||||
border border-dashed border-[#9fc0e8]
|
border border-dashed border-[#9fc0e8]
|
||||||
flex items-center justify-center
|
flex items-center justify-center
|
||||||
@@ -32,7 +32,18 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { taskCenterList } from '@constant/taskCenterList'
|
import { taskCenterList, taskCenterItem } from '@constant/taskCenterList'
|
||||||
|
import emitter from '@utils/emitter'
|
||||||
|
|
||||||
const taskList = computed(() => taskCenterList)
|
const taskList = computed(() => taskCenterList)
|
||||||
|
|
||||||
|
// 点击任务项
|
||||||
|
const handleTaskItem = (item: taskCenterItem) => {
|
||||||
|
if (item.type === 'sale') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作房型
|
||||||
|
emitter.emit('OPERATION_CHANNEL', item)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
79
src/renderer/views/home/components/TaskOperationDialog.vue
Normal file
79
src/renderer/views/home/components/TaskOperationDialog.vue
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="isVisible" :title="title" width="480" align-center>
|
||||||
|
<el-form :model="form" :rules="rules" ref="formRef" label-position="top" class="pl-4 pr-4 pt-4">
|
||||||
|
<el-form-item label="选择房型" prop="roomType">
|
||||||
|
<el-select v-model="form.roomType" placeholder="请选择房型">
|
||||||
|
<el-option label="单人间" value="single"></el-option>
|
||||||
|
<el-option label="双人间" value="double"></el-option>
|
||||||
|
</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="请选择日期"
|
||||||
|
style="width: 100%">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="cancel">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirm">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { taskCenterItem } from '@constant/taskCenterList'
|
||||||
|
|
||||||
|
const isVisible = ref(false)
|
||||||
|
const title = ref('')
|
||||||
|
const form = ref({
|
||||||
|
roomType: '',
|
||||||
|
date: '',
|
||||||
|
operation: '',
|
||||||
|
})
|
||||||
|
const rules = ref({
|
||||||
|
roomType: [
|
||||||
|
{ required: true, message: '请选择房型', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
date: [
|
||||||
|
{ required: true, message: '请选择日期', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
// 打开弹窗
|
||||||
|
const open = ({ type }: taskCenterItem) => {
|
||||||
|
title.value = type === 'open' ? '开启渠道房型' : '关闭渠道房型'
|
||||||
|
isVisible.value = true
|
||||||
|
form.value.operation = type
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const close = () => {
|
||||||
|
isVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置form
|
||||||
|
const reset = () => {
|
||||||
|
form.value.roomType = ''
|
||||||
|
form.value.date = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消操作
|
||||||
|
const cancel = () => {
|
||||||
|
close()
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认操作
|
||||||
|
const confirm = () => {
|
||||||
|
close()
|
||||||
|
console.log(form.value)
|
||||||
|
window.api.taskOperation(form.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open,
|
||||||
|
close,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -2,28 +2,42 @@
|
|||||||
<layout>
|
<layout>
|
||||||
<div class="flex h-full w-full flex-col md:flex-row">
|
<div class="flex h-full w-full flex-col md:flex-row">
|
||||||
<ChatHistory class="flex-none w-50" @new-chat="guide = true" @select-chat="handleSelectChat" />
|
<ChatHistory class="flex-none w-50" @new-chat="guide = true" @select-chat="handleSelectChat" />
|
||||||
|
|
||||||
<div class="flex-1 mr-2 overflow-hidden bg-white rounded-xl">
|
<div class="flex-1 mr-2 overflow-hidden bg-white rounded-xl">
|
||||||
<ChatBox v-model:guide="guide" :conversationId="selectedConversationId" />
|
<ChatBox v-model:guide="guide" :conversationId="selectedConversationId" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TaskList />
|
<TaskList />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<TaskOperationDialog ref="taskOperationDialogRef" />
|
||||||
</layout>
|
</layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import TaskList from '@renderer/components/TaskList/index.vue'
|
import TaskList from '@renderer/components/TaskList/index.vue'
|
||||||
|
import TaskOperationDialog from '@renderer/views/home/components/TaskOperationDialog.vue'
|
||||||
import ChatHistory from './ChatHistory.vue'
|
import ChatHistory from './ChatHistory.vue'
|
||||||
import ChatBox from './ChatBox.vue'
|
import ChatBox from './ChatBox.vue'
|
||||||
import { ref } from 'vue'
|
import emitter from '@utils/emitter'
|
||||||
/// 是否显示引导页
|
|
||||||
const guide = ref(true)
|
|
||||||
/// 选择的历史会话ID
|
|
||||||
const selectedConversationId = ref('')
|
|
||||||
|
|
||||||
/// 选择历史会话
|
// 是否显示引导页
|
||||||
|
const guide = ref(true)
|
||||||
|
// 选择的历史会话ID
|
||||||
|
const selectedConversationId = ref('')
|
||||||
|
// 任务操作弹窗引用
|
||||||
|
const taskOperationDialogRef = ref()
|
||||||
|
|
||||||
|
|
||||||
|
// 选择历史会话
|
||||||
const handleSelectChat = (conversationId: string) => {
|
const handleSelectChat = (conversationId: string) => {
|
||||||
guide.value = false;
|
guide.value = false;
|
||||||
selectedConversationId.value = conversationId;
|
selectedConversationId.value = conversationId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 监听任务操作弹窗关闭事件
|
||||||
|
emitter.on('OPERATION_CHANNEL', (item) => {
|
||||||
|
taskOperationDialogRef.value?.open(item);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
132
src/scripts/fg_trace.js
Normal file
132
src/scripts/fg_trace.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import { chromium } from 'playwright';
|
||||||
|
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];
|
||||||
|
|
||||||
|
await context.addInitScript(() => {
|
||||||
|
Object.defineProperty(navigator, 'webdriver', { get: ()=> undefined });
|
||||||
|
});
|
||||||
|
|
||||||
|
const pages = await context.pages();
|
||||||
|
|
||||||
|
const page = pages.length ? pages[0] : await context.newPage();
|
||||||
|
|
||||||
|
await page.goto('https://hotel.fliggy.com/ebooking/hotelBaseInfoUv.htm#/ebk/homeV1');
|
||||||
|
|
||||||
|
const isLogin = await checkLoginStatus(page);
|
||||||
|
|
||||||
|
if(!isLogin) {
|
||||||
|
await page.getByRole('textbox', { name: '请输入账号' }).dblclick();
|
||||||
|
await page.getByRole('textbox', { name: '请输入账号' }).click();
|
||||||
|
await page.getByRole('textbox', { name: '请输入账号' }).fill(process.env.FZ_USERNAME, { delay: 80 + Math.random() * 120 });
|
||||||
|
await page.waitForTimeout(1000 + Math.random() * 1000);
|
||||||
|
await page.getByRole('button', { name: '下一步' }).click();
|
||||||
|
|
||||||
|
const frame_1 = await page.frameLocator('#alibaba-login-box');
|
||||||
|
await page.locator('#alibaba-login-box').contentFrame().getByRole('textbox', { name: '请输入登录密码' }).dblclick();
|
||||||
|
await page.locator('#alibaba-login-box').contentFrame().getByRole('textbox', { name: '请输入登录密码' }).fill(process.env.FZ_PASSWORD, { delay: 80 + Math.random() * 120 });
|
||||||
|
await page.waitForTimeout(1000 + Math.random() * 1000);
|
||||||
|
await page.locator('#alibaba-login-box').contentFrame().getByRole('button', { name: '登录' }).click();
|
||||||
|
|
||||||
|
// 等待滑块真正出现在 DOM 并可见
|
||||||
|
await page.waitForTimeout(4000 + Math.random() * 1000);
|
||||||
|
const frame_2 = await frame_1.frameLocator('#baxia-dialog-content');
|
||||||
|
const container = await frame_2.locator('#nc_1_nocaptcha');
|
||||||
|
const slider = await frame_2.locator('#nc_1_n1z');
|
||||||
|
const isVisible = await slider.isVisible();
|
||||||
|
|
||||||
|
if (isVisible) {
|
||||||
|
// 重新获取滑块按钮(可能嵌套在 iframe 里)
|
||||||
|
const containerBox = await container.boundingBox();
|
||||||
|
const sliderBox = await slider.boundingBox();
|
||||||
|
|
||||||
|
const startX = sliderBox.x + sliderBox.width / 2;
|
||||||
|
const startY = sliderBox.y + sliderBox.height / 2;
|
||||||
|
const distance = containerBox.width - sliderBox.width; // 适当拉长拖动距离
|
||||||
|
const steps = 20; // 分多步模拟人手拖动
|
||||||
|
|
||||||
|
await page.mouse.move(startX, startY);
|
||||||
|
// 等待随机时间再开始滑动(模拟人类反应)
|
||||||
|
await page.waitForTimeout(200 + Math.random() * 300);
|
||||||
|
await page.mouse.down();
|
||||||
|
await page.waitForTimeout(100 + Math.random() * 200);
|
||||||
|
|
||||||
|
// 按轨迹滑动
|
||||||
|
for (let i = 0; i < steps; i++) {
|
||||||
|
await page.mouse.move(
|
||||||
|
sliderBox.x + sliderBox.width / 2 + (distance * (i + 1) / steps),
|
||||||
|
sliderBox.y + sliderBox.height / 2 + (Math.random() * 5 - 2.5), // 模拟轻微Y轴抖动
|
||||||
|
{ steps: 5 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.mouse.up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.waitForTimeout(4000 + Math.random() * 300);
|
||||||
|
|
||||||
|
await page.getByRole('menuitem', { name: '房价房量管理' }).click();
|
||||||
|
await page.waitForTimeout(4000 + Math.random() * 1000);
|
||||||
|
await page.getByText('房价房量日历').click();
|
||||||
|
|
||||||
|
// await page.pause();
|
||||||
|
/*
|
||||||
|
* 1、我要知道日期
|
||||||
|
* 2、我要知道房型
|
||||||
|
* 3、我要知道是关闭或开启操作
|
||||||
|
*
|
||||||
|
* 存在以下影响自动化情况:
|
||||||
|
* 1、房型重新拖拽排序,会影响后续操作
|
||||||
|
* 2、筛选日期下存在没有安排的房型
|
||||||
|
*/
|
||||||
|
|
||||||
|
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();
|
||||||
|
// 关闭房型,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();
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user