You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
6.1 KiB
249 lines
6.1 KiB
<template>
|
|
<div class="app-container" ref="containerRef">
|
|
<!-- 左侧 SQL 编辑区 -->
|
|
<div class="sql-container" :style="{ width: leftWidth + 'px' }">
|
|
<!-- 工具栏 -->
|
|
<div class="toolbar">
|
|
<!-- 数据库类型 -->
|
|
<el-select
|
|
v-model="dbType"
|
|
placeholder="选择数据库类型"
|
|
size="small"
|
|
style="width: 140px; margin-left: 10px;"
|
|
>
|
|
<el-option label="MySQL" value="MYSQL" />
|
|
<el-option label="PostgreSQL" value="POSTGRESQL" />
|
|
<el-option label="SQL Server" value="MSSQL" />
|
|
<el-option label="Oracle" value="ORACLE" />
|
|
<el-option label="DB2" value="DB2" />
|
|
</el-select>
|
|
<!-- 系统选择 -->
|
|
<el-select
|
|
v-model="selectedSystem"
|
|
placeholder="选择系统"
|
|
size="small"
|
|
style="width: 160px"
|
|
>
|
|
<el-option
|
|
v-for="sys in dsSysList"
|
|
:key="sys.id"
|
|
:label="sys.name"
|
|
:value="sys.id"
|
|
/>
|
|
</el-select>
|
|
<!-- 模式 -->
|
|
<el-input
|
|
v-model="defaultModel"
|
|
placeholder="输入模式名"
|
|
size="small"
|
|
style="width: 140px; margin-left: 10px;"
|
|
clearable
|
|
/>
|
|
|
|
<!-- 执行按钮 -->
|
|
<el-button
|
|
type="primary"
|
|
size="small"
|
|
style="margin-left: 10px"
|
|
@click="executeSql"
|
|
>
|
|
执行
|
|
</el-button>
|
|
</div>
|
|
|
|
<!-- SQL 编辑器 -->
|
|
<SQLCodeMirror
|
|
v-model="procStr"
|
|
v-if="activeColumnTab === 'proc'"
|
|
:data="procStr"
|
|
:dbType="dbType"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 分隔条 -->
|
|
<div class="divider" @mousedown="startDragging"></div>
|
|
|
|
<!-- 右侧 血缘关系图 -->
|
|
<div class="relation-container">
|
|
<BloodRelation :currentTable="currentMetaData" :data="bloodRelation" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { getMetaDataBloodRelship, runBloodAnalysisBySql } from '@/api/meta/metaInfo'
|
|
import BloodRelation from '@/views/meta/metaInfo/bloodRelationSql.vue'
|
|
import SQLCodeMirror from '@/components/codemirror/SQLCodeMirrorSqlFlow.vue'
|
|
import useUserStore from '@/store/modules/user'
|
|
import cache from "@/plugins/cache";
|
|
|
|
const userStore = useUserStore()
|
|
const dsSysList = userStore.dsSysList
|
|
|
|
|
|
// ========================= 数据定义 =========================
|
|
const activeColumnTab = ref('proc')
|
|
const procStr = ref('')
|
|
const dbType = ref('MYSQL')
|
|
const containerRef = ref(null)
|
|
const childRef = ref(null)
|
|
|
|
// 当前选中系统
|
|
const selectedSystem = ref(dsSysList?.[0]?.id || null)
|
|
// 模式(可手动输入)
|
|
const defaultModel = ref('')
|
|
|
|
// 当前元数据信息
|
|
const currentMetaData = reactive({
|
|
tabEngName: 't_dim_comp',
|
|
tabCnName: '公司维度表',
|
|
ssysCd: 'PG_CONN',
|
|
ssysId: 1,
|
|
mdlName: 'public',
|
|
tabCrrctName: '',
|
|
tabDesc: '',
|
|
govFlag: null,
|
|
pic: '',
|
|
tags: []
|
|
})
|
|
|
|
// 血缘图数据
|
|
const bloodRelation = ref([])
|
|
|
|
// ========================= 拖拽逻辑 =========================
|
|
const leftWidth = ref(600)
|
|
const isDragging = ref(false)
|
|
let startX = 0
|
|
let startWidth = 0
|
|
|
|
const startDragging = (e) => {
|
|
isDragging.value = true
|
|
startX = e.clientX
|
|
startWidth = leftWidth.value
|
|
document.body.style.userSelect = 'none'
|
|
document.addEventListener('mousemove', handleDragging)
|
|
document.addEventListener('mouseup', stopDragging)
|
|
}
|
|
|
|
const handleDragging = (e) => {
|
|
if (!isDragging.value) return
|
|
const delta = e.clientX - startX
|
|
const newWidth = startWidth + delta
|
|
const minWidth = 300
|
|
const maxWidth = window.innerWidth - 400
|
|
leftWidth.value = Math.min(Math.max(newWidth, minWidth), maxWidth)
|
|
}
|
|
|
|
const stopDragging = () => {
|
|
isDragging.value = false
|
|
document.body.style.userSelect = ''
|
|
document.removeEventListener('mousemove', handleDragging)
|
|
document.removeEventListener('mouseup', stopDragging)
|
|
}
|
|
|
|
// ========================= 方法 =========================
|
|
const changeBloodOption = () => {
|
|
getMetaDataBloodRelship(currentMetaData.ssysId).then((res) => {
|
|
bloodRelation.value = res.data
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 执行 SQL 并生成血缘分析图
|
|
*/
|
|
const executeSql = async () => {
|
|
|
|
if (!selectedSystem.value) {
|
|
ElMessage.warning('请选择系统')
|
|
return
|
|
}
|
|
if (!procStr.value.trim()) {
|
|
ElMessage.warning('请输入 SQL 语句')
|
|
return
|
|
}
|
|
const params = {
|
|
sqlType: dbType.value,
|
|
defaultSystem: selectedSystem.value,
|
|
defaultModel: defaultModel.value || '',
|
|
sql: procStr.value,
|
|
userName: cache.local.get("username"),
|
|
password: cache.local.get("password")
|
|
}
|
|
try {
|
|
ElMessage.info('正在执行血缘分析,请稍候...')
|
|
const res = await runBloodAnalysisBySql(params)
|
|
if (res?.data) {
|
|
bloodRelation.value = res.data
|
|
ElMessage.success('血缘分析执行成功')
|
|
} else {
|
|
ElMessage.warning('未返回血缘数据')
|
|
}
|
|
} catch (err) {
|
|
console.error(err)
|
|
ElMessage.error('执行血缘分析失败')
|
|
}
|
|
}
|
|
|
|
// ========================= 生命周期 =========================
|
|
onMounted(() => {
|
|
changeBloodOption() // 初始化时仅加载血缘,不执行SQL
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
stopDragging()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.app-container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
height: 100vh;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 左侧 SQL 编辑区 */
|
|
.sql-container {
|
|
height: 100%;
|
|
background: #fafafa;
|
|
border-right: 1px solid #e0e0e0;
|
|
overflow: auto;
|
|
transition: width 0.1s ease-out;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* 工具栏 */
|
|
.toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
background: #f5f7fa;
|
|
border-bottom: 1px solid #e0e0e0;
|
|
padding: 8px 12px;
|
|
height: 45px;
|
|
}
|
|
|
|
/* 分隔条 */
|
|
.divider {
|
|
width: 6px;
|
|
cursor: col-resize;
|
|
background-color: #dcdcdc;
|
|
transition: background-color 0.2s;
|
|
flex-shrink: 0;
|
|
}
|
|
.divider:hover {
|
|
background-color: #aaa;
|
|
}
|
|
|
|
/* 右侧 血缘关系图 */
|
|
.relation-container {
|
|
flex: 1;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
padding: 8px;
|
|
background: #fff;
|
|
}
|
|
</style>
|
|
|