Bläddra i källkod

feat: 数据源管理页面接口对接

yanglzh 5 månader sedan
förälder
incheckning
211234e08f
4 ändrade filer med 332 tillägg och 452 borttagningar
  1. 1 1
      src/api/modules/apiHub.ts
  2. 0 2
      src/views/apihub/apilist.vue
  3. 196 219
      src/views/apihub/component/test.vue
  4. 135 230
      src/views/apihub/datasource.vue

+ 1 - 1
src/api/modules/apiHub.ts

@@ -17,7 +17,7 @@ export default {
     edit: (data: object) => put('/api_group/edit', data),
   },
   dataSource: {
-    list: () => get('/datasource/list'),
+    list: (params: object) => get('/datasource/list', params),
     get: (id: number) => get(`/datasource/get`, { id }),
     add: (data: object) => post('/datasource/add', data),
     edit: (data: object) => put('/datasource/edit', data),

+ 0 - 2
src/views/apihub/apilist.vue

@@ -221,8 +221,6 @@ const { params, tableData, getList, loading } = useSearch<ApiDefinition[]>(api.l
   status: "",
   dateRange: [],
   orderBy: "",
-  pageNum: 1,
-  pageSize: 10,
 });
 
 // 加载数据源列表

+ 196 - 219
src/views/apihub/component/test.vue

@@ -1,286 +1,263 @@
 <template>
-	<el-dialog class="api-test" v-model="showDialog" title="测试API" width="800px" :close-on-click-modal="false" :close-on-press-escape="false">
-		<el-descriptions :column="2" border>
-			<el-descriptions-item label="API名称" :span="2">{{ apiData.name }}</el-descriptions-item>
-			<el-descriptions-item label="API路径" :span="2">{{ apiData.path }}</el-descriptions-item>
-			<el-descriptions-item label="请求方法">
-				<el-tag :type="getMethodTagType(apiData.method)" size="small">{{ apiData.method }}</el-tag>
-			</el-descriptions-item>
-			<el-descriptions-item label="数据源">{{ apiData.dataSourceName }}</el-descriptions-item>
-		</el-descriptions>
+  <el-dialog class="api-test" v-model="showDialog" title="测试API" width="800px" :close-on-click-modal="false" :close-on-press-escape="false">
+    <el-descriptions :column="2" border>
+      <el-descriptions-item label="API名称" :span="2">{{ apiData.name }}</el-descriptions-item>
+      <el-descriptions-item label="API路径" :span="2">{{ apiData.path }}</el-descriptions-item>
+      <el-descriptions-item label="请求方法">
+        <el-tag :type="getMethodTagType(apiData.method)" size="small">{{ apiData.method }}</el-tag>
+      </el-descriptions-item>
+      <el-descriptions-item label="数据源">{{ apiData.dataSourceName }}</el-descriptions-item>
+    </el-descriptions>
 
-		<div class="section-title">参数设置</div>
-		<el-form :model="testParams" label-width="120px" v-if="apiData.parameters && apiData.parameters.length">
-			<el-form-item v-for="param in apiData.parameters" :key="param.name" :label="param.name" :required="param.required">
-				<el-input v-if="param.type === 'string'" v-model="testParams[param.name]" :placeholder="getParamPlaceholder(param)"></el-input>
-				<el-input-number
-					v-else-if="param.type === 'int' || param.type === 'float'"
-					v-model="testParams[param.name]"
-					:placeholder="getParamPlaceholder(param)"></el-input-number>
-				<el-switch v-else-if="param.type === 'bool'" v-model="testParams[param.name]" :active-value="true" :inactive-value="false"></el-switch>
-				<el-input v-else v-model="testParams[param.name]" :placeholder="getParamPlaceholder(param)"></el-input>
-				<div class="param-desc" v-if="param.description">{{ param.description }}</div>
-			</el-form-item>
-		</el-form>
-		<el-empty description="该API没有定义参数" v-else></el-empty>
+    <div class="section-title">参数设置</div>
+    <el-form :model="testParams" label-width="120px" v-if="apiData.parameters && apiData.parameters.length">
+      <el-form-item v-for="param in apiData.parameters" :key="param.name" :label="param.name" :required="param.required">
+        <el-input v-if="param.type === 'string'" v-model="testParams[param.name]" :placeholder="getParamPlaceholder(param)"></el-input>
+        <el-input-number v-else-if="param.type === 'int' || param.type === 'float'" v-model="testParams[param.name]" :placeholder="getParamPlaceholder(param)"></el-input-number>
+        <el-switch v-else-if="param.type === 'bool'" v-model="testParams[param.name]" :active-value="true" :inactive-value="false"></el-switch>
+        <el-input v-else v-model="testParams[param.name]" :placeholder="getParamPlaceholder(param)"></el-input>
+        <div class="param-desc" v-if="param.description">{{ param.description }}</div>
+      </el-form-item>
+    </el-form>
+    <el-empty description="该API没有定义参数" v-else></el-empty>
 
-		<div class="section-title">测试结果</div>
-		<div v-if="!testResult.success && !loading" class="test-placeholder">点击下方"执行测试"按钮开始测试</div>
-		<div v-else>
-			<el-alert :title="testResult.message" :type="testResult.success ? 'success' : 'error'" :closable="false" show-icon></el-alert>
-			<div v-if="testResult.success && testResult.data" class="result-container">
-				<el-tabs v-model="activeTab">
-					<el-tab-pane label="结果数据" name="data">
-						<pre class="result-json">{{ formatJson(testResult.data) }}</pre>
-					</el-tab-pane>
-					<el-tab-pane label="原始响应" name="raw">
-						<pre class="result-json">{{ formatJson(testResult) }}</pre>
-					</el-tab-pane>
-				</el-tabs>
-			</div>
-		</div>
+    <div class="section-title">测试结果</div>
+    <div v-if="!testResult.success && !loading" class="test-placeholder">点击下方"执行测试"按钮开始测试</div>
+    <div v-else>
+      <el-alert :title="testResult.message" :type="testResult.success ? 'success' : 'error'" :closable="false" show-icon></el-alert>
+      <div v-if="testResult.success && testResult.data" class="result-container">
+        <el-tabs v-model="activeTab">
+          <el-tab-pane label="结果数据" name="data">
+            <pre class="result-json">{{ formatJson(testResult.data) }}</pre>
+          </el-tab-pane>
+          <el-tab-pane label="原始响应" name="raw">
+            <pre class="result-json">{{ formatJson(testResult) }}</pre>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+    </div>
 
-		<template #footer>
-			<div class="dialog-footer">
-				<el-button @click="closeDialog">关闭</el-button>
-				<el-button type="primary" @click="runTest" :loading="loading">执行测试</el-button>
-			</div>
-		</template>
-	</el-dialog>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="closeDialog">关闭</el-button>
+        <el-button type="primary" @click="runTest" :loading="loading">执行测试</el-button>
+      </div>
+    </template>
+  </el-dialog>
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, watch } from 'vue'
-import apiHub from '/@/api/modules/apiHub'
+import { ref, reactive, watch } from "vue";
+import apiHub from "/@/api/modules/apiHub";
 
-const showDialog = ref(false)
-const loading = ref(false)
-const activeTab = ref('data')
+const showDialog = ref(false);
+const loading = ref(false);
+const activeTab = ref("data");
 
 // API数据
 const apiData = reactive<any>({
-	id: null,
-	name: '',
-	path: '',
-	method: '',
-	dataSourceId: null,
-	dataSourceName: '',
-	sqlType: '',
-	sqlContent: '',
-	parameters: [],
-	returnFormat: '',
-	version: '',
-	status: '',
-	plugins: [],
-	description: '',
-	createdAt: '',
-	updatedAt: '',
-})
+  id: null,
+  name: "",
+  path: "",
+  method: "",
+  dataSourceId: null,
+  dataSourceName: "",
+  sqlType: "",
+  sqlContent: "",
+  parameters: [],
+  returnFormat: "",
+  version: "",
+  status: "",
+  plugins: [],
+  description: "",
+  createdAt: "",
+  updatedAt: "",
+});
 
 // 测试参数
-const testParams = reactive<any>({})
+const testParams = reactive<any>({});
 
 // 测试结果
 const testResult = reactive<any>({
-	success: false,
-	message: '',
-	data: null,
-})
+  success: false,
+  message: "",
+  data: null,
+});
 
 // 监听API数据变化,初始化测试参数
 watch(
-	() => apiData.parameters,
-	(newParams) => {
-		// 清空测试参数
-		Object.keys(testParams).forEach((key) => {
-			delete testParams[key]
-		})
+  () => apiData.parameters,
+  (newParams) => {
+    // 清空测试参数
+    Object.keys(testParams).forEach((key) => {
+      delete testParams[key];
+    });
 
-		// 根据参数定义初始化测试参数
-		if (newParams && newParams.length) {
-			newParams.forEach((param: any) => {
-				// 如果有默认值,使用默认值
-				if (param.defaultValue !== undefined && param.defaultValue !== '') {
-					// 根据类型转换默认值
-					if (param.type === 'int') {
-						testParams[param.name] = parseInt(param.defaultValue)
-					} else if (param.type === 'float') {
-						testParams[param.name] = parseFloat(param.defaultValue)
-					} else if (param.type === 'bool') {
-						testParams[param.name] = param.defaultValue === 'true'
-					} else {
-						testParams[param.name] = param.defaultValue
-					}
-				} else {
-					// 否则设置为空值
-					if (param.type === 'int' || param.type === 'float') {
-						testParams[param.name] = null
-					} else if (param.type === 'bool') {
-						testParams[param.name] = false
-					} else {
-						testParams[param.name] = ''
-					}
-				}
-			})
-		}
-	},
-	{ deep: true }
-)
+    // 根据参数定义初始化测试参数
+    if (newParams && newParams.length) {
+      newParams.forEach((param: any) => {
+        // 如果有默认值,使用默认值
+        if (param.defaultValue !== undefined && param.defaultValue !== "") {
+          // 根据类型转换默认值
+          if (param.type === "int") {
+            testParams[param.name] = parseInt(param.defaultValue);
+          } else if (param.type === "float") {
+            testParams[param.name] = parseFloat(param.defaultValue);
+          } else if (param.type === "bool") {
+            testParams[param.name] = param.defaultValue === "true";
+          } else {
+            testParams[param.name] = param.defaultValue;
+          }
+        } else {
+          // 否则设置为空值
+          if (param.type === "int" || param.type === "float") {
+            testParams[param.name] = null;
+          } else if (param.type === "bool") {
+            testParams[param.name] = false;
+          } else {
+            testParams[param.name] = "";
+          }
+        }
+      });
+    }
+  },
+  { deep: true }
+);
 
 // 根据请求方法返回不同的标签类型
 const getMethodTagType = (method: string) => {
-	switch (method?.toUpperCase()) {
-		case 'GET':
-			return 'success'
-		case 'POST':
-			return 'primary'
-		case 'PUT':
-			return 'warning'
-		case 'DELETE':
-			return 'danger'
-		default:
-			return 'info'
-	}
-}
+  switch (method?.toUpperCase()) {
+    case "GET":
+      return "success";
+    case "POST":
+      return "primary";
+    case "PUT":
+      return "warning";
+    case "DELETE":
+      return "danger";
+    default:
+      return "info";
+  }
+};
 
 // 获取参数占位符文本
 const getParamPlaceholder = (param: any) => {
-	if (param.required) {
-		return `请输入${param.description || param.name}(必填)`
-	}
-	return `请输入${param.description || param.name}(选填)`
-}
+  if (param.required) {
+    return `请输入${param.description || param.name}(必填)`;
+  }
+  return `请输入${param.description || param.name}(选填)`;
+};
 
 // 格式化JSON
 const formatJson = (json: any) => {
-	try {
-		return JSON.stringify(json, null, 2)
-	} catch (e) {
-		return json
-	}
-}
+  try {
+    return JSON.stringify(json, null, 2);
+  } catch (e) {
+    return json;
+  }
+};
 
 // 关闭对话框
 const closeDialog = () => {
-	showDialog.value = false
-}
+  showDialog.value = false;
+};
 
 // 执行测试
 const runTest = async () => {
-	// 重置测试结果
-	testResult.success = false
-	testResult.message = ''
-	testResult.data = null
+  // 重置测试结果
+  testResult.success = false;
+  testResult.message = "";
+  testResult.data = null;
 
-	loading.value = true
+  loading.value = true;
 
-	apiHub.test({
-		id: apiData.id,
-		parameters: testParams
-	}).then((res: any) => {
-		// 模拟测试结果
-		testResult.success = true
-		testResult.message = '测试成功'
+  apiHub
+    .test({
+      id: apiData.id,
+      parameters: testParams,
+    })
+    .then((res: any) => {
+      testResult.success = true;
+      testResult.message = "测试成功";
 
-		// 根据API类型模拟不同的测试数据
-		if (apiData.path.includes('users')) {
-			if (apiData.method === 'GET') {
-				testResult.data = {
-					id: 1,
-					username: 'admin',
-					email: 'admin@example.com',
-					created_at: '2025-05-01 10:00:00',
-				}
-			} else {
-				testResult.data = {
-					id: 10,
-					username: testParams.username || 'newuser',
-					email: testParams.email || 'newuser@example.com',
-					created_at: '2025-05-06 11:00:00',
-				}
-			}
-		} else {
-			testResult.data = {
-				result: '测试数据',
-				timestamp: new Date().toISOString(),
-			}
-		}
-	}).catch((error: any) => {
-		testResult.success = false
-		testResult.message = error?.message || '测试失败'
-	}).finally(() => {
-		loading.value = false
-	})
-
-}
+      testResult.data = res;
+    })
+    .catch((error: any) => {
+      testResult.success = false;
+      testResult.message = error?.message || "测试失败";
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+};
 
 // 打开对话框
 const open = async (row: any) => {
-	// 清空数据
-	Object.keys(apiData).forEach((key) => {
-		apiData[key] = undefined
-	})
+  // 清空数据
+  Object.keys(apiData).forEach((key) => {
+    apiData[key] = undefined;
+  });
 
-	// 重置测试结果
-	testResult.success = false
-	testResult.message = ''
-	testResult.data = null
+  // 重置测试结果
+  testResult.success = false;
+  testResult.message = "";
+  testResult.data = null;
 
-	showDialog.value = true
+  showDialog.value = true;
 
-	// 实际使用时,应该调用API获取详细信息
-	// const res = await apiHub.get(row.id)
-	// Object.assign(apiData, res)
+  // 实际使用时,应该调用API获取详细信息
+  // const res = await apiHub.get(row.id)
+  // Object.assign(apiData, res)
 
-	// 这里模拟直接使用传入的行数据
-	Object.assign(apiData, row)
-}
+  // 这里模拟直接使用传入的行数据
+  Object.assign(apiData, row);
+};
 
-defineExpose({ open })
+defineExpose({ open });
 </script>
 
 <style scoped>
 .dialog-footer {
-	display: flex;
-	justify-content: flex-end;
+  display: flex;
+  justify-content: flex-end;
 }
 
 .section-title {
-	font-weight: bold;
-	margin: 20px 0 10px;
-	font-size: 16px;
-	border-left: 4px solid #409eff;
-	padding-left: 10px;
+  font-weight: bold;
+  margin: 20px 0 10px;
+  font-size: 16px;
+  border-left: 4px solid #409eff;
+  padding-left: 10px;
 }
 
 .param-desc {
-	font-size: 12px;
-	color: #909399;
-	margin-top: 5px;
+  font-size: 12px;
+  color: #909399;
+  margin-top: 5px;
 }
 
 .test-placeholder {
-	text-align: center;
-	color: #909399;
-	padding: 20px;
-	background-color: #f5f7fa;
-	border-radius: 4px;
+  text-align: center;
+  color: #909399;
+  padding: 20px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
 }
 
 .result-container {
-	margin-top: 15px;
-	border: 1px solid #e4e7ed;
-	border-radius: 4px;
+  margin-top: 15px;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
 }
 
 .result-json {
-	background-color: #f5f7fa;
-	padding: 10px;
-	font-family: monospace;
-	white-space: pre-wrap;
-	word-break: break-all;
-	margin: 0;
-	max-height: 300px;
-	overflow: auto;
+  background-color: #f5f7fa;
+  padding: 10px;
+  font-family: monospace;
+  white-space: pre-wrap;
+  word-break: break-all;
+  margin: 0;
+  max-height: 300px;
+  overflow: auto;
 }
 </style>

+ 135 - 230
src/views/apihub/datasource.vue

@@ -1,27 +1,13 @@
 <template>
   <div class="page">
     <el-card shadow="never">
-      <template #header>
-        <div class="card-header">
-          <span>数据源管理</span>
-        </div>
-      </template>
-      
       <!-- 搜索表单 -->
       <el-form :model="params" inline ref="queryRef">
         <el-form-item label="数据源名称" prop="keyWord">
           <el-input v-model="params.keyWord" placeholder="请输入数据源名称" clearable style="width: 200px" @keyup.enter.native="getList(1)" />
         </el-form-item>
         <el-form-item label="日期范围" prop="dateRange">
-          <el-date-picker
-            v-model="params.dateRange"
-            type="daterange"
-            range-separator="至"
-            start-placeholder="开始日期"
-            end-placeholder="结束日期"
-            value-format="YYYY-MM-DD"
-            style="width: 240px"
-          />
+          <el-date-picker v-model="params.dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" style="width: 240px" />
         </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="getList(1)">
@@ -35,7 +21,7 @@
           </el-button>
         </el-form-item>
       </el-form>
-      
+
       <!-- 数据表格 -->
       <el-table :data="tableData" style="width: 100%" v-loading="loading" row-key="id">
         <el-table-column type="selection" width="55" align="center" />
@@ -47,43 +33,23 @@
         <el-table-column prop="database" label="数据库名" min-width="120" show-overflow-tooltip />
         <el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip />
         <el-table-column prop="createdAt" label="创建时间" width="160" />
-        <el-table-column label="操作" width="200" fixed="right">
+        <el-table-column label="操作" width="160" align="center" fixed="right">
           <template #default="{ row }">
-            <el-button type="primary" link @click="testConnection(row)" v-auth="'test_datasource'">
-              测试连接
-            </el-button>
-            <el-button type="primary" link @click="addOrEdit(row)" v-auth="'edit_datasource'">
-              编辑
-            </el-button>
-            <el-button type="danger" link @click="deleteDataSource(row)" v-auth="'delete_datasource'">
-              删除
-            </el-button>
+            <el-button type="primary" size="small" text @click="testConnection(row)" v-auth="'test_datasource'"> 测试连接 </el-button>
+            <el-button type="primary" size="small" text @click="addOrEdit(row)" v-auth="'edit_datasource'"> 编辑 </el-button>
+            <el-button type="danger" size="small" text @click="deleteDataSource(row)" v-auth="'delete_datasource'"> 删除 </el-button>
           </template>
         </el-table-column>
       </el-table>
-      
+
       <!-- 分页 -->
       <div class="pagination-container">
-        <el-pagination
-          v-model:current-page="params.pageNum"
-          v-model:page-size="params.pageSize"
-          :page-sizes="[10, 20, 50, 100]"
-          layout="total, sizes, prev, pager, next, jumper"
-          :total="total"
-          @size-change="getList()"
-          @current-change="getList()"
-        />
+        <el-pagination v-model:current-page="params.pageNum" v-model:page-size="params.pageSize" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="params.total" @size-change="getList()" @current-change="getList()" />
       </div>
     </el-card>
-    
+
     <!-- 数据源表单对话框 -->
-    <el-dialog
-      v-model="dialogVisible"
-      :title="formData.id ? '编辑数据源' : '新增数据源'"
-      width="600px"
-      :close-on-click-modal="false"
-      :close-on-press-escape="false"
-    >
+    <el-dialog v-model="dialogVisible" :title="formData.id ? '编辑数据源' : '新增数据源'" width="600px" :close-on-click-modal="false" :close-on-press-escape="false">
       <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">
         <el-form-item label="数据源名称" prop="name">
           <el-input v-model="formData.name" placeholder="请输入数据源名称" />
@@ -133,13 +99,9 @@
         </div>
       </template>
     </el-dialog>
-    
+
     <!-- 测试连接对话框 -->
-    <el-dialog
-      v-model="testDialogVisible"
-      title="测试数据源连接"
-      width="500px"
-    >
+    <el-dialog v-model="testDialogVisible" title="测试数据源连接" width="500px">
       <el-form ref="testFormRef" :model="testFormData" :rules="testRules" label-width="120px">
         <el-form-item label="数据库类型" prop="type">
           <el-select v-model="testFormData.type" placeholder="请选择数据库类型" style="width: 100%">
@@ -175,208 +137,162 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted } from 'vue'
-import { ElMessage, ElMessageBox } from 'element-plus'
-import request from '/@/utils/request'
-import { useSearch } from '/@/hooks/useSearch'
+import { ref, reactive, onMounted } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { useSearch } from "/@/hooks/useCommon";
+import apiHub from "/@/api/modules/apiHub";
 
 // 定义数据源类型
 interface DataSource {
-  id?: number
-  name: string
-  type: string
-  host: string
-  port: number
-  username: string
-  password?: string
-  database: string
-  maxOpenConns?: number
-  maxIdleConns?: number
-  connMaxLifetime?: number
-  remark?: string
-  createdAt?: string
-  updatedAt?: string
+  id?: number;
+  name: string;
+  type: string;
+  host: string;
+  port: number;
+  username: string;
+  password?: string;
+  database: string;
+  maxOpenConns?: number;
+  maxIdleConns?: number;
+  connMaxLifetime?: number;
+  remark?: string;
+  createdAt?: string;
+  updatedAt?: string;
 }
 
 // 表单引用
-const formRef = ref()
-const testFormRef = ref()
-const queryRef = ref()
+const formRef = ref();
+const testFormRef = ref();
+const queryRef = ref();
 
 // 对话框状态
-const dialogVisible = ref(false)
-const testDialogVisible = ref(false)
-
-// 总数
-const total = ref(0)
-
-// 加载状态
-const loading = ref(false)
+const dialogVisible = ref(false);
+const testDialogVisible = ref(false);
 
 // 表单数据
 const formData = reactive<DataSource>({
-  name: '',
-  type: 'MySQL',
-  host: '',
+  name: "",
+  type: "MySQL",
+  host: "",
   port: 3306,
-  username: '',
-  password: '',
-  database: '',
+  username: "",
+  password: "",
+  database: "",
   maxOpenConns: 100,
   maxIdleConns: 10,
   connMaxLifetime: 3600,
-  remark: ''
-})
+  remark: "",
+});
 
 // 测试连接表单数据
 const testFormData = reactive({
-  type: 'MySQL',
-  host: '',
+  type: "MySQL",
+  host: "",
   port: 3306,
-  username: '',
-  password: '',
-  database: ''
-})
+  username: "",
+  password: "",
+  database: "",
+});
 
 // 表单验证规则
 const rules = {
-  name: [{ required: true, message: '请输入数据源名称', trigger: 'blur' }],
-  type: [{ required: true, message: '请选择数据库类型', trigger: 'change' }],
-  host: [{ required: true, message: '请输入主机地址', trigger: 'blur' }],
-  port: [{ required: true, message: '请输入端口', trigger: 'blur' }],
-  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
-  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
-  database: [{ required: true, message: '请输入数据库名', trigger: 'blur' }]
-}
+  name: [{ required: true, message: "请输入数据源名称", trigger: "blur" }],
+  type: [{ required: true, message: "请选择数据库类型", trigger: "change" }],
+  host: [{ required: true, message: "请输入主机地址", trigger: "blur" }],
+  port: [{ required: true, message: "请输入端口", trigger: "blur" }],
+  username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
+  password: [{ required: true, message: "请输入密码", trigger: "blur" }],
+  database: [{ required: true, message: "请输入数据库名", trigger: "blur" }],
+};
 
 // 测试连接表单验证规则
 const testRules = {
-  type: [{ required: true, message: '请选择数据库类型', trigger: 'change' }],
-  host: [{ required: true, message: '请输入主机地址', trigger: 'blur' }],
-  port: [{ required: true, message: '请输入端口', trigger: 'blur' }],
-  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
-  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
-  database: [{ required: true, message: '请输入数据库名', trigger: 'blur' }]
-}
-
-// 数据源列表请求函数
-const dataSourceRequest = (params: any) => {
-  return request({
-    url: '/datasource/list',
-    method: 'get',
-    params
-  })
-}
+  type: [{ required: true, message: "请选择数据库类型", trigger: "change" }],
+  host: [{ required: true, message: "请输入主机地址", trigger: "blur" }],
+  port: [{ required: true, message: "请输入端口", trigger: "blur" }],
+  username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
+  password: [{ required: true, message: "请输入密码", trigger: "blur" }],
+  database: [{ required: true, message: "请输入数据库名", trigger: "blur" }],
+};
 
 // 使用通用搜索钩子
-const { params, tableData, getList } = useSearch<DataSource[]>(
-  dataSourceRequest,
-  'data',
-  (res: any) => {
-    total.value = res.pagination?.total || 0
-    return res.data || []
-  },
-  {
-    keyWord: '',
-    dateRange: [],
-    pageNum: 1,
-    pageSize: 10
-  }
-)
+const { params, tableData, getList, loading } = useSearch<DataSource[]>(apiHub.dataSource.list, "Data", {
+  keyWord: "",
+  dateRange: [],
+});
 
 // 页面加载时获取列表数据
 onMounted(() => {
-  getList(1)
-})
+  getList(1);
+});
 
 // 重置查询表单
 const resetQuery = () => {
-  queryRef.value?.resetFields()
-  getList(1)
-}
+  queryRef.value?.resetFields();
+  getList(1);
+};
 
 // 新增或编辑数据源
 const addOrEdit = (row?: DataSource) => {
   // 重置表单
   Object.assign(formData, {
     id: undefined,
-    name: '',
-    type: 'MySQL',
-    host: '',
+    name: "",
+    type: "MySQL",
+    host: "",
     port: 3306,
-    username: '',
-    password: '',
-    database: '',
+    username: "",
+    password: "",
+    database: "",
     maxOpenConns: 100,
     maxIdleConns: 10,
     connMaxLifetime: 3600,
-    remark: ''
-  })
-  
+    remark: "",
+  });
+
   // 如果是编辑,填充表单数据
   if (row) {
-    Object.assign(formData, { ...row, password: '' })
+    Object.assign(formData, { ...row, password: "" });
   }
-  
+
   // 显示对话框
-  dialogVisible.value = true
-}
+  dialogVisible.value = true;
+};
 
 // 提交表单
 const submitForm = async () => {
   // 表单验证
-  await formRef.value.validate()
-  
-  try {
-    // 根据是否有ID判断是新增还是编辑
-    const url = formData.id ? '/datasource/edit' : '/datasource/add'
-    const method = formData.id ? 'put' : 'post'
-    
-    // 发送请求
-    await request({
-      url,
-      method,
-      data: formData
-    })
-    
-    // 关闭对话框
-    dialogVisible.value = false
-    
-    // 刷新列表
-    getList()
-    
-    // 提示成功
-    ElMessage.success(formData.id ? '编辑成功' : '添加成功')
-  } catch (error) {
-    console.error('提交表单失败:', error)
-  }
-}
+  await formRef.value.validate();
+
+  const theApi = formData.id ? apiHub.dataSource.edit : apiHub.dataSource.add;
+
+  // 发送请求
+  await theApi(formData);
+
+  // 关闭对话框
+  dialogVisible.value = false;
+
+  // 刷新列表
+  getList();
+
+  // 提示成功
+  ElMessage.success(formData.id ? "编辑成功" : "添加成功");
+};
 
 // 删除数据源
 const deleteDataSource = (row: DataSource) => {
-  ElMessageBox.confirm(`确定要删除数据源「${row.name}」吗?`, '警告', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
-    type: 'warning'
-  }).then(async () => {
-    try {
-      // 发送删除请求
-      await request({
-        url: '/datasource/delete',
-        method: 'delete',
-        data: { ids: [row.id] }
-      })
-      
-      // 刷新列表
-      getList()
-      
-      // 提示成功
-      ElMessage.success('删除成功')
-    } catch (error) {
-      console.error('删除失败:', error)
-    }
-  }).catch(() => {})
-}
+  ElMessageBox.confirm(`确定要删除数据源「${row.name}」吗?`, "警告", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(async () => {
+      await apiHub.dataSource.delete([row.id!]);
+      getList();
+      ElMessage.success("删除成功");
+    })
+    .catch(() => {});
+};
 
 // 测试连接(从列表)
 const testConnection = (row: DataSource) => {
@@ -386,19 +302,19 @@ const testConnection = (row: DataSource) => {
     host: row.host,
     port: row.port,
     username: row.username,
-    password: '', // 密码需要重新输入
-    database: row.database
-  })
-  
+    password: "", // 密码需要重新输入
+    database: row.database,
+  });
+
   // 显示测试对话框
-  testDialogVisible.value = true
-}
+  testDialogVisible.value = true;
+};
 
 // 测试连接(从表单)
 const testConnectionForm = async () => {
   // 表单验证
-  await formRef.value.validate()
-  
+  await formRef.value.validate();
+
   // 填充测试表单
   Object.assign(testFormData, {
     type: formData.type,
@@ -406,37 +322,26 @@ const testConnectionForm = async () => {
     port: formData.port,
     username: formData.username,
     password: formData.password,
-    database: formData.database
-  })
-  
+    database: formData.database,
+  });
+
   // 显示测试对话框
-  testDialogVisible.value = true
-}
+  testDialogVisible.value = true;
+};
 
 // 提交测试连接
 const submitTestConnection = async () => {
   // 表单验证
-  await testFormRef.value.validate()
-  
-  try {
-    // 发送测试连接请求
-    const res = await request({
-      url: '/datasource/test',
-      method: 'post',
-      data: testFormData
-    })
-    
-    // 根据测试结果显示提示
-    if (res.data.success) {
-      ElMessage.success(res.data.message || '连接成功')
+  await testFormRef.value.validate();
+
+  await apiHub.dataSource.test(testFormData).then((res: any) => {
+    if (res.success) {
+      ElMessage.success(res.message || "连接成功");
     } else {
-      ElMessage.error(res.data.message || '连接失败')
+      ElMessage.error(res.message || "连接失败");
     }
-  } catch (error) {
-    console.error('测试连接失败:', error)
-    ElMessage.error('测试连接失败')
-  }
-}
+  });
+};
 </script>
 
 <style scoped>