// ==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> 较新版本IDEA需要下载 IDE Remote Control 插件</p>
<p><label>ToolBox Open File <input type="radio" name="copyValue" value="3" /></label> 需要下载 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> </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, ' ')
}
}
})
}
}, 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
})
}
})();