sawAdmin/src/views/system/db-manage2.vue

574 lines
16 KiB
Vue

<template>
<div class="db-manage-container">
<el-row :gutter="20">
<!-- 左侧数据库表列表 -->
<el-col :span="4">
<div class="table-list">
<h3>数据库表</h3>
<el-scrollbar height="400px">
<el-tree
:data="tables"
node-key="name"
:props="defaultProps"
@node-click="handleTableClick"
/>
</el-scrollbar>
</div>
</el-col>
<!-- 右侧主内容区 -->
<el-col :span="20">
<!-- 顶部下拉选择框 -->
<el-row :gutter="20" class="mb-20">
<el-col :span="10">
<el-select
v-model="selectedDatabase"
filterable
placeholder="请选择数据库"
class="w-100"
@change="getRunSQLHistory"
>
<template #prefix>
<el-icon><search /></el-icon>
</template>
<el-option
v-for="item in databases"
:key="item.ID"
:label="item.Name"
:value="item.ID"
>
<span>{{ item.Name }}</span>
<span class="option-actions">
<el-icon @click.stop="editDatabase(item)"><edit /></el-icon>
<el-icon @click.stop="deleteDatabase(item)"
><delete
/></el-icon>
</span>
</el-option>
<template #append>
<el-button icon="plus" @click="showAddDatabaseDialog" />
</template>
</el-select>
</el-col>
<el-col :span="1">
<el-icon @click="showAddDatabaseDialog"><FolderAdd /></el-icon>
</el-col>
<el-col :span="6">
<el-select
v-model="selectedConnection"
filterable
placeholder="请选择服务器"
class="w-100"
>
<template #prefix>
<el-icon><search /></el-icon>
</template>
<el-option
v-for="item in connections"
:key="item.domain"
:label="item.name"
:value="item.domain"
>
<span>{{ item.name }}</span>
</el-option>
<template #append>
<el-button circle @click="showAddDatabaseDialog" />
</template>
</el-select>
</el-col>
<el-col :span="3">
<el-button
type="primary"
@click="showSQLHistoryDialog"
class="w-100"
:loading="executing"
>执行历史SQL</el-button
>
</el-col>
</el-row>
<!-- SQL输入框和执行按钮 -->
<el-row class="mb-20">
<el-col :span="20">
<el-input
v-model="sqlQuery"
type="textarea"
:rows="3"
placeholder="请输入SQL语句"
/>
<!-- <SqlEditor v-model="sqlQuery" /> -->
</el-col>
<el-col :span="4">
<el-button
type="primary"
@click="executeSql"
class="w-100"
:loading="executing"
>
执行
</el-button>
</el-col>
</el-row>
<!-- 结果表格 -->
<el-table
:data="tableData"
style="width: 100%"
height="400px"
v-horizontal-scroll="'always'"
v-loading="loading"
>
<el-table-column
v-for="column in tableColumns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
/>
</el-table>
</el-col>
</el-row>
<!-- 添加/编辑数据库对话框 -->
<el-dialog
v-model="databaseDialogVisible"
:title="isEditDatabase ? '编辑数据库' : '添加数据库'"
width="50%"
:close-on-click-modal="false"
>
<el-form :model="databaseForm" label-width="100px">
<el-form-item label="数据库名称" required>
<el-input
v-model="databaseForm.DB_NAME"
placeholder="请输入数据库名称"
/>
</el-form-item>
</el-form>
<el-form :model="databaseForm" label-width="100px">
<el-form-item label="数据库密码" required>
<el-input
v-model="databaseForm.DB_Password"
type="password"
placeholder="请输入数据库密码"
show-password
/>
</el-form-item>
</el-form>
<el-form :model="databaseForm" label-width="100px">
<el-form-item label="用户名" required>
<el-input
v-model="databaseForm.DB_User"
placeholder="请输入用户名称"
/>
</el-form-item>
</el-form>
<el-form :model="databaseForm" label-width="100px">
<el-form-item label="IP或域名" required>
<el-input
v-model="databaseForm.DB_IP"
placeholder="请输入数据库ip或域名"
/>
</el-form-item>
</el-form>
<el-form :model="databaseForm" label-width="100px">
<el-form-item label="数据库端口" required>
<el-input
v-model="databaseForm.DB_Port"
placeholder="请输入数据库端口"
/>
</el-form-item>
</el-form>
<el-form :model="databaseForm" label-width="100px">
<el-form-item label="数据库类型" required>
<el-select
v-model="databaseForm.DB_Type"
placeholder="请选择数据库类型"
>
<el-option label="MySQL" value="0" />
<el-option label="PostgreSQL" value="1" />
</el-select>
</el-form-item>
</el-form>
<el-form :model="databaseForm" label-width="100px">
<el-form-item label="描述信息">
<el-input
v-model="databaseForm.DB_Desc"
placeholder="请输入备注信息"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="databaseDialogVisible = false">取消</el-button>
<el-button type="primary" @click="saveDatabase">保存</el-button>
</template>
</el-dialog>
<el-dialog
v-model="sqlHistoryDialogVisible"
title="SQL执行历史"
width="50%"
:close-on-click-modal="false"
>
<el-table :data="sqlHistory" stripe width="100%" height="600px" fit>
<el-table-column prop="ID" label="SQLID" width="150"></el-table-column>
<el-table-column prop="SQL" label="SQL" width="500"> </el-table-column>
<el-table-column label="操作" width="270">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="useCurrSql(scope.$index)"
>引用</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="DelSqlHistory(scope.$index)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="sqlHistoryDialogVisible = false">取消</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import {
FindDBManageListService,
AddDBManageService,
UpdateDBManageService,
RunSQLService,
GetSQLRunHistoryService,
} from "@/api/dbm";
import { DatabaseConfig, ISQLOperation } from "@/types/dbm";
import { Search, Edit, Delete, Plus } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import SqlEditor from './sqlEditor.vue';
// 数据库下拉框数据
const databases = ref<DatabaseConfig[]>([]);
const selectedDatabase = ref("");
// 连接下拉框数据
const connections = ref([
{ name: "腾讯服务器", domain: "tx.ljsea.top" },
{ name: "阿里云服务器", domain: "al.ljsea.top" },
{ name: "家里服务器", domain: "gep.ljsea.top" },
]);
const supportdedDBTypes = ref({ 0: "mysql", 1: "postgresql" });
const selectedConnection = ref("");
// SQL查询相关
const sqlQuery = ref("");
const executing = ref(false);
const tableData = ref([]);
const tableColumns = ref([]);
const loading = ref(false);
// 数据库表列表
const tables = ref([
{
name: "users",
children: [{ name: "id" }, { name: "username" }, { name: "email" }],
},
{
name: "products",
children: [{ name: "id" }, { name: "name" }, { name: "price" }],
},
]);
const defaultProps = {
children: "children",
label: "name",
};
// 数据库对话框相关
const databaseDialogVisible = ref(false);
const sqlHistoryDialogVisible = ref(false);
const isEditDatabase = ref(false);
const databaseForm = ref<DatabaseConfig>();
const sqlHistory = ref<ISQLOperation[]>([]);
// 连接对话框相关
const connectionDialogVisible = ref(false);
const isEditConnection = ref(false);
const connectionForm = reactive({
id: 0,
name: "",
host: "",
port: "",
username: "",
password: "",
});
const showSQLHistoryDialog = async () => {
sqlHistoryDialogVisible.value = true;
console.log('SQL history dialog opened:', sqlHistoryDialogVisible.value);
await getRunSQLHistory();
};
// 方法定义
const showAddDatabaseDialog = () => {
isEditDatabase.value = false;
databaseForm.value = {
ID: 0,
DB_IP: "",
DB_Port: 3306,
DB_NAME: "",
DB_User: "",
DB_Password: "",
DB_Type: 0,
CreatedAt: "",
UpdatedAt: "",
UserID: 0,
DB_Desc: "",
DB_STATUS: 0,
Name: "",
DeletedAt: null,
};
databaseDialogVisible.value = true;
};
const editDatabase = (item) => {
isEditDatabase.value = true;
console.log("editDatabase:", item);
databaseForm.value = item;
databaseDialogVisible.value = true;
};
const GetDBManageList = async () => {
let req = {
get_type: 0,
token: localStorage.getItem("token"),
id: localStorage.getItem("userId"),
};
await FindDBManageListService(req)
.then((res: any) => {
if (res.code === 0) {
databases.value = res.data;
for (let i = 0; i < databases.value.length; i++) {
let type = supportdedDBTypes.value[databases.value[i].DB_Type];
databases.value[i].Name =
type +
" - " +
databases.value[i].DB_IP +
":" +
databases.value[i].DB_Port +
" - " +
databases.value[i].DB_NAME;
}
ElMessage.success("获取数据库列表成功");
console.log("获取数据库列表成功:", databases.value);
// console.log("获取数据库列表成功:", res.data);
// console.log("获取数据库列表成功:", res.data);
// console.log("获取数据库列表成功:", res.data);
} else {
console.error("获取数据库列表失败:", res.message);
}
})
.catch((error: any) => {
console.error("请求错误:", error);
});
};
GetDBManageList();
const useCurrSql = (index) => {
sqlQuery.value = sqlHistory.value[index].SQL;
sqlHistoryDialogVisible.value = false;
};
const DelSqlHistory = (index) => {
sqlHistory.value.splice(index, 1);
};
const deleteDatabase = (item) => {
// 实际项目中这里应该调用API删除
databases.value = databases.value.filter((db) => db.ID !== item.id);
};
const saveDatabase = () => {
let req = {};
if (isEditDatabase.value) {
// 更新
// const index = databases.value.findIndex(db => db.ID === databaseForm.id);
// if (index !== -1) {
// databases.value[index].Name = databaseForm.name;
// }]
req = {
token: localStorage.getItem("token"),
db_id: databaseForm.value.ID,
db_name: databaseForm.value.DB_NAME,
db_type: databaseForm.value.DB_Type,
db_ip: databaseForm.value.DB_IP,
db_port: databaseForm.value.DB_Port,
db_user: databaseForm.value.DB_User,
db_password: databaseForm.value.DB_Password,
db_desc: databaseForm.value.DB_Desc,
};
UpdateDBManageService(req)
.then((res: any) => {
if (res.code === 0) {
ElMessage.success("更新成功");
GetDBManageList();
} else {
ElMessage.error("更新失败");
}
})
.catch((error: any) => {
console.error("请求错误:", error);
});
} else {
// 新增
// databases.value.push({
// id: databases.value.length + 1,
// name: databaseForm.name,
// });
req = {
token: localStorage.getItem("token"),
db_id: databaseForm.value.ID,
db_name: databaseForm.value.DB_NAME,
db_type: databaseForm.value.DB_Type,
db_ip: databaseForm.value.DB_IP,
db_port: databaseForm.value.DB_Port,
db_user: databaseForm.value.DB_User,
db_password: databaseForm.value.DB_Password,
db_desc: databaseForm.value.DB_Desc,
};
AddDBManageService(req)
.then((res: any) => {
if (res.code === 0) {
ElMessage.success("添加成功");
GetDBManageList();
} else {
ElMessage.error("添加失败");
}
})
.catch((error: any) => {
console.error("请求错误:", error);
});
}
databaseDialogVisible.value = false;
};
const getRunSQLHistory = async () => {
if (!selectedDatabase.value) {
ElMessage({
type: "error",
message: "请选择数据库",
});
return;
}
let req = {
db_id: selectedDatabase.value,
token: localStorage.getItem("token"),
get_type: 0,
};
await GetSQLRunHistoryService(req)
.then((res: any) => {
if (res.code === 0) {
sqlHistory.value = res.data;
ElMessage({
type: "success",
message: "获取SQL执行历史成功",
});
} else {
console.error("获取SQL执行历史失败:", res.message);
}
})
.catch((error: any) => {
console.error("请求错误:", error);
});
};
const executeSql = () => {
if (!selectedDatabase.value) {
ElMessage({
type: "error",
message: "请选择数据库",
});
return;
}
executing.value = true;
loading.value = true;
let req = {
token: localStorage.getItem("token"),
id: localStorage.getItem("userId"),
sql: sqlQuery.value,
db_id: selectedDatabase.value,
};
try {
RunSQLService(req)
.then((res: any) => {
if (res.code === 0) {
tableData.value = res.data.Rows;
tableColumns.value = res.data.Columns;
// let keys = Object.keys(res.data.Rows[0]);
//console.log( 'columns:',tableColumns.value);
// tableColumns.value = res.columns;
// tableColumns.value = keys.map((key) => {
// return { prop: key, label: key };
// });
// console.log(res.data);
} else {
console.error("执行SQL失败:", res.message);
ElMessage({
type: "error",
message: res.message,
});
}
})
.catch((error: any) => {
console.error("请求错误:", error);
});
} catch (e) {
console.log(e);
}
executing.value = false;
loading.value = false;
};
const handleTableClick = (data) => {
// 点击表名时自动生成查询语句
if (!data.children) {
sqlQuery.value = `SELECT * FROM ${data.name}`;
}
};
</script>
<style scoped>
.db-manage-container {
padding: 20px;
}
.table-list {
background: #fff;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.mb-20 {
margin-bottom: 20px;
}
.w-100 {
width: 100%;
}
.option-actions {
float: right;
}
.option-actions .el-icon {
margin-left: 10px;
cursor: pointer;
}
</style>