From 66427493fc3f0c285162b726ff6f223326458cb8 Mon Sep 17 00:00:00 2001 From: caorui <3165079241@qq.com> Date: Fri, 20 Jun 2025 18:58:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=AD=E5=BF=83=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20=E5=8A=A8=E6=80=81=E9=85=8D=E7=BD=AE=E8=A1=A8?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E3=80=81=E5=AD=97=E6=AE=B5=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/permission.js | 2 +- src/views/LinkUp/compoment/TreeNode.vue | 132 ++ src/views/LinkUp/compoment/addAccount.vue | 85 +- src/views/LinkUp/compoment/addDialogChunk.vue | 1149 +++++++++++++++-- src/views/LinkUp/compoment/constant.js | 196 ++- 5 files changed, 1405 insertions(+), 159 deletions(-) create mode 100644 src/views/LinkUp/compoment/TreeNode.vue diff --git a/src/permission.js b/src/permission.js index 5b91e00..0106dfa 100644 --- a/src/permission.js +++ b/src/permission.js @@ -30,7 +30,7 @@ const whiteList = [ router.beforeEach((to, from, next) => { let reloaded = sessionStorage.getItem('reloaded') //网站第一次进来逻辑 当from为空 - if (from.path === '/' && !reloaded && isFirst) { + if (from.path === '/' && !reloaded && isFirst && !whiteList.includes(to.path)) { isFirst = false setMenuNode("/index"); store.commit("SET_CURRENT_MENU_NODE", "/index"); diff --git a/src/views/LinkUp/compoment/TreeNode.vue b/src/views/LinkUp/compoment/TreeNode.vue new file mode 100644 index 0000000..0ca76b5 --- /dev/null +++ b/src/views/LinkUp/compoment/TreeNode.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/views/LinkUp/compoment/addAccount.vue b/src/views/LinkUp/compoment/addAccount.vue index 17ac29a..6ec8501 100644 --- a/src/views/LinkUp/compoment/addAccount.vue +++ b/src/views/LinkUp/compoment/addAccount.vue @@ -7,14 +7,17 @@ :appendBody="true" :loading="true" :footerShow="true" - :submitShow="true" + :submitShow="submitShow" :submitTitle="'保存'" - title="新增应用账号授权" + title="新增账号" > +
+
+ + +
+
+ + +
@@ -166,13 +189,21 @@ export default { ], }, appID: "", + sceneID: "", + stepID: "", accountType: "", + submitShow: false, //是否显示查看按钮 + message: "", }; }, methods: { - openDialog(appID) { + openDialog(appID, sceneID, stepID) { + this.submitShow = false; + this.message = ""; this.queryDictionaryList(); this.appID = appID; + this.sceneID = sceneID; + this.stepID = stepID; this.dialogVisible = true; this.$nextTick(() => { this.$refs.customForm?.resetFields("ruleForm"); @@ -194,12 +225,46 @@ export default { this.accountFormRow[3].elCol[0].options = res.attribute; } }, + VerifyAccount() { + this.$refs.customForm.$refs["ruleForm"].validate((valid) => { + if (valid) { + let params = { + ...this.$refs.customForm.ruleForm, + }; + this.verifyDataBase(params); + } else { + this.$message({ message: "请选择必填项", type: "warning" }); + return; + } + }); + }, + async verifyDataBase(params) { + this.openLoading("验证"); + let res = await authApi( + "sysFlowStepAccountService", + "", + "verifyDataBase", + "", + params + ); + if (res.status == "200") { + this.message = res.attribute.msg || ""; + if (res.attribute.flag == true) { + this.submitShow = true; + } else { + this.submitShow = false; + } + } + }, handleConfirmClick() { this.$refs.customForm.$refs["ruleForm"].validate((valid) => { if (valid) { let params = { ...this.$refs.customForm.ruleForm, appId: this.appID, + status: 1, + flowId: this.sceneID, + stepId: this.stepID, }; this.SaveAccountData(params); } else { @@ -211,7 +276,7 @@ export default { async SaveAccountData(params) { let res = await authApi( - "sysApplicationAccountService", + "sysFlowStepAccountService", "", "saveAccount", "", @@ -238,4 +303,14 @@ export default { ::v-deep .label { text-align: left !important; } + +::v-deep .custom-error-box .el-alert { + padding: 15px 16px !important; +} +::v-deep .custom-error-box .el-alert__title { + font-size: 14px !important; +} +::v-deep .custom-error-box .el-alert__description { + font-size: 13px !important; +} \ No newline at end of file diff --git a/src/views/LinkUp/compoment/addDialogChunk.vue b/src/views/LinkUp/compoment/addDialogChunk.vue index 8ca294b..e1cffdc 100644 --- a/src/views/LinkUp/compoment/addDialogChunk.vue +++ b/src/views/LinkUp/compoment/addDialogChunk.vue @@ -25,8 +25,8 @@ v-if="drawShowList.length > 0" style="background: #fff" > - -
+ +
- {{ ele.options.description }} + {{ ele.options.stepDescribe }}
{{ ele.content }}
@@ -122,6 +122,53 @@ 添加新步骤
+ +
+
+ + + + +
+ 关闭 +
+
+ +
+
+ + + + + +
+
+
@@ -171,7 +218,11 @@
- +
- +
@@ -330,7 +385,7 @@ v-for="(item, index) in apiList" class="appItem" @click="hangleApiClickEvent(item, index)" - :class="{ active: apiIdActiv == item.apiId }" + :class="{ active: apiIdActiv == item.id }" >
@@ -347,7 +402,7 @@ v-for="(item, index) in pluginList" class="appItem" @click="hanglePluginClickEvent(item, index)" - :class="{ active: pluginActiv == item.plugId }" + :class="{ active: pluginActiv == item.id }" >
@@ -360,7 +415,13 @@
- +
@@ -391,14 +452,184 @@
-
{{ item.name }}
+
+ + + +
+
+
{{ item.name }}
+
+ 最新编辑时间:{{ item.modify_time }} +
+
+ + +
+
+
+ +
+
+ +
+ {{ CurrentAppRow.appName }} +
+ +
+ {{ CurrentAppRow.description }} +
+
+
+
+
+ + + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
@@ -417,17 +648,23 @@ import baseRightDialog from "@/components/base/baseRightDialog/index.vue"; import editSence from "./editSence.vue"; import { authApi } from "@/api/apis/auth"; // 导入步骤添加和使用的常量 -import { stepAdd, stepUse, timeDivide } from "./constant"; +import { stepAdd, stepUse, timeDivide, representationData } from "./constant"; // 导入 cron 表达式组件 import FishCrontab from "fish-crontab"; // 导入添加账号组件 import addAccount from "./addAccount.vue"; +import baseForm from "@/components/base/baseNewForm"; +import treeNode from "./TreeNode"; +import IconsDialog from "../../tool/build/IconsDialog.vue"; export default { components: { editSence, baseRightDialog, FishCrontab, addAccount, + baseForm, + treeNode, + IconsDialog, }, data() { return { @@ -466,6 +703,77 @@ export default { // 用户列表 userList: [], userActivId: "", // 选择的用户 ID + outsideFormRow: [ + { + elCol: [ + { + label: "选择表", + prop: "tableName", + tag: "elSelect", + span: 24, + }, + ], + }, + ], + outsideRules: { + tableName: [ + { + required: true, + message: "请选择表", + trigger: "change, blur", + }, + ], + }, + outsideFormData: { + tableName: "", + }, + outsideOptions: [], + outsideColumns: [], //表字段 + activeNames: "1", //展开 + ColumnsFormData: {}, + ColumnsRules: {}, + + representation: false, + selectedNode: "", + representationActiveName: "first", + treeData: { + user: { + id: 1001, + profile: { + name: "李四", + email: "lisi@example.com", + settings: { + theme: "dark", + notifications: { + email: true, + sms: false, + push: true, + }, + }, + }, + permissions: ["read", "write", "admin"], + metadata: { + created_at: "2023-01-15T10:30:00Z", + updated_at: "2024-03-20T15:45:30Z", + version: 2.1, + }, + }, + config: { + database: { + host: "localhost", + port: 5432, + ssl: false, + }, + features: { + experimental: ["ai_assist", "real_time_sync"], + stable: ["user_management", "data_export"], + }, + }, + }, + currenrActiveNodeRef: "", + lastSelectedTokenIndex: -1, + tokenCounter: 0, + representationData: representationData, }; }, methods: { @@ -537,6 +845,7 @@ export default { options: { ...item, stepID: item.id, + taskType: item.apiId, }, }; if (this.triggerMode === 2) { @@ -557,6 +866,7 @@ export default { options: { ...item, stepID: item.id, + stepDescribe: item.apiName || item.plugName, }, }); } @@ -697,13 +1007,14 @@ export default { * 切换步骤时 * @param {number} index 步骤索引 */ - selectDrawItem(index) { + async selectDrawItem(index) { // 更新当前选中的步骤索引 this.drawSelectIndex = index; // 先清空 this.pluginActiv = ""; this.apiIDActiv = ""; this.userActivId = ""; + this.CurrentAppRow = {}; if (index === 0) { this.activeTabName = "选择操作"; } else { @@ -711,9 +1022,9 @@ export default { // 清空应用搜索关键字 this.appCodeOrName = ""; // 获取应用列表 - this.getAppList(); + await this.getAppList(); // 获取场景步骤数据 - this.GetSceneStepData(); + await this.GetSceneStepData(); } }, /** @@ -737,13 +1048,15 @@ export default { ...res.attribute, }; // 更新当前步骤的选项 + obj.stepDescribe = obj.apiName || obj.plugName; this.drawShowList[this.drawSelectIndex].options = obj; - + // 更新当前选择的应用步骤描述 + this.CurrentAppRow.description = obj.stepDescribe; if (this.drawSelectIndex == 0) { this.expression = obj.taskCorn; this.activTimeIndex = obj.apiId; } else { - this.activeApiPliginTabName = obj.actionType; + this.activeApiPliginTabName = obj.actionType || "API接口"; // 清空 API 或插件搜索关键字 this.operateCodeOrName = ""; @@ -761,58 +1074,57 @@ export default { this.CurrentAppRow.appName = this.drawShowList[this.drawSelectIndex].options.appName; // 获取当前步骤的 api、插件、账号 - this.GetApiList(this.appActivIndex); + await this.GetApiList(this.appActivIndex); // this.getPluginList(this.appActivIndex); - this.GetAccountListAPI(this.appActivIndex); + await this.GetAccountListAPI(this.appActivIndex); } else { // 重置当前选中的应用 ID this.appActivIndex = ""; // 重置当前选择的应用数据 this.CurrentAppRow = {}; } - if (this.drawShowList[this.drawSelectIndex].options.description) { - // 更新步骤描述 - this.description = - this.drawShowList[this.drawSelectIndex].options.description; - // 更新当前选择的应用步骤描述 - this.CurrentAppRow.description = this.description; - } else { - // 重置步骤描述 - this.description = ""; - // 重置当前选择的应用步骤描述 - this.CurrentAppRow.description = ""; - } - if (this.drawShowList[this.drawSelectIndex].options.apiId) { - // 更新选择的 API ID - this.apiIdActiv = - this.drawShowList[this.drawSelectIndex].options.apiId; - } else { - // 重置选择的 API ID - this.apiIdActiv = ""; - } - // 插件 - if (this.drawShowList[this.drawSelectIndex].options.plugId) { - // 更新选择的插件 ID - this.pluginActiv = - this.drawShowList[this.drawSelectIndex].options.plugId; - } else { - // 重置选择的插件 ID - this.pluginActiv = ""; - } - // 账号 - if (this.drawShowList[this.drawSelectIndex].options.step_acc_id) { - // 更新选择的用户 ID - this.userActivId = - this.drawShowList[this.drawSelectIndex].options.step_acc_id; - // 更新当前选择的应用账号名称 - this.CurrentAppRow.step_acc_name = - this.drawShowList[this.drawSelectIndex].options.step_acc_name; - } else { - // 重置选择的用户 ID - this.userActivId = ""; - // 重置当前选择的应用账号名称 - this.CurrentAppRow.step_acc_name = ""; - } + this.$nextTick(() => { + if (this.drawShowList[this.drawSelectIndex].options.description) { + // 更新步骤描述 + this.description = + this.drawShowList[this.drawSelectIndex].options.description; + } else { + // 重置步骤描述 + this.description = ""; + } + + if (this.drawShowList[this.drawSelectIndex].options.apiId) { + // 更新选择的 API ID + this.apiIdActiv = + this.drawShowList[this.drawSelectIndex].options.apiId; + } else { + // 重置选择的 API ID + this.apiIdActiv = ""; + } + // 插件 + if (this.drawShowList[this.drawSelectIndex].options.plugId) { + // 更新选择的插件 ID + this.pluginActiv = + this.drawShowList[this.drawSelectIndex].options.plugId; + } else { + // 重置选择的插件 ID + this.pluginActiv = ""; + } + // 账号 + if (this.drawShowList[this.drawSelectIndex].options.step_acc_id) { + // 更新选择的用户 ID + this.userActivId = + this.drawShowList[this.drawSelectIndex].options.step_acc_id; + // 更新当前选择的应用账号名称 + this.CurrentAppRow.step_acc_name = + this.drawShowList[this.drawSelectIndex].options.step_acc_name; + } else { + // 重置选择的用户 ID + this.userActivId = ""; + // 重置当前选择的应用账号名称 + this.CurrentAppRow.step_acc_name = ""; + } + }); } } }, @@ -975,8 +1287,6 @@ export default { * 步骤描述变化时保存数据 */ changeDescription() { - // 更新当前选择的应用步骤描述 - this.CurrentAppRow.description = this.description; // 更新当前步骤的步骤描述 this.drawShowList[this.drawSelectIndex].options.description = this.description; @@ -994,73 +1304,108 @@ export default { * @param {number} index 应用索引 */ async hangleAppItem(row, index) { - if (this.appActivIndex !== row.appId) { - // 重置当前选择的应用插件名称 - this.CurrentAppRow.plugName = ""; - // 重置当前选择的应用账号名称 - this.CurrentAppRow.step_acc_name = ""; - // 重置当前步骤的资源类型 - this.drawShowList[this.drawSelectIndex].options.actionType = ""; - // 重置当前步骤的 API ID - this.drawShowList[this.drawSelectIndex].options.apiId = ""; - this.drawShowList[this.drawSelectIndex].options.apiName = ""; - // 重置当前步骤的插件 ID - this.drawShowList[this.drawSelectIndex].options.plugId = ""; - // 重置当前步骤的插件名称 - this.drawShowList[this.drawSelectIndex].options.plugName = ""; - // 重置当前步骤的账号 ID - this.drawShowList[this.drawSelectIndex].options.step_acc_id = ""; - // 重置当前步骤的账号名称 - this.drawShowList[this.drawSelectIndex].options.step_acc_name = ""; - this.apiIdActiv = ""; - this.apiList = []; - this.pluginActiv = ""; - this.pluginList = []; - this.userActivId = ""; - this.userList = []; - // 更新当前选中的应用 ID - this.appActivIndex = row.id; - // 更新当前选择的应用 ID - this.CurrentAppRow.appId = row.id; - // 更新当前选择的应用名称 - this.CurrentAppRow.appName = row.name; - // 更新当前步骤的应用 ID - this.drawShowList[this.drawSelectIndex].options.appId = row.id; - // 更新当前步骤的应用名称 - this.drawShowList[this.drawSelectIndex].options.appName = row.name; - - // 切换到选择操作标签页 - this.activeOtherTabName = "选择操作"; - // 切换到 API 接口标签页 - this.activeApiPliginTabName = "API接口"; - // 清空 API 或插件搜索关键字 - this.operateCodeOrName = ""; - // 更新当前步骤的资源类型 - this.drawShowList[this.drawSelectIndex].options.actionType = "API接口"; - // 实时保存配置 - let params = { - flowId: this.sceneID, - id: this.drawShowList[this.drawSelectIndex].options.stepID, - appId: row.id, - appName: row.name, - actionType: "", - plugId: "", - plugName: "", - apiId: "", - apiName: "", - step_acc_name: "", - step_acc_id: "", - }; - // 保存场景步骤数据 - await this.SaveSceneStepData(params); - // 获取 API 列表 - await this.GetApiList(row.id); - // 获取插件列表 - // await this.getPluginList(row.id); - // // 获取用户列表 - await this.GetAccountListAPI(row.id); + if (!this.appActivIndex) { + // 保存应用信息 + this.matchAppData(row); + } else if (this.appActivIndex !== row.appId) { + this.$confirm( + "切换应用会清空操作、账号及配置内的所有数据,确定切换吗?", + "提示", + { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: "warning", + } + ) + .then(async () => { + // 重置当前选择的应用插件名称 + this.CurrentAppRow.plugName = ""; + // 重置当前选择的应用账号名称 + this.CurrentAppRow.step_acc_name = ""; + this.CurrentAppRow.description = ""; + // 重置当前步骤的资源类型 + this.drawShowList[this.drawSelectIndex].options.actionType = ""; + // 重置当前步骤的 API ID + this.drawShowList[this.drawSelectIndex].options.apiId = ""; + this.drawShowList[this.drawSelectIndex].options.apiName = ""; + // 重置当前步骤的插件 ID + this.drawShowList[this.drawSelectIndex].options.plugId = ""; + // 重置当前步骤的插件名称 + this.drawShowList[this.drawSelectIndex].options.plugName = ""; + // 重置当前步骤的账号 ID + this.drawShowList[this.drawSelectIndex].options.step_acc_id = ""; + // 重置当前步骤的账号名称 + this.drawShowList[this.drawSelectIndex].options.step_acc_name = ""; + this.drawShowList[this.drawSelectIndex].options.stepDescribe = ""; + this.apiIdActiv = ""; + this.apiList = []; + this.pluginActiv = ""; + this.pluginList = []; + this.userActivId = ""; + this.userList = []; + // 保存应用信息 + this.matchAppData(row); + // 清空步骤配置 + await this.clearFlowStep(); + }) + .catch(() => {}); } }, + async matchAppData(row) { + // 更新当前选中的应用 ID + this.appActivIndex = row.id; + // 更新当前选择的应用 ID + this.CurrentAppRow.appId = row.id; + // 更新当前选择的应用名称 + this.CurrentAppRow.appName = row.name; + // 更新当前步骤的应用 ID + this.drawShowList[this.drawSelectIndex].options.appId = row.id; + // 更新当前步骤的应用名称 + this.drawShowList[this.drawSelectIndex].options.appName = row.name; + + // 切换到选择操作标签页 + this.activeOtherTabName = "选择操作"; + // 切换到 API 接口标签页 + this.activeApiPliginTabName = "API接口"; + // 清空 API 或插件搜索关键字 + this.operateCodeOrName = ""; + // 更新当前步骤的资源类型 + this.drawShowList[this.drawSelectIndex].options.actionType = "API接口"; + // 实时保存配置 + let params = { + flowId: this.sceneID, + id: this.drawShowList[this.drawSelectIndex].options.stepID, + appId: row.id, + appName: row.name, + actionType: "", + plugId: "", + plugName: "", + apiId: "", + apiName: "", + step_acc_name: "", + step_acc_id: "", + }; + // 保存场景步骤数据 + await this.SaveSceneStepData(params); + // 获取 API 列表 + await this.GetApiList(row.id); + // 获取插件列表 + // await this.getPluginList(row.id); + // // 获取用户列表 + await this.GetAccountListAPI(row.id); + }, + async clearFlowStep() { + let params = { + id: this.drawShowList[this.drawSelectIndex].options.stepID, + }; + let res = await authApi( + "sysFlowStepService", + "", + "clearFlowStep", + "", + params + ); + }, /** * API 或者插件的搜索 */ @@ -1110,6 +1455,10 @@ export default { // 更新当前步骤的 API ID this.drawShowList[this.drawSelectIndex].options.apiId = item.id; this.drawShowList[this.drawSelectIndex].options.apiName = item.apiName; + // 更新当前选择的应用步骤描述 + this.CurrentAppRow.description = item.apiName; + this.drawShowList[this.drawSelectIndex].options.stepDescribe = + item.apiName; // 更新当前步骤的资源类型 this.drawShowList[this.drawSelectIndex].options.actionType = this.activeApiPliginTabName; @@ -1137,6 +1486,10 @@ export default { this.pluginActiv = item.id; this.drawShowList[this.drawSelectIndex].options.plugId = item.id; this.drawShowList[this.drawSelectIndex].options.plugName = item.plugName; + // 更新当前选择的应用步骤描述 + this.CurrentAppRow.description = item.plugName; + this.drawShowList[this.drawSelectIndex].options.stepDescribe = + item.plugName; // 更新当前步骤的资源类型 this.drawShowList[this.drawSelectIndex].options.actionType = this.activeApiPliginTabName; @@ -1163,7 +1516,11 @@ export default { return; } // 打开添加账号弹窗 - this.$refs.addAccount.openDialog(this.appActivIndex); + this.$refs.addAccount.openDialog( + this.appActivIndex, + this.sceneID, + this.drawShowList[this.drawSelectIndex].options.stepID + ); }, /** * 重新加载用户列表 @@ -1176,7 +1533,7 @@ export default { * 当前选中的用户 * @param {Object} item 用户数据 */ - handleUserClickEvent(item) { + async handleUserClickEvent(item) { // 更新选择的用户 ID this.userActivId = item.id; // 更新当前选择的应用账号名称 @@ -1185,6 +1542,12 @@ export default { this.drawShowList[this.drawSelectIndex].options.step_acc_id = item.id; // 更新当前步骤的用户账号名称 this.drawShowList[this.drawSelectIndex].options.step_acc_name = item.name; + this.outsideFormData = { + tableName: "", + }; + this.ColumnsFormData = {}; + this.outsideOptions = []; + this.outsideColumns = []; let params = { flowId: this.sceneID, id: this.drawShowList[this.drawSelectIndex].options.stepID, @@ -1192,7 +1555,71 @@ export default { step_acc_id: item.id, }; // 保存场景步骤数据 - this.SaveSceneStepData(params); + await this.SaveSceneStepData(params); + // 切换到配置应用 + this.activeOtherTabName = "配置应用"; + // 获取表数据 + await this.queryTables(item.id); + this.$nextTick(() => { + this.resetForm("outsideForm"); + }); + }, + /** + * 重置表单 + * @param {string} formName 表单的ref + */ + resetForm(formName) { + this.$refs[formName].resetFields(); + }, + /** + * 获取表列表 + * @param {string} stepAccountId 账号ID + */ + async queryTables(stepAccountId) { + let params = { + stepAccountId: stepAccountId, + }; + let res = await authApi( + "sysFlowDataBaseExtServiceImpl", + "", + "queryTables", + "", + params + ); + this.drawMask = false; + if (res.status == "200") { + this.outsideOptions = res.attribute; + } + }, + // 切换表时 + outsideSelectChange(val) { + if (val) { + this.outsideColumns = []; + this.queryColumns(val); + } + }, + // 获取表字段 + async queryColumns(tableName) { + let params = { + stepAccountId: this.userActivId, //账户id + tableName: tableName, + }; + let res = await authApi( + "sysFlowDataBaseExtServiceImpl", + "", + "queryColumns", + "", + params + ); + this.drawMask = false; + if (res.status == "200") { + this.outsideColumns = res.attribute.cloums || []; + this.ColumnsRules = res.attribute.rules || {}; + this.$nextTick(() => { + this.ColumnsFormData = {}; + this.resetForm("ColumnsForm"); + }); + } }, /** * 获取插件列表 @@ -1344,6 +1771,280 @@ export default { this.userActivId = ""; // 清空用户列表 this.userList = []; + this.representation = false; + }, + + handleKeyDown(e, columnName, rowIndex) { + const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + + if (e.key === "Backspace") { + // 检查是否在光标前有token需要删除 + const selection = window.getSelection(); + if (selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + + // 如果光标在文本开头或者前一个兄弟节点是token + if (range.startOffset === 0) { + const prevSibling = range.startContainer.previousSibling; + if ( + prevSibling && + prevSibling.classList && + prevSibling.classList.contains("content-token") + ) { + e.preventDefault(); + prevSibling.remove(); + this.$message.success("已删除元素"); + return; + } + } + } + } + + // 清除token选中状态(除了特殊键) + if ( + ![ + "Backspace", + "Delete", + "ArrowLeft", + "ArrowRight", + "ArrowUp", + "ArrowDown", + ].includes(e.key) + ) { + this.clearTokenSelection(columnName, rowIndex); + } + }, + // 清除token选中状态 + clearTokenSelection(columnName, rowIndex) { + const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + + this.lastSelectedTokenIndex = -1; + }, + // 处理输入事件 + handleInput(e, columnName, rowIndex) { + // 清除token选中状态 + this.clearTokenSelection(columnName, rowIndex); + + // 强制更新computed属性 + this.$forceUpdate(); + }, + // 处理编辑器点击 + 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); + } + + // 确保编辑器获得焦点 + if (e.target === editor || editor.contains(e.target)) { + editor.focus(); + } + }, + // 处理粘贴事件 + handlePaste(e, columnName, rowIndex) { + // 清除token选中状态 + this.clearTokenSelection(columnName, rowIndex); + }, + // 处理编辑器获得焦点 + handleEditorFocus(e, columnName, rowIndex) { + const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + + // 如果编辑器为空,设置光标到开始位置 + if (this.isEmpty(columnName, rowIndex)) { + setTimeout(() => { + const range = document.createRange(); + const selection = window.getSelection(); + range.setStart(editor, 0); + range.setEnd(editor, 0); + selection.removeAllRanges(); + selection.addRange(range); + }, 0); + } + }, + // 判断当前编辑器是否为空 + isEmpty(columnName, rowIndex) { + const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + if (!editor) return true; + const content = editor.textContent.trim(); + const hasTokens = editor.querySelectorAll(".content-token").length > 0; + return content === "" && !hasTokens; + }, + // 处理编辑器失去焦点 + handleEditorBlur(e, columnName, rowIndex) { + // 可以在这里处理失去焦点的逻辑 + }, + handleClearNodeToEditor(columnName, rowIndex) { + const editor = this.$refs["contentEditor" + columnName + rowIndex][0]; + if (!editor) return; + let nodeRef = "contentEditor" + columnName + rowIndex; + this.currenrActiveNodeRef = nodeRef; + + editor.innerHTML = ""; // 先清空内容 + this.$forceUpdate(); + this.$nextTick(() => { + // 创建 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(); + }); + }, + + //添加节点 + handleAddNodeToEditor(columnName, rowIndex) { + let nodeRef = "contentEditor" + columnName + rowIndex; + this.currenrActiveNodeRef = nodeRef; + this.representation = true; + this.representationActiveName = "first"; + + // 这段代码的目的是 让光标停留在最后一个span标签后面 + 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(); + }, + handleNodeSelected(path) { + this.selectedNode = path; + this.insertToken(path, "node-reference"); + }, + handleTagSelected(label){ + + }, + // 插入token到编辑器 + insertToken(text, type) { + if (!this.currenrActiveNodeRef) return; + + const editor = this.$refs[this.currenrActiveNodeRef][0]; + if (!editor) return; + + // 确保编辑器有焦点 + editor.focus(); + + const token = this.createTokenElement(text, type); + + // 获取当前光标位置 + const selection = window.getSelection(); + if (selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + range.deleteContents(); + + // 插入token + range.insertNode(token); + + // 在token后添加一个空格 + const space = document.createTextNode(" "); + range.setStartAfter(token); + range.insertNode(space); + + // 使用setTimeout确保DOM更新完成后设置光标 + setTimeout(() => { + if (!this.setCursorAfter(space)) { + // 如果设置失败,则设置到编辑器末尾 + this.setCursorToEnd(); + } + }, 10); // 增加延迟时间确保DOM完全更新 + } else { + // 如果没有选中区域,直接添加到末尾 + editor.appendChild(token); + const space = document.createTextNode(" "); + editor.appendChild(space); + + // 使用setTimeout确保DOM更新完成后设置光标 + setTimeout(() => { + if (!this.setCursorAfter(space)) { + this.setCursorToEnd(); + } + }, 10); + } + + // 强制更新 + this.$forceUpdate(); + }, + // 设置光标到末尾 + setCursorToEnd() { + if (!this.currenrActiveNodeRef) return; + + const editor = this.$refs[this.currenrActiveNodeRef][0]; + if (!editor) return; + + const range = document.createRange(); + const selection = window.getSelection(); + range.selectNodeContents(editor); + range.collapse(false); + selection.removeAllRanges(); + selection.addRange(range); + }, + + // 设置光标到指定节点后面 + setCursorAfter(node) { + try { + const selection = window.getSelection(); + const range = document.createRange(); + range.setStartAfter(node); + range.collapse(true); + selection.removeAllRanges(); + selection.addRange(range); + return true; + } catch (error) { + return false; + } + }, + // 创建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); + + if (type === "node-reference") { + token.innerHTML = ` ${text}`; + } + return token; + }, + // 设置光标到末尾 + setCursorToEnd() { + // 清除之前的选中状态 + if (!this.currenrActiveNodeRef) return; + const editor = this.$refs[this.currenrActiveNodeRef][0]; + if (!editor) return; + + const range = document.createRange(); + const selection = window.getSelection(); + range.selectNodeContents(editor); + range.collapse(false); + selection.removeAllRanges(); + selection.addRange(range); + }, + closeRepContainer() { + this.representationActiveName = "first"; + this.representation = false; + this.selectedNode = ""; + this.currenrActiveNodeRef = ""; }, }, }; @@ -1460,6 +2161,7 @@ export default { font-weight: 500; font-size: 14px; color: #333333; + margin-top: 5px; } } .drawBox:hover { @@ -1627,6 +2329,7 @@ export default { font-weight: 500; font-size: 14px; color: #333333; + margin-top: 5px; } } @@ -1819,6 +2522,10 @@ export default { padding: 15px; cursor: pointer; } + .status { + margin-right: 10px; + font-size: 18px !important; + } .userAccountIcon { width: 15px; height: 15px; @@ -2069,4 +2776,184 @@ export default { height: 15px; margin-left: 5px; } + +::v-deep .el-form-item { + margin-bottom: 0 !important; +} +::v-deep .el-form-item__label { + padding-bottom: 0 !important; + font-weight: bold; +} + +.outsideContent { + height: calc(100vh - 220px); + overflow: auto; + padding: 0 10px 10px 10px; +} +::v-deep .el-collapse-item__header.is-active { + padding-left: 10px !important; +} +// ------------------------ +.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: 36px; + padding: 0 50px 0 15px; + background: #fff; + position: relative; + font-size: 14px; + // 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: 20px; +} + +.content-editor:focus { + outline: none; +} + +// -------------------------------- +::v-deep .content-token { + display: inline-table; + padding: 0 10px; + border-radius: 4px; + margin: 2px; + cursor: pointer; + transition: all 0.2s ease; + vertical-align: middle; + font-size: 13px; + font-weight: 500; + user-select: none; +} +::v-deep .token-function { + background: #e0e7ff; + color: #5b21b6; + border: 1px solid #8b5cf6; +} + +::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; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/views/LinkUp/compoment/constant.js b/src/views/LinkUp/compoment/constant.js index e02831d..06a6eda 100644 --- a/src/views/LinkUp/compoment/constant.js +++ b/src/views/LinkUp/compoment/constant.js @@ -8,26 +8,178 @@ var stepAdd = { icon: '', title: '触发条件', actionName: '平台触发配置 var stepUse = { icon: '', title: '执行操作', actionName: '请选择执行操作', content: '请选择动作', } var timeDivide = [ - { - id: 1, - title: "秒级", - content: "用户可使用 cron 表达式自定义时间执行", - }, - { - id: 2, - title: "分钟级", - content: "用户可使用 cron 表达式自定义时间执行", - }, - { - id: 3, - title: "小时级", - content: "按设定的周期时间开始执行,如每月 x 执行一次", - }, - { - id: 4, - title: "天级", - content: "按设定的时间间隔开始执行,如间隔 x 小时执行一次", - }, - ] + { + id: 1, + title: "秒级", + content: "用户可使用 cron 表达式自定义时间执行", + }, + { + id: 2, + title: "分钟级", + content: "用户可使用 cron 表达式自定义时间执行", + }, + { + id: 3, + title: "小时级", + content: "按设定的周期时间开始执行,如每月 x 执行一次", + }, + { + id: 4, + title: "天级", + content: "按设定的时间间隔开始执行,如间隔 x 小时执行一次", + }, +] +var representationData = [ + { + id: 1, + label: "字符串函数", + children: [ + { + label: "concat", + value: "将任意数量的字符串拼接到一起", + }, + { + label: "replaceFirst", + value: "用给定的字符串替换字符串中的第一个", + }, + { + label: "replaceAll", + value: "用给定的字符串替换字符串中所有匹配上的字符串", + }, + { + label: "format", + value: "使用指定的格式字符串和参数返回一个格式化字符串", + }, + { + label: "startsWith", + value: "判断字符串是否是以指定的字符串开始", + }, + { + label: "endsWith", + value: "判断字符串是否是以指定的字符串结束", + }, + { + label: "equals", + value: "判断两个字符串是否相等", + }, + { + label: "equalsIgnoreCase", + value: "判断两个字符串是否相等(忽略大小写)", + }, + { + label: "contains", + value: "判断字符串是否包含指定的字符串", + }, + { + label: "indexOf", + value: "查询指定字符串在字符串中的第一次出现的位置", + }, + { + label: "substring", + value: "截取指定位置字符串,end不指定时表示到字符串末尾,从0开始", + }, + { + label: "split", + value: "按分割符分割字符串", + }, + { + label: "md5", + value: "MD5加密", + }, + { + label: "upperCase", + value: "英文字符串转大写", + }, + { + label: "lowerCase", + value: "英文字符串转小写", + }, + ] + }, + { + id: 2, + label: "JSON函数", + children: [ + { + label: "toString", + value: "将JSON转化为字符串输出", + }, + { + label: "parseObject", + value: "将字符串转化为JSON输出", + }, + ] + }, + { + id: 3, + label: "数学计算", + children: [ + { + label: "add", + value: "计算两个数据的和", + }, + { + label: "addWithScale", + value: "计算两个数据的和(指定精度)", + }, + { + label: "subtract", + value: "计算两个数据的差", + }, + { + label: "subtractWithScale", + value: "计算两个数据的差(指定精度)", + }, + { + label: "multiply", + value: "计算两个数据的积", + }, + { + label: "multiplyWithScale", + value: "计算两个数据的积(指定精度)", + }, + { + label: "divide", + value: "计算两个数据的商", + }, + { + label: "divideWithScale", + value: "计算两个数据的商(指定精度)", + }, + { + label: "modly", + value: "取两个数据的余数", + }, + { + label: "abs", + value: "计算数据绝对值", + }, + { + label: "greaterThan", + value: "判断数据1是否大于数据2", + }, + { + label: "greaterThanOrEqual", + value: "判断数据1是否大于等于数据2", + }, + { + label: "lessThan", + value: "判断数据1是否小于数据2", + }, + { + label: "lessThanOrEqual", + value: "判断数据1是否小于等于数据2", + }, + { + label: "equals", + value: "判断数据1是否等于数据2", + }, + { + label: "notEqual", + value: "判断数据1是否不等于数据2", + }, + ] + }, +] -export { tabListDisposition, tabListAction, stepAdd, stepUse, timeDivide } +export { tabListDisposition, tabListAction, stepAdd, stepUse, timeDivide,representationData }