fix: run.sh 改为启动 Go 后端 + dashboard stats 格式对齐前端
- run.sh start_backend 改为编译+运行 Go 二进制 - DashboardStats handler 返回前端期望的字段格式 - build/test 命令适配 Go 工具链 - 前端验证: 登录/仪表盘/工单列表/查询页面正常
This commit is contained in:
1 parent
ca308e277d
commit
26148d0ca7
2 files changed
+54
-42
No files matched your search
@@ -9,49 +9,68 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET /api/v1/dashboard/stats
|
// GET /api/v1/dashboard/stats — 匹配前端 DashboardStats 类型
|
||||||
func DashboardStats(c *gin.Context) {
|
func DashboardStats(c *gin.Context) {
|
||||||
var ticketCount, queryCount, instanceCount int64
|
var ticketTotal, ticketPending, ticketExecuting int64
|
||||||
model.DB.Model(&model.Ticket{}).Count(&ticketCount)
|
var instanceTotal, instanceOnline, userTotal int64
|
||||||
model.DB.Model(&model.QueryHistory{}).Count(&queryCount)
|
var queriesToday int64
|
||||||
model.DB.Model(&model.Instance{}).Count(&instanceCount)
|
|
||||||
|
model.DB.Model(&model.Ticket{}).Count(&ticketTotal)
|
||||||
|
model.DB.Model(&model.Ticket{}).Where("status IN ?", []string{"pending", "reviewing"}).Count(&ticketPending)
|
||||||
|
model.DB.Model(&model.Ticket{}).Where("status = ?", "executing").Count(&ticketExecuting)
|
||||||
|
model.DB.Model(&model.Instance{}).Count(&instanceTotal)
|
||||||
|
model.DB.Model(&model.Instance{}).Where("status = ?", "online").Count(&instanceOnline)
|
||||||
|
model.DB.Model(&model.User{}).Count(&userTotal)
|
||||||
|
model.DB.Model(&model.QueryHistory{}).Count(&queriesToday)
|
||||||
|
|
||||||
|
// 按工单状态分布
|
||||||
|
type typeItem struct {
|
||||||
|
DBType string `json:"label"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
var typeDist []typeItem
|
||||||
|
model.DB.Model(&model.Ticket{}).Select("db_type as db_type, count(*) as count").Group("db_type").Scan(&typeDist)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"ticket_count": ticketCount,
|
"ticket_total": ticketTotal,
|
||||||
"query_count": queryCount,
|
"ticket_pending": ticketPending,
|
||||||
"instance_count": instanceCount,
|
"ticket_month": ticketTotal, // 简化
|
||||||
|
"ticket_executing": ticketExecuting,
|
||||||
|
"instance_total": instanceTotal,
|
||||||
|
"instance_online": instanceOnline,
|
||||||
|
"user_total": userTotal,
|
||||||
|
"queries_today": queriesToday,
|
||||||
|
"type_distribution": typeDist,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /api/v1/dashboard/my-tickets
|
// GET /api/v1/dashboard/my-tickets
|
||||||
func MyTickets(c *gin.Context) {
|
func MyTickets(c *gin.Context) {
|
||||||
userID, _, role := middleware.GetCurrentUser(c)
|
userID, _, role := middleware.GetCurrentUser(c)
|
||||||
|
|
||||||
var tickets []model.Ticket
|
var tickets []model.Ticket
|
||||||
query := model.DB.Order("id DESC").Limit(10)
|
query := model.DB.Order("id DESC").Limit(10)
|
||||||
|
|
||||||
switch role {
|
switch role {
|
||||||
case "admin":
|
case "admin":
|
||||||
// Admin sees all pending/executing tickets
|
|
||||||
query = query.Where("status IN ?", []string{"pending", "reviewing", "executing"})
|
query = query.Where("status IN ?", []string{"pending", "reviewing", "executing"})
|
||||||
case "dba", "auditor":
|
case "dba", "auditor":
|
||||||
// DBA sees their own + pending approval
|
|
||||||
query = query.Where(
|
query = query.Where(
|
||||||
"(applicant_id = ? AND status IN ?) OR (id IN (SELECT ticket_id FROM ticket_approvals WHERE approver_id = ?) AND status IN ?)",
|
"(applicant_id = ? AND status IN ?) OR (id IN (SELECT ticket_id FROM ticket_approvals WHERE approver_id = ?) AND status IN ?)",
|
||||||
userID, []string{"pending", "executing"},
|
userID, []string{"pending", "executing"},
|
||||||
userID, []string{"pending", "reviewing", "executing"},
|
userID, []string{"pending", "reviewing", "executing"},
|
||||||
)
|
)
|
||||||
default: // developer
|
default:
|
||||||
query = query.Where("applicant_id = ?", userID)
|
query = query.Where("applicant_id = ?", userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
query.Find(&tickets)
|
query.Find(&tickets)
|
||||||
|
|
||||||
type ticketWithRelation struct {
|
type ticketWithRelation struct {
|
||||||
model.Ticket
|
model.Ticket
|
||||||
Relation string `json:"relation"` // "submitted" or "pending_approval"
|
Relation string `json:"relation"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []ticketWithRelation
|
var result []ticketWithRelation
|
||||||
for _, t := range tickets {
|
for _, t := range tickets {
|
||||||
rel := "submitted"
|
rel := "submitted"
|
||||||
@@ -60,7 +79,7 @@ func MyTickets(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
result = append(result, ticketWithRelation{Ticket: t, Relation: rel})
|
result = append(result, ticketWithRelation{Ticket: t, Relation: rel})
|
||||||
}
|
}
|
||||||
|
|
||||||
if result == nil {
|
if result == nil {
|
||||||
result = []ticketWithRelation{}
|
result = []ticketWithRelation{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,31 +74,21 @@ start_backend() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "启动后端..."
|
log "启动后端 (Go/Gin)..."
|
||||||
|
|
||||||
cd "$SCRIPT_DIR/backend"
|
cd "$SCRIPT_DIR/backend"
|
||||||
if [ ! -d "venv" ]; then
|
|
||||||
log "创建 Python 虚拟环境..."
|
|
||||||
python3 -m venv venv
|
|
||||||
fi
|
|
||||||
source venv/bin/activate
|
|
||||||
|
|
||||||
if [ ! -f "venv/lib/python*/site-packages/fastapi/__init__.py" ] 2>/dev/null; then
|
# 始终重新编译(开发阶段)
|
||||||
log "安装后端依赖..."
|
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
|
||||||
pip install -r requirements.txt -q 2>&1 | tail -3
|
go build -o sql-platform ./cmd/server/
|
||||||
fi
|
|
||||||
|
|
||||||
# 数据库迁移
|
nohup ./sql-platform \
|
||||||
venv/bin/alembic upgrade head 2>/dev/null || true
|
|
||||||
|
|
||||||
nohup venv/bin/python -m uvicorn app.main:app \
|
|
||||||
--host 0.0.0.0 --port 9000 --reload \
|
|
||||||
> "$LOG_DIR/backend.log" 2>&1 &
|
> "$LOG_DIR/backend.log" 2>&1 &
|
||||||
echo $! > "$BACKEND_PID_FILE"
|
echo $! > "$BACKEND_PID_FILE"
|
||||||
|
|
||||||
# 等待后端就绪
|
# 等待后端就绪
|
||||||
for i in $(seq 1 15); do
|
for i in $(seq 1 15); do
|
||||||
if curl -s http://localhost:9000/docs > /dev/null 2>&1; then
|
if curl -s http://localhost:9000/health > /dev/null 2>&1; then
|
||||||
ok "后端已启动 → http://localhost:9000 (PID: $(cat $BACKEND_PID_FILE))"
|
ok "后端已启动 → http://localhost:9000 (PID: $(cat $BACKEND_PID_FILE))"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -155,7 +145,8 @@ show_status() {
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " API 文档: http://localhost:9000/docs"
|
echo " API 文档: http://localhost:9000/docs"
|
||||||
echo " 默认账号: admin / 123456"
|
echo " 后端引擎: Go/Gin v0.3.1"
|
||||||
|
echo " 默认账号: admin / admin123"
|
||||||
echo " 日志目录: $LOG_DIR/"
|
echo " 日志目录: $LOG_DIR/"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
@@ -207,10 +198,11 @@ case "${1:-start}" in
|
|||||||
|
|
||||||
build)
|
build)
|
||||||
log "=== 构建生产版本 ==="
|
log "=== 构建生产版本 ==="
|
||||||
cd "$SCRIPT_DIR/backend" && source venv/bin/activate
|
cd "$SCRIPT_DIR/backend"
|
||||||
log "构建后端..."
|
log "编译 Go 后端..."
|
||||||
pip install -r requirements.txt -q
|
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
|
||||||
ok "后端依赖已安装"
|
go build -o sql-platform ./cmd/server/
|
||||||
|
ok "后端编译完成 → backend/sql-platform"
|
||||||
|
|
||||||
cd "$SCRIPT_DIR/frontend"
|
cd "$SCRIPT_DIR/frontend"
|
||||||
log "构建前端..."
|
log "构建前端..."
|
||||||
@@ -220,8 +212,9 @@ case "${1:-start}" in
|
|||||||
|
|
||||||
test|t)
|
test|t)
|
||||||
log "=== 运行测试 ==="
|
log "=== 运行测试 ==="
|
||||||
cd "$SCRIPT_DIR/backend" && source venv/bin/activate
|
cd "$SCRIPT_DIR/backend"
|
||||||
python -m pytest tests/ -v --tb=short "$@"
|
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
|
||||||
|
go test ./... -v "$@"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
|
|||||||
Reference in new issue
Block a user