using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Net.Http; using System.Reflection; using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; using BootstrapBlazor.Components; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; using Microsoft.JSInterop; using WalkingTec.Mvvm.Core; using WalkingTec.Mvvm.Core.Extensions; using WalkingTec.Mvvm.Core.Support.Json; namespace WtmBlazorUtils { public abstract class BasePage : ComponentBase { [Inject] public WtmBlazorContext WtmBlazor { get; set; } [Inject] public IJSRuntime JSRuntime { get; set; } public List DeletedFileIds { get; set; } [CascadingParameter] public LoginUserInfo UserInfo { get; set; } public object _userinfo; [CascadingParameter(Name = "BodyContext")] public object UserInfoForDialog { get { return _userinfo; } set { _userinfo = value; UserInfo = value as LoginUserInfo; } } [Parameter] public Action OnCloseDialog { get; set; } protected void CloseDialog(DialogResult result = DialogResult.Close) { OnCloseDialog?.Invoke(result); } public async Task OpenDialog(string Title, Expression> Values = null, Size size = Size.ExtraExtraLarge, LoginUserInfo userinfo = null, bool isMax = false) { return await WtmBlazor.OpenDialog(Title, Values, size, userinfo??this.UserInfo, isMax); } public async Task PostsData(object data, string url, Func Msg = null, Action ErrorHandler = null, HttpMethodEnum method = HttpMethodEnum.POST) { var rv = await WtmBlazor.Api.CallAPI(url, method, data); if (rv.StatusCode == System.Net.HttpStatusCode.OK) { if (Msg != null) { var m = Msg.Invoke(rv.Data); await WtmBlazor.Toast.Success(WtmBlazor.Localizer["Sys.Info"], WtmBlazor.Localizer[m]); } CloseDialog(DialogResult.Yes); return true; } else { if (rv.Errors == null) { await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], rv.StatusCode.ToString()); } else { var err = rv.Errors.GetFirstError(); if (string.IsNullOrEmpty(err) == false) { await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], err); } else { await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], rv.ErrorMsg); } ErrorHandler?.Invoke(rv.Errors); } return false; } } public async Task PostsForm(ValidateForm form, string url, Func Msg = null, Action ErrorHandler = null, HttpMethodEnum method = HttpMethodEnum.POST) { if(form.Model is BaseVM bv) { bv.DeletedFileIds = this.DeletedFileIds; } var rv = await WtmBlazor.Api.CallAPI(url, method, form.Model); if (rv.StatusCode == System.Net.HttpStatusCode.OK) { if (Msg != null) { var m = Msg.Invoke(rv.Data); await WtmBlazor.Toast.Success(WtmBlazor.Localizer["Sys.Info"], WtmBlazor.Localizer[m]); } CloseDialog(DialogResult.Yes); return true; } else { if (rv.Errors == null) { await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], rv.StatusCode.ToString()); } else { SetError(form, rv.Errors); ErrorHandler?.Invoke(rv.Errors); } return false; } } public async Task> StartSearch(string url, BaseSearcher searcher, QueryPageOptions options) where T : class, new() { if (searcher != null) { searcher.IsEnumToString = false; } var rv = await WtmBlazor.Api.CallSearchApi(url, searcher, options); QueryData data = new QueryData(); if (rv.StatusCode == System.Net.HttpStatusCode.OK) { data.Items = rv.Data?.Data; data.TotalCount = rv.Data?.Count ?? 0; } if (rv.StatusCode == System.Net.HttpStatusCode.Forbidden) { await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], WtmBlazor.Localizer["Sys.NoPrivilege"]); } return data; } public async Task> StartSearchTree(string url, BaseSearcher searcher, QueryPageOptions options) where T : class, new() { if (searcher != null) { searcher.IsEnumToString = false; } var rv = await WtmBlazor.Api.CallSearchApi(url, searcher, options); QueryData data = new QueryData(); if (rv.StatusCode == System.Net.HttpStatusCode.OK) { var idpro = typeof(T).GetSingleProperty("ID"); if (rv.Data?.Data != null) { foreach (var item in rv.Data.Data) { string pid = idpro.GetValue(item)?.ToString(); item.SetPropertyValue("Children", new List(rv.Data.Data.AsQueryable().CheckParentID(pid))); } } data.Items = rv.Data?.Data.AsQueryable().CheckParentID(null); data.TotalCount = rv.Data?.Count ?? 0; } if (rv.StatusCode == System.Net.HttpStatusCode.Forbidden) { await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], WtmBlazor.Localizer["Sys.NoPrivilege"]); } return data; } public async void SetError(ValidateForm form, ErrorObj errors) { if (errors != null) { foreach (var item in errors.Form) { Regex r = new Regex("(.*?)\\[(\\-?\\d?)\\]\\.(.*?)$"); var match = r.Match(item.Key); if (match.Success) { int index = 0; int.TryParse(match.Groups[2].Value, out index); await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], $"{index+1}:{item.Value}" ); } else { form.SetError(item.Key, item.Value); } } if (errors.Message != null && errors.Message.Count > 0) { await WtmBlazor.Toast.Error(WtmBlazor.Localizer["Sys.Error"], errors.Message[0]); } } } public async Task GetFileUrl(string fileid, int? width = null, int? height = null) { var rv = await WtmBlazor.Api.CallAPI($"/api/_file/GetFile/{fileid}", HttpMethodEnum.GET, new Dictionary { {"width", width?.ToString() }, {"height", height?.ToString() } }); if (rv.StatusCode == System.Net.HttpStatusCode.OK) { return $"data:image/jpeg;base64,{Convert.ToBase64String(rv.Data)}"; } else { return $"data:image/jpeg;base64,0"; } } public async Task GetToken() { return await GetLocalStorage("wtmtoken"); } public async Task GetRefreshToken() { return await GetLocalStorage("wtmrefreshtoken"); } public async Task SetToken(string token, string refreshtoken) { await SetLocalStorage("wtmtoken", token); await SetLocalStorage("wtmrefreshtoken", refreshtoken); } public async Task DeleteToken() { await DeleteLocalStorage("wtmtoken"); await DeleteLocalStorage("wtmrefreshtoken"); } public async Task SetUserInfo(LoginUserInfo userinfo) { await JSRuntime.InvokeVoidAsync("localStorageFuncs.set", "wtmuser", JsonSerializer.Serialize(userinfo)); } public async Task GetUserInfo() { var user = await GetLocalStorage("wtmuser"); JsonSerializerOptions options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; user.Attributes["Actions"] = JsonSerializer.Deserialize(user.Attributes["Actions"].ToString(), options).Where(x => x != null).ToArray(); user.Attributes["Menus"] = JsonSerializer.Deserialize(user.Attributes["Menus"].ToString(), options); return user; } public async Task GetLocalStorage(string key) where T : class { string rv = ""; while (true) { string part = await JSRuntime.InvokeAsync("localStorageFuncs.get", System.Threading.CancellationToken.None, key, rv.Length); if(part == null) { return null; } rv += part; if (part.Length < 20000) { break; } } if(typeof(T) == typeof(string)) { return rv as T; } var obj = JsonSerializer.Deserialize(rv); return obj; } public async Task SetLocalStorage(string key, T data) where T : class { if (typeof(T) == typeof(string)) { await JSRuntime.InvokeVoidAsync("localStorageFuncs.set", key, data); } else { await JSRuntime.InvokeVoidAsync("localStorageFuncs.set", key, JsonSerializer.Serialize(data)); } } public async Task DeleteLocalStorage(string key) { await JSRuntime.InvokeAsync("localStorageFuncs.remove", key); } public bool IsAccessable(string url) { if (WtmBlazor.ConfigInfo.IsQuickDebug == true) { return true; } if (UserInfo != null) { var actions = UserInfo.Attributes["Actions"] as string[]; url = url.ToLower(); return actions.Any(x => x.ToLower() == url.ToLower()); } else if (WtmBlazor.PublicPages.Contains(url?.ToLower())) { return true; } return false; } public async Task Redirect(string path) { await JSRuntime.InvokeVoidAsync("urlFuncs.redirect", path); } public async Task Download(string url, object data, HttpMethodEnum method = HttpMethodEnum.POST) { url = WtmBlazor.GetServerUrl() + url; await JSRuntime.InvokeVoidAsync("urlFuncs.download", url, JsonSerializer.Serialize(data, CoreProgram.DefaultPostJsonOption), method.ToString()); } } public class WtmBlazorContext { public IStringLocalizer Localizer { get; set; } public GlobalItems GlobalSelectItems { get; set; } public ApiClient Api { get; set; } public DialogService Dialog { get; set; } public ToastService Toast { get; set; } public IHttpClientFactory ClientFactory { get; set; } private Configs _configInfo; public Configs ConfigInfo { get => _configInfo; } public List _publicPages = null; public WtmBlazorContext(IStringLocalizer local, GlobalItems gi, ApiClient api, DialogService dialog, ToastService toast, IHttpClientFactory cf, Configs _config) { _configInfo = _config; this.Localizer = local; this.GlobalSelectItems = gi; this.Api = api; this.Dialog = dialog; this.Toast = toast; this.ClientFactory = cf; } public List GetAllPages() { var pages = Assembly.GetCallingAssembly().GetTypes().Where(x => typeof(BasePage).IsAssignableFrom(x)).ToList(); var menus = new List(); foreach (var item in pages) { var actdes = item.GetCustomAttribute(); if (actdes != null) { var route = item.GetCustomAttribute(); var parts = route.Template.Split("/").Where(x => x != "").ToArray(); var area = Localizer["Sys.DefaultArea"].Value; if (parts.Length > 1) { area = parts[0]; } var areamenu = menus.Where(x => x.PageName == area).FirstOrDefault(); if (areamenu == null) { areamenu = new FrameworkMenu { PageName = area, Icon = "fa fa-fw fa-folder", Children = new List() }; menus.Add(areamenu); } areamenu.Children.Add(new FrameworkMenu { PageName = Localizer[actdes.Description], Icon = "fa fa-fw fa-file", Url = route.Template, ClassName = actdes.ClassFullName }); } } return menus; } public List PublicPages { get { if(_publicPages == null) { var pages = Assembly.GetCallingAssembly().GetTypes().Where(x => typeof(BasePage).IsAssignableFrom(x)).ToList(); _publicPages = new List(); foreach (var item in pages) { var route = item.GetCustomAttribute(); var ispublic = item.GetCustomAttribute(); if (ispublic != null) { var url = route.Template.ToLower(); if (url.StartsWith("/")) { url = url[1..]; } url = Regex.Replace(url, "{.*?}", ".*?"); url = "^" + url + "$"; _publicPages.Add(url); } } } return _publicPages; } } public async Task GetBase64Image(string fileid, int? width = null, int? height = null) { if (string.IsNullOrEmpty(fileid) == false) { var rv = await Api.CallAPI($"/api/_file/GetFile/{fileid}", HttpMethodEnum.GET, new Dictionary { {"width", width?.ToString() }, {"height", height?.ToString() } }); if (rv.StatusCode == System.Net.HttpStatusCode.OK) { return $"data:image/jpeg;base64,{Convert.ToBase64String(rv.Data)}"; } else { return ""; } } else { return ""; } } public async Task OpenDialog(string Title, Expression> Values = null, Size? size = null, LoginUserInfo userinfo = null, bool isMax = false) { TaskCompletionSource ReturnTask = new TaskCompletionSource(); SetValuesParser p = new SetValuesParser(); if(size != null) { size = Size.ExtraLarge; } DialogOption option = new DialogOption { ShowCloseButton = false, ShowFooter = false, IsDraggable = true, ShowMaximizeButton = !isMax, FullScreenSize = isMax==true?FullScreenSize.Always:FullScreenSize.Medium, Size = size.Value, IsScrolling = true, BodyContext = userinfo, Title = Title }; option.BodyTemplate = builder => { builder.OpenComponent(0, typeof(T)); builder.AddMultipleAttributes(2, p.Parse(Values)); try { builder.AddAttribute(3, "OnCloseDialog", new Action((r) => { option.OnCloseAsync = null; ReturnTask.TrySetResult(r); option.CloseDialogAsync(); })); } catch { }; //builder.SetKey(Guid.NewGuid()); builder.AddMarkupContent(4, "
"); builder.CloseComponent(); }; option.OnCloseAsync = async () => { option.OnCloseAsync = null; await option.CloseDialogAsync(); ReturnTask.TrySetResult(DialogResult.Close); }; await Dialog.Show(option); var rv = await ReturnTask.Task; return rv; } public string GetServerUrl() { var server = ConfigInfo.Domains.Where(x => x.Key.ToLower() == "serverpub").Select(x => x.Value).FirstOrDefault(); if (server == null) { server = ConfigInfo.Domains.Where(x => x.Key.ToLower() == "server").Select(x => x.Value).FirstOrDefault(); } if (server != null) { return server.Address.TrimEnd('/'); } else { return ""; } } public Task>> DefaultTreeConverter(IEnumerable data) where T:TreePoco { List> rv = new List>(); if(data == null || data.Count() == 0) { return Task.FromResult(rv.AsEnumerable()); } foreach (var item in data) { TableTreeNode tt = new TableTreeNode(item); tt.HasChildren = item.HasChildren; tt.Items = DefaultTreeConverter(item.Children).Result; rv.Add(tt); } return Task.FromResult(rv.AsEnumerable()); } } }