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

440 lines
13 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="12">
<el-select
v-model="selectedDatabase"
filterable
placeholder="请选择数据库"
class="w-100"
>
<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="12">
<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.id"
:label="item.name"
:value="item.id"
>
<span>{{ item.name }}</span>
<span class="option-actions">
<el-icon @click.stop="editConnection(item)"><edit /></el-icon>
<el-icon @click.stop="deleteConnection(item)"><delete /></el-icon>
</span>
</el-option>
<template #append>
<el-button icon="plus" @click="showAddConnectionDialog" />
</template>
</el-select>
</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语句"
/>
</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"
border
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.name" 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="connectionDialogVisible"
:title="isEditConnection ? '编辑连接' : '添加连接'"
width="50%"
:close-on-click-modal="false"
>
<el-form :model="connectionForm" label-width="100px">
<el-form-item label="连接名称" required>
<el-input v-model="connectionForm.name" placeholder="请输入连接名称" />
</el-form-item>
<el-form-item label="连接地址" required>
<el-input v-model="connectionForm.host" placeholder="请输入连接地址" />
</el-form-item>
<el-form-item label="端口" required>
<el-input v-model="connectionForm.port" placeholder="请输入端口" />
</el-form-item>
<el-form-item label="用户名" required>
<el-input v-model="connectionForm.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" required>
<el-input v-model="connectionForm.password" type="password" placeholder="请输入密码" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="connectionDialogVisible = false">取消</el-button>
<el-button type="primary" @click="saveConnection">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from 'vue';
import {FindDBManageListService,AddDBManageService,UpdateDBManageService,RunSQLService,GetSQLRunHistoryService } from '@/api/dbm';
import {DatabaseConfig} from '@/types/dbm';
import horizontalScroll from 'el-table-horizontal-scroll'
import {
Search, Edit, Delete, Plus
} from '@element-plus/icons-vue';
export default defineComponent({
name: 'DbManage',
components: {
Search, Edit, Delete, Plus,horizontalScroll
},
setup() {
// 数据库下拉框数据
const databases = ref<DatabaseConfig[]>([]);
const selectedDatabase = ref('');
// 连接下拉框数据
const connections = ref([
{ id: 1, name: '本地开发环境' },
{ id: 2, name: '测试环境' },
{ id: 3, name: '生产环境' },
]);
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 isEditDatabase = ref(false);
const databaseForm = reactive({
id: 0,
name: '',
});
// 连接对话框相关
const connectionDialogVisible = ref(false);
const isEditConnection = ref(false);
const connectionForm = reactive({
id: 0,
name: '',
host: '',
port: '',
username: '',
password: '',
});
// 方法定义
const showAddDatabaseDialog = () => {
isEditDatabase.value = false;
databaseForm.id = 0;
databaseForm.name = '';
databaseDialogVisible.value = true;
};
const editDatabase = (item) => {
isEditDatabase.value = true;
databaseForm.id = item.id;
databaseForm.name = item.name;
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 = "MySQL";
switch(databases.value[i].DB_Type) {
case 0:
type = "MySQL";
break;
case 1:
type = "PostgreSQL";
break;
}
databases.value[i].Name = type + " - "+ databases.value[i].DB_IP + ":" + databases.value[i].DB_Port + " - " + databases.value[i].DB_NAME;
}
} else {
console.error('获取数据库列表失败:', res.message);
}
}).catch((error: any) => {
console.error('请求错误:', error);
});
};
GetDBManageList();
const deleteDatabase = (item) => {
// 实际项目中这里应该调用API删除
databases.value = databases.value.filter(db => db.ID !== item.id);
};
const saveDatabase = () => {
if (isEditDatabase.value) {
// 更新
const index = databases.value.findIndex(db => db.ID === databaseForm.id);
if (index !== -1) {
databases.value[index].Name = databaseForm.name;
}
} else {
// 新增
// databases.value.push({
// id: databases.value.length + 1,
// name: databaseForm.name,
// });
}
databaseDialogVisible.value = false;
};
const showAddConnectionDialog = () => {
isEditConnection.value = false;
connectionForm.id = 0;
connectionForm.name = '';
connectionForm.host = '';
connectionForm.port = '';
connectionForm.username = '';
connectionForm.password = '';
connectionDialogVisible.value = true;
};
const editConnection = (item) => {
isEditConnection.value = true;
connectionForm.id = item.id;
connectionForm.name = item.name;
connectionForm.host = item.host || '';
connectionForm.port = item.port || '';
connectionForm.username = item.username || '';
connectionForm.password = item.password || '';
connectionDialogVisible.value = true;
};
const deleteConnection = (item) => {
// 实际项目中这里应该调用API删除
connections.value = connections.value.filter(conn => conn.id !== item.id);
};
const saveConnection = () => {
if (isEditConnection.value) {
// 更新
const index = connections.value.findIndex(conn => conn.id === connectionForm.id);
if (index !== -1) {
connections.value[index] = { ...connectionForm };
}
} else {
// 新增
connections.value.push({
id: connections.value.length + 1,
...connectionForm,
});
}
connectionDialogVisible.value = false;
};
const executeSql = () => {
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;
// tableColumns.value = res.columns;
let first = res.data[0];
let keys = Object.keys(first);
tableColumns.value = keys.map((key) => {
return { prop: key, label: key };
});
console.log(res.data);
} else {
console.error('执行SQL失败:', 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}`;
}
};
return {
databases,
selectedDatabase,
connections,
selectedConnection,
sqlQuery,
executing,
tableData,
tableColumns,
loading,
tables,
defaultProps,
databaseDialogVisible,
isEditDatabase,
databaseForm,
connectionDialogVisible,
isEditConnection,
connectionForm,
showAddDatabaseDialog,
editDatabase,
deleteDatabase,
saveDatabase,
showAddConnectionDialog,
editConnection,
deleteConnection,
saveConnection,
executeSql,
handleTableClick,
};
},
});
</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>