场景中心动态配置
This commit is contained in:
parent
66427493fc
commit
f81a35c10e
|
@ -129,7 +129,10 @@
|
|||
v-show="representation"
|
||||
>
|
||||
<div class="repContainer">
|
||||
<el-tabs v-model="representationActiveName">
|
||||
<el-tabs
|
||||
v-model="representationActiveName"
|
||||
@tab-click="representationChange"
|
||||
>
|
||||
<el-tab-pane label="动态内容" name="first"></el-tab-pane>
|
||||
<el-tab-pane label="表达式" name="second"></el-tab-pane>
|
||||
</el-tabs>
|
||||
|
@ -551,10 +554,11 @@
|
|||
label-position="top"
|
||||
style="margin: 0 10px"
|
||||
>
|
||||
<div ref="editorContainer">
|
||||
<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">
|
||||
|
@ -628,6 +632,10 @@
|
|||
</el-form>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<div>
|
||||
<el-button @click="HitTesting">点击测试</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
@ -772,11 +780,69 @@ export default {
|
|||
},
|
||||
currenrActiveNodeRef: "",
|
||||
lastSelectedTokenIndex: -1,
|
||||
tokenCounter: 0,
|
||||
representationData: representationData,
|
||||
savedRange: null, // ⬅️ 用于存储当前 range
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async HitTesting() {
|
||||
this.openLoading("处理");
|
||||
// 使用示例:传入你这段 HTML 所在的 DOM 根节点
|
||||
const root = document.querySelector("#editorContainer");
|
||||
const parsed = this.extractEditorItems(root);
|
||||
let data = this.drawShowList[this.drawSelectIndex].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,
|
||||
};
|
||||
let res = await authApi(
|
||||
"sysFlowStepConfigService",
|
||||
"",
|
||||
"saveOrUpdateConfig",
|
||||
"",
|
||||
params
|
||||
);
|
||||
if (res.status == "200") {
|
||||
this.$vmNews("测试成功!", "success");
|
||||
}
|
||||
},
|
||||
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;
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
* @param {string} sceneID 场景 ID
|
||||
|
@ -1592,10 +1658,20 @@ export default {
|
|||
}
|
||||
},
|
||||
// 切换表时
|
||||
outsideSelectChange(val) {
|
||||
async outsideSelectChange(val) {
|
||||
if (val) {
|
||||
this.outsideColumns = [];
|
||||
this.queryColumns(val);
|
||||
// 更新当前步骤的步骤描述
|
||||
this.drawShowList[this.drawSelectIndex].options.description =
|
||||
this.description;
|
||||
let params = {
|
||||
flowId: this.sceneID,
|
||||
id: this.drawShowList[this.drawSelectIndex].options.stepID,
|
||||
tableName: val,
|
||||
};
|
||||
// 保存场景步骤数据
|
||||
await this.SaveSceneStepData(params);
|
||||
await this.queryColumns(val);
|
||||
}
|
||||
},
|
||||
// 获取表字段
|
||||
|
@ -1773,7 +1849,24 @@ export default {
|
|||
this.userList = [];
|
||||
this.representation = false;
|
||||
},
|
||||
representationChange() {
|
||||
if (!this.currenrActiveNodeRef) return;
|
||||
const editor = this.$refs[this.currenrActiveNodeRef][0];
|
||||
if (!editor) return;
|
||||
// 创建 range 和 selection
|
||||
const range = document.createRange();
|
||||
const selection = window.getSelection();
|
||||
|
||||
// 将 range 定位到 editor 的最后一个子节点
|
||||
range.selectNodeContents(editor);
|
||||
range.collapse(false); // 折叠到末尾
|
||||
// 清空现有选区并设置新 range
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
// 确保编辑器有焦点
|
||||
editor.focus();
|
||||
this.saveRange();
|
||||
},
|
||||
handleKeyDown(e, columnName, rowIndex) {
|
||||
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
||||
|
||||
|
@ -1799,20 +1892,6 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清除token选中状态(除了特殊键)
|
||||
if (
|
||||
![
|
||||
"Backspace",
|
||||
"Delete",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"ArrowUp",
|
||||
"ArrowDown",
|
||||
].includes(e.key)
|
||||
) {
|
||||
this.clearTokenSelection(columnName, rowIndex);
|
||||
}
|
||||
},
|
||||
// 清除token选中状态
|
||||
clearTokenSelection(columnName, rowIndex) {
|
||||
|
@ -1822,29 +1901,27 @@ export default {
|
|||
},
|
||||
// 处理输入事件
|
||||
handleInput(e, columnName, rowIndex) {
|
||||
// 清除token选中状态
|
||||
this.clearTokenSelection(columnName, rowIndex);
|
||||
|
||||
// 强制更新computed属性
|
||||
this.$forceUpdate();
|
||||
// this.clearTokenSelection(columnName, rowIndex);
|
||||
this.saveRange();
|
||||
},
|
||||
// 处理编辑器点击
|
||||
handleEditorClick(e, columnName, rowIndex) {
|
||||
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
||||
this.currenrActiveNodeRef = "contentEditor" + columnName + rowIndex;
|
||||
|
||||
// 如果点击的不是token,清除选中状态
|
||||
if (
|
||||
!e.target.classList.contains("content-token") &&
|
||||
!e.target.closest(".content-token")
|
||||
) {
|
||||
this.clearTokenSelection(columnName, rowIndex);
|
||||
}
|
||||
// // 如果点击的不是token,清除选中状态
|
||||
// if (
|
||||
// !e.target.classList.contains("content-token") &&
|
||||
// !e.target.closest(".content-token")
|
||||
// ) {
|
||||
// this.clearTokenSelection(columnName, rowIndex);
|
||||
// }
|
||||
|
||||
// 确保编辑器获得焦点
|
||||
if (e.target === editor || editor.contains(e.target)) {
|
||||
editor.focus();
|
||||
}
|
||||
// // 确保编辑器获得焦点
|
||||
// if (e.target === editor || editor.contains(e.target)) {
|
||||
editor.focus();
|
||||
this.saveRange();
|
||||
// }
|
||||
},
|
||||
// 处理粘贴事件
|
||||
handlePaste(e, columnName, rowIndex) {
|
||||
|
@ -1854,7 +1931,6 @@ export default {
|
|||
// 处理编辑器获得焦点
|
||||
handleEditorFocus(e, columnName, rowIndex) {
|
||||
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
||||
|
||||
// 如果编辑器为空,设置光标到开始位置
|
||||
if (this.isEmpty(columnName, rowIndex)) {
|
||||
setTimeout(() => {
|
||||
|
@ -1900,6 +1976,7 @@ export default {
|
|||
selection.addRange(range);
|
||||
// 确保编辑器有焦点
|
||||
editor.focus();
|
||||
this.saveRange();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1925,13 +2002,14 @@ export default {
|
|||
selection.addRange(range);
|
||||
// 确保编辑器有焦点
|
||||
editor.focus();
|
||||
this.saveRange();
|
||||
},
|
||||
handleNodeSelected(path) {
|
||||
this.selectedNode = path;
|
||||
this.insertToken(path, "node-reference");
|
||||
},
|
||||
handleTagSelected(label){
|
||||
|
||||
handleTagSelected(label) {
|
||||
this.insertToken(label, "node-edit");
|
||||
},
|
||||
// 插入token到编辑器
|
||||
insertToken(text, type) {
|
||||
|
@ -1942,46 +2020,64 @@ export default {
|
|||
|
||||
// 确保编辑器有焦点
|
||||
editor.focus();
|
||||
setTimeout(() => {
|
||||
const token = this.createTokenElement(text, type);
|
||||
const space = document.createTextNode(" ");
|
||||
|
||||
const token = this.createTokenElement(text, type);
|
||||
// 获取当前光标位置
|
||||
const selection = window.getSelection();
|
||||
let range = this.savedRange?.cloneRange();
|
||||
|
||||
// 获取当前光标位置
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount > 0) {
|
||||
const range = selection.getRangeAt(0);
|
||||
// fallback:没有保存 range,则使用当前选区
|
||||
if (!range && selection.rangeCount > 0) {
|
||||
range = selection.getRangeAt(0);
|
||||
}
|
||||
|
||||
if (!range) {
|
||||
// fallback:插入到末尾
|
||||
editor.appendChild(token);
|
||||
editor.appendChild(space);
|
||||
this.setCursorToEnd();
|
||||
this.$nextTick(() => {
|
||||
if (!this.setCursorAfter(space)) {
|
||||
this.setCursorToEnd();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 删除选中内容(若有)
|
||||
range.deleteContents();
|
||||
|
||||
// 插入token
|
||||
range.insertNode(token);
|
||||
// 插入 token + 空格
|
||||
const frag = document.createDocumentFragment();
|
||||
frag.appendChild(token);
|
||||
frag.appendChild(space);
|
||||
range.insertNode(frag);
|
||||
|
||||
// 在token后添加一个空格
|
||||
const space = document.createTextNode(" ");
|
||||
range.setStartAfter(token);
|
||||
range.insertNode(space);
|
||||
// 设置光标到空格后
|
||||
range.setStartAfter(space);
|
||||
range.collapse(true);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
// 使用setTimeout确保DOM更新完成后设置光标
|
||||
setTimeout(() => {
|
||||
if (!this.setCursorAfter(space)) {
|
||||
// 如果设置失败,则设置到编辑器末尾
|
||||
this.setCursorToEnd();
|
||||
}
|
||||
}, 10); // 增加延迟时间确保DOM完全更新
|
||||
} else {
|
||||
// 如果没有选中区域,直接添加到末尾
|
||||
editor.appendChild(token);
|
||||
const space = document.createTextNode(" ");
|
||||
editor.appendChild(space);
|
||||
// 更新 savedRange
|
||||
this.savedRange = range.cloneRange();
|
||||
|
||||
// 使用setTimeout确保DOM更新完成后设置光标
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
if (!this.setCursorAfter(space)) {
|
||||
this.setCursorToEnd();
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
|
||||
this.saveRange();
|
||||
}, 10);
|
||||
},
|
||||
saveRange() {
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount > 0) {
|
||||
this.savedRange = selection.getRangeAt(0).cloneRange();
|
||||
}
|
||||
|
||||
// 强制更新
|
||||
this.$forceUpdate();
|
||||
},
|
||||
// 设置光标到末尾
|
||||
setCursorToEnd() {
|
||||
|
@ -2014,15 +2110,17 @@ export default {
|
|||
},
|
||||
// 创建token元素
|
||||
createTokenElement(text, type) {
|
||||
const token = document.createElement("span");
|
||||
token.className = `content-token token-function`;
|
||||
token.contentEditable = false;
|
||||
token.setAttribute("data-token-id", ++this.tokenCounter);
|
||||
token.setAttribute("data-token-type", type);
|
||||
token.setAttribute("data-token-text", text);
|
||||
let token = null;
|
||||
|
||||
token = document.createElement("span");
|
||||
token.contentEditable = false;
|
||||
token.setAttribute("data-token-text", text);
|
||||
if (type === "node-reference") {
|
||||
token.className = "content-token token-function";
|
||||
token.innerHTML = `<i class="el-icon-connection"></i> ${text}`;
|
||||
} else {
|
||||
token.className = "content-token token-edit";
|
||||
token.innerHTML = `${text}`;
|
||||
}
|
||||
return token;
|
||||
},
|
||||
|
@ -2047,6 +2145,15 @@ export default {
|
|||
this.currenrActiveNodeRef = "";
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 绑定事件监听器
|
||||
const editor = this.$refs[this.currenrActiveNodeRef]?.[0];
|
||||
if (editor) {
|
||||
editor.addEventListener("mouseup", this.saveRange);
|
||||
editor.addEventListener("keyup", this.saveRange);
|
||||
editor.addEventListener("mouseleave", this.saveRange); // 鼠标移开也记录一次
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -2874,9 +2981,9 @@ export default {
|
|||
user-select: none;
|
||||
}
|
||||
::v-deep .token-function {
|
||||
background: #e0e7ff;
|
||||
color: #5b21b6;
|
||||
border: 1px solid #8b5cf6;
|
||||
background: #ecfdf5;
|
||||
color: #047857;
|
||||
border: 1px solid #10b981;
|
||||
}
|
||||
|
||||
::v-deep .repContainer {
|
||||
|
@ -2915,7 +3022,7 @@ export default {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.repItem:hover .repItemValue{
|
||||
.repItem:hover .repItemValue {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
|
@ -2924,6 +3031,21 @@ export default {
|
|||
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;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue