Prechádzať zdrojové kódy

feat: 优化 api 列表的分组的增删改差,列表的增删改查

yanglzh 5 mesiacov pred
rodič
commit
06a3901de4

+ 27 - 0
src/api/modules/apiHub.ts

@@ -0,0 +1,27 @@
+import { get, post, del, put } from '/@/utils/request';
+
+export default {
+  list: (params: object) => get('/api/list', params),
+  add: (data: object) => post('/api/add', data),
+  edit: (data: object) => put('/api/edit', data),
+  delete: (ids: number[]) => del('/api/delete', { ids }),
+  get: (id: number) => get(`/api/get`, { id }),
+  publish: (id: number) => put(`/api/publish`, { id }),
+  deprecate: (id: number) => put(`/api/deprecate`, { id }),
+  test: (data: object) => post(`/api/test`, data),
+  group: {
+    tree: () => get('/api_group/tree'),
+    get: (id: number) => get(`/api_group/get`, { id }),
+    delete: (ids: number[]) => post('/api_group/delete', { ids }),
+    add: (data: object) => post('/api_group/add', data),
+    edit: (data: object) => put('/api_group/edit', data),
+  },
+  dataSource: {
+    list: () => get('/datasource/list'),
+    get: (id: number) => get(`/datasource/get`, { id }),
+    add: (data: object) => post('/datasource/add', data),
+    edit: (data: object) => put('/datasource/edit', data),
+    delete: (ids: number[]) => del('/datasource/delete', { ids }),
+    test: (data: object) => post('/datasource/test', data),
+  }
+}

+ 156 - 227
src/views/apihub/apilist.vue

@@ -23,8 +23,7 @@
 							placeholder="搜索分组"
 							clearable
 							prefix-icon="ele-Search"
-							@input="filterGroups"
-						/>
+							@input="filterGroups" />
 					</div>
 					<div class="group-tree-container">
 						<el-tree
@@ -35,14 +34,13 @@
 							highlight-current
 							:expand-on-click-node="true"
 							default-expand-all
-							@node-click="handleGroupClick"
-						>
+							@node-click="handleGroupClick">
 							<template #default="{ node, data }">
 								<div class="custom-tree-node">
 									<span>{{ node.label }}</span>
 									<span class="api-count" v-if="data.ApiCount">{{ data.ApiCount }}</span>
 									<div class="node-actions">
-										<el-dropdown @command="(command) => handleGroupCommand(command, data)" trigger="click">
+										<el-dropdown @command="(command: string) => handleGroupCommand(command, data)" trigger="click">
 											<el-icon><ele-More /></el-icon>
 											<template #dropdown>
 												<el-dropdown-menu>
@@ -72,107 +70,105 @@
 						</div>
 					</div>
 					<el-form :model="params" inline ref="queryRef">
-				<el-form-item label="API名称" prop="keyWord">
-					<el-input v-model="params.keyWord" placeholder="请输入API名称" clearable style="width: 180px" @keyup.enter.native="getList(1)" />
-				</el-form-item>
-				<el-form-item label="数据源" prop="dataSourceId">
-					<el-select v-model="params.dataSourceId" placeholder="请选择数据源" clearable style="width: 180px">
-						<el-option v-for="item in dataSources" :key="item.id" :label="item.name" :value="item.id" />
-					</el-select>
-				</el-form-item>
-				<el-form-item label="状态" prop="status">
-					<el-select v-model="params.status" placeholder="请选择状态" clearable style="width: 120px">
-						<el-option label="全部" value="" />
-						<el-option label="草稿" value="Draft" />
-						<el-option label="已发布" value="Published" />
-						<el-option label="已废弃" value="Deprecated" />
-					</el-select>
-				</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-form-item>
-				<el-form-item>
-					<el-button type="primary" class="ml10" @click="getList(1)">
-						<el-icon>
-							<ele-Search />
-						</el-icon>
-						查询
-					</el-button>
-					<el-button @click="resetQuery()">
-						<el-icon>
-							<ele-Refresh />
-						</el-icon>
-						重置
-					</el-button>
-					<el-button type="primary" @click="addOrEdit()" v-auth="'add'">
-						<el-icon>
-							<ele-FolderAdd />
-						</el-icon>
-						新增API
-					</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" />
-				<el-table-column prop="id" label="ID" width="80" align="center" />
-				<el-table-column prop="name" label="API名称" min-width="120" show-overflow-tooltip></el-table-column>
-				<el-table-column prop="path" label="API路径" min-width="150" show-overflow-tooltip></el-table-column>
-				<el-table-column prop="method" label="请求方法" width="100" align="center">
-					<template #default="scope">
-						<el-tag
-							:type="getMethodTagType(scope.row.method)"
-							size="small"
-						>
-							{{ scope.row.method }}
-						</el-tag>
-					</template>
-				</el-table-column>
-				<el-table-column prop="dataSourceName" label="数据源" width="120" show-overflow-tooltip></el-table-column>
-				<el-table-column prop="sqlType" label="SQL类型" width="100" align="center">
-					<template #default="scope">
-						<el-tag size="small" type="info" v-if="scope.row.sqlType === 'query'">查询</el-tag>
-						<el-tag size="small" type="warning" v-else-if="scope.row.sqlType === 'procedure'">存储过程</el-tag>
-						<span v-else>{{ scope.row.sqlType }}</span>
-					</template>
-				</el-table-column>
-				<el-table-column prop="version" label="版本" width="80" align="center"></el-table-column>
-				<el-table-column prop="status" label="状态" width="100" align="center">
-					<template #default="scope">
-						<el-tag size="small" v-if="scope.row.status === 'Draft'">草稿</el-tag>
-						<el-tag size="small" type="success" v-else-if="scope.row.status === 'Published'">已发布</el-tag>
-						<el-tag size="small" type="info" v-else-if="scope.row.status === 'Deprecated'">已废弃</el-tag>
-						<span v-else>{{ scope.row.status }}</span>
-					</template>
-				</el-table-column>
-				<el-table-column prop="createdAt" label="创建时间" width="160" align="center"></el-table-column>
-				<el-table-column label="操作" width="220" align="center">
-					<template #default="scope">
-						<el-button size="small" text type="primary" @click="viewDetail(scope.row)" v-auth="'view'">查看</el-button>
-						<el-button size="small" text type="warning" @click="addOrEdit(scope.row)" v-auth="'edit'">编辑</el-button>
-						<el-button size="small" text type="success" @click="testApi(scope.row)" v-auth="'test'">测试</el-button>
-						<el-dropdown @command="(command) => handleCommand(command, scope.row)">
-							<el-button size="small" text type="primary">
-								更多<el-icon class="el-icon--right"><arrow-down /></el-icon>
+						<el-form-item label="API名称" prop="keyWord">
+							<el-input v-model="params.keyWord" placeholder="请输入API名称" clearable style="width: 180px" @keyup.enter.native="getList(1)" />
+						</el-form-item>
+						<el-form-item label="数据源" prop="dataSourceId">
+							<el-select v-model="params.dataSourceId" placeholder="请选择数据源" clearable style="width: 180px">
+								<el-option v-for="item in dataSources" :key="item.id" :label="item.name" :value="item.id" />
+							</el-select>
+						</el-form-item>
+						<el-form-item label="状态" prop="status">
+							<el-select v-model="params.status" placeholder="请选择状态" clearable style="width: 120px">
+								<el-option label="全部" value="" />
+								<el-option label="草稿" value="Draft" />
+								<el-option label="已发布" value="Published" />
+								<el-option label="已废弃" value="Deprecated" />
+							</el-select>
+						</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-form-item>
+						<el-form-item>
+							<el-button type="primary" class="ml10" @click="getList(1)">
+								<el-icon>
+									<ele-Search />
+								</el-icon>
+								查询
+							</el-button>
+							<el-button @click="resetQuery()">
+								<el-icon>
+									<ele-Refresh />
+								</el-icon>
+								重置
+							</el-button>
+							<el-button type="primary" @click="addOrEdit()" v-auth="'add'">
+								<el-icon>
+									<ele-FolderAdd />
+								</el-icon>
+								新增API
 							</el-button>
-							<template #dropdown>
-								<el-dropdown-menu>
-									<el-dropdown-item command="publish" v-if="scope.row.status === 'Draft'" v-auth="'publish'">发布</el-dropdown-item>
-									<el-dropdown-item command="deprecate" v-if="scope.row.status === 'Published'" v-auth="'deprecate'">废弃</el-dropdown-item>
-									<el-dropdown-item command="delete" v-auth="'delete'">删除</el-dropdown-item>
-								</el-dropdown-menu>
+						</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" />
+						<el-table-column prop="id" label="ID" width="80" align="center" />
+						<el-table-column prop="name" label="API名称" min-width="120" show-overflow-tooltip></el-table-column>
+						<el-table-column prop="path" label="API路径" min-width="150" show-overflow-tooltip></el-table-column>
+						<el-table-column prop="method" label="请求方法" width="100" align="center">
+							<template #default="scope">
+								<el-tag
+									:type="getMethodTagType(scope.row.method)"
+									size="small">
+									{{ scope.row.method }}
+								</el-tag>
 							</template>
-						</el-dropdown>
-					</template>
-				</el-table-column>
-			</el-table>
+						</el-table-column>
+						<el-table-column prop="dataSourceName" label="数据源" width="120" show-overflow-tooltip></el-table-column>
+						<el-table-column prop="sqlType" label="SQL类型" width="100" align="center">
+							<template #default="scope">
+								<el-tag size="small" type="info" v-if="scope.row.sqlType === 'query'">查询</el-tag>
+								<el-tag size="small" type="warning" v-else-if="scope.row.sqlType === 'procedure'">存储过程</el-tag>
+								<span v-else>{{ scope.row.sqlType }}</span>
+							</template>
+						</el-table-column>
+						<el-table-column prop="version" label="版本" width="80" align="center"></el-table-column>
+						<el-table-column prop="status" label="状态" width="100" align="center">
+							<template #default="scope">
+								<el-tag size="small" v-if="scope.row.status === 'Draft'">草稿</el-tag>
+								<el-tag size="small" type="success" v-else-if="scope.row.status === 'Published'">已发布</el-tag>
+								<el-tag size="small" type="info" v-else-if="scope.row.status === 'Deprecated'">已废弃</el-tag>
+								<span v-else>{{ scope.row.status }}</span>
+							</template>
+						</el-table-column>
+						<el-table-column prop="createdAt" label="创建时间" width="160" align="center"></el-table-column>
+						<el-table-column label="操作" width="220" align="center">
+							<template #default="scope">
+								<el-button size="small" text type="primary" @click="viewDetail(scope.row)" v-auth="'view'">查看</el-button>
+								<el-button size="small" text type="warning" @click="addOrEdit(scope.row)" v-auth="'edit'">编辑</el-button>
+								<el-button size="small" text type="success" @click="testApi(scope.row)" v-auth="'test'">测试</el-button>
+								<el-dropdown @command="(command: string) => handleCommand(command, scope.row)">
+									<el-button size="small" text type="primary">
+										更多<el-icon class="el-icon--right"><arrow-down /></el-icon>
+									</el-button>
+									<template #dropdown>
+										<el-dropdown-menu>
+											<el-dropdown-item command="publish" v-if="scope.row.status === 'Draft'" v-auth="'publish'">发布</el-dropdown-item>
+											<el-dropdown-item command="deprecate" v-if="scope.row.status === 'Published'" v-auth="'deprecate'">废弃</el-dropdown-item>
+											<el-dropdown-item command="delete" v-auth="'delete'">删除</el-dropdown-item>
+										</el-dropdown-menu>
+									</template>
+								</el-dropdown>
+							</template>
+						</el-table-column>
+					</el-table>
 					<pagination v-if="params.total" :total="params.total" v-model:page="params.pageNum" v-model:limit="params.pageSize" @pagination="getList()" />
 				</el-card>
 			</div>
@@ -195,7 +191,7 @@ import GroupForm from './component/group.vue'
 import { useSearch } from '/@/hooks/useCommon'
 import { ElMessageBox, ElMessage } from 'element-plus'
 import { ArrowDown } from '@element-plus/icons-vue'
-import request from '/@/utils/request'
+import api from '/@/api/modules/apiHub'
 
 // 定义API接口类型
 interface ApiDefinition {
@@ -227,101 +223,65 @@ const groupTreeRef = ref()
 
 // 分组相关状态
 const groupSearchKey = ref('')
-const groupTreeData = ref([])
-const currentGroup = reactive({
+const groupTreeData = ref<any[]>([])
+const currentGroup = reactive<any>({
 	Id: undefined,
 	GroupKey: '',
 	Name: '',
 	ParentId: 0,
 	Description: ''
 })
-const originalGroupTree = ref([])
+const originalGroupTree = ref<any[]>([])
 
 // 数据源列表
-const dataSources = ref([])
-
-// API列表请求函数
-const apiRequest = (params: any) => {
-	// 这里使用request函数发起请求
-	// 实际使用时替换为真实API路径
-	return request({
-		url: '/api/list',
-		method: 'get',
-		params
-	})
-}
-
-// 获取分组树形结构
-const getGroupTree = () => {
-	return request({
-		url: '/api_group/tree',
-		method: 'get'
-	})
-}
-
-// 删除分组
-const deleteGroup = (ids: number[]) => {
-	return request({
-		url: '/api_group/delete',
-		method: 'post',
-		data: { ids }
-	})
-}
+const dataSources = ref<any[]>([])
 
 // 使用通用搜索钩子
-const { params, tableData, getList, loading } = useSearch<ApiDefinition[]>(
-	apiRequest,
-	'data',
-	{
-		keyWord: '',
-		dataSourceId: '',
-		status: '',
-		dateRange: [],
-		orderBy: '',
-		pageNum: 1,
-		pageSize: 10
-	}
-)
+const { params, tableData, getList, loading } = useSearch<ApiDefinition[]>(api.list, 'Data', {
+	keyWord: '',
+	dataSourceId: '',
+	status: '',
+	dateRange: [],
+	orderBy: '',
+	pageNum: 1,
+	pageSize: 10
+})
 
 // 加载数据源列表
 const loadDataSources = () => {
-	// 实际使用时替换为真实API调用
-	// 模拟数据
-	dataSources.value = [
-		{ id: 1, name: '主数据库' },
-		{ id: 2, name: '业务数据库' },
-		{ id: 3, name: '日志数据库' }
-	]
+	api.dataSource.list().then((res: any) => {
+		dataSources.value = res.list
+	})
 }
 
 // 页面加载时获取列表数据
 onMounted(() => {
 	// 获取API列表
 	getList(1)
-	
+
 	// 加载数据源列表
 	loadDataSources()
-	
+
 	// 加载分组树
 	refreshGroups()
 })
 
 // 将扁平数组转换为树形结构
-const convertToTree = (flatData) => {
+const convertToTree = (flatData: any[]) => {
 	// 创建一个映射表,用于快速查找节点
-	const map = {}
-	const result = []
-	
+	const map: any = {}
+	const result: any[] = []
+
 	// 首先创建所有节点的映射
 	flatData.forEach(item => {
 		// 确保每个节点都有Children属性
 		map[item.Id] = { ...item, Children: [] }
 	})
-	
+
 	// 然后建立父子关系
 	flatData.forEach(item => {
 		const node = map[item.Id]
-		
+
 		if (item.ParentId === 0 || !map[item.ParentId]) {
 			// 如果ParentId为0或者父节点不存在,则为顶级节点
 			result.push(node)
@@ -330,19 +290,19 @@ const convertToTree = (flatData) => {
 			map[item.ParentId].Children.push(node)
 		}
 	})
-	
+
 	// 清理空的Children数组
 	flatData.forEach(item => {
 		if (map[item.Id].Children.length === 0) {
 			map[item.Id].Children = null
 		}
 	})
-	
+
 	return result
 }
 
 // 检查数据是否已经是树形结构
-const isTreeStructure = (data) => {
+const isTreeStructure = (data: any[]) => {
 	// 检查数据中是否有包含非空的Children字段的项
 	return data.some(item => item.Children && Array.isArray(item.Children) && item.Children.length > 0)
 }
@@ -351,60 +311,29 @@ const isTreeStructure = (data) => {
 const refreshGroups = async () => {
 	try {
 		// 调用API获取分组树
-		const res = await getGroupTree()
-		console.log('获取到的API分组数据:', res)
+		const res: any = await api.group.tree()
 
 		// 使用API返回的数据
-		if (res.data && res.data.list) {
+		if (res?.list) {
 			// 获取原始数据
-			const apiData = res.data.list || []
-			console.log('原始数据:', apiData)
-			
+			const apiData = res.list || []
+
 			// 检查数据是否已经是树形结构
 			const hasTreeStructure = isTreeStructure(apiData)
-			console.log('是否已经是树形结构:', hasTreeStructure)
-			
-			let treeData
+
+			let treeData: any[]
 			if (hasTreeStructure) {
 				// 如果已经是树形结构,直接使用
 				treeData = apiData
-				console.log('使用原始树形结构')
 			} else {
 				// 如果是扁平结构,通过ParentId构建树形结构
 				treeData = convertToTree(apiData)
-				console.log('通过ParentId构建的树形结构:', treeData)
 			}
-			
-			// 手动设置测试数据,确认组件是否正常工作
-			const testData = [
-				{
-					"Id": 10,
-					"GroupKey": "group_1746503398664_968",
-					"Name": "巡检管理",
-					"ParentId": 0,
-					"Sort": 0,
-					"Description": "",
-					"Children": [
-						{
-							"Id": 11,
-							"GroupKey": "group_1746515959076_509",
-							"Name": "能耗分析",
-							"ParentId": 10,
-							"Sort": 0,
-							"Description": "",
-							"Children": null,
-							"ApiCount": 0
-						}
-					],
-					"ApiCount": 0
-				}
-			]
-			console.log('测试数据:', testData)
-			
+
+
 			// 设置到组件中
-			groupTreeData.value = testData
-			originalGroupTree.value = JSON.parse(JSON.stringify(testData))
-			console.log('设置后的分组数据:', groupTreeData.value)
+			groupTreeData.value = treeData
+			originalGroupTree.value = JSON.parse(JSON.stringify(treeData))
 			return
 		}
 
@@ -425,7 +354,7 @@ const filterGroups = () => {
 	}
 
 	// 递归搜索函数
-	const searchTree = (nodes) => {
+	const searchTree = (nodes: any[]) => {
 		return nodes.filter(node => {
 			// 当前节点名称匹配
 			const matchesName = node.Name.toLowerCase().includes(groupSearchKey.value.toLowerCase())
@@ -445,7 +374,8 @@ const filterGroups = () => {
 }
 
 // 点击分组节点
-const handleGroupClick = (data) => {
+const handleGroupClick = (data: any) => {
+	console.log(data)
 	// 设置当前选中分组
 	Object.assign(currentGroup, data)
 
@@ -462,7 +392,7 @@ const addGroup = () => {
 }
 
 // 处理分组操作
-const handleGroupCommand = (command, data) => {
+const handleGroupCommand = (command: string, data: any) => {
 	switch (command) {
 		case 'edit':
 			groupFormRef.value.open(data)
@@ -477,7 +407,7 @@ const handleGroupCommand = (command, data) => {
 }
 
 // 删除分组确认
-const deleteGroupConfirm = (data) => {
+const deleteGroupConfirm = (data: any) => {
 	ElMessageBox.confirm(`确定要删除分组「${data.Name}」吗?如果包含子分组或API,将一并删除。`, '警告', {
 		confirmButtonText: '确定',
 		cancelButtonText: '取消',
@@ -485,7 +415,7 @@ const deleteGroupConfirm = (data) => {
 	}).then(async () => {
 		try {
 			// 实际使用时调用API
-			await deleteGroup([data.Id])
+			await api.group.delete([data.Id])
 			ElMessage.success('删除成功')
 
 			// 如果当前选中的是要删除的分组,则清空当前分组
@@ -506,7 +436,7 @@ const deleteGroupConfirm = (data) => {
 		} catch (error) {
 			ElMessage.error('删除失败')
 		}
-	}).catch(() => {})
+	}).catch(() => { })
 }
 
 // 根据请求方法返回不同的标签类型
@@ -539,7 +469,7 @@ const addOrEdit = (row?: ApiDefinition) => {
 		editFormRef.value.open(row)
 	} else {
 		// 新增API,如果有选中分组,则传递分组标识
-		editFormRef.value.open(null, currentGroup.groupKey)
+		editFormRef.value.open(null, currentGroup.GroupKey)
 	}
 }
 
@@ -575,11 +505,10 @@ const publishApi = (row: ApiDefinition) => {
 		cancelButtonText: '取消',
 		type: 'warning'
 	}).then(async () => {
-		// 实际使用时替换为真实API调用
-		// await api.apihub.publish({ id: row.id })
+		await api.publish(row.id!)
 		ElMessage.success('发布成功')
 		getList()
-	}).catch(() => {})
+	})
 }
 
 // 废弃API
@@ -589,11 +518,10 @@ const deprecateApi = (row: ApiDefinition) => {
 		cancelButtonText: '取消',
 		type: 'warning'
 	}).then(async () => {
-		// 实际使用时替换为真实API调用
-		// await api.apihub.deprecate({ id: row.id })
+		await api.deprecate(row.id!)
 		ElMessage.success('废弃成功')
 		getList()
-	}).catch(() => {})
+	})
 }
 
 // 删除API
@@ -603,11 +531,10 @@ const deleteApi = (row: ApiDefinition) => {
 		cancelButtonText: '取消',
 		type: 'error'
 	}).then(async () => {
-		// 实际使用时替换为真实API调用
-		// await api.apihub.delete({ ids: [row.id] })
+		await api.delete([row.id!])
 		ElMessage.success('删除成功')
 		getList()
-	}).catch(() => {})
+	})
 }
 </script>
 
@@ -656,8 +583,10 @@ const deleteApi = (row: ApiDefinition) => {
 .group-tree-container {
 	overflow-y: auto;
 	flex: 1;
-	min-height: 200px; /* 确保容器有最小高度 */
-	border: 1px solid #ebeef5; /* 添加边框以便于调试 */
+	min-height: 200px;
+	/* 确保容器有最小高度 */
+	border: 1px solid #ebeef5;
+	/* 添加边框以便于调试 */
 	padding: 10px;
 }
 

+ 41 - 109
src/views/apihub/component/edit.vue

@@ -5,8 +5,7 @@
 		:title="`${formData.id ? '编辑API' : '新增API'}`"
 		width="800px"
 		:close-on-click-modal="false"
-		:close-on-press-escape="false"
-	>
+		:close-on-press-escape="false">
 		<el-form ref="formRef" :model="formData" :rules="ruleForm" label-width="100px" @keyup.enter="onSubmit">
 			<el-form-item label="API名称" prop="name">
 				<el-input v-model="formData.name" placeholder="请输入API名称" />
@@ -37,16 +36,15 @@
 				<el-cascader
 					v-model="formData.groupKey"
 					:options="groupOptions"
-					:props="{ checkStrictly: true, emitPath: false, value: 'groupKey', label: 'name' }"
+					:props="{ checkStrictly: true, emitPath: false, value: 'GroupKey', label: 'Name', children: 'Children' }"
 					placeholder="请选择所属分组"
 					clearable
-					style="width: 100%"
-				/>
+					style="width: 100%" />
 			</el-form-item>
 			<el-form-item label="SQL内容" prop="sqlContent">
 				<el-input v-model="formData.sqlContent" type="textarea" :rows="4" placeholder="请输入SQL语句或存储过程名称" />
 			</el-form-item>
-			
+
 			<el-form-item label="参数定义">
 				<el-button type="primary" size="small" @click="addParameter">
 					<el-icon><ele-Plus /></el-icon>添加参数
@@ -91,7 +89,7 @@
 					</el-table-column>
 				</el-table>
 			</el-form-item>
-			
+
 			<el-form-item label="返回格式" prop="returnFormat">
 				<el-select v-model="formData.returnFormat" placeholder="请选择返回格式">
 					<el-option label="JSON" value="JSON"></el-option>
@@ -125,28 +123,28 @@
 import { ref, reactive, nextTick } from 'vue'
 import { ElMessage } from 'element-plus'
 import { ruleRequired } from '/@/utils/validator'
-import request from '/@/utils/request'
+import api from '/@/api/modules/apiHub'
 
 const emit = defineEmits(['getList'])
 
 const showDialog = ref(false)
 const formRef = ref()
-const dataSources = ref([
-	{ id: 1, name: '主数据库' },
-	{ id: 2, name: '业务数据库' },
-	{ id: 3, name: '日志数据库' }
-])
+const dataSources = ref<any[]>([])
+
+api.dataSource.list().then((res: any) => {
+	dataSources.value = res.list
+})
 
 // 分组选项
 const groupOptions = ref([])
 
 // 定义基础表单数据
 const baseForm = {
-	id: undefined,
+	id: null,
 	name: '',
 	path: '',
 	method: 'GET',
-	dataSourceId: undefined,
+	dataSourceId: null,
 	sqlType: 'query',
 	sqlContent: '',
 	parameters: [],
@@ -188,53 +186,31 @@ const addParameter = () => {
 }
 
 // 移除参数
-const removeParameter = (index) => {
+const removeParameter = (index: number) => {
 	formData.parameters.splice(index, 1)
 }
 
-// 添加API
-const addApi = (data) => {
-	return request({
-		url: '/api/add',
-		method: 'post',
-		data
-	})
-}
-
-// 编辑API
-const editApi = (data) => {
-	return request({
-		url: '/api/edit',
-		method: 'put',
-		data
-	})
-}
-
 // 提交表单
 const onSubmit = async () => {
-	try {
-		// 表单验证
-		await formRef.value.validate()
-		
-		// 准备提交数据
-		const submitData = JSON.parse(JSON.stringify(formData))
-		
-		// 调用API
-		if (submitData.id) {
-			// 编辑模式
-			await editApi(submitData)
-		} else {
-			// 新增模式
-			await addApi(submitData)
-		}
-		
-		ElMessage.success('操作成功')
-		resetForm()
-		showDialog.value = false
-		emit('getList')
-	} catch (error) {
-		ElMessage.error(error.message || '操作失败')
+	// 表单验证
+	await formRef.value.validate()
+
+	// 准备提交数据
+	const submitData = JSON.parse(JSON.stringify(formData))
+
+	// 调用API
+	if (submitData.id) {
+		// 编辑模式
+		await api.edit(submitData)
+	} else {
+		// 新增模式
+		await api.add(submitData)
 	}
+
+	ElMessage.success('操作成功')
+	resetForm()
+	showDialog.value = false
+	emit('getList')
 }
 
 // 重置表单
@@ -249,81 +225,37 @@ const cancel = () => {
 	showDialog.value = false
 }
 
-// 获取分组树形结构
-const getGroupTree = async () => {
-	try {
-		// 调用API获取分组树
-		const res = await request({
-			url: '/api_group/tree',
-			method: 'get'
-		})
-		return res.data?.list || []
-		
-		// 模拟数据
-		return [
-			{
-				id: 1,
-				groupKey: 'test_group',
-				name: '测试分组',
-				parentKey: '',
-				sort: 0,
-				description: '这是一个测试分组',
-				children: [
-					{
-						id: 3,
-						groupKey: 'test_subgroup',
-						name: '测试子分组',
-						parentKey: 'test_group',
-						sort: 0,
-						description: '这是一个测试子分组',
-						children: []
-					}
-				]
-			},
-			{
-				id: 2,
-				groupKey: 'user_api',
-				name: '用户API',
-				parentKey: '',
-				sort: 1,
-				description: '用户相关API',
-				children: []
-			}
-		]
-	} catch (error) {
-		ElMessage.error('获取分组树失败')
-		return []
-	}
-}
-
 // 加载分组选项
 const loadGroupOptions = async () => {
-	const treeData = await getGroupTree()
-	groupOptions.value = treeData
+	api.group.tree().then((res: any) => {
+		groupOptions.value = res.list || []
+	})
 }
 
 // 打开对话框
 const open = async (row?: any, defaultGroupKey?: string) => {
 	resetForm()
 	showDialog.value = true
-	
+
 	// 加载分组选项
 	await loadGroupOptions()
-	
+
 	if (row) {
 		// 编辑模式,填充表单数据
 		nextTick(() => {
 			// 如果是编辑模式,需要先获取详情
 			// 实际使用时,可能需要先调用API获取完整数据
 			// 这里模拟直接使用传入的行数据
+
 			Object.assign(formData, JSON.parse(JSON.stringify(row)))
-			
+
 			// 确保参数数组存在
 			if (!formData.parameters) {
 				formData.parameters = []
 			}
 		})
-	} else if (defaultGroupKey) {
+	}
+	if (defaultGroupKey) {
 		// 新增模式,设置默认分组
 		formData.groupKey = defaultGroupKey
 	}

+ 53 - 83
src/views/apihub/component/group.vue

@@ -5,8 +5,7 @@
 		:title="`${formData.id ? '编辑分组' : '新增分组'}`"
 		width="500px"
 		:close-on-click-modal="false"
-		:close-on-press-escape="false"
-	>
+		:close-on-press-escape="false">
 		<el-form ref="formRef" :model="formData" :rules="ruleForm" label-width="100px" @keyup.enter="onSubmit">
 			<el-form-item label="分组名称" prop="name">
 				<el-input v-model="formData.name" placeholder="请输入分组名称" />
@@ -14,15 +13,14 @@
 			<el-form-item label="分组标识" prop="groupKey">
 				<el-input v-model="formData.groupKey" placeholder="请输入分组唯一标识,留空则自动生成" />
 			</el-form-item>
-			<el-form-item label="父级分组" prop="parentKey">
+			<el-form-item label="父级分组" prop="parentId">
 				<el-cascader
-					v-model="formData.parentKey"
+					v-model="formData.parentId"
 					:options="groupOptions"
-					:props="{ checkStrictly: true, emitPath: false, value: 'groupKey', label: 'name' }"
+					:props="{ checkStrictly: true, emitPath: false, value: 'Id', label: 'Name', children: 'Children' }"
 					placeholder="请选择父级分组,不选择则为顶级分组"
 					clearable
-					style="width: 100%"
-				/>
+					style="width: 100%" />
 			</el-form-item>
 			<el-form-item label="排序号" prop="sort">
 				<el-input-number v-model="formData.sort" :min="0" :max="999" />
@@ -44,25 +42,26 @@
 import { ref, reactive, nextTick } from 'vue'
 import { ElMessage } from 'element-plus'
 import { ruleRequired } from '/@/utils/validator'
-import request from '/@/utils/request'
+import api from '/@/api/modules/apiHub'
 
 const emit = defineEmits(['refresh'])
 
 const showDialog = ref(false)
 const formRef = ref()
-const groupOptions = ref([])
+const groupOptions = ref<any[]>([])
+let treeData: any[] = []
 
 // 定义基础表单数据
 const baseForm = {
 	id: undefined,
 	groupKey: '',
 	name: '',
-	parentKey: '',
+	parentId: '',
 	sort: 0,
 	description: ''
 }
 
-const formData = reactive({...baseForm})
+const formData = reactive({ ...baseForm })
 
 // 表单验证规则
 const ruleForm = {
@@ -70,78 +69,46 @@ const ruleForm = {
 }
 
 // 获取分组树形结构
-const getGroupTree = async () => {
-	try {
-		// 调用API获取分组树
-		const res = await request({
-			url: '/api_group/tree',
-			method: 'get'
-		})
-		return res.data?.list || []
-	} catch (error) {
-		ElMessage.error('获取分组树失败')
-		return []
-	}
-}
-
-// 添加分组
-const addGroup = async (data) => {
-	return request({
-		url: '/api_group/add',
-		method: 'post',
-		data
-	})
-}
-
-// 编辑分组
-const editGroup = async (data) => {
-	return request({
-		url: '/api_group/edit',
-		method: 'post',
-		data
-	})
-}
+api.group.tree().then((res: any) => {
+	treeData = res.list || []
+	groupOptions.value = res.list || []
+})
 
 // 提交表单
 const onSubmit = async () => {
-	try {
-		// 表单验证
-		await formRef.value.validate()
+	await formRef.value.validate()
 
-		// 准备提交数据
-		const submitData = JSON.parse(JSON.stringify(formData))
-
-		// 如果没有设置groupKey,生成一个基于名称的唯一标识
-		if (!submitData.groupKey) {
-			submitData.groupKey = 'group_' + Date.now() + '_' + Math.floor(Math.random() * 1000)
-		}
+	// 准备提交数据
+	const submitData = JSON.parse(JSON.stringify(formData))
 
-		// 处理空的parent_key,将空字符串设置为null
-		if (submitData.parentKey === '') {
-			submitData.parentKey = null
-		}
+	// 如果没有设置groupKey,生成一个基于名称的唯一标识
+	if (!submitData.groupKey) {
+		submitData.groupKey = 'group_' + Date.now() + '_' + Math.floor(Math.random() * 1000)
+	}
 
-		// 调用API
-		if (submitData.id) {
-			// 编辑模式
-			await editGroup(submitData)
-		} else {
-			// 新增模式
-			await addGroup(submitData)
-		}
+	// 处理空的parent_key,将空字符串设置为null
+	if (submitData.parentId === '') {
+		submitData.parentId = null
+	}
 
-		ElMessage.success('操作成功')
-		resetForm()
-		showDialog.value = false
-		emit('refresh')
-	} catch (error) {
-		ElMessage.error(error.message || '操作失败')
+	// 调用API
+	if (submitData.id) {
+		// 编辑模式
+		await api.group.edit(submitData)
+	} else {
+		// 新增模式
+		await api.group.add(submitData)
 	}
+
+	ElMessage.success('操作成功')
+	resetForm()
+	showDialog.value = false
+	emit('refresh')
 }
 
 // 重置表单
 const resetForm = () => {
-	Object.assign(formData, {...baseForm})
+	Object.assign(formData, { ...baseForm })
 	formRef.value && formRef.value.resetFields()
 }
 
@@ -152,18 +119,16 @@ const cancel = () => {
 }
 
 // 加载分组选项
-const loadGroupOptions = async (excludeId) => {
-	const treeData = await getGroupTree()
-
+const loadGroupOptions = async (excludeId?: string) => {
 	// 如果是编辑模式,需要排除当前分组及其子分组
 	if (excludeId) {
-		const filterTree = (nodes) => {
+		const filterTree = (nodes: any[]) => {
 			return nodes.filter(node => {
-				if (node.id === excludeId) {
+				if (node.Id === excludeId) {
 					return false
 				}
-				if (node.children && node.children.length) {
-					node.children = filterTree(node.children)
+				if (node.Children && node.Children.length) {
+					node.Children = filterTree(node.Children)
 				}
 				return true
 			})
@@ -176,21 +141,26 @@ const loadGroupOptions = async (excludeId) => {
 }
 
 // 打开对话框
-const open = async (row?: any, parentKey?: string) => {
+const open = async (row?: any, parentId?: string) => {
 	resetForm()
 	showDialog.value = true
 
 	// 加载分组选项
-	await loadGroupOptions(row?.id)
+	await loadGroupOptions(row?.Id)
 
 	if (row) {
 		// 编辑模式,填充表单数据
 		nextTick(() => {
-			Object.assign(formData, JSON.parse(JSON.stringify(row)))
+			formData.id = row.Id
+			formData.groupKey = row.GroupKey
+			formData.name = row.Name
+			formData.parentId = row.ParentId
+			formData.sort = row.Sort
+			formData.description = row.Description
 		})
-	} else if (parentKey) {
+	} else if (parentId) {
 		// 新增子分组模式
-		formData.parentKey = parentKey
+		formData.parentId = parentId
 	}
 }
 

+ 37 - 46
src/views/apihub/component/test.vue

@@ -5,8 +5,7 @@
 		title="测试API"
 		width="800px"
 		:close-on-click-modal="false"
-		:close-on-press-escape="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>
@@ -15,41 +14,34 @@
 			</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>
+			<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>
@@ -57,9 +49,8 @@
 				:title="testResult.message"
 				:type="testResult.success ? 'success' : 'error'"
 				:closable="false"
-				show-icon
-			></el-alert>
-			
+				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">
@@ -71,7 +62,7 @@
 				</el-tabs>
 			</div>
 		</div>
-		
+
 		<template #footer>
 			<div class="dialog-footer">
 				<el-button @click="closeDialog">关闭</el-button>
@@ -89,7 +80,7 @@ const loading = ref(false)
 const activeTab = ref('data')
 
 // API数据
-const apiData = reactive({
+const apiData = reactive<any>({
 	id: undefined,
 	name: '',
 	path: '',
@@ -124,7 +115,7 @@ watch(() => apiData.parameters, (newParams) => {
 	Object.keys(testParams).forEach(key => {
 		delete testParams[key]
 	})
-	
+
 	// 根据参数定义初始化测试参数
 	if (newParams && newParams.length) {
 		newParams.forEach(param => {
@@ -198,23 +189,23 @@ const runTest = async () => {
 	testResult.success = false
 	testResult.message = ''
 	testResult.data = null
-	
+
 	loading.value = true
-	
+
 	try {
 		// 实际使用时,应该调用API进行测试
 		// const res = await api.apihub.test({ 
 		//   id: apiData.id,
 		//   parameters: testParams
 		// })
-		
+
 		// 模拟API调用
 		await new Promise(resolve => setTimeout(resolve, 1000))
-		
+
 		// 模拟测试结果
 		testResult.success = true
 		testResult.message = '测试成功'
-		
+
 		// 根据API类型模拟不同的测试数据
 		if (apiData.path.includes('users')) {
 			if (apiData.method === 'GET') {
@@ -252,18 +243,18 @@ const open = async (row: any) => {
 	Object.keys(apiData).forEach(key => {
 		apiData[key] = undefined
 	})
-	
+
 	// 重置测试结果
 	testResult.success = false
 	testResult.message = ''
 	testResult.data = null
-	
+
 	showDialog.value = true
-	
+
 	// 实际使用时,应该调用API获取详细信息
 	// const res = await api.apihub.getDetail({ id: row.id })
 	// Object.assign(apiData, res)
-	
+
 	// 这里模拟直接使用传入的行数据
 	Object.assign(apiData, row)
 }