using _29WxOrderWpf.CefHelper; using _29WxOrderWpf.Commands; using AllBase; using AllBase.Helper; using AllBase.Model.DBModel; using AllBase.Model.MvvmBaseClasses; using AllBase.Model.Result; using CefSharp; using CefSharp.Handler; using CefSharp.Wpf; using NaiBa.Util.Extension; using NPOI.SS.Formula.Functions; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using TemuKJD.ToolForms; using Work; using Work._29Tools.BLL; using Work._29Tools.CefTools; namespace _29WxOrderWpf.ViewModels { /// /// 拼多多买手移动版登录窗口 视图模型(WPF 版 PddMobileLoginForm) /// public class PddMobileLoginViewModel : PropertyNotifyObject { // 拼多多买手退货退款售后地址 // https://mobile.yangkeduo.com/complaint.html?order_sn=260718-101481213440980&after_sales_reason=0&after_sales_type=2&after_sales_code=1002 Dictionary dicPddPickInfo = new Dictionary(); public static PddMobileLoginViewModel PddMobileLoginInstance { get; set; } = null; /// 浏览器创建完成后触发(视图在此把浏览器加入可视树) public event Action BrowserCreated; /// 请求关闭窗口 public event Action RequestClose; public int CloseAfterSecond { get; set; } private EnumOpenType _openType = EnumOpenType.manage; public EnumOpenType OpenType { get { return _openType; } set { _openType = value; OnPropertyChanged(nameof(OpenType)); OnPropertyChanged(nameof(IsLoginMode)); } } public string InitUrl { get; set; } = ""; private string shopCookieHead = "yangkeduo.com"; private string shopLoginUrl = "https://mobile.yangkeduo.com/login.html?from=https%3A%2F%2Fmobile.yangkeduo.com%2Fpersonal.html"; private string shopMainUrl = "https://mobile.yangkeduo.com/index.html"; public ChromiumWebBrowser CefWebBrowser { get; private set; } private BuyerLoginInfo buyer = null; private List lstShopCompany = new List(); private string currentUrl = ""; private volatile bool _isWindowLoaded = false; #region 界面绑定属性 /// 用户名 public string UserName { get { return this.GetValue(x => x.UserName); } set { this.SetValue(x => x.UserName, value); } } /// 密码 public string PassWord { get { return this.GetValue(x => x.PassWord); } set { this.SetValue(x => x.PassWord, value); } } /// 地址栏 public string Address { get { return this.GetValue(x => x.Address); } set { this.SetValue(x => x.Address, value); } } /// 登录成功后关闭窗口 public bool IsCloseAfterLogin { get { return this.GetValue(x => x.IsCloseAfterLogin); } set { this.SetValue(x => x.IsCloseAfterLogin, value); } } /// 登录模式(显示扫码提示和导入PDDAccessToken面板) public bool IsLoginMode { get { return this.GetValue(x => x.IsLoginMode); } set { this.SetValue(x => x.IsLoginMode, value); } } /// 导入的PDDAccessToken public string AccessToken { get { return this.GetValue(x => x.AccessToken); } set { this.SetValue(x => x.AccessToken, value); } } #endregion #region 命令 public ICommand ReloadCommand { get; } public ICommand LoginAgainCommand { get; } public ICommand StopCommand { get; } public ICommand CopyUserNameCommand { get; } public ICommand CopyPasswordCommand { get; } public ICommand SaveCookieCommand { get; } #endregion public PddMobileLoginViewModel(BuyerLoginInfo buyerInfo) { PddMobileLoginInstance = this; buyer = buyerInfo; UserName = buyerInfo?.buyer_name; PassWord = ""; //DataOpenSSL.DecryptString(buyerInfo.Password); IsCloseAfterLogin = true; IsLoginMode = OpenType == EnumOpenType.login; ReloadCommand = new DelegateCommand(Reload); LoginAgainCommand = new DelegateCommand(LoginAgain); StopCommand = new DelegateCommand(StopButton); CopyUserNameCommand = new DelegateCommand(CopyUserName); CopyPasswordCommand = new DelegateCommand(CopyPassword); SaveCookieCommand = new DelegateCommand(SaveCookie); } /// /// 窗口加载完成时调用 /// public void Start() { IsLoginMode = OpenType == EnumOpenType.login; _isWindowLoaded = true; if (CloseAfterSecond > 0) { Task.Run(() => { Thread.Sleep(1000 * CloseAfterSecond); if (_isWindowLoaded) { Application.Current?.Dispatcher.Invoke(new Action(() => { if (_isWindowLoaded) RequestClose?.Invoke(); })); } }); } Task.Run(() => { AutoLogin(); }); } /// /// 窗口关闭时调用,停止后台任务 /// public void Stop() { _isWindowLoaded = false; } /// /// 自动登录店铺后台 /// private async void AutoLogin() { if (OpenType != EnumOpenType.login && buyer == null) return; _ = Application.Current.Dispatcher.InvokeAsync(async () => { if (CefWebBrowser == null) { if (!string.IsNullOrEmpty(InitUrl)) CefWebBrowser = WPFCEFBrowser.CreateChromiumWebBrowser(InitUrl, false); else CefWebBrowser = WPFCEFBrowser.CreateChromiumWebBrowser(shopMainUrl, false); LocalResourceRequestHandler resourceRequestHandler = new LocalResourceRequestHandler(); resourceRequestHandler.ResourceLoadCompleteEvent += RequestHandler_ResourceLoadComplete; resourceRequestHandler.BeforeResourceLoadEvent += RequestHandler_BeforeResourceLoad; CefWebBrowser.RequestHandler = new LocalRequestHandler(resourceRequestHandler); var lifeSapnHandler = new LocalLifeSpanHandler(PopWindowType.SelfWindow); CefWebBrowser.LifeSpanHandler = lifeSapnHandler; CefWebBrowser.KeyboardHandler = new CefKeyboardHandler(); CefWebBrowser.FrameLoadEnd += CefWebBrowser_FrameLoadEnd; CefWebBrowser.AddressChanged += CefWebBrowser_AddressChanged; CefWebBrowser.LoadError += CefWebBrowser_LoadError; // 通知视图把浏览器加入可视树(必须在等待浏览器初始化之前完成) BrowserCreated?.Invoke(CefWebBrowser); List cookieLst = new List(); try { if (buyer != null) { cookieLst = JsonHelper.DeserializeJsonToList(buyer?.cookie); if (cookieLst == null) cookieLst = new List(); } } catch { } // cef138必须init后方可设置或删除cookie while (!CefWebBrowser.IsBrowserInitialized || !CefWebBrowser.GetBrowser().MainFrame.IsValid) await Task.Delay(20); WPFCEFBrowser.DeleteCookie(CefWebBrowser.GetCookieManager(null)); //cef 138 如果没有设置RequestContext 可能为空,直接getCookieManager var t = WPFCEFBrowser.SetCookieAsync(JsonHelper.SerializeObject(cookieLst), CefWebBrowser.GetCookieManager(null)); foreach (var cook in cookieLst) { //var t = CEFBrowser.SetCookieAsync(cook.Domain.Trim('.'), cook.Name + "=" + cook.Value + ";", CefWebBrowser.GetCookieManager(null)); //t.Wait(5000); } //根据登录的具体店铺设置local storage if (!string.IsNullOrEmpty(buyer?.buyer_id)) { //var storageJsCode = "window.localStorage.setItem('" + "mall-info-id" + "', '" + shop.ShopId + "');\r\n"; //storageJsCode += "window.localStorage.setItem('" + "agentseller-mall-info-id" + "', '" + shop.ShopId + "');\r\n"; //while (!CefWebBrowser.IsBrowserInitialized || !CefWebBrowser.GetBrowser().MainFrame.IsValid) // Thread.Sleep(20); //CefWebBrowser.GetBrowser().MainFrame.ExecuteJavaScriptAsync(storageJsCode); } if (!string.IsNullOrEmpty(InitUrl)) CefWebBrowser.Load(InitUrl); else CefWebBrowser.Load(shopMainUrl); //不是登录的话就此返回 if (OpenType != EnumOpenType.login) { return; } for (int i = 0; i < 50; i++) { if (CefWebBrowser.IsLoading) await Task.Delay(100); //Thread.Sleep(100); } await Task.Delay(Randomx.GetId(1500, 2000)); if (!_isWindowLoaded) return; while (!CefWebBrowser.Address?.StartsWith(shopLoginUrl) ?? false) { await Task.Delay(1000); if (!_isWindowLoaded) return; } } }); } private void CefWebBrowser_LoadError(object sender, CefSharp.LoadErrorEventArgs e) { } private void CefWebBrowser_AddressChanged(object sender, DependencyPropertyChangedEventArgs e) { if (Application.Current?.Dispatcher != null) { Application.Current.Dispatcher.Invoke(new Action(() => { currentUrl = e.NewValue.ParseToString(); Address = e.NewValue.ParseToString(); })); } } private void CefWebBrowser_FrameLoadEnd(object sender, CefSharp.FrameLoadEndEventArgs e) { //js绑定C#对象 html页面内声明绑定的C#对象 StringBuilder sb = new StringBuilder(); sb.Append("(function(){"); sb.Append("CefSharp.BindObjectAsync('shopObj');"); sb.Append("})();"); CefWebBrowser.GetBrowser().MainFrame.EvaluateScriptAsync(sb.ToString()); } private bool RequestHandler_BeforeResourceLoad(object sender, string url, string postData, IRequest request) { return false; } private void RequestHandler_ResourceLoadComplete(object sender, string url, string postData, string responseData, IRequest request) { var data = responseData; var send = sender; if (data.Contains("\"pick_code\":\"取件码") /*|| data.Contains("21-2110")*/) { try { var combine_track_list = BaseRegex.GetJsonArrStrJson(ref data, "combine_track_list"); var noPickupPackageData = BaseRegex.GetJsonObjStrJson(ref data, "noPickupPackageData").FirstOrDefault(); if (!noPickupPackageData.IsNullOrEmpty() && send is ChromiumWebBrowser cef) { var buyer = GlobalConfig.PDDBuyerLoginList.FirstOrDefault(buy => buy.wpf_browser == cef); if (buyer != null) { dicPddPickInfo[buyer] = JsonHelper.DeserializeJsonToObject(noPickupPackageData); } } } catch { } } if (url.Contains("https://mobile.yangkeduo.com/index.html") && OpenType == EnumOpenType.login) { Task.Run(() => { CefWebBrowser.Load("https://mobile.yangkeduo.com/personal.html"); }); } if (url.Contains("https://mobile.yangkeduo.com/personal.html")) { if (OpenType == EnumOpenType.login) { Task.Run(() => { var data = responseData; if (data.Contains("\"success\":true") || data.Contains("nickname")) { var uid = BaseRegex.GetStringJson(ref data, "uid"); var nickname = BaseRegex.GetStringJson(ref data, "nickname"); var username = nickname; if (!string.IsNullOrEmpty(nickname) && !string.IsNullOrEmpty(uid)) { Thread.Sleep(2000); List cookieList = WPFCEFBrowser.GetCookieList(shopCookieHead, CefWebBrowser.GetCookieManager(null)); var buyerUrl = BaseClass.Build29PDDObjString("user/add_buyer"); if (this.buyer == null || this.buyer.buyer_id != uid) this.buyer = GlobalConfig.PDDBuyerLoginList.FirstOrDefault(b => b.buyer_id == uid); if (this.buyer != null) { this.buyer.user_name = username; this.buyer.buyer_nick = nickname; this.buyer.cookie = JsonHelper.SerializeObject(cookieList); buyerUrl = BaseClass.Build29PDDObjString("user/mdy_buyer"); } var buyerData = UserLogin.GetSignaturex() + "&buyer_id=" + uid + "&buyer_name=" + username + "&buyer_nick=" + nickname; var result = GetHtml.PostUtf8(buyerUrl, buyerData); if (string.IsNullOrEmpty(result) || !result.Contains("\"code\":200")) result = GetHtml.PostUtf8(buyerUrl, buyerData); buyerUrl = BaseClass.Build29PDDObjString("user/mdy_buyer_cookie"); buyerData = UserLogin.GetSignaturex() + "&buyer_id=" + uid + "&status=" + "在线" + "&cookie=" + GetHtml.UrlEncodeUtf8(JsonHelper.SerializeObject(cookieList)); result = GetHtml.PostUtf8(buyerUrl, buyerData); if (string.IsNullOrEmpty(result) || !result.Contains("\"code\":200")) result = GetHtml.PostUtf8(buyerUrl, buyerData); Application.Current?.Dispatcher.Invoke(new Action(() => { try { if (IsCloseAfterLogin) RequestClose?.Invoke(); } catch (Exception ex) { } })); } } }); } } } private void StopButton() { } private void CopyUserName() { if (!string.IsNullOrEmpty(UserName)) Clipboard.SetDataObject(UserName); } private void CopyPassword() { if (!string.IsNullOrEmpty(PassWord)) Clipboard.SetDataObject(PassWord); } private void Reload() { if (CefWebBrowser != null) { if (Address != "about:blank") CefWebBrowser.Load(Address); else CefWebBrowser.Load(shopMainUrl); } } private void LoginAgain() { if (this.currentUrl != shopLoginUrl) this.CefWebBrowser?.Load(shopLoginUrl); } private void SaveCookie() { Cookie cookie = new Cookie(); cookie.Name = "PDDAccessToken"; cookie.Domain = "mobile.yangkeduo.com"; cookie.Expires = DateTime.Now.AddDays(465); cookie.HttpOnly = true; cookie.Secure = true; cookie.Value = AccessToken.Trim(); if (this.CefWebBrowser != null) { var t = WPFCEFBrowser.SetCookieAsync(JsonHelper.SerializeObject(new List { cookie }), CefWebBrowser.GetCookieManager(null)); t.Wait(2000); CefWebBrowser.Load("https://mobile.yangkeduo.com/personal.html"); } } #region 静态方法(检测/更新买手登录状态) public static void CheckBuyerLogin(List checkBuyers, bool isShowProgress = true) { for (int i = 0; i < checkBuyers.Count; i++) { var buyer = GlobalConfig.PDDBuyerLoginList.FirstOrDefault(v => v.buyer_id == checkBuyers[i].buyer_id); var buys = GlobalConfig.PDDBuyerLoginList.Where(v => v.buyer_id == checkBuyers[i].buyer_id).ToList(); if (buyer == null) continue; // 先从服务端取最新cookie var url = BaseClass.Build29PDDObjString("user/get_buyer"); var data = UserLogin.GetSignaturex(); data += "&buyer_ids=" + buyer.buyer_id; data += "&page_size=1"; var result = GetHtml.PostUtf8(url, data); if (string.IsNullOrEmpty(result) || !result.Contains("\"code\":200")) result = GetHtml.PostUtf8(url, data); if (!result.Contains("\"code\":200")) continue; List loginInfoLst = JsonHelper.DeserializeJsonToList(JsonHelper.JObjectParse(result)["data"].ParseToString()); var serverBuyer = loginInfoLst.FirstOrDefault(); if (buyer != null && serverBuyer != null) { buyer.cookie = serverBuyer.cookie; foreach (var buy in buys) { buy.cookie = serverBuyer.cookie; } } if (buyer != null) { var loginResult = CheckBuyerLogin(buyer); if (!loginResult.Contains("\"success\":true") && !loginResult.Contains("\"login\":true") && !loginResult.Contains("\"nickname\"")) { buyer.cookie = "[]"; foreach (var buy in buys) { buy.status = "掉线"; buy.cookie = "[]"; } } else { foreach (var buy in buys) { buy.status = "在线"; } } UpdateServerBuyerCookies(buyer); // 店铺cookie和状态写入服务端 } } } public static string CheckBuyerLogin(BuyerLoginInfo buyer, string refere = "https://mobile.yangkeduo.com/goods.html") { string url = "https://mobile.yangkeduo.com/proxy/api/api/apollo/v3/user/me?pdduid=" + buyer.buyer_id; return HttpResponseYkdBLL.YangkeduoGetResponse(buyer, url, refere); } public static string UpdateServerBuyerCookies(BuyerLoginInfo buyer, string fromTool = null) { var url = BaseClass.Build29PDDObjString("user/mdy_buyer_cookie"); var data = UserLogin.GetSignaturex() + "&status=" + buyer.status + "&cookie=" + GetHtml.UrlEncodeUtf8(buyer.cookie) + "&buyer_id=" + buyer.buyer_id; var result = GetHtml.PostUtf8(url, data); if (!result.Contains("\"code\":200")) result = GetHtml.PostUtf8(url, data); return result; } #endregion } }