Jelajahi Sumber

😎优化调整库表可视化(表关系图)

zuohuaijun 2 tahun lalu
induk
melakukan
00f5c6f304

+ 0 - 1
Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs

@@ -170,7 +170,6 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
 
             new SysMenu{ Id=1310000000601, Pid=0, Title="开发工具", Path="/develop", Name="develop", Component="Layout", Icon="ele-Cpu", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=13000 },
             new SysMenu{ Id=1310000000611, Pid=1310000000601, Title="库表管理", Path="/develop/database", Name="sysDatabase", Component="/system/database/index",Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
-            new SysMenu{ Id=1310000000651, Pid=1310000000601, Title="可视化库表管理", Path="/develop/visualdatabase", Name="sysVisualDatabase", Component="/system/database/visualdata",Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
             new SysMenu{ Id=1310000000621, Pid=1310000000601, Title="代码生成", Path="/develop/codeGen", Name="sysCodeGen", Component="/system/codeGen/index", Icon="ele-Crop", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
             new SysMenu{ Id=1310000000631, Pid=1310000000601, Title="表单设计", Path="/develop/formDes", Name="sysFormDes", Component="/system/formDes/index", Icon="ele-Edit", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 },
             new SysMenu{ Id=1310000000641, Pid=1310000000601, Title="系统接口", Path="/develop/api", Name="sysApi", Component="layout/routerView/iframe", IsIframe=true, OutLink="http://localhost:5005", Icon="ele-Help", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },

+ 4 - 4
Web/package.json

@@ -14,7 +14,7 @@
 		"@element-plus/icons-vue": "^2.3.1",
 		"@microsoft/signalr": "^8.0.0",
 		"@vue-office/docx": "^1.6.0",
-		"@vue-office/excel": "^1.7.0",
+		"@vue-office/excel": "^1.7.1",
 		"@vue-office/pdf": "^1.6.4",
 		"@wangeditor/editor": "^5.1.23",
 		"@wangeditor/editor-for-vue": "^5.1.12",
@@ -58,7 +58,7 @@
 	},
 	"devDependencies": {
 		"@types/lodash-es": "^4.17.12",
-		"@types/node": "^20.11.26",
+		"@types/node": "^20.11.28",
 		"@types/nprogress": "^0.2.3",
 		"@types/sortablejs": "^1.15.8",
 		"@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -66,12 +66,12 @@
 		"@vitejs/plugin-vue": "^5.0.4",
 		"@vitejs/plugin-vue-jsx": "^3.1.0",
 		"@vue/compiler-sfc": "^3.4.21",
-		"code-inspector-plugin": "^0.9.3",
+		"code-inspector-plugin": "^0.10.0",
 		"eslint": "^8.57.0",
 		"eslint-plugin-vue": "^9.23.0",
 		"less": "^4.2.0",
 		"prettier": "^3.2.5",
-		"sass": "^1.71.1",
+		"sass": "^1.72.0",
 		"typescript": "^5.4.2",
 		"vite": "^5.1.6",
 		"vite-plugin-cdn-import": "^0.3.5",

+ 13 - 0
Web/src/router/route.ts

@@ -62,6 +62,19 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
 			icon: 'ele-Clock',
 		},
 	},
+	{
+		path: '/develop/database/visual',
+		name: 'databaseVisual',
+		component: () => import('/@/views/system/database/component/visualTable.vue'),
+		meta: {
+			title: '库表可视化',
+			isHide: true,
+			isKeepAlive: true,
+			isAffix: false,
+			// isIframe: true,
+			icon: 'ele-View',
+		},
+	},
 ];
 
 /**

+ 282 - 0
Web/src/views/system/database/component/visualTable.vue

@@ -0,0 +1,282 @@
+<template>
+	<div class="sys-databaseVisual-container">
+		<div style="height: calc(100vh - 60px)">
+			<RelationGraph ref="graphRef" :options="graphOptions" :on-node-click="onNodeClick" :on-line-click="onLineClick">
+				<template #graph-plug>
+					<!-- To facilitate understanding, the CSS style code is directly embedded here. -->
+					<div
+						style="
+							z-index: 300;
+							position: absolute;
+							left: 10px;
+							top: calc(100% - 50px);
+							font-size: 12px;
+							background-color: #ffffff;
+							border: #efefef solid 1px;
+							border-radius: 10px;
+							width: 260px;
+							height: 40px;
+							display: flex;
+							align-items: center;
+							justify-content: center;
+						"
+					>
+						图例:
+						<div>
+							一对多
+							<div style="height: 5px; width: 80px; background-color: rgba(159, 23, 227, 0.65)"></div>
+						</div>
+						<div style="margin-left: 10px">
+							一对一
+							<div style="height: 5px; width: 80px; background-color: rgba(29, 169, 245, 0.76)"></div>
+						</div>
+					</div>
+				</template>
+				<template #canvas-plug>
+					<!--- You can put some elements that are not allowed to be dragged here --->
+				</template>
+				<template #node="{ node }">
+					<div style="width: 300px; background-color: #f39930">
+						<!---------------- if node a ---------------->
+						<div>{{ node.text }} - {{ node.data.columns.length }} Cols</div>
+						<table class="c-data-table">
+							<tr>
+								<th>Column Name</th>
+								<th>Data Type</th>
+							</tr>
+							<template v-for="column of node.data.columns" :key="column.columnName">
+								<tr>
+									<td>
+										<div :id="`${node.id}-${column.columnName}`">{{ column.columnName }}</div>
+									</td>
+									<td>{{ column.dataType }}</td>
+								</tr>
+							</template>
+						</table>
+					</div>
+				</template>
+			</RelationGraph>
+		</div>
+	</div>
+</template>
+
+<script lang="ts" setup name="databaseVisual">
+import { onMounted, reactive, ref } from 'vue';
+import { useRoute } from 'vue-router';
+
+import RelationGraph from 'relation-graph/vue3';
+import type { RGOptions, RGNode, RGLine, RGLink, RGUserEvent, RGJsonData, RelationGraphComponent } from 'relation-graph/vue3';
+
+// import { getAPI } from '/@/utils/axios-utils';
+// import { SysDatabaseApi } from '/@/api-services/api';
+import { DbColumnOutput, DbTableInfo } from '/@/api-services/models';
+
+const route = useRoute();
+const state = reactive({
+	loading: false,
+	loading1: false,
+	dbData: [] as any,
+	configId: '' as any,
+	tableData: [] as Array<DbTableInfo>,
+	visualTable: [],
+	visualRTable: [],
+	tableName: '',
+	columnData: [] as Array<DbColumnOutput>,
+	queryParams: {
+		name: undefined,
+		code: undefined,
+	},
+	editPosTitle: '',
+	appNamespaces: [] as Array<String>, // 存储位置
+	//graphOptions: {
+	//    defaultNodeBorderWidth: 0,
+	//    defaultNodeColor: "rgba(238, 178, 94, 1)",
+	//    allowSwitchLineShape: true,
+	//    allowSwitchJunctionPoint: true,
+	//    defaultLineShape: 1,
+	//    layouts: [
+	//      {
+	//        label: "自动布局",
+	//        layoutName: "force",
+	//        layoutClassName: "seeks-layout-force",
+	//        distance_coefficient: 3
+	//      },
+	//    ],
+	//    defaultJunctionPoint: "border",
+	//  },
+});
+
+onMounted(async () => {
+	state.configId = route.query.configId;
+	console.log(state.configId);
+
+	showGraph();
+});
+
+// // 获取可视化表和字段
+// const getVisualTableList = async () => {
+// 	state.columnData = [];
+// 	if (state.tableName == '') return;
+
+// 	state.loading1 = true;
+// 	var res = await getAPI(SysDatabaseApi).apiGetVisualTableList();
+// 	state.columnData = res.data.result ?? [];
+// 	state.loading1 = false;
+// };
+
+// // 获取可视化表关系
+// const getVisualRTableList = async () => {
+// 	state.columnData = [];
+// 	if (state.tableName == '') return;
+
+// 	state.loading1 = true;
+// 	var res = await getAPI(SysDatabaseApi).apiGetVisualRTableList();
+// 	state.columnData = res.data.result ?? [];
+// 	state.loading1 = false;
+// };
+
+const graphRef = ref<RelationGraphComponent | null>(null);
+const graphOptions: RGOptions = {
+	debug: false,
+	allowSwitchLineShape: true,
+	allowSwitchJunctionPoint: true,
+	allowShowDownloadButton: true,
+	defaultJunctionPoint: 'border',
+	// placeOtherNodes: false,
+	placeSingleNode: false,
+	graphOffset_x: -200,
+	graphOffset_y: 100,
+	defaultLineMarker: {
+		markerWidth: 20,
+		markerHeight: 20,
+		refX: 3,
+		refY: 3,
+		data: 'M 0 0, V 6, L 4 3, Z',
+	},
+	layout: {
+		layoutName: 'fixed',
+	},
+	// You can refer to the parameters in "Graph" for setting here
+};
+
+const showGraph = async () => {
+	const tables = [
+		{ tableName: 'SYS_USER', tableComents: 'SYS_USER comments', x: 500, y: -300 },
+		{ tableName: 'SYS_DEPT', tableComents: 'SYS_DEPT comments', x: 0, y: -300 },
+		{ tableName: 'SYS_ROLE', tableComents: 'SYS_ROLE comments', x: 0, y: 0 },
+		{ tableName: 'SYS_USER_ROLE', tableComents: 'SYS_USER_ROLE comments', x: 500, y: 0 },
+		{ tableName: 'SYS_RESOURCE', tableComents: 'SYS_RESOURCE comments', x: 0, y: 300 },
+		{ tableName: 'SYS_ROLE_RESOURCE', tableComents: 'SYS_ROLE_RESOURCE comments', x: 500, y: 300 },
+	];
+	const tableCols = [
+		{ tableName: 'SYS_USER', columnName: 'id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_USER', columnName: 'user_name', dataType: 'varchar(50)' },
+		{ tableName: 'SYS_USER', columnName: 'dept_id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_USER', columnName: 'create_time', dataType: 'TIMESTAMP' },
+		{ tableName: 'SYS_USER', columnName: 'status', dataType: 'varchar(1)' },
+		{ tableName: 'SYS_DEPT', columnName: 'id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_DEPT', columnName: 'dept_name', dataType: 'varchar(50)' },
+		{ tableName: 'SYS_DEPT', columnName: 'parent_dept_id', dataType: 'varchar(50)' },
+		{ tableName: 'SYS_DEPT', columnName: 'create_time', dataType: 'TIMESTAMP' },
+		{ tableName: 'SYS_DEPT', columnName: 'status', dataType: 'varchar(50)' },
+		{ tableName: 'SYS_ROLE', columnName: 'id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_ROLE', columnName: 'role_name', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_ROLE', columnName: 'create_time', dataType: 'TIMESTAMP' },
+		{ tableName: 'SYS_USER_ROLE', columnName: 'id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_USER_ROLE', columnName: 'user_id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_USER_ROLE', columnName: 'role_id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_USER_ROLE', columnName: 'create_time', dataType: 'TIMESTAMP' },
+		{ tableName: 'SYS_USER_ROLE', columnName: 'status', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_RESOURCE', columnName: 'id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_RESOURCE', columnName: 'resource_name', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_RESOURCE', columnName: 'create_time', dataType: 'TIMESTAMP' },
+		{ tableName: 'SYS_ROLE_RESOURCE', columnName: 'id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_ROLE_RESOURCE', columnName: 'role_id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_ROLE_RESOURCE', columnName: 'resource_id', dataType: 'varchar(36)' },
+		{ tableName: 'SYS_ROLE_RESOURCE', columnName: 'status', dataType: 'varchar(1)' },
+	];
+	const columnRelations = [
+		{ sourceTableName: 'SYS_USER', sourceColumnName: 'dept_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_DEPT', targetColumnName: 'id' },
+		{ sourceTableName: 'SYS_DEPT', sourceColumnName: 'parent_dept_id', type: 'ONE_TO_ONE', targetTableName: 'SYS_DEPT', targetColumnName: 'id' },
+		{ sourceTableName: 'SYS_USER_ROLE', sourceColumnName: 'user_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_USER', targetColumnName: 'id' },
+		{ sourceTableName: 'SYS_USER_ROLE', sourceColumnName: 'role_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_ROLE', targetColumnName: 'id' },
+		{ sourceTableName: 'SYS_ROLE_RESOURCE', sourceColumnName: 'role_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_ROLE', targetColumnName: 'id' },
+		{ sourceTableName: 'SYS_ROLE_RESOURCE', sourceColumnName: 'resource_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_RESOURCE', targetColumnName: 'id' },
+	];
+	const graphNodes = tables.map((table) => {
+		const { tableName, tableComents, x, y } = table;
+		return {
+			id: tableName,
+			text: tableComents,
+			x,
+			y,
+			nodeShape: 1,
+			data: {
+				// Costomer key have to in data
+
+				columns: tableCols.filter((col) => col.tableName === table.tableName),
+			},
+		};
+	});
+	const graphLines = columnRelations.map((relation) => {
+		return {
+			from: relation.sourceTableName + '-' + relation.sourceColumnName, // HtmlElement id
+
+			to: relation.targetTableName + '-' + relation.targetColumnName, // HtmlElement id
+
+			color: relation.type === 'ONE_TO_ONE' ? 'rgba(29,169,245,0.76)' : 'rgba(159,23,227,0.65)',
+			text: '',
+			fromJunctionPoint: 'left',
+			toJunctionPoint: 'lr',
+			lineShape: 6,
+			lineWidth: 3,
+		};
+	});
+	const graphJsonData: RGJsonData = {
+		nodes: graphNodes,
+		lines: [],
+		elementLines: graphLines,
+	};
+	const graphInstance = graphRef.value?.getInstance();
+	if (graphInstance) {
+		await graphInstance.setJsonData(graphJsonData);
+		await graphInstance.moveToCenter();
+		await graphInstance.zoomToFit();
+	}
+};
+
+const onNodeClick = (nodeObject: RGNode, $event: RGUserEvent) => {
+	console.log('onNodeClick:', nodeObject);
+};
+
+const onLineClick = (lineObject: RGLine, linkObject: RGLink, $event: RGUserEvent) => {
+	console.log('onLineClick:', lineObject);
+};
+</script>
+
+<style lang="scss" scoped>
+::v-deep(.relation-graph) {
+	.rel-node-shape-1 {
+		overflow: hidden;
+	}
+}
+.c-data-table {
+	background-color: #ffffff;
+	border-collapse: collapse;
+	width: 100%;
+}
+.c-data-table td,
+.c-data-table th {
+	border: 1px solid #f39930;
+	color: #333333;
+	padding: 5px;
+	padding-left: 20px;
+	padding-right: 20px;
+}
+.c-data-table td div,
+.c-data-table th div {
+	background-color: #1da9f5;
+	color: #ffffff;
+	border-radius: 5px;
+}
+</style>

+ 54 - 13
Web/src/views/system/database/index.vue

@@ -13,12 +13,17 @@
 					</el-select>
 				</el-form-item>
 				<el-form-item>
-					<el-button icon="ele-Edit" type="primary" @click="openEditTable"> 编辑表 </el-button>
-					<el-button icon="ele-Delete" type="danger" @click="delTable"> 删除表 </el-button>
-					<el-button icon="ele-Plus" @click="openAddTable"> 增加表 </el-button>
-					<el-button icon="ele-Plus" @click="openAddColumn"> 增加列 </el-button>
-					<el-button icon="ele-Plus" @click="openGenDialog"> 生成实体 </el-button>
-					<el-button icon="ele-Plus" @click="openGenSeedDataDialog"> 生成种子数据 </el-button>
+					<el-button-group>
+						<el-button icon="ele-Plus" type="primary" @click="openAddTable"> 增加表 </el-button>
+						<el-button icon="ele-Edit" @click="openEditTable"> 编辑表 </el-button>
+						<el-button icon="ele-Delete" type="danger" @click="delTable"> 删除表 </el-button>
+						<el-button icon="ele-View" @click="visualTable"> 可视化 </el-button>
+					</el-button-group>
+					<el-button-group style="padding-left: 10px">
+						<el-button icon="ele-Plus" @click="openAddColumn"> 增加列 </el-button>
+						<el-button icon="ele-Plus" @click="openGenDialog"> 生成实体 </el-button>
+						<el-button icon="ele-Plus" @click="openGenSeedDataDialog"> 生成种子 </el-button>
+					</el-button-group>
 				</el-form-item>
 			</el-form>
 		</el-card>
@@ -50,7 +55,7 @@
 				<el-table-column prop="decimalDigits" label="精度" width="70" align="center" show-overflow-tooltip />
 				<el-table-column prop="defaultValue" label="默认值" align="center" show-overflow-tooltip />
 				<el-table-column prop="columnDescription" label="描述" header-align="center" show-overflow-tooltip />
-				<el-table-column label="操作" width="140" fixed="right" align="center" show-overflow-tooltip>
+				<el-table-column label="操作" width="145" fixed="right" align="center" show-overflow-tooltip>
 					<template #default="scope">
 						<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditColumn(scope.row)"> 编辑 </el-button>
 						<el-button icon="ele-Delete" size="small" text type="danger" @click="delColumn(scope.row)"> 删除 </el-button>
@@ -71,6 +76,7 @@
 <script lang="ts" setup name="sysDatabase">
 import { onMounted, reactive, ref } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
+import { useRouter } from 'vue-router';
 import EditTable from '/@/views/system/database/component/editTable.vue';
 import EditColumn from '/@/views/system/database/component/editColumn.vue';
 import AddTable from '/@/views/system/database/component/addTable.vue';
@@ -88,6 +94,7 @@ const addTableRef = ref<InstanceType<typeof AddTable>>();
 const addColumnRef = ref<InstanceType<typeof AddColumn>>();
 const genEntityRef = ref<InstanceType<typeof GenEntity>>();
 const genSeedDataRef = ref<InstanceType<typeof GenSeedData>>();
+const router = useRouter();
 const state = reactive({
 	loading: false,
 	loading1: false,
@@ -145,8 +152,13 @@ const handleQueryColumn = async () => {
 
 // 打开表编辑页面
 const openEditTable = () => {
-	if (state.configId == '' || state.tableName == '') return;
-
+	if (state.configId == '' || state.tableName == '') {
+		ElMessage({
+			type: 'error',
+			message: `请选择库名和表名!`,
+		});
+		return;
+	}
 	var res = state.tableData.filter((u: any) => u.name == state.tableName);
 	var table: any = {
 		configId: state.configId,
@@ -159,8 +171,13 @@ const openEditTable = () => {
 
 // 打开实体生成页面
 const openGenDialog = () => {
-	if (state.configId == '' || state.tableName == '') return;
-
+	if (state.configId == '' || state.tableName == '') {
+		ElMessage({
+			type: 'error',
+			message: `请选择库名和表名!`,
+		});
+		return;
+	}
 	// var res = state.tableData.filter((u: any) => u.name == state.tableName);
 	var table: any = {
 		configId: state.configId,
@@ -172,7 +189,13 @@ const openGenDialog = () => {
 
 // 生成种子数据页面
 const openGenSeedDataDialog = () => {
-	if (state.configId == '' || state.tableName == '') return;
+	if (state.configId == '' || state.tableName == '') {
+		ElMessage({
+			type: 'error',
+			message: `请选择库名和表名!`,
+		});
+		return;
+	}
 	var table: any = {
 		configId: state.configId,
 		tableName: state.tableName,
@@ -190,7 +213,6 @@ const openAddTable = () => {
 		});
 		return;
 	}
-
 	var table: any = {
 		configId: state.configId,
 		tableName: '',
@@ -241,6 +263,13 @@ const openAddColumn = () => {
 
 // 删除表
 const delTable = () => {
+	if (state.tableName == '') {
+		ElMessage({
+			type: 'error',
+			message: `请选择表名!`,
+		});
+		return;
+	}
 	ElMessageBox.confirm(`确定删除表:【${state.tableName}】?`, '提示', {
 		confirmButtonText: '确定',
 		cancelButtonText: '取消',
@@ -277,4 +306,16 @@ const delColumn = (row: any) => {
 		})
 		.catch(() => {});
 };
+
+// 可视化表
+const visualTable = () => {
+	if (state.configId == '') {
+		ElMessage({
+			type: 'error',
+			message: `请选择库名!`,
+		});
+		return;
+	}
+	router.push(`/develop/database/visual?configId=${state.configId}`);
+};
 </script>

+ 0 - 486
Web/src/views/system/database/visualdata.vue

@@ -1,486 +0,0 @@
-<template>
-	<div class="sys-database-container">
-		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
-			<el-form :model="state.queryParams" ref="queryForm" :inline="true" v-loading="state.loading">
-				<el-form-item label="库名">
-					<el-select v-model="state.configId" placeholder="库名" filterable @change="handleQueryTable">
-						<el-option v-for="item in state.dbData" :key="item" :label="item" :value="item" />
-					</el-select>
-				</el-form-item>
-				<el-form-item label="表名">
-					<el-select v-model="state.tableName" placeholder="表名" filterable clearable @change="handleQueryColumn">
-						<el-option v-for="item in state.tableData" :key="item.name" :label="item.name + '[' + item.description + ']'" :value="item.name" />
-					</el-select>
-				</el-form-item>
-				<el-form-item>
-					<el-button icon="ele-Edit" type="primary" @click="openEditTable"> 编辑表 </el-button>
-					<el-button icon="ele-Delete" type="danger" @click="delTable"> 删除表 </el-button>
-					<el-button icon="ele-Plus" @click="openAddTable"> 增加表 </el-button>
-					<el-button icon="ele-Plus" @click="openAddColumn"> 增加列 </el-button>
-					<el-button icon="ele-Plus" @click="openGenDialog"> 生成实体 </el-button>
-					<el-button icon="ele-Plus" @click="openGenSeedDataDialog"> 生成种子数据 </el-button>
-				</el-form-item>
-			</el-form>
-		</el-card>
-
-    <div style="height:calc(100vh - 60px);">
-      <RelationGraph
-
-        ref="graphRef"
-        :options="graphOptions"
-        :on-node-click="onNodeClick"
-        :on-line-click="onLineClick">
-        <template #graph-plug>
-          <!-- To facilitate understanding, the CSS style code is directly embedded here. -->
-          <div style="z-index: 300;position: absolute;left:10px; top: calc(100% - 50px);font-size: 12px;background-color: #ffffff;border:#efefef solid 1px;border-radius: 10px;width:260px;height:40px;display: flex;align-items: center;justify-content: center;">
-            Legend:
-            <div>
-              More to one
-
-              <div style="height:5px;width:80px;background-color: rgba(159,23,227,0.65);"></div>
-            </div>
-            <div style="margin-left:10px;">
-              One to one
-
-              <div style="height:5px;width:80px;background-color: rgba(29,169,245,0.76);"></div>
-            </div>
-          </div>
-        </template>
-        <template #canvas-plug>
-          <!--- You can put some elements that are not allowed to be dragged here --->
-        </template>
-        <template #node="{node}">
-          <div style="width: 300px;background-color: #f39930"><!---------------- if node a ---------------->
-            <div>{{node.text}} - {{node.data.columns.length}} Cols</div>
-            <table class="c-data-table">
-              <tr>
-                <th>Column Name</th>
-                <th>Data Type</th>
-              </tr>
-              <template v-for="column of node.data.columns" :key="column.columnName">
-                <tr>
-                  <td><div :id="`${node.id}-${column.columnName}`">{{column.columnName}}</div></td>
-                  <td>{{column.dataType}}</td>
-                </tr>
-              </template>
-            </table>
-          </div>
-        </template>
-      </RelationGraph>
-    </div>
-  </div>
-</template>
-     
-
-<script lang="ts" setup name="sysDatabase">
-import { onMounted, reactive, ref,defineComponent } from 'vue';
-import { ElMessageBox, ElMessage } from 'element-plus';
-
-import RelationGraph from 'relation-graph/vue3';
-import type { RGOptions, RGNode, RGLine, RGLink, RGUserEvent, RGJsonData, RelationGraphComponent } from 'relation-graph/vue3';
-import EditTable from '/@/views/system/database/component/editTable.vue';
-import EditColumn from '/@/views/system/database/component/editColumn.vue';
-import AddTable from '/@/views/system/database/component/addTable.vue';
-import AddColumn from '/@/views/system/database/component/addColumn.vue';
-import GenEntity from '/@/views/system/database/component/genEntity.vue';
-import GenSeedData from '/@/views/system/database/component/genSeedData.vue';
-
-import { getAPI } from '/@/utils/axios-utils';
-import { SysDatabaseApi, SysCodeGenApi } from '/@/api-services/api';
-import { DbColumnOutput, DbTableInfo, DbColumnInput, DeleteDbTableInput, DeleteDbColumnInput } from '/@/api-services/models';
-
-
-
-const editTableRef = ref<InstanceType<typeof EditTable>>();
-const editColumnRef = ref<InstanceType<typeof EditColumn>>();
-const addTableRef = ref<InstanceType<typeof AddTable>>();
-const addColumnRef = ref<InstanceType<typeof AddColumn>>();
-const genEntityRef = ref<InstanceType<typeof GenEntity>>();
-const genSeedDataRef = ref<InstanceType<typeof GenSeedData>>();
-const state = reactive({
-	loading: false,
-	loading1: false,
-	dbData: [] as any,
-	configId: '',
-	tableData: [] as Array<DbTableInfo>,
-	visualTable: [],
-	visualRTable: [],
-	tableName: '',
-	columnData: [] as Array<DbColumnOutput>,
-	queryParams: {
-		name: undefined,
-		code: undefined,
-	},
-	editPosTitle: '',
-	appNamespaces: [] as Array<String>, // 存储位置
-	//graphOptions: {
-    //    defaultNodeBorderWidth: 0,
-    //    defaultNodeColor: "rgba(238, 178, 94, 1)",
-    //    allowSwitchLineShape: true,
-    //    allowSwitchJunctionPoint: true,
-    //    defaultLineShape: 1,
-    //    layouts: [
-    //      {
-    //        label: "自动布局",
-    //        layoutName: "force",
-    //        layoutClassName: "seeks-layout-force",
-    //        distance_coefficient: 3
-    //      },
-    //    ],
-    //    defaultJunctionPoint: "border",
-    //  },
-});
-
-onMounted(async () => {
-	showGraph();
-	state.loading = true;
-	var res = await getAPI(SysDatabaseApi).apiSysDatabaseListGet();
-	state.dbData = res.data.result;
-	state.loading = false;
-
-	let appNamesRes = await getAPI(SysCodeGenApi).apiSysCodeGenApplicationNamespacesGet();
-	state.appNamespaces = appNamesRes.data.result as Array<string>;
-});
-
-// 增加表
-const addTableSubmitted = (e: any) => {
-	handleQueryTable();
-	state.tableName = e;
-	handleQueryColumn();
-};
-
-// 表查询操作
-const handleQueryTable = async () => {
-	state.tableName = '';
-	state.columnData = [];
-	state.loading = true;
-
-	var resVisualTable = await getAPI(SysDatabaseApi).apiGetVisualTableList(state.configId);
-	state.visualTable = resVisualTable.data.result ?? [];
-	var resVisualRTable = await getAPI(SysDatabaseApi).apiGetVisualRTableList(state.configId);
-	state.visualRTable = resVisualRTable.data.result ?? [];
-
-	var res = await getAPI(SysDatabaseApi).apiSysDatabaseTableListConfigIdGet(state.configId);
-	state.tableData = res.data.result ?? [];
-	state.loading = false;
-};
-
-// 列查询操作
-const handleQueryColumn = async () => {
-	state.columnData = [];
-	if (state.tableName == '') return;
-
-	state.loading1 = true;
-	var res = await getAPI(SysDatabaseApi).apiSysDatabaseColumnListTableNameConfigIdGet(state.tableName, state.configId);
-	state.columnData = res.data.result ?? [];
-	state.loading1 = false;
-};
-
-// 获取可视化表和字段
-const getVisualTableList = async () => {
-	state.columnData = [];
-	if (state.tableName == '') return;
-
-	state.loading1 = true;
-	var res = await getAPI(SysDatabaseApi).apiGetVisualTableList();
-	state.columnData = res.data.result ?? [];
-	state.loading1 = false;
-};
-
-// 获取可视化表关系
-const getVisualRTableList = async () => {
-	state.columnData = [];
-	if (state.tableName == '') return;
-
-	state.loading1 = true;
-	var res = await getAPI(SysDatabaseApi).apiGetVisualRTableList();
-	state.columnData = res.data.result ?? [];
-	state.loading1 = false;
-};
-
-
-// 打开表编辑页面
-const openEditTable = () => {
-	if (state.configId == '' || state.tableName == '') return;
-
-	var res = state.tableData.filter((u: any) => u.name == state.tableName);
-	var table: any = {
-		configId: state.configId,
-		tableName: state.tableName,
-		oldTableName: state.tableName,
-		description: res[0].description,
-	};
-	editTableRef.value?.openDialog(table);
-};
-
-// 打开实体生成页面
-const openGenDialog = () => {
-	if (state.configId == '' || state.tableName == '') return;
-
-	// var res = state.tableData.filter((u: any) => u.name == state.tableName);
-	var table: any = {
-		configId: state.configId,
-		tableName: state.tableName,
-		position: state.appNamespaces[0],
-	};
-	genEntityRef.value?.openDialog(table);
-};
-
-// 生成种子数据页面
-const openGenSeedDataDialog = () => {
-	if (state.configId == '' || state.tableName == '') return;
-	var table: any = {
-		configId: state.configId,
-		tableName: state.tableName,
-		position: state.appNamespaces[0],
-	};
-	genSeedDataRef.value?.openDialog(table);
-};
-
-// 打开表增加页面
-const openAddTable = () => {
-	if (state.configId == '') {
-		ElMessage({
-			type: 'error',
-			message: `请选择库名!`,
-		});
-		return;
-	}
-
-	var table: any = {
-		configId: state.configId,
-		tableName: '',
-		oldTableName: '',
-		description: '',
-	};
-	addTableRef.value?.openDialog(table);
-};
-
-// 打开列编辑页面
-const openEditColumn = (row: any) => {
-	var column: any = {
-		configId: state.configId,
-		tableName: row.tableName,
-		columnName: row.dbColumnName,
-		oldColumnName: row.dbColumnName,
-		description: row.columnDescription,
-	};
-	editColumnRef.value?.openDialog(column);
-};
-
-// 打开列增加页面
-const openAddColumn = () => {
-	if (state.configId == '' || state.tableName == '') {
-		ElMessage({
-			type: 'error',
-			message: `请选择库名和表名!`,
-		});
-		return;
-	}
-	const addRow: DbColumnInput = {
-		configId: state.configId,
-		tableName: state.tableName,
-		columnDescription: '',
-		dataType: '',
-		dbColumnName: '',
-		decimalDigits: 0,
-		isIdentity: 0,
-		isNullable: 0,
-		isPrimarykey: 0,
-		length: 0,
-		// key: 0,
-		// editable: true,
-		// isNew: true,
-	};
-	addColumnRef.value?.openDialog(addRow);
-};
-
-// 删除表
-const delTable = () => {
-	ElMessageBox.confirm(`确定删除表:【${state.tableName}】?`, '提示', {
-		confirmButtonText: '确定',
-		cancelButtonText: '取消',
-		type: 'warning',
-	})
-		.then(async () => {
-			const deleteDbTableInput: DeleteDbTableInput = {
-				configId: state.configId,
-				tableName: state.tableName,
-			};
-			await getAPI(SysDatabaseApi).apiSysDatabaseDeleteTablePost(deleteDbTableInput);
-			handleQueryTable();
-			ElMessage.success('表删除成功');
-		})
-		.catch(() => {});
-};
-
-// 删除列
-const delColumn = (row: any) => {
-	ElMessageBox.confirm(`确定删除列:【${row.dbColumnName}】?`, '提示', {
-		confirmButtonText: '确定',
-		cancelButtonText: '取消',
-		type: 'warning',
-	})
-		.then(async () => {
-			const eleteDbColumnInput: DeleteDbColumnInput = {
-				configId: state.configId,
-				tableName: state.tableName,
-				dbColumnName: row.dbColumnName,
-			};
-			await getAPI(SysDatabaseApi).apiSysDatabaseDeleteColumnPost(eleteDbColumnInput);
-			handleQueryTable();
-			ElMessage.success('列删除成功');
-		})
-		.catch(() => {});
-};
-
-
-const graphRef = ref<RelationGraphComponent | null>(null);
-const graphOptions: RGOptions = {
-    debug: false,
-    allowSwitchLineShape: true,
-    allowSwitchJunctionPoint: true,
-    allowShowDownloadButton: true,
-    defaultJunctionPoint: 'border',
-    placeOtherNodes: false,
-    placeSingleNode: false,
-    graphOffset_x: -200,
-    graphOffset_y: 100,
-    defaultLineMarker: {
-        markerWidth: 20,
-        markerHeight: 20,
-        refX: 3,
-        refY: 3,
-        data: "M 0 0, V 6, L 4 3, Z"
-    },
-    layout: {
-        layoutName: 'fixed'
-    }
-    // You can refer to the parameters in "Graph" for setting here
-
-};
-
-
-const showGraph = async() => {
-    const tables =  [
-        { tableName: 'SYS_USER',          tableComents: 'SYS_USER comments',           x: 500, y: -300 },
-        { tableName: 'SYS_DEPT',          tableComents: 'SYS_DEPT comments',           x: 0,    y: -300 },
-        { tableName: 'SYS_ROLE',          tableComents: 'SYS_ROLE comments',           x: 0,  y: 0 },
-        { tableName: 'SYS_USER_ROLE',     tableComents: 'SYS_USER_ROLE comments',      x: 500,  y: 0 },
-        { tableName: 'SYS_RESOURCE',      tableComents: 'SYS_RESOURCE comments',       x: 0,    y: 300 },
-        { tableName: 'SYS_ROLE_RESOURCE', tableComents: 'SYS_ROLE_RESOURCE comments',  x: 500,    y: 300 }
-    ];
-    const tableCols = [
-        { tableName: 'SYS_USER', columnName: 'id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_USER', columnName: 'user_name', dataType: 'varchar(50)'},
-        { tableName: 'SYS_USER', columnName: 'dept_id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_USER', columnName: 'create_time', dataType: 'TIMESTAMP'},
-        { tableName: 'SYS_USER', columnName: 'status', dataType: 'varchar(1)'},
-        { tableName: 'SYS_DEPT', columnName: 'id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_DEPT', columnName: 'dept_name', dataType: 'varchar(50)'},
-        { tableName: 'SYS_DEPT', columnName: 'parent_dept_id', dataType: 'varchar(50)'},
-        { tableName: 'SYS_DEPT', columnName: 'create_time', dataType: 'TIMESTAMP'},
-        { tableName: 'SYS_DEPT', columnName: 'status', dataType: 'varchar(50)'},
-        { tableName: 'SYS_ROLE', columnName: 'id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_ROLE', columnName: 'role_name', dataType: 'varchar(36)'},
-        { tableName: 'SYS_ROLE', columnName: 'create_time', dataType: 'TIMESTAMP'},
-        { tableName: 'SYS_USER_ROLE', columnName: 'id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_USER_ROLE', columnName: 'user_id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_USER_ROLE', columnName: 'role_id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_USER_ROLE', columnName: 'create_time', dataType: 'TIMESTAMP'},
-        { tableName: 'SYS_USER_ROLE', columnName: 'status', dataType: 'varchar(36)'},
-        { tableName: 'SYS_RESOURCE', columnName: 'id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_RESOURCE', columnName: 'resource_name', dataType: 'varchar(36)'},
-        { tableName: 'SYS_RESOURCE', columnName: 'create_time', dataType: 'TIMESTAMP'},
-        { tableName: 'SYS_ROLE_RESOURCE', columnName: 'id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_ROLE_RESOURCE', columnName: 'role_id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_ROLE_RESOURCE', columnName: 'resource_id', dataType: 'varchar(36)'},
-        { tableName: 'SYS_ROLE_RESOURCE', columnName: 'status', dataType: 'varchar(1)'},
-    ];
-    const columnRelations = [
-        { sourceTableName: 'SYS_USER', sourceColumnName: 'dept_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_DEPT', targetColumnName: 'id' },
-        { sourceTableName: 'SYS_DEPT', sourceColumnName: 'parent_dept_id', type: 'ONE_TO_ONE', targetTableName: 'SYS_DEPT', targetColumnName: 'id' },
-        { sourceTableName: 'SYS_USER_ROLE', sourceColumnName: 'user_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_USER', targetColumnName: 'id' },
-        { sourceTableName: 'SYS_USER_ROLE', sourceColumnName: 'role_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_ROLE', targetColumnName: 'id' },
-        { sourceTableName: 'SYS_ROLE_RESOURCE', sourceColumnName: 'role_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_ROLE', targetColumnName: 'id' },
-        { sourceTableName: 'SYS_ROLE_RESOURCE', sourceColumnName: 'resource_id', type: 'MORE_TO_ONE', targetTableName: 'SYS_RESOURCE', targetColumnName: 'id' },
-    ]
-    const graphNodes = tables.map(table => {
-        const { tableName, tableComents, x, y} = table;
-        return {
-            id: tableName,
-            text: tableComents,
-            x,
-            y,
-            nodeShape: 1,
-            data: { // Costomer key have to in data
-
-                columns: tableCols.filter(col => col.tableName === table.tableName)
-            }
-        }
-    });
-    const graphLines = columnRelations.map(relation => {
-        return {
-            from: relation.sourceTableName + '-' + relation.sourceColumnName, // HtmlElement id
-
-            to: relation.targetTableName + '-' + relation.targetColumnName, // HtmlElement id
-
-            color: relation.type === 'ONE_TO_ONE' ? 'rgba(29,169,245,0.76)' : 'rgba(159,23,227,0.65)',
-            text: '',
-            fromJunctionPoint: 'left',
-            toJunctionPoint: 'lr',
-            lineShape: 6,
-            lineWidth: 3
-
-        }
-    });
-    const graphJsonData: RGJsonData = {
-        nodes: graphNodes,
-        lines: [
-        ],
-        elementLines: graphLines
-
-    };
-    const graphInstance = graphRef.value?.getInstance();
-    if (graphInstance) {
-        await graphInstance.setJsonData(graphJsonData);
-        await graphInstance.moveToCenter();
-        await graphInstance.zoomToFit();
-    }
-};
-
-const onNodeClick = (nodeObject: RGNode, $event: RGUserEvent) => {
-    console.log('onNodeClick:', nodeObject);
-};
-
-const onLineClick = (lineObject: RGLine, linkObject: RGLink, $event: RGUserEvent) => {
-    console.log('onLineClick:', lineObject);
-};
-
-
-</script>
-<style lang="scss" scoped>
-::v-deep(.relation-graph) {
-    .rel-node-shape-1 {
-        overflow: hidden;
-    }
-}
-.c-data-table{
-  background-color: #ffffff;
-  border-collapse:collapse;
-  width: 100%;
-}
-.c-data-table td,.c-data-table th{
-  border:1px solid #f39930;
-  color: #333333;
-  padding: 5px;
-  padding-left: 20px;
-  padding-right: 20px;
-}
-.c-data-table td div,.c-data-table th div{
-  background-color: #1da9f5;
-  color: #ffffff;
-  border-radius: 5px;
-}
-</style>
-