场景中心动态配置
This commit is contained in:
parent
66427493fc
commit
f81a35c10e
|
@ -129,7 +129,10 @@
|
||||||
v-show="representation"
|
v-show="representation"
|
||||||
>
|
>
|
||||||
<div class="repContainer">
|
<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="first"></el-tab-pane>
|
||||||
<el-tab-pane label="表达式" name="second"></el-tab-pane>
|
<el-tab-pane label="表达式" name="second"></el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
@ -551,10 +554,11 @@
|
||||||
label-position="top"
|
label-position="top"
|
||||||
style="margin: 0 10px"
|
style="margin: 0 10px"
|
||||||
>
|
>
|
||||||
<div ref="editorContainer">
|
<div id="editorContainer">
|
||||||
<div
|
<div
|
||||||
v-for="(row, rowIndex) in outsideColumns"
|
v-for="(row, rowIndex) in outsideColumns"
|
||||||
:key="rowIndex"
|
:key="rowIndex"
|
||||||
|
class="editorItem"
|
||||||
>
|
>
|
||||||
<el-form-item :label="row.column_name">
|
<el-form-item :label="row.column_name">
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
|
@ -628,6 +632,10 @@
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<el-button @click="HitTesting">点击测试</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
@ -772,11 +780,69 @@ export default {
|
||||||
},
|
},
|
||||||
currenrActiveNodeRef: "",
|
currenrActiveNodeRef: "",
|
||||||
lastSelectedTokenIndex: -1,
|
lastSelectedTokenIndex: -1,
|
||||||
tokenCounter: 0,
|
|
||||||
representationData: representationData,
|
representationData: representationData,
|
||||||
|
savedRange: null, // ⬅️ 用于存储当前 range
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
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
|
* @param {string} sceneID 场景 ID
|
||||||
|
@ -1592,10 +1658,20 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 切换表时
|
// 切换表时
|
||||||
outsideSelectChange(val) {
|
async outsideSelectChange(val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
this.outsideColumns = [];
|
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.userList = [];
|
||||||
this.representation = false;
|
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) {
|
handleKeyDown(e, columnName, rowIndex) {
|
||||||
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
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选中状态
|
// 清除token选中状态
|
||||||
clearTokenSelection(columnName, rowIndex) {
|
clearTokenSelection(columnName, rowIndex) {
|
||||||
|
@ -1822,29 +1901,27 @@ export default {
|
||||||
},
|
},
|
||||||
// 处理输入事件
|
// 处理输入事件
|
||||||
handleInput(e, columnName, rowIndex) {
|
handleInput(e, columnName, rowIndex) {
|
||||||
// 清除token选中状态
|
// this.clearTokenSelection(columnName, rowIndex);
|
||||||
this.clearTokenSelection(columnName, rowIndex);
|
this.saveRange();
|
||||||
|
|
||||||
// 强制更新computed属性
|
|
||||||
this.$forceUpdate();
|
|
||||||
},
|
},
|
||||||
// 处理编辑器点击
|
// 处理编辑器点击
|
||||||
handleEditorClick(e, columnName, rowIndex) {
|
handleEditorClick(e, columnName, rowIndex) {
|
||||||
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
||||||
this.currenrActiveNodeRef = "contentEditor" + columnName + rowIndex;
|
this.currenrActiveNodeRef = "contentEditor" + columnName + rowIndex;
|
||||||
|
|
||||||
// 如果点击的不是token,清除选中状态
|
// // 如果点击的不是token,清除选中状态
|
||||||
if (
|
// if (
|
||||||
!e.target.classList.contains("content-token") &&
|
// !e.target.classList.contains("content-token") &&
|
||||||
!e.target.closest(".content-token")
|
// !e.target.closest(".content-token")
|
||||||
) {
|
// ) {
|
||||||
this.clearTokenSelection(columnName, rowIndex);
|
// this.clearTokenSelection(columnName, rowIndex);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 确保编辑器获得焦点
|
// // 确保编辑器获得焦点
|
||||||
if (e.target === editor || editor.contains(e.target)) {
|
// if (e.target === editor || editor.contains(e.target)) {
|
||||||
editor.focus();
|
editor.focus();
|
||||||
}
|
this.saveRange();
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
// 处理粘贴事件
|
// 处理粘贴事件
|
||||||
handlePaste(e, columnName, rowIndex) {
|
handlePaste(e, columnName, rowIndex) {
|
||||||
|
@ -1854,7 +1931,6 @@ export default {
|
||||||
// 处理编辑器获得焦点
|
// 处理编辑器获得焦点
|
||||||
handleEditorFocus(e, columnName, rowIndex) {
|
handleEditorFocus(e, columnName, rowIndex) {
|
||||||
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
const editor = this.$refs["contentEditor" + columnName + rowIndex][0];
|
||||||
|
|
||||||
// 如果编辑器为空,设置光标到开始位置
|
// 如果编辑器为空,设置光标到开始位置
|
||||||
if (this.isEmpty(columnName, rowIndex)) {
|
if (this.isEmpty(columnName, rowIndex)) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -1900,6 +1976,7 @@ export default {
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
// 确保编辑器有焦点
|
// 确保编辑器有焦点
|
||||||
editor.focus();
|
editor.focus();
|
||||||
|
this.saveRange();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1925,13 +2002,14 @@ export default {
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
// 确保编辑器有焦点
|
// 确保编辑器有焦点
|
||||||
editor.focus();
|
editor.focus();
|
||||||
|
this.saveRange();
|
||||||
},
|
},
|
||||||
handleNodeSelected(path) {
|
handleNodeSelected(path) {
|
||||||
this.selectedNode = path;
|
this.selectedNode = path;
|
||||||
this.insertToken(path, "node-reference");
|
this.insertToken(path, "node-reference");
|
||||||
},
|
},
|
||||||
handleTagSelected(label){
|
handleTagSelected(label) {
|
||||||
|
this.insertToken(label, "node-edit");
|
||||||
},
|
},
|
||||||
// 插入token到编辑器
|
// 插入token到编辑器
|
||||||
insertToken(text, type) {
|
insertToken(text, type) {
|
||||||
|
@ -1942,46 +2020,64 @@ export default {
|
||||||
|
|
||||||
// 确保编辑器有焦点
|
// 确保编辑器有焦点
|
||||||
editor.focus();
|
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();
|
||||||
|
|
||||||
// 获取当前光标位置
|
// fallback:没有保存 range,则使用当前选区
|
||||||
const selection = window.getSelection();
|
if (!range && selection.rangeCount > 0) {
|
||||||
if (selection.rangeCount > 0) {
|
range = selection.getRangeAt(0);
|
||||||
const 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();
|
range.deleteContents();
|
||||||
|
|
||||||
// 插入token
|
// 插入 token + 空格
|
||||||
range.insertNode(token);
|
const frag = document.createDocumentFragment();
|
||||||
|
frag.appendChild(token);
|
||||||
|
frag.appendChild(space);
|
||||||
|
range.insertNode(frag);
|
||||||
|
|
||||||
// 在token后添加一个空格
|
// 设置光标到空格后
|
||||||
const space = document.createTextNode(" ");
|
range.setStartAfter(space);
|
||||||
range.setStartAfter(token);
|
range.collapse(true);
|
||||||
range.insertNode(space);
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
|
||||||
// 使用setTimeout确保DOM更新完成后设置光标
|
// 更新 savedRange
|
||||||
setTimeout(() => {
|
this.savedRange = range.cloneRange();
|
||||||
if (!this.setCursorAfter(space)) {
|
|
||||||
// 如果设置失败,则设置到编辑器末尾
|
|
||||||
this.setCursorToEnd();
|
|
||||||
}
|
|
||||||
}, 10); // 增加延迟时间确保DOM完全更新
|
|
||||||
} else {
|
|
||||||
// 如果没有选中区域,直接添加到末尾
|
|
||||||
editor.appendChild(token);
|
|
||||||
const space = document.createTextNode(" ");
|
|
||||||
editor.appendChild(space);
|
|
||||||
|
|
||||||
// 使用setTimeout确保DOM更新完成后设置光标
|
this.$nextTick(() => {
|
||||||
setTimeout(() => {
|
|
||||||
if (!this.setCursorAfter(space)) {
|
if (!this.setCursorAfter(space)) {
|
||||||
this.setCursorToEnd();
|
this.setCursorToEnd();
|
||||||
}
|
}
|
||||||
}, 10);
|
});
|
||||||
|
|
||||||
|
this.saveRange();
|
||||||
|
}, 10);
|
||||||
|
},
|
||||||
|
saveRange() {
|
||||||
|
const selection = window.getSelection();
|
||||||
|
if (selection.rangeCount > 0) {
|
||||||
|
this.savedRange = selection.getRangeAt(0).cloneRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 强制更新
|
|
||||||
this.$forceUpdate();
|
|
||||||
},
|
},
|
||||||
// 设置光标到末尾
|
// 设置光标到末尾
|
||||||
setCursorToEnd() {
|
setCursorToEnd() {
|
||||||
|
@ -2014,15 +2110,17 @@ export default {
|
||||||
},
|
},
|
||||||
// 创建token元素
|
// 创建token元素
|
||||||
createTokenElement(text, type) {
|
createTokenElement(text, type) {
|
||||||
const token = document.createElement("span");
|
let token = null;
|
||||||
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);
|
|
||||||
|
|
||||||
|
token = document.createElement("span");
|
||||||
|
token.contentEditable = false;
|
||||||
|
token.setAttribute("data-token-text", text);
|
||||||
if (type === "node-reference") {
|
if (type === "node-reference") {
|
||||||
|
token.className = "content-token token-function";
|
||||||
token.innerHTML = `<i class="el-icon-connection"></i> ${text}`;
|
token.innerHTML = `<i class="el-icon-connection"></i> ${text}`;
|
||||||
|
} else {
|
||||||
|
token.className = "content-token token-edit";
|
||||||
|
token.innerHTML = `${text}`;
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
},
|
},
|
||||||
|
@ -2047,6 +2145,15 @@ export default {
|
||||||
this.currenrActiveNodeRef = "";
|
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>
|
</script>
|
||||||
|
|
||||||
|
@ -2874,9 +2981,9 @@ export default {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
::v-deep .token-function {
|
::v-deep .token-function {
|
||||||
background: #e0e7ff;
|
background: #ecfdf5;
|
||||||
color: #5b21b6;
|
color: #047857;
|
||||||
border: 1px solid #8b5cf6;
|
border: 1px solid #10b981;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .repContainer {
|
::v-deep .repContainer {
|
||||||
|
@ -2915,7 +3022,7 @@ export default {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.repItem:hover .repItemValue{
|
.repItem:hover .repItemValue {
|
||||||
color: #409eff;
|
color: #409eff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2924,6 +3031,21 @@ export default {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin-left: 10px;
|
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>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue