Files
tiku-backend.net/Tiku.Api/Contracts/LearningDtos.cs
xiong 33375a38d7
Some checks failed
ci / release-gate (push) Has been cancelled
refactor(architecture): harden module boundaries
2026-08-04 12:10:36 +08:00

369 lines
8.2 KiB
C#

using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Tiku.Application.Learning;
using Tiku.Application.QuestionBanks;
using Tiku.Domain.Common;
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()
{
return new LearningLimitFilter(Limit, Status, UnitId);
}
}
/// <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; }
public PracticeSessionFilter ToFilter(Guid? routePracticeSessionId = null)
{
return new PracticeSessionFilter(
routePracticeSessionId ?? PracticeSessionId,
BlueprintId,
Mode,
Status,
Limit);
}
}
/// <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()
{
return new PracticeSessionCommand(
Mode,
TargetType,
TargetId,
BlueprintId,
CollectionId,
EntryId,
ContentNodeId,
QuestionLimit,
DurationMinutes,
TotalScore,
Metadata);
}
}
/// <summary>
/// 提交练习会话请求 DTO。
/// </summary>
public sealed class SubmitPracticeSessionDto
{
/// <summary>
/// 练习会话 ID。
/// </summary>
[Required]
public Guid PracticeSessionId { get; set; }
[Required][Range(1, long.MaxValue)] public long ExpectedSessionVersion { get; set; }
[Required]
[StringLength(200, MinimumLength = 1)]
public string IdempotencyKey { get; set; } = string.Empty;
public SubmitPracticeSessionCommand ToCommand()
{
return new SubmitPracticeSessionCommand(PracticeSessionId, ExpectedSessionVersion, IdempotencyKey);
}
}
/// <summary>
/// 提交答案请求 DTO。
/// </summary>
public sealed class SubmitAnswerDto
{
/// <summary>
/// 会话题目 ID。
/// </summary>
[Required]
public Guid SessionQuestionId { get; set; }
/// <summary>
/// 客户端读取会话时获得的版本。
/// </summary>
[Required]
[Range(1, long.MaxValue)]
public long ExpectedSessionVersion { get; set; }
/// <summary>
/// 客户端在本会话内单调递增的序列。
/// </summary>
[Required]
[Range(1, long.MaxValue)]
public long ClientSequence { get; set; }
/// <summary>
/// 网络重试幂等键。
/// </summary>
[Required]
[StringLength(200, MinimumLength = 1)]
public string IdempotencyKey { get; set; } = string.Empty;
/// <summary>
/// 已选选项的零基索引。
/// </summary>
public IReadOnlyCollection<int>? SelectedOptionIndices { get; set; }
/// <summary>
/// 文字答案。
/// </summary>
[StringLength(10000)]
public string? AnswerText { get; set; }
public SubmitAnswerCommand ToCommand()
{
return new SubmitAnswerCommand(
SessionQuestionId,
ExpectedSessionVersion,
ClientSequence,
IdempotencyKey,
SelectedOptionIndices,
AnswerText);
}
}
/// <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()
{
return new QuestionActionCommand(new QuestionLocator(Source, QuestionId), Favorite);
}
}
/// <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()
{
return new WordProgressCommand(
WordId,
Status,
CorrectDelta,
WrongDelta,
NextReviewAt);
}
}
/// <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; }
public FavoriteWordCommand ToCommand()
{
return new FavoriteWordCommand(WordId, Favorite, Note);
}
}
/// <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()
{
return new WordReviewCommand(WordId, Result, NextReviewAt);
}
}