diff --git a/src/components/CommandEditor.vue b/src/components/CommandEditor.vue index 97170ca..6466f7d 100644 --- a/src/components/CommandEditor.vue +++ b/src/components/CommandEditor.vue @@ -195,6 +195,11 @@ export default { }, insertText(text) { this.$refs.editor.repacleEditorSelection(text); + this.$refs.editor.formatDocument(); + }, + replaceText(text) { + this.$refs.editor.setEditorValue(text); + this.$refs.editor.formatDocument(); }, handleComposer({ type, code }) { switch (type) { @@ -203,7 +208,7 @@ export default { case "insert": return this.insertText(code); case "apply": - return this.$refs.editor.setEditorValue(code); + return this.replaceText(code); } }, // 保存 diff --git a/src/components/editor/CommandLanguageBar.vue b/src/components/editor/CommandLanguageBar.vue index 877ef34..3ea3972 100644 --- a/src/components/editor/CommandLanguageBar.vue +++ b/src/components/editor/CommandLanguageBar.vue @@ -221,10 +221,10 @@ export default { "program-changed", "run", "save", - "show-recorder", - "show-actions", + // "show-recorder", + // "show-actions", "show-help", - "add-action", + "use-composer", ], computed: { programLanguages() { diff --git a/src/components/editor/MonacoEditor.vue b/src/components/editor/MonacoEditor.vue index c203a3a..eb46449 100644 --- a/src/components/editor/MonacoEditor.vue +++ b/src/components/editor/MonacoEditor.vue @@ -66,6 +66,16 @@ export default { minimap: { enabled: false, }, + formatOnType: true, + formatOnPaste: true, + autoIndent: "full", + // JavaScript 特定的格式化选项 + "javascript.format.insertSpaceAfterSemicolonInForStatements": true, + "javascript.format.insertSpaceBeforeAndAfterBinaryOperators": true, + "javascript.format.insertSpaceAfterConstructor": true, + "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": true, + "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": true, + "javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, }; this.editor = monaco.editor.create( document.getElementById("monacoEditor"), @@ -212,6 +222,9 @@ export default { }; this.rawEditor().executeEdits("my-source", [op]); }, + formatDocument() { + this.rawEditor().getAction("editor.action.formatDocument").run(); + }, listenEditorValue() { this.rawEditor().focus(); this.rawEditor().onDidChangeModelContent(() => { diff --git a/src/components/editor/composer/CommandComposer.vue b/src/components/editor/composer/CommandComposer.vue index 8f17cb5..b7048a6 100644 --- a/src/components/editor/composer/CommandComposer.vue +++ b/src/components/editor/composer/CommandComposer.vue @@ -61,6 +61,7 @@ export default defineComponent({ availableCommands, }; }, + emits: ["use-composer", "update:modelValue"], methods: { addCommand(action) { this.commandFlow.push({ @@ -84,8 +85,9 @@ export default defineComponent({ outputVars.set(index, varName); line += `let ${varName} = `; } - - if (cmd.useOutput !== null) { + if (cmd.value === "ubrowser") { + line += cmd.argv; + } else if (cmd.useOutput !== null) { const inputVar = outputVars.get(cmd.useOutput); line += `${cmd.value}(${inputVar})`; } else { diff --git a/src/components/editor/composer/composerConfig.js b/src/components/editor/composer/composerConfig.js index e89eda6..646b161 100644 --- a/src/components/editor/composer/composerConfig.js +++ b/src/components/editor/composer/composerConfig.js @@ -1,3 +1,9 @@ +export { + ubrowserActionIcons, + ubrowserOperationConfigs, + defaultUBrowserConfigs, +} from "./ubrowser/ubrowserConfig"; + // 定义命令图标映射 export const commandIcons = { open: "folder_open", @@ -137,58 +143,3 @@ export const commandsAcceptOutput = { send: true, copyTo: true, }; - -// 添加 ubrowser 操作图标映射 -export const ubrowserActionIcons = { - wait: "timer", - click: "mouse", - css: "style", - press: "keyboard", - paste: "content_paste", - screenshot: "photo_camera", - pdf: "picture_as_pdf", - device: "devices", - cookies: "cookie", - evaluate: "code", - when: "rule", - mousedown: "mouse", - mouseup: "mouse", - file: "upload_file", - value: "edit", - check: "check_box", - focus: "center_focus_strong", - scroll: "swap_vert", - download: "download", - hide: "visibility_off", - show: "visibility", - devTools: "developer_board", -}; - -// 添加 ubrowser 可用操作列表 -export const ubrowserAvailableActions = [ - { label: "等待", value: "wait" }, - { label: "点击", value: "click" }, - { label: "注入CSS", value: "css" }, - { label: "按键", value: "press" }, - { label: "粘贴", value: "paste" }, - { label: "截图", value: "screenshot" }, - { label: "导出PDF", value: "pdf" }, - { label: "模拟设备", value: "device" }, - { label: "获取Cookie", value: "cookies" }, - { label: "设置Cookie", value: "setCookies" }, - { label: "删除Cookie", value: "removeCookies" }, - { label: "清除Cookie", value: "clearCookies" }, - { label: "执行脚本", value: "evaluate" }, - { label: "条件判断", value: "when" }, - { label: "鼠标按下", value: "mousedown" }, - { label: "鼠标释放", value: "mouseup" }, - { label: "上传文件", value: "file" }, - { label: "设置值", value: "value" }, - { label: "选中状态", value: "check" }, - { label: "获取焦点", value: "focus" }, - { label: "滚动", value: "scroll" }, - { label: "下载", value: "download" }, - { label: "隐藏", value: "hide" }, - { label: "显示", value: "show" }, - { label: "开发工具", value: "devTools" }, -]; diff --git a/src/components/editor/composer/ubrowser/UBrowserBasic.vue b/src/components/editor/composer/ubrowser/UBrowserBasic.vue index 86f9168..c221db2 100644 --- a/src/components/editor/composer/ubrowser/UBrowserBasic.vue +++ b/src/components/editor/composer/ubrowser/UBrowserBasic.vue @@ -15,22 +15,6 @@ - -
- - - -
-
@@ -48,20 +32,57 @@
- - - +
+
+ + + +
+
+ + + +
+
+ + +
+ + + +
@@ -76,10 +97,14 @@ export default defineComponent({ required: true, }, }, - emits: ["update:configs"], data() { return { + selectedUA: null, localConfigs: { + useragent: { + preset: null, + value: "", + }, goto: { url: "", headers: { @@ -89,27 +114,83 @@ export default defineComponent({ timeout: 60000, }, }, + userAgentOptions: [ + { + label: "Chrome (Windows)", + value: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + }, + { + label: "Chrome (macOS)", + value: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + }, + { + label: "Chrome (Linux)", + value: + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + }, + { + label: "IE 11", + value: + "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", + }, + { + label: "微信 (Android)", + value: + "Mozilla/5.0 (Linux; Android 14; Pixel 8 Build/UQ1A.240205.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.64 Mobile Safari/537.36 XWEB/1160027 MMWEBSDK/20231202 MMWEBID/2308 MicroMessenger/8.0.47.2560(0x28002F35) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64", + }, + { + label: "微信 (iOS)", + value: + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.47(0x18002f2c) NetType/WIFI Language/zh_CN", + }, + { + label: "iPhone", + value: + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1", + }, + { + label: "iPad", + value: + "Mozilla/5.0 (iPad; CPU OS 17_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1", + }, + { + label: "Android Phone", + value: + "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36", + }, + { + label: "Android Tablet", + value: + "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + }, + ], }; }, created() { // 初始化本地配置 - this.localConfigs = JSON.parse(JSON.stringify(this.configs)); + this.localConfigs = _.cloneDeep(this.configs); }, methods: { updateConfigs() { - this.$emit( - "update:configs", - JSON.parse(JSON.stringify(this.localConfigs)) - ); + this.$emit("update:configs", _.cloneDeep(this.localConfigs)); }, }, watch: { configs: { deep: true, handler(newConfigs) { - this.localConfigs = JSON.parse(JSON.stringify(newConfigs)); + this.localConfigs = _.cloneDeep(newConfigs); }, }, + selectedUA(value) { + if (value) { + this.localConfigs.goto.headers.userAgent = value; + this.updateConfigs(); + this.selectedUA = null; + } + }, }, }); diff --git a/src/components/editor/composer/ubrowser/UBrowserEditor.vue b/src/components/editor/composer/ubrowser/UBrowserEditor.vue index a1fae37..846330e 100644 --- a/src/components/editor/composer/ubrowser/UBrowserEditor.vue +++ b/src/components/editor/composer/ubrowser/UBrowserEditor.vue @@ -66,6 +66,8 @@ import { defineComponent } from "vue"; import UBrowserBasic from "./UBrowserBasic.vue"; import UBrowserOperations from "./UBrowserOperations.vue"; import UBrowserRun from "./UBrowserRun.vue"; +import { defaultUBrowserConfigs } from "./ubrowserConfig"; +import { generateUBrowserCode } from "./generateUBrowserCode"; export default defineComponent({ name: "UBrowserEditor", @@ -85,142 +87,7 @@ export default defineComponent({ return { step: 1, selectedActions: [], - configs: { - // 基础参数 - useragent: { - value: "", - }, - goto: { - url: "", - headers: { - Referer: "", - userAgent: "", - }, - timeout: 60000, - }, - // 浏览器操作 - wait: { - value: "", - timeout: 60000, - }, - click: { - selector: "", - }, - css: { - value: "", - }, - press: { - key: "", - modifiers: [], - }, - paste: { - text: "", - }, - screenshot: { - selector: "", - rect: { x: 0, y: 0, width: 0, height: 0 }, - savePath: "", - }, - pdf: { - options: { - marginsType: 0, - pageSize: "A4", - }, - savePath: "", - }, - device: { - size: { width: 1280, height: 800 }, - useragent: "", - }, - cookies: { - name: "", - }, - setCookies: { - items: [{ name: "", value: "" }], - }, - removeCookies: { - name: "", - }, - clearCookies: { - url: "", - }, - evaluate: { - function: "", - params: [], - }, - when: { - condition: "", - }, - mousedown: { - selector: "", - }, - mouseup: { - selector: "", - }, - file: { - selector: "", - files: [], - }, - value: { - selector: "", - value: "", - }, - check: { - selector: "", - checked: false, - }, - focus: { - selector: "", - }, - scroll: { - target: "", - x: 0, - y: 0, - }, - download: { - url: "", - savePath: "", - }, - // 运行参数 - run: { - show: true, - width: 1280, - height: 800, - x: undefined, - y: undefined, - center: true, - minWidth: 800, - minHeight: 600, - maxWidth: undefined, - maxHeight: undefined, - resizable: true, - movable: true, - minimizable: true, - maximizable: true, - alwaysOnTop: false, - fullscreen: false, - fullscreenable: true, - enableLargerThanScreen: false, - opacity: 1, - }, - }, - defaultRunConfigs: { - show: true, - width: 1280, - height: 800, - center: true, - minWidth: 800, - minHeight: 600, - resizable: true, - movable: true, - minimizable: true, - maximizable: true, - alwaysOnTop: false, - fullscreen: false, - fullscreenable: true, - enableLargerThanScreen: false, - opacity: 1, - }, + configs: _.cloneDeep(defaultUBrowserConfigs), }; }, methods: { @@ -235,249 +102,31 @@ export default defineComponent({ this.selectedActions.splice(index, 1); } }, - generateCode() { - let code = "utools.ubrowser"; - - // 基础参数 - if (this.configs.useragent.value) { - code += `.useragent('${this.configs.useragent.value}')`; - } - - if (this.configs.goto.url) { - const gotoOptions = {}; - if (this.configs.goto.headers.Referer) { - gotoOptions.headers = gotoOptions.headers || {}; - gotoOptions.headers.Referer = this.configs.goto.headers.Referer; - } - if (this.configs.goto.headers.userAgent) { - gotoOptions.headers = gotoOptions.headers || {}; - gotoOptions.headers["User-Agent"] = - this.configs.goto.headers.userAgent; - } - if (this.configs.goto.timeout !== 60000) { - gotoOptions.timeout = this.configs.goto.timeout; - } - - code += `.goto('${this.configs.goto.url}'${ - Object.keys(gotoOptions).length - ? `, ${JSON.stringify(gotoOptions)}` - : "" - })`; - } - - // 浏览器操作 - this.selectedActions.forEach((action) => { - const config = this.configs[action.value]; - switch (action.value) { - case "wait": - if (config.value) { - code += `.wait('${config.value}'${ - config.timeout !== 60000 ? `, ${config.timeout}` : "" - })`; - } - break; - - case "click": - if (config.selector) { - code += `.click('${config.selector}')`; - } - break; - - case "css": - if (config.value) { - code += `.css('${config.value}')`; - } - break; - - case "press": - if (config.key) { - const modifiers = config.modifiers.length - ? `, ${JSON.stringify(config.modifiers)}` - : ""; - code += `.press('${config.key}'${modifiers})`; - } - break; - - case "paste": - if (config.text) { - code += `.paste('${config.text}')`; - } - break; - - case "screenshot": - if (config.selector || config.savePath) { - const options = {}; - if (config.selector) options.selector = config.selector; - if (config.rect.width && config.rect.height) { - options.rect = config.rect; - } - code += `.screenshot('${config.savePath}'${ - Object.keys(options).length - ? `, ${JSON.stringify(options)}` - : "" - })`; - } - break; - - case "pdf": - if (config.savePath) { - code += `.pdf('${config.savePath}'${ - config.options ? `, ${JSON.stringify(config.options)}` : "" - })`; - } - break; - - case "device": - if (config.size.width && config.size.height) { - const options = { - size: config.size, - }; - if (config.useragent) options.useragent = config.useragent; - code += `.device(${JSON.stringify(options)})`; - } - break; - - case "cookies": - if (config.name) { - code += `.cookies('${config.name}')`; - } - break; - - case "setCookies": - if (config.items?.length) { - code += `.setCookies(${JSON.stringify(config.items)})`; - } - break; - - case "removeCookies": - if (config.name) { - code += `.removeCookies('${config.name}')`; - } - break; - - case "clearCookies": - code += `.clearCookies(${config.url ? `'${config.url}'` : ""})`; - break; - - case "evaluate": - if (config.function) { - const params = config.params.length - ? `, ${JSON.stringify(config.params)}` - : ""; - code += `.evaluate(\`${config.function}\`${params})`; - } - break; - - case "when": - if (config.condition) { - code += `.when('${config.condition}')`; - } - break; - - case "mousedown": - case "mouseup": - if (config.selector) { - code += `.${action.value}('${config.selector}')`; - } - break; - - case "file": - if (config.selector && config.files?.length) { - code += `.file('${config.selector}', ${JSON.stringify( - config.files - )})`; - } - break; - - case "value": - if (config.selector) { - code += `.value('${config.selector}', '${config.value}')`; - } - break; - - case "check": - if (config.selector) { - code += `.check('${config.selector}'${ - config.checked !== undefined ? `, ${config.checked}` : "" - })`; - } - break; - - case "focus": - if (config.selector) { - code += `.focus('${config.selector}')`; - } - break; - - case "scroll": - if (config.type === "element" && config.selector) { - code += `.scroll('${config.selector}')`; - } else if (config.type === "position") { - if (config.x !== undefined && config.y !== undefined) { - code += `.scroll(${config.x}, ${config.y})`; - } else if (config.y !== undefined) { - code += `.scroll(${config.y})`; - } - } - break; - - case "download": - if (config.url) { - code += `.download('${config.url}'${ - config.savePath ? `, '${config.savePath}'` : "" - })`; - } - break; - - case "hide": - case "show": - code += `.${action.value}()`; - break; - - case "devTools": - if (config.mode) { - code += `.devTools('${config.mode}')`; - } else { - code += `.devTools()`; - } - break; - } - }); - - // 运行参数 - const runOptions = {}; - Object.entries(this.configs.run).forEach(([key, value]) => { - if ( - value !== undefined && - value !== null && - value !== this.defaultRunConfigs[key] - ) { - runOptions[key] = value; - } - }); - - code += `.run(${ - Object.keys(runOptions).length ? JSON.stringify(runOptions) : "" - })`; - - this.$emit("update:modelValue", code); - }, }, watch: { configs: { deep: true, handler() { - this.generateCode(); + this.$emit( + "update:modelValue", + generateUBrowserCode(this.configs, this.selectedActions) + ); }, }, selectedActions: { handler() { - this.generateCode(); + this.$emit( + "update:modelValue", + generateUBrowserCode(this.configs, this.selectedActions) + ); }, }, step: { handler() { - this.generateCode(); + this.$emit( + "update:modelValue", + generateUBrowserCode(this.configs, this.selectedActions) + ); }, }, }, diff --git a/src/components/editor/composer/ubrowser/UBrowserOperations.vue b/src/components/editor/composer/ubrowser/UBrowserOperations.vue index 60c5898..c662ec6 100644 --- a/src/components/editor/composer/ubrowser/UBrowserOperations.vue +++ b/src/components/editor/composer/ubrowser/UBrowserOperations.vue @@ -4,8 +4,10 @@
- {{ action.label }} + {{ label }}
@@ -43,7 +45,9 @@ @@ -72,11 +76,11 @@ />
-
+
@@ -88,10 +92,7 @@ + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserCheckbox.vue b/src/components/editor/composer/ubrowser/operations/UBrowserCheckbox.vue new file mode 100644 index 0000000..c368d48 --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserCheckbox.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserCheckboxGroup.vue b/src/components/editor/composer/ubrowser/operations/UBrowserCheckboxGroup.vue new file mode 100644 index 0000000..adb26f7 --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserCheckboxGroup.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserCookieList.vue b/src/components/editor/composer/ubrowser/operations/UBrowserCookieList.vue new file mode 100644 index 0000000..6efc7ec --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserCookieList.vue @@ -0,0 +1,89 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserDeviceName.vue b/src/components/editor/composer/ubrowser/operations/UBrowserDeviceName.vue new file mode 100644 index 0000000..e418576 --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserDeviceName.vue @@ -0,0 +1,83 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserDeviceSize.vue b/src/components/editor/composer/ubrowser/operations/UBrowserDeviceSize.vue new file mode 100644 index 0000000..3b47402 --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserDeviceSize.vue @@ -0,0 +1,68 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserFileList.vue b/src/components/editor/composer/ubrowser/operations/UBrowserFileList.vue new file mode 100644 index 0000000..11da2a4 --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserFileList.vue @@ -0,0 +1,73 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserFunctionInput.vue b/src/components/editor/composer/ubrowser/operations/UBrowserFunctionInput.vue new file mode 100644 index 0000000..f417ed1 --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserFunctionInput.vue @@ -0,0 +1,197 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserInput.vue b/src/components/editor/composer/ubrowser/operations/UBrowserInput.vue index 2402bbe..caa9394 100644 --- a/src/components/editor/composer/ubrowser/operations/UBrowserInput.vue +++ b/src/components/editor/composer/ubrowser/operations/UBrowserInput.vue @@ -1,26 +1,16 @@ diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserNamedParamList.vue b/src/components/editor/composer/ubrowser/operations/UBrowserNamedParamList.vue new file mode 100644 index 0000000..b90121e --- /dev/null +++ b/src/components/editor/composer/ubrowser/operations/UBrowserNamedParamList.vue @@ -0,0 +1,82 @@ + + + diff --git a/src/components/editor/composer/ubrowser/operations/UBrowserOperation.vue b/src/components/editor/composer/ubrowser/operations/UBrowserOperation.vue index cf6cbc5..26f2b96 100644 --- a/src/components/editor/composer/ubrowser/operations/UBrowserOperation.vue +++ b/src/components/editor/composer/ubrowser/operations/UBrowserOperation.vue @@ -7,240 +7,119 @@ > - -