using OrderSupportTicket.Models.Api; using System; using System.Globalization; using WPFCommon.Models; namespace OrderSupportTicket.ViewModels; /// /// 历史工单列表中的单个工单摘要。 /// public sealed class WorkOrderSummaryViewModel : BindableBaseEx { private string _appId; private string _wechatOrderId; private string _status; private string _statusText; private DateTimeOffset _updatedAt; private DateTimeOffset _lastMessageAt; private DateTimeOffset? _lastReplyAt; private string _lastSenderType; private int _unreadCount; private bool _hasNewMessage; private string _version; public WorkOrderSummaryViewModel(WorkOrderSummaryDto dto) { if (dto == null) throw new ArgumentNullException(nameof(dto)); Apply(dto); } /// /// 订单所属店铺 APPID。 /// public string AppId { get => _appId; private set => SetValue(ref _appId, value); } /// /// 微信订单号,也是客户端使用的工单号。 /// public string WechatOrderId { get => _wechatOrderId; private set => SetValue(ref _wechatOrderId, value); } /// /// 工单状态编码。 /// public string Status { get => _status; private set { if (SetValue(ref _status, value)) RaisePropertyChanged(nameof(IsCompleted)); } } /// /// 工单状态中文文本。 /// public string StatusText { get => _statusText; private set => SetValue(ref _statusText, value); } /// /// 工单最后更新时间。 /// public DateTimeOffset UpdatedAt { get => _updatedAt; private set { if (SetValue(ref _updatedAt, value)) RaisePropertyChanged(nameof(UpdatedAtText)); } } /// /// 最近一条公开留言的时间。 /// public DateTimeOffset LastMessageAt { get => _lastMessageAt; private set => SetValue(ref _lastMessageAt, value); } /// /// 最近一次客服正式回复时间。 /// public DateTimeOffset? LastReplyAt { get => _lastReplyAt; private set => SetValue(ref _lastReplyAt, value); } /// /// 最近一条留言的发送方类型。 /// public string LastSenderType { get => _lastSenderType; private set { if (SetValue(ref _lastSenderType, value)) RaisePropertyChanged(nameof(PreviewText)); } } /// /// 当前工单的未读留言数量。 /// public int UnreadCount { get => _unreadCount; private set => SetValue(ref _unreadCount, value); } /// /// 本次服务器刷新是否检测到比本地缓存更新的公开消息。 /// public bool HasNewMessage { get => _hasNewMessage; private set { if (SetValue(ref _hasNewMessage, value)) RaisePropertyChanged(nameof(PreviewText)); } } /// /// 工单版本号字符串。 /// public string Version { get => _version; private set => SetValue(ref _version, value); } /// /// 用于合并工单的 APPID 与订单号组合键。 /// public string Key => AppId + "|" + WechatOrderId; /// /// 工单是否已完结。 /// public bool IsCompleted => string.Equals(Status, "completed", StringComparison.OrdinalIgnoreCase); /// /// 适合列表展示的本地时间文本。 /// public string UpdatedAtText => UpdatedAt == default ? string.Empty : UpdatedAt.ToLocalTime().ToString("MM-dd HH:mm", CultureInfo.CurrentCulture); /// /// 不读取留言正文时使用的最近动态摘要。 /// public string PreviewText { get { if (HasNewMessage) return "有新消息,点击查看"; if (string.Equals( LastSenderType, "customer", StringComparison.OrdinalIgnoreCase)) { return "客户最近有新留言"; } if (LastReplyAt.HasValue) return "客服最近已回复"; return "暂无公开留言"; } } public bool TryApply(WorkOrderSummaryDto dto) { if (dto == null || !string.Equals(Key, dto.AppId + "|" + dto.WechatOrderId, StringComparison.Ordinal)) { return false; } if (!IsAtLeastCurrentVersion(dto.Version)) return false; Apply(dto); return true; } public void ApplySendResult(string status, string version) { if (!string.IsNullOrWhiteSpace(status)) { Status = status; StatusText = GetStatusText(status); } if (!string.IsNullOrWhiteSpace(version)) Version = version; UpdatedAt = DateTimeOffset.Now; LastMessageAt = UpdatedAt; LastSenderType = "customer"; HasNewMessage = false; } public void MarkRead() { UnreadCount = 0; HasNewMessage = false; } /// /// 标记检测到新消息,并确保列表显示未读角标。 /// public void MarkHasNewMessage() { HasNewMessage = true; if (UnreadCount <= 0) UnreadCount = 1; } private void Apply(WorkOrderSummaryDto dto) { AppId = dto.AppId; WechatOrderId = dto.WechatOrderId; Status = dto.Status; StatusText = string.IsNullOrWhiteSpace(dto.StatusText) ? GetStatusText(dto.Status) : dto.StatusText; UpdatedAt = ParseTimestamp(dto.UpdatedAt); LastMessageAt = ParseTimestamp(dto.LastMessageAt); LastReplyAt = ParseNullableTimestamp(dto.LastReplyAt); LastSenderType = dto.LastSenderType; UnreadCount = Math.Max(0, dto.UnreadCount); Version = dto.Version; } private bool IsAtLeastCurrentVersion(string incomingVersion) { if (string.IsNullOrWhiteSpace(incomingVersion)) return true; if (!long.TryParse(incomingVersion, out var incoming)) return true; if (!long.TryParse(Version, out var current)) return true; return incoming >= current; } private static DateTimeOffset ParseTimestamp(string value) { if (DateTimeOffset.TryParse( value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var parsed)) { return parsed; } return default; } private static DateTimeOffset? ParseNullableTimestamp(string value) { var parsed = ParseTimestamp(value); return parsed == default ? (DateTimeOffset?)null : parsed; } private static string GetStatusText(string status) { if (string.Equals(status, "waiting_reply", StringComparison.OrdinalIgnoreCase)) return "待客服回复"; if (string.Equals(status, "replied", StringComparison.OrdinalIgnoreCase)) return "客服已回复"; if (string.Equals(status, "completed", StringComparison.OrdinalIgnoreCase)) return "已完结"; return string.IsNullOrWhiteSpace(status) ? "状态未知" : status; } }