package tools import ( "context" "fmt" "sort" "strings" "github.com/mark3labs/mcp-go/mcp" "fwh-toolbox-server/agentmcp/kit" "fwh-toolbox-server/domain" "fwh-toolbox-server/services" ) // ---- sim_get ---- type simGetArgs struct { ICCID string `json:"iccid" jsonschema:"SIM 卡 GICCID(19 位)"` } var SimGet = kit.Def[simGetArgs]{ Name: "sim_get", Title: "查询 SIM 卡", Description: "按 GICCID 查询单张 SIM 卡的详细信息(ToolBox SIM 卡管理,平台为 SmartHub 或 Acceleronix,自动判断)。" + "返回状态、平台、关联站点 SN、本月用量(KB)、激活时间等(IMEI/IMSI/MSISDN 已脱敏)。", ReadOnly: true, Handler: func(ctx context.Context, a simGetArgs) (*mcp.CallToolResult, error) { id, err := kit.Required("iccid", a.ICCID) if err != nil { return kit.Fail(err), nil } info, err := services.GetSimCardInfo(id) if err != nil { return kit.Upstream("SIM 卡管理", err), nil } if info == nil { return kit.Empty("没有找到该 SIM 卡。"), nil } return kit.Object(info), nil }, } // ---- sim_search ---- type simSearchArgs struct { Search string `json:"search,omitempty" jsonschema:"搜索关键字(GICCID 片段)"` Status string `json:"status,omitempty" jsonschema:"状态过滤,多个用逗号分隔:UNKNOWN、NOT_ACTIVATED、ACTIVATED、DEACTIVATED、RETIRED"` Platform string `json:"platform,omitempty" jsonschema:"平台过滤,多个用逗号分隔:SmartHub、Acceleronix"` Page int `json:"page,omitempty" jsonschema:"页码,默认 1"` Size int `json:"size,omitempty" jsonschema:"每页条数,1~100,默认 20"` } var simStatuses = []string{"UNKNOWN", "NOT_ACTIVATED", "ACTIVATED", "DEACTIVATED", "RETIRED"} var simPlatforms = []string{"SmartHub", "Acceleronix"} var SimSearch = kit.Def[simSearchArgs]{ Name: "sim_search", Title: "搜索 SIM 卡", Description: "按关键字、状态、平台分页搜索 SIM 卡(ToolBox SIM 卡管理)。返回 total 与 items(GICCID、状态、平台、关联 SN、用量等)。", ReadOnly: true, Handler: func(ctx context.Context, a simSearchArgs) (*mcp.CallToolResult, error) { status, err := enumList("status", a.Status, simStatuses) if err != nil { return kit.Fail(err), nil } platform, err := enumList("platform", a.Platform, simPlatforms) if err != nil { return kit.Fail(err), nil } page := kit.Page(a.Page) size := kit.Limit(a.Size, 20, 100) data, err := services.GetSimCardBatchInfo(uint(page), uint(size), strings.TrimSpace(a.Search), status, platform) if err != nil { return kit.Upstream("SIM 卡管理", err), nil } if data == nil { return kit.Empty(""), nil } return kit.List(data.Data, int(data.Total), size, fmt.Sprintf("共 %d 条,当前第 %d 页,可用 page 翻页", data.Total, page)), nil }, } // enumList 校验逗号分隔的多选值;为空返回 nil。 func enumList(name, v string, allowed []string) (*string, error) { v = strings.TrimSpace(v) if v == "" { return nil, nil } parts := strings.Split(v, ",") out := make([]string, 0, len(parts)) for _, p := range parts { e, err := kit.Enum(name, p, "", allowed...) if err != nil { return nil, err } if e != "" { out = append(out, e) } } joined := strings.Join(out, ",") return &joined, nil } // ---- sim_usage_monthly ---- type simUsageMonthlyArgs struct { ICCID string `json:"iccid" jsonschema:"SIM 卡 GICCID(19 位)"` Month string `json:"month" jsonschema:"月份,yyyy-MM"` } var SimUsageMonthly = kit.Def[simUsageMonthlyArgs]{ Name: "sim_usage_monthly", Title: "查询 SIM 卡月度每日用量", Description: "查询单张 SIM 卡某个月每天的数据用量。返回 month、allDataUsage(月用量,KB)、updateTime(UTC),以及 days(按日排序的每日用量明细)。", ReadOnly: true, Handler: func(ctx context.Context, a simUsageMonthlyArgs) (*mcp.CallToolResult, error) { id, err := kit.Required("iccid", a.ICCID) if err != nil { return kit.Fail(err), nil } month, err := kit.Required("month", a.Month) if err != nil { return kit.Fail(err), nil } data, err := services.GetSimCardMonthlyData(month, id) if err != nil { return kit.Upstream("SIM 卡管理", err), nil } if data == nil { return kit.Empty("该月没有用量数据。"), nil } return kit.Object(MonthlyUsageView(data)), nil }, } // MonthlyUsageView 把按日索引的 map 转为按日排序的列表。 func MonthlyUsageView(d *domain.SimCardMonthlyData) map[string]any { days := make([]uint8, 0, len(d.DailyUsage)) for k := range d.DailyUsage { days = append(days, k) } sort.Slice(days, func(i, j int) bool { return days[i] < days[j] }) list := make([]map[string]any, 0, len(days)) for _, day := range days { list = append(list, map[string]any{"day": day, "usage": d.DailyUsage[day]}) } return map[string]any{ "iccid": d.SimId, "month": d.Month, "allDataUsage": d.AllDataUsage, "updateTime": d.UpdateTime, "days": list, } }