feat(saas): implement marketplace and tenant onboarding

This commit is contained in:
2026-07-29 13:58:59 +08:00
parent 76606029e2
commit 6db200a2fc
145 changed files with 16862 additions and 94529 deletions

View File

@@ -6,15 +6,27 @@ using Tiku.Domain.Content;
namespace Tiku.Api.Contracts;
/// <summary>
/// 资产访问签名查询参数。
/// </summary>
public sealed class AssetAccessQueryDto
{
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
/// <summary>
/// 有效期秒数。
/// </summary>
[Range(1, 7200)]
public int? ExpiresInSeconds { get; set; }
}
/// <summary>
/// 资产访问签名响应。
/// </summary>
public sealed record AssetAccessResponseDto(
ContentAssetAccessSummaryDto Item,
AssetAccessPrincipalDto Access,
@@ -34,6 +46,9 @@ public sealed record AssetAccessResponseDto(
}
}
/// <summary>
/// 内容资产访问摘要。
/// </summary>
public sealed record ContentAssetAccessSummaryDto(
Guid Id,
ContentAssetType AssetType,
@@ -60,11 +75,17 @@ public sealed record ContentAssetAccessSummaryDto(
}
}
/// <summary>
/// 资产访问Principal请求 DTO。
/// </summary>
public sealed record AssetAccessPrincipalDto(
Guid? UserId,
bool IsMember,
bool HasSvip);
/// <summary>
/// SignedStorageUrl请求 DTO。
/// </summary>
public sealed record SignedStorageUrlDto(
string Provider,
string? Bucket,

View File

@@ -3,39 +3,84 @@ using Tiku.Application.Assets;
namespace Tiku.Api.Contracts;
/// <summary>
/// 资产查询参数。
/// </summary>
public sealed class AssetQueryDto
{
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 题目 ID。
/// </summary>
public Guid? QuestionId { get; set; }
/// <summary>
/// 资产 ID。
/// </summary>
public Guid? AssetId { get; set; }
/// <summary>
/// 资产类型。
/// </summary>
[StringLength(50)]
public string? AssetType { get; set; }
/// <summary>
/// 分类。
/// </summary>
[StringLength(100)]
public string? Category { get; set; }
/// <summary>
/// 资产键。
/// </summary>
[StringLength(200)]
public string? AssetKey { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 是否包含锁定资源。
/// </summary>
public bool IncludeLocked { get; set; }
/// <summary>
/// 是否包含停用数据。
/// </summary>
public bool IncludeInactive { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }

View File

@@ -5,64 +5,130 @@ using Tiku.Domain.Common;
namespace Tiku.Api.Contracts;
/// <summary>
/// 创建资产上传签名请求。
/// </summary>
public sealed class AssetUploadSignDto
{
/// <summary>
/// 资产 ID。
/// </summary>
public Guid? AssetId { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 资产键。
/// </summary>
[StringLength(200)]
public string? AssetKey { get; set; }
/// <summary>
/// 标题。
/// </summary>
[StringLength(300)]
public string? Title { get; set; }
/// <summary>
/// 分类。
/// </summary>
[StringLength(100)]
public string? Category { get; set; }
/// <summary>
/// 说明。
/// </summary>
[StringLength(1000)]
public string? Description { get; set; }
/// <summary>
/// 文件名。
/// </summary>
[Required]
[StringLength(500)]
public string FileName { get; set; } = string.Empty;
/// <summary>
/// MIME 类型。
/// </summary>
[Required]
[StringLength(200)]
public string MimeType { get; set; } = string.Empty;
/// <summary>
/// 文件大小,单位为字节。
/// </summary>
[Range(0, long.MaxValue)]
public long? FileSizeBytes { get; set; }
/// <summary>
/// SHA-256 校验值。
/// </summary>
[RegularExpression("^[A-Fa-f0-9]{64}$")]
public string? ChecksumSha256 { get; set; }
/// <summary>
/// 资产类型。
/// </summary>
[StringLength(50)]
public string? AssetType { get; set; }
/// <summary>
/// 可见性。
/// </summary>
[StringLength(50)]
public string? Visibility { get; set; }
/// <summary>
/// 是否公开。
/// </summary>
public bool? IsPublic { get; set; }
/// <summary>
/// 服务提供方。
/// </summary>
[StringLength(50)]
public string? Provider { get; set; }
/// <summary>
/// 存储桶。
/// </summary>
[StringLength(200)]
public string? Bucket { get; set; }
/// <summary>
/// 对象存储键。
/// </summary>
[StringLength(1000)]
public string? ObjectKey { get; set; }
/// <summary>
/// 有效期秒数。
/// </summary>
[Range(1, 3600)]
public int? ExpiresInSeconds { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public AssetUploadSignCommand ToCommand()
@@ -92,17 +158,32 @@ public sealed class AssetUploadSignDto
}
}
/// <summary>
/// 确认资产上传请求。
/// </summary>
public sealed class AssetUploadConfirmDto
{
/// <summary>
/// 资产 ID。
/// </summary>
[Required]
public Guid AssetId { get; set; }
/// <summary>
/// MIME 类型。
/// </summary>
[StringLength(200)]
public string? MimeType { get; set; }
/// <summary>
/// 文件大小,单位为字节。
/// </summary>
[Range(0, long.MaxValue)]
public long? FileSizeBytes { get; set; }
/// <summary>
/// SHA-256 校验值。
/// </summary>
[RegularExpression("^[A-Fa-f0-9]{64}$")]
public string? ChecksumSha256 { get; set; }
@@ -112,34 +193,118 @@ public sealed class AssetUploadConfirmDto
}
}
/// <summary>
/// 新增或更新内容资产请求。
/// </summary>
public sealed class UpsertAssetDto
{
/// <summary>
/// 资产 ID。
/// </summary>
public Guid? AssetId { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 资产键。
/// </summary>
public string? AssetKey { get; set; }
/// <summary>
/// 标题。
/// </summary>
public string? Title { get; set; }
/// <summary>
/// 分类。
/// </summary>
public string? Category { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 文件名。
/// </summary>
public string? FileName { get; set; }
/// <summary>
/// CDN 地址。
/// </summary>
public string? CdnUrl { get; set; }
/// <summary>
/// 是否公开。
/// </summary>
public bool? IsPublic { get; set; }
/// <summary>
/// 资产类型。
/// </summary>
public string? AssetType { get; set; }
/// <summary>
/// 可见性。
/// </summary>
public string? Visibility { get; set; }
/// <summary>
/// 状态。
/// </summary>
public string? Status { get; set; }
/// <summary>
/// 服务提供方。
/// </summary>
public string? Provider { get; set; }
/// <summary>
/// 存储桶。
/// </summary>
public string? Bucket { get; set; }
/// <summary>
/// 对象存储键。
/// </summary>
public string? ObjectKey { get; set; }
/// <summary>
/// MIME 类型。
/// </summary>
public string? MimeType { get; set; }
/// <summary>
/// 文件大小,单位为字节。
/// </summary>
public long? FileSizeBytes { get; set; }
/// <summary>
/// SHA-256 校验值。
/// </summary>
public string? ChecksumSha256 { get; set; }
/// <summary>
/// 预览地址。
/// </summary>
public string? PreviewUrl { get; set; }
/// <summary>
/// 预览对象存储键。
/// </summary>
public string? PreviewObjectKey { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 访问规则。
/// </summary>
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertAssetCommand ToCommand()
@@ -175,11 +340,20 @@ public sealed class UpsertAssetDto
}
}
/// <summary>
/// 创建资产访问签名请求。
/// </summary>
public sealed class AssetAccessSignDto
{
/// <summary>
/// 资产 ID。
/// </summary>
[Required]
public Guid AssetId { get; set; }
/// <summary>
/// 有效期秒数。
/// </summary>
[Range(60, 3600)]
public int? ExpiresInSeconds { get; set; }
@@ -189,31 +363,64 @@ public sealed class AssetAccessSignDto
}
}
/// <summary>
/// 资产管理查询参数。
/// </summary>
public sealed class AssetManagementQueryDto
{
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 资产类型。
/// </summary>
[StringLength(50)]
public string? AssetType { get; set; }
/// <summary>
/// 分类。
/// </summary>
[StringLength(100)]
public string? Category { get; set; }
/// <summary>
/// 上传状态。
/// </summary>
[StringLength(50)]
public string? UploadStatus { get; set; }
/// <summary>
/// 安全扫描状态。
/// </summary>
[StringLength(50)]
public string? SecurityScanStatus { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }
@@ -233,11 +440,23 @@ public sealed class AssetManagementQueryDto
}
}
/// <summary>
/// 资产事件查询参数。
/// </summary>
public sealed class AssetEventQueryDto
{
/// <summary>
/// 资产 ID。
/// </summary>
public Guid? AssetId { get; set; }
/// <summary>
/// 用户 ID。
/// </summary>
public Guid? UserId { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }
@@ -247,17 +466,32 @@ public sealed class AssetEventQueryDto
}
}
/// <summary>
/// 导入任务查询参数。
/// </summary>
public sealed class ImportJobQueryDto
{
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 导入Type。
/// </summary>
[StringLength(50)]
public string? ImportType { get; set; }
/// <summary>
/// 来源格式。
/// </summary>
[StringLength(50)]
public string? SourceFormat { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }

View File

@@ -6,32 +6,38 @@ using Tiku.Domain.Tenancy;
namespace Tiku.Api.Contracts;
/// <summary>
/// 手机号密码登录请求
/// PasswordLogin请求 DTO
/// </summary>
public sealed class PasswordLoginDto
{
/// <summary>
/// 认证域。
/// </summary>
[Required]
public AuthRealm? Realm { get; set; }
/// <summary>
/// 平台控制域名登录时使用的租户代码;自定义域名登录可省略
/// 租户编码
/// </summary>
[StringLength(100)]
[Description("平台控制域名登录时使用的租户代码;自定义域名登录可省略。")]
public string? TenantCode { get; set; }
/// <summary>
/// 账号标识。tenant 可使用手机号platform 可使用邮箱或用户名。
/// 账号标识。
/// </summary>
[StringLength(320)]
[Description("账号标识。tenant 可使用手机号platform 可使用邮箱或用户名。")]
public string? Identifier { get; set; }
/// <summary>
/// 兼容手机号字段;新客户端应使用 identifier。
/// </summary>
[StringLength(32)]
[Description("兼容手机号字段;新客户端应使用 identifier。")]
public string? Phone { get; set; }
/// <summary>
/// 用户密码。
/// 密码。
/// </summary>
[Required]
[StringLength(128, MinimumLength = 8)]
@@ -40,21 +46,24 @@ public sealed class PasswordLoginDto
}
/// <summary>
/// 短信验证码登录请求
/// SmsLogin请求 DTO
/// </summary>
public sealed class SmsLoginDto
{
/// <summary>
/// 认证域。
/// </summary>
[Required]
public AuthRealm? Realm { get; set; }
/// <summary>
/// 平台控制域名登录时使用的租户代码;自定义域名登录可省略
/// 租户编码
/// </summary>
[StringLength(100)]
[Description("平台控制域名登录时使用的租户代码;自定义域名登录可省略。")]
public string? TenantCode { get; set; }
/// <summary>
/// 中国大陆手机号。
/// 手机号。
/// </summary>
[Required]
[StringLength(32)]
@@ -62,7 +71,7 @@ public sealed class SmsLoginDto
public string Phone { get; set; } = string.Empty;
/// <summary>
/// 收到的短信验证码。
/// 码。
/// </summary>
[Required]
[StringLength(12, MinimumLength = 4)]
@@ -70,38 +79,56 @@ public sealed class SmsLoginDto
public string Code { get; set; } = string.Empty;
}
/// <summary>
/// 发送短信验证码请求。
/// </summary>
public sealed class SendSmsCodeDto
{
/// <summary>
/// 认证域。
/// </summary>
[Required]
public AuthRealm? Realm { get; set; }
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
/// <summary>
/// 手机号。
/// </summary>
[Required]
[StringLength(32)]
public string Phone { get; set; } = string.Empty;
/// <summary>
/// 设备 ID。
/// </summary>
[StringLength(256)]
public string? DeviceId { get; set; }
}
/// <summary>
/// OAuth code 登录请求
/// O认证编码请求 DTO
/// </summary>
public sealed class OAuthCodeDto
{
/// <summary>
/// 认证域。
/// </summary>
[Required]
public AuthRealm? Realm { get; set; }
/// <summary>
/// 平台控制域名登录时使用的租户代码;自定义域名登录可省略
/// 租户编码
/// </summary>
[StringLength(100)]
[Description("平台控制域名登录时使用的租户代码;自定义域名登录可省略。")]
public string? TenantCode { get; set; }
/// <summary>
/// OAuth 平台返回的一次性授权 code
/// 编码
/// </summary>
[Required]
[StringLength(512)]
@@ -109,13 +136,13 @@ public sealed class OAuthCodeDto
public string Code { get; set; } = string.Empty;
/// <summary>
/// 客户端可提供的公开用户资料,不允许包含 token/secret。当前后端先保留模板字段后续按业务需要逐步使用
/// 公开用户资料
/// </summary>
[Description("客户端可提供的公开用户资料,不允许包含 token/secret。当前后端先保留模板字段后续按业务需要逐步使用。")]
public Dictionary<string, object?>? Profile { get; set; }
/// <summary>
/// 微信用户资料语言,例如 zh_CN。当前微信小程序登录不会使用该字段
/// 语言
/// </summary>
[StringLength(20)]
[Description("微信用户资料语言,例如 zh_CN。当前微信小程序登录不会使用该字段。")]
@@ -123,12 +150,12 @@ public sealed class OAuthCodeDto
}
/// <summary>
/// refresh token 请求
/// 刷新会话请求 DTO
/// </summary>
public sealed class RefreshSessionDto
{
/// <summary>
/// refresh token。服务端只存储哈希明文只返回给客户端一次
/// 刷新令牌
/// </summary>
[Required]
[StringLength(2048)]
@@ -137,7 +164,7 @@ public sealed class RefreshSessionDto
}
/// <summary>
/// 登录成功后的用户、租户成员和令牌信息
/// Authenticated用户请求 DTO
/// </summary>
public sealed class AuthenticatedUserDto
{
@@ -157,19 +184,22 @@ public sealed class AuthenticatedUserDto
public string? Email { get; init; }
/// <summary>
/// 用户显示名称。
/// 名称。
/// </summary>
public string? Name { get; init; }
/// <summary>
/// 认证域。
/// </summary>
public AuthRealm Realm { get; init; }
/// <summary>
/// 当前登录租户成员摘要。
/// 租户成员摘要。
/// </summary>
public TenantMembershipSummary? Tenant { get; init; }
/// <summary>
/// access token 和 refresh token
/// 访问令牌和刷新令牌
/// </summary>
public AuthTokenPair Tokens { get; init; } = default!;
@@ -188,11 +218,26 @@ public sealed class AuthenticatedUserDto
}
}
/// <summary>
/// 登录认证结果。
/// </summary>
public sealed class AuthenticationResultDto
{
/// <summary>
/// 状态。
/// </summary>
public AuthenticationStatus Status { get; init; }
/// <summary>
/// 用户信息。
/// </summary>
public AuthenticatedUserDto? User { get; init; }
/// <summary>
/// 挑战令牌。
/// </summary>
public string? ChallengeToken { get; init; }
/// <summary>
/// 挑战令牌过期时间。
/// </summary>
public DateTimeOffset? ChallengeExpiresAt { get; init; }
public static AuthenticationResultDto FromApplication(AuthenticationResult result) => new()
@@ -204,12 +249,21 @@ public sealed class AuthenticationResultDto
};
}
/// <summary>
/// 首次登录必改密码请求。
/// </summary>
public sealed class RequiredPasswordChangeDto
{
/// <summary>
/// 挑战令牌。
/// </summary>
[Required]
[StringLength(2048)]
public string ChallengeToken { get; set; } = string.Empty;
/// <summary>
/// 新密码。
/// </summary>
[Required]
[StringLength(128, MinimumLength = 8)]
public string NewPassword { get; set; } = string.Empty;

View File

@@ -3,11 +3,26 @@ using Tiku.Application.Jobs;
namespace Tiku.Api.Contracts;
/// <summary>
/// 创建租户后台任务请求。
/// </summary>
public sealed class CreateBackgroundJobDto
{
/// <summary>
/// 任务类型。
/// </summary>
public string JobType { get; set; } = string.Empty;
/// <summary>
/// 任务载荷。
/// </summary>
public JsonElement Payload { get; set; }
/// <summary>
/// 计划运行时间。
/// </summary>
public DateTimeOffset? RunAfter { get; set; }
/// <summary>
/// 最大重试次数。
/// </summary>
public int MaxRetries { get; set; } = 3;
public CreateBackgroundJobCommand ToCommand(Guid tenantId)

View File

@@ -4,13 +4,34 @@ using Tiku.Domain.Operations;
namespace Tiku.Api.Contracts;
/// <summary>
/// 创建或更新后台角色请求。
/// </summary>
public sealed class UpsertBackofficeRoleDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 编码。
/// </summary>
public string Code { get; set; } = string.Empty;
/// <summary>
/// 名称。
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 状态。
/// </summary>
public BackendRoleStatus Status { get; set; } = BackendRoleStatus.Active;
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 数据范围配置。
/// </summary>
public JsonElement? DataScope { get; set; }
public UpsertBackofficeRoleCommand ToCommand()
@@ -19,9 +40,18 @@ public sealed class UpsertBackofficeRoleDto
}
}
/// <summary>
/// 替换角色权限绑定请求。
/// </summary>
public sealed class ReplaceRoleBindingsDto
{
/// <summary>
/// 权限编码列表。
/// </summary>
public IReadOnlyCollection<string> PermissionCodes { get; set; } = [];
/// <summary>
/// 菜单编码列表。
/// </summary>
public IReadOnlyCollection<string> MenuCodes { get; set; } = [];
public ReplaceRoleBindingsCommand ToCommand(Guid roleId)
@@ -30,8 +60,14 @@ public sealed class ReplaceRoleBindingsDto
}
}
/// <summary>
/// 替换用户角色请求。
/// </summary>
public sealed class ReplaceUserRolesDto
{
/// <summary>
/// 角色 ID 列表。
/// </summary>
public IReadOnlyCollection<Guid> RoleIds { get; set; } = [];
public ReplaceUserRolesCommand ToCommand(Guid userId)

View File

@@ -3,10 +3,13 @@ using Tiku.Application.Catalog;
namespace Tiku.Api.Contracts;
/// <summary>
/// 目录查询参数。
/// </summary>
public sealed class CatalogQueryDto
{
/// <summary>
/// 租户编码。未登录公开查询时使用;已登录时优先使用当前 token 的租户。
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
@@ -17,7 +20,7 @@ public sealed class CatalogQueryDto
public Guid? RegionId { get; set; }
/// <summary>
/// 功能模块 ID
/// ModuleId
/// </summary>
public Guid? ModuleId { get; set; }
@@ -44,24 +47,24 @@ public sealed class CatalogQueryDto
public Guid? SubjectId { get; set; }
/// <summary>
/// 导航节点 ID。
/// 节点 ID。
/// </summary>
public Guid? NodeId { get; set; }
/// <summary>
/// 名称关键
/// 关键
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 类型过滤,例如 cultural、professional、chapter、paper
/// 类型。
/// </summary>
[StringLength(50)]
public string? Type { get; set; }
/// <summary>
/// 返回数上限。
/// 返回数上限。
/// </summary>
[Range(1, 2000)]
public int? Limit { get; set; }

View File

@@ -3,25 +3,49 @@ using Tiku.Application.Commerce;
namespace Tiku.Api.Contracts;
/// <summary>
/// 创建交易订单请求 DTO。
/// </summary>
public sealed class CreateCommerceOrderDto
{
/// <summary>
/// 套餐 ID。
/// </summary>
[Required]
public Guid PlanId { get; set; }
/// <summary>
/// 数量。
/// </summary>
[Range(1, 99)]
public int Quantity { get; set; } = 1;
/// <summary>
/// 支付方式。
/// </summary>
[StringLength(50)]
public string? PayMethod { get; set; }
/// <summary>
/// 支付渠道。
/// </summary>
[StringLength(50)]
public string? PayProvider { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 优惠券码。
/// </summary>
[StringLength(100)]
public string? CouponCode { get; set; }
/// <summary>
/// 优惠券领取记录 ID。
/// </summary>
public Guid? CouponRedemptionId { get; set; }
public CreateCommerceOrderCommand ToCommand()
@@ -37,35 +61,65 @@ public sealed class CreateCommerceOrderDto
}
}
/// <summary>
/// 交易订单查询参数。
/// </summary>
public sealed class CommerceOrderQueryDto
{
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 100)]
public int? Limit { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(32)]
public string? Status { get; set; }
}
/// <summary>
/// 创建交易支付请求 DTO。
/// </summary>
public sealed class CreateCommercePaymentDto
{
/// <summary>
/// 订单号。
/// </summary>
[Required]
[StringLength(100)]
public string OrderNo { get; set; } = string.Empty;
/// <summary>
/// 服务提供方。
/// </summary>
[Required]
[StringLength(50)]
public string Provider { get; set; } = string.Empty;
/// <summary>
/// 方式。
/// </summary>
[Required]
[StringLength(50)]
public string Method { get; set; } = string.Empty;
/// <summary>
/// 微信或支付渠道 openid。
/// </summary>
[StringLength(255)]
public string? OpenId { get; set; }
/// <summary>
/// 支付完成返回地址。
/// </summary>
[StringLength(2048)]
public string? ReturnUrl { get; set; }
/// <summary>
/// 支付取消返回地址。
/// </summary>
[StringLength(2048)]
public string? QuitUrl { get; set; }
@@ -81,11 +135,20 @@ public sealed class CreateCommercePaymentDto
}
}
/// <summary>
/// 交易优惠券查询参数。
/// </summary>
public sealed class CommerceCouponQueryDto
{
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 100)]
public int? Limit { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(32)]
public string? Status { get; set; }
@@ -95,8 +158,14 @@ public sealed class CommerceCouponQueryDto
}
}
/// <summary>
/// 领取交易优惠券请求 DTO。
/// </summary>
public sealed class ClaimCommerceCouponDto
{
/// <summary>
/// 优惠券码。
/// </summary>
[Required]
[StringLength(100)]
public string CouponCode { get; set; } = string.Empty;
@@ -107,19 +176,37 @@ public sealed class ClaimCommerceCouponDto
}
}
/// <summary>
/// 校验交易优惠券请求 DTO。
/// </summary>
public sealed class CheckCommerceCouponDto
{
/// <summary>
/// 优惠券码。
/// </summary>
[StringLength(100)]
public string? CouponCode { get; set; }
/// <summary>
/// 优惠券领取记录 ID。
/// </summary>
public Guid? CouponRedemptionId { get; set; }
/// <summary>
/// 套餐 ID。
/// </summary>
[Required]
public Guid PlanId { get; set; }
/// <summary>
/// 数量。
/// </summary>
[Range(1, 99)]
public int Quantity { get; set; } = 1;
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
public CheckCommerceCouponCommand ToCommand()

View File

@@ -5,132 +5,294 @@ using Tiku.Application.Growth;
namespace Tiku.Api.Contracts;
/// <summary>
/// 保存佣金配置请求。
/// </summary>
public sealed class UpdateCommissionSettingsDto
{
/// <summary>
/// 默认佣金比例。
/// </summary>
[Range(0, 1)]
public decimal? DefaultRate { get; set; }
/// <summary>
/// 最低结算金额,单位为分。
/// </summary>
[Range(0, int.MaxValue)]
public int? MinSettlementCents { get; set; }
/// <summary>
/// 结算周期。
/// </summary>
[StringLength(50)]
public string? SettlementCycle { get; set; }
/// <summary>
/// 配置内容。
/// </summary>
public JsonElement? Config { get; set; }
public UpdateCommissionSettingsCommand ToCommand() => new(DefaultRate, MinSettlementCents, SettlementCycle, Config);
}
/// <summary>
/// 调整成员佣金比例请求。
/// </summary>
public sealed class UpdateMemberCommissionRateDto
{
/// <summary>
/// 用户 ID。
/// </summary>
[Required]
public Guid UserId { get; set; }
/// <summary>
/// 成员佣金比例。
/// </summary>
[Range(0, 1)]
public decimal? CommissionRate { get; set; }
/// <summary>
/// 佣金扩展配置。
/// </summary>
public JsonElement? CommissionConfig { get; set; }
public UpdateMemberCommissionRateCommand ToCommand() => new(UserId, CommissionRate, CommissionConfig);
}
/// <summary>
/// 佣金统计周期查询参数。
/// </summary>
public class CommissionPeriodQueryDto
{
/// <summary>
/// 开始日期,格式为 yyyy-MM-dd。
/// </summary>
[RegularExpression("^\\d{4}-\\d{2}-\\d{2}$")]
public string? StartDate { get; set; }
/// <summary>
/// 结束日期,格式为 yyyy-MM-dd。
/// </summary>
[RegularExpression("^\\d{4}-\\d{2}-\\d{2}$")]
public string? EndDate { get; set; }
/// <summary>
/// 推荐人用户 ID。
/// </summary>
public Guid? ReferrerUserId { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }
public CommissionPeriodQuery ToQuery() => new(ParseDate(StartDate), ParseDate(EndDate), ReferrerUserId, Limit);
protected static DateOnly? ParseDate(string? value) => string.IsNullOrWhiteSpace(value) ? null : DateOnly.ParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture);
}
/// <summary>
/// 佣金结算单查询参数。
/// </summary>
public sealed class CommissionSettlementsQueryDto
{
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 推荐人用户 ID。
/// </summary>
public Guid? ReferrerUserId { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }
public CommissionSettlementQuery ToQuery() => new(Status, ReferrerUserId, Limit);
}
/// <summary>
/// 生成佣金结算单请求 DTO。
/// </summary>
public sealed class GenerateCommissionSettlementDto
{
/// <summary>
/// 开始日期,格式为 yyyy-MM-dd。
/// </summary>
[Required]
[RegularExpression("^\\d{4}-\\d{2}-\\d{2}$")]
public string StartDate { get; set; } = string.Empty;
/// <summary>
/// 结束日期,格式为 yyyy-MM-dd。
/// </summary>
[Required]
[RegularExpression("^\\d{4}-\\d{2}-\\d{2}$")]
public string EndDate { get; set; } = string.Empty;
/// <summary>
/// 推荐人用户 ID。
/// </summary>
[Required]
public Guid ReferrerUserId { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 备注。
/// </summary>
[StringLength(1000)]
public string? Remark { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public GenerateCommissionSettlementCommand ToCommand() => new(Parse(StartDate), Parse(EndDate), ReferrerUserId, Status, Remark, Metadata);
private static DateOnly Parse(string value) => DateOnly.ParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture);
}
/// <summary>
/// 更新佣金结算单状态请求 DTO。
/// </summary>
public sealed class UpdateCommissionSettlementStatusDto
{
/// <summary>
/// 结算单 ID。
/// </summary>
[Required]
public Guid SettlementId { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 审核备注。
/// </summary>
[StringLength(1000)]
public string? ReviewNote { get; set; }
/// <summary>
/// 支付方式。
/// </summary>
[StringLength(100)]
public string? PaymentMethod { get; set; }
/// <summary>
/// 收款账号。
/// </summary>
[StringLength(200)]
public string? PaymentAccount { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public UpdateCommissionSettlementStatusCommand ToCommand() => new(SettlementId, Status, ReviewNote, PaymentMethod, PaymentAccount, Metadata);
}
/// <summary>
/// 佣金结算单导出查询参数。
/// </summary>
public sealed class CommissionSettlementExportQueryDto
{
/// <summary>
/// 结算单 ID。
/// </summary>
[Required]
public Guid SettlementId { get; set; }
/// <summary>
/// 导出格式。
/// </summary>
[StringLength(10)]
public string? Format { get; set; }
}
/// <summary>
/// 佣金结算单凭证查询参数。
/// </summary>
public sealed class CommissionSettlementProofQueryDto
{
/// <summary>
/// 结算单 ID。
/// </summary>
[Required]
public Guid SettlementId { get; set; }
}
/// <summary>
/// 创建佣金结算凭证请求。
/// </summary>
public sealed class CreateCommissionProofDto
{
/// <summary>
/// 结算单 ID。
/// </summary>
[Required]
public Guid SettlementId { get; set; }
/// <summary>
/// 凭证类型。
/// </summary>
[StringLength(50)]
public string? ProofType { get; set; }
/// <summary>
/// 标题。
/// </summary>
[StringLength(200)]
public string? Title { get; set; }
/// <summary>
/// 说明。
/// </summary>
[StringLength(2000)]
public string? Description { get; set; }
/// <summary>
/// 资产 ID。
/// </summary>
public Guid? AssetId { get; set; }
/// <summary>
/// 外部链接。
/// </summary>
[StringLength(2048)]
public string? ExternalUrl { get; set; }
/// <summary>
/// 金额,单位为分。
/// </summary>
[Range(0, int.MaxValue)]
public int? AmountCents { get; set; }
/// <summary>
/// 支付方式。
/// </summary>
[StringLength(100)]
public string? PaymentMethod { get; set; }
/// <summary>
/// 收款账号。
/// </summary>
[StringLength(200)]
public string? PaymentAccount { get; set; }
/// <summary>
/// 支付时间。
/// </summary>
public DateTimeOffset? PaidAt { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public CreateCommissionProofCommand ToCommand() => new(SettlementId, ProofType, Title, Description, AssetId, ExternalUrl, AmountCents, PaymentMethod, PaymentAccount, PaidAt, Metadata);
}
/// <summary>
/// 更新佣金结算凭证状态请求。
/// </summary>
public sealed class UpdateCommissionProofStatusDto
{
/// <summary>
/// 凭证 ID。
/// </summary>
[Required]
public Guid ProofId { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 审核备注。
/// </summary>
[StringLength(1000)]
public string? ReviewNote { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public UpdateCommissionProofStatusCommand ToCommand() => new(ProofId, Status, ReviewNote, Metadata);
}

View File

@@ -7,37 +7,76 @@ using Tiku.Domain.Content;
namespace Tiku.Api.Contracts;
/// <summary>
/// 内容管理查询参数。
/// </summary>
public sealed class ContentManagementQueryDto
{
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 节点 ID。
/// </summary>
public Guid? NodeId { get; set; }
/// <summary>
/// 题集 ID。
/// </summary>
public Guid? CollectionId { get; set; }
/// <summary>
/// 父节点 ID传 root 表示根节点。
/// </summary>
[StringLength(64)]
[RegularExpression("^(root|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$")]
public string? ParentId { get; set; }
/// <summary>
/// 入口类型。
/// </summary>
[StringLength(50)]
public string? EntryType { get; set; }
/// <summary>
/// 题集类型。
/// </summary>
[StringLength(50)]
public string? CollectionType { get; set; }
/// <summary>
/// 模式。
/// </summary>
[StringLength(50)]
public string? Mode { get; set; }
/// <summary>
/// 标记类型。
/// </summary>
[StringLength(50)]
public string? MarkerType { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 是否包含停用数据。
/// </summary>
public bool IncludeInactive { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 1000)]
public int? Limit { get; set; }
@@ -59,43 +98,88 @@ public sealed class ContentManagementQueryDto
}
}
/// <summary>
/// 新增或更新内容条目请求 DTO。
/// </summary>
public sealed class UpsertContentEntryDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
[StringLength(64)]
public string? LegacyId { get; set; }
/// <summary>
/// 入口键。
/// </summary>
[StringLength(100)]
public string? EntryKey { get; set; }
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(300)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 入口类型。
/// </summary>
[StringLength(50)]
public string? EntryType { get; set; }
/// <summary>
/// 图标。
/// </summary>
[StringLength(100)]
public string? Icon { get; set; }
/// <summary>
/// 路由地址。
/// </summary>
[StringLength(500)]
public string? Route { get; set; }
/// <summary>
/// 说明。
/// </summary>
[StringLength(2000)]
public string? Description { get; set; }
/// <summary>
/// 可见性。
/// </summary>
[StringLength(50)]
public string? Visibility { get; set; }
/// <summary>
/// 访问规则。
/// </summary>
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
/// <summary>
/// 布局配置。
/// </summary>
public JsonElement LayoutConfig { get; set; } = JsonDefaults.Object();
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
public UpsertContentEntryCommand ToCommand()
@@ -118,45 +202,96 @@ public sealed class UpsertContentEntryDto
}
}
/// <summary>
/// 新增或更新内容节点请求 DTO。
/// </summary>
public sealed class UpsertContentNodeDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
[Required]
public Guid EntryId { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 父节点 ID。
/// </summary>
public Guid? ParentId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
[StringLength(64)]
public string? LegacyId { get; set; }
/// <summary>
/// 节点键。
/// </summary>
[StringLength(100)]
public string? NodeKey { get; set; }
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(300)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 节点Type。
/// </summary>
[StringLength(50)]
public string? NodeType { get; set; }
/// <summary>
/// 标记类型。
/// </summary>
[StringLength(50)]
public string? MarkerType { get; set; }
/// <summary>
/// 标记配置。
/// </summary>
public JsonElement MarkerConfig { get; set; } = JsonDefaults.Object();
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 是否可选择。
/// </summary>
public bool? IsSelectable { get; set; }
/// <summary>
/// 是否叶子节点。
/// </summary>
public bool? IsLeaf { get; set; }
/// <summary>
/// 访问规则。
/// </summary>
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertContentNodeCommand ToCommand()
@@ -181,48 +316,105 @@ public sealed class UpsertContentNodeDto
}
}
/// <summary>
/// 新增或更新题目题集请求 DTO。
/// </summary>
public sealed class UpsertQuestionCollectionDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 节点 ID。
/// </summary>
public Guid? NodeId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 题库 ID。
/// </summary>
public Guid? QuestionBankId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
[StringLength(64)]
public string? LegacyId { get; set; }
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(300)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 题集类型。
/// </summary>
[StringLength(50)]
public string? CollectionType { get; set; }
/// <summary>
/// 来源类型。
/// </summary>
[StringLength(50)]
public string? SourceType { get; set; }
/// <summary>
/// 筛选条件。
/// </summary>
public JsonElement Filters { get; set; } = JsonDefaults.Object();
/// <summary>
/// 总分。
/// </summary>
public decimal? TotalScore { get; set; }
/// <summary>
/// 时长,单位为分钟。
/// </summary>
public int? DurationMinutes { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 访问规则。
/// </summary>
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertQuestionCollectionCommand ToCommand()
@@ -249,23 +441,47 @@ public sealed class UpsertQuestionCollectionDto
}
}
/// <summary>
/// 题集题目请求 DTO。
/// </summary>
public sealed class CollectionQuestionDto
{
/// <summary>
/// 题目 ID。
/// </summary>
[Required]
public Guid QuestionId { get; set; }
/// <summary>
/// 来源。
/// </summary>
[Required]
public QuestionSource Source { get; set; } = QuestionSource.Tenant;
/// <summary>
/// 分段键。
/// </summary>
[StringLength(100)]
public string? SectionKey { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 分数。
/// </summary>
public decimal? Score { get; set; }
/// <summary>
/// 是否必填。
/// </summary>
public bool? Required { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public CollectionQuestionCommand ToCommand()
@@ -280,11 +496,20 @@ public sealed class CollectionQuestionDto
}
}
/// <summary>
/// 替换题集Items请求 DTO。
/// </summary>
public sealed class ReplaceCollectionItemsDto
{
/// <summary>
/// 题集 ID。
/// </summary>
[Required]
public Guid CollectionId { get; set; }
/// <summary>
/// 题目列表。
/// </summary>
public IReadOnlyCollection<CollectionQuestionDto> Questions { get; set; } = [];
public ReplaceCollectionItemsCommand ToCommand()
@@ -295,48 +520,105 @@ public sealed class ReplaceCollectionItemsDto
}
}
/// <summary>
/// 新增或更新练习Blueprint请求 DTO。
/// </summary>
public sealed class UpsertPracticeBlueprintDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 节点 ID。
/// </summary>
public Guid? NodeId { get; set; }
/// <summary>
/// 题集 ID。
/// </summary>
public Guid? CollectionId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
[StringLength(64)]
public string? LegacyId { get; set; }
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(300)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 模式。
/// </summary>
[StringLength(50)]
public string? Mode { get; set; }
/// <summary>
/// 组卷方式。
/// </summary>
[StringLength(50)]
public string? AssemblyType { get; set; }
/// <summary>
/// 题目数量上限。
/// </summary>
public int? QuestionLimit { get; set; }
/// <summary>
/// 时长,单位为分钟。
/// </summary>
public int? DurationMinutes { get; set; }
/// <summary>
/// 总分。
/// </summary>
public decimal? TotalScore { get; set; }
/// <summary>
/// 及格分。
/// </summary>
public decimal? PassScore { get; set; }
/// <summary>
/// 分段配置。
/// </summary>
public JsonElement Sections { get; set; } = JsonDefaults.Array();
/// <summary>
/// 规则配置。
/// </summary>
public JsonElement Rules { get; set; } = JsonDefaults.Object();
/// <summary>
/// 访问规则。
/// </summary>
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
public UpsertPracticeBlueprintCommand ToCommand()
@@ -363,12 +645,21 @@ public sealed class UpsertPracticeBlueprintDto
}
}
/// <summary>
/// 导入Template查询参数。
/// </summary>
public sealed class ImportTemplateQueryDto
{
/// <summary>
/// 导入Type。
/// </summary>
[Required]
[StringLength(50)]
public string ImportType { get; set; } = string.Empty;
/// <summary>
/// 导出格式。
/// </summary>
[StringLength(10)]
public string? Format { get; set; }
}

View File

@@ -3,42 +3,87 @@ using Tiku.Application.Content;
namespace Tiku.Api.Contracts;
/// <summary>
/// 内容Navigation查询参数。
/// </summary>
public sealed class ContentNavigationQueryDto
{
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 节点 ID。
/// </summary>
public Guid? NodeId { get; set; }
/// <summary>
/// 题集 ID。
/// </summary>
public Guid? CollectionId { get; set; }
/// <summary>
/// 父节点 ID传 root 表示根节点。
/// </summary>
[StringLength(64)]
[RegularExpression("^(root|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$")]
public string? ParentId { get; set; }
/// <summary>
/// 入口类型。
/// </summary>
[StringLength(50)]
public string? EntryType { get; set; }
/// <summary>
/// 题集类型。
/// </summary>
[StringLength(50)]
public string? CollectionType { get; set; }
/// <summary>
/// 模式。
/// </summary>
[StringLength(50)]
public string? Mode { get; set; }
/// <summary>
/// 标记类型。
/// </summary>
[StringLength(50)]
public string? MarkerType { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 是否包含隐藏数据。
/// </summary>
public bool IncludeHidden { get; set; }
/// <summary>
/// 是否包含停用数据。
/// </summary>
public bool IncludeInactive { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 1000)]
public int? Limit { get; set; }

View File

@@ -4,35 +4,71 @@ using Tiku.Application.Growth;
namespace Tiku.Api.Contracts;
/// <summary>
/// 新增或更新CRM配置请求 DTO。
/// </summary>
public sealed class UpsertCrmConfigDto
{
/// <summary>
/// 是否启用。
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// 访问地址。
/// </summary>
[StringLength(2048)]
public string? Url { get; set; }
/// <summary>
/// 密钥引用。
/// </summary>
[StringLength(300)]
public string? SecretRef { get; set; }
/// <summary>
/// 密钥内容。
/// </summary>
public string? Secret { get; set; }
/// <summary>
/// 表单名称。
/// </summary>
[StringLength(200)]
public string? FormName { get; set; }
/// <summary>
/// 考试类型。
/// </summary>
[StringLength(100)]
public string? ExamType { get; set; }
/// <summary>
/// 超时时长,单位为秒。
/// </summary>
[Range(1, 120)]
public int? TimeoutSeconds { get; set; }
/// <summary>
/// 延迟秒数。
/// </summary>
[Range(0, 86400)]
public int? DelaySeconds { get; set; }
/// <summary>
/// 分配模式。
/// </summary>
[StringLength(50)]
public string? AssignmentMode { get; set; }
/// <summary>
/// 分配池。
/// </summary>
public JsonElement? AssignmentPool { get; set; }
/// <summary>
/// 分配配置。
/// </summary>
public JsonElement? AssignmentConfig { get; set; }
public UpsertCrmConfigCommand ToCommand()
@@ -52,16 +88,31 @@ public sealed class UpsertCrmConfigDto
}
}
/// <summary>
/// CRM队列查询参数。
/// </summary>
public sealed class CrmQueueQueryDto
{
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 队列任务 ID。
/// </summary>
public Guid? QueueId { get; set; }
/// <summary>
/// 来源。
/// </summary>
[StringLength(200)]
public string? Source { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }
@@ -71,10 +122,19 @@ public sealed class CrmQueueQueryDto
}
}
/// <summary>
/// CRM队列日志查询参数。
/// </summary>
public sealed class CrmQueueLogQueryDto
{
/// <summary>
/// 队列任务 ID。
/// </summary>
public Guid? QueueId { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 200)]
public int? Limit { get; set; }
@@ -84,17 +144,32 @@ public sealed class CrmQueueLogQueryDto
}
}
/// <summary>
/// CRM队列Action请求 DTO。
/// </summary>
public sealed class CrmQueueActionDto
{
/// <summary>
/// 队列任务 ID。
/// </summary>
[Required]
public Guid QueueId { get; set; }
/// <summary>
/// 操作。
/// </summary>
[StringLength(50)]
public string? Action { get; set; }
/// <summary>
/// 备注。
/// </summary>
[StringLength(500)]
public string? Note { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public CrmQueueActionCommand ToCommand()

View File

@@ -5,28 +5,73 @@ using Tiku.Domain.Common;
namespace Tiku.Api.Contracts;
/// <summary>
/// 管理侧内容查询参数。
/// </summary>
public sealed class DirectContentQueryDto
{
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 父节点 ID。
/// </summary>
public Guid? ParentId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 章节 ID。
/// </summary>
public Guid? ChapterId { get; set; }
/// <summary>
/// 单元 ID。
/// </summary>
public Guid? UnitId { get; set; }
/// <summary>
/// 院校 ID。
/// </summary>
public Guid? SchoolId { get; set; }
/// <summary>
/// 专业 ID。
/// </summary>
public Guid? MajorId { get; set; }
/// <summary>
/// 题目 ID。
/// </summary>
public Guid? QuestionId { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(200)]
public string? Keyword { get; set; }
/// <summary>
/// 年份。
/// </summary>
[Range(1900, 3000)]
public int? Year { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 1000)]
public int? Limit { get; set; }
@@ -50,37 +95,121 @@ public sealed class DirectContentQueryDto
}
}
/// <summary>
/// 管理侧题目写入请求。
/// </summary>
public sealed class DirectQuestionWriteDto
{
/// <summary>
/// 题目 ID。
/// </summary>
public Guid? QuestionId { get; set; }
/// <summary>
/// 题库 ID。
/// </summary>
public Guid? QuestionBankId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 节点 ID。
/// </summary>
public Guid? NodeId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 主题集 ID。
/// </summary>
public Guid? PrimaryCollectionId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 类型。
/// </summary>
public string? Type { get; set; }
/// <summary>
/// 类型显示名。
/// </summary>
public string? TypeLabel { get; set; }
/// <summary>
/// 难度。
/// </summary>
[Range(1, 5)]
public int? Difficulty { get; set; }
/// <summary>
/// 标签列表。
/// </summary>
public JsonElement Tags { get; set; } = JsonDefaults.Array();
/// <summary>
/// 内容。
/// </summary>
public string? Content { get; set; }
/// <summary>
/// 选项配置。
/// </summary>
public JsonElement Options { get; set; } = JsonDefaults.Array();
/// <summary>
/// 正确选项索引。
/// </summary>
public int? CorrectOptionIndex { get; set; }
/// <summary>
/// 正确选项索引列表。
/// </summary>
public JsonElement CorrectOptionIndices { get; set; } = JsonDefaults.Array();
/// <summary>
/// 文字答案。
/// </summary>
public string? AnswerText { get; set; }
/// <summary>
/// 解析。
/// </summary>
public string? Explanation { get; set; }
/// <summary>
/// 子题列表。
/// </summary>
public JsonElement SubQuestions { get; set; } = JsonDefaults.Array();
/// <summary>
/// 代码语言。
/// </summary>
public string? CodeLang { get; set; }
/// <summary>
/// 代码模板。
/// </summary>
public string? CodeTemplate { get; set; }
/// <summary>
/// 媒体地址。
/// </summary>
public string? MediaUrl { get; set; }
/// <summary>
/// 状态。
/// </summary>
public string? Status { get; set; }
/// <summary>
/// 考试标记配置。
/// </summary>
public JsonElement ExamMarkers { get; set; } = JsonDefaults.Object();
/// <summary>
/// 来源哈希。
/// </summary>
public string? SourceHash { get; set; }
/// <summary>
/// 是否创建题目版本。
/// </summary>
public bool? CreateVersion { get; set; }
public QuestionWriteCommand ToCommand(bool createVersionDefault)
@@ -116,18 +245,54 @@ public sealed class DirectQuestionWriteDto
}
}
/// <summary>
/// 管理侧词汇单元写入请求。
/// </summary>
public sealed class DirectVocabularyUnitDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 名称。
/// </summary>
public required string Name { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 单词数量。
/// </summary>
public int? WordCount { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public VocabularyUnitCommand ToCommand()
@@ -136,22 +301,70 @@ public sealed class DirectVocabularyUnitDto
}
}
/// <summary>
/// 管理侧词汇单词写入请求。
/// </summary>
public sealed class DirectVocabularyWordDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 单元 ID。
/// </summary>
public Guid? UnitId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 单词。
/// </summary>
public required string Word { get; set; }
/// <summary>
/// 音标。
/// </summary>
public string? Phonetic { get; set; }
/// <summary>
/// 释义。
/// </summary>
public string? Meaning { get; set; }
/// <summary>
/// 例句。
/// </summary>
public string? Example { get; set; }
/// <summary>
/// 例句翻译。
/// </summary>
public string? ExampleTranslation { get; set; }
/// <summary>
/// 难度。
/// </summary>
public int? Difficulty { get; set; }
/// <summary>
/// 标签列表。
/// </summary>
public JsonElement Tags { get; set; } = JsonDefaults.Array();
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public VocabularyWordCommand ToCommand()
@@ -175,22 +388,70 @@ public sealed class DirectVocabularyWordDto
}
}
/// <summary>
/// 管理侧知识手册科目写入请求。
/// </summary>
public sealed class DirectHandbookSubjectDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 院校 ID。
/// </summary>
public Guid? SchoolId { get; set; }
/// <summary>
/// 专业 ID。
/// </summary>
public Guid? MajorId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 名称。
/// </summary>
public required string Name { get; set; }
/// <summary>
/// 类型。
/// </summary>
public string? Type { get; set; }
/// <summary>
/// 图标。
/// </summary>
public string? Icon { get; set; }
/// <summary>
/// 颜色。
/// </summary>
public string? Color { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public HandbookSubjectCommand ToCommand()
@@ -214,17 +475,50 @@ public sealed class DirectHandbookSubjectDto
}
}
/// <summary>
/// 管理侧知识手册章节写入请求。
/// </summary>
public sealed class DirectHandbookChapterDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 名称。
/// </summary>
public required string Name { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public HandbookChapterCommand ToCommand()
@@ -233,19 +527,58 @@ public sealed class DirectHandbookChapterDto
}
}
/// <summary>
/// 管理侧知识手册条目写入请求。
/// </summary>
public sealed class DirectHandbookEntryDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 章节 ID。
/// </summary>
public Guid? ChapterId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 标题。
/// </summary>
public required string Title { get; set; }
/// <summary>
/// 摘要。
/// </summary>
public string? Summary { get; set; }
/// <summary>
/// 内容。
/// </summary>
public string? Content { get; set; }
/// <summary>
/// 标签列表。
/// </summary>
public JsonElement Tags { get; set; } = JsonDefaults.Array();
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public HandbookEntryCommand ToCommand()
@@ -254,13 +587,34 @@ public sealed class DirectHandbookEntryDto
}
}
/// <summary>
/// 管理侧院校写入请求。
/// </summary>
public sealed class DirectSchoolDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 名称。
/// </summary>
public required string Name { get; set; }
/// <summary>
/// 专业考试日期。
/// </summary>
public string? ProfessionalExamDate { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public SchoolCommand ToCommand()
@@ -269,16 +623,46 @@ public sealed class DirectSchoolDto
}
}
/// <summary>
/// 管理侧专业写入请求。
/// </summary>
public sealed class DirectMajorDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 院校 ID。
/// </summary>
public Guid? SchoolId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 名称。
/// </summary>
public required string Name { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 备考建议。
/// </summary>
public string? StudyTips { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
public MajorCommand ToCommand()
@@ -287,22 +671,70 @@ public sealed class DirectMajorDto
}
}
/// <summary>
/// 管理侧分数线字段写入请求。
/// </summary>
public sealed class DirectScorelineFieldDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 字段键。
/// </summary>
public required string FieldKey { get; set; }
/// <summary>
/// 字段名称。
/// </summary>
public required string FieldName { get; set; }
/// <summary>
/// 字段类型。
/// </summary>
public string? FieldType { get; set; }
/// <summary>
/// 单位。
/// </summary>
public string? Unit { get; set; }
/// <summary>
/// 是否可筛选。
/// </summary>
public bool? IsFilter { get; set; }
/// <summary>
/// 是否必填。
/// </summary>
public bool? IsRequired { get; set; }
/// <summary>
/// 是否可见。
/// </summary>
public bool? IsVisible { get; set; }
/// <summary>
/// 是否参与趋势展示。
/// </summary>
public bool? IsTrend { get; set; }
/// <summary>
/// 选项配置。
/// </summary>
public JsonElement Options { get; set; } = JsonDefaults.Array();
/// <summary>
/// 占位提示。
/// </summary>
public string? Placeholder { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
public ScorelineFieldCommand ToCommand()
@@ -326,19 +758,49 @@ public sealed class DirectScorelineFieldDto
}
}
/// <summary>
/// 管理侧分数线记录写入请求。
/// </summary>
public sealed class DirectScorelineRecordDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 院校 ID。
/// </summary>
public Guid? SchoolId { get; set; }
/// <summary>
/// 专业 ID。
/// </summary>
public Guid? MajorId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 年份。
/// </summary>
[Range(1900, 3000)]
public int Year { get; set; }
/// <summary>
/// 院校名称。
/// </summary>
public string? SchoolName { get; set; }
/// <summary>
/// 专业名称。
/// </summary>
public string? MajorName { get; set; }
/// <summary>
/// 动态字段值。
/// </summary>
public JsonElement FieldValues { get; set; } = JsonDefaults.Object();
public ScorelineRecordCommand ToCommand()
@@ -356,21 +818,66 @@ public sealed class DirectScorelineRecordDto
}
}
/// <summary>
/// 管理侧视频写入请求。
/// </summary>
public sealed class DirectVideoDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 标题。
/// </summary>
public required string Title { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 视频地址。
/// </summary>
public string? VideoUrl { get; set; }
/// <summary>
/// 缩略图地址。
/// </summary>
public string? ThumbnailUrl { get; set; }
/// <summary>
/// 时长,单位为秒。
/// </summary>
public int? DurationSeconds { get; set; }
/// <summary>
/// 知识标签。
/// </summary>
public JsonElement KnowledgeTags { get; set; } = JsonDefaults.Array();
/// <summary>
/// 是否通用视频。
/// </summary>
public bool? IsGeneral { get; set; }
/// <summary>
/// 难度。
/// </summary>
public int? Difficulty { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public VideoExplanationCommand ToCommand()
@@ -393,13 +900,34 @@ public sealed class DirectVideoDto
}
}
/// <summary>
/// 管理侧题目视频绑定请求。
/// </summary>
public sealed class DirectQuestionVideoDto
{
/// <summary>
/// 题目 ID。
/// </summary>
public Guid QuestionId { get; set; }
/// <summary>
/// 视频 ID。
/// </summary>
public Guid VideoId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 视频类型。
/// </summary>
public string? VideoType { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public QuestionVideoCommand ToCommand()
@@ -408,28 +936,94 @@ public sealed class DirectQuestionVideoDto
}
}
/// <summary>
/// 管理侧运营内容写入请求。
/// </summary>
public sealed class DirectOperationContentDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 院校 ID。
/// </summary>
public Guid? SchoolId { get; set; }
/// <summary>
/// 历史系统 ID。
/// </summary>
public string? LegacyId { get; set; }
/// <summary>
/// 标题。
/// </summary>
public string? Title { get; set; }
/// <summary>
/// 副标题。
/// </summary>
public string? Subtitle { get; set; }
/// <summary>
/// 内容。
/// </summary>
public string? Content { get; set; }
/// <summary>
/// 问题。
/// </summary>
public string? Question { get; set; }
/// <summary>
/// 答案。
/// </summary>
public string? Answer { get; set; }
/// <summary>
/// 链接地址。
/// </summary>
public string? Link { get; set; }
/// <summary>
/// 按钮文案。
/// </summary>
public string? ButtonText { get; set; }
/// <summary>
/// 按钮链接。
/// </summary>
public string? ButtonLink { get; set; }
/// <summary>
/// 背景颜色。
/// </summary>
public string? BackgroundColor { get; set; }
/// <summary>
/// 边框颜色。
/// </summary>
public string? BorderColor { get; set; }
/// <summary>
/// 考试名称。
/// </summary>
public string? ExamName { get; set; }
/// <summary>
/// 考试时间。
/// </summary>
public DateTimeOffset? ExamAt { get; set; }
/// <summary>
/// 考试类型。
/// </summary>
public string? ExamType { get; set; }
/// <summary>
/// 说明。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 显示顺序。
/// </summary>
public int? Order { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool? IsActive { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public OperationContentCommand ToCommand()
@@ -459,27 +1053,90 @@ public sealed class DirectOperationContentDto
}
}
/// <summary>
/// 管理侧内容导入请求。
/// </summary>
public sealed class DirectImportDto
{
/// <summary>
/// 来源格式。
/// </summary>
public string? SourceFormat { get; set; }
/// <summary>
/// 来源名称。
/// </summary>
public string? SourceName { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 题库 ID。
/// </summary>
public Guid? QuestionBankId { get; set; }
/// <summary>
/// 题集 ID。
/// </summary>
public Guid? CollectionId { get; set; }
/// <summary>
/// 是否异步执行。
/// </summary>
public bool? Async { get; set; }
/// <summary>
/// 数据项列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Items { get; set; }
/// <summary>
/// 单元数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Units { get; set; }
/// <summary>
/// 单词数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Words { get; set; }
/// <summary>
/// 科目数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Subjects { get; set; }
/// <summary>
/// 条目数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Entries { get; set; }
/// <summary>
/// 字段数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Fields { get; set; }
/// <summary>
/// 院校数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Schools { get; set; }
/// <summary>
/// 专业数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Majors { get; set; }
/// <summary>
/// 记录数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Records { get; set; }
/// <summary>
/// 视频数据列表。
/// </summary>
public IReadOnlyCollection<JsonElement>? Videos { get; set; }
public SimpleImportCommand ToCommand(string importType, bool dryRun)
@@ -513,7 +1170,13 @@ public sealed class DirectImportDto
}
}
/// <summary>
/// 管理侧内容导入任务查询请求。
/// </summary>
public sealed class DirectImportJobDto
{
/// <summary>
/// 任务 ID。
/// </summary>
public Guid JobId { get; set; }
}

View File

@@ -6,6 +6,9 @@ namespace Tiku.Api.Contracts;
/// <param name="Status">服务状态,例如 ok。</param>
/// <param name="Service">服务名称。</param>
/// <param name="CheckedAt">检查时间。</param>
/// <summary>
/// 健康检查Response请求 DTO。
/// </summary>
public sealed record HealthResponseDto(
string Status,
string Service,

View File

@@ -7,14 +7,26 @@ using Tiku.Domain.Content;
namespace Tiku.Api.Contracts;
/// <summary>
/// 学习Limit查询参数。
/// </summary>
public sealed class LearningLimitQueryDto
{
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 单元 ID。
/// </summary>
public Guid? UnitId { get; set; }
public LearningLimitFilter ToFilter()
@@ -23,18 +35,36 @@ public sealed class LearningLimitQueryDto
}
}
/// <summary>
/// 练习会话查询参数。
/// </summary>
public sealed class PracticeSessionQueryDto
{
/// <summary>
/// 练习会话 ID。
/// </summary>
public Guid? PracticeSessionId { get; set; }
/// <summary>
/// 练习蓝图 ID。
/// </summary>
public Guid? BlueprintId { get; set; }
/// <summary>
/// 模式。
/// </summary>
[StringLength(50)]
public string? Mode { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 200)]
public int? Limit { get; set; }
@@ -49,33 +79,69 @@ public sealed class PracticeSessionQueryDto
}
}
/// <summary>
/// 创建练习会话请求 DTO。
/// </summary>
public sealed class CreatePracticeSessionDto
{
/// <summary>
/// 模式。
/// </summary>
[StringLength(50)]
public string? Mode { get; set; }
/// <summary>
/// 目标类型。
/// </summary>
[StringLength(50)]
public string? TargetType { get; set; }
/// <summary>
/// 目标 ID。
/// </summary>
public Guid? TargetId { get; set; }
/// <summary>
/// 练习蓝图 ID。
/// </summary>
public Guid? BlueprintId { get; set; }
/// <summary>
/// 题集 ID。
/// </summary>
public Guid? CollectionId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 题目数量上限。
/// </summary>
[Range(1, 500)]
public int? QuestionLimit { get; set; }
/// <summary>
/// 时长,单位为分钟。
/// </summary>
[Range(1, 1440)]
public int? DurationMinutes { get; set; }
/// <summary>
/// 总分。
/// </summary>
[Range(typeof(decimal), "0", "99999")]
public decimal? TotalScore { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public PracticeSessionCommand ToCommand()
@@ -95,8 +161,14 @@ public sealed class CreatePracticeSessionDto
}
}
/// <summary>
/// 提交练习会话请求 DTO。
/// </summary>
public sealed class SubmitPracticeSessionDto
{
/// <summary>
/// 练习会话 ID。
/// </summary>
[Required]
public Guid PracticeSessionId { get; set; }
@@ -106,16 +178,31 @@ public sealed class SubmitPracticeSessionDto
}
}
/// <summary>
/// 提交答案请求 DTO。
/// </summary>
public sealed class SubmitAnswerDto
{
/// <summary>
/// 会话题目 ID。
/// </summary>
[Required]
public Guid SessionQuestionId { get; set; }
/// <summary>
/// 已选选项。
/// </summary>
public IReadOnlyCollection<string>? SelectedOptions { get; set; }
/// <summary>
/// 文字答案。
/// </summary>
[StringLength(10000)]
public string? AnswerText { get; set; }
/// <summary>
/// 主观题自评是否正确。
/// </summary>
public bool? SelfJudgedCorrect { get; set; }
public SubmitAnswerCommand ToCommand()
@@ -128,14 +215,26 @@ public sealed class SubmitAnswerDto
}
}
/// <summary>
/// 题目Action请求 DTO。
/// </summary>
public sealed class QuestionActionDto
{
/// <summary>
/// 题目 ID。
/// </summary>
[Required]
public Guid QuestionId { get; set; }
/// <summary>
/// 来源。
/// </summary>
[Required]
public QuestionSource Source { get; set; } = QuestionSource.Tenant;
/// <summary>
/// 是否收藏。
/// </summary>
public bool? Favorite { get; set; }
public QuestionActionCommand ToCommand()
@@ -144,20 +243,38 @@ public sealed class QuestionActionDto
}
}
/// <summary>
/// 单词Progress请求 DTO。
/// </summary>
public sealed class WordProgressDto
{
/// <summary>
/// 单词 ID。
/// </summary>
[Required]
public Guid WordId { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 答对数量变化。
/// </summary>
[Range(0, 100)]
public int? CorrectDelta { get; set; }
/// <summary>
/// 答错数量变化。
/// </summary>
[Range(0, 100)]
public int? WrongDelta { get; set; }
/// <summary>
/// 下次复习时间。
/// </summary>
public DateTimeOffset? NextReviewAt { get; set; }
public WordProgressCommand ToCommand()
@@ -171,13 +288,25 @@ public sealed class WordProgressDto
}
}
/// <summary>
/// 收藏单词请求 DTO。
/// </summary>
public sealed class FavoriteWordDto
{
/// <summary>
/// 单词 ID。
/// </summary>
[Required]
public Guid WordId { get; set; }
/// <summary>
/// 是否收藏。
/// </summary>
public bool? Favorite { get; set; }
/// <summary>
/// 备注。
/// </summary>
[StringLength(1000)]
public string? Note { get; set; }
@@ -187,14 +316,26 @@ public sealed class FavoriteWordDto
}
}
/// <summary>
/// 单词Review请求 DTO。
/// </summary>
public sealed class WordReviewDto
{
/// <summary>
/// 单词 ID。
/// </summary>
[Required]
public Guid WordId { get; set; }
/// <summary>
/// 结果。
/// </summary>
[StringLength(50)]
public string? Result { get; set; }
/// <summary>
/// 下次复习时间。
/// </summary>
public DateTimeOffset? NextReviewAt { get; set; }
public WordReviewCommand ToCommand()

View File

@@ -9,88 +9,201 @@ using Tiku.Domain.Tenancy;
namespace Tiku.Api.Contracts;
/// <summary>
/// 平台管理端查询参数。
/// </summary>
public sealed class PlatformAdminQueryDto
{
/// <summary>
/// 状态。
/// </summary>
[StringLength(32)]
public string? Status { get; set; }
/// <summary>
/// 搜索关键字。
/// </summary>
[StringLength(200)]
public string? Search { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 200)]
public int? Limit { get; set; }
public PlatformAdminQuery ToQuery() => new(Status, Search, Limit);
}
/// <summary>
/// 创建平台租户请求 DTO。
/// </summary>
public sealed class CreatePlatformTenantDto
{
/// <summary>
/// 短编码。
/// </summary>
[Required]
[StringLength(100)]
public string Slug { get; set; } = string.Empty;
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(200)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 法定名称。
/// </summary>
[StringLength(300)]
public string? LegalName { get; set; }
/// <summary>
/// 状态。
/// </summary>
public TenantStatus Status { get; set; } = TenantStatus.Active;
/// <summary>
/// 账务状态。
/// </summary>
public BillingStatus BillingStatus { get; set; } = BillingStatus.Trial;
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public CreatePlatformTenantCommand ToCommand() => new(Slug, Name, LegalName, Status, BillingStatus, Metadata);
/// <summary>
/// 租户负责人邮箱。
/// </summary>
[EmailAddress, StringLength(320)]
public string? OwnerEmail { get; set; }
/// <summary>
/// 租户负责人手机号。
/// </summary>
[Phone, StringLength(32)]
public string? OwnerPhone { get; set; }
/// <summary>
/// 租户负责人姓名。
/// </summary>
[Required, StringLength(100)]
public string OwnerName { get; set; } = string.Empty;
/// <summary>
/// 临时密码。
/// </summary>
[Required, StringLength(200, MinimumLength = 12)]
public string TemporaryPassword { get; set; } = string.Empty;
public CreatePlatformTenantCommand ToCommand() => new(
Slug, Name, LegalName, Status, BillingStatus, Metadata,
OwnerEmail, OwnerPhone, OwnerName, TemporaryPassword);
}
/// <summary>
/// 更新平台租户状态请求 DTO。
/// </summary>
public sealed class UpdatePlatformTenantStatusDto
{
/// <summary>
/// 租户 ID。
/// </summary>
[Required]
public Guid TenantId { get; set; }
/// <summary>
/// 状态。
/// </summary>
public TenantStatus Status { get; set; } = TenantStatus.Active;
/// <summary>
/// 账务状态。
/// </summary>
public BillingStatus BillingStatus { get; set; } = BillingStatus.Active;
/// <summary>
/// 原因。
/// </summary>
[StringLength(1000)]
public string? Reason { get; set; }
public UpdatePlatformTenantStatusCommand ToCommand() => new(TenantId, Status, BillingStatus, Reason);
}
/// <summary>
/// 新增或更新平台租户账务资料请求 DTO。
/// </summary>
public sealed class UpsertPlatformTenantBillingProfileDto
{
/// <summary>
/// 租户 ID。
/// </summary>
[Required]
public Guid TenantId { get; set; }
/// <summary>
/// 账务名称。
/// </summary>
[StringLength(300)]
public string? BillingName { get; set; }
/// <summary>
/// 税号。
/// </summary>
[StringLength(100)]
public string? TaxId { get; set; }
/// <summary>
/// 联系人姓名。
/// </summary>
[StringLength(100)]
public string? ContactName { get; set; }
/// <summary>
/// 联系人手机号。
/// </summary>
[StringLength(32)]
public string? ContactPhone { get; set; }
/// <summary>
/// 联系人邮箱。
/// </summary>
[StringLength(320)]
public string? ContactEmail { get; set; }
/// <summary>
/// 账务地址。
/// </summary>
[StringLength(1000)]
public string? BillingAddress { get; set; }
/// <summary>
/// 发票抬头。
/// </summary>
[StringLength(300)]
public string? InvoiceTitle { get; set; }
public TenantInvoiceTitleType? InvoiceType { get; set; }
/// <summary>
/// 发票类型。
/// </summary>
public TenantBillingInvoiceTitleType? InvoiceType { get; set; }
/// <summary>
/// 开户银行。
/// </summary>
[StringLength(300)]
public string? BankName { get; set; }
/// <summary>
/// 脱敏银行账号。
/// </summary>
[StringLength(100)]
public string? BankAccountMasked { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertPlatformTenantBillingProfileCommand ToCommand() => new(
@@ -108,143 +221,180 @@ public sealed class UpsertPlatformTenantBillingProfileDto
Metadata);
}
public sealed class UpsertPlatformSubscriptionDto
{
[Required]
public Guid TenantId { get; set; }
[Required]
[StringLength(100)]
public string PlanCode { get; set; } = string.Empty;
public TenantSubscriptionStatus Status { get; set; } = TenantSubscriptionStatus.Active;
public DateTimeOffset? StartsAt { get; set; }
public DateTimeOffset? ExpiresAt { get; set; }
[StringLength(32)]
public string? BillingCycle { get; set; }
[Range(0, int.MaxValue)]
public int AmountCents { get; set; }
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertPlatformSubscriptionCommand ToCommand() => new(
TenantId,
PlanCode,
Status,
StartsAt,
ExpiresAt,
BillingCycle,
AmountCents,
Metadata);
}
public sealed class ReplacePlatformPlanModulesDto
{
[Required]
public IReadOnlyCollection<string> ModuleCodes { get; set; } = [];
public ReplacePlatformPlanModulesCommand ToCommand(string planCode) => new(planCode, ModuleCodes);
}
public sealed class UpsertPlatformTenantModuleOverrideDto
{
public TenantModuleOverrideMode Mode { get; set; }
public DateTimeOffset? ExpiresAt { get; set; }
[Required]
[StringLength(1000, MinimumLength = 1)]
public string Reason { get; set; } = string.Empty;
public UpsertPlatformTenantModuleOverrideCommand ToCommand(Guid tenantId, string moduleCode) =>
new(tenantId, moduleCode, Mode, ExpiresAt, Reason);
}
/// <summary>
/// 新增或更新平台Staff请求 DTO。
/// </summary>
public sealed class UpsertPlatformStaffDto
{
/// <summary>
/// 用户 ID。
/// </summary>
public Guid? UserId { get; set; }
/// <summary>
/// 邮箱。
/// </summary>
[StringLength(320)]
public string? Email { get; set; }
/// <summary>
/// 手机号。
/// </summary>
[StringLength(32)]
public string? Phone { get; set; }
/// <summary>
/// 名称。
/// </summary>
[StringLength(200)]
public string? Name { get; set; }
/// <summary>
/// 状态。
/// </summary>
public UserStatus Status { get; set; } = UserStatus.Active;
/// <summary>
/// 角色 ID 列表。
/// </summary>
public IReadOnlyCollection<Guid> RoleIds { get; set; } = [];
public UpsertPlatformStaffCommand ToCommand() => new(UserId, Email, Phone, Name, Status, RoleIds);
}
/// <summary>
/// 更新平台Staff状态请求 DTO。
/// </summary>
public sealed class UpdatePlatformStaffStatusDto
{
/// <summary>
/// 用户 ID。
/// </summary>
[Required]
public Guid UserId { get; set; }
/// <summary>
/// 状态。
/// </summary>
public UserStatus Status { get; set; } = UserStatus.Active;
/// <summary>
/// 原因。
/// </summary>
[StringLength(1000)]
public string? Reason { get; set; }
public UpdatePlatformStaffStatusCommand ToCommand() => new(UserId, Status, Reason);
}
/// <summary>
/// 更新平台审计Alert状态请求 DTO。
/// </summary>
public sealed class UpdatePlatformAuditAlertStatusDto
{
/// <summary>
/// 告警 ID。
/// </summary>
[Required]
public Guid AlertId { get; set; }
/// <summary>
/// 状态。
/// </summary>
public PlatformAuditAlertStatus Status { get; set; } = PlatformAuditAlertStatus.Acknowledged;
/// <summary>
/// 处理备注。
/// </summary>
[StringLength(1000)]
public string? ResolutionNote { get; set; }
public UpdatePlatformAuditAlertStatusCommand ToCommand() => new(AlertId, Status, ResolutionNote);
}
public sealed class UpsertPlatformDunningChannelDto
/// <summary>
/// 新增或更新平台DunningChannel请求 DTO。
/// </summary>
public sealed class UpsertPlatformBillingDunningChannelDto
{
/// <summary>
/// 通知渠道 ID。
/// </summary>
public Guid? ChannelId { get; set; }
/// <summary>
/// 渠道编码。
/// </summary>
[Required]
[StringLength(100)]
public string ChannelCode { get; set; } = string.Empty;
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(200)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 说明。
/// </summary>
[StringLength(1000)]
public string? Description { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool Enabled { get; set; } = true;
public PlatformDunningProvider Provider { get; set; } = PlatformDunningProvider.Generic;
/// <summary>
/// 服务提供方。
/// </summary>
public PlatformBillingDunningProvider Provider { get; set; } = PlatformBillingDunningProvider.Generic;
/// <summary>
/// Webhook 地址。
/// </summary>
[Required]
[StringLength(2048)]
public string WebhookUrl { get; set; } = string.Empty;
/// <summary>
/// 密钥引用。
/// </summary>
[StringLength(300)]
public string? SecretRef { get; set; }
/// <summary>
/// 提醒类型列表。
/// </summary>
public IReadOnlyCollection<string> ReminderTypes { get; set; } = ["overdue", "final_notice"];
/// <summary>
/// 提醒渠道列表。
/// </summary>
public IReadOnlyCollection<string> ReminderChannels { get; set; } = ["internal"];
/// <summary>
/// 最低提醒级别。
/// </summary>
[Range(1, 20)]
public int MinReminderLevel { get; set; } = 1;
/// <summary>
/// 租户 ID 列表。
/// </summary>
public IReadOnlyCollection<Guid> TenantIds { get; set; } = [];
/// <summary>
/// 超时时长,单位为秒。
/// </summary>
[Range(1, 60)]
public int TimeoutSeconds { get; set; } = 10;
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertPlatformDunningChannelCommand ToCommand() => new(
public UpsertPlatformBillingDunningChannelCommand ToCommand() => new(
ChannelId,
ChannelCode,
Name,
@@ -261,24 +411,42 @@ public sealed class UpsertPlatformDunningChannelDto
Metadata);
}
public sealed class DisablePlatformDunningChannelDto
/// <summary>
/// 禁用平台DunningChannel请求 DTO。
/// </summary>
public sealed class DisablePlatformBillingDunningChannelDto
{
/// <summary>
/// 通知渠道 ID。
/// </summary>
[Required]
public Guid ChannelId { get; set; }
/// <summary>
/// 原因。
/// </summary>
[StringLength(1000)]
public string? Reason { get; set; }
public DisablePlatformDunningChannelCommand ToCommand() => new(ChannelId, Reason);
public DisablePlatformBillingDunningChannelCommand ToCommand() => new(ChannelId, Reason);
}
public sealed class RetryPlatformDunningEventDto
/// <summary>
/// 重试平台Dunning事件请求 DTO。
/// </summary>
public sealed class RetryPlatformBillingDunningEventDto
{
/// <summary>
/// 事件 ID。
/// </summary>
[Required]
public Guid EventId { get; set; }
/// <summary>
/// 原因。
/// </summary>
[StringLength(1000)]
public string? Reason { get; set; }
public RetryPlatformDunningEventCommand ToCommand() => new(EventId, Reason);
public RetryPlatformBillingDunningEventCommand ToCommand() => new(EventId, Reason);
}

View File

@@ -3,14 +3,26 @@ using Tiku.Application.Points;
namespace Tiku.Api.Contracts;
/// <summary>
/// 积分查询参数。
/// </summary>
public sealed class PointQueryDto
{
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 200)]
public int? Limit { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(32)]
public string? Status { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
public PointLimitQuery ToQuery()
@@ -19,15 +31,27 @@ public sealed class PointQueryDto
}
}
/// <summary>
/// 领取积分任务请求 DTO。
/// </summary>
public sealed class ClaimPointTaskDto
{
/// <summary>
/// 任务键。
/// </summary>
[Required]
[StringLength(100)]
public string TaskKey { get; set; } = string.Empty;
/// <summary>
/// 来源类型。
/// </summary>
[StringLength(100)]
public string? SourceType { get; set; }
/// <summary>
/// 来源 ID。
/// </summary>
public Guid? SourceId { get; set; }
public ClaimPointTaskCommand ToCommand()
@@ -36,8 +60,14 @@ public sealed class ClaimPointTaskDto
}
}
/// <summary>
/// 创建积分兑换订单请求 DTO。
/// </summary>
public sealed class CreatePointExchangeOrderDto
{
/// <summary>
/// 兑换项 ID。
/// </summary>
[Required]
public Guid ItemId { get; set; }

View File

@@ -4,47 +4,107 @@ using Tiku.Application.Profile;
namespace Tiku.Api.Contracts;
/// <summary>
/// 资料查询参数。
/// </summary>
public sealed class ProfileQueryDto
{
/// <summary>
/// 最近记录数量上限。
/// </summary>
[Range(1, 50)]
public int? RecentLimit { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 20)]
public int? Limit { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(32)]
public string? Status { get; set; }
/// <summary>
/// 类型。
/// </summary>
[StringLength(50)]
public string? Type { get; set; }
/// <summary>
/// 分类。
/// </summary>
[StringLength(50)]
public string? Category { get; set; }
/// <summary>
/// 是否包含锁定资源。
/// </summary>
public bool IncludeLocked { get; set; }
/// <summary>
/// 来源类型。
/// </summary>
[StringLength(100)]
public string? SourceType { get; set; }
/// <summary>
/// 开始时间。
/// </summary>
public DateTimeOffset? From { get; set; }
/// <summary>
/// 结束时间。
/// </summary>
public DateTimeOffset? To { get; set; }
}
/// <summary>
/// 更新资料请求 DTO。
/// </summary>
public sealed class UpdateProfileDto
{
/// <summary>
/// 名称。
/// </summary>
[StringLength(100)]
public string? Name { get; set; }
/// <summary>
/// 头像预设。
/// </summary>
[StringLength(32)]
public string? AvatarPreset { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 已选择院校 ID。
/// </summary>
public Guid? SelectedSchoolId { get; set; }
/// <summary>
/// 已选择专业 ID。
/// </summary>
public Guid? SelectedMajorId { get; set; }
/// <summary>
/// 统计数据。
/// </summary>
public JsonElement? Stats { get; set; }
/// <summary>
/// 进度数据。
/// </summary>
public JsonElement? Progress { get; set; }
/// <summary>
/// 模块选择数据。
/// </summary>
public JsonElement? ModuleSelections { get; set; }
/// <summary>
/// 最近活动数据。
/// </summary>
public JsonElement? RecentActivities { get; set; }
public UpdateProfileCommand ToCommand()
@@ -62,13 +122,22 @@ public sealed class UpdateProfileDto
}
}
/// <summary>
/// 通知状态请求 DTO。
/// </summary>
public sealed class NotificationStatusDto
{
/// <summary>
/// 通知 ID 列表。
/// </summary>
[Required]
[MinLength(1)]
[MaxLength(100)]
public IReadOnlyCollection<Guid> NotificationIds { get; set; } = [];
/// <summary>
/// 状态。
/// </summary>
[StringLength(32)]
public string? Status { get; set; }
@@ -78,30 +147,60 @@ public sealed class NotificationStatusDto
}
}
/// <summary>
/// 提交反馈请求 DTO。
/// </summary>
public sealed class SubmitFeedbackDto
{
/// <summary>
/// 题目 ID。
/// </summary>
public Guid? QuestionId { get; set; }
/// <summary>
/// 类型。
/// </summary>
[StringLength(50)]
public string? Type { get; set; }
/// <summary>
/// 分类。
/// </summary>
[StringLength(100)]
public string? Category { get; set; }
/// <summary>
/// 标题。
/// </summary>
[StringLength(200)]
public string? Title { get; set; }
/// <summary>
/// 说明。
/// </summary>
[Required]
[StringLength(5000)]
public string Description { get; set; } = string.Empty;
/// <summary>
/// 优先级。
/// </summary>
[StringLength(32)]
public string? Priority { get; set; }
/// <summary>
/// 联系方式。
/// </summary>
[StringLength(200)]
public string? Contact { get; set; }
/// <summary>
/// 附件列表。
/// </summary>
public JsonElement Attachments { get; set; } = JsonSerializer.SerializeToElement(Array.Empty<object>());
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonSerializer.SerializeToElement(new { });
public SubmitFeedbackCommand ToCommand()

View File

@@ -4,40 +4,82 @@ using Tiku.Domain.Content;
namespace Tiku.Api.Contracts;
/// <summary>
/// 题目题库查询参数。
/// </summary>
public sealed class QuestionBankQueryDto
{
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 题库 ID。
/// </summary>
public Guid? QuestionBankId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 分类 ID。
/// </summary>
public Guid? CategoryId { get; set; }
/// <summary>
/// 节点 ID。
/// </summary>
public Guid? NodeId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 题集 ID。
/// </summary>
public Guid? CollectionId { get; set; }
/// <summary>
/// 来源。
/// </summary>
public QuestionSource? Source { get; set; }
/// <summary>
/// 类型。
/// </summary>
[StringLength(50)]
public string? Type { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 题目 ID 列表,支持逗号分隔;最多取前 300 个
/// 题目 ID 列表。
/// </summary>
public string? QuestionIds { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }

View File

@@ -5,17 +5,32 @@ using Tiku.Application.Growth;
namespace Tiku.Api.Contracts;
/// <summary>
/// 推荐租户查询参数。
/// </summary>
public sealed class ReferralTenantQueryDto
{
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
}
/// <summary>
/// 推荐邀请码请求 DTO。
/// </summary>
public sealed class ReferralInviteDto
{
/// <summary>
/// 渠道。
/// </summary>
[StringLength(100)]
public string? Channel { get; set; }
/// <summary>
/// 落地页路径。
/// </summary>
[StringLength(2048)]
public string? LandingPath { get; set; }
@@ -25,11 +40,20 @@ public sealed class ReferralInviteDto
}
}
/// <summary>
/// 解析推荐请求 DTO。
/// </summary>
public sealed class ResolveReferralDto
{
/// <summary>
/// 编码。
/// </summary>
[StringLength(100)]
public string? Code { get; set; }
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
@@ -39,22 +63,43 @@ public sealed class ResolveReferralDto
}
}
/// <summary>
/// 记录推荐事件请求 DTO。
/// </summary>
public sealed class TrackReferralEventDto
{
/// <summary>
/// 推荐码。
/// </summary>
[Required]
[StringLength(100)]
public string RefCode { get; set; } = string.Empty;
/// <summary>
/// 事件类型。
/// </summary>
[StringLength(100)]
public string? EventType { get; set; }
/// <summary>
/// 来源。
/// </summary>
[StringLength(100)]
public string? Source { get; set; }
/// <summary>
/// 目标用户 ID。
/// </summary>
public Guid? TargetUserId { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
@@ -64,15 +109,27 @@ public sealed class TrackReferralEventDto
}
}
/// <summary>
/// 绑定推荐请求 DTO。
/// </summary>
public sealed class BindReferralDto
{
/// <summary>
/// 推荐码。
/// </summary>
[Required]
[StringLength(100)]
public string RefCode { get; set; } = string.Empty;
/// <summary>
/// 来源。
/// </summary>
[StringLength(100)]
public string? Source { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public BindReferralCommand ToCommand()
@@ -81,20 +138,38 @@ public sealed class BindReferralDto
}
}
/// <summary>
/// 推荐二维码请求 DTO。
/// </summary>
public sealed class ReferralQrcodeDto
{
/// <summary>
/// 页码。
/// </summary>
[StringLength(500)]
public string? Page { get; set; }
/// <summary>
/// 场景参数。
/// </summary>
[StringLength(128)]
public string? Scene { get; set; }
/// <summary>
/// 服务提供方。
/// </summary>
[StringLength(100)]
public string? Provider { get; set; }
/// <summary>
/// 二维码地址。
/// </summary>
[StringLength(2048)]
public string? QrcodeUrl { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public ReferralQrcodeCommand ToCommand()
@@ -103,10 +178,19 @@ public sealed class ReferralQrcodeDto
}
}
/// <summary>
/// 推荐统计查询参数。
/// </summary>
public sealed class ReferralStatsQueryDto
{
/// <summary>
/// 推荐人用户 ID。
/// </summary>
public Guid? ReferrerUserId { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }
@@ -116,19 +200,37 @@ public sealed class ReferralStatsQueryDto
}
}
/// <summary>
/// 推荐Conversion查询参数。
/// </summary>
public sealed class ReferralConversionQueryDto
{
/// <summary>
/// 推荐人用户 ID。
/// </summary>
public Guid? ReferrerUserId { get; set; }
/// <summary>
/// 开始日期,格式为 yyyy-MM-dd。
/// </summary>
[RegularExpression("^\\d{4}-\\d{2}-\\d{2}$")]
public string? StartDate { get; set; }
/// <summary>
/// 结束日期,格式为 yyyy-MM-dd。
/// </summary>
[RegularExpression("^\\d{4}-\\d{2}-\\d{2}$")]
public string? EndDate { get; set; }
/// <summary>
/// 天数。
/// </summary>
[Range(1, 365)]
public int? Days { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 100)]
public int? Limit { get; set; }
@@ -150,19 +252,37 @@ public sealed class ReferralConversionQueryDto
}
}
/// <summary>
/// 人工绑定推荐请求 DTO。
/// </summary>
public sealed class ManualBindReferralDto
{
/// <summary>
/// 学生用户 ID。
/// </summary>
[Required]
public Guid StudentUserId { get; set; }
/// <summary>
/// 推荐人用户 ID。
/// </summary>
[Required]
public Guid ReferrerUserId { get; set; }
/// <summary>
/// 来源。
/// </summary>
[StringLength(100)]
public string? Source { get; set; }
/// <summary>
/// 是否强制执行。
/// </summary>
public bool Force { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public ManualBindReferralCommand ToCommand()
@@ -171,8 +291,14 @@ public sealed class ManualBindReferralDto
}
}
/// <summary>
/// 推荐团队查询参数。
/// </summary>
public sealed class ReferralTeamQueryDto
{
/// <summary>
/// 上级成员用户 ID。
/// </summary>
public Guid? LeaderUserId { get; set; }
public ReferralTeamQuery ToQuery()
@@ -181,19 +307,37 @@ public sealed class ReferralTeamQueryDto
}
}
/// <summary>
/// 新增或更新推荐团队请求 DTO。
/// </summary>
public sealed class UpsertReferralTeamDto
{
/// <summary>
/// 成员用户 ID。
/// </summary>
[Required]
public Guid MemberUserId { get; set; }
/// <summary>
/// 上级成员用户 ID。
/// </summary>
public Guid? LeaderUserId { get; set; }
/// <summary>
/// 关系类型。
/// </summary>
[StringLength(50)]
public string? RelationType { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(50)]
public string? Status { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement? Metadata { get; set; }
public UpsertReferralTeamCommand ToCommand()

View File

@@ -0,0 +1,151 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Tiku.Application.PlatformBilling;
using Tiku.Domain.Platform;
namespace Tiku.Api.Contracts;
/// <summary>
/// 新增或更新SaaS功能请求 DTO。
/// </summary>
public sealed record UpsertSaasFeatureDto(
Guid? Id,
[Required, MaxLength(120)] string Code,
[Required, MaxLength(200)] string Name,
[Required, MaxLength(100)] string Category,
[MaxLength(1000)] string? Description,
[Range(0, int.MaxValue)] int ReferencePriceCents,
[Required, MaxLength(10)] string Currency,
SaasFeatureStatus Status,
int SortOrder)
{
public UpsertSaasFeatureCommand ToCommand() => new(Id, Code, Name, Category, Description, ReferencePriceCents, Currency, Status, SortOrder);
}
/// <summary>
/// 新增或更新SaaS套餐请求 DTO。
/// </summary>
public sealed record UpsertSaasOfferingDto(
Guid? Id,
[Required, MaxLength(120)] string Code,
[Required, MaxLength(200)] string Name,
SaasOfferingType Type,
SaasOfferingStatus Status,
[MaxLength(1000)] string? Description,
int SortOrder)
{
public UpsertSaasOfferingCommand ToCommand() => new(Id, Code, Name, Type, Status, Description, SortOrder);
}
/// <summary>
/// 新增或更新 SaaS 功能额度定义。
/// </summary>
public sealed record UpsertSaasFeatureLimitDto(
Guid? Id,
[Required, MaxLength(120)] string MetricCode,
[Required, MaxLength(120)] string FeatureCode,
[Required, MaxLength(200)] string Name,
[Required, MaxLength(50)] string Unit,
SaasFeatureLimitKind Kind,
[Range(1, 100)] int WarningPercent,
bool IsHardLimit)
{
public UpsertSaasFeatureLimitCommand ToCommand() => new(
Id, MetricCode, FeatureCode, Name, Unit, Kind, WarningPercent, IsHardLimit);
}
/// <summary>
/// 新增或更新SaaS套餐版本请求 DTO。
/// </summary>
public sealed record UpsertSaasOfferingVersionDto(
Guid? Id,
Guid OfferingId,
PlatformBillingCycle BillingCycle,
[Range(0, int.MaxValue)] int OriginalAmountCents,
[Range(0, int.MaxValue)] int AmountCents,
[Required, MaxLength(10)] string Currency,
DateTimeOffset? EffectiveAt,
IReadOnlyCollection<string>? FeatureCodes,
IReadOnlyDictionary<string, long>? Limits,
JsonElement Metadata)
{
public UpsertSaasOfferingVersionCommand ToCommand() => new(
Id, OfferingId, BillingCycle, OriginalAmountCents, AmountCents, Currency, EffectiveAt,
FeatureCodes ?? [], Limits ?? new Dictionary<string, long>(), Metadata);
}
/// <summary>
/// 创建平台账务报价请求 DTO。
/// </summary>
public sealed record CreatePlatformBillingQuoteDto(
Guid BaseOfferingVersionId,
IReadOnlyCollection<Guid>? AddOnOfferingVersionIds,
PlatformBillingOrderPurpose Purpose,
[Required, MaxLength(200)] string IdempotencyKey)
{
public CreatePlatformBillingQuoteCommand ToCommand() => new(BaseOfferingVersionId, AddOnOfferingVersionIds ?? [], Purpose, IdempotencyKey);
}
/// <summary>
/// 创建平台账务订单请求 DTO。
/// </summary>
public sealed record CreatePlatformBillingOrderDto(Guid QuoteId, [Required, MaxLength(200)] string IdempotencyKey)
{
public CreatePlatformBillingOrderCommand ToCommand() => new(QuoteId, IdempotencyKey);
}
/// <summary>
/// 创建平台账务支付请求 DTO。
/// </summary>
public sealed record CreatePlatformBillingPaymentDto(
[Required, MaxLength(50)] string Provider,
[Required, MaxLength(50)] string Method,
[Required, MaxLength(200)] string IdempotencyKey,
string? OpenId,
string? ReturnUrl,
string? QuitUrl)
{
public CreatePlatformBillingPaymentCommand ToCommand(string orderNo) =>
new(orderNo, Provider, Method, IdempotencyKey, OpenId, ReturnUrl, QuitUrl);
}
/// <summary>
/// 变更租户订阅请求 DTO。
/// </summary>
public sealed record ChangeTenantSubscriptionDto(
Guid BaseOfferingVersionId,
IReadOnlyCollection<Guid>? AddOnOfferingVersionIds,
[Required, MaxLength(200)] string IdempotencyKey)
{
public ChangeTenantSubscriptionCommand ToCommand() => new(BaseOfferingVersionId, AddOnOfferingVersionIds ?? []);
}
/// <summary>
/// Idempotent租户账务请求 DTO。
/// </summary>
public sealed record IdempotentTenantBillingDto([Required, MaxLength(200)] string IdempotencyKey);
/// <summary>
/// 确认人工平台支付请求 DTO。
/// </summary>
public sealed record ConfirmManualPlatformPaymentDto(
Guid PaymentId,
string? ProviderTradeNo,
DateTimeOffset? PaidAt,
[Required, MaxLength(1000)] string Reason)
{
public ConfirmManualPaymentCommand ToCommand() => new(PaymentId, ProviderTradeNo, PaidAt, Reason);
}
/// <summary>
/// 新增或更新租户功能覆盖规则请求 DTO。
/// </summary>
public sealed record UpsertTenantFeatureOverrideDto(
Guid TenantId,
[Required, MaxLength(120)] string FeatureCode,
TenantFeatureOverrideMode Mode,
DateTimeOffset? ExpiresAt,
[Required, MaxLength(1000)] string Reason)
{
public UpsertTenantFeatureOverrideCommand ToCommand() => new(TenantId, FeatureCode, Mode, ExpiresAt, Reason);
}

View File

@@ -3,27 +3,57 @@ using Tiku.Application.Scoreline;
namespace Tiku.Api.Contracts;
/// <summary>
/// 分数线查询参数。
/// </summary>
public sealed class ScorelineQueryDto
{
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 院校 ID。
/// </summary>
public Guid? SchoolId { get; set; }
/// <summary>
/// 专业 ID。
/// </summary>
public Guid? MajorId { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 年份。
/// </summary>
[Range(1900, 3000)]
public int? Year { get; set; }
/// <summary>
/// 页码。
/// </summary>
[Range(1, 10000)]
public int? Page { get; set; }
/// <summary>
/// 每页数量。
/// </summary>
[Range(1, 200)]
public int? PageSize { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 2000)]
public int? Limit { get; set; }

View File

@@ -3,28 +3,61 @@ using Tiku.Application.StudyContent;
namespace Tiku.Api.Contracts;
/// <summary>
/// Study内容查询参数。
/// </summary>
public sealed class StudyContentQueryDto
{
/// <summary>
/// 租户编码。
/// </summary>
[StringLength(100)]
public string? TenantCode { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 单元 ID。
/// </summary>
public Guid? UnitId { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 章节 ID。
/// </summary>
public Guid? ChapterId { get; set; }
/// <summary>
/// 内容入口 ID。
/// </summary>
public Guid? EntryId { get; set; }
/// <summary>
/// 内容节点 ID。
/// </summary>
public Guid? ContentNodeId { get; set; }
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 是否包含正文内容。
/// </summary>
public bool IncludeContent { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 2000)]
public int? Limit { get; set; }

View File

@@ -7,17 +7,41 @@ using Tiku.Domain.Content;
namespace Tiku.Api.Contracts;
/// <summary>
/// 创建分类节点请求 DTO。
/// </summary>
public sealed class CreateTaxonomyNodeDto
{
/// <summary>
/// 父节点 ID。
/// </summary>
public Guid? ParentId { get; set; }
/// <summary>
/// 父级来源。
/// </summary>
public QuestionSource? ParentSource { get; set; }
/// <summary>
/// 节点Type。
/// </summary>
[Required]
public TaxonomyNodeType NodeType { get; set; }
/// <summary>
/// 编码。
/// </summary>
[Required, StringLength(100)]
public string Code { get; set; } = string.Empty;
/// <summary>
/// 名称。
/// </summary>
[Required, StringLength(300)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 排序值。
/// </summary>
public int SortOrder { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public CreateTaxonomyNodeCommand ToCommand() => new(

File diff suppressed because it is too large Load Diff

View File

@@ -7,41 +7,83 @@ using Tiku.Domain.Tenancy;
namespace Tiku.Api.Contracts;
/// <summary>
/// 租户交易查询参数。
/// </summary>
public sealed class TenantCommerceQueryDto
{
/// <summary>
/// 服务提供方。
/// </summary>
[StringLength(50)]
public string? Provider { get; set; }
/// <summary>
/// 状态。
/// </summary>
[StringLength(32)]
public string? Status { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 200)]
public int? Limit { get; set; }
/// <summary>
/// 用户 ID。
/// </summary>
public Guid? UserId { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
}
/// <summary>
/// 新增或更新支付账号请求 DTO。
/// </summary>
public sealed class UpsertPaymentAccountDto
{
/// <summary>
/// 服务提供方。
/// </summary>
[Required]
[StringLength(50)]
public string Provider { get; set; } = string.Empty;
/// <summary>
/// 模式。
/// </summary>
[StringLength(50)]
public string? Mode { get; set; } = "TenantCollect";
/// <summary>
/// 显示名称。
/// </summary>
[StringLength(200)]
public string? DisplayName { get; set; }
/// <summary>
/// 状态。
/// </summary>
public TenantExternalProviderStatus Status { get; set; } = TenantExternalProviderStatus.Disabled;
/// <summary>
/// 密钥引用。
/// </summary>
[StringLength(300)]
public string? SecretRef { get; set; }
/// <summary>
/// 优先级。
/// </summary>
public int? Priority { get; set; }
/// <summary>
/// 公开配置内容。
/// </summary>
public JsonElement ConfigPublic { get; set; } = JsonDefaults.Object();
public UpsertPaymentAccountCommand ToCommand()
@@ -50,25 +92,49 @@ public sealed class UpsertPaymentAccountDto
}
}
/// <summary>
/// 新增或更新租户Secret请求 DTO。
/// </summary>
public sealed class UpsertTenantSecretDto
{
/// <summary>
/// 用途。
/// </summary>
[Required]
[StringLength(80)]
public string Purpose { get; set; } = "payment";
/// <summary>
/// 服务提供方。
/// </summary>
[Required]
[StringLength(50)]
public string Provider { get; set; } = string.Empty;
/// <summary>
/// 密钥键。
/// </summary>
[Required]
[StringLength(120)]
public string SecretKey { get; set; } = string.Empty;
/// <summary>
/// 密钥引用。
/// </summary>
[StringLength(300)]
public string SecretRef { get; set; } = string.Empty;
/// <summary>
/// 状态。
/// </summary>
public TenantSecretStatus Status { get; set; } = TenantSecretStatus.Active;
/// <summary>
/// 密钥载荷。
/// </summary>
public JsonElement SecretPayload { get; set; } = JsonDefaults.Object();
/// <summary>
/// 过期时间。
/// </summary>
public DateTimeOffset? ExpiresAt { get; set; }
public UpsertTenantSecretCommand ToCommand()
@@ -84,32 +150,62 @@ public sealed class UpsertTenantSecretDto
}
}
/// <summary>
/// 创建编码批次请求 DTO。
/// </summary>
public sealed class CreateCodeBatchDto
{
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(200)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 总数量。
/// </summary>
[Range(1, 1000)]
public int TotalCount { get; set; }
/// <summary>
/// 天数。
/// </summary>
[Range(1, 3650)]
public int Days { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 售卖类型。
/// </summary>
[StringLength(50)]
public string? SaleType { get; set; }
/// <summary>
/// 渠道。
/// </summary>
[StringLength(100)]
public string? Channel { get; set; }
/// <summary>
/// 默认单价,单位为分。
/// </summary>
[Range(0, int.MaxValue)]
public int? DefaultUnitPriceCents { get; set; }
/// <summary>
/// 成本价,单位为分。
/// </summary>
[Range(0, int.MaxValue)]
public int? CostPriceCents { get; set; }
/// <summary>
/// 备注。
/// </summary>
[StringLength(1000)]
public string? Remark { get; set; }
@@ -128,15 +224,27 @@ public sealed class CreateCodeBatchDto
}
}
/// <summary>
/// 核销激活码编码请求 DTO。
/// </summary>
public sealed class RedeemActivationCodeDto
{
/// <summary>
/// 编码。
/// </summary>
[Required]
[StringLength(100)]
public string Code { get; set; } = string.Empty;
/// <summary>
/// 用户 ID。
/// </summary>
[Required]
public Guid UserId { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
public RedeemActivationCodeCommand ToCommand()
@@ -145,34 +253,76 @@ public sealed class RedeemActivationCodeDto
}
}
/// <summary>
/// 新增或更新积分任务请求 DTO。
/// </summary>
public sealed class UpsertPointTaskDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 任务键。
/// </summary>
[Required]
[StringLength(100)]
public string TaskKey { get; set; } = string.Empty;
/// <summary>
/// 标题。
/// </summary>
[Required]
[StringLength(200)]
public string Title { get; set; } = string.Empty;
/// <summary>
/// 说明。
/// </summary>
[StringLength(1000)]
public string? Description { get; set; }
/// <summary>
/// 任务类型。
/// </summary>
public PointActivityTaskType TaskType { get; set; } = PointActivityTaskType.Manual;
/// <summary>
/// 状态。
/// </summary>
public PointActivityTaskStatus Status { get; set; } = PointActivityTaskStatus.Active;
/// <summary>
/// 积分数量。
/// </summary>
[Range(1, int.MaxValue)]
public int Points { get; set; }
/// <summary>
/// 每用户最多领取次数。
/// </summary>
[Range(1, 1000)]
public int MaxClaimsPerUser { get; set; } = 1;
/// <summary>
/// 开始时间。
/// </summary>
public DateTimeOffset? StartsAt { get; set; }
/// <summary>
/// 结束时间。
/// </summary>
public DateTimeOffset? EndsAt { get; set; }
/// <summary>
/// 排序值。
/// </summary>
public int SortOrder { get; set; }
/// <summary>
/// 规则配置。
/// </summary>
public JsonElement Rules { get; set; } = JsonDefaults.Object();
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertPointTaskCommand ToCommand()
@@ -194,38 +344,86 @@ public sealed class UpsertPointTaskDto
}
}
/// <summary>
/// 新增或更新积分兑换Item请求 DTO。
/// </summary>
public sealed class UpsertPointExchangeItemDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 地区 ID。
/// </summary>
public Guid? RegionId { get; set; }
/// <summary>
/// 兑换项键。
/// </summary>
[Required]
[StringLength(100)]
public string ItemKey { get; set; } = string.Empty;
/// <summary>
/// 名称。
/// </summary>
[Required]
[StringLength(200)]
public string Name { get; set; } = string.Empty;
/// <summary>
/// 说明。
/// </summary>
[StringLength(1000)]
public string? Description { get; set; }
/// <summary>
/// 兑换项类型。
/// </summary>
public PointExchangeItemType ItemType { get; set; } = PointExchangeItemType.Entitlement;
/// <summary>
/// 状态。
/// </summary>
public PointExchangeItemStatus Status { get; set; } = PointExchangeItemStatus.Active;
/// <summary>
/// 所需积分。
/// </summary>
[Range(1, int.MaxValue)]
public int PointsCost { get; set; }
/// <summary>
/// 库存数量。
/// </summary>
[Range(0, int.MaxValue)]
public int? Stock { get; set; }
/// <summary>
/// 天数。
/// </summary>
[Range(0, 3650)]
public int? Days { get; set; }
/// <summary>
/// 排序值。
/// </summary>
public int SortOrder { get; set; }
/// <summary>
/// 开始时间。
/// </summary>
public DateTimeOffset? StartsAt { get; set; }
/// <summary>
/// 结束时间。
/// </summary>
public DateTimeOffset? EndsAt { get; set; }
/// <summary>
/// 履约载荷。
/// </summary>
public JsonElement FulfillmentPayload { get; set; } = JsonDefaults.Object();
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public UpsertPointExchangeItemCommand ToCommand()
@@ -249,20 +447,41 @@ public sealed class UpsertPointExchangeItemDto
}
}
/// <summary>
/// 创建退款Request请求 DTO。
/// </summary>
public sealed class CreateRefundRequestDto
{
/// <summary>
/// 订单 ID。
/// </summary>
[Required]
public Guid OrderId { get; set; }
/// <summary>
/// 支付记录 ID。
/// </summary>
public Guid? PaymentId { get; set; }
/// <summary>
/// 金额,单位为分。
/// </summary>
[Range(1, int.MaxValue)]
public int AmountCents { get; set; }
/// <summary>
/// 原因。
/// </summary>
[StringLength(1000)]
public string? Reason { get; set; }
/// <summary>
/// 权益动作。
/// </summary>
public RefundEntitlementAction EntitlementAction { get; set; } = RefundEntitlementAction.RevokeOnSuccess;
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public CreateRefundRequestCommand ToCommand()
@@ -271,16 +490,31 @@ public sealed class CreateRefundRequestDto
}
}
/// <summary>
/// 更新退款状态请求 DTO。
/// </summary>
public sealed class UpdateRefundStatusDto
{
/// <summary>
/// 退款申请 ID。
/// </summary>
[Required]
public Guid RefundRequestId { get; set; }
/// <summary>
/// 状态。
/// </summary>
public CommerceRefundStatus Status { get; set; }
/// <summary>
/// 原因。
/// </summary>
[StringLength(1000)]
public string? Reason { get; set; }
/// <summary>
/// 渠道退款单号。
/// </summary>
[StringLength(200)]
public string? ProviderRefundNo { get; set; }
@@ -290,23 +524,47 @@ public sealed class UpdateRefundStatusDto
}
}
/// <summary>
/// 创建对账批次请求 DTO。
/// </summary>
public sealed class CreateReconciliationBatchDto
{
/// <summary>
/// 服务提供方。
/// </summary>
[Required]
[StringLength(50)]
public string Provider { get; set; } = string.Empty;
/// <summary>
/// 账单日期。
/// </summary>
public DateOnly BillDate { get; set; }
/// <summary>
/// 账单类型。
/// </summary>
public ReconciliationBillType BillType { get; set; } = ReconciliationBillType.Combined;
/// <summary>
/// 来源。
/// </summary>
public ReconciliationSource Source { get; set; } = ReconciliationSource.ManualUpload;
/// <summary>
/// 来源名称。
/// </summary>
[StringLength(200)]
public string? SourceName { get; set; }
/// <summary>
/// 来源哈希。
/// </summary>
[Required]
[StringLength(200)]
public string SourceHash { get; set; } = string.Empty;
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public CreateReconciliationBatchCommand ToCommand()
@@ -315,17 +573,35 @@ public sealed class CreateReconciliationBatchDto
}
}
/// <summary>
/// 更新对账Issue请求 DTO。
/// </summary>
public sealed class UpdateReconciliationIssueDto
{
/// <summary>
/// 工单 ID。
/// </summary>
[Required]
public Guid IssueId { get; set; }
/// <summary>
/// 状态。
/// </summary>
public ReconciliationIssueStatus Status { get; set; } = ReconciliationIssueStatus.Investigating;
/// <summary>
/// 处理类型。
/// </summary>
public ReconciliationResolutionType ResolutionType { get; set; } = ReconciliationResolutionType.None;
/// <summary>
/// 备注。
/// </summary>
[StringLength(1000)]
public string? Note { get; set; }
/// <summary>
/// 分配处理人。
/// </summary>
public Guid? AssignedTo { get; set; }
public UpdateReconciliationIssueCommand ToCommand()
@@ -334,19 +610,37 @@ public sealed class UpdateReconciliationIssueDto
}
}
/// <summary>
/// 预览对账导入请求 DTO。
/// </summary>
public sealed class PreviewReconciliationImportDto
{
/// <summary>
/// 服务提供方。
/// </summary>
[Required]
[StringLength(50)]
public string Provider { get; set; } = string.Empty;
/// <summary>
/// 账单日期。
/// </summary>
public DateOnly BillDate { get; set; }
/// <summary>
/// 账单类型。
/// </summary>
public ReconciliationBillType BillType { get; set; } = ReconciliationBillType.Combined;
/// <summary>
/// 来源名称。
/// </summary>
[Required]
[StringLength(300)]
public string SourceName { get; set; } = string.Empty;
/// <summary>
/// 数据行列表。
/// </summary>
public JsonElement Rows { get; set; } = JsonDefaults.Array();
public PreviewReconciliationImportCommand ToPreviewCommand() => new(Provider, BillDate, BillType, SourceName, Rows);
@@ -354,29 +648,68 @@ public sealed class PreviewReconciliationImportDto
public ImportReconciliationCommand ToImportCommand() => new(Provider, BillDate, BillType, SourceName, Rows);
}
/// <summary>
/// 创建调账凭证请求 DTO。
/// </summary>
public sealed class CreateAdjustmentVoucherDto
{
/// <summary>
/// 工单 ID。
/// </summary>
public Guid? IssueId { get; set; }
/// <summary>
/// 批次 ID。
/// </summary>
public Guid? BatchId { get; set; }
/// <summary>
/// 兑换项 ID。
/// </summary>
public Guid? ItemId { get; set; }
/// <summary>
/// 订单 ID。
/// </summary>
public Guid? OrderId { get; set; }
/// <summary>
/// 支付记录 ID。
/// </summary>
public Guid? PaymentId { get; set; }
/// <summary>
/// 退款申请 ID。
/// </summary>
public Guid? RefundRequestId { get; set; }
/// <summary>
/// 方向。
/// </summary>
public CommerceAdjustmentDirection Direction { get; set; } = CommerceAdjustmentDirection.IncreaseRevenue;
/// <summary>
/// 金额,单位为分。
/// </summary>
[Range(1, int.MaxValue)]
public int AmountCents { get; set; }
/// <summary>
/// 币种。
/// </summary>
[StringLength(10)]
public string? Currency { get; set; }
/// <summary>
/// 原因。
/// </summary>
[Required]
[StringLength(1000)]
public string Reason { get; set; } = string.Empty;
/// <summary>
/// 证明资产键。
/// </summary>
[StringLength(500)]
public string? ProofAssetKey { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public CreateAdjustmentVoucherCommand ToCommand() => new(
@@ -394,56 +727,110 @@ public sealed class CreateAdjustmentVoucherDto
Metadata);
}
/// <summary>
/// 更新调账凭证状态请求 DTO。
/// </summary>
public sealed class UpdateAdjustmentVoucherStatusDto
{
/// <summary>
/// 凭证 ID。
/// </summary>
[Required]
public Guid VoucherId { get; set; }
/// <summary>
/// 状态。
/// </summary>
public CommerceAdjustmentVoucherStatus Status { get; set; } = CommerceAdjustmentVoucherStatus.PendingReview;
/// <summary>
/// 备注。
/// </summary>
[StringLength(1000)]
public string? Note { get; set; }
public UpdateAdjustmentVoucherStatusCommand ToCommand() => new(VoucherId, Status, Note);
}
/// <summary>
/// RequestProviderBill任务请求 DTO。
/// </summary>
public sealed class RequestProviderBillJobDto
{
/// <summary>
/// 服务提供方。
/// </summary>
[Required]
[StringLength(50)]
public string Provider { get; set; } = string.Empty;
/// <summary>
/// 账单日期。
/// </summary>
public DateOnly BillDate { get; set; }
/// <summary>
/// 账单类型。
/// </summary>
public ReconciliationBillType BillType { get; set; } = ReconciliationBillType.Combined;
/// <summary>
/// 计划运行时间。
/// </summary>
public DateTimeOffset? RunAfter { get; set; }
public RequestProviderBillJobCommand ToCommand() => new(Provider, BillDate, BillType, RunAfter);
}
/// <summary>
/// 退款通知请求 DTO。
/// </summary>
public sealed class RefundNotificationDto
{
/// <summary>
/// 退款单号。
/// </summary>
[Required]
[StringLength(100)]
public string RefundNo { get; set; } = string.Empty;
/// <summary>
/// 渠道退款单号。
/// </summary>
[StringLength(200)]
public string? ProviderRefundNo { get; set; }
/// <summary>
/// 状态。
/// </summary>
public CommerceRefundStatus Status { get; set; } = CommerceRefundStatus.Succeeded;
/// <summary>
/// 事件 ID。
/// </summary>
[StringLength(200)]
public string? EventId { get; set; }
/// <summary>
/// 任务载荷。
/// </summary>
public JsonElement Payload { get; set; } = JsonDefaults.Object();
public RefundNotificationCommand ToCommand(string provider) => new(provider, RefundNo, ProviderRefundNo, Status, EventId, Payload);
}
/// <summary>
/// 更新积分兑换订单状态请求 DTO。
/// </summary>
public sealed class UpdatePointExchangeOrderStatusDto
{
/// <summary>
/// 订单 ID。
/// </summary>
[Required]
public Guid OrderId { get; set; }
/// <summary>
/// 状态。
/// </summary>
public PointExchangeOrderStatus Status { get; set; }
public UpdatePointExchangeOrderStatusCommand ToCommand()
@@ -452,29 +839,62 @@ public sealed class UpdatePointExchangeOrderStatusDto
}
}
/// <summary>
/// 新增或更新租户优惠券请求 DTO。
/// </summary>
public sealed class UpsertTenantCouponDto
{
/// <summary>
/// ID。
/// </summary>
public Guid? Id { get; set; }
/// <summary>
/// 编码。
/// </summary>
[Required]
[StringLength(100)]
public string Code { get; set; } = string.Empty;
/// <summary>
/// 套餐 ID。
/// </summary>
public Guid? PlanId { get; set; }
/// <summary>
/// 优惠类型。
/// </summary>
public DiscountType DiscountType { get; set; } = DiscountType.Fixed;
/// <summary>
/// 优惠值。
/// </summary>
[Range(typeof(decimal), "0.01", "999999")]
public decimal DiscountValue { get; set; }
/// <summary>
/// 有效期开始时间。
/// </summary>
public DateTimeOffset? ValidFrom { get; set; }
/// <summary>
/// 有效期结束时间。
/// </summary>
public DateTimeOffset? ValidTo { get; set; }
/// <summary>
/// 最大使用次数。
/// </summary>
[Range(1, int.MaxValue)]
public int? MaxUses { get; set; }
/// <summary>
/// 来源。
/// </summary>
[StringLength(50)]
public string? Source { get; set; }
/// <summary>
/// 备注。
/// </summary>
[StringLength(1000)]
public string? Remark { get; set; }

View File

@@ -12,14 +12,14 @@ namespace Tiku.Api.Contracts;
public sealed class TenantResolveQueryDto
{
/// <summary>
/// 要解析的访问域名,例如 student.example.com。本地开发也可以直接传 localhost
/// 访问域名
/// </summary>
[StringLength(253)]
[Description("要解析的访问域名,例如 student.example.com。本地开发也可以直接传 localhost。")]
public string? Host { get; set; }
/// <summary>
/// 租户编码;本地开发或无独立域名时使用,例如 master
/// 租户编码。
/// </summary>
[StringLength(100)]
[Description("租户编码;本地开发或无独立域名时使用,例如 master。")]
@@ -34,6 +34,9 @@ public sealed class TenantResolveQueryDto
/// <param name="Features">面向前端公开的功能开关。</param>
/// <param name="AdminFeatures">面向管理端公开的功能开关。</param>
/// <param name="PublicConfig">可公开的租户配置,不包含密钥或内部配置。</param>
/// <summary>
/// 租户解析Response请求 DTO。
/// </summary>
public sealed record TenantResolveResponseDto(
PublicTenantDto Tenant,
PublicTenantBrandingDto Branding,
@@ -50,6 +53,9 @@ public sealed record TenantResolveResponseDto(
/// <param name="Status">租户状态。</param>
/// <param name="Mode">租户模式。</param>
/// <param name="Host">当前匹配到的访问域名。</param>
/// <summary>
/// 公开租户请求 DTO。
/// </summary>
public sealed record PublicTenantDto(
Guid Id,
string Slug,
@@ -70,6 +76,9 @@ public sealed record PublicTenantDto(
/// <param name="ServiceAccountName">公众号或服务号名称。</param>
/// <param name="Theme">公开主题配置。</param>
/// <param name="PublicAssets">公开资源配置。</param>
/// <summary>
/// 公开租户品牌请求 DTO。
/// </summary>
public sealed record PublicTenantBrandingDto(
string? BrandName,
string? ShortName,

View File

@@ -5,12 +5,30 @@ using Tiku.Domain.Common;
namespace Tiku.Api.Contracts;
/// <summary>
/// 保存租户前端配置草稿请求。
/// </summary>
public sealed class SaveTenantFrontendConfigDraftDto
{
/// <summary>
/// 品牌配置。
/// </summary>
public JsonElement Branding { get; set; } = JsonDefaults.Object();
/// <summary>
/// 主题配置。
/// </summary>
public JsonElement Theme { get; set; } = JsonDefaults.Object();
/// <summary>
/// 功能配置。
/// </summary>
public JsonElement Features { get; set; } = JsonDefaults.Object();
/// <summary>
/// 导航配置。
/// </summary>
public JsonElement Navigation { get; set; } = JsonDefaults.Array();
/// <summary>
/// 首页模块配置。
/// </summary>
public JsonElement HomeModules { get; set; } = JsonDefaults.Array();
public TenantFrontendConfigDraft ToDraft() => new(
@@ -21,8 +39,14 @@ public sealed class SaveTenantFrontendConfigDraftDto
HomeModules);
}
/// <summary>
/// 发布租户前端配置请求。
/// </summary>
public sealed class PublishTenantFrontendConfigDto
{
/// <summary>
/// 期望配置版本。
/// </summary>
[Range(1, int.MaxValue)]
public int ExpectedVersion { get; set; }
}

View File

@@ -4,47 +4,92 @@ using Tiku.Application.Assets;
namespace Tiku.Api.Contracts;
/// <summary>
/// 视频Search查询参数。
/// </summary>
public sealed class VideoSearchQueryDto
{
/// <summary>
/// 关键字。
/// </summary>
[StringLength(100)]
public string? Keyword { get; set; }
/// <summary>
/// 科目 ID。
/// </summary>
public Guid? SubjectId { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 200)]
public int? Limit { get; set; }
public VideoSearchQuery ToQuery() => new(Keyword, SubjectId, Limit);
}
/// <summary>
/// 视频Play请求 DTO。
/// </summary>
public sealed class VideoPlayDto
{
/// <summary>
/// 视频 ID。
/// </summary>
[Required]
public Guid VideoId { get; set; }
/// <summary>
/// 题目 ID。
/// </summary>
public Guid? QuestionId { get; set; }
public VideoPlayCommand ToCommand() => new(VideoId, QuestionId);
}
/// <summary>
/// 视频Progress请求 DTO。
/// </summary>
public sealed class VideoProgressDto
{
/// <summary>
/// 视频 ID。
/// </summary>
[Required]
public Guid VideoId { get; set; }
/// <summary>
/// 题目 ID。
/// </summary>
public Guid? QuestionId { get; set; }
/// <summary>
/// 播放位置,单位为秒。
/// </summary>
[Range(0, int.MaxValue)]
public int PositionSeconds { get; set; }
/// <summary>
/// 时长,单位为秒。
/// </summary>
[Range(0, int.MaxValue)]
public int? DurationSeconds { get; set; }
/// <summary>
/// 已观看时长,单位为秒。
/// </summary>
[Range(0, int.MaxValue)]
public int? WatchedSeconds { get; set; }
/// <summary>
/// 是否已完成。
/// </summary>
public bool? IsCompleted { get; set; }
/// <summary>
/// 扩展元数据。
/// </summary>
public JsonElement Metadata { get; set; } = JsonSerializer.SerializeToElement(new { });
public VideoProgressCommand ToCommand()
@@ -60,13 +105,25 @@ public sealed class VideoProgressDto
}
}
/// <summary>
/// 题目视频查询参数。
/// </summary>
public sealed class QuestionVideoQueryDto
{
/// <summary>
/// 题目 ID。
/// </summary>
public Guid? QuestionId { get; set; }
/// <summary>
/// 题目 ID 列表。
/// </summary>
[MaxLength(100)]
public IReadOnlyCollection<Guid>? QuestionIds { get; set; }
/// <summary>
/// 返回数量上限。
/// </summary>
[Range(1, 500)]
public int? Limit { get; set; }