工单 优化 ,增加图片
This commit is contained in:
1 parent
bf5a70597c
commit
cf2efbcb16
27 files changed
+3555
-1538
No files matched your search
@@ -1,5 +1,6 @@
|
||||
using AllBase.Helper;
|
||||
using AllBase.Helper;
|
||||
using AllBase.Model.DBModel;
|
||||
using Microsoft.Win32;
|
||||
using OrderSupportTicket.Models;
|
||||
using OrderSupportTicket.Models.Api;
|
||||
using OrderSupportTicket.Services;
|
||||
@@ -8,8 +9,10 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
@@ -17,6 +20,7 @@ using System.Windows.Threading;
|
||||
using WPFCommon.Models;
|
||||
using WxOrder.Framework.Commons;
|
||||
using WxOrder.Framework.Commons.Dialogs;
|
||||
using WxOrder.Framework.Controls;
|
||||
|
||||
namespace OrderSupportTicket.ViewModels;
|
||||
|
||||
@@ -36,8 +40,10 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
private readonly AsyncDelegateCommand<WorkOrderSummaryViewModel> _selectTicketCommand;
|
||||
private readonly AsyncDelegateCommand _createTicketCommand;
|
||||
private readonly AsyncDelegateCommand _sendMessageCommand;
|
||||
private readonly AsyncDelegateCommand<PendingAttachmentViewModel> _removePendingAttachmentCommand;
|
||||
private readonly AsyncDelegateCommand _loadEarlierMessagesCommand;
|
||||
private readonly AsyncDelegateCommand _retryRealtimeCommand;
|
||||
private readonly DelegateCommand<FrameworkElement> _addImagesCommand;
|
||||
private readonly HashSet<string> _seenEventIds =
|
||||
new HashSet<string>(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, int> _lastReadSequences =
|
||||
@@ -57,6 +63,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
private string _chatText;
|
||||
private string _draftText;
|
||||
private string _ticketSearchText = string.Empty;
|
||||
private int _selectedTicketStatusIndex;
|
||||
private bool _isDraft;
|
||||
private bool _isBusy;
|
||||
private bool _isLoading;
|
||||
@@ -88,6 +95,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
|
||||
Tickets = new ObservableCollection<WorkOrderSummaryViewModel>();
|
||||
Messages = new ObservableCollection<ChatMessageViewModel>();
|
||||
PendingAttachments = new ObservableCollection<PendingAttachmentViewModel>();
|
||||
TicketView = CollectionViewSource.GetDefaultView(Tickets);
|
||||
TicketView.Filter = FilterTicket;
|
||||
_selectTicketCommand = new AsyncDelegateCommand<WorkOrderSummaryViewModel>(
|
||||
@@ -99,12 +107,19 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
_sendMessageCommand = new AsyncDelegateCommand(
|
||||
SendMessageAsync,
|
||||
CanSendMessage);
|
||||
_removePendingAttachmentCommand =
|
||||
new AsyncDelegateCommand<PendingAttachmentViewModel>(
|
||||
RemovePendingAttachmentAsync,
|
||||
attachment => attachment != null && !IsBusy);
|
||||
_loadEarlierMessagesCommand = new AsyncDelegateCommand(
|
||||
LoadEarlierMessagesAsync,
|
||||
() => !IsBusy && SelectedTicket != null && HasMoreMessages);
|
||||
_retryRealtimeCommand = new AsyncDelegateCommand(
|
||||
RestartRealtimeAsync,
|
||||
() => !IsBusy && _configured);
|
||||
() => _configured);
|
||||
_addImagesCommand = new DelegateCommand<FrameworkElement>(
|
||||
AddImages,
|
||||
_ => CanAddImage);
|
||||
_ticketService.NotificationReceived += OnNotificationReceived;
|
||||
_ticketService.StateChanged += OnRealtimeStateChanged;
|
||||
SseState = _ticketService.RealtimeState;
|
||||
@@ -144,6 +159,40 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
/// </summary>
|
||||
public ICommand SendMessageCommand => _sendMessageCommand;
|
||||
|
||||
/// <summary>
|
||||
/// 移除待发送图片的命令。
|
||||
/// </summary>
|
||||
public ICommand RemovePendingAttachmentCommand => _removePendingAttachmentCommand;
|
||||
|
||||
/// <summary>
|
||||
/// 当前留言待发送的本地图片,最多 3 张。
|
||||
/// </summary>
|
||||
public ObservableCollection<PendingAttachmentViewModel> PendingAttachments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已选择待发送图片。
|
||||
/// </summary>
|
||||
public bool HasPendingAttachments => PendingAttachments.Count > 0;
|
||||
|
||||
/// <summary>
|
||||
/// 是否还可以继续选择图片。
|
||||
/// </summary>
|
||||
public bool CanAddImage =>
|
||||
!IsBusy
|
||||
&& SelectedTicket != null
|
||||
&& PendingAttachments.Count < TicketApiService.MaxImageCount;
|
||||
|
||||
/// <summary>
|
||||
/// 选择本地图片并加入当前留言的待发送列表。
|
||||
/// </summary>
|
||||
public ICommand AddImagesCommand => _addImagesCommand;
|
||||
|
||||
/// <summary>
|
||||
/// 待发送图片数量展示文本。
|
||||
/// </summary>
|
||||
public string AttachmentCountText =>
|
||||
PendingAttachments.Count + " / " + TicketApiService.MaxImageCount;
|
||||
|
||||
/// <summary>
|
||||
/// 加载当前工单更早留言的命令。
|
||||
/// </summary>
|
||||
@@ -154,10 +203,23 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
/// </summary>
|
||||
public ICommand RetryRealtimeCommand => _retryRealtimeCommand;
|
||||
|
||||
/// <summary>
|
||||
/// 当前正在查看的历史工单。
|
||||
/// </summary>
|
||||
public WorkOrderSummaryViewModel SelectedTicket
|
||||
/// <summary>
|
||||
/// 显示图片
|
||||
/// </summary>
|
||||
public ICommand ShowImageWindowCommand => new DelegateCommand<ChatAttachmentViewModel>(ShowImageWindow);
|
||||
/// <summary>
|
||||
/// 显示图片
|
||||
/// </summary>
|
||||
/// <param name="chatAttachment"></param>
|
||||
private void ShowImageWindow(ChatAttachmentViewModel chatAttachment)
|
||||
{
|
||||
ImageViewerWindow.OpenDialog(chatAttachment.Image);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前正在查看的历史工单。
|
||||
/// </summary>
|
||||
public WorkOrderSummaryViewModel SelectedTicket
|
||||
{
|
||||
get => _selectedTicket;
|
||||
private set
|
||||
@@ -167,6 +229,8 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
RaisePropertyChanged(nameof(IsChatVisible));
|
||||
RaisePropertyChanged(nameof(IsEmptyVisible));
|
||||
RaisePropertyChanged(nameof(ComposerPlaceholder));
|
||||
RaisePropertyChanged(nameof(CanAddImage));
|
||||
_addImagesCommand.RaiseCanExecuteChanged();
|
||||
RaiseSendCanExecuteChanged();
|
||||
RaiseLoadEarlierCanExecuteChanged();
|
||||
}
|
||||
@@ -240,6 +304,19 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 历史工单状态页签索引:0 全部、1 待客服回复、2 客服已回复、3 已完结。
|
||||
/// </summary>
|
||||
public int SelectedTicketStatusIndex
|
||||
{
|
||||
get => _selectedTicketStatusIndex;
|
||||
set
|
||||
{
|
||||
if (SetValue(ref _selectedTicketStatusIndex, value))
|
||||
TicketView?.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前是否处于新建工单草稿状态。
|
||||
/// </summary>
|
||||
@@ -253,6 +330,8 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
RaisePropertyChanged(nameof(IsChatVisible));
|
||||
RaisePropertyChanged(nameof(IsEmptyVisible));
|
||||
RaisePropertyChanged(nameof(IsDraftVisible));
|
||||
RaisePropertyChanged(nameof(CanAddImage));
|
||||
_addImagesCommand.RaiseCanExecuteChanged();
|
||||
RaiseCreateCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
@@ -269,11 +348,14 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
if (SetValue(ref _isBusy, value))
|
||||
{
|
||||
RaisePropertyChanged(nameof(IsNotBusy));
|
||||
RaisePropertyChanged(nameof(CanAddImage));
|
||||
RaiseSendCanExecuteChanged();
|
||||
RaiseCreateCanExecuteChanged();
|
||||
_removePendingAttachmentCommand.RaiseCanExecuteChanged();
|
||||
RaiseLoadEarlierCanExecuteChanged();
|
||||
_retryRealtimeCommand.RaiseCanExecuteChanged();
|
||||
_selectTicketCommand.RaiseCanExecuteChanged();
|
||||
_addImagesCommand.RaiseCanExecuteChanged();
|
||||
if (!value && !string.IsNullOrWhiteSpace(_pendingOpenKey))
|
||||
_ = SelectPendingTicketAsync();
|
||||
}
|
||||
@@ -624,6 +706,146 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
CancelDraft();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把文件选择器返回的本地图片加入待发送列表。
|
||||
/// 每次留言最多 3 张,单张不超过 5 MiB。
|
||||
/// </summary>
|
||||
public void AddPendingImages(IEnumerable<string> filePaths)
|
||||
{
|
||||
if (filePaths == null || IsBusy || IsDraft || SelectedTicket == null)
|
||||
return;
|
||||
|
||||
var errors = new List<string>();
|
||||
var added = 0;
|
||||
foreach (var filePath in filePaths)
|
||||
{
|
||||
if (PendingAttachments.Count >= TicketApiService.MaxImageCount)
|
||||
{
|
||||
errors.Add("每次留言最多上传 3 张图片。");
|
||||
break;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(filePath))
|
||||
continue;
|
||||
|
||||
string fullPath;
|
||||
try
|
||||
{
|
||||
fullPath = Path.GetFullPath(filePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
errors.Add("图片路径无效:" + filePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PendingAttachments.Any(item =>
|
||||
string.Equals(item.FilePath, fullPath, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!PendingAttachmentViewModel.TryCreate(
|
||||
fullPath,
|
||||
out var attachment,
|
||||
out var error))
|
||||
{
|
||||
errors.Add(error);
|
||||
continue;
|
||||
}
|
||||
|
||||
PendingAttachments.Add(attachment);
|
||||
added++;
|
||||
}
|
||||
|
||||
OnPendingAttachmentsChanged();
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
SetNotice(
|
||||
string.Join(" ", errors.Distinct(StringComparer.Ordinal)),
|
||||
true);
|
||||
}
|
||||
else if (added > 0)
|
||||
{
|
||||
ClearNotice();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将剪贴板中的位图加入待发送列表。
|
||||
/// </summary>
|
||||
public void AddPendingImage(System.Windows.Media.Imaging.BitmapSource bitmap)
|
||||
{
|
||||
if (IsBusy || IsDraft || SelectedTicket == null)
|
||||
return;
|
||||
if (PendingAttachments.Count >= TicketApiService.MaxImageCount)
|
||||
{
|
||||
SetNotice("每次留言最多上传 3 张图片。", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PendingAttachmentViewModel.TryCreateTemporary(
|
||||
bitmap, out var attachment, out var error))
|
||||
{
|
||||
SetNotice(error, true);
|
||||
return;
|
||||
}
|
||||
|
||||
PendingAttachments.Add(attachment);
|
||||
OnPendingAttachmentsChanged();
|
||||
ClearNotice();
|
||||
}
|
||||
|
||||
private void AddImages(FrameworkElement commandSource)
|
||||
{
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
Title = "选择图片",
|
||||
Filter = "图片文件 (*.jpg;*.jpeg;*.png;*.webp)|*.jpg;*.jpeg;*.png;*.webp",
|
||||
CheckFileExists = true,
|
||||
Multiselect = true
|
||||
};
|
||||
|
||||
var owner = commandSource == null ? null : Window.GetWindow(commandSource);
|
||||
var selected = owner == null
|
||||
? dialog.ShowDialog()
|
||||
: dialog.ShowDialog(owner);
|
||||
if (selected == true)
|
||||
AddPendingImages(dialog.FileNames);
|
||||
}
|
||||
|
||||
private Task RemovePendingAttachmentAsync(
|
||||
PendingAttachmentViewModel attachment)
|
||||
{
|
||||
if (attachment == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (PendingAttachments.Remove(attachment))
|
||||
attachment.Dispose();
|
||||
OnPendingAttachmentsChanged();
|
||||
ClearNotice();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void ClearPendingAttachments()
|
||||
{
|
||||
foreach (var attachment in PendingAttachments)
|
||||
attachment.Dispose();
|
||||
if (PendingAttachments.Count > 0)
|
||||
PendingAttachments.Clear();
|
||||
_pendingMessageFingerprint = null;
|
||||
_pendingMessageId = null;
|
||||
OnPendingAttachmentsChanged();
|
||||
}
|
||||
|
||||
private void OnPendingAttachmentsChanged()
|
||||
{
|
||||
RaisePropertyChanged(nameof(HasPendingAttachments));
|
||||
RaisePropertyChanged(nameof(CanAddImage));
|
||||
RaisePropertyChanged(nameof(AttachmentCountText));
|
||||
RaiseSendCanExecuteChanged();
|
||||
_removePendingAttachmentCommand.RaiseCanExecuteChanged();
|
||||
_addImagesCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
public void Configure(TicketClientOptions options)
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -652,6 +874,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
DraftText = string.Empty;
|
||||
Tickets.Clear();
|
||||
Messages.Clear();
|
||||
ClearPendingAttachments();
|
||||
|
||||
if (_options.AppIds == null || _options.AppIds.Count == 0)
|
||||
{
|
||||
@@ -826,6 +1049,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
return;
|
||||
SaveWorkOrderList();
|
||||
_disposed = true;
|
||||
ClearPendingAttachments();
|
||||
_ticketService.NotificationReceived -= OnNotificationReceived;
|
||||
_ticketService.StateChanged -= OnRealtimeStateChanged;
|
||||
_ticketService.Dispose();
|
||||
@@ -842,6 +1066,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
IsDraft = true;
|
||||
SelectedTicket = null;
|
||||
Messages.Clear();
|
||||
ClearPendingAttachments();
|
||||
HasMoreMessages = false;
|
||||
_nextBefore = null;
|
||||
DraftText = string.Empty;
|
||||
@@ -861,6 +1086,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
IsDraft = false;
|
||||
SelectedOrder = null;
|
||||
DraftText = string.Empty;
|
||||
ClearPendingAttachments();
|
||||
_pendingCreateFingerprint = null;
|
||||
_pendingCreateRequestId = null;
|
||||
ClearNotice();
|
||||
@@ -904,6 +1130,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
|
||||
TicketSearchText = string.Empty;
|
||||
CancelDraft();
|
||||
ClearPendingAttachments();
|
||||
ApplyKnownProductInfo(ticket);
|
||||
SelectedTicket = ticket;
|
||||
await LoadMessagesAsync(ticket, replace: true);
|
||||
@@ -987,7 +1214,11 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
|
||||
var ticket = SelectedTicket;
|
||||
var text = (ChatText ?? string.Empty).Trim();
|
||||
var fingerprint = ticket.Key + "|" + text;
|
||||
var pendingAttachments = PendingAttachments.ToList();
|
||||
var attachmentFingerprint = string.Join(
|
||||
"|",
|
||||
pendingAttachments.Select(item => item.Fingerprint));
|
||||
var fingerprint = ticket.Key + "|" + text + "|" + attachmentFingerprint;
|
||||
if (!string.Equals(
|
||||
fingerprint,
|
||||
_pendingMessageFingerprint,
|
||||
@@ -1001,32 +1232,88 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
ClearNotice();
|
||||
try
|
||||
{
|
||||
var receipts = new List<MessageAttachmentReceipt>();
|
||||
for (var index = 0; index < pendingAttachments.Count; index++)
|
||||
{
|
||||
var attachment = pendingAttachments[index];
|
||||
if (!attachment.HasReceipt)
|
||||
{
|
||||
SetNotice(
|
||||
"正在上传图片 "
|
||||
+ (index + 1)
|
||||
+ "/"
|
||||
+ pendingAttachments.Count
|
||||
+ "…",
|
||||
false);
|
||||
var uploadTicket =
|
||||
await _ticketService.CreateImageUploadTicketAsync(
|
||||
_options,
|
||||
ticket.AppId,
|
||||
ticket.WechatOrderId,
|
||||
attachment.FileName,
|
||||
attachment.MimeType,
|
||||
attachment.ByteSize);
|
||||
var receipt = await _ticketService.UploadImageAsync(
|
||||
uploadTicket.Upload,
|
||||
attachment.FilePath);
|
||||
attachment.SetReceipt(receipt);
|
||||
}
|
||||
receipts.Add(attachment.Receipt);
|
||||
}
|
||||
|
||||
if (pendingAttachments.Count > 0)
|
||||
SetNotice("正在发送留言…", false);
|
||||
|
||||
var result = await _ticketService.SendMessageAsync(
|
||||
_options,
|
||||
ToSummaryDto(ticket),
|
||||
text,
|
||||
_pendingMessageId);
|
||||
string.IsNullOrWhiteSpace(text) ? null : text,
|
||||
_pendingMessageId,
|
||||
receipts);
|
||||
|
||||
if (result.Message != null)
|
||||
AppendMessage(result.Message);
|
||||
ticket.ApplySendResult(result.Status, result.Version);
|
||||
MoveTicketToTop(ticket);
|
||||
TicketView.Refresh();
|
||||
ChatText = string.Empty;
|
||||
_pendingMessageFingerprint = null;
|
||||
_pendingMessageId = null;
|
||||
ClearPendingAttachments();
|
||||
SetNotice(
|
||||
result.Reopened
|
||||
? "留言已发送,已完结工单已重新开启。"
|
||||
: "留言已发送。",
|
||||
: (pendingAttachments.Count > 0
|
||||
? "图片已发送。"
|
||||
: "留言已发送。"),
|
||||
false);
|
||||
await MarkReadBestEffortAsync(ticket);
|
||||
SaveWorkOrderList();
|
||||
MessageScrollVersion++;
|
||||
}
|
||||
catch (TicketApiException ex)
|
||||
when (ex.StatusCode == 409)
|
||||
when (ex.StatusCode == 410
|
||||
|| string.Equals(
|
||||
ex.ErrorCode,
|
||||
"client_api_image_expired",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
SetNotice("工单状态或数据版本发生冲突,正在刷新最新内容。", true);
|
||||
foreach (var attachment in PendingAttachments)
|
||||
attachment.ClearReceipt();
|
||||
_pendingMessageFingerprint = null;
|
||||
_pendingMessageId = null;
|
||||
SetNotice(
|
||||
"图片上传凭证已过期,已重置上传状态,请重新点击发送。",
|
||||
true);
|
||||
}
|
||||
catch (TicketApiException ex)
|
||||
when (ex.StatusCode == 409
|
||||
|| string.Equals(
|
||||
ex.ErrorCode,
|
||||
"client_api_image_already_used",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var attachment in PendingAttachments)
|
||||
attachment.ClearReceipt();
|
||||
SetNotice("工单状态或图片回执发生冲突,正在刷新最新内容。", true);
|
||||
_pendingMessageFingerprint = null;
|
||||
_pendingMessageId = null;
|
||||
await RefreshAllWorkOrdersAsync(
|
||||
@@ -1256,6 +1543,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
ApplyKnownProductInfo(existing);
|
||||
SaveWorkOrderList();
|
||||
ReorderTickets();
|
||||
TicketView.Refresh();
|
||||
if (SelectedTicket != null
|
||||
&& string.Equals(SelectedTicket.Key, key, StringComparison.Ordinal)
|
||||
&& !IsDraft)
|
||||
@@ -1276,7 +1564,9 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
var id = dto.MessageId;
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
id = "sequence:" + dto.SequenceNo;
|
||||
if (!byId.ContainsKey(id))
|
||||
if (byId.TryGetValue(id, out var existing))
|
||||
existing.UpdateFrom(dto);
|
||||
else
|
||||
byId[id] = new ChatMessageViewModel(dto);
|
||||
}
|
||||
|
||||
@@ -1450,6 +1740,13 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
if (!(item is WorkOrderSummaryViewModel ticket))
|
||||
return false;
|
||||
|
||||
var expectedStatus = GetStatusFilter(SelectedTicketStatusIndex);
|
||||
if (expectedStatus != null
|
||||
&& !string.Equals(ticket.Status, expectedStatus, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var keyword = (TicketSearchText ?? string.Empty).Trim();
|
||||
if (keyword.Length == 0)
|
||||
return true;
|
||||
@@ -1461,6 +1758,21 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
|| ContainsIgnoreCase(ticket.PreviewText, keyword);
|
||||
}
|
||||
|
||||
private static string GetStatusFilter(int selectedIndex)
|
||||
{
|
||||
switch (selectedIndex)
|
||||
{
|
||||
case 1:
|
||||
return "waiting_reply";
|
||||
case 2:
|
||||
return "replied";
|
||||
case 3:
|
||||
return "completed";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ContainsIgnoreCase(string source, string keyword)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(source)
|
||||
@@ -1469,10 +1781,11 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
|
||||
private bool CanSendMessage()
|
||||
{
|
||||
var text = (ChatText ?? string.Empty).Trim();
|
||||
return !IsBusy
|
||||
&& SelectedTicket != null
|
||||
&& !string.IsNullOrWhiteSpace(ChatText)
|
||||
&& ChatText.Trim().Length <= 4000;
|
||||
&& (!string.IsNullOrWhiteSpace(text) || PendingAttachments.Count > 0)
|
||||
&& text.Length <= 4000;
|
||||
}
|
||||
|
||||
private void RaiseSendCanExecuteChanged()
|
||||
@@ -1768,9 +2081,10 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
{
|
||||
400 => "请求格式错误。",
|
||||
404 => "该 APPID 和订单下尚无工单。",
|
||||
409 => "数据版本或幂等编号冲突。",
|
||||
409 => "数据版本、幂等编号或图片回执冲突。",
|
||||
410 => "图片上传凭证已过期。",
|
||||
413 => "请求内容超过大小限制。",
|
||||
422 => "参数或订单归属校验失败。",
|
||||
422 => "参数、图片格式或订单归属校验失败。",
|
||||
429 => "请求过于频繁,请稍后重试。",
|
||||
503 => "工单服务暂未开启或数据库繁忙。",
|
||||
_ => null
|
||||
|
||||
Reference in new issue
Block a user