Commit 3f3b8f29 authored by yuguo's avatar yuguo

fix

parent 04584395
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"strings" "strings"
"internet-hospital/internal/model" "internet-hospital/internal/model"
"internet-hospital/internal/service/notification"
"internet-hospital/pkg/agent" "internet-hospital/pkg/agent"
"internet-hospital/pkg/agent/tools" "internet-hospital/pkg/agent/tools"
"internet-hospital/pkg/database" "internet-hospital/pkg/database"
...@@ -110,7 +111,10 @@ func WireCallbacks() { ...@@ -110,7 +111,10 @@ func WireCallbacks() {
return output.Response, nil return output.Response, nil
}) })
log.Println("[InitTools] AgentCallFn & WorkflowTriggerFn & SkillExecutor 注入完成") // 注入通知回调
tools.NotifyFn = notification.Notify
log.Println("[InitTools] AgentCallFn & WorkflowTriggerFn & NotifyFn & SkillExecutor 注入完成")
} }
// syncToolsToDB 将注册的工具元数据写入 AgentTool 表(不存在则创建,存在则不覆盖) // syncToolsToDB 将注册的工具元数据写入 AgentTool 表(不存在则创建,存在则不覆盖)
......
package admin package admin
import ( import (
"fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"internet-hospital/internal/service/doctor" "internet-hospital/internal/service/doctor"
...@@ -144,6 +146,7 @@ func (h *Handler) RegisterRoutes(r *gin.RouterGroup) { ...@@ -144,6 +146,7 @@ func (h *Handler) RegisterRoutes(r *gin.RouterGroup) {
adm.POST("/seed/rbac", h.SeedRBACHandler) adm.POST("/seed/rbac", h.SeedRBACHandler)
adm.POST("/seed/departments", h.SeedDepartmentsHandler) adm.POST("/seed/departments", h.SeedDepartmentsHandler)
adm.POST("/seed/medicines", h.SeedMedicinesHandler) adm.POST("/seed/medicines", h.SeedMedicinesHandler)
adm.POST("/seed/workflows", h.SeedWorkflowsHandler)
// 数据库维护 // 数据库维护
adm.GET("/db/extra-tables", h.ScanExtraTablesHandler) adm.GET("/db/extra-tables", h.ScanExtraTablesHandler)
...@@ -491,3 +494,14 @@ func (h *Handler) SeedMedicinesHandler(c *gin.Context) { ...@@ -491,3 +494,14 @@ func (h *Handler) SeedMedicinesHandler(c *gin.Context) {
response.Success(c, gin.H{"message": "药品种子数据已导入"}) response.Success(c, gin.H{"message": "药品种子数据已导入"})
} }
// SeedWorkflowsHandler 手动导入工作流种子数据
func (h *Handler) SeedWorkflowsHandler(c *gin.Context) {
created, skipped, errs := SeedWorkflows()
response.Success(c, gin.H{
"message": fmt.Sprintf("工作流种子数据导入完成:创建 %d 个,跳过 %d 个,失败 %d 个", created, skipped, len(errs)),
"created": created,
"skipped": skipped,
"errors": errs,
})
}
package admin
import (
"log"
"os"
"internet-hospital/internal/model"
"internet-hospital/pkg/database"
)
// SeedWorkflows 初始化工作流种子数据(幂等,表空时从 scripts/seed_workflows.sql 导入)
func SeedWorkflows() (created int, skipped int, errors []string) {
db := database.GetDB()
if db == nil {
errors = append(errors, "数据库未初始化")
return
}
var count int64
db.Model(&model.WorkflowDefinition{}).Count(&count)
if count > 0 {
skipped = int(count)
return
}
sqlBytes, err := os.ReadFile("scripts/seed_workflows.sql")
if err != nil {
errMsg := "无法读取 scripts/seed_workflows.sql: " + err.Error()
log.Printf("[SeedWorkflows] %s", errMsg)
errors = append(errors, errMsg)
return
}
if err := db.Exec(string(sqlBytes)).Error; err != nil {
errMsg := "执行 SQL 失败: " + err.Error()
log.Printf("[SeedWorkflows] %s", errMsg)
errors = append(errors, errMsg)
return
}
db.Model(&model.WorkflowDefinition{}).Count(&count)
created = int(count)
log.Printf("[SeedWorkflows] 工作流种子数据已导入(%d 个)", created)
return
}
...@@ -52,6 +52,7 @@ type CreateDoctorReq struct { ...@@ -52,6 +52,7 @@ type CreateDoctorReq struct {
Hospital string `json:"hospital" binding:"required"` Hospital string `json:"hospital" binding:"required"`
Introduction string `json:"introduction"` Introduction string `json:"introduction"`
Specialties []string `json:"specialties"` Specialties []string `json:"specialties"`
Price int `json:"price"`
} }
// CreateAdminReq 创建管理员请求 // CreateAdminReq 创建管理员请求
...@@ -438,7 +439,7 @@ func (s *Service) CreateDoctor(ctx context.Context, req *CreateDoctorReq) error ...@@ -438,7 +439,7 @@ func (s *Service) CreateDoctor(ctx context.Context, req *CreateDoctorReq) error
Introduction: req.Introduction, Introduction: req.Introduction,
Specialties: req.Specialties, Specialties: req.Specialties,
Rating: 5.0, Rating: 5.0,
Price: 5000, // 默认50元 Price: req.Price,
Status: "approved", Status: "approved",
} }
if err := s.db.Create(doctor).Error; err != nil { if err := s.db.Create(doctor).Error; err != nil {
......
...@@ -5,13 +5,13 @@ import ( ...@@ -5,13 +5,13 @@ import (
"fmt" "fmt"
"time" "time"
"internet-hospital/internal/model"
"internet-hospital/pkg/agent" "internet-hospital/pkg/agent"
"internet-hospital/pkg/database"
) )
// NotifyFn 通知回调函数,由 WireCallbacks 注入 notification.Notify
var NotifyFn func(userID, title, content, nType, relatedID string)
// SendNotificationTool 向用户发送系统通知(站内信 + WebSocket 推送) // SendNotificationTool 向用户发送系统通知(站内信 + WebSocket 推送)
// 此工具之前在分类 map 中声明但从未注册,此次完整落地
type SendNotificationTool struct{} type SendNotificationTool struct{}
func (t *SendNotificationTool) Name() string { return "send_notification" } func (t *SendNotificationTool) Name() string { return "send_notification" }
...@@ -46,21 +46,15 @@ func (t *SendNotificationTool) Parameters() []agent.ToolParameter { ...@@ -46,21 +46,15 @@ func (t *SendNotificationTool) Parameters() []agent.ToolParameter {
Enum: []string{"reminder", "alert", "info", "followup", "system"}, Enum: []string{"reminder", "alert", "info", "followup", "system"},
}, },
{ {
Name: "priority", Name: "related_id",
Type: "string", Type: "string",
Description: "优先级:normal/high/urgent", Description: "关联业务ID(如问诊ID、处方ID等)",
Required: false, Required: false,
Enum: []string{"normal", "high", "urgent"},
}, },
} }
} }
func (t *SendNotificationTool) Execute(_ context.Context, params map[string]interface{}) (interface{}, error) { func (t *SendNotificationTool) Execute(_ context.Context, params map[string]interface{}) (interface{}, error) {
db := database.GetDB()
if db == nil {
return nil, fmt.Errorf("数据库未初始化")
}
userID, ok := params["user_id"].(string) userID, ok := params["user_id"].(string)
if !ok || userID == "" { if !ok || userID == "" {
return nil, fmt.Errorf("user_id 必填") return nil, fmt.Errorf("user_id 必填")
...@@ -74,28 +68,19 @@ func (t *SendNotificationTool) Execute(_ context.Context, params map[string]inte ...@@ -74,28 +68,19 @@ func (t *SendNotificationTool) Execute(_ context.Context, params map[string]inte
if nType == "" { if nType == "" {
nType = "info" nType = "info"
} }
priority, _ := params["priority"].(string) relatedID, _ := params["related_id"].(string)
if priority == "" {
priority = "normal"
}
// 写入系统日志表作为站内信(复用 SystemLog) if NotifyFn == nil {
log := model.SystemLog{ return nil, fmt.Errorf("通知服务未初始化")
Action: "notification",
Resource: fmt.Sprintf("%s/%s", nType, priority),
Detail: fmt.Sprintf("[%s] %s: %s", nType, title, content),
UserID: userID,
}
if err := db.Create(&log).Error; err != nil {
return nil, fmt.Errorf("写入通知失败: %w", err)
} }
NotifyFn(userID, title, content, nType, relatedID)
return map[string]interface{}{ return map[string]interface{}{
"notification_id": log.ID, "user_id": userID,
"user_id": userID, "title": title,
"title": title, "type": nType,
"type": nType, "related_id": relatedID,
"priority": priority, "sent_at": time.Now().Format(time.RFC3339),
"sent_at": time.Now().Format(time.RFC3339),
}, nil }, nil
} }
...@@ -196,12 +196,27 @@ func (e *Engine) executeNode(ctx context.Context, wf *Workflow, node *Node, exec ...@@ -196,12 +196,27 @@ func (e *Engine) executeNode(ctx context.Context, wf *Workflow, node *Node, exec
execCtx.NodeOutputs[node.ID] = output execCtx.NodeOutputs[node.ID] = output
// 执行下一个节点 // 执行下一个节点
for _, nextID := range node.NextNodes { // 条件节点支持真正的分支:NextNodes[0] = true 分支,NextNodes[1] = false 分支
if next, ok := wf.Nodes[nextID]; ok { if node.Type == NodeTypeCondition && len(node.NextNodes) >= 2 {
condResult, _ := output.(map[string]interface{})
result, _ := condResult["result"].(bool)
targetIdx := 0
if !result {
targetIdx = 1
}
if next, ok := wf.Nodes[node.NextNodes[targetIdx]]; ok {
if _, err := e.executeNode(ctx, wf, next, execCtx); err != nil { if _, err := e.executeNode(ctx, wf, next, execCtx); err != nil {
return nil, err return nil, err
} }
} }
} else {
for _, nextID := range node.NextNodes {
if next, ok := wf.Nodes[nextID]; ok {
if _, err := e.executeNode(ctx, wf, next, execCtx); err != nil {
return nil, err
}
}
}
} }
return output, nil return output, nil
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment