bag
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
// 跨 TFM 显式全局 using(net5.0 不支持 ImplicitUsings,统一在此收敛)
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
global using System.Net.Http;
|
||||
global using System.Text;
|
||||
global using System.Text.Json;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
// Java 侧 Map<String,Object> 兼容行的 .NET 承载类型(net5.0 可用,不依赖 net6+ 的 JsonNode)
|
||||
global using SchClassRow = System.Collections.Generic.Dictionary<string, System.Text.Json.JsonElement>;
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yh.SchClass.OpenApi.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 学校视图对象(镜像 Java <c>com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO</c>)。
|
||||
/// Java 侧以 <c>@JsonProperty</c> 显式指定键名,故此处按原样锚定。
|
||||
/// </summary>
|
||||
public class SchInfoVo
|
||||
{
|
||||
/// <summary>学校外部序列号</summary>
|
||||
[JsonPropertyName("SchSerId")]
|
||||
public string? SchSerId { get; set; }
|
||||
|
||||
/// <summary>用户中心学校 ID</summary>
|
||||
[JsonPropertyName("UserSchSerId")]
|
||||
public int? UserSchSerId { get; set; }
|
||||
|
||||
/// <summary>学校名称</summary>
|
||||
[JsonPropertyName("SchName")]
|
||||
public string? SchName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yh.SchClass.OpenApi.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 教师信息视图对象(镜像 Java <c>com.yunhai.bschclassmanage.model.oa.TeaInfoVO</c>)。
|
||||
/// <para>
|
||||
/// Java 侧为 Lombok <c>@Data</c>,序列化键名由 Jackson 从 getter 推导;本客户端大小写不敏感反序列化,
|
||||
/// 故按 Java 字段原名锚定即可双向兼容。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class TeaInfoVo
|
||||
{
|
||||
/// <summary>学校外部序列号</summary>
|
||||
[JsonPropertyName("SchSerID")] public string? SchSerId { get; set; }
|
||||
|
||||
/// <summary>政治面貌</summary>
|
||||
[JsonPropertyName("Teapolitical")] public string? TeaPolitical { get; set; }
|
||||
|
||||
/// <summary>参加工作日期</summary>
|
||||
[JsonPropertyName("TeaWorkStart")] public string? TeaWorkStart { get; set; }
|
||||
|
||||
/// <summary>登录账户</summary>
|
||||
[JsonPropertyName("Account")] public string? Account { get; set; }
|
||||
|
||||
/// <summary>学校序列号(多校场景,当前与 SchSerID 相同)</summary>
|
||||
[JsonPropertyName("SchSerIDs")] public string? SchSerIds { get; set; }
|
||||
|
||||
/// <summary>角色</summary>
|
||||
[JsonPropertyName("role")] public int? Role { get; set; }
|
||||
|
||||
/// <summary>教育局</summary>
|
||||
[JsonPropertyName("JiaoYuJu")] public string? JiaoYuJu { get; set; }
|
||||
|
||||
/// <summary>性别(文本)</summary>
|
||||
[JsonPropertyName("TeaSex")] public string? TeaSex { get; set; }
|
||||
|
||||
/// <summary>是否中层以上干部</summary>
|
||||
[JsonPropertyName("IsLeadingMiddle")] public int? IsLeadingMiddle { get; set; }
|
||||
|
||||
/// <summary>籍贯</summary>
|
||||
[JsonPropertyName("TeaOriginPlace")] public string? TeaOriginPlace { get; set; }
|
||||
|
||||
/// <summary>头像</summary>
|
||||
[JsonPropertyName("Photo")] public string? Photo { get; set; }
|
||||
|
||||
/// <summary>身份证号</summary>
|
||||
[JsonPropertyName("TeaIDCard")] public string? TeaIdCard { get; set; }
|
||||
|
||||
/// <summary>姓名</summary>
|
||||
[JsonPropertyName("Name")] public string? Name { get; set; }
|
||||
|
||||
/// <summary>分组 ID</summary>
|
||||
[JsonPropertyName("GroupID")] public int? GroupId { get; set; }
|
||||
|
||||
/// <summary>学校名称</summary>
|
||||
[JsonPropertyName("SchName")] public string? SchName { get; set; }
|
||||
|
||||
/// <summary>从教日期</summary>
|
||||
[JsonPropertyName("TeaTeachStart")] public string? TeaTeachStart { get; set; }
|
||||
|
||||
/// <summary>教师序列号(teaId 的字符串形式)</summary>
|
||||
[JsonPropertyName("TeaSerID")] public string? TeaSerId { get; set; }
|
||||
|
||||
/// <summary>用户 ID</summary>
|
||||
[JsonPropertyName("UserID")] public int? UserId { get; set; }
|
||||
|
||||
/// <summary>民族</summary>
|
||||
[JsonPropertyName("TeaNation")] public string? TeaNation { get; set; }
|
||||
|
||||
/// <summary>电话</summary>
|
||||
[JsonPropertyName("Tel")] public string? Tel { get; set; }
|
||||
|
||||
/// <summary>工作类型</summary>
|
||||
[JsonPropertyName("TeaWorkType")] public string? TeaWorkType { get; set; }
|
||||
|
||||
/// <summary>教师编号</summary>
|
||||
[JsonPropertyName("TeaNo")] public int? TeaNo { get; set; }
|
||||
|
||||
/// <summary>出生日期</summary>
|
||||
[JsonPropertyName("TeaBirth")] public string? TeaBirth { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yh.SchClass.OpenApi.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 用户信息视图对象(镜像 Java <c>com.yunhai.bschclassmanage.model.oa.UserInfoVO</c>)。
|
||||
/// <para>
|
||||
/// Java 侧为 Lombok <c>@Data</c>,序列化键名由 Jackson 从 getter 推导(如 <c>getSchSerID()</c> → <c>schSerID</c>);
|
||||
/// 本客户端使用大小写不敏感反序列化(<see cref="JsonSerializerDefaults.Web"/>),故此处按 Java 字段原名锚定即可双向兼容。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class UserInfoVo
|
||||
{
|
||||
/// <summary>学校外部序列号</summary>
|
||||
[JsonPropertyName("SchSerID")] public string? SchSerId { get; set; }
|
||||
|
||||
/// <summary>编号(教师为 sort)</summary>
|
||||
[JsonPropertyName("No")] public int? No { get; set; }
|
||||
|
||||
/// <summary>身份证号</summary>
|
||||
[JsonPropertyName("IDCard")] public string? IdCard { get; set; }
|
||||
|
||||
/// <summary>用户 ID(教师为 teaId,学生为 stuId)</summary>
|
||||
[JsonPropertyName("UserID")] public int? UserId { get; set; }
|
||||
|
||||
/// <summary>性别</summary>
|
||||
[JsonPropertyName("sex")] public int? Sex { get; set; }
|
||||
|
||||
/// <summary>用户类型(教师 1 / 学生按 UserRole)</summary>
|
||||
[JsonPropertyName("usertype")] public int? UserType { get; set; }
|
||||
|
||||
/// <summary>序列号(Java 侧恒为 null)</summary>
|
||||
[JsonPropertyName("SerID")] public string? SerId { get; set; }
|
||||
|
||||
/// <summary>头像(Java 侧恒为 null)</summary>
|
||||
[JsonPropertyName("Photo")] public string? Photo { get; set; }
|
||||
|
||||
/// <summary>电话(学生为 null)</summary>
|
||||
[JsonPropertyName("Tel")] public string? Tel { get; set; }
|
||||
|
||||
/// <summary>登录账户</summary>
|
||||
[JsonPropertyName("Uids")] public string? Uids { get; set; }
|
||||
|
||||
/// <summary>分组 ID</summary>
|
||||
[JsonPropertyName("GroupID")] public int? GroupId { get; set; }
|
||||
|
||||
/// <summary>姓名</summary>
|
||||
[JsonPropertyName("Name")] public string? Name { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务(SchClass / bschclassmanage)开放接口客户端基类。
|
||||
/// <para>
|
||||
/// 与 <c>Yh.Platform.OpenApi.OpenApiClientBase</c> 同构,但刻意保持零项目依赖,便于单独打包引用。
|
||||
/// </para>
|
||||
/// <para><b>响应约定</b>(Java 侧 OA 兼容端点):成功时直接返回裸数据(对象 / 数组 / 字符串数组),无统一信封;
|
||||
/// 部分端点以 HTTP 404 / 204 表示"无数据",以 HTTP 400 表示参数缺失。因此本基类默认把 404 与 204
|
||||
/// 归一为 <c>null</c>(列表则为空列表),仅对 400 及其它非 2xx 抛 <see cref="SchClassOpenApiException"/>。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract class SchClassClientBase
|
||||
{
|
||||
/// <summary>教务开放接口统一前缀(与 Java <c>Config.OAPI</c> 严格一致)</summary>
|
||||
protected const string Prefix = "/oapi";
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOpts = new(JsonSerializerDefaults.Web);
|
||||
|
||||
protected HttpClient HttpClient { get; }
|
||||
|
||||
protected SchClassOpenApiOptions Options { get; }
|
||||
|
||||
protected SchClassClientBase(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
{
|
||||
HttpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
Options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
// ====================== 请求构造 ======================
|
||||
|
||||
/// <summary>构造查询参数;值为 null 的参数会被跳过(对应 Java 侧 required=false)。</summary>
|
||||
protected static Dictionary<string, string?> Params(params (string key, object? value)[] kv)
|
||||
{
|
||||
var map = new Dictionary<string, string?>(StringComparer.Ordinal);
|
||||
if (kv == null)
|
||||
{
|
||||
return map;
|
||||
}
|
||||
foreach (var (key, value) in kv)
|
||||
{
|
||||
if (key != null && value != null)
|
||||
{
|
||||
map[key] = value.ToString();
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static string BuildQuery(Dictionary<string, string?>? query)
|
||||
{
|
||||
if (query == null || query.Count == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
var sb = new StringBuilder();
|
||||
foreach (var kv in query)
|
||||
{
|
||||
if (string.IsNullOrEmpty(kv.Key) || kv.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sb.Append(sb.Length == 0 ? '?' : '&')
|
||||
.Append(Uri.EscapeDataString(kv.Key))
|
||||
.Append('=')
|
||||
.Append(Uri.EscapeDataString(kv.Value));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// ====================== 发送与解析 ======================
|
||||
|
||||
/// <summary>
|
||||
/// 发送请求并返回裸数据节点(可能为 null)。
|
||||
/// <para><paramref name="body"/> 为 <see cref="string"/> 时按 text/plain 原样提交(对应 Java <c>@RequestBody String</c>),
|
||||
/// 其余类型按 application/json 序列化后提交。</para>
|
||||
/// </summary>
|
||||
/// <param name="notFoundAsNull">为 true 时把 HTTP 404 / 204 归一为 null(OA 端点惯用的"无数据"语义)。</param>
|
||||
protected async Task<JsonElement?> SendAsync(HttpMethod method, string path,
|
||||
Dictionary<string, string?>? query = null, object? body = null,
|
||||
bool notFoundAsNull = true, CancellationToken ct = default)
|
||||
{
|
||||
var url = Options.ResolveBaseUrl() + path + BuildQuery(query);
|
||||
using var request = new HttpRequestMessage(method, url);
|
||||
if (body != null)
|
||||
{
|
||||
request.Content = body is string raw
|
||||
? new StringContent(raw, Encoding.UTF8, "text/plain")
|
||||
: new StringContent(JsonSerializer.Serialize(body, JsonOpts), Encoding.UTF8, "application/json");
|
||||
}
|
||||
|
||||
using var response = await HttpClient.SendAsync(request, ct).ConfigureAwait(false);
|
||||
var text = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var status = (int)response.StatusCode;
|
||||
|
||||
// OA 兼容端点惯用 404 / 204 表达"查无数据",不是调用失败
|
||||
if ((status == 404 && notFoundAsNull) || status == 204 || status == 205)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new SchClassOpenApiException("SchClass OpenAPI HTTP " + status + ": " + text, status, text);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(text);
|
||||
return Unwrap(doc.RootElement);
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
throw new SchClassOpenApiException("SchClass OpenAPI 响应解析失败: " + e.Message, status, text);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>裸数据反序列化为 <typeparamref name="T"/>。</summary>
|
||||
protected async Task<T?> ResolveAsync<T>(HttpMethod method, string path,
|
||||
Dictionary<string, string?>? query = null, object? body = null,
|
||||
bool notFoundAsNull = true, CancellationToken ct = default)
|
||||
{
|
||||
var data = await SendAsync(method, path, query, body, notFoundAsNull, ct).ConfigureAwait(false);
|
||||
if (data == null || data.Value.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(data.Value.GetRawText(), JsonOpts);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
throw new SchClassOpenApiException("SchClass OpenAPI 反序列化失败: " + typeof(T).Name, 0, data.Value.GetRawText());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>裸数组 / 单对象反序列化为列表;无数据时返回空列表(不会为 null)。</summary>
|
||||
protected async Task<List<T>> ResolveListAsync<T>(HttpMethod method, string path,
|
||||
Dictionary<string, string?>? query = null, object? body = null,
|
||||
bool notFoundAsNull = true, CancellationToken ct = default)
|
||||
{
|
||||
var data = await SendAsync(method, path, query, body, notFoundAsNull, ct).ConfigureAwait(false);
|
||||
var result = new List<T>();
|
||||
if (data == null || data.Value.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (data.Value.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
foreach (var item in data.Value.EnumerateArray())
|
||||
{
|
||||
if (item.ValueKind is not (JsonValueKind.Null or JsonValueKind.Undefined))
|
||||
{
|
||||
result.Add(JsonSerializer.Deserialize<T>(item.GetRawText(), JsonOpts)!);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(JsonSerializer.Deserialize<T>(data.Value.GetRawText(), JsonOpts)!);
|
||||
}
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
throw new SchClassOpenApiException("SchClass OpenAPI 列表反序列化失败: " + typeof(T).Name, 0, data.Value.GetRawText());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 弱类型兼容行(Java <c>Map<String,Object></c>)列表;无数据时返回空列表。
|
||||
/// 每行键名与 Java 侧 <c>LinkedHashMap</c> 的 put 顺序完全一致。
|
||||
/// </summary>
|
||||
protected Task<List<SchClassRow>> ResolveRowsAsync(HttpMethod method, string path,
|
||||
Dictionary<string, string?>? query = null, object? body = null,
|
||||
bool notFoundAsNull = true, CancellationToken ct = default)
|
||||
=> ResolveListAsync<SchClassRow>(method, path, query, body, notFoundAsNull, ct);
|
||||
|
||||
/// <summary>
|
||||
/// 信封感知:仅当同时出现数字 <c>code</c> 与(<c>data</c> 或字符串 <c>msg</c>)时才认定为信封,
|
||||
/// 避免把业务行里恰好叫 <c>code</c> 的字段(如学制等级的 code=gradeId)误判成错误响应。
|
||||
/// </summary>
|
||||
private static JsonElement? Unwrap(JsonElement root)
|
||||
{
|
||||
if (root.ValueKind != JsonValueKind.Object
|
||||
|| !root.TryGetProperty("code", out var codeEl)
|
||||
|| codeEl.ValueKind != JsonValueKind.Number)
|
||||
{
|
||||
return root.Clone();
|
||||
}
|
||||
|
||||
var hasData = root.TryGetProperty("data", out var dataEl);
|
||||
var hasMsg = root.TryGetProperty("msg", out var msgEl) && msgEl.ValueKind == JsonValueKind.String;
|
||||
if (!hasData && !hasMsg)
|
||||
{
|
||||
// 业务行里恰好含 code 字段(如学制等级的 code=gradeId),不是错误信封
|
||||
return root.Clone();
|
||||
}
|
||||
|
||||
codeEl.TryGetInt32(out var code);
|
||||
if (code != 0)
|
||||
{
|
||||
var msg = hasMsg ? msgEl.GetString() : null;
|
||||
throw new SchClassOpenApiException(
|
||||
string.IsNullOrEmpty(msg) ? "SchClass OpenAPI 业务错误" : msg!, 0, root.GetRawText());
|
||||
}
|
||||
return hasData && dataEl.ValueKind is not (JsonValueKind.Null or JsonValueKind.Undefined)
|
||||
? dataEl.Clone()
|
||||
: null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 DbClass 接口客户端(镜像 Java <c>DbClassController</c>,路径前缀 <c>/oapi/DbClass/</c>)。
|
||||
/// </summary>
|
||||
public class SchClassDbClassClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/DbClass/";
|
||||
|
||||
public SchClassDbClassClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询学校教师名单(<c>GET /oapi/DbClass/GetSchteaList</c>)。
|
||||
/// 每位教师的每个有效分组归属返回一行(同一教师多分组会重复出现)。
|
||||
/// 行字段:<c>SchSerID / TeaTel / TeaName / UserTeaSerID / TeaIDCard / TeaNo / GroupID</c>。
|
||||
/// </summary>
|
||||
/// <param name="group">学校 ID(Java 参数名 <c>Group</c>),必须大于 0;<=0 时服务端返回 400。</param>
|
||||
public Task<List<SchClassRow>> GetSchteaListAsync(int group, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchteaList", Params(("Group", group)), ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务家长兼容接口客户端(镜像 Java <c>FamilyCompatController</c>,路径前缀 <c>/oapi/Common/FamCom/</c>)。
|
||||
/// 两个端点当前服务端均恒返回空数据,保留调用以兼容既有消费方。
|
||||
/// </summary>
|
||||
public class SchClassFamilyCompatClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/Common/FamCom/";
|
||||
|
||||
public SchClassFamilyCompatClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询学生家长用户 ID 列表,<c>POST /oapi/Common/FamCom/GetStuUserFamIDList</c>;
|
||||
/// 请求体为逗号分隔的学生 ID(Java 侧 <c>@RequestBody String</c>,按 text/plain 提交)。
|
||||
/// </summary>
|
||||
public Task<List<string>> GetStuUserFamIdListAsync(string? stuIds, CancellationToken ct = default)
|
||||
=> ResolveListAsync<string>(HttpMethod.Post, Root + "GetStuUserFamIDList", body: stuIds, ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 查询学生家庭成员,<c>POST /oapi/Common/FamCom/GetAllStuFamMem</c>;
|
||||
/// 请求体为逗号分隔的学生 ID(text/plain)。
|
||||
/// </summary>
|
||||
public Task<List<SchClassRow>> GetAllStuFamMemAsync(string? stuIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Post, Root + "GetAllStuFamMem", body: stuIds, ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务(SchClass)开放接口聚合门面:一个入口访问全部 OA 兼容端点。
|
||||
/// <para>
|
||||
/// 用法:
|
||||
/// <code>
|
||||
/// var api = SchClassOpenApiFactory.Create(new SchClassOpenApiOptions { BaseHost = "http://bschclassmanage" });
|
||||
/// var schools = await api.SchInfo.AllListAsync();
|
||||
/// </code>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class SchClassOpenApi
|
||||
{
|
||||
public SchClassOpenApi(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
{
|
||||
if (httpClient == null) throw new ArgumentNullException(nameof(httpClient));
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
Options = options;
|
||||
HttpClient = httpClient;
|
||||
|
||||
DbClass = new SchClassDbClassClient(httpClient, options);
|
||||
VClass = new SchClassVClassClient(httpClient, options);
|
||||
Schooling = new SchClassSchoolingClient(httpClient, options);
|
||||
UserInfo = new SchClassUserInfoClient(httpClient, options);
|
||||
SchInfo = new SchClassSchInfoClient(httpClient, options);
|
||||
TeaInfo = new SchClassTeaInfoClient(httpClient, options);
|
||||
StuInfo = new SchClassStuInfoClient(httpClient, options);
|
||||
TeachInfo = new SchClassTeachInfoClient(httpClient, options);
|
||||
SubInfo = new SchClassSubInfoClient(httpClient, options);
|
||||
FamilyCompat = new SchClassFamilyCompatClient(httpClient, options);
|
||||
}
|
||||
|
||||
/// <summary>当前生效的配置。</summary>
|
||||
public SchClassOpenApiOptions Options { get; }
|
||||
|
||||
/// <summary>底层 HttpClient 的 BaseAddress(配置为空时为 null)。</summary>
|
||||
public Uri? HttpBaseAddress => HttpClient.BaseAddress;
|
||||
|
||||
private HttpClient HttpClient { get; }
|
||||
|
||||
/// <summary>DbClass:学校教师名单(<c>/oapi/DbClass/</c>)。</summary>
|
||||
public SchClassDbClassClient DbClass { get; }
|
||||
|
||||
/// <summary>VSchClass:班级(<c>/oapi/VSchClass/</c>)。</summary>
|
||||
public SchClassVClassClient VClass { get; }
|
||||
|
||||
/// <summary>Schoolen:学制与年级(<c>/oapi/Schoolen/</c>)。</summary>
|
||||
public SchClassSchoolingClient Schooling { get; }
|
||||
|
||||
/// <summary>UserInfo:师生统一用户(<c>/oapi/UserInfo/</c>)。</summary>
|
||||
public SchClassUserInfoClient UserInfo { get; }
|
||||
|
||||
/// <summary>SchInfo:学校(<c>/oapi/SchInfo/</c>)。</summary>
|
||||
public SchClassSchInfoClient SchInfo { get; }
|
||||
|
||||
/// <summary>OATea:教师(<c>/oapi/OATea/</c>)。</summary>
|
||||
public SchClassTeaInfoClient TeaInfo { get; }
|
||||
|
||||
/// <summary>OAStu:学生(<c>/oapi/OAStu/</c>)。</summary>
|
||||
public SchClassStuInfoClient StuInfo { get; }
|
||||
|
||||
/// <summary>TeachInfo:任课(<c>/oapi/TeachInfo/</c>)。</summary>
|
||||
public SchClassTeachInfoClient TeachInfo { get; }
|
||||
|
||||
/// <summary>SubInfo:科目(<c>/oapi/SubInfo/</c>)。</summary>
|
||||
public SchClassSubInfoClient SubInfo { get; }
|
||||
|
||||
/// <summary>FamCom:家长兼容(<c>/oapi/Common/FamCom/</c>)。</summary>
|
||||
public SchClassFamilyCompatClient FamilyCompat { get; }
|
||||
}
|
||||
|
||||
/// <summary><see cref="SchClassOpenApi"/> 的轻量工厂(不依赖 DI 容器)。</summary>
|
||||
public static class SchClassOpenApiFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 按配置创建 <see cref="HttpClient"/>:预设 BaseAddress 与读超时。
|
||||
/// 生产环境建议改用 <c>IHttpClientFactory</c> 注入实例,本方法仅用于快速接入与测试。
|
||||
/// </summary>
|
||||
public static HttpClient CreateHttpClient(SchClassOpenApiOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
var client = new HttpClient
|
||||
{
|
||||
Timeout = TimeSpan.FromMilliseconds(options.ReadTimeoutMs <= 0 ? 5000 : options.ReadTimeoutMs)
|
||||
};
|
||||
var baseUrl = options.ResolveBaseUrl();
|
||||
if (!string.IsNullOrEmpty(baseUrl))
|
||||
{
|
||||
client.BaseAddress = new Uri(baseUrl, UriKind.Absolute);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <summary>按配置创建一个完整的门面实例(内部自建 HttpClient,调用方负责复用而非频繁创建)。</summary>
|
||||
public static SchClassOpenApi Create(SchClassOpenApiOptions options)
|
||||
=> new SchClassOpenApi(CreateHttpClient(options), options);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>教务开放接口调用异常(HTTP 非 2xx 或响应解析失败)。</summary>
|
||||
public class SchClassOpenApiException : Exception
|
||||
{
|
||||
/// <summary>HTTP 状态码;非 HTTP 层错误时为 0。</summary>
|
||||
public int StatusCode { get; }
|
||||
|
||||
/// <summary>原始响应文本(若有)。</summary>
|
||||
public string? ResponseBody { get; }
|
||||
|
||||
public SchClassOpenApiException(string message, int statusCode = 0, string? responseBody = null)
|
||||
: base(message)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
ResponseBody = responseBody;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 云海教务(SchClass / bschclassmanage)开放接口客户端配置,配置节 <c>yh:schclass:open</c>。
|
||||
/// 与 UserBase 的 OpenApiOptions 同构,但独立配置节,便于分别指向不同后端。
|
||||
/// </summary>
|
||||
public class SchClassOpenApiOptions
|
||||
{
|
||||
public const string SectionName = "yh:schclass:open";
|
||||
|
||||
/// <summary>
|
||||
/// 共享开放接口配置节(与 UserBase 的 OpenApiOptions 同节):
|
||||
/// 其中 <c>BaseHost</c> 与 <c>SchClassPath</c> 可作为教务客户端的缺省来源。
|
||||
/// <code>
|
||||
/// "yh": {
|
||||
/// "open": {
|
||||
/// "BaseHost": "http://base.yunhaixingtong.com",
|
||||
/// "BasePath": "/userbase", ← UserBase 用
|
||||
/// "SchClassPath": "/bschclass" ← 教务(SchClass)用
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public const string SharedSectionName = "yh:open";
|
||||
|
||||
/// <summary>共享节里教务路径的键名。</summary>
|
||||
public const string SchClassPathKey = "SchClassPath";
|
||||
|
||||
/// <summary>HTTP 客户端逻辑名(IHttpClientFactory)。</summary>
|
||||
public const string HttpClientName = "yh-schclass-openapi";
|
||||
|
||||
/// <summary>是否启用(默认 true)</summary>
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
/// <summary>教务开放接口基础地址,例如 http://base.yunhaixingtong.com</summary>
|
||||
public string? BaseHost { get; set; }
|
||||
|
||||
/// <summary>基础路径(默认 null,挂载在根路径);联调环境为 /bschclass</summary>
|
||||
public string? BasePath { get; set; }
|
||||
|
||||
/// <summary>连接超时(毫秒),默认 1500</summary>
|
||||
public long ConnectTimeoutMs { get; set; } = 1500;
|
||||
|
||||
/// <summary>读超时(毫秒),默认 5000</summary>
|
||||
public long ReadTimeoutMs { get; set; } = 5000;
|
||||
|
||||
/// <summary>写超时(毫秒),默认 5000</summary>
|
||||
public long WriteTimeoutMs { get; set; } = 5000;
|
||||
|
||||
/// <summary>调用方在教务平台注册的应用标识(用于签名,可选)</summary>
|
||||
public string? AppKey { get; set; }
|
||||
|
||||
/// <summary>调用方在教务平台注册的密钥(用于签名,可选)</summary>
|
||||
public string? AppSecret { get; set; }
|
||||
|
||||
/// <summary>拼接 baseHost + basePath 为统一开放接口基址。</summary>
|
||||
public string ResolveBaseUrl()
|
||||
{
|
||||
var baseHost = BaseHost?.Trim() ?? "";
|
||||
if (baseHost.EndsWith('/'))
|
||||
{
|
||||
baseHost = baseHost.TrimEnd('/');
|
||||
}
|
||||
return baseHost + (NormalizeBasePath(BasePath) ?? "");
|
||||
}
|
||||
|
||||
/// <summary>归一化 basePath:trim、去尾斜杠、无前导斜杠补 /;null/空白返回 null。</summary>
|
||||
public static string? NormalizeBasePath(string? path)
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var trimmed = path.Trim().TrimEnd('/');
|
||||
if (trimmed.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return trimmed.StartsWith('/') ? trimmed : "/" + trimmed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从共享节(<see cref="SharedSectionName"/>,即 <c>yh:open</c>)按键读取,回填本选项中**未显式配置**的项:
|
||||
/// <para><c>BaseHost</c> ← <c>yh:open:BaseHost</c>;<c>BasePath</c> ← <c>yh:open:SchClassPath</c>(注意不是 BasePath —— 那是 UserBase 的路径)。</para>
|
||||
/// <paramref name="readShared"/> 传相对键名(如 "BaseHost"),返回 null/空白视为未配置。
|
||||
/// </summary>
|
||||
public void FillFromSharedSection(Func<string, string?> readShared)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(BaseHost))
|
||||
{
|
||||
BaseHost = readShared("BaseHost");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(BasePath))
|
||||
{
|
||||
BasePath = readShared(SchClassPathKey);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(AppKey))
|
||||
{
|
||||
AppKey = readShared("AppKey");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(AppSecret))
|
||||
{
|
||||
AppSecret = readShared("AppSecret");
|
||||
}
|
||||
BasePath = NormalizeBasePath(BasePath);
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// DI 注册扩展:从配置读取地址并装配全部教务客户端。
|
||||
/// <para>
|
||||
/// 配置来源(优先级从高到低):
|
||||
/// 1. 独立节 <c>yh:schclass:open</c>(整节绑定,适合教务单独部署、地址与 UserBase 无关的场景);
|
||||
/// 2. 共享节 <c>yh:open</c> 回填:<c>BaseHost</c> ← <c>yh:open:BaseHost</c>、
|
||||
/// <c>BasePath</c> ← <c>yh:open:SchClassPath</c>(注意共享节的 <c>BasePath=/userbase</c> 是 UserBase 的,不会被教务采用)、
|
||||
/// <c>AppKey</c>/<c>AppSecret</c> 同名回填。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class SchClassOpenApiServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册教务 /oapi 全部客户端:IHttpClientFactory + typed client + 聚合门面 <see cref="SchClassOpenApi"/>(Singleton)。
|
||||
/// <code>
|
||||
/// builder.Services.AddSchClassOpenApi(builder.Configuration);
|
||||
/// // 注入使用:
|
||||
/// public class X(SchClassOpenApi sch) { ... sch.SchInfo.AllListAsync() ... }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public static IServiceCollection AddSchClassOpenApi(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddOptions<SchClassOpenApiOptions>()
|
||||
.Bind(configuration.GetSection(SchClassOpenApiOptions.SectionName))
|
||||
.PostConfigure(o =>
|
||||
{
|
||||
var shared = configuration.GetSection(SchClassOpenApiOptions.SharedSectionName);
|
||||
o.FillFromSharedSection(key => shared[key]);
|
||||
});
|
||||
|
||||
services.AddHttpClient(SchClassOpenApiOptions.HttpClientName)
|
||||
.ConfigureHttpClient((sp, client) =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<SchClassOpenApiOptions>>().Value;
|
||||
client.Timeout = TimeSpan.FromMilliseconds(options.ReadTimeoutMs > 0 ? options.ReadTimeoutMs : 5000);
|
||||
var baseUrl = options.ResolveBaseUrl();
|
||||
if (!string.IsNullOrEmpty(baseUrl))
|
||||
{
|
||||
client.BaseAddress = new Uri(baseUrl, UriKind.Absolute);
|
||||
}
|
||||
})
|
||||
.ConfigurePrimaryHttpMessageHandler(sp =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<SchClassOpenApiOptions>>().Value;
|
||||
return new SocketsHttpHandler
|
||||
{
|
||||
ConnectTimeout = TimeSpan.FromMilliseconds(options.ConnectTimeoutMs > 0 ? options.ConnectTimeoutMs : 1500),
|
||||
};
|
||||
});
|
||||
|
||||
services.AddSingleton(sp =>
|
||||
{
|
||||
var factory = sp.GetRequiredService<IHttpClientFactory>();
|
||||
return new SchClassOpenApi(factory.CreateClient(SchClassOpenApiOptions.HttpClientName),
|
||||
sp.GetRequiredService<IOptions<SchClassOpenApiOptions>>().Value);
|
||||
});
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Yh.SchClass.OpenApi.Model;
|
||||
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 SchInfo(学校)接口客户端(镜像 Java <c>SchInfoController</c>,路径前缀 <c>/oapi/SchInfo/</c>)。
|
||||
/// </summary>
|
||||
public class SchClassSchInfoClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/SchInfo/";
|
||||
|
||||
public SchClassSchInfoClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>按多个学校 ID 查询学校列表,<c>GET /oapi/SchInfo/GetSchlist</c>。</summary>
|
||||
/// <param name="schIdArr">逗号分隔的学校 ID 列表(Java 参数名 <c>SchIDArr</c>);为 null 时等价于查询全部。</param>
|
||||
public Task<List<SchInfoVo>> GetSchListAsync(string? schIdArr, CancellationToken ct = default)
|
||||
=> ResolveListAsync<SchInfoVo>(HttpMethod.Get, Root + "GetSchlist",
|
||||
Params(("SchIDArr", schIdArr)), ct: ct);
|
||||
|
||||
/// <summary>查询全部学校列表,<c>GET /oapi/SchInfo/AllList</c>。</summary>
|
||||
public Task<List<SchInfoVo>> AllListAsync(CancellationToken ct = default)
|
||||
=> ResolveListAsync<SchInfoVo>(HttpMethod.Get, Root + "AllList", ct: ct);
|
||||
|
||||
/// <summary>按学校外部序列号查询单个学校,<c>GET /oapi/SchInfo/GetSchFirst</c>;未找到返回 null。</summary>
|
||||
/// <param name="schId">学校外部序列号(Java 参数名 <c>SchID</c>)。</param>
|
||||
public Task<SchInfoVo?> GetSchFirstAsync(string? schId, CancellationToken ct = default)
|
||||
=> ResolveAsync<SchInfoVo>(HttpMethod.Get, Root + "GetSchFirst", Params(("SchID", schId)), ct: ct);
|
||||
|
||||
/// <summary>按用户中心学校 ID 查询单个学校,<c>GET /oapi/SchInfo/GetUserSchFirst</c>;未找到返回 null。</summary>
|
||||
/// <param name="userSchId">用户中心学校 ID(Java 参数名 <c>UserSchID</c>)。</param>
|
||||
public Task<SchInfoVo?> GetUserSchFirstAsync(int? userSchId, CancellationToken ct = default)
|
||||
=> ResolveAsync<SchInfoVo>(HttpMethod.Get, Root + "GetUserSchFirst",
|
||||
Params(("UserSchID", userSchId)), ct: ct);
|
||||
|
||||
/// <summary>按多个用户中心学校 ID 查询学校列表,<c>GET /oapi/SchInfo/GetUserSchlist</c>。</summary>
|
||||
/// <param name="userSchIds">逗号分隔的用户中心学校 ID 列表(Java 参数名 <c>UserSchIds</c>)。</param>
|
||||
public Task<List<SchInfoVo>> GetUserSchListAsync(string? userSchIds, CancellationToken ct = default)
|
||||
=> ResolveListAsync<SchInfoVo>(HttpMethod.Get, Root + "GetUserSchlist",
|
||||
Params(("UserSchIds", userSchIds)), ct: ct);
|
||||
|
||||
/// <summary>按用户中心组 ID 查询学校列表,<c>GET /oapi/SchInfo/GetSchoolByGroupId</c>;0 或空时返回空列表。</summary>
|
||||
/// <param name="groupId">用户中心组 ID(Java 参数名 <c>groupId</c>)。</param>
|
||||
public Task<List<SchInfoVo>> GetSchoolByGroupIdAsync(int? groupId, CancellationToken ct = default)
|
||||
=> ResolveListAsync<SchInfoVo>(HttpMethod.Get, Root + "GetSchoolByGroupId",
|
||||
Params(("groupId", groupId)), ct: ct);
|
||||
|
||||
/// <summary>按学制 ID 查询学校,<c>GET /oapi/SchInfo/GetSchoolBySchoolenId</c>;当前服务端恒返回空列表。</summary>
|
||||
public Task<List<SchClassRow>> GetSchoolBySchoolenIdAsync(int? groupId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchoolBySchoolenId",
|
||||
Params(("groupId", groupId)), ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 Schoolen(学制 / 年级)接口客户端(镜像 Java <c>SchoolingController</c>,路径前缀 <c>/oapi/Schoolen/</c>)。
|
||||
/// <para>
|
||||
/// 年级行字段:<c>Id / Name / OwnerId / Levell / code / sx</c>;
|
||||
/// 学制行字段:<c>Id / Name / FormerName / Type</c>。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class SchClassSchoolingClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/Schoolen/";
|
||||
|
||||
public SchClassSchoolingClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>按学校查询年级(学制层级)列表,<c>GET /oapi/Schoolen/GetSchLenLevellist</c>。</summary>
|
||||
/// <param name="schSerId">学校外部序列号(Java 参数名 <c>SchSerID</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetSchLenLevelListAsync(string? schSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchLenLevellist", Params(("SchSerID", schSerId)), ct: ct);
|
||||
|
||||
/// <summary>按学制 ID 查询年级列表,<c>GET /oapi/Schoolen/GetLevelIdlist</c>。</summary>
|
||||
/// <param name="schooling">学制 ID(Java 参数名 <c>Schooling</c>);0 或空时服务端返回空列表。</param>
|
||||
public Task<List<SchClassRow>> GetLevelIdListAsync(int? schooling, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetLevelIdlist", Params(("Schooling", schooling)), ct: ct);
|
||||
|
||||
/// <summary>按年级 ID 查询单个年级,<c>GET /oapi/Schoolen/GetSchLenLevelFirst</c>;未找到返回 null。</summary>
|
||||
/// <param name="gradeId">年级 ID(Java 参数名 <c>GradeId</c>,字符串形式)。</param>
|
||||
public Task<SchClassRow?> GetSchLenLevelFirstAsync(string? gradeId, CancellationToken ct = default)
|
||||
=> ResolveAsync<SchClassRow>(HttpMethod.Get, Root + "GetSchLenLevelFirst",
|
||||
Params(("GradeId", gradeId)), ct: ct);
|
||||
|
||||
/// <summary>按学校查询学制列表,<c>GET /oapi/Schoolen/GetSchLenlist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetSchLenListAsync(string? schSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchLenlist", Params(("SchSerID", schSerId)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 查询班级科目,<c>GET /oapi/Schoolen/GetAllClassSubject</c>;当前服务端恒返回空列表。
|
||||
/// </summary>
|
||||
public Task<List<SchClassRow>> GetAllClassSubjectAsync(int? schId, string? schserid, string? startTime, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetAllClassSubject",
|
||||
Params(("schId", schId), ("schserid", schserid), ("startTime", startTime)), ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 OAStu(学生)接口客户端(镜像 Java <c>StuInfoController</c>,路径前缀 <c>/oapi/OAStu/</c>)。
|
||||
/// <para>
|
||||
/// 学生行字段(<c>OaCompatSupport.student</c>):
|
||||
/// <c>Account / UserStuSerID / StuName / StuIDCard / StuSex / StuStatus / ClassID / ClassStuID /
|
||||
/// GroupID / StuPhoto / CardID / StuCurrentTel / invitecode / SchSerID / Graduated / isjiedu</c>;
|
||||
/// 走班(Elective)行在此基础上追加 <c>electiveId / schoolId</c> 且 <c>StuSex</c> 为数值。
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 历史学生行字段:<c>stuId / stuName / classId / className / grade / name / school_system_id / system_grade</c>。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class SchClassStuInfoClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/OAStu/";
|
||||
|
||||
public SchClassStuInfoClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>查询全部学生,<c>GET /oapi/OAStu/GetAllStulist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetAllStuListAsync(CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetAllStulist", ct: ct);
|
||||
|
||||
/// <summary>查询全部走班学生,<c>GET /oapi/OAStu/GetEleAllStulist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleAllStuListAsync(CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleAllStulist", ct: ct);
|
||||
|
||||
/// <summary>按学校查询学生,<c>GET /oapi/OAStu/GetSchStulist</c>。</summary>
|
||||
/// <param name="schserid">学校外部序列号(Java 参数名 <c>schserid</c>,全小写)。</param>
|
||||
/// <param name="schgroupid">学校分组 ID(Java 参数名 <c>schgroupid</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetSchStuListAsync(string? schserid, string? schgroupid, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchStulist",
|
||||
Params(("schserid", schserid), ("schgroupid", schgroupid)), ct: ct);
|
||||
|
||||
/// <summary>按学校查询走班学生,<c>GET /oapi/OAStu/GetEleSchStulist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchStuListAsync(string? schserid, string? schgroupid, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchStulist",
|
||||
Params(("schserid", schserid), ("schgroupid", schgroupid)), ct: ct);
|
||||
|
||||
/// <summary>按班级查询学生,<c>GET /oapi/OAStu/GetClaStulist</c>。</summary>
|
||||
/// <param name="classId">班级 ID(Java 参数名 <c>ClassID</c>)。</param>
|
||||
/// <param name="claGroupId">班级分组 ID(Java 参数名 <c>clagroupid</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetClaStuListAsync(string? classId, string? claGroupId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetClaStulist",
|
||||
Params(("ClassID", classId), ("clagroupid", claGroupId)), ct: ct);
|
||||
|
||||
/// <summary>按班级查询走班学生,<c>GET /oapi/OAStu/GetEleClaStulist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleClaStuListAsync(string? classId, string? claGroupId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleClaStulist",
|
||||
Params(("ClassID", classId), ("clagroupid", claGroupId)), ct: ct);
|
||||
|
||||
/// <summary>按多个班级查询学生,<c>GET /oapi/OAStu/GetClaArrStulist</c>。</summary>
|
||||
/// <param name="classIds">逗号分隔的班级 ID 列表(Java 参数名 <c>ClassIDs</c>)。</param>
|
||||
/// <param name="claGroupIds">逗号分隔的班级分组 ID 列表(Java 参数名 <c>clagroupids</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetClaArrStuListAsync(string? classIds, string? claGroupIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetClaArrStulist",
|
||||
Params(("ClassIDs", classIds), ("clagroupids", claGroupIds)), ct: ct);
|
||||
|
||||
/// <summary>按多个班级查询走班学生,<c>GET /oapi/OAStu/GetEleClaArrStulist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleClaArrStuListAsync(string? classIds, string? claGroupIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleClaArrStulist",
|
||||
Params(("ClassIDs", classIds), ("clagroupids", claGroupIds)), ct: ct);
|
||||
|
||||
/// <summary>按多个学生 ID 查询学生,<c>GET /oapi/OAStu/GetStuIdslist</c>。</summary>
|
||||
/// <param name="stuids">逗号分隔的学生 ID 列表(Java 参数名 <c>stuids</c>,全小写)。</param>
|
||||
public Task<List<SchClassRow>> GetStuIdsListAsync(string? stuids, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetStuIdslist", Params(("stuids", stuids)), ct: ct);
|
||||
|
||||
/// <summary>按多个学生 ID 查询走班学生,<c>GET /oapi/OAStu/GetEleStuIdslist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleStuIdsListAsync(string? stuids, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleStuIdslist", Params(("stuids", stuids)), ct: ct);
|
||||
|
||||
/// <summary>查询学生家长用户 ID 列表,<c>GET /oapi/OAStu/GetStuUserFamIDList</c>;当前服务端恒返回空列表。</summary>
|
||||
public Task<List<string>> GetStuUserFamIdListAsync(string? stuids, CancellationToken ct = default)
|
||||
=> ResolveListAsync<string>(HttpMethod.Get, Root + "GetStuUserFamIDList",
|
||||
Params(("stuids", stuids)), ct: ct);
|
||||
|
||||
/// <summary>按邀请码查询学生,<c>GET /oapi/OAStu/GetFamStulist</c>。</summary>
|
||||
/// <param name="invitecodes">逗号分隔的邀请码列表(Java 参数名 <c>invitecodes</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetFamStuListAsync(string? invitecodes, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetFamStulist",
|
||||
Params(("invitecodes", invitecodes)), ct: ct);
|
||||
|
||||
/// <summary>查询学生家庭成员,<c>GET /oapi/OAStu/GetStuFamMem</c>;当前服务端恒返回空列表。</summary>
|
||||
public Task<List<SchClassRow>> GetStuFamMemAsync(string? schSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetStuFamMem", Params(("SchSerID", schSerId)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校序列号查询学生,<c>GET /oapi/OAStu/GetSchBySchIds</c>。</summary>
|
||||
/// <param name="schserids">逗号分隔的学校序列号列表(Java 参数名 <c>schserids</c>,全小写)。</param>
|
||||
public Task<List<SchClassRow>> GetSchBySchIdsAsync(string? schserids, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchBySchIds", Params(("schserids", schserids)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校序列号查询走班学生,<c>GET /oapi/OAStu/GetEleSchIdsStulist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchIdsStuListAsync(string? schserids, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchIdsStulist", Params(("schserids", schserids)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校序列号查询走班学生,<c>GET /oapi/OAStu/GetEleSchBySchIds</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchBySchIdsAsync(string? schserids, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchBySchIds", Params(("schserids", schserids)), ct: ct);
|
||||
|
||||
/// <summary>按选课 ID 查询学生,<c>GET /oapi/OAStu/GetStudentsByElectiveId</c>;当前服务端恒返回空列表。</summary>
|
||||
public Task<List<SchClassRow>> GetStudentsByElectiveIdAsync(int? electiveIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetStudentsByElectiveId",
|
||||
Params(("electiveIds", electiveIds)), ct: ct);
|
||||
|
||||
/// <summary>按学校 + 年度查询历史学生,<c>GET /oapi/OAStu/getHistoryStudentsBySchoolId</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetHistoryStudentsBySchoolIdAsync(int schoolId, int year, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "getHistoryStudentsBySchoolId",
|
||||
Params(("schoolId", schoolId), ("year", year)), ct: ct);
|
||||
|
||||
/// <summary>按学校 + 年度查询历史班级,<c>GET /oapi/OAStu/getHistoryClass</c>;当前服务端恒返回空列表。</summary>
|
||||
public Task<List<SchClassRow>> GetHistoryClassAsync(int schoolId, int year, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "getHistoryClass",
|
||||
Params(("schoolId", schoolId), ("year", year)), ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 SubInfo(科目)接口客户端(镜像 Java <c>SchSubController</c>,路径前缀 <c>/oapi/SubInfo/</c>)。
|
||||
/// <para>科目行字段:<c>SchSerID / SubID / SubName / No</c>。</para>
|
||||
/// </summary>
|
||||
public class SchClassSubInfoClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/SubInfo/";
|
||||
|
||||
public SchClassSubInfoClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>按学校 + 学制查询科目列表,<c>GET /oapi/SubInfo/GetSchSublist</c>。</summary>
|
||||
/// <param name="schId">学校外部序列号(Java 参数名 <c>SchID</c>)。</param>
|
||||
/// <param name="schooling">学制 ID(Java 参数名 <c>schooling</c>,全小写)。</param>
|
||||
/// <param name="gradeId">年级 ID(Java 参数名 <c>gradeId</c>;当前服务端未使用该参数)。</param>
|
||||
public Task<List<SchClassRow>> GetSchSubListAsync(string? schId, int? schooling, int? gradeId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchSublist",
|
||||
Params(("SchID", schId), ("schooling", schooling), ("gradeId", gradeId)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校查询科目列表,<c>GET /oapi/SubInfo/GetSchIdsSublist</c>。</summary>
|
||||
/// <param name="schIds">逗号分隔的学校序列号列表(Java 参数名 <c>SchIds</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetSchIdsSubListAsync(string? schIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchIdsSublist", Params(("SchIds", schIds)), ct: ct);
|
||||
|
||||
/// <summary>按教师查询其任教的科目编码列表(去重字符串),<c>GET /oapi/SubInfo/GetSchTeaSublist</c>。</summary>
|
||||
/// <param name="userTeaSerId">教师 ID(Java 参数名 <c>UserTeaSerID</c>,字符串形式)。</param>
|
||||
public Task<List<string>> GetSchTeaSubListAsync(string? userTeaSerId, CancellationToken ct = default)
|
||||
=> ResolveListAsync<string>(HttpMethod.Get, Root + "GetSchTeaSublist",
|
||||
Params(("UserTeaSerID", userTeaSerId)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按学校查询该校全部任课科目编码(小写去重字符串),<c>GET /oapi/SubInfo/GetSchTeachSublist</c>。
|
||||
/// </summary>
|
||||
public Task<List<string>> GetSchTeachSubListAsync(string? schId, CancellationToken ct = default)
|
||||
=> ResolveListAsync<string>(HttpMethod.Get, Root + "GetSchTeachSublist",
|
||||
Params(("SchID", schId)), ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Yh.SchClass.OpenApi.Model;
|
||||
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 OATea(教师)接口客户端(镜像 Java <c>TeainfoController</c>,路径前缀 <c>/oapi/OATea/</c>)。
|
||||
/// </summary>
|
||||
public class SchClassTeaInfoClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/OATea/";
|
||||
|
||||
public SchClassTeaInfoClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按教师 ID 查询教师(<c>GET /oapi/OATea/GetTeainfo</c>)。
|
||||
/// 教师不存在或无分组归属时服务端返回 404,本方法返回 null。
|
||||
/// </summary>
|
||||
/// <param name="uid">教师 ID(Java 参数名 <c>uid</c>,全小写)。</param>
|
||||
public Task<TeaInfoVo?> GetTeaInfoAsync(int uid, CancellationToken ct = default)
|
||||
=> ResolveAsync<TeaInfoVo>(HttpMethod.Get, Root + "GetTeainfo", Params(("uid", uid)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按多个教师 ID 查询教师列表(<c>POST /oapi/OATea/GetArrTeainfo</c>)。
|
||||
/// 请求体为逗号分隔的教师 ID(Java 侧 <c>@RequestBody String</c>,按 text/plain 提交);
|
||||
/// 参数缺失时服务端返回 400,查询为空时返回 204(本方法返回空列表)。
|
||||
/// </summary>
|
||||
public Task<List<TeaInfoVo>> GetArrTeaInfoAsync(string userIds, CancellationToken ct = default)
|
||||
=> ResolveListAsync<TeaInfoVo>(HttpMethod.Post, Root + "GetArrTeainfo", body: userIds, ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按学校查询教师列表(<c>GET /oapi/OATea/GetSchTeainfo</c>)。
|
||||
/// <paramref name="schId"/> 与 <paramref name="schSerId"/> 至少提供一个,否则服务端返回 400。
|
||||
/// </summary>
|
||||
/// <param name="schSerId">学校外部序列号(Java 参数名 <c>SchSerID</c>)。</param>
|
||||
/// <param name="schId">学校内部 ID(Java 参数名 <c>schId</c>,优先使用)。</param>
|
||||
public Task<List<TeaInfoVo>> GetSchTeaInfoAsync(string? schSerId = null, int? schId = null, CancellationToken ct = default)
|
||||
=> ResolveListAsync<TeaInfoVo>(HttpMethod.Get, Root + "GetSchTeainfo",
|
||||
Params(("SchSerID", schSerId), ("schId", schId)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按学校查询教师列表(<c>GET /oapi/OATea/GetSchTeaList</c>),与 <see cref="GetSchTeaInfoAsync"/> 等价。
|
||||
/// </summary>
|
||||
public Task<List<TeaInfoVo>> GetSchTeaListAsync(string? schSerId = null, int? schId = null, CancellationToken ct = default)
|
||||
=> ResolveListAsync<TeaInfoVo>(HttpMethod.Get, Root + "GetSchTeaList",
|
||||
Params(("SchSerID", schSerId), ("schId", schId)), ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 TeachInfo(任课)接口客户端(镜像 Java <c>TeaChesController</c>,路径前缀 <c>/oapi/TeachInfo/</c>)。
|
||||
/// <para>
|
||||
/// 任课行字段(<c>OaCompatSupport.teaching</c>):
|
||||
/// <c>SerID / SchSerID / UserTeaSerID / SubID / ClassID / UserClassID / CreationTime / static</c>。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class SchClassTeachInfoClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/TeachInfo/";
|
||||
|
||||
public SchClassTeachInfoClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>按学校 + 教师查询任课,<c>GET /oapi/TeachInfo/GetSchTeachlist</c>。</summary>
|
||||
/// <param name="schId">学校外部序列号(Java 参数名 <c>SchID</c>)。</param>
|
||||
/// <param name="userTeaSerId">教师 ID(Java 参数名 <c>UserTeaSerID</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetSchTeachListAsync(string? schId, int? userTeaSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchTeachlist",
|
||||
Params(("SchID", schId), ("UserTeaSerID", userTeaSerId)), ct: ct);
|
||||
|
||||
/// <summary>按学校 + 教师查询走班任课,<c>GET /oapi/TeachInfo/GetEleSchTeachlist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchTeachListAsync(string? schId, int? userTeaSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchTeachlist",
|
||||
Params(("SchID", schId), ("UserTeaSerID", userTeaSerId)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校查询任课,<c>GET /oapi/TeachInfo/GetSchArrTeachlist</c>。</summary>
|
||||
/// <param name="schIdArr">逗号分隔的学校序列号列表(Java 参数名 <c>SchIDArr</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetSchArrTeachListAsync(string? schIdArr, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchArrTeachlist", Params(("SchIDArr", schIdArr)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校查询走班任课,<c>GET /oapi/TeachInfo/GetEleSchArrTeachList</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchArrTeachListAsync(string? schIdArr, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchArrTeachList", Params(("SchIDArr", schIdArr)), ct: ct);
|
||||
|
||||
/// <summary>按班级查询任课,<c>GET /oapi/TeachInfo/GetSchClaTeachlist</c>。</summary>
|
||||
/// <param name="classId">班级 ID(Java 参数名 <c>ClassID</c>);非法或为空时返回空列表。</param>
|
||||
public Task<List<SchClassRow>> GetSchClaTeachListAsync(string? classId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchClaTeachlist", Params(("ClassID", classId)), ct: ct);
|
||||
|
||||
/// <summary>按班级查询走班任课,<c>GET /oapi/TeachInfo/GetEleSchClaTeachlist</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchClaTeachListAsync(string? classId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchClaTeachlist", Params(("ClassID", classId)), ct: ct);
|
||||
|
||||
/// <summary>按学校 + 年级查询选课班级,<c>GET /oapi/TeachInfo/GetElectiveClassByGrade</c>;当前服务端恒返回空列表。</summary>
|
||||
public Task<List<SchClassRow>> GetElectiveClassByGradeAsync(int? schoolId, int? gradeId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetElectiveClassByGrade",
|
||||
Params(("schoolId", schoolId), ("gradeId", gradeId)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按多个教师查询选课班级,<c>POST /oapi/TeachInfo/GetElectiveClassByTeachers</c>;
|
||||
/// 请求体为逗号分隔的教师 ID(text/plain),当前服务端恒返回空列表。
|
||||
/// </summary>
|
||||
public Task<List<SchClassRow>> GetElectiveClassByTeachersAsync(string? teacherIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Post, Root + "GetElectiveClassByTeachers", body: teacherIds, ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Yh.SchClass.OpenApi.Model;
|
||||
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 UserInfo(师生统一用户)接口客户端(镜像 Java <c>UserInfoController</c>,路径前缀 <c>/oapi/UserInfo/</c>)。
|
||||
/// </summary>
|
||||
public class SchClassUserInfoClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/UserInfo/";
|
||||
|
||||
public SchClassUserInfoClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询学校全部教师 + 学生(<c>GET /oapi/UserInfo/GetUserList</c>)。
|
||||
/// 参数缺失或学校不存在时服务端返回 400;查询为空时返回 204(本方法返回空列表)。
|
||||
/// </summary>
|
||||
/// <param name="schSerId">学校外部序列号(Java 参数名 <c>SchSerID</c>)。</param>
|
||||
public Task<List<UserInfoVo>> GetUserListAsync(string schSerId, CancellationToken ct = default)
|
||||
=> ResolveListAsync<UserInfoVo>(HttpMethod.Get, Root + "GetUserList",
|
||||
Params(("SchSerID", schSerId)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按用户 ID 查询用户信息(<c>GET /oapi/UserInfo/getUserIdList</c>)。
|
||||
/// 教师 / 学生均未命中时服务端返回 404,本方法返回空列表。
|
||||
/// </summary>
|
||||
/// <param name="userid">用户 ID(Java 参数名 <c>userid</c>,全小写)。</param>
|
||||
public Task<List<UserInfoVo>> GetUserIdListAsync(int userid, CancellationToken ct = default)
|
||||
=> ResolveListAsync<UserInfoVo>(HttpMethod.Get, Root + "getUserIdList",
|
||||
Params(("userid", userid)), ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
namespace Yh.SchClass.OpenApi;
|
||||
|
||||
/// <summary>
|
||||
/// 教务 VSchClass(班级)接口客户端(镜像 Java <c>VClassController</c>,路径前缀 <c>/oapi/VSchClass/</c>)。
|
||||
/// <para>
|
||||
/// 班级行字段(<c>OaCompatSupport.classInfo</c>):
|
||||
/// <c>Id / Name / OwnerId / Levell / sx / SchSerID / ClassID / UserClassID / Schooling / MajorCode /
|
||||
/// ClassCode / ClassMotto / ClassName / StartDate / FirstTeaUserID / SecondTeaUserID / UpgradeYear /
|
||||
/// CurrentIndex / CreationTime / GradtionTime / GreduatedYear / Graduated</c>。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class SchClassVClassClient : SchClassClientBase
|
||||
{
|
||||
private const string Root = Prefix + "/VSchClass/";
|
||||
|
||||
public SchClassVClassClient(HttpClient httpClient, SchClassOpenApiOptions options)
|
||||
: base(httpClient, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>按学校查询班级(排除已毕业),<c>GET /oapi/VSchClass/GetVClassList</c>。</summary>
|
||||
/// <param name="schSerId">学校外部序列号(Java 参数名 <c>SchSerID</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetVClassListAsync(string? schSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetVClassList", Params(("SchSerID", schSerId)), ct: ct);
|
||||
|
||||
/// <summary>按学校查询班级(含已毕业),<c>GET /oapi/VSchClass/GetEleVClassList</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleVClassListAsync(string? schSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleVClassList", Params(("SchSerID", schSerId)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校查询班级(排除已毕业),<c>GET /oapi/VSchClass/GetSchArrVClassList</c>。</summary>
|
||||
/// <param name="schIdArr">逗号分隔的学校序列号列表(Java 参数名 <c>SchIDArr</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetSchArrVClassListAsync(string? schIdArr, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchArrVClassList", Params(("SchIDArr", schIdArr)), ct: ct);
|
||||
|
||||
/// <summary>按多个学校查询班级(含已毕业),<c>GET /oapi/VSchClass/GetEleSchArrVClassList</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchArrVClassListAsync(string? schIdArr, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchArrVClassList", Params(("SchIDArr", schIdArr)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按时间查询学校班级,<c>GET /oapi/VSchClass/GetFunTimeSchClass</c>。
|
||||
/// 注意:Java 实现忽略 <paramref name="time"/>,实际按学校过滤。
|
||||
/// </summary>
|
||||
public Task<List<SchClassRow>> GetFunTimeSchClassAsync(string? time, string? schSerId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetFunTimeSchClass",
|
||||
Params(("time", time), ("SchSerID", schSerId)), ct: ct);
|
||||
|
||||
/// <summary>按班级 ID 查询单个班级,<c>GET /oapi/VSchClass/GetVClassFirst</c>;未找到返回 null。</summary>
|
||||
/// <param name="classId">班级 ID(Java 参数名 <c>ClassID</c>)。</param>
|
||||
public Task<SchClassRow?> GetVClassFirstAsync(string? classId, CancellationToken ct = default)
|
||||
=> ResolveAsync<SchClassRow>(HttpMethod.Get, Root + "GetVClassFirst", Params(("ClassID", classId)), ct: ct);
|
||||
|
||||
/// <summary>按班级 ID 查询单个班级(含已毕业),<c>GET /oapi/VSchClass/GetEleVClassFirst</c>。</summary>
|
||||
public Task<SchClassRow?> GetEleVClassFirstAsync(string? classId, CancellationToken ct = default)
|
||||
=> ResolveAsync<SchClassRow>(HttpMethod.Get, Root + "GetEleVClassFirst", Params(("ClassID", classId)), ct: ct);
|
||||
|
||||
/// <summary>按多个班级 ID 查询班级,<c>GET /oapi/VSchClass/GetVClassIdsList</c>。</summary>
|
||||
/// <param name="classIds">逗号分隔的班级 ID 列表(Java 参数名 <c>ClassIds</c>)。</param>
|
||||
public Task<List<SchClassRow>> GetVClassIdsListAsync(string? classIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetVClassIdsList", Params(("ClassIds", classIds)), ct: ct);
|
||||
|
||||
/// <summary>按多个班级 ID 查询班级(含已毕业),<c>GET /oapi/VSchClass/GetEleVClassIdsList</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleVClassIdsListAsync(string? classIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleVClassIdsList", Params(("ClassIds", classIds)), ct: ct);
|
||||
|
||||
/// <summary>按学校 + 学制 + 年级查询班级,<c>GET /oapi/VSchClass/GetGradeClassList</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetGradeClassListAsync(string? schSerId, int? schooling, int? gradeId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetGradeClassList",
|
||||
Params(("SchSerID", schSerId), ("Schooling", schooling), ("GradeId", gradeId)), ct: ct);
|
||||
|
||||
/// <summary>查询教师任课的班级 ID 列表(去重后的字符串),<c>GET /oapi/VSchClass/GetTeachClassArr</c>。</summary>
|
||||
/// <param name="userTeaSerId">教师 ID(Java 参数名 <c>UserTeaSerID</c>)。</param>
|
||||
public Task<List<string>> GetTeachClassArrAsync(int? userTeaSerId, CancellationToken ct = default)
|
||||
=> ResolveListAsync<string>(HttpMethod.Get, Root + "GetTeachClassArr",
|
||||
Params(("UserTeaSerID", userTeaSerId)), ct: ct);
|
||||
|
||||
/// <summary>查询全部班级(排除已毕业),<c>GET /oapi/VSchClass/GetSchArrVClassListAll</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetSchArrVClassListAllAsync(CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetSchArrVClassListAll", ct: ct);
|
||||
|
||||
/// <summary>查询全部班级(含已毕业),<c>GET /oapi/VSchClass/GetEleSchArrVClassListAll</c>。</summary>
|
||||
public Task<List<SchClassRow>> GetEleSchArrVClassListAllAsync(CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetEleSchArrVClassListAll", ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 以 POST 方式按多个学校查询班级,<c>POST /oapi/VSchClass/GetSchArrVClassListPost</c>。
|
||||
/// 请求体为逗号分隔的学校序列号(Java 侧 <c>@RequestBody String</c>,按 text/plain 提交)。
|
||||
/// </summary>
|
||||
public Task<List<SchClassRow>> GetSchArrVClassListPostAsync(string? body, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Post, Root + "GetSchArrVClassListPost", body: body, ct: ct);
|
||||
|
||||
/// <summary>按选课 ID 查询班级,<c>GET /oapi/VSchClass/GetElectiveClassById</c>;当前服务端恒返回 null。</summary>
|
||||
public Task<SchClassRow?> GetElectiveClassByIdAsync(int? electiveId, CancellationToken ct = default)
|
||||
=> ResolveAsync<SchClassRow>(HttpMethod.Get, Root + "GetElectiveClassById",
|
||||
Params(("electiveId", electiveId)), ct: ct);
|
||||
|
||||
/// <summary>按学校 + 年级查询选课班级,<c>GET /oapi/VSchClass/GetElectiveClassByGrade</c>;当前服务端恒返回空列表。</summary>
|
||||
public Task<List<SchClassRow>> GetElectiveClassByGradeAsync(int? schoolId, int? gradeId, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Get, Root + "GetElectiveClassByGrade",
|
||||
Params(("schoolId", schoolId), ("gradeId", gradeId)), ct: ct);
|
||||
|
||||
/// <summary>
|
||||
/// 按多个教师查询选课班级,<c>POST /oapi/VSchClass/GetElectiveClassByTeachers</c>;
|
||||
/// 请求体为逗号分隔的教师 ID(text/plain),当前服务端恒返回空列表。
|
||||
/// </summary>
|
||||
public Task<List<SchClassRow>> GetElectiveClassByTeachersAsync(string? teacherIds, CancellationToken ct = default)
|
||||
=> ResolveRowsAsync(HttpMethod.Post, Root + "GetElectiveClassByTeachers", body: teacherIds, ct: ct);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Yh.SchClass.OpenApi</PackageId>
|
||||
<Description>云海教务(SchClass)开放接口客户端:对应 Java 教务 OpenApi 调用封装</Description>
|
||||
<Summary>SchClass /oapi 同构客户端 SDK,支持 yh:open / yh:schclass:open 配置节绑定与 DI 注册</Summary>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Http" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user