lowerCodeHelper

低代码平台助手

目前為 2023-12-08 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         lowerCodeHelper
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  低代码平台助手
// @author       Ziker
// @match        https://ops.iyunquna.com/63008/*
// @match        http://localhost:63342/api/file/*
// @require      https://code.jquery.com/jquery-3.4.1.min.js
// @icon         https://favicon.qqsuu.cn/work.yqn.com
// @grant GM_openInTab
// @grant unsafeWindow
// @grant window.close
// @grant window.focus
// @run-at       document-body
// @noframes
// @license           AGPL License
// ==/UserScript==

window.jq = $.noConflict(true);

(function (window) {
    window.pageHelper = {
        // 等待元素可见
        waitElementVisible(visibleTag, index, fun) {
            let node = jq(visibleTag)
            if (node === null || node[index] === null || node[index] === undefined) {
                setTimeout(() => {
                    pageHelper.waitElementVisible(visibleTag, index, fun)
                }, 500)
            } else {
                fun()
            }
        },
        getCurrentAppIndex() {
            const nodes = document.getElementsByClassName("bar-tab");
            for (let i = 0; i < nodes.length; i++) {
                if (nodes[i].className.indexOf("bar-tab-selected") > 0) {
                    return i;
                }
            }
            return -1;
        },
        getCurrentApiId() {
            const nodes = document.getElementsByClassName("tab-content-presentation-components");
            if (nodes.length === 0) {
                return null;
            }
            let className = nodes[this.getCurrentAppIndex()].className;
            return className.substring(className.indexOf("theia-tab-") + "theia-tab-".length);
        },
        sleep(duration) {
            return new Promise(resolve => {
                setTimeout(resolve, duration)
            })
        },
        showToast(msg, duration) {
            // 显示提示
            duration = isNaN(duration) ? 3000 : duration;
            const m = document.createElement('div');
            m.innerHTML = msg;
            m.style.cssText = "display: flex;justify-content: center;align-items: center;width:60%; min-width:180px; " +
                "background:#000000; opacity:0.98; height:auto;min-height: 50px;font-size:25px; color:#fff; " +
                "line-height:30px; text-align:center; border-radius:4px; position:fixed; top:85%; left:20%; z-index:999999;";
            document.body.appendChild(m);
            setTimeout(function () {
                const d = 0.5;
                m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
                m.style.opacity = '0';
                setTimeout(function () {
                    document.body.removeChild(m)
                }, d * 1000);
            }, duration);
        },
        // 关闭窗口
        closeWindow() {
            window.opener = null;
            window.open('', '_self')
            window.close()
        },
        formatString(str, len, padding) {
            const diff = len - str.toString().length;
            if (diff > 0) {
                return padding.repeat(diff) + str;
            } else {
                return str;
            }
        },
        initSetting() {
            const customSetting = document.createElement("div");
            document.body.appendChild(customSetting)
            customSetting.innerHTML = `
<div id="copy-setting"
     style="display: none;position: absolute;top: 0;right: 0;background-color: #fff3f3;padding: 10px;width: 600px;z-index: 9999">
    <p>拷贝动作</p>
    <p><label>Copy File Id <input type="radio" name="copyValue" value="1" /></label></p>
    <p><label>Rest Api Open File <input type="radio" name="copyValue" value="2" checked/></label>&nbsp;&nbsp;&nbsp;较新版本IDEA需要下载 IDE Remote Control 插件</p>
    <p><label>ToolBox Open File <input type="radio" name="copyValue" value="3" /></label>&nbsp;&nbsp;&nbsp;需要下载 Jetbrains ToolBox 工具箱软件</p>
    <div id="projectPath" style="visibility: visible"><p><label><input name="path" style="width: 100%" type="text" placeholder="项目路径截止到 src 前  E:/yqnProject/yqn-wms/yqn-wms-rest-provider/"/></label></p></div>
    <p style="visibility: hidden"><label>同时打开编排IDE <input type="checkbox" name="openIDE" /></label>&nbsp;&nbsp;&nbsp;</p>
    <div style="display: flex;margin: 5px;justify-content: space-between">
        <button id="save" lang="zh" type="button" class="ant-btn ant-btn-default perf-tracked yqn-button"><span
                style="margin-left: 5px;">save</span></button>
        <button id="close" lang="zh" type="button" class="ant-btn ant-btn-default perf-tracked yqn-button"><span
                style="margin-left: 5px;">close</span></button>
    </div>
</div>
`
            let copyValue = localStorage.getItem("copyValue")
            copyValue = copyValue === null || copyValue === undefined ? 1 : copyValue
            document.querySelector('input[name="copyValue"][value="' + copyValue + '"]').checked = true
            document.getElementById("projectPath").style.visibility = copyValue === "2" ? "visible" : "hidden"

            let path = localStorage.getItem("path")
            document.querySelector('input[name="path"]').value = path === null || path === undefined ? null : path

            let openIDE = JSON.parse(localStorage.getItem("openIDE"));
            document.querySelector('input[name="openIDE"]').checked = openIDE === null || openIDE === undefined ? false : openIDE

            const radios = document.querySelectorAll('input[name="copyValue"]');
            for (let i = 0; i < radios.length; i++) {
                radios[i].onchange = () => {
                    const remoteRadio = document.querySelector('input[name="copyValue"]:checked');
                    document.getElementById("projectPath").style.visibility = remoteRadio.value === "2" ? "visible" : "hidden";
                }
            }
            document.getElementById("save").addEventListener("click", () => {
                const remoteRadio = document.querySelector('input[name="copyValue"]:checked').value;
                const pathInput = document.querySelector('input[name="path"]').value;
                const openIDEValue = document.querySelector('input[name="openIDE"]').checked;
                if (remoteRadio === '2' && (pathInput === null || pathInput.length === 0)) {
                    this.showToast("路径不可为空", 1000)
                } else {
                    localStorage.setItem("copyValue", remoteRadio)
                    localStorage.setItem("path", pathInput)
                    localStorage.setItem("openIDE", JSON.stringify(openIDEValue))
                    this.showToast("保存成功", 1000)
                }
            })
            document.getElementById("close").addEventListener("click", () => {
                document.getElementById("copy-setting").style.display = "none"
            })
        }
    }
})(window);


(function () {
    let historyTrace = ''
    'use strict';
    let appName = null
    jq(document).ready(function () {
        if (window.location.href.indexOf("localhost:63342/api/file/") >= 0) {
            window.pageHelper.closeWindow()
            return
        }
        // 监听api tab变动
        waitObserve(".tabs-bar", () => {
            // 应用接口面板
            const appPanelTag = ".tab-content-presentation-components.theia-tab-" + window.pageHelper.getCurrentApiId();
            // 监听属性面板变动
            waitObserve(appPanelTag + " .p-8", () => {
                const p8 = document.querySelector(appPanelTag + " .p-8");
                const panel = p8.querySelector(".ant-form.ant-form-vertical.yqn-form");
                if (nonNull(panel) && isNull(panel.querySelector(".customScriptInfo"))) {
                    const div = document.createElement("div");
                    div.className = "customScriptInfo";
                    panel.appendChild(div)
                    // 获取当前NodeName
                    const childProcessNode = panel.querySelector("#code");
                    const codeSpan = p8.querySelector(".dashboard-code span");
                    if (isNull(childProcessNode) && isNull(codeSpan)) {
                        return
                    }
                    let nodeName = nonNull(childProcessNode) ? childProcessNode.value : codeSpan.textContent
                    // 获取当前节点信息
                    getNodeInfo(nodeName, node => {
                        // 处理信息
                        const divNode = document.querySelector(appPanelTag + " .customScriptInfo");
                        // 清空显示
                        divNode.innerHTML = ""
                        // 脚本
                        if (nonNull(node.scriptId)) {
                            divNode.appendChild(createButton("脚本:" + node.scriptId, () => copyToClipboard(node.scriptId)))
                        }
                        // 入参
                        let id = node.inputScriptId;
                        const inputScriptIds = node.inputScriptIds;
                        if (nonNull(inputScriptIds)) {
                            id = nonNull(id) ? id : inputScriptIds.example;
                            id = nonNull(id) ? id : inputScriptIds.record;
                            id = nonNull(id) ? id : inputScriptIds.recordList;
                            id = nonNull(id) ? id : inputScriptIds.condition;
                            id = nonNull(id) ? id : inputScriptIds.id;
                        }
                        let isJava = true
                        if (isNull(id) && nonNull(node.dslBulidData)) {
                            isJava = false
                            id = node.dslBulidData.dslScriptId;
                        }
                        if (nonNull(id)) {
                            divNode.appendChild(createButton("入参:" + id, () => copyToClipboard(id, isJava)))
                        }
                        // 条件
                        const executeScriptId = node.executeScriptId;
                        if (nonNull(executeScriptId)) {
                            divNode.appendChild(createButton("条件:" + executeScriptId, () => copyToClipboard(executeScriptId)))
                        }
                        // 校验
                        const assertScriptId = node.assertScriptId;
                        if (nonNull(assertScriptId)) {
                            divNode.appendChild(createButton("校验:" + assertScriptId, () => copyToClipboard(assertScriptId)))
                        }
                    })
                }
            })

            // 监听执行历史面板变动
            const executeHistoryBodyTag = appPanelTag + " .test-split-item.test-split-item-right .ant-table-body tbody";
            waitObserve(executeHistoryBodyTag, () => {
                const lines = document.querySelectorAll(executeHistoryBodyTag + "  .ant-table-row.ant-table-row-level-0");
                if (nonNull(lines) && isNull(lines[0].querySelector(".customer-button-div"))) {
                    const div = document.createElement("div");
                    lines[0].appendChild(div)
                    div.className = "customer-button-div";
                    div.style.display = "none"
                    getExecuteHistory(content => {
                        for (let i = 0; i < content.length; i++) {
                            const tds = lines[i].querySelectorAll("td");
                            const actionCol = tds[tds.length - 1];
                            const detailButton = actionCol.querySelectorAll("button")[0];

                            detailButton.style.display = "none"
                            actionCol.insertBefore(createButton("RT:" + content[i].rt, () => {
                                detailButton.click()
                                historyTrace = tds[3].innerText
                            }), detailButton)
                        }
                    })
                }
            })
        })

        // 监听body变动
        waitObserve("body", () => {
            // 监听执行日志流程图变动
            const processPanelTag = ".node-bpmn #canvas .bjs-container .djs-container .viewport .layer-base";
            waitObserve(processPanelTag, () => {
                const processPanel = document.querySelector(processPanelTag);
                const rtDiv = processPanel.querySelector(".customer-rt");
                if (isNull(rtDiv)) {
                    const div = document.createElement("div");
                    processPanel.appendChild(div)
                    div.className = "customer-rt";
                    div.style.display = "none"
                    getByTraceId(apiNodeLogList => {
                        for (let i = 0; i < apiNodeLogList.length; i++) {
                            const log = apiNodeLogList[i];
                            const textNode = processPanel.querySelector("[data-element-id='" + log.nodeId + "'] text");
                            if (isNull(textNode)) {
                                continue
                            }
                            const tspan = textNode.querySelector("tspan");
                            if (nonNull(tspan)) {
                                const rtNode = tspan.cloneNode(true);
                                textNode.appendChild(rtNode)
                                rtNode.setAttribute("x", "65")
                                rtNode.setAttribute("y", "15")
                                rtNode.innerHTML = window.pageHelper.formatString(log.rt, 4, '&nbsp;&nbsp;')
                            }
                        }
                    })
                }
            }, false)
        })

        // 工具栏设置按钮
        waitObserve(".app-actions", () => {
            const buttonLists = document.querySelector(".app-actions");
            if (isNull(buttonLists) || nonNull(document.querySelector(".setting-flag"))) {
                return
            }
            appendFlagNode(document.body, "setting-flag")
            const settingButton = document.createElement("div");
            settingButton.style.marginLeft = '10px'
            const button = document.createElement("button")
            button.type = "button"
            button.id = name
            button.className = "ant-btn ant-btn-default perf-tracked yqn-button"
            button.onclick = () => {
                const settingPanel = document.getElementById("copy-setting");
                settingPanel.style.display = settingPanel.style.display === 'block' ? 'none' : "block"
            }
            const span = document.createElement("span")
            span.textContent = "CopySetting"
            button.appendChild(span)
            settingButton.appendChild(button)
            buttonLists.appendChild(settingButton)
        })

        window.pageHelper.initSetting()
        getAppProjectName(data => appName = data)
    })


    function nonNull(o) {
        return o !== null && o !== undefined;
    }

    function isNull(o) {
        return o === null || o === undefined;
    }


    // 追加标记节点
    function appendFlagNode(node, flag) {
        const divFlag = document.createElement("div");
        node.appendChild(divFlag)
        divFlag.className = flag;
        divFlag.style.display = "none"
    }

    // 等待出现并监听变化
    function waitObserve(visibleTag, fun, attributes = true) {
        window.pageHelper.waitElementVisible(visibleTag, 0, () => {
            new MutationObserver(function (mutationsList) {
                fun()
            }).observe(document.querySelector(visibleTag), {
                attributes: attributes,
                childList: true,
                subtree: true,
                characterData: true
            })
        })
    }

    function copyToClipboard(text, isJava = true) {
        let copyValue = localStorage.getItem("copyValue");
        copyValue = copyValue === null || copyValue === undefined ? '1' : copyValue;
        if (copyValue === '1') {
            let textarea = document.createElement('textarea');
            textarea.value = text;
            document.body.appendChild(textarea);
            textarea.select();
            document.execCommand('copy');
            document.body.removeChild(textarea);
            window.pageHelper.showToast("已拷贝 " + text, 1500)
        } else if (copyValue === '2') {
            let path = localStorage.getItem("path");
            path = path === null || path === undefined ? null : path;
            otherReq("http://127.0.0.1:63342/api/file/" + path + "src/main/java/com/yqn/framework/composer/api/api_" + window.pageHelper.getCurrentApiId() + "/script/Script_" + text + (isJava ? ".java" : ".json"))
            window.pageHelper.showToast("已打开文件,如未打开,检查插件是否安装以及path是否正确", 2000)
        } else if (copyValue === '3') {
            window.open('jetbrains://idea/navigate/reference?project=' + appName + '&fqn=com.yqn.framework.composer.api.api_' + window.pageHelper.getCurrentApiId() + '.script.Script_' + text)
            window.pageHelper.showToast("已打开文件,如未打开,请确认已安装Jetbrains Toolbox ", 2000)
        }
    }

    // 创建按钮
    function createButton(name, listener) {
        const button = document.createElement("button")
        button.type = "button"
        button.id = name
        button.className = "ant-btn ant-btn-link perf-tracked yqn-button yqn-link-no-padding customer-button"
        button.onclick = listener
        const span = document.createElement("span")
        span.textContent = name
        button.appendChild(span)
        return button;
    }

    // 拿流程信息
    function getNodeInfo(nodeName, fuc, apiMode = 0) {
        const addressArr = ['', '/process', '/mq', '/job'];
        remoteReq('/api/42080/api' + addressArr[apiMode] + '/details_composer', {
            "id": window.pageHelper.getCurrentApiId(),
        }, data => {
            if (isNull(data)) {
                if (apiMode === 0) {
                    getNodeInfo(nodeName, fuc, 1)
                    getNodeInfo(nodeName, fuc, 2)
                    getNodeInfo(nodeName, fuc, 3)
                }
                return
            }
            let processDefine = JSON.parse(data.processDefine);
            for (let i = 0; i < processDefine.nodes.length; i++) {
                if (processDefine.nodes[i].code === nodeName) {
                    fuc(processDefine.nodes[i])
                    break
                }
            }
        })
    }

    // 拿历史执行数据
    function getExecuteHistory(fuc) {
        remoteReq('/api/42086/apiLog/list', {}, data => {
            if (nonNull(data) && nonNull(data.content)) {
                fuc(data.content)
            }
        })
    }

    // 拿 trace 执行数据
    function getByTraceId(fuc, apiMode = 0) {
        const apiType = ['api', 'process', 'mq', 'job'];
        remoteReq('/api/42086/apiLog/getByTraceId', {
            "traceIdLike": historyTrace,
            "testCaseId": null,
            "apiTypeCode": apiMode === 0 ? "api" : apiType[apiMode]
        }, data => {
            if (nonNull(data) && nonNull(data.apiNodeLogList) && data.apiNodeLogList.length !== 0) {
                fuc(data.apiNodeLogList)
            } else if (apiMode === 0) {
                getByTraceId(fuc, 1)
                getByTraceId(fuc, 2)
                getByTraceId(fuc, 3)
            }
        })
    }

    // 获取应用名称
    function getAppProjectName(fuc) {
        remoteReq('/api/42080/application/getById', {}, data => {
            if (nonNull(data)) {
                fuc(data.appName)
            }
        })
    }


    function remoteReq(url, model, fuc) {
        model.apiId = window.pageHelper.getCurrentApiId()
        model.appId = new URLSearchParams(window.location.href.split('?')[1]).get('appId')
        model.env = "qa4"
        model.page = 1
        model.size = 20
        jq.ajax({
            url: 'https://gw-ops.iyunquna.com' + url,
            method: 'POST',
            xhrFields: {
                withCredentials: true
            },
            crossDomain: true,
            contentType: 'application/json',
            data: JSON.stringify({
                "header": {
                    "xSourceAppId": "63008",
                    "guid": "6f87e073-1da1-4017-b2de-c109abcd6d123",
                    "lang": "zh",
                    "timezone": "Asia/Shanghai"
                },
                "model": model
            }),
            success: function (response) {
                if (response.code === 200) {
                    fuc(response.data)
                }
            },
            error: function (xhr, status, error) {
                console.log('Request failed:', error);
            }
        });
    }


    function otherReq(url) {
        jq.ajax(url, {
            method: "GET",
            xhrFields: {
                withCredentials: true
            },
            crossDomain: true
        })
    }
})();