contentUtils.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. export function formatDate(date) {
  2. // 直接创建北京时间的日期对象
  3. const d = new Date(date)
  4. // 获取年、月、日
  5. const year = d.getFullYear()
  6. const month = String(d.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1
  7. const day = String(d.getDate()).padStart(2, '0')
  8. return `${year}-${month}-${day}`
  9. }
  10. export async function simulateCompleteUserAction(
  11. clickElement,
  12. inputElement,
  13. inputText,
  14. tdTitle
  15. ) {
  16. // 1. 模拟鼠标弹起事件
  17. const simulateMouseUp = (element) => {
  18. const mouseUpEvent = new MouseEvent('mouseup', {
  19. bubbles: true,
  20. cancelable: true,
  21. view: window,
  22. button: 0,
  23. buttons: 0,
  24. clientX: 0,
  25. clientY: 0,
  26. detail: 1
  27. })
  28. element.dispatchEvent(mouseUpEvent)
  29. }
  30. // 123456qq?
  31. // 2. 模拟键盘输入
  32. const simulateTyping = async (element, text, delay = 50) => {
  33. element.focus()
  34. for (let char of text) {
  35. await new Promise((resolve) => setTimeout(resolve, delay))
  36. // 按键按下
  37. const keydownEvent = new KeyboardEvent('keydown', {
  38. key: char,
  39. code: `Key${char.toUpperCase()}`,
  40. bubbles: true,
  41. cancelable: true
  42. })
  43. element.dispatchEvent(keydownEvent)
  44. // 更新输入值
  45. element.value += char
  46. // 触发输入事件
  47. const inputEvent = new InputEvent('input', {
  48. bubbles: true,
  49. cancelable: true,
  50. data: char,
  51. inputType: 'insertText'
  52. })
  53. element.dispatchEvent(inputEvent)
  54. // 按键弹起
  55. const keyupEvent = new KeyboardEvent('keyup', {
  56. key: char,
  57. code: `Key${char.toUpperCase()}`,
  58. bubbles: true,
  59. cancelable: true
  60. })
  61. element.dispatchEvent(keyupEvent)
  62. }
  63. // 触发change事件
  64. element.dispatchEvent(new Event('change', { bubbles: true }))
  65. }
  66. // 3. 查找td元素
  67. const findTdByTitle = (title, timeout = 5000) => {
  68. return new Promise((resolve, reject) => {
  69. const startTime = Date.now()
  70. const find = () => {
  71. const td = document.querySelector(`td[title="${title}"]`)
  72. if (td) {
  73. resolve(td)
  74. return
  75. }
  76. if (Date.now() - startTime > timeout) {
  77. reject(new Error(`未找到title为"${title}"的td元素`))
  78. return
  79. }
  80. requestAnimationFrame(find)
  81. }
  82. find()
  83. })
  84. }
  85. // 4. 模拟点击事件
  86. const simulateClick = (element) => {
  87. const clickEvent = new MouseEvent('click', {
  88. bubbles: true,
  89. cancelable: true,
  90. view: window,
  91. detail: 1
  92. })
  93. element.dispatchEvent(clickEvent)
  94. }
  95. try {
  96. // 执行操作序列
  97. // 1. 触发鼠标弹起
  98. simulateMouseUp(clickElement)
  99. await new Promise((resolve) => setTimeout(resolve, 100))
  100. // 2. 模拟键盘输入
  101. await simulateTyping(inputElement, inputText)
  102. await new Promise((resolve) => setTimeout(resolve, 200))
  103. // 3. 查找并点击td元素
  104. // const tdElement = await findTdByTitle(tdTitle);
  105. const enterKeyEvent = new KeyboardEvent('keydown', {
  106. key: 'Enter', // 事件键名
  107. code: 'Enter', // 物理按键编码
  108. keyCode: 13, // 传统键码(Enter键为13)
  109. which: 13, // 同keyCode
  110. bubbles: true, // 允许事件冒泡
  111. cancelable: true // 允许事件被取消
  112. })
  113. setTimeout(() => {
  114. inputElement.dispatchEvent(enterKeyEvent)
  115. }, 0)
  116. await new Promise((resolve) => setTimeout(resolve, 500))
  117. return true
  118. } catch (error) {
  119. throw error
  120. }
  121. }
  122. export async function simulateUserInput(element, value) {
  123. // 设置值
  124. if (element.tagName.toLowerCase() === 'textarea') {
  125. element.focus()
  126. element.value = value
  127. element.blur()
  128. return
  129. }
  130. element.value = value
  131. // 创建并触发 input 事件
  132. const inputEvent = new Event('input', { bubbles: true })
  133. element.dispatchEvent(inputEvent)
  134. // 创建并触发 change 事件
  135. const changeEvent = new Event('change', { bubbles: true })
  136. element.dispatchEvent(changeEvent)
  137. // 可选:如果表单使用了 React/Vue 等框架,可能还需要触发以下事件
  138. element.dispatchEvent(new Event('blur'))
  139. element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' }))
  140. }
  141. export function findLabelForInput(label) {
  142. let p = label.parentElement
  143. for (let i = 0; i < 5; i++) {
  144. const input = p.getElementsByTagName('input')
  145. if (input.length > 0) {
  146. return input[0]
  147. }
  148. p = p.parentElement
  149. }
  150. return null
  151. }
  152. export function findLabelForTag(label, tag) {
  153. let p = label.parentElement
  154. for (let i = 0; i < 10; i++) {
  155. const input = p.getElementsByTagName('input')
  156. if (input.length > 0) {
  157. return input[0]
  158. }
  159. p = p.parentElement
  160. }
  161. return null
  162. }
  163. export function findLabelForSpan(label) {
  164. let p = label.parentElement
  165. for (let i = 0; i < 10; i++) {
  166. const span = p.getElementsByTagName('span')
  167. if (span.length > 0) {
  168. return [...span]
  169. }
  170. p = p.parentElement
  171. }
  172. return null
  173. }
  174. export function findLabelForTextarea(label) {
  175. let p = label.parentElement
  176. for (let i = 0; i < 10; i++) {
  177. const span = p.getElementsByTagName('textarea')
  178. if (span.length > 0) {
  179. return [...span]
  180. }
  181. p = p.parentElement
  182. }
  183. return null
  184. }
  185. export function getPageInfo() {
  186. const favIconUrl = getFavicon()
  187. return {
  188. type: 'PAGE_INFO',
  189. data: {
  190. favIconUrl,
  191. title: document.title,
  192. url: window.location.href,
  193. content: window.pageAnalyzer.analyzePage()
  194. }
  195. }
  196. }
  197. export function getFavicon() {
  198. // 尝试获取动态favicon
  199. const iconLinks = Array.from(document.querySelectorAll('link[rel*="icon"]'))
  200. const favIconUrl = iconLinks
  201. .sort((a, b) => {
  202. // 优先使用大尺寸图标
  203. const sizeA = parseInt(a.sizes?.value) || 0
  204. const sizeB = parseInt(b.sizes?.value) || 0
  205. return sizeB - sizeA
  206. })
  207. .map((link) => link.href)
  208. .find(Boolean)
  209. if (favIconUrl) return favIconUrl
  210. // 如果没有找到,返回网站根目录的favicon.ico
  211. const url = new URL(window.location.href)
  212. return `${url.protocol}//${url.hostname}/favicon.ico`
  213. }