using System.ComponentModel.DataAnnotations;
using EARSystem.Core;
namespace EARSystem.Web.Models;
public class LoginInput
{
[Required, EmailAddress, StringLength(254)] public string Email { get; set; } = "";
[Required, StringLength(128)] public string Password { get; set; } = "";
public bool Remember { get; set; }
public string? ReturnUrl { get; set; }
}
public class RegisterInput
{
[Required, StringLength(40, MinimumLength = 1)] public string DisplayName { get; set; } = "";
[Required, EmailAddress, StringLength(254)] public string Email { get; set; } = "";
[Required, StringLength(128, MinimumLength = 10)] public string Password { get; set; } = "";
[Compare(nameof(Password))] public string ConfirmPassword { get; set; } = "";
}
public class MoodInput : IValidatableObject
{
[Range(1, 5)] public int Mood { get; set; } = 3;
[Range(1, 5)] public int Energy { get; set; } = 3;
[Range(1, 5)] public int Stress { get; set; } = 3;
[StringLength(5000)] public string Thoughts { get; set; } = "";
public string[] Tags { get; set; } = [];
public DateTimeOffset RecordedAt { get; set; }
public Guid? Version { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (RecordedAt == default || RecordedAt > DateTimeOffset.UtcNow.AddMinutes(1))
yield return new("请选择有效的记录时间,不能记录未来状态。", [nameof(RecordedAt)]);
if (Tags.Length > 12 || Tags.Except(Labels.EmotionTags.Concat(Labels.SceneTags)).Any())
yield return new("请选择支持的情绪或场景标签。", [nameof(Tags)]);
}
}
public class TagInput { [StringLength(5000)] public string Text { get; set; } = ""; }
public class RecommendationInput : IValidatableObject
{
[Range(-180, 180)] public double Longitude { get; set; }
[Range(-90, 90)] public double Latitude { get; set; }
public string CoordinateSystem { get; set; } = "GCJ02";
public int RadiusMeters { get; set; } = 3000;
[Range(1, 100000)] public decimal? Budget { get; set; }
public PlaceCategory[] Categories { get; set; } = [];
public bool OpenOnly { get; set; }
public RecommendationGoal? Goal { get; set; }
public DataMode Mode { get; set; } = DataMode.Demo;
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (!double.IsFinite(Longitude) || !double.IsFinite(Latitude)) yield return new("坐标无效。");
if (CoordinateSystem is not ("GCJ02" or "WGS84")) yield return new("坐标系无效。");
if (!new[] { 1000, 3000, 5000, 10000 }.Contains(RadiusMeters)) yield return new("距离范围无效。");
if (!Enum.IsDefined(Mode) || Goal.HasValue && !Enum.IsDefined(Goal.Value) || Categories.Length > 6
|| Categories.Any(x => !Enum.IsDefined(x))) yield return new("推荐选项无效。");
}
public RecommendationQuery Query() => new() { Location = new(Longitude, Latitude, CoordinateSystem), RadiusMeters = RadiusMeters,
Budget = Budget, Categories = Categories, OpenOnly = OpenOnly, Goal = Goal, Mode = Mode };
}
public class ExperienceInput : IValidatableObject
{
public Guid PlaceId { get; set; }
public DateTimeOffset VisitedAt { get; set; }
[Range(1, 5)] public int Satisfaction { get; set; } = 4;
[Range(1, 5)] public int? MoodBefore { get; set; }
[Range(1, 5)] public int? MoodAfter { get; set; }
[Range(1, 5)] public int Quiet { get; set; } = 3;
[Range(1, 5)] public int Comfort { get; set; } = 3;
[Range(1, 5)] public int Nature { get; set; } = 3;
[Range(1, 5)] public int Liveliness { get; set; } = 3;
[Range(1, 5)] public int Social { get; set; } = 3;
[Range(1, 5)] public int Focus { get; set; } = 3;
[StringLength(5000)] public string Thoughts { get; set; } = "";
public bool Contribute { get; set; }
public bool SyncDiary { get; set; }
[Range(1, 5)] public int Energy { get; set; } = 3;
[Range(1, 5)] public int Stress { get; set; } = 3;
public Guid? Version { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (PlaceId == Guid.Empty || VisitedAt == default || VisitedAt > DateTimeOffset.UtcNow.AddMinutes(1))
yield return new("请选择地点与有效的到访时间。");
if (SyncDiary && !MoodAfter.HasValue) yield return new("同步日记时请填写体验后的心情。");
}
public Experience Entity(Guid? id = null) => new() { Id = id ?? Guid.NewGuid(), PlaceId = PlaceId, VisitedAt = VisitedAt,
Satisfaction = Satisfaction, MoodBefore = MoodBefore, MoodAfter = MoodAfter, Quiet = Quiet, Comfort = Comfort,
Nature = Nature, Liveliness = Liveliness, Social = Social, Focus = Focus, Thoughts = Thoughts, Contribute = Contribute };
}
public class FavoriteInput { public Guid PlaceId { get; set; } }
public class PreferenceInput : IValidatableObject
{
public PlaceCategory[] FavoriteCategories { get; set; } = [];
public PlaceCategory[] BlockedCategories { get; set; } = [];
public Guid[] BlockedPlaces { get; set; } = [];
[Range(1, 100000)] public decimal? Budget { get; set; }
public int RadiusMeters { get; set; } = 3000;
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (FavoriteCategories.Concat(BlockedCategories).Any(x => !Enum.IsDefined(x)) || FavoriteCategories.Length > 6
|| BlockedCategories.Length > 6 || BlockedPlaces.Length > 100) yield return new("偏好选项无效。");
if (!new[] { 1000, 3000, 5000, 10000 }.Contains(RadiusMeters)) yield return new("默认距离无效。");
if (FavoriteCategories.Intersect(BlockedCategories).Any()) yield return new("同一类别不能同时喜欢和屏蔽。");
}
}
using System.ComponentModel.DataAnnotations;
using EARSystem.Core;
namespace EARSystem.Web.Models;
public class LoginInput
{
[Required, EmailAddress, StringLength(254)] public string Email { get; set; } = "";
[Required, StringLength(128)] public string Password { get; set; } = "";
public bool Remember { get; set; }
public string? ReturnUrl { get; set; }
}
public class RegisterInput
{
[Required, StringLength(40, MinimumLength = 1)] public string DisplayName { get; set; } = "";
[Required, EmailAddress, StringLength(254)] public string Email { get; set; } = "";
[Required, StringLength(128, MinimumLength = 10)] public string Password { get; set; } = "";
[Compare(nameof(Password))] public string ConfirmPassword { get; set; } = "";
}
public class MoodInput : IValidatableObject
{
[Range(1, 5)] public int Mood { get; set; } = 3;
[Range(1, 5)] public int Energy { get; set; } = 3;
[Range(1, 5)] public int Stress { get; set; } = 3;
[StringLength(5000)] public string Thoughts { get; set; } = "";
public string[] Tags { get; set; } = [];
public DateTimeOffset RecordedAt { get; set; }
public Guid? Version { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (RecordedAt == default || RecordedAt > DateTimeOffset.UtcNow.AddMinutes(1))
yield return new("请选择有效的记录时间,不能记录未来状态。", [nameof(RecordedAt)]);
if (Tags.Length > 12 || Tags.Except(Labels.EmotionTags.Concat(Labels.SceneTags)).Any())
yield return new("请选择支持的情绪或场景标签。", [nameof(Tags)]);
}
}
public class TagInput { [StringLength(5000)] public string Text { get; set; } = ""; }
public class RecommendationInput : IValidatableObject
{
[Range(-180, 180)] public double Longitude { get; set; }
[Range(-90, 90)] public double Latitude { get; set; }
public string CoordinateSystem { get; set; } = "GCJ02";
public int RadiusMeters { get; set; } = 3000;
[Range(1, 100000)] public decimal? Budget { get; set; }
public PlaceCategory[] Categories { get; set; } = [];
public bool OpenOnly { get; set; }
public RecommendationGoal? Goal { get; set; }
public DataMode Mode { get; set; } = DataMode.Demo;
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (!double.IsFinite(Longitude) || !double.IsFinite(Latitude)) yield return new("坐标无效。");
if (CoordinateSystem is not ("GCJ02" or "WGS84")) yield return new("坐标系无效。");
if (!new[] { 1000, 3000, 5000, 10000 }.Contains(RadiusMeters)) yield return new("距离范围无效。");
if (!Enum.IsDefined(Mode) || Goal.HasValue && !Enum.IsDefined(Goal.Value) || Categories.Length > 6
|| Categories.Any(x => !Enum.IsDefined(x))) yield return new("推荐选项无效。");
}
public RecommendationQuery Query() => new() { Location = new(Longitude, Latitude, CoordinateSystem), RadiusMeters = RadiusMeters,
Budget = Budget, Categories = Categories, OpenOnly = OpenOnly, Goal = Goal, Mode = Mode };
}
public class ExperienceInput : IValidatableObject
{
public Guid PlaceId { get; set; }
public DateTimeOffset VisitedAt { get; set; }
[Range(1, 5)] public int Satisfaction { get; set; } = 4;
[Range(1, 5)] public int? MoodBefore { get; set; }
[Range(1, 5)] public int? MoodAfter { get; set; }
[Range(1, 5)] public int Quiet { get; set; } = 3;
[Range(1, 5)] public int Comfort { get; set; } = 3;
[Range(1, 5)] public int Nature { get; set; } = 3;
[Range(1, 5)] public int Liveliness { get; set; } = 3;
[Range(1, 5)] public int Social { get; set; } = 3;
[Range(1, 5)] public int Focus { get; set; } = 3;
[StringLength(5000)] public string Thoughts { get; set; } = "";
public bool Contribute { get; set; }
public bool SyncDiary { get; set; }
[Range(1, 5)] public int Energy { get; set; } = 3;
[Range(1, 5)] public int Stress { get; set; } = 3;
public Guid? Version { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (PlaceId == Guid.Empty || VisitedAt == default || VisitedAt > DateTimeOffset.UtcNow.AddMinutes(1))
yield return new("请选择地点与有效的到访时间。");
if (SyncDiary && !MoodAfter.HasValue) yield return new("同步日记时请填写体验后的心情。");
}
public Experience Entity(Guid? id = null) => new() { Id = id ?? Guid.NewGuid(), PlaceId = PlaceId, VisitedAt = VisitedAt,
Satisfaction = Satisfaction, MoodBefore = MoodBefore, MoodAfter = MoodAfter, Quiet = Quiet, Comfort = Comfort,
Nature = Nature, Liveliness = Liveliness, Social = Social, Focus = Focus, Thoughts = Thoughts, Contribute = Contribute };
}
public class FavoriteInput { public Guid PlaceId { get; set; } }
public class PreferenceInput : IValidatableObject
{
public PlaceCategory[] FavoriteCategories { get; set; } = [];
public PlaceCategory[] BlockedCategories { get; set; } = [];
public Guid[] BlockedPlaces { get; set; } = [];
[Range(1, 100000)] public decimal? Budget { get; set; }
public int RadiusMeters { get; set; } = 3000;
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (FavoriteCategories.Concat(BlockedCategories).Any(x => !Enum.IsDefined(x)) || FavoriteCategories.Length > 6
|| BlockedCategories.Length > 6 || BlockedPlaces.Length > 100) yield return new("偏好选项无效。");
if (!new[] { 1000, 3000, 5000, 10000 }.Contains(RadiusMeters)) yield return new("默认距离无效。");
if (FavoriteCategories.Intersect(BlockedCategories).Any()) yield return new("同一类别不能同时喜欢和屏蔽。");
}
}