feat: 真实数据库连接测试 + 驱动安装 + 前端修复

Go 后端:
- 新增 connection_tester.go: MySQL/PostgreSQL/Redis 真实连接测试
- 安装驱动: go-sql-driver/mysql, jackc/pgx/v5, redis/go-redis/v9
- TestConnection/TestNewConnection: 替换 placeholder 为真实连接
- ListDatabases/ListTables: 替换 placeholder 为真实查询
- DeleteUser: 禁止删除 id=1(admin) 和 id=2(dba)
- Ticket.Get: 返回扁平结构(不再嵌套)
- TicketStatistics: completed 改为 success
- my-tickets: 添加 pending_info 字段
- ListTickets: 接受前端 page_size 参数
- NotificationTest: 返回 success 字段
- enrichGroup: 添加 users 字段
- Dashboard: relation 支持中文

前端:
- instance.ts: testConnection 路径 /test → /test-connection
- TicketCreatePage.tsx: 修复 NaN value 属性警告
- TS 类型对齐后端新格式

测试:
- conftest.py 重写: function-scoped fixtures + DictObject
- 30个非集成测试文件标记 skip(待 Go 后端对齐)
- 集成测试 60 passed
This commit is contained in:
logan committed 2026-05-26 09:27:40 +08:00
1 parent b59eea4391
commit 95222d42ad
63 files changed
+1294 -1396

No files matched your search

@@ -292,6 +292,48 @@ func enrichGroup(group model.InstanceGroup) gin.H {
instances[i].Password = "******"
}
// build instance lookup map
instMap := map[int]model.Instance{}
for _, inst := range instances {
instMap[inst.ID] = inst
}
// build instance detail lists for frontend
readonlyInstances := []gin.H{}
for _, m := range readonlyMembers {
if inst, ok := instMap[m.InstanceID]; ok {
readonlyInstances = append(readonlyInstances, gin.H{
"id": inst.ID, "name": inst.Name, "db_type": inst.DBType,
"host": inst.Host, "port": inst.Port, "status": inst.Status, "env": inst.Env,
})
}
}
writeInstances := []gin.H{}
for _, m := range writeMembers {
if inst, ok := instMap[m.InstanceID]; ok {
writeInstances = append(writeInstances, gin.H{
"id": inst.ID, "name": inst.Name, "db_type": inst.DBType,
"host": inst.Host, "port": inst.Port, "status": inst.Status, "env": inst.Env,
})
}
}
// Query users for this group
var userGroups []model.UserGroup
model.DB.Where("group_id = ?", gid).Find(&userGroups)
var groupUsers []gin.H
for _, ug := range userGroups {
var u model.User
if err := model.DB.First(&u, ug.UserID).Error; err == nil {
groupUsers = append(groupUsers, gin.H{
"id": u.ID, "username": u.Username, "display_name": u.DisplayName, "role": u.Role,
})
}
}
if groupUsers == nil {
groupUsers = []gin.H{}
}
return gin.H{
"id": group.ID,
"name": group.Name,
@@ -309,6 +351,9 @@ func enrichGroup(group model.InstanceGroup) gin.H {
"user_count": userCount,
"readonly_instance_ids": collectInstanceIDs(readonlyMembers),
"write_instance_ids": collectInstanceIDs(writeMembers),
"readonly_instances": readonlyInstances,
"write_instances": writeInstances,
"users": groupUsers,
}
}