From 86a6a25bf35ac5d377b38c6b2a04dbb534e945e7 Mon Sep 17 00:00:00 2001 From: caorui <3165079241@qq.com> Date: Fri, 1 Aug 2025 14:59:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=AD=E5=BF=83=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E8=BF=AD=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/LinkUp/compoment/EditorItem.vue | 415 ++++++++++++++++++ src/views/LinkUp/compoment/addDialogChunk.vue | 397 ++++++++++------- .../LinkUp/compoment/viewDialogChunk.vue | 384 +++++++++++++--- 3 files changed, 975 insertions(+), 221 deletions(-) create mode 100644 src/views/LinkUp/compoment/EditorItem.vue diff --git a/src/views/LinkUp/compoment/EditorItem.vue b/src/views/LinkUp/compoment/EditorItem.vue new file mode 100644 index 0000000..83145d3 --- /dev/null +++ b/src/views/LinkUp/compoment/EditorItem.vue @@ -0,0 +1,415 @@ + + + + + + diff --git a/src/views/LinkUp/compoment/addDialogChunk.vue b/src/views/LinkUp/compoment/addDialogChunk.vue index b0c6036..1529379 100644 --- a/src/views/LinkUp/compoment/addDialogChunk.vue +++ b/src/views/LinkUp/compoment/addDialogChunk.vue @@ -575,6 +575,35 @@ +
+
+ Headers入参 +
+
+ Query入参 +
+
+ Body入参 +
+
暂存
-
- -
-
-
- -
-
- -
-
-
-
+
+ +
@@ -732,6 +699,7 @@ import baseForm from "@/components/base/baseNewForm"; import treeNode from "./TreeNode"; import IconsDialog from "../../tool/build/IconsDialog.vue"; import jsonView from "vue-json-views"; +import EditorItem from "./EditorItem.vue"; export default { components: { editSence, @@ -742,6 +710,7 @@ export default { treeNode, IconsDialog, jsonView, + EditorItem, }, data() { return { @@ -826,35 +795,60 @@ export default { }, parameterType: "body", //参数类型 + + editorRefs: {}, // 用来保存所有子组件的 editor DOM }; }, methods: { + switchTabs(val) { + this.parameterType = val; + // 非数据库应用 + if (this.currentRowData.options.appType != "9") { + this.queryApiConfig("tab"); + } + }, async saveTestTableEvent(type) { - if (!this.outsideFormData.tableName) { + if ( + this.currentRowData.options.appType == "9" && + !this.outsideFormData.tableName + ) { this.$vmNews("请先选择表"); return; } this.openLoading("暂存"); // 使用示例:传入你这段 HTML 所在的 DOM 根节点 - const root = document.querySelector("#editorContainer"); - const parsed = this.extractEditorItems(root); + const parsed = this.extractEditorItems(); let data = this.currentRowData.options; - let params = { - detailList: parsed, - flowId: this.sceneID, - stepID: data.stepID, - stepAccountId: data.step_acc_id, - actionName: data.apiName || data.plugName, - tableName: this.outsideFormData.tableName, - appType: this.currentRowData.options.appType, - }; - if ( - this.currentRowData.options && - this.currentRowData.options.appType == "9" && - this.currentRowData.options.apiName.includes("查询") - ) { - params.rowNum = this.pageFormData.rowNum; - params.pageLimit = this.pageFormData.pageLimit; + let params = {}; + if (data && data.appType == "9") { + params = { + detailList: parsed, + flowId: this.sceneID, + stepID: data.stepID, + stepAccountId: data.step_acc_id, + actionName: data.apiName || data.plugName, + tableName: this.outsideFormData.tableName, + appType: data.appType, + }; + if (data.apiName.includes("查询")) { + params.rowNum = this.pageFormData.rowNum; + params.pageLimit = this.pageFormData.pageLimit; + } + } else { + params = { + flowId: this.sceneID, + stepID: data.stepID, + headerIn: "", //请求头入参 + queryIn: "", //query入参 + bodyIn: "", //bodyIn入参 + }; + if (this.parameterType == "body") { + params.bodyIn = parsed; + } else if (this.parameterType == "header") { + params.headerIn = parsed; + } else if (this.parameterType == "query") { + params.queryIn = parsed; + } } let res = await authApi( @@ -872,38 +866,18 @@ export default { } } }, - extractEditorItems(rootElement) { - const result = []; - const items = rootElement.querySelectorAll(".editorItem"); - items.forEach((item) => { - const fieldName = - item.querySelector(".el-form-item__label")?.innerText.trim() || ""; - const editor = item.querySelector(".content-editor"); - if (!editor) return; + extractEditorItems() { + if (!this.$refs.editorRefs) return []; - const html_label = editor.innerHTML.trim(); // 保留标签结构 - - let whereCondition = ""; - editor.childNodes.forEach((node) => { - if (node.nodeType === Node.TEXT_NODE) { - whereCondition += node.textContent; - } else if (node.nodeType === Node.ELEMENT_NODE) { - whereCondition += node.getAttribute("data-token-text") || ""; - } - }); - // 替换中文符号为英文符号 - whereCondition = whereCondition - .replace(/,/g, ",") - .replace(/(/g, "(") - .replace(/)/g, ")"); - - result.push({ fieldName, whereCondition, html_label }); - }); - - return result; + return this.$refs.editorRefs.map((editorComp) => + editorComp.getEditorContent() + ); }, async hitTesting() { - if (!this.outsideFormData.tableName) { + if ( + this.currentRowData.options.appType == "9" && + !this.outsideFormData.tableName + ) { this.$vmNews("请先选择表"); return; } @@ -913,7 +887,11 @@ export default { let params = { stepID: data.stepID, tableName: this.outsideFormData.tableName, + appType: this.currentRowData.options.appType, }; + if (this.currentRowData.options.appType == "9") { + delete params.tableName; + } let res = await authApi( "sysFlowStepConfigService", "", @@ -1169,6 +1147,9 @@ export default { this.apiIDActiv = ""; this.userActivId = ""; this.CurrentAppRow = {}; + // 用来保存所有子组件的 editor DOM + this.editorRefs = {}; + this.parameterType= "body" if (index === 0) { this.activeTabName = "选择操作"; @@ -1443,6 +1424,13 @@ export default { ) { this.queryColumns(this.outsideFormData.tableName); } + if ( + this.activeOtherTabName == "配置应用" && + this.apiIdActiv && + this.currentRowData.options.appType != "9" + ) { + this.getStepConfig(); + } }, /** * 应用搜索 @@ -1679,7 +1667,7 @@ export default { } }, // 获取表字段 - async queryApiConfig() { + async queryApiConfig(type) { if (!this.currentRowData.options.apiId) { return; } @@ -1700,7 +1688,9 @@ export default { if (res.status == "200") { this.outsideColumns = res.attribute || []; this.$nextTick(() => { - // this.getStepConfig(); + if (type == "tab") { + this.getStepConfig(); + } }); } }, @@ -1876,15 +1866,29 @@ export default { params ); if (res.status == "200") { - const root = document.querySelector("#editorContainer"); + let detailList = []; if ( - res.attribute && - res.attribute.detailList && - res.attribute.detailList.length > 0 + this.currentRowData.options.appType && + this.currentRowData.options.appType == "9" ) { - res.attribute.detailList.forEach((item) => { - this.matchEditorItems(root, item.fieldName, item.html_label); - }); + detailList = res.attribute?.detailList || []; + } else { + if (this.parameterType == "body") { + detailList = res.attribute?.bodyIn + ? JSON.parse(res.attribute.bodyIn) + : []; + } else if (this.parameterType == "header") { + detailList = res.attribute?.headerIn + ? JSON.parse(res.attribute.headerIn) + : []; + } else if (this.parameterType == "query") { + detailList = res.attribute?.queryIn + ? JSON.parse(res.attribute.queryIn) + : []; + } + } + if (detailList.length > 0) { + this.recursivelyApplyHtmlLabel(this.outsideColumns, detailList); } if ( this.currentRowData.options && @@ -1896,18 +1900,43 @@ export default { } } }, - matchEditorItems(rootElement, rootName, rootHtml) { - const items = rootElement.querySelectorAll(".editorItem"); - items.forEach((item) => { - const fieldName = - item.querySelector(".el-form-item__label")?.innerText.trim() || ""; - const editor = item.querySelector(".content-editor"); - if (!editor) return; - if (rootName == fieldName) { - editor.innerHTML = rootHtml; + // 匹配数据 + recursivelyApplyHtmlLabel(columns, detailList, path = []) { + columns.forEach((col, index) => { + const match = detailList.find( + (item) => item.fieldName === col.column_name + ); + if (match && match.html_label) { + this.matchEditorItems(match, index, path); + } + if ( + col.children && + col.children.length > 0 && + match.children && + match.children.length > 0 + ) { + this.recursivelyApplyHtmlLabel(col.children, match.children, [ + ...path, + index, + ]); } }); }, + // 回显 + matchEditorItems(match, index, path = []) { + const refName = + "contentEditor" + match.fieldName + [...path, index].join("-"); + // 这里获取ref + const refEl = this.editorRefs[refName]; + if (match && match.html_label && refEl) { + // 可能refEl是数组,取第一个元素 + if (Array.isArray(refEl)) { + refEl[0].innerHTML = match.html_label; + } else if (refEl instanceof HTMLElement) { + refEl.innerHTML = match.html_label; + } + } + }, /** * 获取插件列表 * @param {string} appId 应用 ID @@ -2066,9 +2095,13 @@ export default { pageLimit: "100", }; }, + + registerEditorRef(refName, dom) { + this.$set(this.editorRefs, refName, dom); + }, representationChange() { if (!this.currenrActiveNodeRef) return; - const editor = this.$refs[this.currenrActiveNodeRef][0]; + const editor = this.editorRefs[this.currenrActiveNodeRef]; if (!editor) return; // 创建 range 和 selection const range = document.createRange(); @@ -2085,8 +2118,9 @@ export default { this.saveRange(); }, handleKeyDown(e, columnName, rowIndex) { - const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; - + const refName = "contentEditor" + columnName + rowIndex; + const editor = this.editorRefs[refName]; + if (!editor) return; if (e.key === "Backspace") { // 检查是否在光标前有token需要删除 const selection = window.getSelection(); @@ -2123,8 +2157,10 @@ export default { }, // 处理编辑器点击 handleEditorClick(e, columnName, rowIndex) { - const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; - this.currenrActiveNodeRef = "contentEditor" + columnName + rowIndex; + const refName = "contentEditor" + columnName + rowIndex; + const editor = this.editorRefs[refName]; + if (!editor) return; + this.currenrActiveNodeRef = refName; editor.focus(); this.saveRange(); }, @@ -2135,7 +2171,9 @@ export default { }, // 处理编辑器获得焦点 handleEditorFocus(e, columnName, rowIndex) { - const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + const refName = "contentEditor" + columnName + rowIndex; + const editor = this.editorRefs[refName]; + if (!editor) return; // 如果编辑器为空,设置光标到开始位置 if (this.isEmpty(columnName, rowIndex)) { setTimeout(() => { @@ -2150,7 +2188,8 @@ export default { }, // 判断当前编辑器是否为空 isEmpty(columnName, rowIndex) { - const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + const refName = "contentEditor" + columnName + rowIndex; + const editor = this.editorRefs[refName]; if (!editor) return true; const content = editor.textContent.trim(); const hasTokens = editor.querySelectorAll(".content-token").length > 0; @@ -2161,10 +2200,10 @@ export default { // 可以在这里处理失去焦点的逻辑 }, handleClearNodeToEditor(columnName, rowIndex) { - const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + const refName = "contentEditor" + columnName + rowIndex; + const editor = this.editorRefs[refName]; if (!editor) return; - let nodeRef = "contentEditor" + columnName + rowIndex; - this.currenrActiveNodeRef = nodeRef; + this.currenrActiveNodeRef = refName; editor.innerHTML = ""; // 先清空内容 this.$forceUpdate(); @@ -2187,15 +2226,14 @@ export default { //添加节点 handleAddNodeToEditor(columnName, rowIndex) { - let nodeRef = "contentEditor" + columnName + rowIndex; - this.currenrActiveNodeRef = nodeRef; + const refName = "contentEditor" + columnName + rowIndex; + const editor = this.editorRefs[refName]; + if (!editor) return; + this.currenrActiveNodeRef = refName; this.representation = true; this.TestResultDisplayArea = false; this.representationActiveName = "first"; - // 这段代码的目的是 让光标停留在最后一个span标签后面 - const editor = this.$refs[this.currenrActiveNodeRef][0]; - if (!editor) return; // 创建 range 和 selection const range = document.createRange(); const selection = window.getSelection(); @@ -2221,7 +2259,7 @@ export default { insertToken(text, type) { if (!this.currenrActiveNodeRef) return; - const editor = this.$refs[this.currenrActiveNodeRef][0]; + const editor = this.editorRefs[this.currenrActiveNodeRef]; if (!editor) return; // 确保编辑器有焦点 @@ -2289,7 +2327,7 @@ export default { setCursorToEnd() { if (!this.currenrActiveNodeRef) return; - const editor = this.$refs[this.currenrActiveNodeRef][0]; + const editor = this.editorRefs[this.currenrActiveNodeRef]; if (!editor) return; const range = document.createRange(); @@ -2334,7 +2372,7 @@ export default { setCursorToEnd() { // 清除之前的选中状态 if (!this.currenrActiveNodeRef) return; - const editor = this.$refs[this.currenrActiveNodeRef][0]; + const editor = this.editorRefs[this.currenrActiveNodeRef]; if (!editor) return; const range = document.createRange(); @@ -2353,7 +2391,7 @@ export default { }, mounted() { // 绑定事件监听器 - const editor = this.$refs[this.currenrActiveNodeRef]?.[0]; + const editor = this.editorRefs[this.currenrActiveNodeRef]; if (editor) { editor.addEventListener("mouseup", this.saveRange); editor.addEventListener("keyup", this.saveRange); @@ -3304,6 +3342,33 @@ export default { ::v-deep .el-alert { padding: 10px !important; } + +.tabs { + display: flex; + align-items: center; + height: 32px; + background: #fff; + border-radius: 4px; + padding: 2px; + width: fit-content; + margin-top: 10px; + + .tabsItem { + height: 28px; + line-height: 28px; + background: #fff; + border-radius: 3px; + font-size: 14px; + color: #999; + padding: 0 10px; + cursor: pointer; + } + + .active { + background: #f5f5f5; + color: #333; + } +} diff --git a/src/views/LinkUp/compoment/viewDialogChunk.vue b/src/views/LinkUp/compoment/viewDialogChunk.vue index eeed1f3..b2b3c29 100644 --- a/src/views/LinkUp/compoment/viewDialogChunk.vue +++ b/src/views/LinkUp/compoment/viewDialogChunk.vue @@ -389,45 +389,34 @@ > - - - @@ -472,6 +461,38 @@ > + +
+ + + + +
+ +
+
+
+
+ + +
@@ -513,6 +534,70 @@ spanWidth="80px" > +
运行记录
+
+
+ 总记录 + {{ + OperationRecords.total ? OperationRecords.total : 0 + }} +
+
+ 运行成功 + {{ + OperationRecords.success ? OperationRecords.success : 0 + }} +
+
+ 运行失败 + + {{ + OperationRecords.error ? OperationRecords.error : 0 + }} +
+
+
+
关联账户
+
+
+
+ {{ item.accountName }} +
+
+
+ 验证成功 +
+
+ 验证失败 +
+
+ 未验证 +
+
+
+
@@ -529,8 +614,9 @@ import FishCrontab from "fish-crontab"; import * as echarts from "echarts"; import { authApi } from "@/api/apis/auth"; import baseForm from "@/components/base/baseNewForm"; +import EditorItem from "./EditorItem.vue"; export default { - components: { FishCrontab, baseRightDialog, baseForm }, + components: { FishCrontab, baseRightDialog, baseForm, EditorItem }, data() { return { examineOperateDialog: false, @@ -617,6 +703,19 @@ export default { rowNum: "1", pageLimit: "100", }, + + parameterType: "body", //参数类型 + + editorRefs: {}, // 用来保存所有子组件的 editor DOM + + // 运行记录 + OperationRecords: { + total: 0, + success: 0, + error: 0, + }, + OperationRecordsIndex: 2, + RelatedAccounts: [], //场景下关联的所有账户 }; }, methods: { @@ -638,6 +737,7 @@ export default { } this.formRowData = formRow; this.$refs.senceForm.choiceAssignment(formRow); + await this.GetSceneLog7Days(); await this.GetSceneStepList(); }); }, @@ -713,8 +813,14 @@ export default { // 更新当前选中的步骤索引 this.currentRowData = rowData; this.drawSelectIndex = index; + // 用来保存所有子组件的 editor DOM + this.editorRefs = {}; + this.parameterType = "body"; this.GetSceneStepData(); }, + registerEditorRef(refName, dom) { + this.$set(this.editorRefs, refName, dom); + }, /** * 获取场景步骤数据 */ @@ -759,10 +865,52 @@ export default { ) { this.queryColumns(); } + // 非数据库应用 + if ( + this.currentRowData.options.apiId && + this.currentRowData.options.appType != "9" + ) { + this.queryApiConfig(); + } }); } } }, + switchTabs(val) { + this.parameterType = val; + // 非数据库应用 + if (this.currentRowData.options.appType != "9") { + this.queryApiConfig("tab"); + } + }, + // 获取表字段 + async queryApiConfig(type) { + if (!this.currentRowData.options.apiId) { + return; + } + this.outsideColumns = []; + let params = { + stepId: this.currentRowData.options.stepID, //账户id + apiId: this.currentRowData.options.apiId, + type: this.parameterType, + }; + let res = await authApi( + "sysFlowStepApiConfigService", + "", + "queryApiConfig", + "", + params + ); + this.drawMask = false; + if (res.status == "200") { + this.outsideColumns = res.attribute || []; + this.$nextTick(() => { + if (type == "tab") { + this.getStepConfig(); + } + }); + } + }, // 获取表字段 async queryColumns() { this.outsideColumns = []; @@ -802,15 +950,29 @@ export default { params ); if (res.status == "200") { - const root = document.querySelector("#editorContainer"); + let detailList = []; if ( - res.attribute && - res.attribute.detailList && - res.attribute.detailList.length > 0 + this.currentRowData.options.appType && + this.currentRowData.options.appType == "9" ) { - res.attribute.detailList.forEach((item) => { - this.matchEditorItems(root, item.fieldName, item.html_label); - }); + detailList = res.attribute?.detailList || []; + } else { + if (this.parameterType == "body") { + detailList = res.attribute?.bodyIn + ? JSON.parse(res.attribute.bodyIn) + : []; + } else if (this.parameterType == "header") { + detailList = res.attribute?.headerIn + ? JSON.parse(res.attribute.headerIn) + : []; + } else if (this.parameterType == "query") { + detailList = res.attribute?.queryIn + ? JSON.parse(res.attribute.queryIn) + : []; + } + } + if (detailList.length > 0) { + this.recursivelyApplyHtmlLabel(this.outsideColumns, detailList); } if ( this.currentRowData.options && @@ -822,16 +984,93 @@ export default { } } }, - matchEditorItems(rootElement, rootName, rootHtml) { - const items = rootElement.querySelectorAll(".editorItem"); - items.forEach((item) => { - const fieldName = - item.querySelector(".el-form-item__label")?.innerText.trim() || ""; - const editor = item.querySelector(".content-editor"); - if (!editor) return; - if (rootName == fieldName) { - editor.innerHTML = rootHtml; + // 匹配数据 + recursivelyApplyHtmlLabel(columns, detailList, path = []) { + columns.forEach((col, index) => { + const match = detailList.find( + (item) => item.fieldName === col.column_name + ); + if (match && match.html_label) { + this.matchEditorItems(match, index, path); } + if ( + col.children && + col.children.length > 0 && + match.children && + match.children.length > 0 + ) { + this.recursivelyApplyHtmlLabel(col.children, match.children, [ + ...path, + index, + ]); + } + }); + }, + // 回显 + matchEditorItems(match, index, path = []) { + const refName = + "contentEditor" + match.fieldName + [...path, index].join("-"); + // 这里获取ref + const refEl = this.editorRefs[refName]; + if (match && match.html_label && refEl) { + // 可能refEl是数组,取第一个元素 + if (Array.isArray(refEl)) { + refEl[0].innerHTML = match.html_label; + } else if (refEl instanceof HTMLElement) { + refEl.innerHTML = match.html_label; + } + } + }, + // 场景记录改变 + RecordsChange(type) { + this.OperationRecordsIndex = type; + }, + // 获取最近7天运行统计 + async GetSceneLog7Days() { + // let params = { + // sceneID: this.sceneID, + // isSuccess: this.flagRecordsIndex, + // }; + // if (this.flagRecordsIndex == 2) { + // params.isSuccess = ""; + // } + // let res = await GetSceneLog7Days(params); + // if (res.code == 1) { + let data = []; + let xData = []; + let yData = []; + data.forEach((item) => { + xData.push(item.column1); + yData.push(item.allCount); + }); + this.renderChart(yData, xData); + // } + }, + renderChart(data = [], xData = []) { + const option = { + tooltip: { + trigger: "axis", + }, + xAxis: { + type: "category", + data: xData, + }, + yAxis: { + type: "value", + }, + series: [ + { + name: "", + type: "line", + data: data, + }, + ], + }; + this.$nextTick(() => { + const chartContainer = document.getElementById("overProjectChart"); + const chart = echarts.init(chartContainer); + this.chartData = chart; + chart.setOption(option); }); }, // 发布场景 @@ -1762,4 +2001,39 @@ export default { ::v-deep .el-form-item { margin-bottom: 0; } + +.tabs { + display: flex; + align-items: center; + height: 32px; + background: #fff; + border-radius: 4px; + padding: 2px; + width: fit-content; + margin: 10px 0; + + .tabsItem { + height: 28px; + line-height: 28px; + background: #fff; + border-radius: 3px; + font-size: 14px; + color: #999; + padding: 0 10px; + cursor: pointer; + } + + .active { + background: #f5f5f5; + color: #333; + } +} +::v-deep .el-collapse-item__header { + padding-left: 10px !important; +} +.pie { + height: 300px; + padding-bottom: 10px; +} +