using _29WxOrderWpf.ToolCtrls; using OrderSupportTicket.Models; using OrderSupportTicket.Services; using OrderSupportTicket.ViewModels; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace OrderSupportTicket.Views; /// /// 工单对话页面。页面生命周期只负责激活/停用 ViewModel,业务交互均在 ViewModel 中。 /// public partial class OrderSupportTicketView : UserControl { private bool _active; private Window _hostWindow; public OrderSupportTicketView() : this( new TicketApiService(), new EventSourceTicketRealtimeService(), CreateDefaultOptions(), ownsRealtime: true) { } public OrderSupportTicketView( ITicketApiService api, ITicketRealtimeService realtime, TicketClientOptions options = null) : this(api, realtime, options, ownsRealtime: true) { } /// /// 创建工单页。ownsRealtime 为 false 时复用宿主提供的共享 SSE 连接, /// 页面关闭不会停止该连接。 /// public OrderSupportTicketView( ITicketApiService api, ITicketRealtimeService realtime, TicketClientOptions options, bool ownsRealtime) { InitializeComponent(); ViewModel = new OrderSupportTicketViewModel( api, realtime, options ?? CreateDefaultOptions(), ownsRealtime); DataContext = ViewModel; Loaded += OnLoaded; Unloaded += OnUnloaded; } /// /// 当前联调使用的默认参数。正式接入时可由宿主替换为登录账号和店铺 APPID。 /// public static TicketClientOptions CreateDefaultOptions(string fallbackUserName = null) { var configured = TicketClientOptions.FromApplicationSettings(); var userName = !string.IsNullOrWhiteSpace(configured.UserName) ? configured.UserName : (!string.IsNullOrWhiteSpace(fallbackUserName) ? fallbackUserName.Trim() : "18990991234"); var appIds = configured.AppIds != null && configured.AppIds.Count > 0 ? configured.AppIds : new List { "wx316b1291351558aa", "wx7999743c3d64c05c" }; return new TicketClientOptions { UserName = userName, AppIds = appIds, Orders = [ new TicketOrderOption { Amount = 109m, AppId = "wx316b1291351558aa", GoodsName = "梵客隆收腹内裤女新款高腰无痕磨毛暖融收小肚子提臀塑身平角裤", OrderId = "9000000000000000001", OrderedAt = new DateTime(2020, 1, 1), }, new TicketOrderOption { Amount = 109m, AppId = "wx7999743c3d64c05c", GoodsName = "洁柔抽纸粉Face家用实惠装批发纸巾大包面纸餐巾纸抽整箱可湿水纸", OrderId = "9000000000000000002", OrderedAt = new DateTime(2020, 1, 1), } ] }; } /// /// 当前页面对应的工单 ViewModel。 /// public OrderSupportTicketViewModel ViewModel { get; } /// /// 宿主可在页面加载前注入账号、APPID 与本地订单数据。 /// public void Configure(TicketClientOptions options) { ViewModel.Configure(options); } /// /// 从订单页直接打开新工单草稿。 /// public void OpenNewTicket(TicketOrderOption order) { ViewModel.OpenNewTicket(order); } /// /// 打开并定位到指定工单。 /// public void OpenTicket(string appId, string wechatOrderId) { ViewModel.OpenTicket(appId, wechatOrderId); } private void TicketSearchBox_GotFocus(object sender, RoutedEventArgs e) { ViewModel.CancelNewTicketDraft(); } /// /// 点击订单号复制到剪贴板,并使用宿主窗口的 Toast 提示结果。 /// private void CopyOrderId_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (sender is not FrameworkElement element) return; var orderId = element.Tag as string; if (string.IsNullOrWhiteSpace(orderId) && element.DataContext is WorkOrderSummaryViewModel ticket) { orderId = ticket.WechatOrderId; } if (string.IsNullOrWhiteSpace(orderId)) return; var window = Window.GetWindow(this) ?? _hostWindow; if (window == null) return; if (ClipboardHelper.TrySetText(orderId)) { ToastHelper.Show(window, "订单号已复制"); } else { ToastHelper.Show(window, "复制失败"); } } private async void OnLoaded(object sender, System.Windows.RoutedEventArgs e) { if (_active) return; _active = true; AttachHostWindow(Window.GetWindow(this)); UpdateWindowActiveState(); await ViewModel.InitializeAsync(); } private async void OnUnloaded(object sender, System.Windows.RoutedEventArgs e) { if (!_active) return; _active = false; ViewModel.IsWindowActive = false; DetachHostWindow(); await ViewModel.DeactivateAsync(); } private void AttachHostWindow(Window window) { DetachHostWindow(); _hostWindow = window; if (_hostWindow == null) return; _hostWindow.Activated += OnHostWindowActivated; _hostWindow.Deactivated += OnHostWindowDeactivated; _hostWindow.IsVisibleChanged += OnHostWindowIsVisibleChanged; _hostWindow.StateChanged += OnHostWindowStateChanged; _hostWindow.Closed += OnHostWindowClosed; } private void DetachHostWindow() { if (_hostWindow == null) return; _hostWindow.Activated -= OnHostWindowActivated; _hostWindow.Deactivated -= OnHostWindowDeactivated; _hostWindow.IsVisibleChanged -= OnHostWindowIsVisibleChanged; _hostWindow.StateChanged -= OnHostWindowStateChanged; _hostWindow.Closed -= OnHostWindowClosed; _hostWindow = null; } private void UpdateWindowActiveState() { var window = _hostWindow; ViewModel.IsWindowActive = window != null && window.IsVisible && window.IsActive && window.WindowState != WindowState.Minimized; } private void OnHostWindowActivated(object sender, EventArgs e) { UpdateWindowActiveState(); } private void OnHostWindowDeactivated(object sender, EventArgs e) { UpdateWindowActiveState(); } private void OnHostWindowIsVisibleChanged( object sender, DependencyPropertyChangedEventArgs e) { UpdateWindowActiveState(); } private void OnHostWindowStateChanged(object sender, EventArgs e) { UpdateWindowActiveState(); } private void OnHostWindowClosed(object sender, EventArgs e) { ViewModel.IsWindowActive = false; DetachHostWindow(); } }