From 4f2d13e6de729a08bf96a391fdd21f1cc8f48453 Mon Sep 17 00:00:00 2001
From: wujingjing <gersonwu@qq.com>
Date: 星期五, 20 九月 2024 13:03:28 +0800
Subject: [PATCH] 自动加注释

---
 src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue |  461 +++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 376 insertions(+), 85 deletions(-)

diff --git a/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue b/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue
index dbc68a5..08b1351 100644
--- a/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue
+++ b/src/views/project/yw/lowCode/sqlAmis/edit/SqlAmisEdit.vue
@@ -4,7 +4,7 @@
 			<template v-slot:left>
 				<el-button
 					icon="ele-ArrowLeft"
-					text
+					link
 					style="margin-right: 10px; margin-left: 10px; width: 40px"
 					size="small"
 					@click="backLastPage"
@@ -13,47 +13,92 @@
 			</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="queryId" label="鏌ヨ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">
-				<codemirror
-					class="h-full overflow-auto"
-					v-model="sqlCode"
-					:style="{ height: '100%' }"
-					:autofocus="true"
-					:indent-with-tab="true"
-					:tab-size="2"
-					:extensions="sqlEditorExtensions"
-					@change="log('change', $event)"
-					@focus="log('focus', $event)"
-					@blur="log('blur', $event)"
-				/>
-			</div>
-		</div>
+					<el-table-column prop="recordId" label="SQL id" />
+					<!-- <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>
+								<codemirror
+									class="overflow-auto"
+									style="height: calc(100% - 36px)"
+									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)"
+								/>
+							</template>
+						</div>
+					</Pane>
+				</Splitpanes>
+			</Pane>
+		</Splitpanes>
 	</div>
 </template>
 
@@ -62,20 +107,24 @@
 import { sql } from '@codemirror/lang-sql';
 import { xml } from '@codemirror/lang-xml';
 import { vscodeDark } from '@uiw/codemirror-theme-vscode';
-import _ from 'lodash';
-import { onMounted, ref } from 'vue';
-import { Codemirror } from 'vue-codemirror';
-import * as codeExample from './testData';
-import titleBox from '/@/components/titleBox.vue';
-
-import { v4 as uuid } from 'uuid';
-import { getAmisXml } from '/@/api/supervisorAdmin';
-import { useCompRef } from '/@/utils/types';
-import { XMLParser, XMLBuilder, XMLValidator } from 'fast-xml-parser';
+import type { TableInstance } from 'element-plus';
 import { ElMessage } 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';
 
 const props = defineProps(['supervisor']);
-const emit = defineEmits(['backLastPage']);
+const emit = defineEmits(['backLastPage', 'updatePublished']);
 const log = console.log;
 const jsonCode = ref(codeExample.jsonCode);
 const dockCode = ref(codeExample.dockCode);
@@ -89,17 +138,76 @@
 	configList.value = [];
 	sqlCode.value = '';
 };
+
+let defaultSelectDatabase = null;
+const databaseSelectChange = (val) => {
+	defaultSelectDatabase = val;
+	if (currentDockConfig.value) {
+		currentDockConfig.value.database = val;
+	}
+	updateSqlAndRs(currentDockConfig.value.id, currentDockConfig.value);
+};
 const backLastPage = () => {
 	// setTimeout(() => {
 	// 	resetStatus();
 	// }, 300);
 	emit('backLastPage');
 };
-const dockRowChange = (row) => {};
+const currentRs = ref<AmisDockConfig>(null);
+
+const getWithTemplateDataCommentSql = (sql: string, data: any) => {
+	if (!Array.isArray(data)) {
+		return sql;
+	}
+	const first = data[0];
+	if (!_.isObjectLike(first)) {
+		return sql;
+	}
+	const firstKeyList = Object.keys(first);
+	// 鍊间负瀵硅薄
+	if (_.isObjectLike(first[firstKeyList[0]])) {
+		return sql;
+	}
+
+	
+
+	let comment = '';
+	firstKeyList.map((key, index, array) => {
+		const value = JSON.stringify(first[key]);
+		comment += `-- "${key}": ${value}\n`;
+	});
+
+	const reg = new RegExp(`^\\s*(\\s*--\\s*".*"\\s*:.*\\n)+`)
+	// 宸茬粡瀛樺湪锛屼竴瀹氳鏇挎崲鎴愭渶鏂扮殑
+	if (reg.test(sql)) {
+		const replaceStr =  sql.replace(reg,comment);
+		return replaceStr;
+	}
+
+	const result = comment+sql;
+	return result;
+};
+const dockRowChange = (row) => {
+	currentRs.value = row;
+	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 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;
@@ -107,7 +215,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;
@@ -135,61 +243,244 @@
 };
 
 const enum AmisDockType {
-	Api,
+	Sql = 'SQL',
 }
 type AmisDockApi = string;
 type AmisDockValue = AmisDockApi;
 type AmisDockConfig = {
-	type: AmisDockType;
+	type?: AmisDockType;
 	path: string;
-	value: AmisDockValue;
-};
-
-type AmisDockSQLConfig = AmisDockConfig & {
-	queryId: string;
+	asyncId: string;
 	recordId: string;
+	// url: string;
 };
 
 const configList = ref<AmisDockConfig[]>([]);
-const parseJSONData = (json: string) => {
-	if (!json) return;
-	const obj = JSON.parse(json);
-	travelObj(obj, (key, value, path) => {
-		if (key === 'api') {
-			const url = value.url;
-			const urlPath = path + PATH_SEPARATOR + 'url';
-			const queryId = 'query_' + uuid().slice(0, 12);
 
+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 = [];
+	extraInfoMap.value.clear();
+	travelObj(obj, (key, value, path, item) => {
+		if (key === 'api') {
+			// const url = value.url;
+			const urlPath = path + PATH_SEPARATOR + 'url';
+			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()
-			configList.value.push({
-				queryId: queryId,
-				recordId: queryId,
-				type: AmisDockType.Api,
+			jsonConfigList.push({
+				asyncId: asyncId,
+				recordId: recordId,
+				type: AmisDockType.Sql,
 				path: urlPath,
-				value: url,
-				url: url,
-			} as any);
+			});
 		}
+	});
+
+	return jsonConfigList;
+};
+
+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 recordIds = apiConfig?.map((item) => item.recordId) ?? [];
+	// 杩囨护鍑� apiConfig 涓湁鐨剅ecord;
+	dockConfigList.value = dockConfigList.value?.filter((item) => recordIds.includes(item.id)) ?? [];
+	const asyncRsList = apiConfig.map((item) => ({
+		amis_path: item.path,
+		async_id: item.asyncId,
+		rec_id: item.recordId,
+	}));
+
+	if (id && sqlValue) {
+		const foundIndex = dockConfigList.value?.findIndex((item) => item.id === id);
+		if (foundIndex > -1) {
+			dockConfigList.value[foundIndex] = {
+				...dockConfigList.value[foundIndex],
+				...sqlValue,
+			};
+		} else {
+			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 {
+				dockConfigList.value.push(newSqlValue);
+			}
+		}
+	}
+
+	updateSqlApi(
+		{
+			id: props.supervisor.id,
+			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,
+		}
+	).then(() => {
+		emit('updatePublished', props.supervisor.id, SupervisorPublished.N);
 	});
 };
 
+const sqlCodeChange = debounce((val) => {
+	if (!currentRs.value.recordId) return;
+	if (currentDockConfig.value) {
+		if (!currentDockConfig.value.database) {
+			ElMessage.warning('璇峰厛閫夋嫨鏁版嵁搴�');
+			return;
+		}
+	}
+	updateSqlAndRs(currentDockConfig.value.id, currentDockConfig.value);
+}, 1000);
+const dockConfigList = ref([]);
+const rsTableRef = ref<TableInstance>(null);
+let xmlJson = null;
 
-const xmlParserInstance = new XMLParser();
-const xmlBuilderInstance = new XMLBuilder();
-let xmlConfig = null;
-onMounted(async () => {
-	xmlConfig = await getAmisXml({
-		agent_id: props.supervisor.id,
+// 妫�鏌ユ槸鍚﹂渶瑕佹洿鏂� rs
+const checkRsUpdate = (originData: AmisDockConfig[], currentData: AmisDockConfig[]) => {
+	// 閮戒负绌猴紝涓嶉渶瑕佹洿鏂�
+	if ((!originData || originData.length === 0) && (!currentData || currentData.length === 0)) {
+		return false;
+	}
+
+	// 瀛樺湪涓�鏂逛负绌猴紝闇�瑕佹洿鏂�
+	if (!originData || !currentData) {
+		return true;
+	}
+
+	// 闀垮害涓嶄竴鑷达紝闇�瑕佹洿鏂�
+	if (originData.length !== currentData.length) {
+		return true;
+	}
+
+	return originData.some((originItem) => {
+		const id = originItem.asyncId;
+		const currentItem = currentData.find((item) => item.asyncId === id);
+		// 娌℃壘鍒板搴旈」锛岄渶瑕佹洿鏂�
+		if (!currentItem) {
+			return true;
+		}
+
+		// 瀵硅薄椤瑰�间笉鐩哥瓑锛岄渶瑕佹洿鏂�
+		return Object.keys(currentItem).some((item) => originItem[item] !== currentItem[item]);
 	});
-	if (!xmlConfig?.amis_xml) {
-		// ElMessage.warning('鏆傛棤鏁版嵁');
-		return;
+};
+
+//#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);
 	}
-	const jObj = xmlParserInstance.parse(xmlConfig.amis_xml);
-	if (!jObj?.AMIS_JSON) {
-		return;
+
+	updateSqlAndRs();
+};
+
+const deleteArg = (index) => {
+	args.value.splice(index, 1);
+	updateSqlAndRs();
+};
+
+const databaseList = ref([]);
+//#endregion
+onMounted(async () => {
+	xmlJson = await supervisorApi.getLowCodeJson({
+		id: props.supervisor.id,
+	});
+
+	const originConfig =
+		xmlJson.async_rs?.map(
+			(item) =>
+				({
+					type: AmisDockType.Sql,
+					asyncId: item.async_id,
+					recordId: item.rec_id,
+					path: item.amis_path,
+				} as AmisDockConfig)
+		) ?? [];
+	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]);
 	}
-	const amisJSON = jObj.AMIS_JSON;
-	parseJSONData(amisJSON);
+
+	if (!configList || configList.value.length === 0) {
+		ElMessage.warning('鏆傛棤瀵规帴閰嶇疆');
+	}
+
+	const isRsUpdate = checkRsUpdate(originConfig, configList.value);
+	if (isRsUpdate) {
+		// 鑷姩鏇存柊Rs
+		updateSqlAndRs();
+	}
 });
+
+// watch(() => sqlCodemirrorRef.value, (codeMirrorRef) => {
+// 	codeMirrorRef.
+// })
 </script>

--
Gitblit v1.9.3