场景中心代码迭代

This commit is contained in:
caorui 2025-08-01 14:59:22 +08:00
parent 583759c70b
commit 86a6a25bf3
3 changed files with 975 additions and 221 deletions

View File

@ -0,0 +1,415 @@
<template>
<div class="editorItem">
<el-form-item>
<div class="editor-header" :style="indentStyle">
<span
v-if="row.children && row.children.length > 0"
class="toggle-btn"
@click="toggleCollapse"
>
<i
:class="
isCollapsed ? 'el-icon-caret-right' : 'el-icon-caret-bottom'
"
></i>
</span>
<span class="column-title"
>{{ row.column_name }}
<span style="font-size: 12px; margin-left: 5px; font-weight: bold">{{
row.column_comment
}}</span></span
>
</div>
<div class="editor-container" :style="indentStyle">
<div
class="content-editor"
:ref="'contentEditor' + row.column_name + rowIndex"
:contenteditable="!viewFlag"
@keydown="handleKeyDown($event, row.column_name, rowIndex)"
@input="handleInput($event, row.column_name, rowIndex)"
@click="handleEditorClick($event, row.column_name, rowIndex)"
@paste="handlePaste($event, row.column_name, rowIndex)"
@focus="handleEditorFocus($event, row.column_name, rowIndex)"
@blur="handleEditorBlur($event, row.column_name, rowIndex)"
></div>
<div
v-if="!viewFlag"
class="editorIcon"
@click.stop="handleAddNodeToEditor(row.column_name, rowIndex)"
>
<i class="el-icon-circle-plus"></i>
</div>
<div
v-if="!viewFlag"
class="clearIcon"
@click.stop="handleClearNodeToEditor(row.column_name, rowIndex)"
>
<i class="el-icon-circle-close"></i>
</div>
</div>
</el-form-item>
<!-- 子项只有在展开时才显示 -->
<EditorItem
v-if="!isCollapsed"
v-for="(child, index) in row.children"
:key="index"
:row="child"
:row-index="`${rowIndex}-${index}`"
v-bind="$attrs"
v-on="$listeners"
ref="childEditors"
ref-in-for
:viewFlag="viewFlag"
/>
</div>
</template>
<script>
export default {
name: "EditorItem",
props: {
row: Object,
rowIndex: [String, Number],
viewFlag: {
type: Boolean,
default: false,
},
},
data() {
return {
isCollapsed: false,
};
},
computed: {
indentLevel() {
return String(this.rowIndex).split("-").length - 1;
},
indentStyle() {
return {
paddingLeft: this.indentLevel * 20 + "px",
};
},
},
mounted() {
this.$nextTick(() => {
const refName = "contentEditor" + this.row.column_name + this.rowIndex;
const editor = this.$refs[refName];
// editor DOM undefined/
if (Array.isArray(editor)) {
if (editor.length > 0) {
this.$emit("register-editor", refName, editor[0]);
}
} else if (editor) {
this.$emit("register-editor", refName, editor);
}
});
},
methods: {
//
getEditorContent() {
// DOM
const refName = "contentEditor" + this.row.column_name + this.rowIndex;
const editor = this.$refs[refName];
//
let html_label = "";
let whereCondition = "";
if (editor) {
html_label = editor.innerHTML.trim();
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, ")");
}
//
let children = [];
if (this.$refs.childEditors && this.$refs.childEditors.length > 0) {
children = this.$refs.childEditors.map((childComp) =>
childComp.getEditorContent()
);
}
return {
character_maximum_length: this.row.character_maximum_length,
column_comment: this.row.column_comment,
column_name: this.row.column_name,
data_type: this.row.data_type,
html_label: this.row.html_label,
is_nullable: this.row.is_nullable,
fieldName: this.row.column_name,
whereCondition,
html_label,
children,
};
},
toggleCollapse() {
this.isCollapsed = !this.isCollapsed;
},
//
handleKeyDown(e, columnName, rowIndex) {
this.$emit("handle-keydown", e, columnName, rowIndex);
},
handleInput(e, columnName, rowIndex) {
this.$emit("handle-input", e, columnName, rowIndex);
},
handleEditorClick(e, columnName, rowIndex) {
this.$emit("handle-editor-click", e, columnName, rowIndex);
},
handlePaste(e, columnName, rowIndex) {
this.$emit("handle-paste", e, columnName, rowIndex);
},
handleEditorFocus(e, columnName, rowIndex) {
this.$emit("handle-editor-focus", e, columnName, rowIndex);
},
handleEditorBlur(e, columnName, rowIndex) {
this.$emit("handle-editor-blur", e, columnName, rowIndex);
},
handleAddNodeToEditor(columnName, rowIndex) {
this.$emit("handle-add-node", columnName, rowIndex);
},
handleClearNodeToEditor(columnName, rowIndex) {
this.$emit("handle-clear-node", columnName, rowIndex);
},
},
components: {
EditorItem: () => import("./EditorItem.vue"),
},
};
</script>
<style lang="scss" scoped>
// ------------------------
.editor-container {
flex: 1;
overflow: hidden;
position: relative;
}
.editorIcon {
position: absolute;
right: 10px;
top: 0;
font-size: 20px;
color: #999999;
}
.clearIcon {
display: none;
position: absolute;
top: 0;
right: 35px;
font-size: 20px;
color: #999999;
}
.editor-container:hover .clearIcon {
display: block;
}
/* hover 时显示 close-icon */
.editor-container:hover .close-icon {
display: inline-flex; /* 或 block根据你的布局 */
}
.content-editor {
border: 1px solid #e5e7eb;
border-radius: 4px;
min-height: 40px;
padding: 0 50px 0 10px;
background: #fff;
position: relative;
font-size: 12px;
// line-height: 1.6;
overflow-y: auto;
outline: none;
word-wrap: break-word;
}
.content-editor:focus {
border-color: #409eff;
}
.content-editor:empty:before {
content: attr(data-placeholder);
color: #9ca3af;
font-style: italic;
pointer-events: none;
}
.content-editor:focus:empty:before {
content: "";
}
/* 确保空编辑器也能显示光标 */
.content-editor:empty {
min-height: 40px;
}
.content-editor:focus {
outline: none;
}
// --------------------------------
::v-deep .content-token {
display: unset !important;
padding: 3px 4px !important;
border-radius: 3px;
margin: 0 2px !important;
cursor: pointer;
transition: all 0.2s ease;
vertical-align: middle;
font-size: 12px;
font-weight: 500;
user-select: none;
}
::v-deep .token-function {
background: #ecfdf5;
color: #047857;
border: 1px solid #10b981;
}
::v-deep .repContainer {
width: 100%;
height: 100%;
background: #f5f5f5;
padding: 10px;
position: relative;
}
.treeNodeBox {
height: calc(100% - 50px);
overflow-y: auto;
}
.closeRepContainer {
position: absolute;
top: 20px;
right: 12px;
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
i {
margin-right: 5px;
}
}
.closeRepContainer:hover {
color: #409eff;
}
.repItem {
display: flex;
align-items: center;
margin-bottom: 8px;
cursor: pointer;
}
.repItem:hover .repItemValue {
color: #409eff;
}
.repItemValue {
color: #6b7280;
font-size: 13px;
margin-left: 10px;
}
.token-editable-content {
display: inline-block;
min-width: 1em;
padding: 0 2px;
border-bottom: 1px dashed #aaa;
cursor: text;
outline: none;
}
::v-deep .content-token.token-edit {
display: inline-flex !important;
color: #5b21b6;
font-weight: bold;
padding: 0;
}
.Columnsbtn {
margin: 10px 0;
display: flex;
justify-content: flex-end;
}
.fixedChildTable {
height: calc(100vh - 360px);
overflow: auto;
}
.drawParent {
position: relative;
}
.TestResultDisplayArea {
width: 400px;
height: calc(100% - 10px);
position: absolute;
right: 10px;
top: 5px;
background-color: #fff;
box-sizing: border-box;
box-shadow: 0 0 8px #0000001a;
border-radius: 4px;
z-index: 100;
overflow: hidden;
}
.testResultBoxTitle {
display: flex;
padding: 15px 10px;
background: #333333;
font-size: 14px;
font-weight: bold;
color: #fff;
justify-content: space-between;
border-radius: 4px 4px 0 0;
.closeTextBox {
cursor: pointer;
}
}
.jsonTestResultBox {
height: calc(100% - 90px);
overflow: auto;
}
::v-deep .el-alert {
padding: 10px !important;
}
.editor-header {
display: flex;
align-items: center;
margin-bottom: 5px;
font-weight: 500;
}
.toggle-btn {
cursor: pointer;
margin-right: 8px;
color: #606266;
font-size: 14px;
}
.column-title {
font-size: 14px;
color: #333;
display: flex;
font-weight: bold;
}
</style>

View File

@ -575,6 +575,35 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div
class="tabs"
v-if="
currentRowData.options &&
currentRowData.options.appType != '9'
"
>
<div
class="tabsItem"
:class="{ active: parameterType === 'header' }"
@click="switchTabs('header')"
>
Headers入参
</div>
<div
class="tabsItem"
:class="{ active: parameterType === 'query' }"
@click="switchTabs('query')"
>
Query入参
</div>
<div
class="tabsItem"
:class="{ active: parameterType === 'body' }"
@click="switchTabs('body')"
>
Body入参
</div>
</div>
<div class="Columnsbtn" v-if="outsideColumns.length > 0"> <div class="Columnsbtn" v-if="outsideColumns.length > 0">
<el-button @click="saveTestTableEvent">暂存</el-button> <el-button @click="saveTestTableEvent">暂存</el-button>
<el-button @click="saveTestTableEvent('hit')" <el-button @click="saveTestTableEvent('hit')"
@ -617,91 +646,29 @@
style="margin: 0 10px" style="margin: 0 10px"
> >
<div id="editorContainer"> <div id="editorContainer">
<div <EditorItem
v-for="(row, rowIndex) in outsideColumns" v-for="(row, index) in outsideColumns"
:key="rowIndex" :key="index"
class="editorItem" :row="row"
> :row-index="index"
<el-form-item :label="row.column_name"> @register-editor="registerEditorRef"
<div class="editor-container"> @handle-keydown="handleKeyDown"
<div @handle-input="handleInput"
class="content-editor" @handle-editor-click="handleEditorClick"
:ref=" @handle-paste="handlePaste"
'contentEditor' + row.column_name + rowIndex @handle-editor-focus="handleEditorFocus"
" @handle-editor-blur="handleEditorBlur"
contenteditable="true" @handle-add-node="handleAddNodeToEditor"
@keydown=" @handle-clear-node="handleClearNodeToEditor"
handleKeyDown( ref="editorRefs"
$event, ref-in-for
row.column_name, />
rowIndex
)
"
@input="
handleInput(
$event,
row.column_name,
rowIndex
)
"
@click="
handleEditorClick(
$event,
row.column_name,
rowIndex
)
"
@paste="
handlePaste(
$event,
row.column_name,
rowIndex
)
"
@focus="
handleEditorFocus(
$event,
row.column_name,
rowIndex
)
"
@blur="
handleEditorBlur(
$event,
row.column_name,
rowIndex
)
"
></div>
<div
class="editorIcon"
@click.stop="
handleAddNodeToEditor(
row.column_name,
rowIndex
)
"
>
<i class="el-icon-circle-plus"></i>
</div>
<div
class="clearIcon"
@click.stop="
handleClearNodeToEditor(
row.column_name,
rowIndex
)
"
>
<i class="el-icon-circle-close"></i>
</div>
</div>
</el-form-item>
</div>
</div> </div>
</el-form> </el-form>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<el-empty v-else description="暂无数据"></el-empty>
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
@ -732,6 +699,7 @@ import baseForm from "@/components/base/baseNewForm";
import treeNode from "./TreeNode"; import treeNode from "./TreeNode";
import IconsDialog from "../../tool/build/IconsDialog.vue"; import IconsDialog from "../../tool/build/IconsDialog.vue";
import jsonView from "vue-json-views"; import jsonView from "vue-json-views";
import EditorItem from "./EditorItem.vue";
export default { export default {
components: { components: {
editSence, editSence,
@ -742,6 +710,7 @@ export default {
treeNode, treeNode,
IconsDialog, IconsDialog,
jsonView, jsonView,
EditorItem,
}, },
data() { data() {
return { return {
@ -826,36 +795,61 @@ export default {
}, },
parameterType: "body", // parameterType: "body", //
editorRefs: {}, // editor DOM
}; };
}, },
methods: { methods: {
switchTabs(val) {
this.parameterType = val;
//
if (this.currentRowData.options.appType != "9") {
this.queryApiConfig("tab");
}
},
async saveTestTableEvent(type) { async saveTestTableEvent(type) {
if (!this.outsideFormData.tableName) { if (
this.currentRowData.options.appType == "9" &&
!this.outsideFormData.tableName
) {
this.$vmNews("请先选择表"); this.$vmNews("请先选择表");
return; return;
} }
this.openLoading("暂存"); this.openLoading("暂存");
// 使 HTML DOM // 使 HTML DOM
const root = document.querySelector("#editorContainer"); const parsed = this.extractEditorItems();
const parsed = this.extractEditorItems(root);
let data = this.currentRowData.options; let data = this.currentRowData.options;
let params = { let params = {};
if (data && data.appType == "9") {
params = {
detailList: parsed, detailList: parsed,
flowId: this.sceneID, flowId: this.sceneID,
stepID: data.stepID, stepID: data.stepID,
stepAccountId: data.step_acc_id, stepAccountId: data.step_acc_id,
actionName: data.apiName || data.plugName, actionName: data.apiName || data.plugName,
tableName: this.outsideFormData.tableName, tableName: this.outsideFormData.tableName,
appType: this.currentRowData.options.appType, appType: data.appType,
}; };
if ( if (data.apiName.includes("查询")) {
this.currentRowData.options &&
this.currentRowData.options.appType == "9" &&
this.currentRowData.options.apiName.includes("查询")
) {
params.rowNum = this.pageFormData.rowNum; params.rowNum = this.pageFormData.rowNum;
params.pageLimit = this.pageFormData.pageLimit; 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( let res = await authApi(
"sysFlowStepConfigService", "sysFlowStepConfigService",
@ -872,38 +866,18 @@ export default {
} }
} }
}, },
extractEditorItems(rootElement) { extractEditorItems() {
const result = []; if (!this.$refs.editorRefs) return [];
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;
const html_label = editor.innerHTML.trim(); // return this.$refs.editorRefs.map((editorComp) =>
editorComp.getEditorContent()
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;
}, },
async hitTesting() { async hitTesting() {
if (!this.outsideFormData.tableName) { if (
this.currentRowData.options.appType == "9" &&
!this.outsideFormData.tableName
) {
this.$vmNews("请先选择表"); this.$vmNews("请先选择表");
return; return;
} }
@ -913,7 +887,11 @@ export default {
let params = { let params = {
stepID: data.stepID, stepID: data.stepID,
tableName: this.outsideFormData.tableName, tableName: this.outsideFormData.tableName,
appType: this.currentRowData.options.appType,
}; };
if (this.currentRowData.options.appType == "9") {
delete params.tableName;
}
let res = await authApi( let res = await authApi(
"sysFlowStepConfigService", "sysFlowStepConfigService",
"", "",
@ -1169,6 +1147,9 @@ export default {
this.apiIDActiv = ""; this.apiIDActiv = "";
this.userActivId = ""; this.userActivId = "";
this.CurrentAppRow = {}; this.CurrentAppRow = {};
// editor DOM
this.editorRefs = {};
this.parameterType= "body"
if (index === 0) { if (index === 0) {
this.activeTabName = "选择操作"; this.activeTabName = "选择操作";
@ -1443,6 +1424,13 @@ export default {
) { ) {
this.queryColumns(this.outsideFormData.tableName); 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) { if (!this.currentRowData.options.apiId) {
return; return;
} }
@ -1700,7 +1688,9 @@ export default {
if (res.status == "200") { if (res.status == "200") {
this.outsideColumns = res.attribute || []; this.outsideColumns = res.attribute || [];
this.$nextTick(() => { this.$nextTick(() => {
// this.getStepConfig(); if (type == "tab") {
this.getStepConfig();
}
}); });
} }
}, },
@ -1876,15 +1866,29 @@ export default {
params params
); );
if (res.status == "200") { if (res.status == "200") {
const root = document.querySelector("#editorContainer"); let detailList = [];
if ( if (
res.attribute && this.currentRowData.options.appType &&
res.attribute.detailList && this.currentRowData.options.appType == "9"
res.attribute.detailList.length > 0
) { ) {
res.attribute.detailList.forEach((item) => { detailList = res.attribute?.detailList || [];
this.matchEditorItems(root, item.fieldName, item.html_label); } 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 ( if (
this.currentRowData.options && this.currentRowData.options &&
@ -1896,18 +1900,43 @@ export default {
} }
} }
}, },
matchEditorItems(rootElement, rootName, rootHtml) { //
const items = rootElement.querySelectorAll(".editorItem"); recursivelyApplyHtmlLabel(columns, detailList, path = []) {
items.forEach((item) => { columns.forEach((col, index) => {
const fieldName = const match = detailList.find(
item.querySelector(".el-form-item__label")?.innerText.trim() || ""; (item) => item.fieldName === col.column_name
const editor = item.querySelector(".content-editor"); );
if (!editor) return; if (match && match.html_label) {
if (rootName == fieldName) { this.matchEditorItems(match, index, path);
editor.innerHTML = rootHtml; }
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 * @param {string} appId 应用 ID
@ -2066,9 +2095,13 @@ export default {
pageLimit: "100", pageLimit: "100",
}; };
}, },
registerEditorRef(refName, dom) {
this.$set(this.editorRefs, refName, dom);
},
representationChange() { representationChange() {
if (!this.currenrActiveNodeRef) return; if (!this.currenrActiveNodeRef) return;
const editor = this.$refs[this.currenrActiveNodeRef][0]; const editor = this.editorRefs[this.currenrActiveNodeRef];
if (!editor) return; if (!editor) return;
// range selection // range selection
const range = document.createRange(); const range = document.createRange();
@ -2085,8 +2118,9 @@ export default {
this.saveRange(); this.saveRange();
}, },
handleKeyDown(e, columnName, rowIndex) { 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") { if (e.key === "Backspace") {
// token // token
const selection = window.getSelection(); const selection = window.getSelection();
@ -2123,8 +2157,10 @@ export default {
}, },
// //
handleEditorClick(e, columnName, rowIndex) { handleEditorClick(e, columnName, rowIndex) {
const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; const refName = "contentEditor" + columnName + rowIndex;
this.currenrActiveNodeRef = "contentEditor" + columnName + rowIndex; const editor = this.editorRefs[refName];
if (!editor) return;
this.currenrActiveNodeRef = refName;
editor.focus(); editor.focus();
this.saveRange(); this.saveRange();
}, },
@ -2135,7 +2171,9 @@ export default {
}, },
// //
handleEditorFocus(e, columnName, rowIndex) { 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)) { if (this.isEmpty(columnName, rowIndex)) {
setTimeout(() => { setTimeout(() => {
@ -2150,7 +2188,8 @@ export default {
}, },
// //
isEmpty(columnName, rowIndex) { 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; if (!editor) return true;
const content = editor.textContent.trim(); const content = editor.textContent.trim();
const hasTokens = editor.querySelectorAll(".content-token").length > 0; const hasTokens = editor.querySelectorAll(".content-token").length > 0;
@ -2161,10 +2200,10 @@ export default {
// //
}, },
handleClearNodeToEditor(columnName, rowIndex) { handleClearNodeToEditor(columnName, rowIndex) {
const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; const refName = "contentEditor" + columnName + rowIndex;
const editor = this.editorRefs[refName];
if (!editor) return; if (!editor) return;
let nodeRef = "contentEditor" + columnName + rowIndex; this.currenrActiveNodeRef = refName;
this.currenrActiveNodeRef = nodeRef;
editor.innerHTML = ""; // editor.innerHTML = ""; //
this.$forceUpdate(); this.$forceUpdate();
@ -2187,15 +2226,14 @@ export default {
// //
handleAddNodeToEditor(columnName, rowIndex) { handleAddNodeToEditor(columnName, rowIndex) {
let nodeRef = "contentEditor" + columnName + rowIndex; const refName = "contentEditor" + columnName + rowIndex;
this.currenrActiveNodeRef = nodeRef; const editor = this.editorRefs[refName];
if (!editor) return;
this.currenrActiveNodeRef = refName;
this.representation = true; this.representation = true;
this.TestResultDisplayArea = false; this.TestResultDisplayArea = false;
this.representationActiveName = "first"; this.representationActiveName = "first";
// span
const editor = this.$refs[this.currenrActiveNodeRef][0];
if (!editor) return;
// range selection // range selection
const range = document.createRange(); const range = document.createRange();
const selection = window.getSelection(); const selection = window.getSelection();
@ -2221,7 +2259,7 @@ export default {
insertToken(text, type) { insertToken(text, type) {
if (!this.currenrActiveNodeRef) return; if (!this.currenrActiveNodeRef) return;
const editor = this.$refs[this.currenrActiveNodeRef][0]; const editor = this.editorRefs[this.currenrActiveNodeRef];
if (!editor) return; if (!editor) return;
// //
@ -2289,7 +2327,7 @@ export default {
setCursorToEnd() { setCursorToEnd() {
if (!this.currenrActiveNodeRef) return; if (!this.currenrActiveNodeRef) return;
const editor = this.$refs[this.currenrActiveNodeRef][0]; const editor = this.editorRefs[this.currenrActiveNodeRef];
if (!editor) return; if (!editor) return;
const range = document.createRange(); const range = document.createRange();
@ -2334,7 +2372,7 @@ export default {
setCursorToEnd() { setCursorToEnd() {
// //
if (!this.currenrActiveNodeRef) return; if (!this.currenrActiveNodeRef) return;
const editor = this.$refs[this.currenrActiveNodeRef][0]; const editor = this.editorRefs[this.currenrActiveNodeRef];
if (!editor) return; if (!editor) return;
const range = document.createRange(); const range = document.createRange();
@ -2353,7 +2391,7 @@ export default {
}, },
mounted() { mounted() {
// //
const editor = this.$refs[this.currenrActiveNodeRef]?.[0]; const editor = this.editorRefs[this.currenrActiveNodeRef];
if (editor) { if (editor) {
editor.addEventListener("mouseup", this.saveRange); editor.addEventListener("mouseup", this.saveRange);
editor.addEventListener("keyup", this.saveRange); editor.addEventListener("keyup", this.saveRange);
@ -3304,6 +3342,33 @@ export default {
::v-deep .el-alert { ::v-deep .el-alert {
padding: 10px !important; 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;
}
}
</style> </style>

View File

@ -389,45 +389,34 @@
></el-input> ></el-input>
</div> </div>
</template> </template>
<template
<!-- 字段 --> v-if="
<template> currentRowData.options &&
<div class="fixedChildTable"> currentRowData.options.appType != '9'
<el-collapse
v-model="activeNames"
v-if="outsideColumns.length > 0"
>
<el-collapse-item title="查询条件配置" name="1">
<el-form
ref="ColumnsForm"
label-width="80px"
label-position="top"
style="margin: 0 10px"
>
<div id="editorContainer">
<div
v-for="(row, rowIndex) in outsideColumns"
:key="rowIndex"
class="editorItem"
>
<el-form-item :label="row.column_name">
<div class="editor-container">
<div
class="content-editor"
:ref="
'contentEditor' +
row.column_name +
rowIndex
" "
contenteditable="true" >
></div> <div class="tabs">
<div
class="tabsItem"
:class="{ active: parameterType === 'header' }"
@click="switchTabs('header')"
>
Headers入参
</div> </div>
</el-form-item> <div
class="tabsItem"
:class="{ active: parameterType === 'query' }"
@click="switchTabs('query')"
>
Query入参
</div> </div>
<div
class="tabsItem"
:class="{ active: parameterType === 'body' }"
@click="switchTabs('body')"
>
Body入参
</div> </div>
</el-form>
</el-collapse-item>
</el-collapse>
</div> </div>
</template> </template>
@ -472,6 +461,38 @@
></el-input> ></el-input>
</div> </div>
</template> </template>
<!-- 表字段展示 -->
<div class="fixedChildTable">
<!-- 表字段 -->
<el-collapse
v-model="activeNames"
v-if="outsideColumns.length > 0"
>
<el-collapse-item title="查询条件配置" name="1">
<el-form
ref="ColumnsForm"
label-width="80px"
label-position="top"
style="margin: 0 10px"
>
<div id="editorContainer">
<EditorItem
v-for="(row, index) in outsideColumns"
:key="index"
:row="row"
:row-index="index"
@register-editor="registerEditorRef"
ref="editorRefs"
ref-in-for
:viewFlag="true"
/>
</div>
</el-form>
</el-collapse-item>
</el-collapse>
<el-empty v-else description="暂无数据"></el-empty>
</div>
</template> </template>
</div> </div>
<!-- 操作展示 End --> <!-- 操作展示 End -->
@ -513,6 +534,70 @@
spanWidth="80px" spanWidth="80px"
> >
</base-form> </base-form>
<div class="globelTitle">运行记录</div>
<div class="OperationRecords">
<div
class="totalItem"
:class="OperationRecordsIndex == 2 ? 'active' : ''"
@click="RecordsChange(2)"
>
<span>总记录</span>
<span>{{
OperationRecords.total ? OperationRecords.total : 0
}}</span>
</div>
<div
class="totalItem"
:class="OperationRecordsIndex == 1 ? 'active' : ''"
@click="RecordsChange(1)"
>
<span>运行成功</span>
<span style="color: #00d104">{{
OperationRecords.success ? OperationRecords.success : 0
}}</span>
</div>
<div
class="totalItem"
:class="OperationRecordsIndex == 0 ? 'active' : ''"
@click="RecordsChange(0)"
>
<span>运行失败</span>
<span style="color: #fa0101">
{{
OperationRecords.error ? OperationRecords.error : 0
}}</span
>
</div>
</div>
<div id="overProjectChart" class="pie"></div>
<div class="globelTitle">关联账户</div>
<div
class="userContentBox"
v-for="(item, index) in RelatedAccounts"
>
<div class="userItem">
<div class="userName">
{{ item.accountName }}
</div>
<div class="status">
<div
v-if="item.authenticationState == 1"
class="successBox"
>
验证成功
</div>
<div
v-else-if="item.authenticationState == 2"
class="redBox"
>
验证失败
</div>
<div v-else="!item.authenticationState" class="redBox">
未验证
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
@ -529,8 +614,9 @@ import FishCrontab from "fish-crontab";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { authApi } from "@/api/apis/auth"; import { authApi } from "@/api/apis/auth";
import baseForm from "@/components/base/baseNewForm"; import baseForm from "@/components/base/baseNewForm";
import EditorItem from "./EditorItem.vue";
export default { export default {
components: { FishCrontab, baseRightDialog, baseForm }, components: { FishCrontab, baseRightDialog, baseForm, EditorItem },
data() { data() {
return { return {
examineOperateDialog: false, examineOperateDialog: false,
@ -617,6 +703,19 @@ export default {
rowNum: "1", rowNum: "1",
pageLimit: "100", pageLimit: "100",
}, },
parameterType: "body", //
editorRefs: {}, // editor DOM
//
OperationRecords: {
total: 0,
success: 0,
error: 0,
},
OperationRecordsIndex: 2,
RelatedAccounts: [], //
}; };
}, },
methods: { methods: {
@ -638,6 +737,7 @@ export default {
} }
this.formRowData = formRow; this.formRowData = formRow;
this.$refs.senceForm.choiceAssignment(formRow); this.$refs.senceForm.choiceAssignment(formRow);
await this.GetSceneLog7Days();
await this.GetSceneStepList(); await this.GetSceneStepList();
}); });
}, },
@ -713,8 +813,14 @@ export default {
// //
this.currentRowData = rowData; this.currentRowData = rowData;
this.drawSelectIndex = index; this.drawSelectIndex = index;
// editor DOM
this.editorRefs = {};
this.parameterType = "body";
this.GetSceneStepData(); this.GetSceneStepData();
}, },
registerEditorRef(refName, dom) {
this.$set(this.editorRefs, refName, dom);
},
/** /**
* 获取场景步骤数据 * 获取场景步骤数据
*/ */
@ -759,10 +865,52 @@ export default {
) { ) {
this.queryColumns(); 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() { async queryColumns() {
this.outsideColumns = []; this.outsideColumns = [];
@ -802,15 +950,29 @@ export default {
params params
); );
if (res.status == "200") { if (res.status == "200") {
const root = document.querySelector("#editorContainer"); let detailList = [];
if ( if (
res.attribute && this.currentRowData.options.appType &&
res.attribute.detailList && this.currentRowData.options.appType == "9"
res.attribute.detailList.length > 0
) { ) {
res.attribute.detailList.forEach((item) => { detailList = res.attribute?.detailList || [];
this.matchEditorItems(root, item.fieldName, item.html_label); } 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 ( if (
this.currentRowData.options && this.currentRowData.options &&
@ -822,16 +984,93 @@ export default {
} }
} }
}, },
matchEditorItems(rootElement, rootName, rootHtml) { //
const items = rootElement.querySelectorAll(".editorItem"); recursivelyApplyHtmlLabel(columns, detailList, path = []) {
items.forEach((item) => { columns.forEach((col, index) => {
const fieldName = const match = detailList.find(
item.querySelector(".el-form-item__label")?.innerText.trim() || ""; (item) => item.fieldName === col.column_name
const editor = item.querySelector(".content-editor"); );
if (!editor) return; if (match && match.html_label) {
if (rootName == fieldName) { this.matchEditorItems(match, index, path);
editor.innerHTML = rootHtml;
} }
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 { ::v-deep .el-form-item {
margin-bottom: 0; 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;
}
</style> </style>