// SchClass OpenAPI 调试入口:独立控制台,不开测试即可联调教务后端。 // // 用法: // dotnet run --project samples/Yh.SchClass.DebugTool # 跑全部 20 个端点 // dotnet run --project samples/Yh.SchClass.DebugTool -- --list # 只列出端点名 // dotnet run --project samples/Yh.SchClass.DebugTool -- --only=OAStu // dotnet run --project samples/Yh.SchClass.DebugTool -- --host=http://192.168.1.20:8080 --path=/bschclass // 可覆盖项:--host --path --sch --class --tea --group --only // // 地址优先级:命令行参数 → 环境变量 YH_SCHCLASS_DEBUG_* → appsettings.json(yh:schclass:open → yh:open)→ 内置默认。 using System.Text; using Microsoft.Extensions.Configuration; using Yh.SchClass.OpenApi; Console.OutputEncoding = Encoding.UTF8; const string DefaultHost = "http://base.yunhaixingtong.com"; const string DefaultPath = "/bschclass"; string? host = null, path = null, sch = null, classId = null, teaRaw = null, groupRaw = null, only = null; bool listOnly = false; // 环境变量兜底(与测试工程的 SchClassLiveDebug 同名同义) string? Env(string n) { var v = Environment.GetEnvironmentVariable(n); return string.IsNullOrWhiteSpace(v) ? null : v.Trim(); } host = Env("YH_SCHCLASS_DEBUG_HOST"); path = Env("YH_SCHCLASS_DEBUG_PATH"); sch = Env("YH_SCHCLASS_DEBUG_SCH"); classId = Env("YH_SCHCLASS_DEBUG_CLASS"); teaRaw = Env("YH_SCHCLASS_DEBUG_TEA"); groupRaw = Env("YH_SCHCLASS_DEBUG_GROUP"); // 命令行参数优先 foreach (var arg in args) { if (!arg.StartsWith("--")) { continue; } var kv = arg[2..].Split('=', 2); var key = kv[0].Trim().ToLowerInvariant(); var val = kv.Length > 1 ? kv[1].Trim() : null; switch (key) { case "host": host = val; break; case "path": path = val; break; case "sch": sch = val; break; case "class": classId = val; break; case "tea": teaRaw = val; break; case "group": groupRaw = val; break; case "only": only = val; break; case "list": listOnly = true; break; } } var config = new ConfigurationBuilder() .SetBasePath(AppContext.BaseDirectory) .AddJsonFile("appsettings.json", optional: true) .Build(); host ??= config["yh:schclass:open:BaseHost"] ?? config["yh:open:BaseHost"] ?? DefaultHost; path ??= config["yh:schclass:open:BasePath"] ?? config["yh:open:SchClassPath"] ?? DefaultPath; var options = new SchClassOpenApiOptions { BaseHost = host, BasePath = string.IsNullOrWhiteSpace(path) ? null : path }; var api = SchClassOpenApiFactory.Create(options); // ---- 构造调试用例(缺省 ID 一律从真实数据推导,避免捏造 ID 造成假 0 条) ---- var group = int.TryParse(groupRaw, out var g) ? g : 3; var teaId = int.TryParse(teaRaw, out var t) ? t : 0; Console.WriteLine($"目标:{options.ResolveBaseUrl()}"); // --list:只打印端点名,不做任何网络请求 if (listOnly) { foreach (var name in new[] { "DbClass.GetSchteaList", "VSchClass.GetVClassList", "VSchClass.GetSchArrVClassListAll", "VSchClass.GetSchArrVClassListPost", "Schoolen.GetSchLenLevellist", "Schoolen.GetSchLenlist", "UserInfo.GetUserList", "SchInfo.AllList", "SchInfo.GetSchlist", "OATea.GetSchTeainfo", "OATea.GetArrTeainfo", "OAStu.GetAllStulist", "OAStu.GetSchStulist", "OAStu.GetClaStulist", "TeachInfo.GetSchTeachlist", "TeachInfo.GetSchClaTeachlist", "SubInfo.GetSchTeachSublist", "SubInfo.GetSchSublist", "FamCom.GetStuUserFamIDList", "FamCom.GetAllStuFamMem", }) { Console.WriteLine(name); } return 0; } var schResolved = sch; var cases = new List<(string Name, Func> Call)>(); // 先探测学校列表,推导缺省参数 try { var schools = await api.SchInfo.AllListAsync(); Console.WriteLine($"学校列表:{schools.Count} 所(前 3:{string.Join(" | ", schools.Take(3).Select(s => $"{s.SchName}[{s.SchSerId}]"))})"); schResolved ??= schools.FirstOrDefault()?.SchSerId ?? "S001"; } catch (Exception e) { Console.WriteLine($"!! 学校列表探测失败:{e.GetType().Name}: {e.Message}"); Console.WriteLine("后端不可达时后续端点大概率全部失败,仍继续逐个执行以便核对。"); schResolved ??= "S001"; } if (!listOnly) { var sch2 = schResolved; string cid = classId ?? ""; if (cid.Length == 0) { var cls = (await api.VClass.GetVClassListAsync(sch2)).FirstOrDefault(); cid = cls != null && cls.TryGetValue("ClassID", out var c) ? c.ToString() ?? "1001" : "1001"; } if (teaId == 0) { var tea = (await api.DbClass.GetSchteaListAsync(group)).FirstOrDefault(); teaId = tea != null && tea.TryGetValue("UserTeaSerID", out var d) && int.TryParse(d.ToString(), out var p) ? p : 77; } Console.WriteLine($"参数:sch={sch2} classId={cid} teaId={teaId} group={group}"); cases.Add(("DbClass.GetSchteaList", async () => (await api.DbClass.GetSchteaListAsync(group)).Count)); cases.Add(("VSchClass.GetVClassList", async () => (await api.VClass.GetVClassListAsync(sch2)).Count)); cases.Add(("VSchClass.GetSchArrVClassListAll", async () => (await api.VClass.GetSchArrVClassListAllAsync()).Count)); cases.Add(("VSchClass.GetSchArrVClassListPost", async () => (await api.VClass.GetSchArrVClassListPostAsync(sch2)).Count)); cases.Add(("Schoolen.GetSchLenLevellist", async () => (await api.Schooling.GetSchLenLevelListAsync(sch2)).Count)); cases.Add(("Schoolen.GetSchLenlist", async () => (await api.Schooling.GetSchLenListAsync(sch2)).Count)); cases.Add(("UserInfo.GetUserList", async () => (await api.UserInfo.GetUserListAsync(sch2)).Count)); cases.Add(("SchInfo.AllList", async () => (await api.SchInfo.AllListAsync()).Count)); cases.Add(("SchInfo.GetSchlist", async () => (await api.SchInfo.GetSchListAsync(null)).Count)); cases.Add(("OATea.GetSchTeainfo", async () => (await api.TeaInfo.GetSchTeaInfoAsync(sch2, null)).Count)); cases.Add(("OATea.GetArrTeainfo", async () => (await api.TeaInfo.GetArrTeaInfoAsync(teaId.ToString())).Count)); cases.Add(("OAStu.GetAllStulist", async () => (await api.StuInfo.GetAllStuListAsync()).Count)); cases.Add(("OAStu.GetSchStulist", async () => (await api.StuInfo.GetSchStuListAsync(sch2, null)).Count)); cases.Add(("OAStu.GetClaStulist", async () => (await api.StuInfo.GetClaStuListAsync(cid, null)).Count)); cases.Add(("TeachInfo.GetSchTeachlist", async () => (await api.TeachInfo.GetSchTeachListAsync(sch2, teaId)).Count)); cases.Add(("TeachInfo.GetSchClaTeachlist", async () => (await api.TeachInfo.GetSchClaTeachListAsync(cid)).Count)); cases.Add(("SubInfo.GetSchTeachSublist", async () => (await api.SubInfo.GetSchTeachSubListAsync(sch2)).Count)); cases.Add(("SubInfo.GetSchSublist", async () => (await api.SubInfo.GetSchSubListAsync(sch2, null, null)).Count)); cases.Add(("FamCom.GetStuUserFamIDList", async () => (await api.FamilyCompat.GetStuUserFamIdListAsync("1,2")).Count)); cases.Add(("FamCom.GetAllStuFamMem", async () => (await api.FamilyCompat.GetAllStuFamMemAsync("1,2")).Count)); } var failures = new List(); if (only != null) { cases = cases.Where(c => c.Name.Contains(only, StringComparison.OrdinalIgnoreCase)).ToList(); if (cases.Count == 0) { Console.WriteLine($"--only={only} 未匹配任何端点(用 --list 查看全部名称)"); return 2; } } foreach (var (name, call) in cases) { try { var count = await call(); Console.WriteLine($" OK {name} -> {count} 条"); } catch (Exception e) { failures.Add(name); Console.WriteLine($" FAIL {name} -> {e.GetType().Name}: {e.Message}"); } } Console.WriteLine($"汇总:{cases.Count - failures.Count}/{cases.Count} 通过"); return failures.Count == 0 ? 0 : 1;