From 924f3850b1295e5f699bea843fcee83ae860feb6 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期五, 20 九月 2024 17:17:38 +0800 Subject: [PATCH] \\s* --- src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue | 456 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 376 insertions(+), 80 deletions(-) diff --git a/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue b/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue index c1aa22e..236e7b0 100644 --- a/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue +++ b/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue @@ -13,50 +13,142 @@ </template> </titleBox> - <div class="grid grid-cols-2 gap-2 h-full flex-auto"> - <div class="h-full overflow-auto"> + <Splitpanes class="default-theme flex-auto" :horizontal="false"> + <Pane :size="40" class="flex-column"> + <div class="flex-0 flex justify-between items-center mb-1 ml-1 h-[36px]"> + <span class="font-bold">閰嶇疆椤�</span> + </div> <el-table ref="rsTableRef" :data="configList" row-class-name="cursor-pointer" - class="h-full" + class="flex-auto" highlight-current-row @current-change="dockRowChange" > <el-table-column prop="asyncId" label="鏌ヨ id" /> - <el-table-column prop="path" label="閰嶇疆璺緞" /> - <el-table-column prop="recordId" label="SQL id" /> - <!-- <el-table-column prop="url" label="璇锋眰鍦板潃" /> --> - </el-table> - <!-- <codemirror - v-model="dockCode" - :style="{ height: '100%' }" - :autofocus="true" - :indent-with-tab="true" - :tab-size="2" - :extensions="dockEditorExtensions" - @change="log('change', $event)" - @focus="log('focus', $event)" - @blur="log('blur', $event)" - /> --> - </div> - <div class="h-full overflow-auto" v-if="currentSql"> - <codemirror - class="h-full overflow-auto" - v-model="currentSql.sql" - :style="{ height: '100%' }" - :autofocus="true" - :indent-with-tab="true" - :tab-size="2" - :extensions="sqlEditorExtensions" - @change="sqlCodeChange" - @focus="log('focus', $event)" - @blur="log('blur', $event)" - /> - </div> - </div> + <!-- <el-table-column label="璇锋眰鍦板潃" ></el-table-column> --> + </el-table></Pane + > + <Pane :size="60"> + <Splitpanes class="default-theme h100" :horizontal="true"> + <Pane :size="35" class="flex-col flex"> + <div class="flex-0 flex justify-between items-center mb-1 ml-1 h-[36px]"> + <span class="font-bold">鍙傛暟</span> + <el-button type="primary" @click="addArg">娣诲姞</el-button> + </div> + <el-table class="flex-auto" :data="args" border> + <el-table-column prop="name" width="150" label="鍚嶇О" show-overflow-tooltip> + <template #default="scope"> + <el-input v-model="scope.row.name" @input="argsInput"></el-input> + </template> + </el-table-column> + <el-table-column prop="prompt" width="450" label="鎻愮ず璇�" show-overflow-tooltip> + <template #default="scope"> + <el-input type="textarea" :rows="2" v-model="scope.row.prompt" @input="argsInput"></el-input> + </template> + </el-table-column> + <el-table-column prop="check" label="缂虹渷鍊�" show-overflow-tooltip> + <template #default="scope"> + <el-input v-model="scope.row.check" @input="argsInput"></el-input> + </template> + </el-table-column> + <el-table-column label="" width="55" fixed="right" show-overflow-tooltip> + <template #default="scope"> + <el-tooltip effect="dark" content="鍒犻櫎" placement="top"> + <i class="ywifont ywicon-shanchu !text-[17px] text-red-400 cursor-pointer" @click="deleteArg(scope.$index)"></i> + </el-tooltip> + </template> + </el-table-column> + </el-table> + </Pane> + <Pane :size="65"> + <div class="h-full"> + <template v-if="currentDockConfig"> + <div class="flex justify-between items-center my-1 ml-1 h-[36px]"> + <el-select class="w-52 font-bold" v-model="currentDockConfig.type"> + <el-option + v-for="item in Object.keys(amisDockTypeMap)" + :key="item" + :value="item" + :label="amisDockTypeMap[item]" + ></el-option> + </el-select> + + <el-select class="w-40" v-model="currentDockConfig.database" @change="databaseSelectChange"> + <el-option v-for="item in databaseList" :key="item.id" :value="item.id" :label="item.title"></el-option> + </el-select> + </div> + <el-tabs v-model="sqlActiveTab" class="overflow-auto" style="height: calc(100% - 36px)"> + <el-tab-pane :label="sqlTabMap[SqlTabType.LinkSql]" :name="SqlTabType.LinkSql" class="h-full"> + <codemirror + class="overflow-auto" + style="height: 100%" + v-model="currentDockConfig.sql" + :autofocus="true" + :indent-with-tab="true" + :tab-size="2" + :extensions="sqlEditorExtensions" + @change="sqlCodeChange" + @focus="log('focus', $event)" + @blur="log('blur', $event)" + /> + </el-tab-pane> + <el-tab-pane :label="sqlTabMap[SqlTabType.Others]" :name="SqlTabType.Others"> + <div class="flex-column"> + <div class="flex-0 flex mb-3.5"> + <el-button class="ml-auto" type="danger" @click="deleteUnLinkSql">鍒犻櫎鎵�鏈夋湭浣跨敤</el-button> + </div> + <el-table + ref="draggableTableRef" + class="flex-auto" + border + row-class-name="cursor-pointer" + :data="otherSqlList" + highlight-current-row + > + + <el-table-column prop="id" label="id" width="220" fixed="left" show-overflow-tooltip> </el-table-column> + <el-table-column label="鏁版嵁搴�" prop="database" show-overflow-tooltip> + + <template #default="scope"> + {{ getMapDatabase(scope.row.database)?.title }} + </template> + + </el-table-column> + + <el-table-column label="鎿嶄綔" width="120" fixed="right" show-overflow-tooltip> + <template #default="scope"> + <div class="space-x-3 items-center flex"> + <el-tooltip effect="dark" content="鏌ョ湅SQL" placement="top"> + <i + class="ywifont ywicon-didaima !text-[21px] text-blue-400 cursor-pointer" + @click="openShowSqlDlg(scope.row)" + ></i> + </el-tooltip> + <el-tooltip effect="dark" content="鍒犻櫎" placement="top"> + <i + class="ywifont ywicon-shanchu !text-[17px] text-red-400 cursor-pointer" + @click="deleteCurrentSql(scope.row)" + ></i> + </el-tooltip> + </div> + </template> + </el-table-column> + </el-table> + </div> + </el-tab-pane> + </el-tabs> + </template> + </div> + </Pane> + </Splitpanes> + </Pane> + </Splitpanes> + + <SqlCodeViewDlg v-model="optDlgIsShow" :item="optDlgMapRow"></SqlCodeViewDlg> </div> </template> @@ -65,19 +157,23 @@ import { sql } from '@codemirror/lang-sql'; import { xml } from '@codemirror/lang-xml'; import { vscodeDark } from '@uiw/codemirror-theme-vscode'; -import _, { debounce } from 'lodash'; -import { onMounted, ref } from 'vue'; -import { Codemirror } from 'vue-codemirror'; -import * as codeExample from './testData'; -import titleBox from '/@/components/titleBox.vue'; - import type { TableInstance } from 'element-plus'; -import { ElMessage } from 'element-plus'; +import { ElMessage, ElMessageBox } from 'element-plus'; +import _, { debounce } from 'lodash'; +import { Pane, Splitpanes } from 'splitpanes'; +import 'splitpanes/dist/splitpanes.css'; import { v4 as uuid } from 'uuid'; +import { onMounted, ref, watch } from 'vue'; +import { Codemirror } from 'vue-codemirror'; +import { SupervisorPublished } from '../types'; +import * as codeExample from './testData'; +import { amisDockTypeMap } from './types'; import * as supervisorApi from '/@/api/supervisorAdmin'; import { updateSqlApi } from '/@/api/supervisorAdmin'; +import titleBox from '/@/components/titleBox.vue'; import { useCompRef } from '/@/utils/types'; -import { SupervisorPublished } from '../types'; +import { computed } from 'vue'; +import SqlCodeViewDlg from './optDlg/SqlCodeViewDlg.vue'; const props = defineProps(['supervisor']); const emit = defineEmits(['backLastPage', 'updatePublished']); @@ -94,6 +190,16 @@ configList.value = []; sqlCode.value = ''; }; + +let defaultSelectDatabase = null; +const databaseSelectChange = (val) => { + defaultSelectDatabase = val; + if (currentDockConfig.value) { + currentDockConfig.value.database = val; + } + sqlActiveTab.value = SqlTabType.LinkSql; + updateSqlAndRs(currentDockConfig.value.id, currentDockConfig.value); +}; const backLastPage = () => { // setTimeout(() => { // resetStatus(); @@ -101,18 +207,72 @@ emit('backLastPage'); }; const currentRs = ref<AmisDockConfig>(null); +const otherSqlList = computed(() => { + const sqlConfig = dockConfigList.value.filter((item) => { + return item.type === AmisDockType.Sql; + }); + if (!currentDockConfig.value) { + return sqlConfig; + } + // 鎺掗櫎褰撳墠 + return sqlConfig.filter((item) => { + return currentDockConfig.value.id !== item.id; + }); +}); +const getWithTemplateDataCommentSql = (sql: string, data: any) => { + const reg = new RegExp(`^\\s*(\\s*--\\s*".*"\\s*:.*\\n)+\\s*`); + const isMatchReg = reg.test(sql); + if (!Array.isArray(data)) { + return isMatchReg ? sql.replace(reg, '') : sql; + } + const first = data[0]; + if (!_.isObjectLike(first)) { + return isMatchReg ? sql.replace(reg, '') : sql; + } + const firstKeyList = Object.keys(first); + // 鍊间负瀵硅薄 + if (_.isObjectLike(first[firstKeyList[0]])) { + return isMatchReg ? sql.replace(reg, '') : sql; + } + + let comment = ''; + firstKeyList.map((key, index, array) => { + const value = JSON.stringify(first[key]); + comment += `-- "${key}": ${value}\n`; + // 鏈�鍚庝竴涓啀鎹㈣ + comment += index === array.length - 1 ? '\n' : ''; + }); + + // 宸茬粡瀛樺湪锛屼竴瀹氳鏇挎崲鎴愭渶鏂扮殑 + if (isMatchReg) { + const replaceStr = sql.replace(reg, comment); + return replaceStr; + } + + const result = comment + sql; + return result; +}; const dockRowChange = (row) => { currentRs.value = row; - currentSql.value = sqlList.value.find((item) => item.id === currentRs.value.recordId) ?? { + currentDockConfig.value = dockConfigList.value.find((item) => item.id === currentRs.value.recordId) ?? { id: row.recordId, + type: AmisDockType.Sql, sql: '', + database: defaultSelectDatabase ?? databaseList.value[0]?.id ?? null, }; + const templateData = extraInfoMap.value.get(row.recordId).templateData; + + currentDockConfig.value.sql = getWithTemplateDataCommentSql(currentDockConfig.value.sql, templateData); }; -const currentSql = ref(null); +const currentDockConfig = ref(null); /** @description 璺緞鍒嗛殧绗� */ const PATH_SEPARATOR = '/'; /** @description 1 閫�鍑烘墍鏈夊惊鐜� -1閫�鍑哄綋娆″惊鐜� 0鎴栧叾浠栧�肩户缁� */ -const travelObj = (obj, callBack?: (key?: string, value?: any, path?: string) => 1 | -1 | undefined | void | 0, path = '') => { +const travelObj = ( + obj, + callBack?: (key?: string, value?: any, path?: string, item?: any) => 1 | -1 | undefined | void | 0, + path = '' +) => { let entry = Object.entries(obj); let res; @@ -120,7 +280,7 @@ iterate: for (const item of entry) { const [key, value] = item; const currentPath = path ? path + PATH_SEPARATOR + key : key; - res = callBack?.(key, value, currentPath); + res = callBack?.(key, value, currentPath, obj); switch (res) { case 1: break iterate; @@ -148,7 +308,7 @@ }; const enum AmisDockType { - Api, + Sql = 'SQL', } type AmisDockApi = string; type AmisDockValue = AmisDockApi; @@ -157,26 +317,50 @@ path: string; asyncId: string; recordId: string; + // url: string; }; const configList = ref<AmisDockConfig[]>([]); + +type ExtraInfo = { + url: string; + templateData: Array<any>; +}; +const extraInfoMap = ref(new Map<string, ExtraInfo>()); + +const getAmisData = (data) => { + if (!data) return null; + + const dataKeyList = Object.keys(data); + if (dataKeyList.length === 0) return null; + if (dataKeyList.length === 1) return data.items ?? data.rows ?? data; + + return data; +}; const parseJSONData = (obj: any, apiDataList) => { // 鍏堟竻绌� const jsonConfigList = []; - travelObj(obj, (key, value, path) => { + extraInfoMap.value.clear(); + travelObj(obj, (key, value, path, item) => { if (key === 'api') { // const url = value.url; const urlPath = path + PATH_SEPARATOR + 'url'; - const randomStr = 'query_' + uuid().slice(0, 12); + const randomStr = 'q_' + value.url + '_' + uuid().slice(0, 12); + const foundItem = apiDataList.find((item) => item.path === urlPath); const asyncId = foundItem?.asyncId ?? randomStr; const recordId = foundItem?.recordId ?? randomStr; + + extraInfoMap.value.set(recordId, { + url: value.url, + templateData: getAmisData(item.data), + }); // const recordId = uniqueId() jsonConfigList.push({ asyncId: asyncId, recordId: recordId, - type: AmisDockType.Api, + type: AmisDockType.Sql, path: urlPath, }); } @@ -185,32 +369,50 @@ return jsonConfigList; }; -const updateSqlAndRs = (id?, sqlValue?: string) => { - const apiConfig = configList.value.filter((item) => item.type === AmisDockType.Api); - if (apiConfig.length === 0) return; +const checkValid = (showTip: boolean, tip?: string) => { + if (!dockConfigList.value || dockConfigList.value.length === 0) return true; + const foundWithNoDatabase = dockConfigList.value?.find((item) => !item.database); + if (foundWithNoDatabase && showTip) { + ElMessage.warning(tip ?? `銆�${foundWithNoDatabase.id}銆戞湭閫夋嫨鏁版嵁搴揱); + } + return !foundWithNoDatabase; +}; + +const updateSqlAndRs = (id?, sqlValue?: { database?: string; sql?: string; type?: AmisDockType }) => { + const apiConfig = configList.value.filter((item) => item.type === AmisDockType.Sql); + + if (!checkValid(true)) { + return; + } + const asyncRsList = apiConfig.map((item) => ({ amis_path: item.path, async_id: item.asyncId, rec_id: item.recordId, })); - if (id) { - const found = sqlList.value?.find((item) => item.id === id); - if (found) { - found.sql = sqlValue; + if (id && sqlValue) { + const foundIndex = dockConfigList.value?.findIndex((item) => item.id === id); + if (foundIndex > -1) { + dockConfigList.value[foundIndex] = { + ...dockConfigList.value[foundIndex], + ...sqlValue, + }; } else { - if (!sqlList.value || sqlList.value.length === 0) { - sqlList.value = [ - { - id: id, - sql: sqlValue, - }, - ]; + if (!sqlValue.database) { + ElMessage.warning('璇峰厛閫夋嫨鏁版嵁搴�'); + return; + } + const newSqlValue = { + id: id, + database: sqlValue.database ?? null, + sql: sqlValue.sql ?? null, + type: sqlValue.type ?? AmisDockType.Sql, + }; + if (!dockConfigList.value || dockConfigList.value.length === 0) { + dockConfigList.value = [newSqlValue]; } else { - sqlList.value.push({ - id: id, - sql: sqlValue, - }); + dockConfigList.value.push(newSqlValue); } } } @@ -218,8 +420,9 @@ updateSqlApi( { id: props.supervisor.id, - sql_json: sqlList.value.length === 0 ? null : JSON.stringify(sqlList.value), + def_rs_json: dockConfigList.value.length === 0 ? null : JSON.stringify(dockConfigList.value), async_rs_json: asyncRsList.length === 0 ? null : JSON.stringify(asyncRsList), + args: args.value.length === 0 ? null : JSON.stringify(args.value), }, { loading: false, @@ -231,9 +434,15 @@ const sqlCodeChange = debounce((val) => { if (!currentRs.value.recordId) return; - updateSqlAndRs(currentRs.value.recordId, val); + if (currentDockConfig.value) { + if (!currentDockConfig.value.database) { + ElMessage.warning('璇峰厛閫夋嫨鏁版嵁搴�'); + return; + } + } + updateSqlAndRs(currentDockConfig.value.id, currentDockConfig.value); }, 1000); -const sqlList = ref([]); +const dockConfigList = ref([]); const rsTableRef = ref<TableInstance>(null); let xmlJson = null; @@ -266,36 +475,123 @@ return Object.keys(currentItem).some((item) => originItem[item] !== currentItem[item]); }); }; + +//#region ====================== 鍙紪杈戣〃鏍� ====================== +const args = ref([]); +const debounceUpdateInput = debounce(() => { + updateSqlAndRs(); +}, 400); +const argsInput = (val) => { + debounceUpdateInput(); +}; +const addArg = () => { + const initData = { + name: '', + prompt: '', + check: '', + }; + if (!args.value || args.value.length === 0) { + args.value = [initData]; + } else { + args.value.push(initData); + } + + updateSqlAndRs(); +}; + +const deleteArg = (index) => { + args.value.splice(index, 1); + updateSqlAndRs(); +}; + +const databaseList = ref([]); + +const getMapDatabase = (id:string)=>{ + const foundItem = databaseList.value.find(item=>item.id===id); + return foundItem; +} +//#endregion onMounted(async () => { xmlJson = await supervisorApi.getLowCodeJson({ id: props.supervisor.id, }); - if (!xmlJson?.amis_json) { - ElMessage.warning('鏆傛棤SQL閰嶇疆'); - return; - } + const originConfig = xmlJson.async_rs?.map( (item) => ({ - type: AmisDockType.Api, + type: AmisDockType.Sql, asyncId: item.async_id, recordId: item.rec_id, path: item.amis_path, } as AmisDockConfig) ) ?? []; - sqlList.value = xmlJson.sql ?? null; + dockConfigList.value = xmlJson.def_rs_json ?? null; + args.value = xmlJson.args ?? []; configList.value = parseJSONData(xmlJson.amis_json, originConfig); - + const res = await supervisorApi.getAmisDatabaseList(); + databaseList.value = res.values ?? []; if (configList.value.length > 0) { rsTableRef.value.setCurrentRow(configList.value[0]); - // dockRowChange(configList.value[0]); } - if (checkRsUpdate(originConfig, configList.value)) { + if (!configList || configList.value.length === 0) { + ElMessage.warning('鏆傛棤瀵规帴閰嶇疆'); + } + + const isRsUpdate = checkRsUpdate(originConfig, configList.value); + if (isRsUpdate) { // 鑷姩鏇存柊Rs updateSqlAndRs(); } }); +//#region ====================== sql 淇濆瓨鍘嗗彶 ====================== +const enum SqlTabType { + LinkSql = 'link-sql', + Others = 'sql-list', +} +const sqlTabMap = { + [SqlTabType.LinkSql]: '鍏宠仈SQL', + [SqlTabType.Others]: '鍏跺畠', +}; +const sqlActiveTab = ref<SqlTabType>(SqlTabType.LinkSql); + +// 鍒犻櫎褰撳墠 +const deleteCurrentSql = (row) => { + ElMessageBox.confirm('纭畾瑕佸垹闄ゅ綋鍓峉QL鍚楋紵', '鎻愮ず', { + confirmButtonText: '纭畾', + cancelButtonText: '鍙栨秷', + type: 'warning', + }).then(async () => { + dockConfigList.value = dockConfigList.value.filter((item) => item.id !== row.id); + updateSqlAndRs(); + }); +}; +// 鍒犻櫎鏈繛鎺� +const deleteUnLinkSql = () => { + ElMessageBox.confirm('纭畾瑕佸垹闄ゆ墍鏈夋湭浣跨敤鐨凷QL鍚楋紵', '鎻愮ず', { + confirmButtonText: '纭畾', + cancelButtonText: '鍙栨秷', + type: 'warning', + }).then(async () => { + const apiConfig = configList.value.filter((item) => item.type === AmisDockType.Sql); + const recordIds = apiConfig?.map((item) => item.recordId) ?? []; + // 杩囨护鍑� apiConfig 涓湁鐨剅ecord; + dockConfigList.value = dockConfigList.value?.filter((item) => recordIds.includes(item.id)) ?? []; + updateSqlAndRs(); + }); +}; + +const optDlgIsShow = ref(false); +const optDlgMapRow = ref(null); +const openShowSqlDlg = (row?: any) => { + optDlgMapRow.value = row; + optDlgIsShow.value = true; +}; + +//#endregion +// watch(() => sqlCodemirrorRef.value, (codeMirrorRef) => { +// codeMirrorRef. +// }) </script> -- Gitblit v1.9.3