修复登录 UI线程bug
This commit is contained in:
1 parent
0eae9f7706
commit
20bfd2c22c
1 file changed
+493
-485
@@ -23,489 +23,497 @@ using Work._29Tools.CefTools;
|
||||
|
||||
namespace _29WxOrderWpf.ViewModels
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 拼多多买手移动版登录窗口 视图模型(WPF 版 PddMobileLoginForm)
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
public static PddMobileLoginViewModel PddMobileLoginInstance { get; set; } = null;
|
||||
|
||||
/// <summary>浏览器创建完成后触发(视图在此把浏览器加入可视树)</summary>
|
||||
public event Action<ChromiumWebBrowser> BrowserCreated;
|
||||
|
||||
/// <summary>请求关闭窗口</summary>
|
||||
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<ShopCompany> lstShopCompany = new List<ShopCompany>();
|
||||
private string currentUrl = "";
|
||||
private volatile bool _isWindowLoaded = false;
|
||||
|
||||
#region 界面绑定属性
|
||||
|
||||
/// <summary>用户名</summary>
|
||||
public string UserName
|
||||
{
|
||||
get { return this.GetValue(x => x.UserName); }
|
||||
set { this.SetValue(x => x.UserName, value); }
|
||||
}
|
||||
|
||||
/// <summary>密码</summary>
|
||||
public string PassWord
|
||||
{
|
||||
get { return this.GetValue(x => x.PassWord); }
|
||||
set { this.SetValue(x => x.PassWord, value); }
|
||||
}
|
||||
|
||||
/// <summary>地址栏</summary>
|
||||
public string Address
|
||||
{
|
||||
get { return this.GetValue(x => x.Address); }
|
||||
set { this.SetValue(x => x.Address, value); }
|
||||
}
|
||||
|
||||
/// <summary>登录成功后关闭窗口</summary>
|
||||
public bool IsCloseAfterLogin
|
||||
{
|
||||
get { return this.GetValue(x => x.IsCloseAfterLogin); }
|
||||
set { this.SetValue(x => x.IsCloseAfterLogin, value); }
|
||||
}
|
||||
|
||||
/// <summary>登录模式(显示扫码提示和导入PDDAccessToken面板)</summary>
|
||||
public bool IsLoginMode
|
||||
{
|
||||
get { return this.GetValue(x => x.IsLoginMode); }
|
||||
set { this.SetValue(x => x.IsLoginMode, value); }
|
||||
}
|
||||
|
||||
/// <summary>导入的PDDAccessToken</summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口加载完成时调用
|
||||
/// </summary>
|
||||
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();
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AutoLogin();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口关闭时调用,停止后台任务
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
_isWindowLoaded = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动登录店铺后台
|
||||
/// </summary>
|
||||
private void AutoLogin()
|
||||
{
|
||||
if (OpenType != EnumOpenType.login && buyer == null)
|
||||
return;
|
||||
|
||||
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 KeyboardHandler();
|
||||
CefWebBrowser.FrameLoadEnd += CefWebBrowser_FrameLoadEnd;
|
||||
CefWebBrowser.AddressChanged += CefWebBrowser_AddressChanged;
|
||||
CefWebBrowser.LoadError += CefWebBrowser_LoadError;
|
||||
|
||||
// 通知视图把浏览器加入可视树(必须在等待浏览器初始化之前完成)
|
||||
BrowserCreated?.Invoke(CefWebBrowser);
|
||||
|
||||
List<Cookie> cookieLst = new List<Cookie>();
|
||||
try
|
||||
{
|
||||
if (buyer != null)
|
||||
{
|
||||
cookieLst = JsonHelper.DeserializeJsonToList<CefSharp.Cookie>(buyer?.cookie);
|
||||
if (cookieLst == null)
|
||||
cookieLst = new List<Cookie>();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
// cef138必须init后方可设置或删除cookie
|
||||
while (!CefWebBrowser.IsBrowserInitialized || !CefWebBrowser.GetBrowser().MainFrame.IsValid)
|
||||
Thread.Sleep(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)
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
Thread.Sleep(Randomx.GetId(1500, 2000));
|
||||
|
||||
if (!_isWindowLoaded)
|
||||
return;
|
||||
|
||||
while (!CefWebBrowser.Address.StartsWith(shopLoginUrl))
|
||||
{
|
||||
Thread.Sleep(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)
|
||||
{
|
||||
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<Cookie> 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> { cookie }), CefWebBrowser.GetCookieManager(null));
|
||||
t.Wait(2000);
|
||||
CefWebBrowser.Load("https://mobile.yangkeduo.com/personal.html");
|
||||
}
|
||||
}
|
||||
|
||||
#region 静态方法(检测/更新买手登录状态)
|
||||
|
||||
public static void CheckBuyerLogin(List<BuyerLoginInfo> 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<BuyerLoginInfo> loginInfoLst = JsonHelper.DeserializeJsonToList<BuyerLoginInfo>(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
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 拼多多买手移动版登录窗口 视图模型(WPF 版 PddMobileLoginForm)
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
public static PddMobileLoginViewModel PddMobileLoginInstance { get; set; } = null;
|
||||
|
||||
/// <summary>浏览器创建完成后触发(视图在此把浏览器加入可视树)</summary>
|
||||
public event Action<ChromiumWebBrowser> BrowserCreated;
|
||||
|
||||
/// <summary>请求关闭窗口</summary>
|
||||
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<ShopCompany> lstShopCompany = new List<ShopCompany>();
|
||||
private string currentUrl = "";
|
||||
private volatile bool _isWindowLoaded = false;
|
||||
|
||||
#region 界面绑定属性
|
||||
|
||||
/// <summary>用户名</summary>
|
||||
public string UserName
|
||||
{
|
||||
get { return this.GetValue(x => x.UserName); }
|
||||
set { this.SetValue(x => x.UserName, value); }
|
||||
}
|
||||
|
||||
/// <summary>密码</summary>
|
||||
public string PassWord
|
||||
{
|
||||
get { return this.GetValue(x => x.PassWord); }
|
||||
set { this.SetValue(x => x.PassWord, value); }
|
||||
}
|
||||
|
||||
/// <summary>地址栏</summary>
|
||||
public string Address
|
||||
{
|
||||
get { return this.GetValue(x => x.Address); }
|
||||
set { this.SetValue(x => x.Address, value); }
|
||||
}
|
||||
|
||||
/// <summary>登录成功后关闭窗口</summary>
|
||||
public bool IsCloseAfterLogin
|
||||
{
|
||||
get { return this.GetValue(x => x.IsCloseAfterLogin); }
|
||||
set { this.SetValue(x => x.IsCloseAfterLogin, value); }
|
||||
}
|
||||
|
||||
/// <summary>登录模式(显示扫码提示和导入PDDAccessToken面板)</summary>
|
||||
public bool IsLoginMode
|
||||
{
|
||||
get { return this.GetValue(x => x.IsLoginMode); }
|
||||
set { this.SetValue(x => x.IsLoginMode, value); }
|
||||
}
|
||||
|
||||
/// <summary>导入的PDDAccessToken</summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口加载完成时调用
|
||||
/// </summary>
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口关闭时调用,停止后台任务
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
_isWindowLoaded = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动登录店铺后台
|
||||
/// </summary>
|
||||
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 KeyboardHandler();
|
||||
CefWebBrowser.FrameLoadEnd += CefWebBrowser_FrameLoadEnd;
|
||||
CefWebBrowser.AddressChanged += CefWebBrowser_AddressChanged;
|
||||
CefWebBrowser.LoadError += CefWebBrowser_LoadError;
|
||||
|
||||
// 通知视图把浏览器加入可视树(必须在等待浏览器初始化之前完成)
|
||||
BrowserCreated?.Invoke(CefWebBrowser);
|
||||
|
||||
List<Cookie> cookieLst = new List<Cookie>();
|
||||
try
|
||||
{
|
||||
if (buyer != null)
|
||||
{
|
||||
cookieLst = JsonHelper.DeserializeJsonToList<CefSharp.Cookie>(buyer?.cookie);
|
||||
if (cookieLst == null)
|
||||
cookieLst = new List<Cookie>();
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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<Cookie> 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> { cookie }), CefWebBrowser.GetCookieManager(null));
|
||||
t.Wait(2000);
|
||||
CefWebBrowser.Load("https://mobile.yangkeduo.com/personal.html");
|
||||
}
|
||||
}
|
||||
|
||||
#region 静态方法(检测/更新买手登录状态)
|
||||
|
||||
public static void CheckBuyerLogin(List<BuyerLoginInfo> 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<BuyerLoginInfo> loginInfoLst = JsonHelper.DeserializeJsonToList<BuyerLoginInfo>(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
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user