export function formatDate(date) { // 直接创建北京时间的日期对象 const d = new Date(date) // 获取年、月、日 const year = d.getFullYear() const month = String(d.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1 const day = String(d.getDate()).padStart(2, '0') return `${year}-${month}-${day}` } export async function simulateCompleteUserAction( clickElement, inputElement, inputText, tdTitle ) { // 1. 模拟鼠标弹起事件 const simulateMouseUp = (element) => { const mouseUpEvent = new MouseEvent('mouseup', { bubbles: true, cancelable: true, view: window, button: 0, buttons: 0, clientX: 0, clientY: 0, detail: 1 }) element.dispatchEvent(mouseUpEvent) } // 123456qq? // 2. 模拟键盘输入 const simulateTyping = async (element, text, delay = 50) => { element.focus() for (let char of text) { await new Promise((resolve) => setTimeout(resolve, delay)) // 按键按下 const keydownEvent = new KeyboardEvent('keydown', { key: char, code: `Key${char.toUpperCase()}`, bubbles: true, cancelable: true }) element.dispatchEvent(keydownEvent) // 更新输入值 element.value += char // 触发输入事件 const inputEvent = new InputEvent('input', { bubbles: true, cancelable: true, data: char, inputType: 'insertText' }) element.dispatchEvent(inputEvent) // 按键弹起 const keyupEvent = new KeyboardEvent('keyup', { key: char, code: `Key${char.toUpperCase()}`, bubbles: true, cancelable: true }) element.dispatchEvent(keyupEvent) } // 触发change事件 element.dispatchEvent(new Event('change', { bubbles: true })) } // 3. 查找td元素 const findTdByTitle = (title, timeout = 5000) => { return new Promise((resolve, reject) => { const startTime = Date.now() const find = () => { const td = document.querySelector(`td[title="${title}"]`) if (td) { resolve(td) return } if (Date.now() - startTime > timeout) { reject(new Error(`未找到title为"${title}"的td元素`)) return } requestAnimationFrame(find) } find() }) } // 4. 模拟点击事件 const simulateClick = (element) => { const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true, view: window, detail: 1 }) element.dispatchEvent(clickEvent) } try { // 执行操作序列 // 1. 触发鼠标弹起 simulateMouseUp(clickElement) await new Promise((resolve) => setTimeout(resolve, 100)) // 2. 模拟键盘输入 await simulateTyping(inputElement, inputText) await new Promise((resolve) => setTimeout(resolve, 200)) // 3. 查找并点击td元素 // const tdElement = await findTdByTitle(tdTitle); const enterKeyEvent = new KeyboardEvent('keydown', { key: 'Enter', // 事件键名 code: 'Enter', // 物理按键编码 keyCode: 13, // 传统键码(Enter键为13) which: 13, // 同keyCode bubbles: true, // 允许事件冒泡 cancelable: true // 允许事件被取消 }) setTimeout(() => { inputElement.dispatchEvent(enterKeyEvent) }, 0) await new Promise((resolve) => setTimeout(resolve, 500)) return true } catch (error) { throw error } } export async function simulateUserInput(element, value) { // 设置值 if (element.tagName.toLowerCase() === 'textarea') { element.focus() element.value = value element.blur() return } element.value = value // 创建并触发 input 事件 const inputEvent = new Event('input', { bubbles: true }) element.dispatchEvent(inputEvent) // 创建并触发 change 事件 const changeEvent = new Event('change', { bubbles: true }) element.dispatchEvent(changeEvent) // 可选:如果表单使用了 React/Vue 等框架,可能还需要触发以下事件 element.dispatchEvent(new Event('blur')) element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' })) } export function findLabelForInput(label) { let p = label.parentElement for (let i = 0; i < 5; i++) { const input = p.getElementsByTagName('input') if (input.length > 0) { return input[0] } p = p.parentElement } return null } export function findLabelForTag(label, tag) { let p = label.parentElement for (let i = 0; i < 10; i++) { const input = p.getElementsByTagName('input') if (input.length > 0) { return input[0] } p = p.parentElement } return null } export function findLabelForSpan(label) { let p = label.parentElement for (let i = 0; i < 10; i++) { const span = p.getElementsByTagName('span') if (span.length > 0) { return [...span] } p = p.parentElement } return null } export function findLabelForTextarea(label) { let p = label.parentElement for (let i = 0; i < 10; i++) { const span = p.getElementsByTagName('textarea') if (span.length > 0) { return [...span] } p = p.parentElement } return null } export function getPageInfo() { const favIconUrl = getFavicon() return { type: 'PAGE_INFO', data: { favIconUrl, title: document.title, url: window.location.href, content: window.pageAnalyzer.analyzePage() } } } export function getFavicon() { // 尝试获取动态favicon const iconLinks = Array.from(document.querySelectorAll('link[rel*="icon"]')) const favIconUrl = iconLinks .sort((a, b) => { // 优先使用大尺寸图标 const sizeA = parseInt(a.sizes?.value) || 0 const sizeB = parseInt(b.sizes?.value) || 0 return sizeB - sizeA }) .map((link) => link.href) .find(Boolean) if (favIconUrl) return favIconUrl // 如果没有找到,返回网站根目录的favicon.ico const url = new URL(window.location.href) return `${url.protocol}//${url.hostname}/favicon.ico` }