添加前后端框架源码

This commit is contained in:
dd 2021-12-14 14:10:44 +08:00
parent 8648886afd
commit 507b0c2114
287 changed files with 42372 additions and 8 deletions

View File

@ -45,7 +45,27 @@
"ProjectGuid": "e5f79995-ab61-41f4-820d-ba39967b406b",
"DisplayName": "PluginInterface",
"ColorIndex": 7
},
"c2672620-8e65-486c-b967-c4c673f8da0f": {
"ProjectGuid": "c2672620-8e65-486c-b967-c4c673f8da0f",
"DisplayName": "WalkingTec.Mvvm.Core",
"ColorIndex": 8
},
"b370f699-965b-4d86-93b1-0f022c95b5c9": {
"ProjectGuid": "b370f699-965b-4d86-93b1-0f022c95b5c9",
"DisplayName": "WalkingTec.Mvvm.Mvc",
"ColorIndex": 9
},
"81cbfd0e-1d89-440a-8cc3-e32672504ff4": {
"ProjectGuid": "81cbfd0e-1d89-440a-8cc3-e32672504ff4",
"DisplayName": "WalkingTec.Mvvm.TagHelpers.LayUI",
"ColorIndex": 10
},
"402e5b3a-ad95-4b6a-a4b0-c8ffcbf494c3": {
"ProjectGuid": "402e5b3a-ad95-4b6a-a4b0-c8ffcbf494c3",
"DisplayName": "test",
"ColorIndex": 11
}
},
"NextColorIndex": 8
"NextColorIndex": 12
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,13 +6,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="WalkingTec.Mvvm.Core" Version="5.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Plugins\PluginInterface\PluginInterface.csproj" />
<ProjectReference Include="..\WalkingTec.Mvvm\WalkingTec.Mvvm.Core\WalkingTec.Mvvm.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -21,6 +21,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Drivers", "Drivers", "{52D9
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DriverModbusTCP", "Plugins\Drivers\DriverModbusTCP\DriverModbusTCP.csproj", "{7B432FC9-57E6-44BF-B8A7-2A1FB31D6ADD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WalkingTec.Mvvm", "WalkingTec.Mvvm", "{98B1C9F0-028C-48D8-8148-54B69CCA4590}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WalkingTec.Mvvm.Core", "WalkingTec.Mvvm\WalkingTec.Mvvm.Core\WalkingTec.Mvvm.Core.csproj", "{C2672620-8E65-486C-B967-C4C673F8DA0F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WalkingTec.Mvvm.Mvc", "WalkingTec.Mvvm\WalkingTec.Mvvm.Mvc\WalkingTec.Mvvm.Mvc.csproj", "{B370F699-965B-4D86-93B1-0F022C95B5C9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WalkingTec.Mvvm.TagHelpers.LayUI", "WalkingTec.Mvvm\WalkingTec.Mvvm.TagHelpers.LayUI\WalkingTec.Mvvm.TagHelpers.LayUI.csproj", "{81CBFD0E-1D89-440A-8CC3-E32672504FF4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -55,6 +63,18 @@ Global
{7B432FC9-57E6-44BF-B8A7-2A1FB31D6ADD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B432FC9-57E6-44BF-B8A7-2A1FB31D6ADD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B432FC9-57E6-44BF-B8A7-2A1FB31D6ADD}.Release|Any CPU.Build.0 = Release|Any CPU
{C2672620-8E65-486C-B967-C4C673F8DA0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2672620-8E65-486C-B967-C4C673F8DA0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2672620-8E65-486C-B967-C4C673F8DA0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2672620-8E65-486C-B967-C4C673F8DA0F}.Release|Any CPU.Build.0 = Release|Any CPU
{B370F699-965B-4D86-93B1-0F022C95B5C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B370F699-965B-4D86-93B1-0F022C95B5C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B370F699-965B-4D86-93B1-0F022C95B5C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B370F699-965B-4D86-93B1-0F022C95B5C9}.Release|Any CPU.Build.0 = Release|Any CPU
{81CBFD0E-1D89-440A-8CC3-E32672504FF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81CBFD0E-1D89-440A-8CC3-E32672504FF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81CBFD0E-1D89-440A-8CC3-E32672504FF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81CBFD0E-1D89-440A-8CC3-E32672504FF4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -64,6 +84,9 @@ Global
{E5F79995-AB61-41F4-820D-BA39967B406B} = {FBED048F-7AB9-4348-AD56-F9BF4D9E3A55}
{52D96C24-2F2F-49B5-9F29-00414DEA41D8} = {FBED048F-7AB9-4348-AD56-F9BF4D9E3A55}
{7B432FC9-57E6-44BF-B8A7-2A1FB31D6ADD} = {52D96C24-2F2F-49B5-9F29-00414DEA41D8}
{C2672620-8E65-486C-B967-C4C673F8DA0F} = {98B1C9F0-028C-48D8-8148-54B69CCA4590}
{B370F699-965B-4D86-93B1-0F022C95B5C9} = {98B1C9F0-028C-48D8-8148-54B69CCA4590}
{81CBFD0E-1D89-440A-8CC3-E32672504FF4} = {98B1C9F0-028C-48D8-8148-54B69CCA4590}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1F219808-E6E8-4C1D-B846-41F2F7CF20FA}

View File

@ -16,8 +16,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.13" />
<PackageReference Include="WalkingTec.Mvvm.TagHelpers.LayUI" Version="5.7.0" />
<PackageReference Include="WalkingTec.Mvvm.Mvc" Version="5.7.0" />
</ItemGroup>
<ItemGroup>
@ -25,6 +23,8 @@
<ProjectReference Include="..\IoTGateway.DataAccess\IoTGateway.DataAccess.csproj" />
<ProjectReference Include="..\IoTGateway.ViewModel\IoTGateway.ViewModel.csproj" />
<ProjectReference Include="..\Plugins\Plugin\Plugin.csproj" />
<ProjectReference Include="..\WalkingTec.Mvvm\WalkingTec.Mvvm.Mvc\WalkingTec.Mvvm.Mvc.csproj" />
<ProjectReference Include="..\WalkingTec.Mvvm\WalkingTec.Mvvm.TagHelpers.LayUI\WalkingTec.Mvvm.TagHelpers.LayUI.csproj" />
</ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties appsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>

View File

@ -0,0 +1,46 @@
using System;
using System.Linq;
using Microsoft.Extensions.Localization;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 标记Controller和Action的描述
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class ActionDescriptionAttribute : Attribute
{
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
public string ClassFullName { get; set; }
public bool IsPage { get; set; }
public IStringLocalizer _localizer { get; set; }
/// <summary>
/// 新建一个描述
/// </summary>
public ActionDescriptionAttribute(string desc)
{
this.Description = desc;
}
public ActionDescriptionAttribute(string desc, string classFullName)
{
this.Description = desc;
this.ClassFullName = classFullName;
}
public ActionDescriptionAttribute(string desc, string classFullName, bool ispage)
{
this.Description = desc;
this.ClassFullName = classFullName;
this.IsPage = ispage;
}
public void SetLoccalizer(Type controllertype)
{
_localizer = Core.CoreProgram._localizer;
}
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 标记Controller或Action不受权限控制只要登录任何人都可访问
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class AllRightsAttribute : Attribute
{
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WalkingTec.Mvvm.Core
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class DebugOnlyAttribute : Attribute
{
}
}

View File

@ -0,0 +1,50 @@
using System;
namespace WalkingTec.Mvvm.Core
{
public enum DBOperationEnum { Default, Read, Write }
/// <summary>
/// 标记Controller或Action使用固定的连接字符串不受其他设定控制
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class FixConnectionAttribute : Attribute
{
/// <summary>
/// 连接字符串名称
/// </summary>
public string CsName { get; set; }
public DBTypeEnum? DbType { get; set; }
/// <summary>
/// 操作类型,读或写
/// </summary>
public DBOperationEnum Operation { get; set; }
/// <summary>
/// 新建固定连接字符串标记
/// </summary>
/// <param name="Operation">Operation</param>
/// <param name="CsName">the key of the ConnectionString in appsettings</param>
public FixConnectionAttribute(DBOperationEnum Operation = DBOperationEnum.Default, string CsName = "")
{
this.CsName = CsName;
this.Operation = Operation;
this.DbType = null;
}
/// <summary>
/// 操作类型,读或写
/// </summary>
/// <param name="DbType">the database type, if t is Default, the value in appsettings will be used</param>
/// <param name="Operation">Operation</param>
/// <param name="CsName">the key of the ConnectionString in appsettings</param>
public FixConnectionAttribute(DBTypeEnum DbType, DBOperationEnum Operation = DBOperationEnum.Default, string CsName = "")
{
this.CsName = CsName;
this.Operation = Operation;
this.DbType = DbType;
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WalkingTec.Mvvm.Core.Attributes
{
/// <summary>
/// 标记某个Model是一个多对多的中间表
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MiddleTableAttribute : Attribute
{
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WalkingTec.Mvvm.Core
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class NoLogAttribute : Attribute
{
}
}

View File

@ -0,0 +1,14 @@
using System;
using Microsoft.AspNetCore.Authorization;
namespace WalkingTec.Mvvm.Core
{
//[Obsolete("已废弃预计v3.0版本及v2.10版本开始将删除")]
/// <summary>
/// 标记Action返回的为公共页面跳过权限验证不需要登录即可访问
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class PublicAttribute : Attribute, IAllowAnonymous
{
}
}

View File

@ -0,0 +1,27 @@
using System;
namespace WalkingTec.Mvvm.Core
{
public enum ReInitModes { FAILEDONLY, SUCCESSONLY, ALWAYS }
/// <summary>
/// 标记VM中的ReInit方法是在提交错误时触发提交成功时触发或是都触发。这是为了一些特殊逻辑的VM设计的
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ReInitAttribute : Attribute
{
/// <summary>
/// 触发模式
/// </summary>
public ReInitModes ReInitMode { get; set; }
/// <summary>
/// 新建触发标记
/// </summary>
/// <param name="mode">触发模式</param>
public ReInitAttribute(ReInitModes mode)
{
this.ReInitMode = mode;
}
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WalkingTec.Mvvm.Core
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class ValidateFormItemOnlyAttribute : Attribute
{
}
}

View File

@ -0,0 +1,419 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core.Extensions;
using WalkingTec.Mvvm.Core.Support.FileHandlers;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 批量操作VM接口
/// </summary>
/// <typeparam name="TEditModel">批量修改的VM</typeparam>
public interface IBaseBatchVM<out TEditModel>
where TEditModel : BaseVM
{
/// <summary>
/// 批量修改的VM
/// </summary>
TEditModel LinkedVM { get; }
/// <summary>
/// 批量列表VM
/// </summary>
IBasePagedListVM<TopBasePoco, ISearcher> ListVM { get; }
/// <summary>
/// 列表数据的Id数组
/// </summary>
//IEnumerable<Guid> Ids { get; set; }
string[] Ids { get; set; }
/// <summary>
/// 批量操作的错误
/// </summary>
Dictionary<string, string> ErrorMessage { get; set; }
}
/// <summary>
/// 批量操作的基础VM所有批量操作的VM应继承本类
/// </summary>
/// <typeparam name="TModel">批量修改的VM</typeparam>
/// <typeparam name="TLinkModel">批量列表VM</typeparam>
public class BaseBatchVM<TModel, TLinkModel> : BaseVM, IBaseBatchVM<TLinkModel> where TModel : TopBasePoco,new() where TLinkModel : BaseVM
{
/// <summary>
/// 批量修改的VM
/// </summary>
public TLinkModel LinkedVM { get; set; }
/// <summary>
/// 批量列表VM
/// </summary>
[JsonIgnore]
public IBasePagedListVM<TopBasePoco, ISearcher> ListVM { get; set; }
/// <summary>
/// 批量操作的错误
/// </summary>
[JsonIgnore]
public Dictionary<string, string> ErrorMessage { get; set; }
/// <summary>
/// 列表数据的Id数组
/// </summary>
public string[] Ids { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public BaseBatchVM()
{
//this.Ids = new List<Guid>();
ErrorMessage = new Dictionary<string, string>();
}
/// <summary>
/// 添加错误信息
/// </summary>
/// <param name="e">错误</param>
/// <param name="id">数据Id</param>
protected void SetExceptionMessage(Exception e, string id)
{
if (id != null)
{
ErrorMessage.Add(id, e.Message);
}
}
/// <summary>
/// 检查是否可以删除,当进行批量删除操作时会调用本函数。子类如果有特殊判断应重载本函数
/// </summary>
/// <param name="id">数据Id</param>
/// <param name="errorMessage">错误信息</param>
/// <returns>true代表可以删除false代表不能删除</returns>
protected virtual bool CheckIfCanDelete(object id, out string errorMessage)
{
errorMessage = null;
return true;
}
/// <summary>
/// 批量删除默认对Ids中包含的主键的数据进行删除。子类如果有特殊判断应重载本函数
/// </summary>
/// <returns>true代表成功false代表失败</returns>
public virtual bool DoBatchDelete()
{
bool rv = true;
//循环所有数据Id
List<string> idsData = Ids.ToList();
var modelType = typeof(TModel);
var pros = modelType.GetAllProperties();
//如果包含附件,则先删除附件
List<Guid> fileids = new List<Guid>();
var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment) || typeof(TopBasePoco).IsAssignableFrom(x.PropertyType)).ToList();
var isPersist =typeof(IPersistPoco).IsAssignableFrom(modelType);
var isBasePoco = typeof(IBasePoco).IsAssignableFrom(modelType);
var query = DC.Set<TModel>().AsQueryable();
var fas = pros.Where(x => typeof(IEnumerable<ISubFile>).IsAssignableFrom(x.PropertyType)).ToList();
foreach (var f in fas)
{
query = query.Include(f.Name);
}
query = query.AsNoTracking().CheckIDs(idsData);
var entityList = query.ToList();
for (int i = 0; i < entityList.Count; i++)
{
string checkErro = null;
//检查是否可以删除,如不能删除则直接跳过
if (CheckIfCanDelete(idsData[i], out checkErro) == false)
{
ErrorMessage.Add(idsData[i], checkErro);
rv = false;
break;
}
//进行删除
try
{
var Entity = entityList[i];
if (isPersist)
{
(Entity as IPersistPoco).IsValid = false;
DC.UpdateProperty(Entity, "IsValid");
if (isBasePoco)
{
(Entity as IBasePoco).UpdateTime = DateTime.Now;
(Entity as IBasePoco).UpdateBy = LoginUserInfo.ITCode;
DC.UpdateProperty(Entity, "UpdateTime");
DC.UpdateProperty(Entity, "UpdateBy");
}
}
else
{
foreach (var f in fa)
{
if (f.PropertyType == typeof(FileAttachment))
{
string fidfield = DC.GetFKName2(modelType, f.Name);
var fidpro = pros.Where(x => x.Name == fidfield).FirstOrDefault();
var idresult = fidpro.GetValue(Entity);
if(idresult != null)
{
Guid fid = Guid.Empty;
if(Guid.TryParse(idresult.ToString(), out fid) == true)
{
fileids.Add(fid);
}
}
}
f.SetValue(Entity, null);
}
foreach (var f in fas)
{
var subs = f.GetValue(Entity) as IEnumerable<ISubFile>;
if (subs != null)
{
foreach (var sub in subs)
{
fileids.Add(sub.FileId);
}
f.SetValue(Entity, null);
}
else
{
}
}
if (typeof(TModel) != typeof(FileAttachment))
{
foreach (var pro in pros)
{
if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco)))
{
pro.SetValue(Entity, null);
}
}
}
DC.DeleteEntity(Entity);
}
}
catch (Exception e)
{
SetExceptionMessage(e, idsData[i]);
rv = false;
}
}
//进行数据库的删除操作
if (rv == true)
{
try
{
DC.SaveChanges();
var fp = Wtm.ServiceProvider.GetRequiredService<WtmFileProvider>();
foreach (var item in fileids)
{
fp.DeleteFile(item.ToString(), DC.ReCreate());
}
}
catch (Exception e)
{
SetExceptionMessage(e, null);
rv = false;
}
}
//如果失败,添加错误信息
if (rv == false)
{
if (ErrorMessage.Count > 0)
{
foreach (var id in idsData)
{
if (!ErrorMessage.ContainsKey(id))
{
ErrorMessage.Add(id, CoreProgram._localizer?["Sys.Rollback"]);
}
}
}
ListVM?.DoSearch();
if (ListVM != null)
{
foreach (var item in ListVM?.GetEntityList())
{
item.BatchError = ErrorMessage.Where(x => x.Key == item.GetID().ToString()).Select(x => x.Value).FirstOrDefault();
}
}
MSD.AddModelError("", CoreProgram._localizer?["Sys.DataCannotDelete"]);
}
return rv;
}
/// <summary>
/// 批量修改默认对Ids中包含的数据进行修改子类如果有特殊判断应重载本函数
/// </summary>
/// <returns>true代表成功false代表失败</returns>
public virtual bool DoBatchEdit()
{
//获取批量修改VM的所有属性
var pros = LinkedVM.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);
bool rv = true;
List<string> idsData = Ids.ToList();
string currentvmname = this.GetType().Name;
Type vmtype = null;
//找到对应的BaseCRUDVM并初始化
if (currentvmname.ToLower().Contains("apibatchvm"))
{
vmtype = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM<TModel>)) && x.Name.ToLower().Contains("apivm") == true).FirstOrDefault();
}
else
{
vmtype = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM<TModel>)) && x.Name.ToLower().Contains("apivm") == false).FirstOrDefault();
}
IBaseCRUDVM<TModel> vm = null;
if (vmtype != null)
{
vm = vmtype.GetConstructor(System.Type.EmptyTypes).Invoke(null) as IBaseCRUDVM<TModel>;
vm.CopyContext(this);
}
var entityList = DC.Set<TModel>().CheckIDs(idsData).ToList();
//循环所有数据
for (int i = 0; i < entityList.Count; i++)
{
try
{
//如果找不到对应数据,则输出错误
TModel entity = entityList[i];
if (vm != null)
{
vm.SetEntity(entity);
}
if (entity == null)
{
ErrorMessage.Add(idsData[i], CoreProgram._localizer?["Sys.DataNotExist"]);
rv = false;
break;
}
//如果能找到则循环LinkedVM中的属性给entity中同名属性赋值
foreach (var pro in pros)
{
var proToSet = entity.GetType().GetSingleProperty(pro.Name);
var val = FC.ContainsKey("LinkedVM." + pro.Name) ? FC["LinkedVM." + pro.Name] : null;
if(val == null && FC.ContainsKey("LinkedVM." + pro.Name + "[]"))
{
val = FC["LinkedVM." + pro.Name + "[]"];
}
if (proToSet != null && val != null)
{
var hasvalue = true;
if ( val is StringValues sv && StringValues.IsNullOrEmpty(sv) == true)
{
hasvalue = false;
}
if (hasvalue)
{
proToSet.SetValue(entity, pro.GetValue(LinkedVM));
}
}
}
//调用controller方法验证model
//try
//{
// Controller.GetType().GetMethod("RedoValidation").Invoke(Controller, new object[] { entity });
//}
//catch { }
//如果有对应的BaseCRUDVM则使用其进行数据验证
if (vm != null)
{
vm.Validate();
var errors = vm.MSD;
if (errors != null && errors.Count > 0)
{
var error = "";
foreach (var key in errors.Keys)
{
if (errors[key].Count > 0)
{
error += errors[key].Select(x => x.ErrorMessage).ToSepratedString();
}
}
if (error != "")
{
ErrorMessage.Add(idsData[i], error);
rv = false;
break;
}
}
}
if (typeof(IBasePoco).IsAssignableFrom( typeof(TModel)))
{
IBasePoco ent = entity as IBasePoco;
if (ent.UpdateTime == null)
{
ent.UpdateTime = DateTime.Now;
}
if (string.IsNullOrEmpty(ent.UpdateBy))
{
ent.UpdateBy = LoginUserInfo?.ITCode;
}
}
DC.UpdateEntity(entity);
}
catch (Exception e)
{
SetExceptionMessage(e, idsData[i]);
rv = false;
}
}
//进行数据库的修改操作
if (rv == true)
{
try
{
DC.SaveChanges();
}
catch (Exception e)
{
SetExceptionMessage(e, null);
rv = false;
}
}
//如果有错误,输出错误信息
if (rv == false)
{
if (ErrorMessage.Count > 0)
{
foreach (var id in idsData)
{
if (!ErrorMessage.ContainsKey(id))
{
ErrorMessage.Add(id, CoreProgram._localizer?["Sys.Rollback"]);
}
}
}
RefreshErrorList();
}
return rv;
}
protected void RefreshErrorList()
{
ListVM.DoSearch();
foreach (var item in ListVM.GetEntityList())
{
item.BatchError = ErrorMessage.Where(x => x.Key == item.GetID().ToString()).Select(x => x.Value).FirstOrDefault();
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 搜索条件基类一般和ListVM配合使用实现对ListVM的搜索功能。
/// </summary>
public class BaseSearcher : ISearcher
{
#region Property
#region
/// <summary>
/// 当前页
/// </summary>
public int Page { get; set; }
/// <summary>
/// 每页数
/// </summary>
public int Limit { get; set; }
/// <summary>
/// 记录数
/// </summary>
[JsonIgnore]
public long Count { get; set; }
/// <summary>
/// 分页数
/// </summary>
[JsonIgnore]
public int PageCount { get; set; }
#endregion
/// <summary>
/// 记录 Controller 中的表单数据
/// </summary>
[JsonIgnore]
public Dictionary<string, object> FC { get; set; }
[JsonIgnore]
public IModelStateService MSD { get => Wtm?.MSD; }
/// <summary>
/// 获取VM的全名
/// </summary>
[JsonIgnore]
public string VMFullName
{
get
{
var name = GetType().AssemblyQualifiedName;
name = name.Substring(0, name.LastIndexOf(", Version="));
return name;
}
}
private IDataContext _dc;
/// <summary>
/// 数据库环境
/// </summary>
[JsonIgnore]
public IDataContext DC
{
get
{
if (_dc == null)
{
return Wtm?.DC;
}
else
{
return _dc;
}
}
set
{
_dc = value;
}
}
/// <summary>
/// Session信息
/// </summary>
[JsonIgnore]
public ISessionService Session { get => Wtm?.Session; }
/// <summary>
/// 当前登录人信息
/// </summary>
[JsonIgnore]
public LoginUserInfo LoginUserInfo { get => Wtm?.LoginUserInfo; }
[JsonIgnore]
public string ViewDivId { get; set; }
#region 使
/// <summary>
/// 排序信息
/// </summary>
public SortInfo SortInfo { get; set; }
/// <summary>
/// 前台搜索框是否展开
/// </summary>
[JsonIgnore]
public bool? IsExpanded { get; set; }
private Guid _uniqueId;
[JsonIgnore]
public string UniqueId
{
get
{
if (_uniqueId == Guid.Empty)
{
_uniqueId = Guid.NewGuid();
}
return _uniqueId.ToNoSplitString();
}
}
[JsonIgnore]
public WTMContext Wtm { get; set; }
#endregion
#endregion
#region Event
/// <summary>
/// InitVM 完成后触发的事件
/// </summary>
public event Action<ISearcher> OnAfterInit;
/// <summary>
/// ReInitVM 完成后触发的事件
/// </summary>
public event Action<ISearcher> OnAfterReInit;
#endregion
#region Method
/// <summary>
/// 调用 InitVM 并触发 OnAfterInit 事件
/// </summary>
public void DoInit()
{
InitVM();
OnAfterInit?.Invoke(this);
}
/// <summary>
/// 调用 ReInitVM 并触发 OnAfterReInit 事件
/// </summary>
public void DoReInit()
{
ReInitVM();
OnAfterReInit?.Invoke(this);
}
/// <summary>
/// 初始化ViewModel框架会在创建VM实例之后自动调用本函数
/// </summary>
protected virtual void InitVM()
{
}
/// <summary>
/// 从新初始化ViewModel框架会在验证失败时自动调用本函数
/// </summary>
protected virtual void ReInitVM()
{
InitVM();
}
public virtual void Validate()
{
}
/// <summary>
/// 将源 VM 的 FC 等内容复制到本VM中
/// </summary>
/// <param name="vm"></param>
public void CopyContext(IBaseVM vm)
{
FC = vm.FC;
this.Wtm = vm.Wtm;
this.ViewDivId = vm.ViewDivId;
}
#endregion
}
}

View File

@ -0,0 +1,345 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.IO;
using System.Linq;
using NPOI.HSSF.UserModel;
using NPOI.HSSF.Util;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
namespace WalkingTec.Mvvm.Core
{
public class BaseTemplateVM : BaseVM
{
#region
/// <summary>
/// 下载模板显示名称
/// </summary>
public string FileDisplayName { get; set; }
/// <summary>
/// 是否验证模板类型当其他系统模板导入到某模块时可设置为False
/// </summary>
public bool ValidityTemplateType { get; set; }
/// <summary>
/// 需要导出的数据
/// </summary>
public DataTable TemplateDataTable { get; set; }
/// <summary>
/// 下载模版页面参数
/// </summary>
public Dictionary<string, string> Parms { get; set; }
/// <summary>
/// Excel索引
/// </summary>
public long ExcelIndex { get; set; }
#endregion
#region
public BaseTemplateVM()
{
ValidityTemplateType = true;
Parms = new Dictionary<string, string>();
var propetys = this.GetType().GetFields().Where(x => x.FieldType == typeof(ExcelPropety)).ToList();
for (int porpetyIndex = 0; porpetyIndex < propetys.Count(); porpetyIndex++)
{
ExcelPropety excelPropety = (ExcelPropety)propetys[porpetyIndex].GetValue(this);
if (propetys[porpetyIndex].GetCustomAttributes(typeof(DisplayAttribute), false).Length == 0)
{
excelPropety.ColumnName = excelPropety.FieldDisplayName;
}
else
{
excelPropety.ColumnName = propetys[porpetyIndex].GetPropertyDisplayName();
}
}
}
#endregion
#region Excel属性数据
/// <summary>
/// 初始化Excel属性数据 包括动态列,列表中的下拉选项
/// </summary>
public virtual void InitExcelData()
{
}
public virtual void InitCustomFormat()
{
}
#endregion
#region
/// <summary>
/// 初始化模版数据
/// </summary>
public virtual void SetTemplateDataValus()
{
}
#endregion
#region
/// <summary>
/// 生成模板
/// </summary>
/// <param name="displayName">文件名</param>
/// <returns>生成的模版文件</returns>
public byte[] GenerateTemplate(out string displayName)
{
//设置导出的文件名称
string SheetName = !string.IsNullOrEmpty(FileDisplayName) ? FileDisplayName : this.GetType().Name;
displayName = SheetName + "_" + DateTime.Now.ToString("yyyy-MM-dd") + "_" + DateTime.Now.ToString("hh^mm^ss") + ".xlsx";
//1.声明Excel文档
IWorkbook workbook = new XSSFWorkbook();
//加载初始化数据和下拉菜单数据,可重载
InitExcelData();
//设置TemplateDataTable的各列的类型
CreateDataTable();
//设置初始化数据到DataTable中
SetTemplateDataValus();
//2.设置workbook的sheet页
ISheet sheet = workbook.CreateSheet();
workbook.SetSheetName(0, SheetName);
//3.设置Sheet页的Row
IRow row = sheet.CreateRow(0);
row.HeightInPoints = 20;
ISheet enumSheet = workbook.CreateSheet();
IRow enumSheetRow1 = enumSheet.CreateRow(0);
enumSheetRow1.CreateCell(0).SetCellValue(CoreProgram._localizer?["Sys.Yes"]);
enumSheetRow1.CreateCell(1).SetCellValue(CoreProgram._localizer?["Sys.No"]);
enumSheetRow1.CreateCell(2).SetCellValue(this.GetType().Name); //为模板添加标记,必要时可添加版本号
ISheet dataSheet = workbook.CreateSheet();
#region excel模板列头
//默认灰色
var headerStyle = GetCellStyle(workbook);
headerStyle.IsLocked = true;
//黄色
var yellowStyle = GetCellStyle(workbook, BackgroudColorEnum.Yellow);
yellowStyle.IsLocked = true;
//红色
var redStyle = GetCellStyle(workbook, BackgroudColorEnum.Red);
redStyle.IsLocked = true;
//取得所有ExcelPropety
var propetys = this.GetType().GetFields().Where(x => x.FieldType == typeof(ExcelPropety)).ToList();
//设置列的索引
int _currentColunmIndex = 0;
//设置Excel是否需要保护默认不保护
bool IsProtect = false;
//循环类的属性,赋值给列
for (int porpetyIndex = 0; porpetyIndex < propetys.Count(); porpetyIndex++)
{
//依次获取属性字段
ExcelPropety excelPropety = (ExcelPropety)propetys[porpetyIndex].GetValue(this);
ColumnDataType dateType = (excelPropety.DataType == ColumnDataType.DateTime || excelPropety.DataType == ColumnDataType.Date) ? ColumnDataType.Text : excelPropety.DataType; //日期类型默认设置成Text类型,在赋值时会进行日期验证
//设置是否保护Excel
if (excelPropety.ReadOnly)
{
IsProtect = true;
}
//给必填项加星号
string colName = excelPropety.IsNullAble ? excelPropety.ColumnName : excelPropety.ColumnName + "*";
row.CreateCell(_currentColunmIndex).SetCellValue(colName);
//修改列头样式
switch (excelPropety.BackgroudColor)
{
case BackgroudColorEnum.Yellow:
row.Cells[_currentColunmIndex].CellStyle = yellowStyle;
break;
case BackgroudColorEnum.Red:
row.Cells[_currentColunmIndex].CellStyle = redStyle;
break;
default:
row.Cells[_currentColunmIndex].CellStyle = headerStyle;
break;
}
var dataStyle = workbook.CreateCellStyle();
var dataFormat = workbook.CreateDataFormat();
if (dateType == ColumnDataType.Dynamic)
{
int dynamicColCount = excelPropety.DynamicColumns.Count();
for (int dynamicColIndex = 0; dynamicColIndex < dynamicColCount; dynamicColIndex++)
{
var dynamicCol = excelPropety.DynamicColumns.ToList()[dynamicColIndex];
string dynamicColName = excelPropety.IsNullAble ? dynamicCol.ColumnName : dynamicCol.ColumnName + "*";
row.CreateCell(_currentColunmIndex).SetCellValue(dynamicColName);
row.Cells[_currentColunmIndex].CellStyle = headerStyle;
if (dynamicCol.ReadOnly)
{
IsProtect = true;
}
//设定列宽
if (excelPropety.CharCount > 0)
{
sheet.SetColumnWidth(_currentColunmIndex, excelPropety.CharCount * 256);
dataStyle.WrapText = true;
}
else
{
sheet.AutoSizeColumn(_currentColunmIndex);
}
//设置单元格样式及数据类型
dataStyle.IsLocked = excelPropety.ReadOnly;
dynamicCol.SetColumnFormat(dynamicCol.DataType, _currentColunmIndex, sheet, dataSheet, dataStyle, dataFormat);
_currentColunmIndex++;
}
}
else
{
//设定列宽
if (excelPropety.CharCount > 0)
{
sheet.SetColumnWidth(_currentColunmIndex, excelPropety.CharCount * 256);
dataStyle.WrapText = true;
}
else
{
sheet.AutoSizeColumn(_currentColunmIndex);
}
//设置是否锁定
dataStyle.IsLocked = excelPropety.ReadOnly;
//设置单元格样式及数据类型
excelPropety.SetColumnFormat(dateType, _currentColunmIndex, sheet, dataSheet, dataStyle, dataFormat);
_currentColunmIndex++;
}
}
#endregion
#region
if (TemplateDataTable.Rows.Count > 0)
{
for (int i = 0; i < TemplateDataTable.Rows.Count; i++)
{
DataRow tableRow = TemplateDataTable.Rows[i];
IRow dataRow = sheet.CreateRow(1 + i);
for (int porpetyIndex = 0; porpetyIndex < propetys.Count(); porpetyIndex++)
{
string colName = propetys[porpetyIndex].Name;
tableRow[colName].ToString();
dataRow.CreateCell(porpetyIndex).SetCellValue(tableRow[colName].ToString());
}
}
}
#endregion
//冻结行
sheet.CreateFreezePane(0, 1, 0, 1);
//锁定excel
if (IsProtect)
{
sheet.ProtectSheet("password");
}
//隐藏前2个Sheet
workbook.SetSheetHidden(1, SheetState.Hidden);
workbook.SetSheetHidden(2, SheetState.Hidden);
//返回byte数组
MemoryStream ms = new MemoryStream();
workbook.Write(ms);
return ms.ToArray();
}
#endregion
#region
private static ICellStyle GetCellStyle(IWorkbook workbook, BackgroudColorEnum backgroudColor = BackgroudColorEnum.Grey)
{
var headerStyle = workbook.CreateCellStyle();
//设定表头样式
headerStyle.BorderBottom = BorderStyle.Thin;
headerStyle.BorderLeft = BorderStyle.Thin;
headerStyle.BorderRight = BorderStyle.Thin;
headerStyle.BorderTop = BorderStyle.Thin;
//用灰色填充背景
short headerbg;
switch (backgroudColor)
{
case BackgroudColorEnum.Grey:
headerbg = HSSFColor.LightBlue.Index;
break;
case BackgroudColorEnum.Yellow:
headerbg = HSSFColor.LightYellow.Index;
break;
case BackgroudColorEnum.Red:
headerbg = HSSFColor.Pink.Index;
break;
default:
headerbg = HSSFColor.Pink.Index;
break;
}
headerStyle.FillForegroundColor = headerbg;
headerStyle.FillPattern = FillPattern.SolidForeground;
headerStyle.FillBackgroundColor = headerbg;
headerStyle.Alignment = HorizontalAlignment.Center;
return headerStyle;
}
#endregion
#region DataTable()
private void CreateDataTable()
{
TemplateDataTable = new DataTable();
var propetys = this.GetType().GetFields().Where(x => x.FieldType == typeof(ExcelPropety)).ToList();
foreach (var p in propetys)
{
ExcelPropety excelPropety = (ExcelPropety)p.GetValue(this);
ColumnDataType dateType = excelPropety.DataType;
switch (dateType)
{
case ColumnDataType.Bool:
TemplateDataTable.Columns.Add(p.Name, typeof(bool));
break;
case ColumnDataType.Date:
TemplateDataTable.Columns.Add(p.Name, typeof(string));
break;
case ColumnDataType.Number:
TemplateDataTable.Columns.Add(p.Name, typeof(int));
break;
case ColumnDataType.Text:
TemplateDataTable.Columns.Add(p.Name, typeof(string));
break;
case ColumnDataType.Float:
TemplateDataTable.Columns.Add(p.Name, typeof(decimal));
break;
default:
TemplateDataTable.Columns.Add(p.Name, typeof(string));
break;
}
}
}
#endregion
}
}

View File

@ -0,0 +1,284 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using WalkingTec.Mvvm.Core.Extensions;
using WalkingTec.Mvvm.Core.Support.Json;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 所有ViewModel的基类提供了基本的功能
/// </summary>
public class BaseVM : IBaseVM
{
/// <summary>
/// BaseVM
/// </summary>
public BaseVM()
{
FC = new Dictionary<string, object>();
}
#region Property
[JsonIgnore]
public WTMContext Wtm { get; set; }
private Guid _uniqueId;
/// <summary>
/// VM实例的Id
/// </summary>
[JsonIgnore]
public string UniqueId
{
get
{
if (_uniqueId == Guid.Empty)
{
_uniqueId = Guid.NewGuid();
}
return _uniqueId.ToNoSplitString();
}
}
/// <summary>
/// 前台传递过来的弹出窗口ID多层弹出窗口用逗号分隔
/// </summary>
[JsonIgnore]
public string WindowIds { get => Wtm?.WindowIds; }
private string _viewdivid;
/// <summary>
/// PartialView中主Div的Id
/// </summary>
[JsonIgnore]
public string ViewDivId
{
set { _viewdivid = value; }
get
{
if (string.IsNullOrEmpty(_viewdivid))
{
_viewdivid = "ViewDiv" + UniqueId;
}
return _viewdivid;
}
}
private IDataContext _dc;
/// <summary>
/// 数据库环境
/// </summary>
[JsonIgnore]
public IDataContext DC
{
get
{
if (_dc == null)
{
return Wtm?.DC;
}
else
{
return _dc;
}
}
set
{
_dc = value;
}
}
/// <summary>
/// 获取VM的全名
/// </summary>
[JsonIgnore]
public string VMFullName
{
get
{
var name = GetType().AssemblyQualifiedName;
name = name.Substring(0, name.LastIndexOf(", Version="));
return name;
}
}
/// <summary>
/// 获取VM所在Dll
/// </summary>
[JsonIgnore]
public string CreatorAssembly
{
get; set;
}
/// <summary>
/// 获取当前使用的连接字符串
/// </summary>
[JsonIgnore]
public string CurrentCS { get => Wtm?.CurrentCS; }
/// <summary>
/// 记录Controller中传递过来的表单数据
/// </summary>
[JsonIgnore]
public Dictionary<string, object> FC { get; set; }
/// <summary>
/// 获取配置文件的信息
/// </summary>
[JsonIgnore]
public Configs ConfigInfo { get=> Wtm?.ConfigInfo; }
[JsonIgnore]
public IUIService UIService { get=> Wtm?.UIService; }
/// <summary>
/// 当前弹出层ID
/// </summary>
[JsonIgnore]
public string CurrentWindowId { get => Wtm?.CurrentWindowId; }
/// <summary>
/// 父级弹出层ID
/// </summary>
[JsonIgnore]
public string ParentWindowId { get => Wtm?.ParentWindowId; }
[JsonIgnore]
public IDistributedCache Cache { get => Wtm?.Cache; }
/// <summary>
/// 当前登录人信息
/// </summary>
[JsonIgnore]
public LoginUserInfo LoginUserInfo { get=> Wtm?.LoginUserInfo;}
/// <summary>
/// 当前Url
/// </summary>
[JsonIgnore]
public string CurrentUrl { get => Wtm?.BaseUrl; }
/// <summary>
/// 记录原始提交页面
/// </summary>
[JsonIgnore]
public string FromView { get; set; }
/// <summary>
/// 记录当前页面
/// </summary>
[JsonIgnore]
public string CurrentView { get; set; }
/// <summary>
/// Session信息
/// </summary>
[JsonIgnore]
public ISessionService Session { get => Wtm?.Session; }
/// <summary>
/// Controller传递过来的ModelState信息
/// </summary>
[JsonIgnore]
public IModelStateService MSD { get => Wtm?.MSD; }
/// <summary>
/// 用于保存删除的附件ID
/// </summary>
public List<string> DeletedFileIds { get; set; } = new List<string>();
[JsonIgnore]
public string ControllerName { get; set; }
[JsonIgnore]
public IStringLocalizer Localizer { get => Wtm?.Localizer; }
#endregion
#region Event
/// <summary>
/// InitVM完成后触发的事件
/// </summary>
public event Action<IBaseVM> OnAfterInit;
/// <summary>
/// ReInitVM完成后触发的事件
/// </summary>
public event Action<IBaseVM> OnAfterReInit;
#endregion
#region Method
/// <summary>
/// 调用 InitVM 并触发 OnAfterInit 事件
/// </summary>
public void DoInit()
{
InitVM();
OnAfterInit?.Invoke(this);
}
/// <summary>
/// 调用 ReInitVM 并触发 OnAfterReInit 事件
/// </summary>
public void DoReInit()
{
ReInitVM();
OnAfterReInit?.Invoke(this);
}
/// <summary>
/// 初始化ViewModel框架会在创建VM实例之后自动调用本函数
/// </summary>
protected virtual void InitVM()
{
}
/// <summary>
/// 从新初始化ViewModel框架会在验证失败时自动调用本函数
/// </summary>
protected virtual void ReInitVM()
{
InitVM();
}
/// <summary>
/// 验证函数MVC会在提交数据的时候自动调用本函数
/// </summary>
/// <returns></returns>
public virtual void Validate()
{
return;
}
/// <summary>
/// 将源VM的上数据库上下文Session登录用户信息模型状态信息缓存信息等内容复制到本VM中
/// </summary>
/// <param name="vm">复制的源</param>
public void CopyContext(BaseVM vm)
{
Wtm = vm.Wtm;
FC = vm.FC;
CreatorAssembly = vm.CreatorAssembly;
}
#endregion
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace WalkingTec.Mvvm.Core
{
public class CS
{
public string Key { get; set; }
public string Value { get; set; }
public DBTypeEnum? DbType { get; set; }
public string Version { get; set; }
public string DbContext { get; set; }
public ConstructorInfo DcConstructor;
public IDataContext CreateDC()
{
if (DcConstructor == null)
{
var AllAssembly = Utils.GetAllAssembly();
List<ConstructorInfo> cis = new List<ConstructorInfo>();
if (AllAssembly != null)
{
foreach (var ass in AllAssembly)
{
try
{
var t = ass.GetExportedTypes().Where(x => typeof(DbContext).IsAssignableFrom(x) && x.Name != "DbContext" && x.Name != "FrameworkContext" && x.Name != "EmptyContext").ToList();
foreach (var st in t)
{
var ci = st.GetConstructor(new Type[] { typeof(CS) });
if (ci != null)
{
cis.Add(ci);
}
}
}
catch { }
}
string dcname = DbContext;
if (string.IsNullOrEmpty(dcname))
{
dcname = "DataContext";
}
DcConstructor = cis.Where(x => x.DeclaringType.Name.ToLower() == dcname.ToLower()).FirstOrDefault();
if (DcConstructor == null)
{
DcConstructor = cis.FirstOrDefault();
}
}
}
return (IDataContext)DcConstructor?.Invoke(new object[] { this });
}
}
}

View File

@ -0,0 +1,480 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.Logging;
using WalkingTec.Mvvm.Core.ConfigOptions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// Configs
/// </summary>
public class Configs
{
#region ConnectionStrings
private List<CS> _connectStrings;
/// <summary>
/// ConnectionStrings
/// </summary>
public List<CS> Connections
{
get
{
if (_connectStrings == null)
{
_connectStrings = new List<CS>();
}
return _connectStrings;
}
set
{
_connectStrings = value;
}
}
#endregion
#region Domains
private Dictionary<string,Domain> _domains;
/// <summary>
/// ConnectionStrings
/// </summary>
public Dictionary<string, Domain> Domains
{
get
{
if (_domains == null)
{
_domains = new Dictionary<string, Domain>();
}
return _domains;
}
set
{
_domains = value;
foreach (var item in _domains)
{
if(item.Value != null)
{
item.Value.Name = item.Key;
}
}
}
}
#endregion
#region QuickDebug
private bool? _isQuickDebug;
/// <summary>
/// Is debug mode
/// </summary>
public bool IsQuickDebug
{
get
{
return _isQuickDebug ?? false;
}
set
{
_isQuickDebug = value;
}
}
#endregion
public string ErrorHandler { get; set; } = "/_Framework/Error";
#region Cookie prefix
private string _cookiePre;
/// <summary>
/// Cookie prefix
/// </summary>
public string CookiePre
{
get
{
return _cookiePre ?? string.Empty;
}
set
{
_cookiePre = value;
}
}
#endregion
#region PageMode
private PageModeEnum? _pageMode;
/// <summary>
/// PageMode
/// </summary>
public PageModeEnum PageMode
{
get
{
if (_pageMode == null)
{
_pageMode = PageModeEnum.Single;
}
return _pageMode.Value;
}
set
{
_pageMode = value;
}
}
#endregion
#region TabMode
private TabModeEnum? _tabMode;
/// <summary>
/// TabMode
/// </summary>
public TabModeEnum TabMode
{
get
{
if (_tabMode == null)
{
_tabMode = TabModeEnum.Default;
}
return _tabMode.Value;
}
set
{
_tabMode = value;
}
}
#endregion
#region BlazorMode
private BlazorModeEnum? _blazorMode;
/// <summary>
/// TabMode
/// </summary>
public BlazorModeEnum BlazorMode
{
get
{
if (_blazorMode == null)
{
_blazorMode = BlazorModeEnum.Server;
}
return _blazorMode.Value;
}
set
{
_blazorMode = value;
}
}
#endregion
#region Custom settings
private Dictionary<string,string> _appSettings;
/// <summary>
/// Custom settings
/// </summary>
public Dictionary<string, string> AppSettings
{
get
{
if (_appSettings == null)
{
_appSettings = new Dictionary<string, string>();
}
return _appSettings;
}
set
{
_appSettings = value;
}
}
#endregion
#region FileOptions
private FileUploadOptions _fileUploadOptions;
/// <summary>
/// FileOptions
/// </summary>
public FileUploadOptions FileUploadOptions
{
get
{
if (_fileUploadOptions == null)
{
_fileUploadOptions = new FileUploadOptions()
{
UploadLimit = DefaultConfigConsts.DEFAULT_UPLOAD_LIMIT,
SaveFileMode = "database",
Settings = new Dictionary<string, List<FileHandlerOptions>>()
};
}
return _fileUploadOptions;
}
set
{
_fileUploadOptions = value;
}
}
#endregion
#region UIOptions
private UIOptions _uiOptions;
/// <summary>
/// UIOptions
/// </summary>
public UIOptions UIOptions
{
get
{
if (_uiOptions == null)
{
_uiOptions = new UIOptions();
if (_uiOptions.DataTable == null)
_uiOptions.DataTable = new UIOptions.DataTableOptions
{
RPP = DefaultConfigConsts.DEFAULT_RPP
};
if (_uiOptions.ComboBox == null)
_uiOptions.ComboBox = new UIOptions.ComboBoxOptions
{
DefaultEnableSearch = DefaultConfigConsts.DEFAULT_COMBOBOX_DEFAULT_ENABLE_SEARCH
};
if (_uiOptions.DateTime == null)
_uiOptions.DateTime = new UIOptions.DateTimeOptions
{
DefaultReadonly = DefaultConfigConsts.DEFAULT_DATETIME_DEFAULT_READONLY
};
if (_uiOptions.SearchPanel == null)
_uiOptions.SearchPanel = new UIOptions.SearchPanelOptions
{
DefaultExpand = DefaultConfigConsts.DEFAULT_SEARCHPANEL_DEFAULT_EXPAND
};
}
return _uiOptions;
}
set
{
_uiOptions = value;
}
}
#endregion
#region Is FileAttachment public
private bool? _isFilePublic;
/// <summary>
/// Is FileAttachment public
/// </summary>
public bool IsFilePublic
{
get
{
return _isFilePublic ?? false;
}
set
{
_isFilePublic = value;
}
}
#endregion
#region UEditorOptions
private UEditorOptions _ueditorOptions;
/// <summary>
/// UEditor配置
/// </summary>
/// <value></value>
public UEditorOptions UEditorOptions
{
get
{
if (_ueditorOptions == null)
{
_ueditorOptions = new UEditorOptions();
}
return _ueditorOptions;
}
set
{
_ueditorOptions = value;
}
}
#endregion
#region Cors configs
private Cors _cors;
/// <summary>
/// Cors configs
/// </summary>
public Cors CorsOptions
{
get
{
if (_cors == null)
{
_cors = new Cors();
_cors.Policy = new List<CorsPolicy>();
}
return _cors;
}
set
{
_cors = value;
}
}
#endregion
#region Support Languages
private string _languages;
/// <summary>
/// Support Languages
/// </summary>
public string Languages
{
get
{
if (string.IsNullOrEmpty((_languages)))
{
_languages = "zh";
}
return _languages;
}
set
{
_languages = value;
}
}
private List<CultureInfo> _supportLanguages;
public List<CultureInfo> SupportLanguages
{
get
{
if(_supportLanguages == null)
{
_supportLanguages = new List<CultureInfo>();
var lans = Languages.Split(",");
foreach (var lan in lans)
{
_supportLanguages.Add(new CultureInfo(lan));
}
}
return _supportLanguages;
}
}
#endregion
public string HostRoot { get; set; } = "";
#region CookieOption configs
private CookieOption _cookieOption;
/// <summary>
/// Cors configs
/// </summary>
public CookieOption CookieOptions
{
get
{
if (_cookieOption == null)
{
_cookieOption = new CookieOption();
}
return _cookieOption;
}
set
{
_cookieOption = value;
}
}
#endregion
#region JwtOption configs
private JwtOption _jwtOption;
/// <summary>
/// Cors configs
/// </summary>
public JwtOption JwtOptions
{
get
{
if (_jwtOption == null)
{
_jwtOption = new JwtOption();
}
return _jwtOption;
}
set
{
_jwtOption = value;
if(_jwtOption.SecurityKey.Length < 18)
{
var count = 18 - _jwtOption.SecurityKey.Length;
for (int i = 0; i < count; i++){
_jwtOption.SecurityKey += "x";
}
}
}
}
#endregion
public IDataContext CreateDC(string csName = null)
{
if (string.IsNullOrEmpty(csName))
{
csName = "default";
}
var cs = Connections.Where(x => x.Key.ToLower() == csName.ToLower()).FirstOrDefault();
return cs?.CreateDC();
}
}
}

View File

@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Authentication.Cookies;
namespace WalkingTec.Mvvm.Core
{
public class CookieOption
{
public string Issuer { get; set; } = "http://localhost";
public string Audience { get; set; } = "http://localhost";
public int Expires { get; set; } = 3600;
public bool SlidingExpiration { get; set; } = true;
public string LoginPath { get; set; } = "/Login/Login";
public string LogoutPath { get; set; } = "/Login/Logout";
public string AccessDeniedPath { get; set; } = "/Login/Login";
public string Domain { get; set; } = "";
public string ReturnUrlParameter { get; set; } = CookieAuthenticationDefaults.ReturnUrlParameter;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WalkingTec.Mvvm.Core
{
public class Cors
{
public bool EnableAll { get; set; }
public List<CorsPolicy> Policy { get; set; }
}
public class CorsPolicy
{
public string Name { get; set; }
public string Domain { get; set; }
}
}

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// DFS
/// </summary>
public class DFS
{
/// <summary>
/// StorageMaxConnection
/// </summary>
public int? StorageMaxConnection { get; set; }
/// <summary>
/// TrackerMaxConnection
/// </summary>
public int? TrackerMaxConnection { get; set; }
/// <summary>
/// ConnectionTimeout
/// </summary>
public int? ConnectionTimeout { get; set; }
/// <summary>
/// ConnectionLifeTime
/// </summary>
public int? ConnectionLifeTime { get; set; }
/// <summary>
/// Trackers
/// </summary>
public List<DFSTracker> Trackers { get; set; }
}
}

View File

@ -0,0 +1,18 @@
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// DFSTracker
/// </summary>
public class DFSTracker
{
/// <summary>
/// IP
/// </summary>
public string IP { get; set; }
/// <summary>
/// Port
/// </summary>
public int Port { get; set; }
}
}

View File

@ -0,0 +1,38 @@
namespace WalkingTec.Mvvm.Core.ConfigOptions
{
/// <summary>
/// DefaultConfigConsts
/// </summary>
public static class DefaultConfigConsts
{
/// <summary>
/// 默认上传路径
/// </summary>
public const string DEFAULT_UPLOAD_DIR = ".\\upload";
/// <summary>
/// 默认列表行数
/// </summary>
public const int DEFAULT_RPP = 20;
/// <summary>
/// 默认上传文件限制
/// </summary>
public const int DEFAULT_UPLOAD_LIMIT = 20 * 1024 * 1024;
/// <summary>
/// 默认允许ComboBox搜索
/// </summary>
public const bool DEFAULT_COMBOBOX_DEFAULT_ENABLE_SEARCH = true;
/// <summary>
/// 默认开启DateTime只读
/// </summary>
public const bool DEFAULT_DATETIME_DEFAULT_READONLY = true;
/// <summary>
/// 默认展开SearchPanel内容
/// </summary>
public const bool DEFAULT_SEARCHPANEL_DEFAULT_EXPAND = true;
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WalkingTec.Mvvm.Core.ConfigOptions
{
public class Domain
{
public string Name { get; set; }
public string Address { get; set; }
public string InnerAddress { get; set; }
public string EntryUrl { get; set; }
public string Url
{
get
{
var rv = Address;
if (string.IsNullOrEmpty(rv) == false && rv.ToLower().StartsWith("http://") == false && rv.ToLower().StartsWith("https://") == false)
{
rv = "http://" + rv;
}
return rv;
}
}
public string InnerUrl
{
get
{
var rv = InnerAddress;
if (string.IsNullOrEmpty(rv) == false && rv.ToLower().StartsWith("http://") == false && rv.ToLower().StartsWith("https://") == false)
{
rv = "http://" + rv;
}
return rv;
}
}
}
}

View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
namespace WalkingTec.Mvvm.Core.ConfigOptions
{
/// <summary>
/// FileOptions
/// </summary>
public class FileUploadOptions
{
/// <summary>
/// 文件保存位置
/// </summary>
public string SaveFileMode { get; set; }
/// <summary>
/// 上传文件限制 单位字节 默认 20 * 1024 * 1024 = 20971520 bytes
/// </summary>
public long UploadLimit { get; set; } = 20971520;
public Dictionary<string, List<FileHandlerOptions>> Settings { get; set; }
}
public class FileHandlerOptions
{
public string GroupName { get; set; }
public string GroupLocation { get; set; }
public string ServerUrl { get; set; }
public string Key { get; set; }
public string Secret { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System.Text;
namespace WalkingTec.Mvvm.Core
{
public class JwtOption
{
public string Issuer { get; set; } = "http://localhost";
public string Audience { get; set; } = "http://localhost";
public int Expires { get; set; } = 3600;
public string SecurityKey { get; set; } = "wtm";
public string LoginPath { get; set; }
public int RefreshTokenExpires { get; set; }
}
}

View File

@ -0,0 +1,19 @@
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// KV
/// </summary>
public class KV
{
/// <summary>
/// Key
/// </summary>
public string Key { get; set; }
/// <summary>
/// Value
/// </summary>
public string Value { get; set; }
}
}

View File

@ -0,0 +1,386 @@
using System.Text.Json.Serialization;
namespace WalkingTec.Mvvm.Core.ConfigOptions
{
public class UEditorOptions
{
#region
/// <summary>
/// 执行上传图片的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("imageActionName")]
public string ImageActionName { get; set; } = "UploadForLayUIUEditor";
/// <summary>
/// 提交的图片表单名称
/// </summary>
/// <value></value>
[JsonPropertyName("imageFieldName")]
public string ImageFieldName { get; set; } = "FileID";
/// <summary>
/// 上传大小限制单位B
/// </summary>
/// <value></value>
[JsonPropertyName("imageMaxSize")]
public int ImageMaxSize { get; set; } = 2048000;
/// <summary>
/// 上传图片格式显示
/// </summary>
/// <value></value>
[JsonPropertyName("imageAllowFiles")]
public string[] ImageAllowFiles { get; set; } = new string[] { ".png", ".jpg", ".jpeg", ".gif", ".bmp" };
/// <summary>
/// 是否压缩图片,默认是true
/// </summary>
/// <value></value>
[JsonPropertyName("imageCompressEnable")]
public bool ImageCompressEnable { get; set; } = true;
/// <summary>
/// 图片压缩最长边限制
/// </summary>
/// <value></value>
[JsonPropertyName("imageCompressBorder")]
public int ImageCompressBorder { get; set; } = 1600;
/// <summary>
/// 插入的图片浮动方式
/// </summary>
/// <value></value>
[JsonPropertyName("imageInsertAlign")]
public string ImageInsertAlign { get; set; } = "none";
/// <summary>
/// 图片访问路径前缀 默认返回全路径
/// </summary>
/// <value></value>
[JsonPropertyName("imageUrlPrefix")]
public string ImageUrlPrefix { get; set; } = string.Empty;
/* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
/* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
/* {time} 会替换成时间戳 */
/* {yyyy} 会替换成四位年份 */
/* {yy} 会替换成两位年份 */
/* {mm} 会替换成两位月份 */
/* {dd} 会替换成两位日期 */
/* {hh} 会替换成两位小时 */
/* {ii} 会替换成两位分钟 */
/* {ss} 会替换成两位秒 */
/* 非法字符 \ : * ? " < > | */
/* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */
/// <summary>
/// 上传保存路径,可以自定义保存路径和文件名格式
/// </summary>
/// <value></value>
[JsonPropertyName("imagePathFormat")]
public string ImagePathFormat { get; set; } = "upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
#endregion
#region
/// <summary>
/// 执行上传涂鸦的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("scrawlActionName")]
public string ScrawlActionName { get; set; } = "UploadForLayUIUEditor";
/// <summary>
/// 提交的图片表单名称
/// </summary>
/// <value></value>
[JsonPropertyName("scrawlFieldName")]
public string ScrawlFieldName { get; set; } = "FileID";
/// <summary>
/// 上传保存路径,可以自定义保存路径和文件名格式
/// </summary>
/// <value></value>
[JsonPropertyName("scrawlPathFormat")]
public string ScrawlPathFormat { get; set; } = "upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
/// <summary>
/// 上传大小限制单位B
/// </summary>
/// <value></value>
[JsonPropertyName("scrawlMaxSize")]
public int ScrawlMaxSize { get; set; } = 2048000;
/// <summary>
/// 图片访问路径前缀
/// </summary>
/// <value></value>
[JsonPropertyName("scrawlUrlPrefix")]
public string ScrawlUrlPrefix { get; set; } = string.Empty;
/// <summary>
/// 插入的图片浮动方式
/// </summary>
/// <value></value>
[JsonPropertyName("scrawlInsertAlign")]
public string ScrawlInsertAlign { get; set; } = "none";
#endregion
#region
/// <summary>
/// 执行上传截图的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("snapscreenActionName")]
public string SnapscreenActionName { get; set; } = "UploadForLayUIUEditor";
/// <summary>
/// 上传保存路径,可以自定义保存路径和文件名格式
/// </summary>
/// <value></value>
[JsonPropertyName("snapscreenPathFormat")]
public string SnapscreenPathFormat { get; set; } = "upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
/// <summary>
/// 图片访问路径前缀
/// </summary>
/// <value></value>
[JsonPropertyName("snapscreenUrlPrefix")]
public string SnapscreenUrlPrefix { get; set; } = string.Empty;
/// <summary>
/// 插入的图片浮动方式
/// </summary>
/// <value></value>
[JsonPropertyName("snapscreenInsertAlign")]
public string SnapscreenInsertAlign { get; set; } = "none";
#endregion
#region
[JsonPropertyName("catcherLocalDomain")]
public string[] CatcherLocalDomain { get; set; } = new string[] { "127.0.0.1", "localhost", "img.baidu.com" };
/// <summary>
/// 执行抓取远程图片的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("catcherActionName")]
public string CatcherActionName { get; set; } = "catchimage";
/// <summary>
/// 提交的图片列表表单名称
/// </summary>
/// <value></value>
[JsonPropertyName("catcherFieldName")]
public string CatcherFieldName { get; set; } = "source";
/// <summary>
/// 上传保存路径,可以自定义保存路径和文件名格式
/// </summary>
/// <value></value>
[JsonPropertyName("catcherPathFormat")]
public string CatcherPathFormat { get; set; } = "upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
/// <summary>
/// 图片访问路径前缀
/// </summary>
/// <value></value>
[JsonPropertyName("catcherUrlPrefix")]
public string CatcherUrlPrefix { get; set; } = string.Empty;
/// <summary>
/// 上传大小限制单位B
/// </summary>
/// <value></value>
[JsonPropertyName("catcherMaxSize")]
public int CatcherMaxSize { get; set; } = 2048000;
/// <summary>
/// 抓取图片格式显示
/// </summary>
/// <value></value>
[JsonPropertyName("catcherAllowFiles")]
public string[] CatcherAllowFiles { get; set; } = new string[] { ".png", ".jpg", ".jpeg", ".gif", ".bmp" };
#endregion
#region
/// <summary>
/// 执行上传视频的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("videoActionName")]
public string VideoActionName { get; set; } = "UploadForLayUIUEditor";
/// <summary>
/// 提交的视频表单名称
/// </summary>
/// <value></value>
[JsonPropertyName("videoFieldName")]
public string VideoFieldName { get; set; } = "FileID";
/// <summary>
/// 上传保存路径,可以自定义保存路径和文件名格式
/// </summary>
/// <value></value>
[JsonPropertyName("videoPathFormat")]
public string VideoPathFormat { get; set; } = "upload/video/{yyyy}{mm}{dd}/{time}{rand:6}";
/// <summary>
/// 视频访问路径前缀
/// </summary>
/// <value></value>
[JsonPropertyName("videoUrlPrefix")]
public string VideoUrlPrefix { get; set; } = string.Empty;
/// <summary>
/// 上传大小限制单位B默认100MB
/// </summary>
/// <value></value>
[JsonPropertyName("videoMaxSize")]
public int VideoMaxSize { get; set; } = 102400000;
/// <summary>
/// 上传视频格式显示
/// </summary>
/// <value></value>
[JsonPropertyName("videoAllowFiles")]
public string[] VideoAllowFiles { get; set; } = new string[] { ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid" };
#endregion
#region
/// <summary>
/// controller里,执行上传视频的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("fileActionName")]
public string FileActionName { get; set; } = "UploadForLayUIUEditor";
/// <summary>
/// 提交的文件表单名称
/// </summary>
/// <value></value>
[JsonPropertyName("fileFieldName")]
public string FileFieldName { get; set; } = "FileID";
/// <summary>
/// 上传保存路径,可以自定义保存路径和文件名格式
/// </summary>
/// <value></value>
[JsonPropertyName("filePathFormat")]
public string FilePathFormat { get; set; } = "upload/file/{yyyy}{mm}{dd}/{time}{rand:6}";
/// <summary>
/// 文件访问路径前缀
/// </summary>
/// <value></value>
[JsonPropertyName("fileUrlPrefix")]
public string FileUrlPrefix { get; set; } = string.Empty;
/// <summary>
/// 上传大小限制单位B默认50MB
/// </summary>
/// <value></value>
[JsonPropertyName("fileMaxSize")]
public int FileMaxSize { get; set; } = 51200000;
/// <summary>
/// 上传文件格式显示
/// </summary>
/// <value></value>
[JsonPropertyName("fileAllowFiles")]
public string[] FileAllowFiles { get; set; } = new string[] { ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml" };
#endregion
#region
/// <summary>
/// 执行图片管理的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("imageManagerActionName")]
public string ImageManagerActionName { get; set; } = "listimage";
/// <summary>
/// 指定要列出图片的目录
/// </summary>
/// <value></value>
[JsonPropertyName("imageManagerListPath")]
public string ImageManagerListPath { get; set; } = string.Empty;
/// <summary>
/// 每次列出文件数量
/// </summary>
/// <value></value>
[JsonPropertyName("imageManagerListSize")]
public int ImageManagerListSize { get; set; } = 20;
/// <summary>
/// 图片访问路径前缀
/// </summary>
/// <value></value>
[JsonPropertyName("imageManagerUrlPrefix")]
public string ImageManagerUrlPrefix { get; set; } = string.Empty;
/// <summary>
/// 插入的图片浮动方式
/// </summary>
/// <value></value>
[JsonPropertyName("imageManagerInsertAlign")]
public string ImageManagerInsertAlign { get; set; } = "none";
/// <summary>
/// 列出的文件类型
/// </summary>
/// <value></value>
[JsonPropertyName("imageManagerAllowFiles")]
public string[] ImageManagerAllowFiles { get; set; } = new string[] { ".png", ".jpg", ".jpeg", ".gif", ".bmp" };
#endregion
#region
/// <summary>
/// 执行文件管理的action名称
/// </summary>
/// <value></value>
[JsonPropertyName("fileManagerActionName")]
public string FileManagerActionName { get; set; } = "listfile";
/// <summary>
/// 指定要列出文件的目录
/// </summary>
/// <value></value>
[JsonPropertyName("fileManagerListPath")]
public string FileManagerListPath { get; set; } = "upload/file";
/// <summary>
/// 文件访问路径前缀
/// </summary>
/// <value></value>
[JsonPropertyName("fileManagerUrlPrefix")]
public string FileManagerUrlPrefix { get; set; } = "/ueditor/net/";
/// <summary>
/// 每次列出文件数量
/// </summary>
/// <value></value>
[JsonPropertyName("fileManagerListSize")]
public int FileManagerListSize { get; set; } = 20;
/// <summary>
/// 列出的文件类型
/// </summary>
/// <value></value>
[JsonPropertyName("fileManagerAllowFiles")]
public string[] FileManagerAllowFiles { get; set; } = new string[] { ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml" };
#endregion
}
}

View File

@ -0,0 +1,49 @@
namespace WalkingTec.Mvvm.Core.ConfigOptions
{
public class UIOptions
{
public DataTableOptions DataTable { get; set; }
public ComboBoxOptions ComboBox { get; set; }
public DateTimeOptions DateTime { get; set; }
public SearchPanelOptions SearchPanel { get; set; }
public class DataTableOptions
{
/// <summary>
/// 默认列表行数
/// </summary>
public int RPP { get; set; }
public bool ShowPrint { get; set; }
public bool ShowFilter { get; set; }
}
public class ComboBoxOptions
{
/// <summary>
/// 默认允许ComboBox搜索
/// </summary>
public bool DefaultEnableSearch { get; set; }
}
public class DateTimeOptions
{
/// <summary>
/// 默认开启DateTime只读
/// </summary>
public bool DefaultReadonly { get; set; }
}
public class SearchPanelOptions
{
/// <summary>
/// 默认展开SearchPanel内容
/// </summary>
public bool DefaultExpand { get; set; }
}
}
}

View File

@ -0,0 +1,34 @@
using System.Text.Json;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
namespace WalkingTec.Mvvm.Core
{
public class CoreProgram
{
public static IStringLocalizer _localizer {
get;
set;
}
public static JsonSerializerOptions DefaultJsonOption
{
get;set;
}
public static JsonSerializerOptions DefaultPostJsonOption
{
get; set;
}
public static string[] Buildindll = new string[]
{
"WalkingTec.Mvvm.Core",
"WalkingTec.Mvvm.Mvc",
"WalkingTec.Mvvm.Admin",
"WalkingTec.Mvvm.Taghelpers"
};
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,156 @@
using System.ComponentModel.DataAnnotations;
namespace WalkingTec.Mvvm.Core
{
public enum HttpMethodEnum
{
GET,
POST,
PUT,
DELETE
}
/// <summary>
/// 列表操作列类型
/// </summary>
public enum ColumnFormatTypeEnum
{
Dialog,//弹出窗口
Button,//按钮
Download,//下载
ViewPic,//查看图片
Script,//脚本
Html
}
/// <summary>
/// 数据库类型
/// </summary>
public enum DBTypeEnum { SqlServer, MySql, PgSql, Memory, SQLite, Oracle }
/// <summary>
/// 页面显示方式
/// </summary>
public enum PageModeEnum { Single, Tab }
/// <summary>
/// Tab页的显示方式
/// </summary>
public enum TabModeEnum { Default, Simple }
public enum BlazorModeEnum { Server, Wasm}
/// <summary>
/// 按钮
/// </summary>
public enum ButtonTypesEnum
{
Button,
Link
};
/// <summary>
/// 按钮
/// </summary>
public enum RedirectTypesEnum
{
Layer,
Self,
NewWindow,
NewTab,
};
/// <summary>
/// 日期类型
/// </summary>
public enum DateTimeTypeEnum
{
/// <summary>
/// 日期选择器
/// 可选择:年、月、日
/// </summary>
Date,
/// <summary>
/// 日期时间选择器
/// 可选择:年、月、日、时、分、秒
/// </summary>
DateTime,
/// <summary>
/// 年选择器
/// 只提供年列表选择
/// </summary>
Year,
/// <summary>
/// 年月选择器
/// 只提供年、月选择
/// </summary>
Month,
/// <summary>
/// 时间选择器
/// 只提供时、分、秒选择
/// </summary>
Time
};
/// <summary>
/// 图形枚举
/// </summary>
public enum ChartEnum
{
line,
pie,
column,
bubble,
barcolumn
}
/// <summary>
/// 图形统计值类型
/// </summary>
public enum ChartValueType
{
sum,
count,
sumpct,
countpct
}
/// <summary>
/// 图形统计分区类型
/// </summary>
public enum PartitionType
{
year,
month,
day,
hour,
minute,
second
}
public enum UIEnum
{ LayUI, React, VUE,Blazor }
public enum BoolComboTypes { YesNo, ValidInvalid, MaleFemale, HaveNotHave, Custom }
public enum SortDir { Asc, Desc }
public enum BackgroudColorEnum
{
Grey,
Yellow,
Red
};
public enum GenderEnum
{
[Display(Name = "Sys.Male")]
Male = 0,
[Display(Name = "Sys.Female")]
Female = 1
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Runtime.Serialization;
namespace WalkingTec.Mvvm.Core.Exceptions
{
/// <summary>
/// 对象为 null 或 空字符串 异常
/// </summary>
public class NullOrEmptyStringException : Exception
{
public const string DEFAULT_EXCEPTION_MSG = "对象为 null 或 空字符串 异常";
public NullOrEmptyStringException() : base(DEFAULT_EXCEPTION_MSG) { }
public NullOrEmptyStringException(string message) : base(message) { }
public NullOrEmptyStringException(string message, Exception innerException) : base(message, innerException) { }
protected NullOrEmptyStringException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}

View File

@ -0,0 +1,192 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
namespace WalkingTec.Mvvm.Core.Extensions
{
public static class ConfigExtension
{
/// <summary>
///
/// </summary>
/// <param name="configBuilder"></param>
/// <param name="env"></param>
/// <param name="jsonFileDir"></param>
/// <param name="jsonFileName"></param>
/// <returns></returns>
public static IConfigurationBuilder WTMConfig(this IConfigurationBuilder configBuilder, IHostEnvironment env, string jsonFileDir=null, string jsonFileName = null)
{
IConfigurationBuilder rv = configBuilder;
if (string.IsNullOrEmpty(jsonFileDir))
{
rv = rv.WTM_SetCurrentDictionary();
}
else
{
rv = rv.SetBasePath(jsonFileDir);
}
if (string.IsNullOrEmpty(jsonFileName))
{
rv = rv.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
}
else
{
rv = rv.AddJsonFile(jsonFileName, optional: true, reloadOnChange: true);
}
rv = rv.AddEnvironmentVariables();
if (env != null)
{
rv = rv.AddInMemoryCollection(new Dictionary<string, string> { { "HostRoot", env.ContentRootPath } });
}
else
{
rv = rv.AddInMemoryCollection(new Dictionary<string, string> { { "HostRoot", Directory.GetCurrentDirectory() } });
}
return rv;
}
public static IConfigurationBuilder WTM_SetCurrentDictionary(this IConfigurationBuilder cb)
{
CurrentDirectoryHelpers.SetCurrentDirectory();
if (!File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json")))
{
var binLocation = Assembly.GetEntryAssembly()?.Location;
if (!string.IsNullOrEmpty(binLocation))
{
var binPath = new FileInfo(binLocation).Directory?.FullName;
if (File.Exists(Path.Combine(binPath, "appsettings.json")))
{
Directory.SetCurrentDirectory(binPath);
cb.SetBasePath(binPath);
//.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
//.AddEnvironmentVariables();
}
}
}
else
{
cb.SetBasePath(Directory.GetCurrentDirectory());
}
return cb;
}
}
/// <summary>
/// 解决IIS InProgress下CurrentDirectory获取错误的问题
/// </summary>
internal class CurrentDirectoryHelpers
{
internal const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll";
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[System.Runtime.InteropServices.DllImport(AspNetCoreModuleDll)]
private static extern int http_get_application_properties(ref IISConfigurationData iiConfigData);
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct IISConfigurationData
{
public IntPtr pNativeApplication;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
public string pwzFullApplicationPath;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
public string pwzVirtualApplicationPath;
public bool fWindowsAuthEnabled;
public bool fBasicAuthEnabled;
public bool fAnonymousAuthEnable;
}
public static void SetCurrentDirectory()
{
try
{
// Check if physical path was provided by ANCM
var sitePhysicalPath = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH");
if (string.IsNullOrEmpty(sitePhysicalPath))
{
// Skip if not running ANCM InProcess
if (GetModuleHandle(AspNetCoreModuleDll) == IntPtr.Zero)
{
return;
}
IISConfigurationData configurationData = default(IISConfigurationData);
if (http_get_application_properties(ref configurationData) != 0)
{
return;
}
sitePhysicalPath = configurationData.pwzFullApplicationPath;
}
Environment.CurrentDirectory = sitePhysicalPath;
}
catch
{
// ignore
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace WalkingTec.Mvvm.Core.Extensions
{
public static class DistinctExtensions
{
public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector)
{
return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));
}
}
}

View File

@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace WalkingTec.Mvvm.Core.Extensions
{
/// <summary>
/// 树形结构Model的扩展函数
/// </summary>
public static class ITreeDataExtension
{
/// <summary>
/// 获取一个父节点下的所有子节点,包括子节点的子节点
/// </summary>
/// <typeparam name="T">树形结构类</typeparam>
/// <param name="self">树形结构实例</param>
/// <param name="order">排序字段,可为空</param>
/// <returns>树形结构列表,包含所有子节点</returns>
public static List<T> GetAllChildren<T>(this T self, Func<T, object> order = null)
where T : TreePoco<T>
{
List<T> rv = new List<T>();
var children = self.Children;
if(order != null && children != null)
{
children = children.OrderBy(order).ToList();
}
if (children != null && children.Count() > 0)
{
//var dictinct = children.Where(x => x.GetID().ToString() != self.GetID().ToString()).ToList();
foreach (var item in children)
{
rv.Add(item);
//递归添加子节点的子节点
rv.AddRange(item.GetAllChildren(order));
}
}
return rv;
}
public static int GetLevel<T>(this T self)
where T : TreePoco<T>
{
int level = 0;
while (self.Parent != null)
{
level++;
self = self.Parent;
}
return level;
}
/// <summary>
/// 查询数据库根据某个节点ID递归获取其下所有级别的子节点ID
/// </summary>
/// <typeparam name="T">树形结构类</typeparam>
/// <param name="self">树形结构实例</param>
/// <param name="dc">dc</param>
/// <param name="subids">子节点ID列表</param>
/// <returns>所有级别子节点ID</returns>
public static List<Guid> GetAllChildrenIDs<T>(this T self
, IDataContext dc
, List<Guid> subids = null)
where T : TreePoco<T>
{
List<Guid> rv = new List<Guid>();
List<Guid> ids = null;
if (subids == null)
{
ids = dc.Set<T>().Where(x => x.ParentId == self.ID).Select(x => x.ID).ToList();
}
else
{
ids = dc.Set<T>().Where(x => subids.Contains(x.ParentId.Value)).Select(x => x.ID).ToList();
}
if (ids != null && ids.Count > 0)
{
rv.AddRange(ids);
rv.AddRange(self.GetAllChildrenIDs(dc, ids));
}
return rv;
}
/// <summary>
/// 将树形结构列表转变为标准列表
/// </summary>
/// <typeparam name="T">树形结构类</typeparam>
/// <param name="self">树形结构实例</param>
/// <param name="order">排序字段,可以为空</param>
/// <returns>返回标准列表,所有节点都在同一级上</returns>
public static List<T> FlatTree<T>(this List<T> self, Func<T,object> order = null)
where T :TreePoco<T>
{
List<T> rv = new List<T>();
if(order != null)
{
self = self.OrderBy(order).ToList();
}
foreach (var item in self)
{
rv.Add(item);
rv.AddRange(item.GetAllChildren(order));
}
return rv;
}
/// <summary>
/// 将树形结构列表转变为标准列表
/// </summary>
/// <param name="self">树形结构实例</param>
/// <param name="order">排序字段,可以为空</param>
/// <returns>返回标准列表,所有节点都在同一级上</returns>
public static IEnumerable<TreeSelectListItem> FlatTreeSelectList(this IEnumerable<TreeSelectListItem> self, Func<TreeSelectListItem, object> order = null)
{
List<TreeSelectListItem> rv = new List<TreeSelectListItem>();
if (order != null)
{
self = self.OrderBy(order).ToList();
}
foreach (var item in self)
{
rv.Add(item);
if (item.Children != null)
{
rv.AddRange(item.GetTreeSelectChildren(order));
}
}
return rv;
}
/// <summary>
/// 获取TreeSelect节点下所有子节点
/// </summary>
/// <param name="self"></param>
/// <param name="order"></param>
/// <returns></returns>
public static List<TreeSelectListItem> GetTreeSelectChildren(this TreeSelectListItem self, Func<TreeSelectListItem, object> order = null)
{
List<TreeSelectListItem> rv = new List<TreeSelectListItem>();
var children = self.Children;
if (order != null && children != null)
{
children = children.OrderBy(order).ToList();
}
if (children != null && children.Count() > 0)
{
var dictinct = children.Where(x => x.Value != self.Value).ToList();
foreach (var item in dictinct)
{
rv.Add(item);
//递归添加子节点的子节点
rv.AddRange(item.GetTreeSelectChildren(order));
}
}
return rv;
}
}
}

View File

@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace WalkingTec.Mvvm.Core.Extensions
{
public static class ListExtension
{
/// <summary>
/// 将数据的List转化为下拉菜单数据List
/// </summary>
/// <typeparam name="T">源数据类</typeparam>
/// <param name="self">源数据List</param>
/// <param name="textField">指向text字段的表达式</param>
/// <param name="valueField">指向value字段的表达式</param>
/// <param name="selectedCondition">默认被选中的条件</param>
/// <returns>下拉菜单数据List</returns>
public static List<ComboSelectListItem> ToListItems<T>(this List<T> self
, Expression<Func<T, object>> textField
, Expression<Func<T, object>> valueField
, Expression<Func<T, bool>> selectedCondition = null)
{
var rv = new List<ComboSelectListItem>();
if (self != null)
{
//循环列表中的数据
foreach (var item in self)
{
//获取textField的值作为text
string text = textField.Compile().Invoke(item).ToString();
//获取valueField的值作为value
string value = valueField.Compile().Invoke(item).ToString();
//添加到下拉菜单List中
ComboSelectListItem li = new ComboSelectListItem();
li.Text = text;
li.Value = value;
//如果有默认选择的条件则将当前数据带入到判断表达式中如果返回true则将下拉数据的selected属性设为true
if (selectedCondition != null)
{
if (selectedCondition.Compile().Invoke(item))
{
li.Selected = true;
}
}
rv.Add(li);
}
}
return rv;
}
public static object ToChartData<T>(this List<T> self, int radius = 100, string seriesname = "Info")
{
//var data = string.Empty;
if (self != null && self.Count > 0)
{
var cd = self as List<ChartData>;
var i = 0;
for (i = 0; i < cd.Count; i++)
{
if (string.IsNullOrEmpty(cd[i].Series))
{
cd[i].Series = "Data";
}
}
string[] series = cd.Select(x => x.Series).Distinct().ToArray();
var yCount = cd.GroupBy(x => x.Category).ToList();
var isScatter = cd.Any(x => x.ValueX > 0);
var dataset = "{\"source\":[";
if (isScatter)
{
dataset = "[{\"source\":[";
i = 0;
foreach (var item in cd)
{
dataset += $"[{item.ValueX},{item.Value},{item.Addition},\"{item.Category}\",\"{item.Series}\"]";
if (i < cd.Count - 1)
{
dataset += ",";
}
i++;
}
dataset += "]},";
for (i = 0; i < series.Length; i++)
{
dataset += $"{{\"transform\": {{\"type\": \"filter\",\"config\": {{\"dimension\": 4,\"value\": \"{series[i]}\"}}}}}}";
if (i < series.Length - 1)
{
dataset += ",";
}
}
dataset += "]";
}
else
{
object[,] rtc = new object[yCount.Count + 1, series.Length + 1];
rtc[0, 0] = $"{seriesname}";
for (i = 0; i < series.Length; i++)
{
rtc[0, i + 1] = series[i];
}
i = 0;
foreach (var item in yCount)
{
rtc[i + 1, 0] = item.Key;
for (int j = 0; j < series.Length; j++)
{
var ser = item.Where(x => x.Series == series[j])?.FirstOrDefault();
if (ser != null)
{
rtc[i + 1, j + 1] = ser.Value;
}
else
{
rtc[i + 1, j + 1] = 0;
}
}
i++;
}
for (i = 0; i <= yCount.Count; i++)
{
dataset += "[";
for (int j = 0; j <= series.Length; j++)
{
dataset += $"\"{rtc[i, j]}\"";
if (j < series.Length)
{
dataset += ",";
}
}
dataset += "]";
if (i < yCount.Count)
{
dataset += ",";
}
}
dataset += "]}";
}
var seriesStr = "[";
var legend = "{\"data\":[";
var max = cd.Max(x => x.Addition);
for (i = 0; i < series.Length; i++)
{
seriesStr += $"{{\"type\":\"charttype\"";
if (isScatter)
{
seriesStr += $",\"encode\":{{\"x\":0,\"y\":1,\"tooltip\":[2,3]}},\"name\": \"{series[i]}\",\"datasetIndex\": {i + 1}";
seriesStr += $",\"symbolSize\": \"function(data) {{return data[2] / ({max} / {radius})}}\"";
}
seriesStr += "}";
legend += $"\"{series[i]}\"";
if (i < series.Length - 1)
{
seriesStr += ",";
legend += ",";
}
}
legend += "]}";
seriesStr += "]";
return new { dataset = dataset, series = seriesStr, legend = legend };
}
else
{
var dataset = "{\"source\":[]}";
var seriesStr = "[]";
var legend = "{\"data\":[]}";
return new { dataset = dataset, series = seriesStr, legend = legend };
}
}
}
}

View File

@ -0,0 +1,377 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WalkingTec.Mvvm.Core.Extensions
{
public static class ListVMExtension
{
/// <summary>
/// 获取Jason格式的列表数据
/// </summary>
/// <param name="self">是否需要对数据进行Json编码</param>
/// <param name="returnColumnObject">不在后台进行ColumnFormatInfo的转化而是直接输出ColumnFormatInfo的json结构到前端由前端处理默认False</param>
/// <param name="enumToString"></param>
/// <returns>Json格式的数据</returns>
public static string GetDataJson<T>(this IBasePagedListVM<T, BaseSearcher> self, bool returnColumnObject = false, bool enumToString = true) where T : TopBasePoco, new()
{
var sb = new StringBuilder();
self.GetHeaders();
if (self.IsSearched == false)
{
self.DoSearch();
}
var el = self.GetEntityList().ToList();
//如果列表主键都为0则生成自增主键避免主键重复
if (el.All(x => {
var id = x.GetID();
if(id == null || (id is Guid gid && gid == Guid.Empty) || (id is int iid && iid==0) || (id is long lid && lid == 0))
{
return true;
}
else
{
return false;
}
} ))
{
el.ForEach(x => x.ID = Guid.NewGuid());
}
//循环生成列表数据
for (int x = 0; x < el.Count; x++)
{
var sou = el[x];
sb.Append(self.GetSingleDataJson(sou, returnColumnObject, x, enumToString));
if (x < el.Count - 1)
{
sb.Append(',');
}
}
return $"[{sb}]";
}
private static string GetFormatResult(BaseVM vm, ColumnFormatInfo info)
{
string rv = "";
switch (info.FormatType)
{
case ColumnFormatTypeEnum.Dialog:
rv = vm.UIService.MakeDialogButton(info.ButtonType, info.Url, info.Text, info.Width, info.Height, info.Title, info.ButtonID, info.ShowDialog, info.Resizable, info.Maxed, info.ButtonClass, info.Style).ToString();
break;
case ColumnFormatTypeEnum.Button:
rv = vm.UIService.MakeButton(info.ButtonType, info.Url, info.Text, info.Width, info.Height, info.Title, info.ButtonID, info.Resizable, info.Maxed, vm.ViewDivId, info.ButtonClass, info.Style, info.RType).ToString();
break;
case ColumnFormatTypeEnum.Download:
if (info.FileID == null)
{
rv = "";
}
else
{
rv = vm.UIService.MakeDownloadButton(info.ButtonType, info.FileID.Value, info.Text, vm.CurrentCS, info.ButtonClass, info.Style).ToString();
}
break;
case ColumnFormatTypeEnum.ViewPic:
if (info.FileID == null)
{
rv = "";
}
else
{
rv = vm.UIService.MakeViewButton(info.ButtonType, info.FileID.Value, info.Text, info.Width, info.Height, info.Title, info.Resizable, vm.CurrentCS, info.Maxed, info.ButtonClass, info.Style).ToString();
}
break;
case ColumnFormatTypeEnum.Script:
rv = vm.UIService.MakeScriptButton(info.ButtonType, info.Text, info.Script, info.ButtonID, info.Url, info.ButtonClass, info.Style).ToString();
break;
case ColumnFormatTypeEnum.Html:
rv = info.Html;
break;
default:
break;
}
return rv;
}
/// <summary>
/// 生成单条数据的Json格式
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="obj">数据</param>
/// <param name="returnColumnObject">不在后台进行ColumnFormatInfo的转化而是直接输出ColumnFormatInfo的json结构到前端由前端处理默认False</param>
/// <param name="index">index</param>
/// <param name="enumToString"></param>
/// <returns>Json格式的数据</returns>
public static string GetSingleDataJson<T>(this IBasePagedListVM<T, BaseSearcher> self, object obj, bool returnColumnObject, int index = 0, bool enumToString = true) where T : TopBasePoco
{
bool inner = false;
var sb = new StringBuilder();
var RowBgColor = string.Empty;
var RowColor = string.Empty;
if (obj is not T sou)
{
sou = self.CreateEmptyEntity();
}
RowBgColor = self.SetFullRowBgColor(sou);
RowColor = self.SetFullRowColor(sou);
var isSelected = self.GetIsSelected(sou);
//循环所有列
sb.Append('{');
bool containsID = false;
bool addHiddenID = false;
Dictionary<string, (string, string)> colorcolumns = new Dictionary<string, (string, string)>();
foreach (var baseCol in self.GetHeaders())
{
foreach (var col in baseCol.BottomChildren)
{
inner = false;
if (col.ColumnType != GridColumnTypeEnum.Normal)
{
continue;
}
if (col.FieldName?.ToLower() == "id")
{
containsID = true;
}
var backColor = col.GetBackGroundColor(sou);
//获取ListVM中设定的单元格前景色
var foreColor = col.GetForeGroundColor(sou);
if (backColor == string.Empty)
{
backColor = RowBgColor;
}
if (foreColor == string.Empty)
{
foreColor = RowColor;
}
(string bgcolor, string forecolor) colors = (null, null);
if (backColor != string.Empty)
{
colors.bgcolor = backColor;
}
if (foreColor != string.Empty)
{
colors.forecolor = foreColor;
}
if (string.IsNullOrEmpty(colors.bgcolor) == false || string.IsNullOrEmpty(colors.forecolor) == false)
{
colorcolumns.Add(col.Field, colors);
}
//设定列名如果是主键ID则列名为id如果不是主键列则使用f0f1,f2...这种方式命名,避免重复
var ptype = col.FieldType;
if (col.Field?.ToLower() == "children" && typeof(IEnumerable<T>).IsAssignableFrom(ptype))
{
var children = ((IEnumerable<T>)col.GetObject(obj))?.ToList();
if (children == null || children.Count == 0)
{
continue;
}
}
var html = string.Empty;
if (col.EditType == EditTypeEnum.Text || col.EditType == null)
{
if (typeof(IEnumerable<T>).IsAssignableFrom(ptype))
{
var children = ((IEnumerable<T>)col.GetObject(obj))?.ToList();
if (children != null)
{
html = "[";
for (int i = 0; i < children.Count; i++)
{
var item = children[i];
html += self.GetSingleDataJson(item, returnColumnObject,0,enumToString);
if (i < children.Count - 1)
{
html += ",";
}
}
html += "]";
}
else
{
//html = "[]";
}
inner = true;
}
else
{
if (returnColumnObject == true)
{
html = col.GetText(sou, false).ToString();
}
else
{
var info = col.GetText(sou);
if (info is ColumnFormatInfo)
{
html = GetFormatResult(self as BaseVM, info as ColumnFormatInfo);
}
else if (info is List<ColumnFormatInfo>)
{
var temp = string.Empty;
foreach (var item in info as List<ColumnFormatInfo>)
{
temp += GetFormatResult(self as BaseVM, item);
temp += "&nbsp;&nbsp;";
}
html = temp;
}
else
{
html = info.ToString();
}
}
//如果列是布尔值直接返回true或false让前台生成CheckBox
if (ptype == typeof(bool) || ptype == typeof(bool?))
{
if(enumToString == false)
{
html = html.ToLower();
inner = true;
}
else if (returnColumnObject == false)
{
if (html.ToLower() == "true")
{
html = (self as BaseVM).UIService.MakeCheckBox(true, isReadOnly: true);
}
if (html.ToLower() == "false" || html == string.Empty)
{
html = (self as BaseVM).UIService.MakeCheckBox(false, isReadOnly: true);
}
}
else
{
if (html != null && html != string.Empty)
{
html = html.ToLower();
}
}
}
//如果列是枚举直接使用枚举的文本作为多语言的Key查询多语言文字
else if (ptype.IsEnumOrNullableEnum())
{
if (enumToString == true)
{
string enumdisplay = PropertyHelper.GetEnumDisplayName(ptype, html);
if (string.IsNullOrEmpty(enumdisplay) == false)
{
html = enumdisplay;
}
}
}
//If this column is a class or list, html will be set to a json string, sest inner to true to remove the "
if (returnColumnObject == true && ptype?.Namespace.Equals("System") == false && ptype?.IsEnumOrNullableEnum() == false)
{
inner = true;
}
}
if (enumToString == false && string.IsNullOrEmpty(html))
{
continue;
}
}
else
{
string val = col.GetText(sou).ToString();
string name = $"{self.DetailGridPrix}[{index}].{col.Field}";
switch (col.EditType)
{
case EditTypeEnum.TextBox:
html = (self as BaseVM).UIService.MakeTextBox(name, val);
break;
case EditTypeEnum.CheckBox:
_ = bool.TryParse(val, out bool nb);
html = (self as BaseVM).UIService.MakeCheckBox(nb, null, name, "true");
break;
case EditTypeEnum.ComboBox:
html = (self as BaseVM).UIService.MakeCombo(name, col.ListItems, val);
break;
case EditTypeEnum.Datetime:
html = (self as BaseVM).UIService.MakeDateTime(name, val);
break;
default:
break;
}
}
if (string.IsNullOrEmpty(self.DetailGridPrix) == false && addHiddenID == false)
{
html += $@"<input hidden name='{self.DetailGridPrix}[{index}].ID' value='{sou.GetID()}'/>";
addHiddenID = true;
}
if (inner == false)
{
html = "\"" + html.Replace(Environment.NewLine, "").Replace("\t", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty).Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
}
sb.Append($"\"{col.Field}\":");
sb.Append(html);
sb.Append(',');
}
}
sb.Append($"\"TempIsSelected\":\"{ (isSelected == true ? "1" : "0") }\"");
foreach (var cc in colorcolumns)
{
if (string.IsNullOrEmpty(cc.Value.Item1) == false)
{
string bg = cc.Value.Item1;
if (bg.StartsWith("#") == false)
{
bg = "#" + bg;
}
sb.Append($",\"{cc.Key}__bgcolor\":\"{bg}\"");
}
if (string.IsNullOrEmpty(cc.Value.Item2) == false)
{
string fore = cc.Value.Item2;
if (fore.StartsWith("#") == false)
{
fore = "#" + fore;
}
sb.Append($",\"{cc.Key}__forecolor\":\"{fore}\"");
}
}
if (containsID == false)
{
sb.Append($",\"ID\":\"{(sou as dynamic).ID}\"");
}
// 标识当前行数据是否被选中
sb.Append($@",""LAY_CHECKED"":{sou.Checked.ToString().ToLower()}");
sb.Append(string.Empty);
sb.Append('}');
return sb.ToString();
}
/// <summary>
/// Get json format string of ListVM's search result
/// </summary>
/// <typeparam name="T">Model type</typeparam>
/// <param name="self">a listvm</param>
/// <param name="PlainText">true to return plain text, false to return formated html, such as checkbox,buttons ...</param>
/// <param name="enumToString">use enum display name</param>
/// <returns>json string</returns>
public static string GetJson<T>(this IBasePagedListVM<T, BaseSearcher> self, bool PlainText = true, bool enumToString = true) where T : TopBasePoco, new()
{
return $@"{{""Data"":{self.GetDataJson(PlainText,enumToString)},""Count"":{self.Searcher.Count},""Page"":{self.Searcher.Page},""PageCount"":{self.Searcher.PageCount},""Msg"":""success"",""Code"":200}}";
}
public static object GetJsonForApi<T>(this IBasePagedListVM<T, BaseSearcher> self, bool PlainText = true) where T : TopBasePoco, new()
{
return new { Data = self.GetEntityList(), Count = self.Searcher.Count, PageCount = self.Searcher.PageCount, Page = self.Searcher.Page, Msg = "success", Code = 200 };
}
public static string GetError<T>(this IBasePagedListVM<T, BaseSearcher> self) where T : TopBasePoco, new()
{
return $@"{{""Data"":{{}},""Count"":0,""Page"":0,""PageCount"":0,""Msg"":""{(self as BaseVM).MSD.GetFirstError()}"",""Code"":400}}";
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using WalkingTec.Mvvm.Core.Auth;
namespace WalkingTec.Mvvm.Core.Extensions
{
public static class LoginUserInfoExtension
{
public static ClaimsPrincipal CreatePrincipal(this LoginUserInfo self)
{
if (string.IsNullOrEmpty(self.ITCode)) throw new ArgumentException("Id is mandatory", nameof(self.ITCode));
var claims = new List<Claim> { new Claim(AuthConstants.JwtClaimTypes.Subject, self.ITCode) };
if (!string.IsNullOrEmpty(self.Name))
{
claims.Add(new Claim(AuthConstants.JwtClaimTypes.Name, self.Name));
}
if (!string.IsNullOrEmpty(self.TenantCode))
{
claims.Add(new Claim(AuthConstants.JwtClaimTypes.TenantCode, self.TenantCode));
}
var id = new ClaimsIdentity(
claims.Distinct(new ClaimComparer()),
AuthConstants.AuthenticationType,
AuthConstants.JwtClaimTypes.Name,
AuthConstants.JwtClaimTypes.TenantCode);
return new ClaimsPrincipal(id);
}
}
}

View File

@ -0,0 +1,323 @@
using System;
using System.Linq.Expressions;
namespace WalkingTec.Mvvm.Core.Extensions
{
public static class PagedListExtension
{
#region MakeGridColumn GridColumn
/// <summary>
/// 生成GridColumn
/// </summary>
/// <typeparam name="T">继承自TopBasePoco的类</typeparam>
/// <typeparam name="V">继承自ISearcher的类</typeparam>
/// <param name="self">self</param>
/// <param name="ColumnExp">指向T中字段的表达式</param>
/// <param name="Format">格式化显示内容的委托函数,函数接受两个参数,第一个是整行数据,第二个是所选列的数据</param>
/// <param name="Header">表头名称</param>
/// <param name="Width">列宽</param>
/// <param name="Flex">是否填充</param>
/// <param name="AllowMultiLine">是否允许多行</param>
/// <param name="NeedGroup">是否需要分组</param>
/// <param name="ForeGroundFunc">设置前景色的委托函数</param>
/// <param name="BackGroundFunc">设置背景色的委托函数</param>
/// <returns>返回设置好的GridColumn类的实例</returns>
public static GridColumn<T> MakeGridColumn<T, V>(this IBasePagedListVM<T, V> self
, Expression<Func<T, object>> ColumnExp
, ColumnFormatCallBack<T> Format = null
, string Header = null
, int? Width = null
, int? Flex = null
, bool AllowMultiLine = true
, bool NeedGroup = false
, Func<T, string> ForeGroundFunc = null
, Func<T, string> BackGroundFunc = null)
where T : TopBasePoco
where V : ISearcher
{
GridColumn<T> rv = new GridColumn<T>(ColumnExp, Format, Header, Width, Flex, AllowMultiLine, NeedGroup, ForeGroundFunc, BackGroundFunc);
return rv;
}
#endregion
#region MakeActionGridColumn Grid动作列()
///// <summary>
///// 生成Grid动作列(增删该查)
///// </summary>
///// <typeparam name="T">继承自TopBasePoco的类</typeparam>
///// <typeparam name="V">继承自ISearcher的类</typeparam>
///// <param name="self">self</param>
///// <param name="Header">表头名称</param>
///// <param name="Width">列宽</param>
///// <returns>返回设置好的动作列</returns>
//public static GridColumn<T> MakeActionGridColumn<T, V>(this IBasePagedListVM<T, V> self
// , string Header = null
// , int? Width = null)
// where T : TopBasePoco
// where V : ISearcher
//{
// ActionGridColumn<T> rv = new ActionGridColumn<T>(Header, Width);
// rv.Sortable = false;
// return rv;
//}
#endregion
#region MakeGridAction
///// <summary>
///// 创建一个新的列表动作
///// </summary>
///// <typeparam name="T">继承自TopBasePoco的类</typeparam>
///// <typeparam name="V">继承自ISearcher的类</typeparam>
///// <param name="self">self</param>
///// <param name="name">动作名</param>
///// <param name="dialogTitle">弹出窗口标题</param>
///// <param name="controllerName">动作的Controller</param>
///// <param name="actionName">动作的Action</param>
///// <param name="paraType">动作类型</param>
///// <param name="showInRow">是否在每行都显示</param>
///// <param name="areaName">域名</param>
///// <param name="showDialog">是否需要弹出窗口默认为true</param>
///// <param name="dialogWidth">弹出窗口的宽度</param>
///// <param name="dialogHeight">弹出窗口的高度</param>
///// <param name="iconCls">动作图标css默认为null没有图标</param>
///// <param name="hideOnToolBar">是否在工具栏隐藏 默认false</param>
///// <param name="buttonId">Button的id 默认自动生成</param>
///// <param name="isRedirect">是否在新页面打开</param>
///// <returns>列表动作</returns>
//public static GridAction MakeGridAction<T, V>(this IBasePagedListVM<T, V> self
// , string name
// , string dialogTitle
// , string controllerName
// , string actionName
// , GridActionParameterTypesEnum paraType
// , bool showInRow
// , string areaName = null
// , bool showDialog = true
// , int? dialogWidth = null
// , int? dialogHeight = null
// , string iconCls = null
// , bool hideOnToolBar = false
// , string buttonId = null
// , bool isRedirect = false
// , bool resizable = true)
// where T : TopBasePoco
// where V : ISearcher
//{
// return new GridAction { Name = name, Area = areaName, ControllerName = controllerName, DialogTitle = dialogTitle, ActionName = actionName, DialogWidth = dialogWidth, DialogHeight = dialogHeight, ParameterType = paraType, ShowInRow = showInRow, OnClickFunc = null, ShowDialog = showDialog, IconCls = iconCls, HideOnToolBar = hideOnToolBar, ButtonId = buttonId, IsRedirect = isRedirect, Resizable = resizable };
//}
#endregion
#region MakeScriptGridAction js的列表动作
///// <summary>
///// 创建一个执行自定义js的列表动作
///// </summary>
///// <typeparam name="T">继承自TopBasePoco的类</typeparam>
///// <typeparam name="V">继承自ISearcher的类</typeparam>
///// <param name="self">self</param>
///// <param name="controllerName">动作的Controller</param>
///// <param name="actionName">动作的Action</param>
///// <param name="name">动作名</param>
///// <param name="script">点击动作按钮执行的js</param>
///// <param name="showInRow">是否在操作列中显示 默认true</param>
///// <param name="hideOnToolBar">是否在工具栏中隐藏 默认true</param>
///// <param name="areaName">动作的区域</param>
///// <param name="buttonId">Button的id 默认自动生成</param>
///// <returns>列表动作</returns>
///// <remarks>
///// 框架的自动权限验证无法验证自定义的js中跳转到的链接
///// 所以虽然只是运行js但如果js最终跳转到某个链接则还是需要在这里指定Controller和Action这样框架就可以自动判断权限
///// </remarks>
//public static GridAction MakeScriptGridAction<T, V>(this IBasePagedListVM<T, V> self
// , string controllerName
// , string actionName
// , string name
// , string script
// , string areaName = null
// , string buttonId = null
// , bool showInRow = true
// , bool hideOnToolBar = true
// , bool resizable = true)//add by wuwh 2014.05.07 添加hideOnToolBar参数
// where T : TopBasePoco
// where V : ISearcher
//{
// return new GridAction { Area = areaName, ControllerName = controllerName, ActionName = actionName, Name = name, OnClickFunc = script, ShowInRow = showInRow, ButtonId = buttonId, HideOnToolBar = hideOnToolBar, Resizable = resizable };
//}
#endregion
#region MakeStandardAction
////新增参数 whereStr
///// <summary>
///// 创建标准动作
///// </summary>
///// <typeparam name="T">继承自TopBasePoco的类</typeparam>
///// <typeparam name="V">继承自ISearcher的类</typeparam>
///// <param name="self">self</param>
///// <param name="controllerName">动作的Controller</param>
///// <param name="standardType">标准动作类型</param>
///// <param name="dialogTitle">弹出窗口的标题</param>
///// <param name="areaName">域名</param>
///// <param name="dialogWidth">弹出窗口的宽度</param>
///// <param name="dialogHeight">弹出窗口的高度</param>
///// <param name="name">动作名,默认为‘新建’</param>
///// <param name="buttonId">Button的id 默认自动生成</param>
///// <returns>列表动作</returns>
///// <remarks>
///// 根据标准动作类型,创建默认属性的标准动作
///// </remarks>
//public static GridAction MakeStandardAction<T, V>(this IBasePagedListVM<T, V> self
// , string controllerName
// , GridActionStandardTypesEnum standardType
// , string dialogTitle
// , string areaName = null
// , int? dialogWidth = null
// , int? dialogHeight = null
// , string name = null
// , string buttonId = null
// , bool resizable = true
// , params Expression<Func<T, object>>[] whereStr)
// where T : TopBasePoco
// where V : ISearcher
//{
// string iconcls = "";
// string action = "";
// string gridname = "";
// GridActionParameterTypesEnum paraType = GridActionParameterTypesEnum.NoId;
// bool showinrow = false;
// bool hideontoolbar = false;
// switch (standardType)
// {
// case GridActionStandardTypesEnum.Create:
// iconcls = "icon-add";
// action = "Create";
// gridname = "新建";
// paraType = GridActionParameterTypesEnum.NoId;
// break;
// case GridActionStandardTypesEnum.Edit:
// iconcls = "icon-edit";
// action = "Edit";
// gridname = "修改";
// paraType = GridActionParameterTypesEnum.SingleId;
// showinrow = true;
// hideontoolbar = true;
// break;
// case GridActionStandardTypesEnum.Delete:
// iconcls = "icon-delete";
// action = "Delete";
// gridname = "删除";
// paraType = GridActionParameterTypesEnum.SingleId;
// showinrow = true;
// hideontoolbar = true;
// break;
// case GridActionStandardTypesEnum.Details:
// iconcls = "icon-details";
// action = "Details";
// gridname = "详细";
// paraType = GridActionParameterTypesEnum.SingleId;
// showinrow = true;
// hideontoolbar = true;
// break;
// case GridActionStandardTypesEnum.BatchEdit:
// iconcls = "icon-edit";
// action = "BatchEdit";
// gridname = "批量修改";
// paraType = GridActionParameterTypesEnum.MultiIds;
// break;
// case GridActionStandardTypesEnum.BatchDelete:
// iconcls = "icon-delete";
// action = "BatchDelete";
// gridname = "批量删除";
// paraType = GridActionParameterTypesEnum.MultiIds;
// break;
// case GridActionStandardTypesEnum.Import:
// iconcls = "icon-details";
// action = "ImportExcelData";
// gridname = "导入";
// paraType = GridActionParameterTypesEnum.NoId;
// break;
// default:
// break;
// }
// List<string> list = new List<string>();
// foreach (var item in whereStr)
// {
// list.Add(PropertyHelper.GetPropertyName(item));
// }
// return new GridAction { Name = (name == null ? gridname : name), DialogTitle = dialogTitle, IconCls = iconcls, ControllerName = controllerName, ActionName = action, Area = areaName, DialogWidth = dialogWidth, DialogHeight = dialogHeight, ParameterType = paraType, ShowInRow = showinrow, ShowDialog = true, HideOnToolBar = hideontoolbar, ButtonId = buttonId, Resizable = resizable, whereStr = list.ToArray() };
//}
#endregion
#region MakeStandardExportAction
///// <summary>
///// 创建标准导出按钮
///// </summary>
///// <typeparam name="T">继承自TopBasePoco的类</typeparam>
///// <typeparam name="V">继承自ISearcher的类</typeparam>
///// <param name="self">self</param>
///// <param name="gridid">vmGuid</param>
///// <param name="MustSelect"></param>
///// <param name="exportType">导出类型 默认null支持所有导出</param>
///// <param name="param">参数</param>
///// <returns></returns>
//public static GridAction MakeStandardExportAction<T, V>(this IBasePagedListVM<T, V> self
// , string gridid = null
// , bool MustSelect = false
// , ExportEnum? exportType = null
// , params KeyValuePair<string, string>[] param)
// where T : TopBasePoco
// where V : ISearcher
//{
// string excelscript = "";
// string pdfscript = "";
// string parameters = "?";
// foreach (var item in param)
// {
// parameters += item.Key + "=" + item.Value + "&";
// }
// if (self.FromFixedCon == true)
// {
// parameters += "DONOTUSECSName=" + self.CurrentCS + "&";
// }
// parameters += "1=1";
// if (gridid == null)
// {
// gridid = "Grid" + self.UniqueId;
// }
// if (MustSelect == false)
// {
// excelscript = string.Format("FF_ShowMask(\"{1}\");FF_DownloadExcelOrPdfPost(\"{0}\",\"/WebApi/Home/ExportExcel{2}\");", gridid, "正在生成文件...", parameters);
// pdfscript = string.Format("FF_ShowMask(\"{1}\");FF_DownloadExcelOrPdfPost(\"{0}\",\"/WebApi/Home/ExportPdf{2}\");", gridid, "正在生成文件...", parameters);
// }
// else
// {
// excelscript += "var sels = Ext.getCmp(\"" + gridid + "\").getSelectionModel().getSelection();";
// excelscript += "if(sels.length == 0){ FF_OpenSimpleDialog(\"" + "错误" + "\",\"" + "请至少选择一条数据" + "\");} else{";
// excelscript += string.Format("FF_ShowMask(\"{1}\");FF_DownloadExcelOrPdfPost(\"{0}\",\"/WebApi/Home/ExportExcel{2}\");", gridid, "正在生成文件...", parameters) + "}";
// pdfscript += "var sels = Ext.getCmp(\"" + gridid + "\").getSelectionModel().getSelection();";
// pdfscript += "if(sels.length == 0){ FF_OpenSimpleDialog(\"" + "错误" + "\",\"" + "请至少选择一条数据" + "\");} else{";
// pdfscript += string.Format("FF_ShowMask(\"{1}\");FF_DownloadExcelOrPdfPost(\"{0}\",\"/WebApi/Home/ExportPdf{2}\");", gridid, "正在生成文件...", parameters) + "}";
// }
// GridAction ga = null;
// if (exportType == ExportEnum.Excel)
// {
// ga = new GridAction { Area = "WebApi", ControllerName = "Home", ActionName = "ExportExcel", Name = "导出Excel", ParameterType = GridActionParameterTypesEnum.NoId, OnClickFunc = excelscript, ShowInRow = false, Resizable = true };
// }
// else if (exportType == ExportEnum.PDF)
// {
// ga = new GridAction { Area = "WebApi", ControllerName = "Home", ActionName = "ExportExcel", Name = "导出PDF", ParameterType = GridActionParameterTypesEnum.NoId, OnClickFunc = excelscript, ShowInRow = false, Resizable = true };
// }
// else
// {
// ga = new GridAction { Area = "WebApi", ControllerName = "Home", ActionName = "ExportExcel", Name = "导出", ParameterType = GridActionParameterTypesEnum.NoId, OnClickFunc = excelscript, ShowInRow = false, Resizable = true };
// GridAction excel = new GridAction { Area = "WebApi", ControllerName = "Home", ActionName = "ExportExcel", Name = "导出Excel", ParameterType = GridActionParameterTypesEnum.NoId, OnClickFunc = excelscript, ShowInRow = false, Resizable = true };
// GridAction pdf = new GridAction { Area = "WebApi", ControllerName = "Home", ActionName = "ExportPdf", Name = "导出PDF", ParameterType = GridActionParameterTypesEnum.NoId, OnClickFunc = pdfscript, ShowInRow = false, Resizable = true };
// ga.SubActions = new List<GridAction> { excel, pdf };
// }
// return ga;
//}
#endregion
}
}

View File

@ -0,0 +1,81 @@
using System;
namespace WalkingTec.Mvvm.Core.Extensions
{
/// <summary>
/// DateTime Helper
/// </summary>
public static class DateTimeHelper
{
#region DateTime Helper
public static int WeekOfYear(this DateTime self)
{
var startDayOfYear = new DateTime(self.Year,1,1);
var weekOffset = 7 - ( startDayOfYear.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)startDayOfYear.DayOfWeek) + 1;
var weekOfYear = (int)Math.Ceiling((self.DayOfYear - weekOffset) / 7.0 + (weekOffset == 0 ? 0 : 1));
return weekOfYear;
}
/// <summary>
/// 获取 指定的一周所在年份 的开始及结束时间
/// </summary>
/// <param name="yearNum">所在年份</param>
/// <param name="weekOfYear">周数</param>
/// <param name="startDay">指定周开始时间</param>
/// <param name="endDay">指定周结束时间</param>
public static void WeekDays(int yearNum, int weekOfYear, out DateTime startDay, out DateTime endDay)
{
var startDayOfYear = new DateTime(yearNum,1,1,0,0,0);
var weekOffset = 7 - ( startDayOfYear.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)startDayOfYear.DayOfWeek) + 1;
startDay = startDayOfYear.AddDays(7 * (weekOfYear - (weekOffset == 0 ? 0 : 1)) + weekOffset - 7);
endDay = startDay.AddDays(7);
}
#endregion
#region DateTime Extensions
private static readonly DateTime _jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0,DateTimeKind.Utc);
/// <summary>
/// UTC 1970/01/01 00:00:00
/// </summary>
public static DateTime Jan1st1970 => _jan1st1970;
/// <summary>
/// 时间戳 ms
/// </summary>
/// <param name="self"></param>
/// <returns>返回标准时间戳 单位 毫秒 注:从 1970/01/01 00:00:00 开始</returns>
public static long ToMilliseconds(this DateTime self)
{
return (long)(self.ToUniversalTime() - Jan1st1970).TotalMilliseconds;
}
/// <summary>
/// 时间戳 microsecond
/// </summary>
/// <param name="self"></param>
/// <returns>返回标准时间戳 单位 微秒 注:从 1970/01/01 00:00:00 开始</returns>
public static long ToMicroseconds(this DateTime self)
{
return (long)((self.ToUniversalTime() - Jan1st1970).TotalMilliseconds * 1000);
}
/// <summary>
/// 获取当前时间所在周的开始及结束时间
/// </summary>
/// <param name="self"></param>
/// <param name="startDay">指定周开始时间</param>
/// <param name="endDay">指定周结束时间</param>
public static void WeekDays(this DateTime self, out DateTime startDay, out DateTime endDay)
{
WeekDays(self.Year, self.WeekOfYear(), out startDay, out endDay);
}
#endregion
}
}

View File

@ -0,0 +1,158 @@
//
// DistributedCacheExtensions.cs
//
// Author:
// Michael,Vito
//
// Copyright (c) 2019 WTM
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
namespace WalkingTec.Mvvm.Core.Extensions
{
public static class DistributedCacheExtensions
{
/// <summary>
/// CachingKey 分割符
/// </summary>
private const string SPLIT_CHAR = ":";
private static string _instanceName;
private static string InstanceName
{
get
{
if (_instanceName == null)
{
_instanceName = Assembly.GetEntryAssembly().GetName().Name + SPLIT_CHAR;
}
return _instanceName;
}
}
public static void SetInstanceName(
this IDistributedCache cache,
string instanceName)
{
_instanceName = instanceName + SPLIT_CHAR;
}
#region Get
public static T Get<T>(
this IDistributedCache cache,
string key)
{
var value = cache.GetString(InstanceName + key.ToLower());
if (value == null)
return default;
else
return JsonSerializer.Deserialize<T>(value,Core.CoreProgram.DefaultJsonOption);
}
public static async Task<T> GetAsync<T>(
this IDistributedCache cache,
string key,
CancellationToken token = default)
{
var value = await cache.GetStringAsync(InstanceName + key.ToLower(), token);
if (value == null)
return default;
else
return JsonSerializer.Deserialize<T>(value, Core.CoreProgram.DefaultJsonOption);
}
public static bool TryGetValue<T>(
this IDistributedCache cache,
string key,
out T outValue)
{
var value = cache.GetString(InstanceName + key.ToLower());
if (value == null)
{
outValue = default;
return false;
}
else
{
outValue = JsonSerializer.Deserialize<T>(value, Core.CoreProgram.DefaultJsonOption);
return true;
}
}
#endregion
#region Set
public static void Add<T>(
this IDistributedCache cache,
string key,
T value,
DistributedCacheEntryOptions options = null)
{
if (options == null)
cache.Set(InstanceName + key.ToLower(), Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, CoreProgram.DefaultJsonOption)));
else
cache.Set(InstanceName + key.ToLower(), Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, CoreProgram.DefaultJsonOption)), options);
}
public static async Task AddAsync<T>(
this IDistributedCache cache,
string key,
T value,
DistributedCacheEntryOptions options = null,
CancellationToken token = default)
{
if (options == null)
await cache.SetAsync(InstanceName + key.ToLower(), Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, CoreProgram.DefaultJsonOption)), token);
else
await cache.SetAsync(InstanceName + key.ToLower(), Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, CoreProgram.DefaultJsonOption)), options, token);
}
#endregion
#region Delete
public static void Delete(
this IDistributedCache cache,
string key)
{
cache.Remove(InstanceName + key.ToLower());
}
public static async Task DeleteAsync(
this IDistributedCache cache,
string key,
CancellationToken token = default)
{
await cache.RemoveAsync(InstanceName + key.ToLower(), token);
}
#endregion
}
}

View File

@ -0,0 +1,91 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace WalkingTec.Mvvm.Core.Extensions
{
/// <summary>
/// 枚举扩展函数
/// </summary>
public static class EnumExtension
{
#region
/// <summary>
/// 将枚举类型转化为下拉列表
/// </summary>
/// <param name="self">枚举类型</param>
/// <param name="value">value</param>
/// <param name="pleaseSelect">pleaseSelect</param>
/// <returns>下拉菜单数据列表</returns>
public static List<ComboSelectListItem> ToListItems(this Type self, object value = null, bool pleaseSelect = false)
{
string[] names = null;
Array values = null;
//如果是枚举
if (self.IsEnum)
{
names = Enum.GetNames(self);
values = Enum.GetValues(self);
}
//如果是nullable的枚举
if (self.IsGenericType && self.GenericTypeArguments[0].IsEnum)
{
names = Enum.GetNames(self.GenericTypeArguments[0]);
values = Enum.GetValues(self.GenericTypeArguments[0]);
}
//生成下拉菜单数据
List<ComboSelectListItem> rv = new List<ComboSelectListItem>();
if (names != null)
{
for(int i=0;i<names.Length;i++)
{
var name = names[i];
var newitem = new ComboSelectListItem { Text = PropertyHelper.GetEnumDisplayName(self, name), Value = values.GetValue(i).ToString() };
if(value is string)
{
if (value != null)
{
string v = value.ToString();
var vs = v.Split(',');
foreach (var item in vs)
{
if (item != null && (newitem.Value.ToString() == item.ToString())||name == item.ToString())
{
newitem.Selected = true;
break;
}
}
}
}
else if (value is IEnumerable it)
{
foreach (var item in it)
{
if (item != null && name == item.ToString())
{
newitem.Selected = true;
break;
}
}
}
else
{
if (value != null && name == value.ToString())
{
newitem.Selected = true;
}
}
rv.Add(newitem);
}
}
if (pleaseSelect == true)
{
rv.Insert(0, new ComboSelectListItem { Text = CoreProgram._localizer?["Sys.PleaseSelect"], Value = "" });
}
return rv;
}
#endregion
}
}

View File

@ -0,0 +1,230 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Linq.Expressions;
namespace WalkingTec.Mvvm.Core.Extensions
{
/// <summary>
/// 字符串辅助类
/// </summary>
public static class StringExtension
{
/// <summary>
/// 根据名字获取Id形式
/// </summary>
/// <param name="fieldName">名字</param>
/// <returns>将[].转换成_形式的Id</returns>
public static string GetIdByName(this string fieldName)
{
return fieldName == null ? "" : fieldName.Replace(".", "_").Replace("[", "_").Replace("]", "_");
}
/// <summary>
/// 格式化URL
/// </summary>
/// <param name="url">初始url</param>
/// <returns>格式化后的url</returns>
public static string CorrectUrl(this string url)
{
if (string.IsNullOrWhiteSpace(url) == true)
{
url = "";
}
else
{
url = url.ToLower();
url = url.Trim('/', '\\');
if (url.StartsWith("http://") == false && url.StartsWith("https://") == false)
{
url = "http://" + url;
}
}
return url;
}
/// <summary>
/// 将数据列表转化为逗号分隔的字符串
/// </summary>
/// <typeparam name="T">源数据类</typeparam>
/// <typeparam name="V">文本字段</typeparam>
/// <param name="self">源数据List</param>
/// <param name="textField">要拼接的文本字段</param>
/// <param name="Format">转化文本字段的表达式</param>
/// <param name="seperator">分隔符,默认为逗号</param>
/// <returns>转化后的字符串</returns>
public static string ToSepratedString<T, V>(this IEnumerable<T> self, Expression<Func<T, V>> textField, Func<V, string> Format = null, string seperator = ",")
{
string rv = "";
if (self == null)
{
return rv;
}
//循环所有数据
for (int i = 0; i < self.Count(); i++)
{
//获取文本字段的值
V text = textField.Compile().Invoke(self.ElementAt(i));
string str = "";
//如果有转换函数,则调用获取转换后的字符串
if (Format == null)
{
if (text == null)
{
str = "";
}
else
{
str = text.ToString();
}
}
else
{
str = Format.Invoke(text);
}
rv += str;
//拼接分隔符
if (i < self.Count() - 1)
{
rv += seperator;
}
}
//返回转化后的字符串
return rv;
}
public static string ToSepratedString(this IEnumerable self, Func<object, string> Format = null, string seperator = ",")
{
string rv = "";
if (self == null)
{
return rv;
}
foreach (var item in self)
{
var s = "";
if (Format == null)
{
s = item.ToString();
}
else
{
s = Format.Invoke(item);
}
if(string.IsNullOrEmpty(s) == false)
{
rv += s + seperator;
}
}
if (rv.Length > 0)
{
rv = rv.Substring(0, rv.Length - 1);
}
return rv;
}
public static string ToSepratedString(this NameValueCollection self, string seperator = ",")
{
string rv = "";
if (self == null)
{
return rv;
}
foreach (var item in self)
{
rv += item.ToString() + "=" + self[item.ToString()] + seperator;
}
if (rv.Length > 0)
{
rv = rv.Substring(0, rv.Length - 1);
}
return rv;
}
public static string AppendQuery(this string self,string query)
{
if(self == null)
{
return null;
}
if (self.Contains("?"))
{
self += "&" + query;
}
else
{
self += "?" + query;
}
return self;
}
public static string AppendQuery(this string self, IDictionary data)
{
if (self == null)
{
return null;
}
string query = "";
foreach (IDictionaryEnumerator item in data)
{
query += item.Key + "=" + item.Value + "&";
}
if (self.Contains("?"))
{
self += "&" + query;
}
else
{
self += "?" + query;
}
return self;
}
public static string AppendQuery(this string self, List<KeyValuePair<string, string>> data)
{
if (self == null)
{
return null;
}
string query = "";
foreach (var item in data)
{
query += item.Key + "=" + item.Value + "&";
}
if (self.Contains("?"))
{
self += "&" + query;
}
else
{
self += "?" + query;
}
return self;
}
public static string ToQueryString(this IEnumerable self, string name=null)
{
if(self == null)
{
return "";
}
if (string.IsNullOrEmpty(name))
{
name = "id";
}
string rv = "";
foreach (var item in self)
{
rv += $"{name}={item?.ToString()}&";
}
if(rv.Length > 0)
{
rv = rv[0..^1];
}
return rv;
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Reflection;
namespace WalkingTec.Mvvm.Core.Extensions
{
/// <summary>
/// System Extension
/// </summary>
public static class SystemExtension
{
#region Guid Extensions
public static string ToNoSplitString(this Guid self)
{
return self.ToString().Replace("-", string.Empty);
}
#endregion
/// <summary>
/// 将CrudVM中Entity的关联字段设为空并返回一个新的CrudVM
/// </summary>
/// <param name="self"></param>
/// <returns></returns>
public static object GetCleanCrudVM(this object self)
{
var mtype = self.GetType();
if(typeof(IBaseCRUDVM<TopBasePoco>).IsAssignableFrom(mtype))
{
var rv = mtype.GetConstructor(Type.EmptyTypes).Invoke(null);
var toppros = mtype.GetAllProperties();
foreach (var tpro in toppros)
{
if(tpro.Name == "Entity")
{
var entity = tpro.GetValue(self);
var pros = tpro.PropertyType.GetAllProperties();
var newEntity = tpro.PropertyType.GetConstructor(Type.EmptyTypes).Invoke(null);
bool isBasePoco = typeof(IBasePoco).IsAssignableFrom(tpro.PropertyType);
//将所有TopBasePoco的属性赋空值防止添加关联的重复内容
foreach (var pro in pros)
{
if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco)) == false)
{
if (isBasePoco == false || (pro.Name != "UpdateTime" && pro.Name != "UpdateBy"))
{
pro.SetValue(newEntity, pro.GetValue(entity));
}
}
}
tpro.SetValue(rv, newEntity);
}
else
{
if (tpro.CanWrite)
{
tpro.SetValue(rv, tpro.GetValue(self));
}
}
}
return rv;
}
return null;
}
}
}

View File

@ -0,0 +1,527 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;
using Fare;
namespace WalkingTec.Mvvm.Core.Extensions
{
/// <summary>
/// Type的扩展函数
/// </summary>
public static class TypeExtension
{
public static ImmutableDictionary<string, List<PropertyInfo>> _propertyCache { get; set; } = new Dictionary<string, List<PropertyInfo>>().ToImmutableDictionary();
/// <summary>
/// 判断是否是泛型
/// </summary>
/// <param name="self">Type类</param>
/// <param name="innerType">泛型类型</param>
/// <returns>判断结果</returns>
public static bool IsGeneric(this Type self, Type innerType)
{
if (self.GetTypeInfo().IsGenericType && self.GetGenericTypeDefinition() == innerType)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 判断是否为Nullable<>类型
/// </summary>
/// <param name="self">Type类</param>
/// <returns>判断结果</returns>
public static bool IsNullable(this Type self)
{
return self.IsGeneric(typeof(Nullable<>));
}
/// <summary>
/// 判断是否为List<>类型
/// </summary>
/// <param name="self">Type类</param>
/// <returns>判断结果</returns>
public static bool IsList(this Type self)
{
return self.IsGeneric(typeof(List<>)) || self.IsGeneric(typeof(IEnumerable<>));
}
/// <summary>
/// 判断是否为List<>类型
/// </summary>
/// <param name="self">Type类</param>
/// <returns>判断结果</returns>
public static bool IsListOf<T>(this Type self)
{
if (self.IsGeneric(typeof(List<>)) && typeof(T).IsAssignableFrom(self.GenericTypeArguments[0]))
{
return true;
}
else
{
return false;
}
}
#region
/// <summary>
/// 判断是否为枚举
/// </summary>
/// <param name="self">Type类</param>
/// <returns>判断结果</returns>
public static bool IsEnum(this Type self)
{
return self.GetTypeInfo().IsEnum;
}
/// <summary>
/// 判断是否为枚举或者可空枚举
/// </summary>
/// <param name="self"></param>
/// <returns></returns>
public static bool IsEnumOrNullableEnum(this Type self)
{
if (self == null)
{
return false;
}
if (self.IsEnum)
{
return true;
}
else
{
if (self.IsGenericType && self.GetGenericTypeDefinition() == typeof(Nullable<>) && self.GetGenericArguments()[0].IsEnum)
{
return true;
}
else
{
return false;
}
}
}
#endregion
/// <summary>
/// 判断是否为值类型
/// </summary>
/// <param name="self">Type类</param>
/// <returns>判断结果</returns>
public static bool IsPrimitive(this Type self)
{
return self.GetTypeInfo().IsPrimitive || self == typeof(decimal);
}
public static bool IsNumber(this Type self)
{
Type checktype = self;
if (self.IsNullable())
{
checktype = self.GetGenericArguments()[0];
}
if (checktype == typeof(int) || checktype == typeof(short) || checktype == typeof(long) || checktype == typeof(float) || checktype == typeof(decimal) || checktype == typeof(double))
{
return true;
}
else
{
return false;
}
}
#region Bool
public static bool IsBool(this Type self)
{
return self == typeof(bool);
}
/// <summary>
/// 判断是否是 bool or bool?类型
/// </summary>
/// <param name="self"></param>
/// <returns></returns>
public static bool IsBoolOrNullableBool(this Type self)
{
if (self == null)
{
return false;
}
if (self == typeof(bool) || self == typeof(bool?))
{
return true;
}
else
{
return false;
}
}
#endregion
public static Dictionary<string, string> GetRandomValues(this Type self)
{
Dictionary<string, string> rv = new Dictionary<string, string>();
string pat = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var pros = self.GetAllProperties();
List<string> skipFields = new List<string>()
{
nameof(TopBasePoco.BatchError),
nameof(TopBasePoco.Checked),
nameof(TopBasePoco.ExcelIndex),
};
if (typeof(IBasePoco).IsAssignableFrom(self))
{
skipFields.AddRange(
new string[]{
nameof(IBasePoco.CreateBy),
nameof(IBasePoco.CreateTime),
nameof(IBasePoco.UpdateBy),
nameof(IBasePoco.UpdateTime) }
);
}
if (typeof(IPersistPoco).IsAssignableFrom(self))
{
skipFields.Add(nameof(IPersistPoco.IsValid));
}
foreach (var pro in pros)
{
string key = pro.Name;
string val = "";
var notmapped = pro.GetCustomAttribute<NotMappedAttribute>();
if (notmapped == null &&
pro.PropertyType.IsList() == false &&
pro.PropertyType.IsSubclassOf(typeof(TopBasePoco)) == false &&
skipFields.Contains(key) == false
)
{
if (pro.PropertyType.IsNumber())
{
var range = pro.GetCustomAttribute<RangeAttribute>();
int start = 0;
int end = 100;
if (range != null)
{
try
{
start = (int)Math.Truncate(double.Parse(range.Minimum.ToString()));
end = (int)Math.Truncate(double.Parse(range.Maximum.ToString()));
}
catch { }
}
Random r = new Random();
val = r.Next(start, end).ToString();
}
else if (pro.PropertyType.IsBoolOrNullableBool())
{
List<string> boolvalues = new List<string> { "true", "false" };
if (pro.PropertyType.IsNullable())
{
boolvalues.Add("null");
}
Random r = new Random();
var index = r.Next(0, boolvalues.Count);
val = boolvalues[index];
}
else if (pro.PropertyType.IsEnumOrNullableEnum())
{
List<string> enumvalues = new List<string>();
Type enumtype = null;
if (pro.PropertyType.IsNullable())
{
enumtype = pro.PropertyType.GenericTypeArguments[0];
enumvalues.Add("null");
}
else
{
enumtype = pro.PropertyType;
}
var vs = Enum.GetValues(enumtype);
Random r = new Random();
var index = r.Next(0, vs.Length);
val = enumtype.FullName+"."+ vs.GetValue(index).ToString();
}
else if (pro.PropertyType == typeof(string))
{
var length = pro.GetCustomAttribute<StringLengthAttribute>();
var min = 1;
var max = 20;
var l = 0;
if (length != null)
{
if (length.MaximumLength > 0)
{
max = length.MaximumLength;
}
if(length.MinimumLength > 0)
{
min = length.MinimumLength;
}
}
if(min == max)
{
l = max;
}
else if(min < max)
{
l = new Random().Next(min, max);
}
Random r = new Random();
for (int i = 0; i < l; i++)
{
int index = r.Next(pat.Length);
val += pat[index];
}
val = "\"" + val + "\"";
}
else if(pro.PropertyType == typeof(DateTime) || pro.PropertyType == typeof(DateTime?))
{
Random r = new Random();
val = DateTime.Now.AddDays(r.Next(-500, 500)).ToString("yyyy-MM-dd HH:mm:ss");
val = $"DateTime.Parse(\"{val}\")";
}
if (pros.Where(x => x.Name.ToLower() + "id" == key.ToLower()).Any())
{
val = "$fk$";
}
if (val != "")
{
if (rv.ContainsKey(key) == false)
{
rv.Add(key, val);
}
}
}
}
return rv;
}
public static Dictionary<string, string> GetRandomValuesForTestData(this Type self)
{
Dictionary<string, string> rv = new Dictionary<string, string>();
string pat = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var pros = self.GetAllProperties();
List<string> skipFields = new List<string>()
{
nameof(TopBasePoco.BatchError),
nameof(TopBasePoco.Checked),
nameof(TopBasePoco.ExcelIndex),
};
if (typeof(IBasePoco).IsAssignableFrom(self))
{
skipFields.AddRange(
new string[]{
nameof(IBasePoco.CreateBy),
nameof(IBasePoco.CreateTime),
nameof(IBasePoco.UpdateBy),
nameof(IBasePoco.UpdateTime) }
);
}
if (typeof(IPersistPoco).IsAssignableFrom(self))
{
skipFields.Add(nameof(IPersistPoco.IsValid));
}
foreach (var pro in pros)
{
string key = pro.Name;
string val = "";
var notmapped = pro.GetCustomAttribute<NotMappedAttribute>();
var required = pro.GetCustomAttributes<RequiredAttribute>() != null;
if (notmapped == null &&
pro.PropertyType.IsList() == false &&
pro.PropertyType.IsSubclassOf(typeof(TopBasePoco)) == false &&
skipFields.Contains(key) == false
)
{
if (pro.PropertyType.IsNumber())
{
if (pro.Name == "ID")
{
val = "";
}
else
{
var range = pro.GetCustomAttribute<RangeAttribute>();
int start = 0;
int end = 100;
if (range != null)
{
try
{
start = (int)Math.Truncate(double.Parse(range.Minimum.ToString()));
end = (int)Math.Truncate(double.Parse(range.Maximum.ToString()));
}
catch { }
}
Random r = new Random();
val = r.Next(start, end).ToString();
}
}
else if (pro.PropertyType.IsBoolOrNullableBool())
{
List<string> boolvalues = new List<string> { "true", "false" };
if (pro.PropertyType.IsNullable())
{
if (required == false)
{
boolvalues.Add("");
}
}
Random r = new Random();
var index = r.Next(0, boolvalues.Count);
val = boolvalues[index];
}
else if (pro.PropertyType.IsEnumOrNullableEnum())
{
List<string> enumvalues = new List<string>();
Type enumtype = null;
if (pro.PropertyType.IsNullable())
{
enumtype = pro.PropertyType.GenericTypeArguments[0];
if (required == false)
{
enumvalues.Add("");
}
}
else
{
enumtype = pro.PropertyType;
}
var vs = Enum.GetValues(enumtype);
foreach (var item in vs)
{
enumvalues.Add((int)item + "");
}
Random r = new Random();
var index = r.Next(0, enumvalues.Count);
val = enumvalues[index];
}
else if (pro.PropertyType == typeof(string))
{
var reg = pro.GetCustomAttribute<RegularExpressionAttribute>();
var length = pro.GetCustomAttribute<StringLengthAttribute>();
if (reg != null) {
Xeger x = new Xeger(reg.Pattern);
val = x.Generate();
if(length != null)
{
if(length.MaximumLength > 0 && val.Length > length.MaximumLength)
{
val = val.Substring(0, length.MaximumLength-1);
}
}
}
else
{
var min = 1;
var max = 20;
var l = 0;
if (length != null)
{
if (length.MaximumLength > 0)
{
max = length.MaximumLength;
}
if (length.MinimumLength > 0)
{
min = length.MinimumLength;
}
}
if (min == max)
{
l = max;
}
else if (min < max)
{
l = new Random().Next(min, max);
}
Random r = new Random();
for (int i = 0; i < l; i++)
{
int index = r.Next(pat.Length);
val += pat[index];
}
}
val = "\"" + val + "\"";
}
else if (pro.PropertyType == typeof(DateTime) || pro.PropertyType == typeof(DateTime?))
{
Random r = new Random();
val = DateTime.Now.AddDays(r.Next(-500, 500)).ToString("yyyy-MM-dd HH:mm:ss");
}
if (pros.Where(x => x.Name.ToLower() + "id" == key.ToLower()).Any())
{
val = "$fk$";
}
if (val != "")
{
if (rv.ContainsKey(key) == false)
{
rv.Add(key, val);
}
}
}
}
return rv;
}
public static PropertyInfo GetSingleProperty(this Type self, string name)
{
if (_propertyCache.ContainsKey(self.FullName) == false)
{
var properties = self.GetProperties().ToList();
_propertyCache = _propertyCache.Add(self.FullName, properties);
return properties.Where(x => x.Name == name).FirstOrDefault();
}
else
{
return _propertyCache[self.FullName].Where(x => x.Name == name).FirstOrDefault();
}
}
public static PropertyInfo GetSingleProperty(this Type self, Func<PropertyInfo,bool> where)
{
if (_propertyCache.ContainsKey(self.FullName) == false)
{
var properties = self.GetProperties().ToList();
_propertyCache = _propertyCache.Add(self.FullName, properties);
return properties.Where(where).FirstOrDefault();
}
else
{
return _propertyCache[self.FullName].Where(where).FirstOrDefault();
}
}
public static List<PropertyInfo> GetAllProperties(this Type self)
{
if (_propertyCache.ContainsKey(self.FullName) == false)
{
var properties = self.GetProperties().ToList();
_propertyCache = _propertyCache.Add(self.FullName, properties);
return properties;
}
else
{
return _propertyCache[self.FullName];
}
}
}
}

View File

@ -0,0 +1,10 @@
namespace WalkingTec.Mvvm.Core
{
public static class GlobalConstants
{
public static class CacheKey
{
public const string UserInfo = "WtmUserInfo";
}
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using WalkingTec.Mvvm.Core.Support.Json;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 应用全局缓存
/// </summary>
public class GlobalData
{
/// <summary>
/// 程序集
/// </summary>
public List<Assembly> AllAssembly { get; set; }
/// <summary>
/// 可访问的url地址
/// </summary>
public List<string> AllAccessUrls { get; set; }
public Type CustomUserType { get; set; }
/// <summary>
/// 模块
/// </summary>
public List<SimpleModule> AllModule { get; set; }
private Func<List<SimpleMenu>> MenuGetFunc;
public List<SimpleMenu> AllMenus => MenuGetFunc?.Invoke();
/// <summary>
/// 设置菜单委托
/// </summary>
/// <param name="func"></param>
public void SetMenuGetFunc(Func<List<SimpleMenu>> func) => MenuGetFunc = func;
public List<Type> GetTypesAssignableFrom<T>()
{
var rv = new List<Type>();
foreach (var ass in AllAssembly)
{
var types = new List<Type>();
try
{
types.AddRange(ass.GetExportedTypes());
}
catch { }
rv.AddRange(types.Where(x => typeof(T).IsAssignableFrom(x) && x != typeof(T) && x.IsAbstract == false).ToList());
}
return rv;
}
}
}

View File

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// GlobalServices
/// </summary>
//public static class GlobalServices
//{
// private static IServiceProvider _serviceProvider = null;
// /// <summary>
// /// IocContainer
// /// </summary>
// public static IServiceProvider ServiceProvider => _serviceProvider;
// /// <summary>
// /// SetServiceProvider
// /// </summary>
// /// <param name="container"></param>
// public static void SetServiceProvider(IServiceProvider container) { _serviceProvider = container; }
// #region GetServicce
// /// <summary>
// /// GetService
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <returns></returns>
// public static T GetService<T>() where T : class => ServiceProvider?.GetService<T>();
// /// <summary>
// /// GetService
// /// </summary>
// /// <param name="type"></param>
// /// <returns></returns>
// public static object GetService(Type type) => ServiceProvider?.GetService(type);
// /// <summary>
// /// GetServices
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <returns></returns>
// public static IEnumerable<T> GetServices<T>() where T : class => ServiceProvider?.GetServices<T>();
// /// <summary>
// /// GetServices
// /// </summary>
// /// <param name="type"></param>
// /// <returns></returns>
// public static IEnumerable<object> GetServices(Type type) => ServiceProvider?.GetServices(type);
// /// <summary>
// /// GetRequiredService
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <returns></returns>
// public static T GetRequiredService<T>() where T : class => ServiceProvider?.GetRequiredService<T>();
// /// <summary>
// /// GetRequiredService
// /// </summary>
// /// <param name="type"></param>
// /// <returns></returns>
// public static object GetRequiredService(Type type) => ServiceProvider?.GetRequiredService(type);
// #endregion
//}
}

View File

@ -0,0 +1,224 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web;
namespace WalkingTec.Mvvm.Core
{
#region
/// <summary>
/// 列表动作类型
/// </summary>
public enum GridActionParameterTypesEnum
{
/// <summary>
/// 不需要传递Id
/// </summary>
NoId,
/// <summary>
/// 只传递一个Id
/// </summary>
SingleId,
/// <summary>
/// 传递多个Id
/// </summary>
MultiIds,
/// <summary>
/// 只传递一个Id但 Id 可能为null
/// </summary>
SingleIdWithNull,
/// <summary>
/// 传递多个 Id 或 null
/// </summary>
MultiIdWithNull,
AddRow,
RemoveRow
}
#endregion
#region
/// <summary>
/// 标准列表动作
/// </summary>
public enum GridActionStandardTypesEnum
{
Create,
Edit,
Delete,
SimpleDelete,
Details,
BatchEdit,
BatchDelete,
SimpleBatchDelete,
Import,
ExportExcel,
AddRow,
RemoveRow,
ActionsGroup
}
#endregion
#region
public enum ExportEnum
{
[Display(Name = "Excel")]
Excel = 0,
[Display(Name = "PDF")]
PDF = 1
}
#endregion
/// <summary>
/// 列表动作类,负责处理列表动作条中的动作按钮
/// </summary>
public class GridAction
{
#region Action属性
/// <summary>
/// 按钮Id一般不需要设定系统会自动生成唯一Id。如果设定请确保 Id 的唯一性
/// </summary>
public string ButtonId { get; set; }
/// <summary>
/// 按钮名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 弹出窗口的标题
/// </summary>
public string DialogTitle { get; set; }
/// <summary>
/// 如果不为null则只运行这个变量设定的script其他的属性都不起作用
/// </summary>
public string OnClickFunc { get; set; }
/// <summary>
/// 是否在每行都显示
/// </summary>
public bool ShowInRow { get; set; }
/// <summary>
/// 是否在工具栏上隐藏按钮
/// </summary>
public bool HideOnToolBar { get; set; }
/// <summary>
/// bind to a column name to deside whether or not to show this action
/// </summary>
public string BindVisiableColName { get; set; }
/// <summary>
/// additional css class of button
/// </summary>
public string ButtonClass { get; set;}
/// <summary>
/// if the dialog need to be maximax
/// </summary>
public bool Max { get; set; }
/// <summary>
/// If this action is to download a file
/// </summary>
public bool IsDownload { get; set; }
#region
/// <summary>
/// 动作的Area
/// </summary>
public string Area { get; set; }
public bool IsExport { get; set; }
/// <summary>
/// 动作的Controller
/// </summary>
public string ControllerName { get; set; }
/// <summary>
/// 动作的Action
/// </summary>
public string ActionName { get; set; }
public string Url
{
get
{
var rv = "";
if(string.IsNullOrEmpty(ControllerName) == false){
rv = $"/{HttpUtility.UrlEncode(ControllerName)}/{HttpUtility.UrlEncode(ActionName)}";
if (!string.IsNullOrEmpty(Area))
{
rv = $"/{HttpUtility.UrlEncode(Area)}{rv}";
}
if (!string.IsNullOrEmpty(QueryString))
{
rv = $"{rv}?{QueryString}";
}
else
{
rv = $"{rv}?1=1"; ;
}
}
return rv;
}
}
#endregion
/// <summary>
/// 是否跳转到新页面
/// </summary>
public bool IsRedirect { get; set; }
/// <summary>
/// 弹出问询框
/// </summary>
public string PromptMessage { get; set; }
/// <summary>
/// 动作类型
/// </summary>
public GridActionParameterTypesEnum ParameterType { get; set; }
public bool ForcePost { get; set; }
#endregion
#region
/// <summary>
/// 是否可以resizable
/// </summary>
public bool Resizable { get; set; }
/// <summary>
/// 动作图标css
/// </summary>
public string IconCls { get; set; }
/// <summary>
/// 动作的QueryString
/// </summary>
public string QueryString { get; set; }
/// <summary>
/// 弹出窗口的宽度
/// </summary>
public int? DialogWidth { get; set; }
/// <summary>
/// 弹出窗口的高度
/// </summary>
public int? DialogHeight { get; set; }
/// <summary>
/// 是否需要弹出窗口
/// </summary>
public bool ShowDialog { get; set; }
/// <summary>
/// 如果设定了SubActions则代表需要用SplitButton的形式展示主GridAction将不起作用
/// </summary>
public List<GridAction> SubActions { get; set; }
public string[] whereStr { get; set; }
#endregion
}
}

View File

@ -0,0 +1,424 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// GridActionExtension
/// </summary>
public static class GridActionExtensions
{
#region MakeStandardAction
/// <summary>
/// 创建标准动作
/// </summary>
/// <typeparam name="T">继承自TopBasePoco的类</typeparam>
/// <typeparam name="V">继承自ISearcher的类</typeparam>
/// <param name="self">self</param>
/// <param name="controllerName">动作的Controller</param>
/// <param name="standardType">标准动作类型</param>
/// <param name="dialogTitle">弹出窗口的标题,可为空,代表使用默认文字</param>
/// <param name="areaName">域名</param>
/// <param name="dialogWidth">弹出窗口的宽度</param>
/// <param name="dialogHeight">弹出窗口的高度</param>
/// <param name="name">按钮显示的文字</param>
/// <param name="buttonId">Button的id 默认自动生成</param>
/// <param name="whereStr">whereStr</param>
/// <returns>列表动作</returns>
/// <remarks>
/// 根据标准动作类型,创建默认属性的标准动作
/// </remarks>
public static GridAction MakeStandardAction<T, V>(this IBasePagedListVM<T, V> self
, string controllerName
, GridActionStandardTypesEnum standardType
, string dialogTitle
, string areaName = null
, int? dialogWidth = null
, int? dialogHeight = null
, string name = null
, string buttonId = null
, params Expression<Func<T, object>>[] whereStr)
where T : TopBasePoco
where V : ISearcher
{
var iconcls = string.Empty;
var actionName = standardType.ToString();
var gridname = string.Empty;
var paraType = GridActionParameterTypesEnum.NoId;
var showInRow = false;
var hideOnToolBar = false;
var showDialog = true;
var isexport = false;
string msg = null;
var ispost = false;
string qs = null;
switch (standardType)
{
case GridActionStandardTypesEnum.Create:
iconcls = "layui-icon layui-icon-add-1";
gridname = CoreProgram._localizer?["Sys.Create"];
paraType = GridActionParameterTypesEnum.NoId;
break;
case GridActionStandardTypesEnum.AddRow:
iconcls = "layui-icon layui-icon-add-1";
gridname = CoreProgram._localizer?["Sys.Create"];
paraType = GridActionParameterTypesEnum.AddRow;
break;
case GridActionStandardTypesEnum.Edit:
iconcls = "layui-icon layui-icon-edit";
gridname = CoreProgram._localizer?["Sys.Edit"];
paraType = GridActionParameterTypesEnum.SingleId;
showInRow = true;
hideOnToolBar = true;
break;
case GridActionStandardTypesEnum.Delete:
iconcls = "layui-icon layui-icon-delete";
gridname = CoreProgram._localizer?["Sys.Delete"];
paraType = GridActionParameterTypesEnum.SingleId;
showInRow = true;
hideOnToolBar = true;
break;
case GridActionStandardTypesEnum.SimpleDelete:
iconcls = "layui-icon layui-icon-delete";
gridname = CoreProgram._localizer?["Sys.Delete"];
paraType = GridActionParameterTypesEnum.SingleIdWithNull;
showInRow = true;
hideOnToolBar = true;
showDialog = false;
actionName = "BatchDelete";
qs = "_donotuse_sd=1";
ispost = true;
msg = CoreProgram._localizer?["Sys.DeleteConfirm"];
break;
case GridActionStandardTypesEnum.RemoveRow:
iconcls = "layui-icon layui-icon-delete";
gridname = CoreProgram._localizer?["Sys.Delete"];
paraType = GridActionParameterTypesEnum.RemoveRow;
showInRow = true;
hideOnToolBar = true;
break;
case GridActionStandardTypesEnum.Details:
iconcls = "layui-icon layui-icon-form";
gridname = CoreProgram._localizer?["Sys.Details"];
paraType = GridActionParameterTypesEnum.SingleId;
showInRow = true;
hideOnToolBar = true;
break;
case GridActionStandardTypesEnum.BatchEdit:
iconcls = "layui-icon layui-icon-edit";
gridname = CoreProgram._localizer?["Sys.BatchEdit"];
paraType = GridActionParameterTypesEnum.MultiIds;
break;
case GridActionStandardTypesEnum.BatchDelete:
iconcls = "layui-icon layui-icon-delete";
gridname = CoreProgram._localizer?["Sys.BatchDelete"];
paraType = GridActionParameterTypesEnum.MultiIds;
break;
case GridActionStandardTypesEnum.SimpleBatchDelete:
iconcls = "layui-icon layui-icon-delete";
gridname = CoreProgram._localizer?["Sys.BatchDelete"];
paraType = GridActionParameterTypesEnum.MultiIds;
showDialog = false;
msg = CoreProgram._localizer?["Sys.BatchDeleteConfirm"];
actionName = "BatchDelete";
ispost = true;
break;
case GridActionStandardTypesEnum.Import:
iconcls = "layui-icon layui-icon-templeate-1";
gridname = CoreProgram._localizer?["Sys.Import"];
paraType = GridActionParameterTypesEnum.NoId;
break;
case GridActionStandardTypesEnum.ExportExcel:
iconcls = "layui-icon layui-icon-download-circle";
gridname = CoreProgram._localizer?["Sys.Export"];
paraType = GridActionParameterTypesEnum.MultiIdWithNull;
name = CoreProgram._localizer?["Sys.ExportExcel"];
showInRow = false;
showDialog = false;
hideOnToolBar = false;
isexport = true;
break;
default:
break;
}
if (string.IsNullOrEmpty(dialogTitle))
{
dialogTitle = gridname;
}
var list = new List<string>();
foreach (var item in whereStr)
{
list.Add(PropertyHelper.GetPropertyName(item));
}
return new GridAction
{
ButtonId = buttonId,
Name = (name ?? gridname),
DialogTitle = dialogTitle,
Area = areaName,
ControllerName = controllerName,
ActionName = actionName,
ParameterType = paraType,
IconCls = iconcls,
DialogWidth = dialogWidth ?? 800,
DialogHeight = dialogHeight,
ShowInRow = showInRow,
ShowDialog = showDialog,
HideOnToolBar = hideOnToolBar,
PromptMessage = msg,
ForcePost = ispost,
QueryString = qs,
IsExport = isexport,
whereStr = list.ToArray()
};
}
#endregion
#region MakeAction
/// <summary>
/// 创建标准动作
/// </summary>
/// <typeparam name="T">继承自TopBasePoco的类</typeparam>
/// <typeparam name="V">继承自ISearcher的类</typeparam>
/// <param name="self">self</param>
/// <param name="controllerName">动作的Controller</param>
/// <param name="actionName">actionName</param>
/// <param name="name">动作名,默认为‘新建’</param>
/// <param name="dialogTitle">弹出窗口的标题</param>
/// <param name="paraType">paraType</param>
/// <param name="areaName">域名</param>
/// <param name="dialogWidth">弹出窗口的宽度</param>
/// <param name="dialogHeight">弹出窗口的高度</param>
/// <param name="buttonId">Button的id 默认自动生成</param>
/// <param name="whereStr">whereStr</param>
/// <returns>列表动作</returns>
/// <remarks>
/// 根据标准动作类型,创建默认属性的标准动作
/// </remarks>
public static GridAction MakeAction<T, V>(this IBasePagedListVM<T, V> self
, string controllerName
, string actionName
, string name
, string dialogTitle
, GridActionParameterTypesEnum paraType
, string areaName = null
, int? dialogWidth = null
, int? dialogHeight = null
, string buttonId = null
, params Expression<Func<T, object>>[] whereStr)
where T : TopBasePoco
where V : ISearcher
{
var iconcls = string.Empty;
var list = new List<string>();
foreach (var item in whereStr)
{
list.Add(PropertyHelper.GetPropertyName(item));
}
return new GridAction
{
ButtonId = buttonId,
Name = name,
DialogTitle = dialogTitle,
Area = areaName,
ControllerName = controllerName,
ActionName = actionName,
ParameterType = paraType,
IconCls = iconcls,
DialogWidth = dialogWidth ?? 800,
DialogHeight = dialogHeight,
ShowDialog = true,
whereStr = list.ToArray()
};
}
public static GridAction MakeActionsGroup<T, V>(this IBasePagedListVM<T, V> self
, string name
, List<GridAction> subActions
, params Expression<Func<T, object>>[] whereStr)
where T : TopBasePoco
where V : ISearcher
{
var iconcls = string.Empty;
var list = new List<string>();
foreach (var item in whereStr)
{
list.Add(PropertyHelper.GetPropertyName(item));
}
return new GridAction
{
ButtonId = Guid.NewGuid().ToString(),
Name = name,
DialogTitle = "",
Area = "",
ControllerName = "",
ActionName = "ActionsGroup",
ParameterType = GridActionParameterTypesEnum.NoId,
IconCls = iconcls,
DialogWidth = 0,
DialogHeight = 0,
ShowDialog = false,
whereStr = list.ToArray(),
SubActions= subActions
};
}
#endregion
#region MakeStandardExportAction
/// <summary>
/// 创建标准导出按钮
/// </summary>
/// <typeparam name="T">继承自TopBasePoco的类</typeparam>
/// <typeparam name="V">继承自ISearcher的类</typeparam>
/// <param name="self">self</param>
/// <param name="gridid">vmGuid</param>
/// <param name="MustSelect"></param>
/// <param name="exportType">导出类型 默认null支持所有导出</param>
/// <param name="param">参数</param>
/// <returns></returns>
[Obsolete("Will be removed in future, use MakeStandardAction with GridActionStandardTypesEnum.ExportExcel instead")]
public static GridAction MakeStandardExportAction<T, V>(this IBasePagedListVM<T, V> self
, string gridid = null
, bool MustSelect = false
, ExportEnum? exportType = null
, params KeyValuePair<string, string>[] param)
where T : TopBasePoco
where V : ISearcher
{
exportType = ExportEnum.Excel;
var action = new GridAction
{
Name = CoreProgram._localizer?["Sys.ExportExcel"],
DialogTitle = CoreProgram._localizer?["Sys.ExportExcel"],
Area = string.Empty,
ControllerName = "_Framework",
ActionName = "GetExportExcel",
ParameterType = GridActionParameterTypesEnum.MultiIdWithNull,
IconCls = "layui-icon layui-icon-download-circle",
ShowInRow = false,
ShowDialog = false,
HideOnToolBar = false
};
return action;
}
#endregion
#region Set Property
/// <summary>
/// Set the dialog to be maximized
/// </summary>
/// <param name="self"></param>
/// <param name="Max"></param>
/// <returns></returns>
public static GridAction SetMax(this GridAction self, bool Max = true)
{
self.Max = Max;
return self;
}
/// <summary>
/// Set the dialog to be maximized
/// </summary>
/// <param name="self"></param>
/// <param name="buttonclass">button class.
/// Some of the layui defined class to control color:
/// layui-btn-primary
/// layui-btn-normal
/// layui-btn-warm
/// layui-btn-danger
/// </param>
/// <returns></returns>
public static GridAction SetButtonClass(this GridAction self, string buttonclass)
{
self.ButtonClass = buttonclass;
return self;
}
/// <summary>
/// Set the dialog to be maximized
/// </summary>
/// <param name="self"></param>
/// <param name="isDownload"></param>
/// <returns></returns>
public static GridAction SetIsDownload(this GridAction self, bool isDownload = true)
{
self.IsDownload = isDownload;
return self;
}
public static GridAction SetIsExport(this GridAction self, bool isExport= true)
{
self.IsExport = isExport;
return self;
}
/// <summary>
/// Set prompt message
/// </summary>
/// <param name="self"></param>
/// <param name="msg"></param>
/// <returns></returns>
public static GridAction SetPromptMessage(this GridAction self, string msg)
{
self.PromptMessage = msg;
return self;
}
/// <summary>
/// 是否在每行都显示
/// </summary>
/// <param name="self"></param>
/// <param name="showInRow"></param>
/// <returns></returns>
public static GridAction SetShowInRow(this GridAction self, bool showInRow = true)
{
self.ShowInRow = showInRow;
return self;
}
/// <summary>
/// 是否在工具栏上隐藏按钮
/// </summary>
/// <param name="self"></param>
/// <param name="hideOnToolBar"></param>
/// <returns></returns>
public static GridAction SetHideOnToolBar(this GridAction self, bool hideOnToolBar = true)
{
self.HideOnToolBar = hideOnToolBar;
return self;
}
/// <summary>
/// 把按钮当作容器,添加按钮的子按钮
/// </summary>
/// <param name="self"></param>
/// <param name="subActions">子按钮</param>
/// <returns></returns>
public static GridAction SetSubActions(this GridAction self, List<GridAction> subActions)
{
self.SubActions = subActions;
return self;
}
#endregion
}
}

View File

@ -0,0 +1,205 @@
using System.Collections.Generic;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// GridActionExtension
/// </summary>
public static class GridActionExtension
{
/// <summary>
/// 按钮Id一般不需要设定系统会自动生成唯一Id。如果设定请确保 Id 的唯一性
/// </summary>
/// <param name="self"></param>
/// <param name="buttonId"></param>
/// <returns></returns>
public static GridAction SetButtonId(this GridAction self, string buttonId)
{
self.ButtonId = buttonId;
return self;
}
/// <summary>
/// 按钮名称
/// </summary>
/// <param name="self"></param>
/// <param name="name"></param>
/// <returns></returns>
public static GridAction SetName(this GridAction self, string name)
{
self.Name = name;
return self;
}
/// <summary>
/// 弹出窗口的标题
/// </summary>
/// <param name="self"></param>
/// <param name="dialogTitle"></param>
/// <returns></returns>
public static GridAction SetDialogTitle(this GridAction self, string dialogTitle)
{
self.DialogTitle = dialogTitle;
return self;
}
/// <summary>
/// 动作图标css
/// </summary>
/// <param name="self"></param>
/// <param name="iconCls"></param>
/// <returns></returns>
public static GridAction SetIconCls(this GridAction self, string iconCls)
{
self.IconCls = iconCls;
return self;
}
/// <summary>
/// 动作的Area
/// </summary>
/// <param name="self"></param>
/// <param name="area"></param>
/// <returns></returns>
public static GridAction SetArea(this GridAction self, string area)
{
self.Area = area;
return self;
}
/// <summary>
/// 动作的Controller
/// </summary>
/// <param name="self"></param>
/// <param name="controllerName"></param>
/// <returns></returns>
public static GridAction SetControllerName(this GridAction self, string controllerName)
{
self.ControllerName = controllerName;
return self;
}
/// <summary>
/// 动作的Action
/// </summary>
/// <param name="self"></param>
/// <param name="actionName"></param>
/// <returns></returns>
public static GridAction SetActionName(this GridAction self, string actionName)
{
self.ActionName = actionName;
return self;
}
/// <summary>
/// 动作的QueryString
/// </summary>
/// <param name="self"></param>
/// <param name="queryString"></param>
/// <returns></returns>
public static GridAction SetQueryString(this GridAction self, string queryString)
{
self.QueryString = queryString;
return self;
}
/// <summary>
/// 弹出窗口的宽度、高度
/// </summary>
/// <param name="self"></param>
/// <param name="dialogWidth"></param>
/// <param name="dialogHeight"></param>
/// <returns></returns>
public static GridAction SetSize(this GridAction self, int? dialogWidth, int? dialogHeight)
{
self.DialogWidth = dialogWidth;
self.DialogHeight = dialogHeight;
return self;
}
/// <summary>
/// 是否需要弹出窗口
/// </summary>
/// <param name="self"></param>
/// <param name="showDialog"></param>
/// <returns></returns>
public static GridAction SetShowDialog(this GridAction self, bool showDialog = true)
{
self.ShowDialog = showDialog;
return self;
}
public static GridAction SetForcePost(this GridAction self, bool forcepost = true)
{
self.ForcePost = forcepost;
return self;
}
/// <summary>
/// 是否跳转到新页面
/// </summary>
/// <param name="self"></param>
/// <param name="isRedirect"></param>
/// <returns></returns>
public static GridAction SetIsRedirect(this GridAction self, bool isRedirect = true)
{
self.IsRedirect = isRedirect;
return self;
}
/// <summary>
/// 动作类型
/// </summary>
/// <param name="self"></param>
/// <param name="parameterType"></param>
/// <returns></returns>
public static GridAction SetParameterType(this GridAction self, GridActionParameterTypesEnum parameterType)
{
self.ParameterType = parameterType;
return self;
}
/// <summary>
/// 如果不为null则只运行这个变量设定的script其他的属性都不起作用
/// </summary>
/// <param name="self"></param>
/// <param name="onClickScript"></param>
/// <remarks>
/// 如设置SetOnClickScript("test")点击按钮时框架会调用页面上的javascript方法: function test(ids,datas){}
/// ids是勾选的id数组datas是勾选的所有字段数组
/// </remarks>
/// <returns></returns>
public static GridAction SetOnClickScript(this GridAction self, string onClickScript)
{
self.OnClickFunc = onClickScript;
return self;
}
/// <summary>
/// 如果设定了SubActions则代表需要用SplitButton的形式展示主GridAction将不起作用
/// </summary>
/// <param name="self"></param>
/// <param name="gridActions"></param>
/// <returns></returns>
public static GridAction SetSubAction(this GridAction self, params GridAction[] gridActions)
{
if (self.SubActions == null)
{
self.SubActions = new List<GridAction>();
}
self.SubActions.AddRange(gridActions);
return self;
}
/// <summary>
/// 是否可以拖动改变弹出窗体大小
/// </summary>
/// <param name="self"></param>
/// <param name="resizable"></param>
/// <returns></returns>
public static GridAction SetNotResizable(this GridAction self, bool resizable = false)
{
self.Resizable = resizable;
return self;
}
/// <summary>
/// 设置一个布尔值的列名当改列值为true的时候才显示本行的这个动作按钮
/// </summary>
/// <param name="self"></param>
/// <param name="colName"></param>
/// <returns></returns>
public static GridAction SetBindVisiableColName(this GridAction self, string colName)
{
self.BindVisiableColName = colName;
return self;
}
}
}

View File

@ -0,0 +1,510 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.Json;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 列表列的定义
/// </summary>
/// <typeparam name="T">列表的数据源类</typeparam>
public class GridColumn<T> : IGridColumn<T> where T : TopBasePoco
{
public bool? ShowTotal { get; set; }
public GridColumn(Expression<Func<T, object>> columnExp, int? width)
{
ColumnExp = columnExp;
Width = width;
}
/// <summary>
/// 表头类型
/// </summary>
public GridColumnTypeEnum ColumnType { get; set; }
private string _field;
/// <summary>
/// 设定字段名
/// </summary>
public string Field
{
get
{
if (_field == null)
{
_field = PI?.Name;
if (_field == null)
{
_field = CompiledCol?.Invoke(null).ToString();
}
}
return _field;
}
set
{
_field = value;
}
}
private string _title;
/// <summary>
/// 标题名称
/// </summary>
public string Title
{
get
{
if (_title == null && PI != null)
{
_title = PropertyHelper.GetPropertyDisplayName(PI) ?? string.Empty;
}
return _title;
}
set
{
_title = value;
}
}
/// <summary>
/// 列宽
/// </summary>
public int? Width { get; set; }
/// <summary>
/// //监听单元格事件
/// </summary>
public string Event { get; set; }
/// <summary>
/// 是否允许排序
/// </summary>
public bool? Sort { get; set; }
/// <summary>
/// 是否固定列
/// </summary>
public GridColumnFixedEnum? Fixed { get; set; }
/// <summary>
/// 对齐方式
/// </summary>
public GridColumnAlignEnum Align { get; set; }
/// <summary>
/// 是否可改变列宽
/// </summary>
public bool? UnResize { get; set; }
/// <summary>
/// 隐藏列
/// </summary>
public bool? Hide { get; set; }
/// <summary>
/// 是否禁止导出此列
/// </summary>
public bool DisableExport { get; set; }
/// <summary>
/// 子列
/// </summary>
public IEnumerable<IGridColumn<T>> Children { get; set; }
private int? _childrenLen;
/// <summary>
/// 底层子列数量
/// </summary>
public int ChildrenLength
{
get
{
if (_childrenLen == null)
{
var len = 0;
if (Children != null && Children.Any())
{
len += Children.Where(x => x.Children == null || !x.Children.Any()).Count();
var tempChildren = Children.Where(x => x.Children != null && x.Children.Any()).ToList();
foreach (var item in tempChildren)
{
len += item.ChildrenLength;
}
}
_childrenLen = len;
}
return _childrenLen.Value;
}
}
public EditTypeEnum? EditType { get; set; }
public List<ComboSelectListItem> ListItems { get; set; }
#region Excel
/// <summary>
/// 递归获取子列数量最大层的子列数量
/// </summary>
public int MaxChildrenCount
{
get
{
int rv = 1;
if (this.Children != null && Children.Any())
{
rv = 0;
foreach (var child in this.Children)
{
rv += child.MaxChildrenCount;
}
}
return rv;
}
}
/// <summary>
/// 获取最大层数
/// </summary>
public int MaxLevel
{
get
{
int rv = 1;
if (this.Children != null && Children.Any())
{
int max = 0;
foreach (var child in this.Children)
{
int temp = child.MaxLevel;
if (max < temp)
{
max = temp;
}
}
rv += max;
}
return rv;
}
}
#endregion
private PropertyInfo _pi;
protected PropertyInfo PI
{
get
{
if (_pi == null && ColumnExp != null)
{
_pi = PropertyHelper.GetPropertyInfo(ColumnExp);
}
return _pi;
}
}
/// <summary>
/// ColumnExp
/// </summary>
public Expression<Func<T, object>> ColumnExp { get; set; }
private int? _maxDepth;
/// <summary>
/// 最大深度
/// </summary>
public int MaxDepth
{
get
{
if (_maxDepth == null)
{
_maxDepth = 1;
if (Children?.Count() > 0)
{
_maxDepth += Children.Max(x => x.MaxDepth);
}
}
return _maxDepth.Value;
}
}
#region
/// <summary>
///
/// </summary>
public string Id { get; set; }
private Func<T, object> _compiledCol;
protected Func<T, object> CompiledCol
{
get
{
if (_compiledCol == null)
{
if (ColumnExp == null)
{
_compiledCol = (T) => "";
}
else
{
_compiledCol = ColumnExp.Compile();
}
}
return _compiledCol;
}
}
private Type _fieldType;
/// <summary>
/// 获取值域类型
/// </summary>
/// <returns></returns>
public Type FieldType
{
get
{
return _fieldType ?? PI?.PropertyType;
}
set
{
_fieldType = value;
}
}
public string FieldName
{
get
{
return PI?.Name;
}
}
/// <summary>
/// 本列是否需要分组
/// </summary>
public bool NeedGroup { get; set; }
public bool IsLocked { get; set; }
public bool Sortable { get; set; }
/// <summary>
/// 是否允许换行
/// </summary>
public bool AllowMultiLine { get; set; }
/// <summary>
/// 设置某列是否应该尽量充满
/// </summary>
public int? Flex { get; set; }
/// <summary>
/// 列内容的格式化函数
/// </summary>
public ColumnFormatCallBack<T> Format { get; set; }
/// <summary>
/// 本列前景色函数
/// </summary>
public Func<T, string> ForeGroundFunc { get; set; }
/// <summary>
/// 本列背景色函数
/// </summary>
public Func<T, string> BackGroundFunc { get; set; }
/// <summary>
/// 获取最底层的子列
/// </summary>
public IEnumerable<IGridColumn<T>> BottomChildren
{
get
{
List<IGridColumn<T>> rv = new List<IGridColumn<T>>();
if (Children != null && Children.Any())
{
foreach (var child in Children)
{
rv.AddRange(child.BottomChildren);
}
}
else
{
rv.Add(this);
}
return rv;
}
}
/// <summary>
/// 根据设置前景色的函数返回前景色
/// </summary>
/// <param name="source">源数据</param>
/// <returns>前景色</returns>
public string GetForeGroundColor(object source)
{
if (ForeGroundFunc == null)
{
return "";
}
else
{
return ForeGroundFunc.Invoke(source as T);
}
}
/// <summary>
/// 根据设置背景色的函数返回背景色
/// </summary>
/// <param name="source">源数据</param>
/// <returns>背景色</returns>
public string GetBackGroundColor(object source)
{
if (BackGroundFunc == null)
{
return "";
}
else
{
return BackGroundFunc.Invoke(source as T);
}
}
public bool HasFormat()
{
if(Format != null)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 获取单元格要输出的内容
/// </summary>
/// <param name="source">源数据</param>
/// <param name="needFormat">是否使用format</param>
/// <returns>Html内容</returns>
public virtual object GetText(object source, bool needFormat = true)
{
object rv = null;
var col = CompiledCol?.Invoke(source as T);
if(needFormat == false && Format != null)
{
var test = Format.Invoke(source as T, col);
if(test is ColumnFormatInfo == false && test is List<ColumnFormatInfo> == false)
{
return test??"";
}
}
if (Format == null || needFormat == false)
{
if (col == null)
{
rv = "";
}
else if (col is DateTime || col is DateTime?)
{
var datevalue = col as DateTime?;
if(datevalue != null)
{
if (datevalue.Value.Hour == 0 && datevalue.Value.Minute == 0 && datevalue.Value.Second == 0)
{
rv = datevalue.Value.ToString("yyyy-MM-dd");
}
else
{
rv = datevalue.Value.ToString("yyyy-MM-dd HH:mm:ss");
}
}
else
{
rv = "";
}
}
else if (col.GetType().IsEnumOrNullableEnum())
{
rv = col.ToString();
}
else if (col.GetType().Namespace.Equals("System") == false)
{
if (needFormat == false)
{
rv = JsonSerializer.Serialize(col, CoreProgram.DefaultJsonOption);
}
else
{
rv = col.ToString();
}
}
else
{
rv = col.ToString();
}
}
else
{
rv = Format.Invoke(source as T, col);
}
if (rv == null)
{
rv = "";
}
return rv;
}
public virtual object GetObject(object source)
{
object rv = CompiledCol?.Invoke(source as T);
return rv;
}
/// <summary>
/// 获取列头内容
/// </summary>
/// <returns>Html内容</returns>
protected virtual string GetHeader()
{
string rv = PropertyHelper.GetPropertyDisplayName(PI);
return rv ?? "";
}
/// <summary>
/// 默认构造函数
/// </summary>
public GridColumn()
{
AllowMultiLine = true;
this.Sortable = true;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="ColumnExp"></param>
/// <param name="Format"></param>
/// <param name="Header"></param>
/// <param name="Width"></param>
/// <param name="Flex"></param>
/// <param name="AllowMultiLine"></param>
/// <param name="NeedGroup"></param>
/// <param name="ForeGroundFunc"></param>
/// <param name="BackGroundFunc"></param>
/// <param name="sortable"></param>
public GridColumn(Expression<Func<T, object>> ColumnExp, ColumnFormatCallBack<T> Format = null, string Header = null, int? Width = null, int? Flex = null, bool AllowMultiLine = true, bool NeedGroup = false, Func<T, string> ForeGroundFunc = null, Func<T, string> BackGroundFunc = null, bool sortable = true)
{
this.ColumnExp = ColumnExp;
this.Format = Format;
this.Title = Header;
this.Width = Width;
this.NeedGroup = NeedGroup;
this.ForeGroundFunc = ForeGroundFunc;
this.BackGroundFunc = BackGroundFunc;
this.AllowMultiLine = AllowMultiLine;
this.Flex = Flex;
this.Sortable = sortable;
}
#endregion
}
}

View File

@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// GridColumnExtension
/// </summary>
public static class GridColumnExtension
{
/// <summary>
/// GetAllBottomColumns
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <returns></returns>
public static IEnumerable<IGridColumn<T>> GetAllBottomColumns<T>(this IEnumerable<IGridColumn<T>> self)
{
List<IGridColumn<T>> rv = new List<IGridColumn<T>>();
foreach (var item in self)
{
rv.AddRange(item.BottomChildren);
}
return rv;
}
/// <summary>
/// Id
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="id"></param>
/// <returns></returns>
public static GridColumn<T> SetId<T>(this GridColumn<T> self, string id) where T : TopBasePoco
{
self.Id = id;
return self;
}
/// <summary>
/// 列头
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="header"></param>
/// <returns></returns>
public static GridColumn<T> SetHeader<T>(this GridColumn<T> self, string header) where T : TopBasePoco
{
self.Title = header;
return self;
}
/// <summary>
/// 本列是否需要分组
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="needGroup"></param>
/// <returns></returns>
public static GridColumn<T> SetNeedGroup<T>(this GridColumn<T> self, bool needGroup) where T : TopBasePoco
{
self.NeedGroup = needGroup;
return self;
}
public static GridColumn<T> SetLocked<T>(this GridColumn<T> self, bool locked) where T : TopBasePoco
{
self.IsLocked = locked;
return self;
}
public static GridColumn<T> SetSortable<T>(this GridColumn<T> self, bool sortable = false) where T : TopBasePoco
{
self.Sortable = sortable;
return self;
}
/// <summary>
/// 列宽
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="width"></param>
/// <returns></returns>
public static GridColumn<T> SetWidth<T>(this GridColumn<T> self, int? width) where T : TopBasePoco
{
self.Width = width;
return self;
}
/// <summary>
/// 是否允许换行
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="allowMultiLine"></param>
/// <returns></returns>
public static GridColumn<T> SetAllowMultiLine<T>(this GridColumn<T> self, bool allowMultiLine) where T : TopBasePoco
{
self.AllowMultiLine = allowMultiLine;
return self;
}
/// <summary>
/// 设置某列是否应该尽量充满
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="flex"></param>
/// <returns></returns>
public static GridColumn<T> SetFlex<T>(this GridColumn<T> self, int? flex) where T : TopBasePoco
{
self.Flex = flex;
return self;
}
///// <summary>
///// 时间与数字类型Format
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="self"></param>
///// <param name="format"></param>
///// <returns></returns>
//public static GridColumn<T> SetFormat<T>(this GridColumn<T> self, string format) where T : TopBasePoco
//{
// self.StringFormat = format;
// return self;
//}
/// <summary>
/// 列内容的格式化函数
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="format"></param>
/// <returns></returns>
public static GridColumn<T> SetFormat<T>(this GridColumn<T> self, ColumnFormatCallBack<T> format) where T : TopBasePoco
{
self.Format = format;
return self;
}
/// <summary>
/// 计算列值的表达式
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="columnExp"></param>
/// <returns></returns>
public static GridColumn<T> SetColumnExp<T>(this GridColumn<T> self, Expression<Func<T, object>> columnExp) where T : TopBasePoco
{
self.ColumnExp = columnExp;
return self;
}
/// <summary>
/// 子列
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="childrens"></param>
/// <returns></returns>
public static GridColumn<T> SetChildren<T>(this GridColumn<T> self, params GridColumn<T>[] childrens) where T : TopBasePoco
{
List<GridColumn<T>> temp = new List<GridColumn<T>>();
if (self.Children == null)
{
temp = new List<GridColumn<T>>();
}
else
{
temp = self.Children.Cast<GridColumn<T>>().ToList();
}
temp.AddRange(childrens);
self.Children = temp;
return self;
}
/// <summary>
/// 本列前景色函数
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="foreGroundFunc"></param>
/// <returns></returns>
public static GridColumn<T> SetForeGroundFunc<T>(this GridColumn<T> self, Func<T, string> foreGroundFunc) where T : TopBasePoco
{
self.ForeGroundFunc = foreGroundFunc;
return self;
}
/// <summary>
/// 本列背景色函数
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="backGroundFunc"></param>
/// <returns></returns>
public static GridColumn<T> SetBackGroundFunc<T>(this GridColumn<T> self, Func<T, string> backGroundFunc) where T : TopBasePoco
{
self.BackGroundFunc = backGroundFunc;
return self;
}
/// <summary>
/// 设置本列是否显示汇总
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="show">是否显示</param>
/// <returns></returns>
public static GridColumn<T> SetShowTotal<T>(this GridColumn<T> self, bool show = true) where T : TopBasePoco
{
self.ShowTotal = show;
return self;
}
/// <summary>
/// 设置禁止导出此列数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <returns></returns>
public static GridColumn<T> SetDisableExport<T>(this GridColumn<T> self) where T : TopBasePoco
{
self.DisableExport = true;
return self;
}
}
}

View File

@ -0,0 +1,310 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// GridColumn Extension
/// </summary>
public static class GridHeaderExtension
{
/// <summary>
/// 创建表头
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="V"></typeparam>
/// <param name="self"></param>
/// <param name="columnExp">绑定猎头表达式</param>
/// <param name="width">宽度</param>
/// <returns></returns>
public static GridColumn<T> MakeGridHeader<T, V>(this IBasePagedListVM<T, V> self
, Expression<Func<T, object>> columnExp
, int? width = null
)
where T : TopBasePoco
where V : ISearcher
{
MemberExpression me = null;
if (columnExp is MemberExpression)
{
me = columnExp as MemberExpression;
}
else if (columnExp is LambdaExpression)
{
var le = columnExp as LambdaExpression;
if (le.Body is MemberExpression)
{
me = le.Body as MemberExpression;
}
}
var alignType = GridColumnAlignEnum.Center;
if (me != null)
{
var propType = me.Type;
if (propType == typeof(string))
{
alignType = GridColumnAlignEnum.Left;
}
}
return new GridColumn<T>(columnExp, width) { ColumnType = GridColumnTypeEnum.Normal, Align = alignType };
}
/// <summary>
/// 创建一个间隙列
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="V"></typeparam>
/// <param name="self"></param>
/// <returns></returns>
public static GridColumn<T> MakeGridHeaderSpace<T, V>(this IBasePagedListVM<T, V> self)
where T : TopBasePoco
where V : ISearcher
{
return new GridColumn<T>() { ColumnType = GridColumnTypeEnum.Space };
}
/// <summary>
/// 创建一个父级表头
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="V"></typeparam>
/// <param name="self"></param>
/// <param name="title">标题</param>
/// <returns></returns>
public static GridColumn<T> MakeGridHeaderParent<T, V>(this IBasePagedListVM<T, V> self, string title
)
where T : TopBasePoco
where V : ISearcher
{
return new GridColumn<T>() { Title = title };
}
public static GridColumn<T> MakeGridHeaderAction<T, V>(this IBasePagedListVM<T, V> self
, string title = null
, int? width = 160
, int? rowspan = null
)
where T : TopBasePoco
where V : ISearcher
{
return new GridColumn<T>()
{
ColumnType = GridColumnTypeEnum.Action,
Width = width,
Fixed = GridColumnFixedEnum.Right,
Title = title ?? CoreProgram._localizer?["Sys.Operation"]
};
}
#region GridColumn Property Setter
/// <summary>
/// 设定字段名
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="field">字段名的设定非常重要,是表格数据列的唯一标识,默认属性对应的名字</param>
/// <returns></returns>
public static GridColumn<T> SetField<T>(this GridColumn<T> self, string field)
where T : TopBasePoco
{
self.Field = field;
return self;
}
/// <summary>
/// 设定标题名称
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="title">即表头各列的标题,默认属性对应的 DisplayName 或 属性名 </param>
/// <returns></returns>
public static GridColumn<T> SetTitle<T>(this GridColumn<T> self, string title)
where T : TopBasePoco
{
self.Title = title;
return self;
}
/// <summary>
/// 设定列宽
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="width">列宽的设定也通常是必须的(“特殊列”除外,如:复选框列、工具列等),它关系到表格的整体美观程度。</param>
/// <returns></returns>
public static GridColumn<T> SetWidth<T>(this GridColumn<T> self, int width)
where T : TopBasePoco
{
self.Width = width;
return self;
}
/// <summary>
/// 单元格事件名称
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="eEvent"></param>
/// <returns></returns>
public static GridColumn<T> SetEvent<T>(this GridColumn<T> self, string eEvent) where T : TopBasePoco
{
self.Event = eEvent;
return self;
}
///// <summary>
///// 设定当前列头 列横跨的单元格数
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="self"></param>
///// <param name="colspan">这种情况下不用设置 Field 和 Width </param>
///// <returns></returns>
//public static GridColumn<T> SetColspan<T>(this GridColumn<T> self, int colspan)
// where T : TopBasePoco
//{
// self.Colspan = colspan;
// return self;
//}
///// <summary>
///// 设定当前列头 纵向跨越的单元格数
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="self"></param>
///// <param name="rowspan">纵向跨越的单元格数</param>
///// <returns></returns>
//public static GridColumn<T> SetRowspan<T>(this GridColumn<T> self, int rowspan)
// where T : TopBasePoco
//{
// self.Rowspan = rowspan;
// return self;
//}
/// <summary>
/// 设定是否允许排序 (ASCII码排序)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="sort">如果设置 true则在对应的表头显示排序icon从而对列开启排序功能。</param>
/// <returns></returns>
public static GridColumn<T> SetSort<T>(this GridColumn<T> self, bool sort = true)
where T : TopBasePoco
{
self.Sort = sort;
return self;
}
/// <summary>
/// 设定是否固定列
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="fixed">如果设置 Left 或 Right则对应的列将会被固定在左或右不随滚动条而滚动。</param>
/// <returns></returns>
public static GridColumn<T> SetFixed<T>(this GridColumn<T> self, GridColumnFixedEnum? @fixed)
where T : TopBasePoco
{
self.Fixed = @fixed;
return self;
}
/// <summary>
/// 设定对齐方式
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="align"></param>
/// <returns></returns>
public static GridColumn<T> SetAlign<T>(this GridColumn<T> self, GridColumnAlignEnum align)
where T : TopBasePoco
{
self.Align = align;
return self;
}
///// <summary>
///// 设定是否允许编辑
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="self"></param>
///// <param name="edit">如果设置 true则对应列的单元格将会被允许编辑目前只支持type="text"的input编辑。</param>
///// <returns></returns>
//public static GridColumn<T> SetEdit<T>(this GridColumn<T> self, bool edit = true)
// where T : TopBasePoco
//{
// self.Edit = edit;
// return self;
//}
///// <summary>
///// 设定自定义模板
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="self"></param>
///// <param name="templet">在默认情况下单元格的内容是完全按照数据接口返回的content原样输出的
///// 如果你想对某列的单元格添加链接等其它元素,你可以借助该参数来轻松实现。
///// 这是一个非常实用的功能,你的表格内容会因此而丰富多样。
///// </param>
///// <returns></returns>
//public static GridColumn<T> SetTemplet<T>(this GridColumn<T> self, string templet)
// where T : TopBasePoco
//{
// self.Templet = templet;
// return self;
//}
[Obsolete("该方法已经被弃用,请使用 SetHide 代替")]
public static GridColumn<T> SetHidden<T>(this GridColumn<T> self, bool hidden = true) where T : TopBasePoco
{
return self;
}
/// <summary>
/// 是否隐藏
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="hide"></param>
/// <returns></returns>
public static GridColumn<T> SetHide<T>(this GridColumn<T> self, bool hide = true) where T : TopBasePoco
{
self.Hide = hide;
return self;
}
/// <summary>
/// 设定列宽不可改变
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="unresize"></param>
/// <returns></returns>
public static GridColumn<T> SetUnResize<T>(this GridColumn<T> self, bool unresize = true)
where T : TopBasePoco
{
self.UnResize = unresize;
return self;
}
/// <summary>
/// 设定单元格编辑类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="self"></param>
/// <param name="editType">单元格编辑类型</param>
/// <param name="listitems">listitems</param>
/// <returns></returns>
public static GridColumn<T> SetEditType<T>(this GridColumn<T> self, EditTypeEnum editType = EditTypeEnum.Text, List<ComboSelectListItem> listitems = null)
where T : TopBasePoco
{
self.EditType = editType;
self.ListItems = listitems;
return self;
}
#endregion
}
}

View File

@ -0,0 +1,225 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text.Json.Serialization;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// Grid Column Content Fixed Enum
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum GridColumnFixedEnum
{
/// <summary>
/// 规定在左侧
/// </summary>
Left = 0,
/// <summary>
/// 规定在右侧
/// </summary>
Right
}
/// <summary>
/// Grid Column Edit Type Enum
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum EditTypeEnum
{
Text,
TextBox,
ComboBox,
Datetime,
CheckBox
}
/// <summary>
/// Grid Column Content Align Enum
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum GridColumnAlignEnum
{
/// <summary>
/// Center
/// </summary>
Center = 0,
/// <summary>
/// Left
/// </summary>
Left,
/// <summary>
/// Right
/// </summary>
Right
}
/// <summary>
/// Grid Column Type Enum
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum GridColumnTypeEnum
{
/// <summary>
/// 正常列
/// </summary>
Normal = 0,
/// <summary>
/// 空列
/// </summary>
Space,
/// <summary>
/// 操作列
/// </summary>
Action
}
/// <summary>
/// IGridColumn
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IGridColumn<out T>
{
/// <summary>
/// 表头类型
/// </summary>
GridColumnTypeEnum ColumnType { get; set; }
/// <summary>
/// 设定字段名
/// </summary>
string Field { get; set; }
/// <summary>
/// 标题名称
/// </summary>
string Title { get; set; }
/// <summary>
/// 列宽
/// </summary>
int? Width { get; set; }
/// <summary>
/// //监听单元格事件
/// </summary>
string Event { get; set; }
/// <summary>
/// 是否允许排序
/// </summary>
bool? Sort { get; set; }
/// <summary>
/// 是否固定列
/// </summary>
GridColumnFixedEnum? Fixed { get; set; }
/// <summary>
/// 对齐方式
/// </summary>
GridColumnAlignEnum Align { get; set; }
/// <summary>
/// 是否可改变列宽
/// </summary>
bool? UnResize { get; set; }
/// <summary>
/// 隐藏列
/// </summary>
bool? Hide { get; set; }
/// <summary>
/// 是否显示汇总
/// </summary>
bool? ShowTotal { get; set; }
/// <summary>
/// 子列
/// </summary>
IEnumerable<IGridColumn<T>> Children { get; }
/// <summary>
/// 底层子列数量
/// </summary>
int ChildrenLength { get; }
EditTypeEnum? EditType { get; set; }
List<ComboSelectListItem> ListItems { get; set; }
#region Excel
/// <summary>
/// 最大子列数量
/// </summary>
int MaxChildrenCount { get; }
/// <summary>
/// 多表头的最大层数
/// </summary>
int MaxLevel { get; }
/// <summary>
/// 最下层列
/// </summary>
IEnumerable<IGridColumn<T>> BottomChildren { get; }
/// <summary>
/// 最大深度
/// </summary>
int MaxDepth { get; }
#endregion
#region
string Id { get; set; }
/// <summary>
/// 是否需要分组
/// </summary>
bool NeedGroup { get; set; }
bool IsLocked { get; set; }
bool Sortable { get; set; }
/// <summary>
/// 是否允许多行
/// </summary>
bool AllowMultiLine { get; set; }
/// <summary>
/// 是否填充
/// </summary>
int? Flex { get; set; }
Type FieldType { get; }
string FieldName { get; }
/// <summary>
/// 获取内容
/// </summary>
/// <param name="source">源数据</param>
/// <param name="needFormat">是否适用format</param>
/// <returns>内容</returns>
object GetText(object source, bool needFormat = true);
object GetObject(object source);
/// <summary>
/// 获取前景色
/// </summary>
/// <param name="source">源数据</param>
/// <returns>前景色</returns>
string GetForeGroundColor(object source);
/// <summary>
/// 获取背景色
/// </summary>
/// <param name="source">源数据</param>
/// <returns>背景色</returns>
string GetBackGroundColor(object source);
bool HasFormat();
#endregion
}
}

View File

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// DataTable和Entity之间转换的辅助类
/// </summary>
public static class EntityHelper
{
/// <summary>
/// 根据DataTable获取Entity列表
/// </summary>
/// <typeparam name="T">Entity类型</typeparam>
/// <param name="table">DataTable</param>
/// <returns>Entity列表</returns>
public static IList<T> GetEntityList<T>(DataTable table)
{
IList<T> entityList = new List<T>();
if (typeof(T) == typeof(DynamicData))
{
foreach (DataRow row in table.Rows)
{
//新建Entity
T entity = (T)Activator.CreateInstance(typeof(T));
foreach (DataColumn col in table.Columns)
{
(entity as DynamicData).Add(col.ColumnName, row[col] == DBNull.Value ? null : row[col]);
}
entityList.Add(entity);
}
}
else
{
var properties = typeof(T).GetAllProperties().ToLookup(property => property.Name, property => property).ToDictionary(i => i.Key, i => i.First()).Values;
//循环Datable中的每一行
foreach (DataRow row in table.Rows)
{
//新建Entity
T entity = (T)Activator.CreateInstance(typeof(T));
//循环Entity的每一个属性
foreach (var item in properties)
{
//如果DataTable中有列名和属性名一致则把单元格内容赋值给Entity的该属性
if (row.Table.Columns.Contains(item.Name))
{
//判断null值
if (string.IsNullOrEmpty(row[item.Name].ToString()))
{
item.SetValue(entity, null);
}
else
{
var ptype = item.PropertyType;
if (ptype.IsNullable())
{
ptype = ptype.GenericTypeArguments[0];
}
//如果是Guid或Guid?类型
if (ptype == typeof(Guid))
{
item.SetValue(entity, Guid.Parse(row[item.Name].ToString()));
}
//如果是enum或enum?类型
else if (ptype.IsEnum)
{
item.SetValue(entity, Enum.ToObject(ptype, row[item.Name]));
}
else
{
item.SetValue(entity, Convert.ChangeType(row[item.Name], ptype));
}
}
}
}
entityList.Add(entity);
}
}
return entityList;
}
#region DataTable
/// <summary>
/// 实体类转换成DataSet
/// </summary>
/// <param name="modelList">实体类列表</param>
/// <returns>DataSet</returns>
public static DataSet ToDataSet<T>(List<T> modelList) where T : new()
{
if (modelList == null || modelList.Count == 0)
{
return null;
}
else
{
DataSet ds = new DataSet();
ds.Tables.Add(ToDataTable(modelList));
return ds;
}
}
/// <summary>
/// 实体类转换成DataTable
/// </summary>
/// <param name="modelList">实体类列表</param>
/// <returns>DataTable</returns>
public static DataTable ToDataTable<T>(List<T> modelList) where T : new()
{
if (modelList == null || modelList.Count == 0)
{
return null;
}
DataTable dt = CreateData(modelList[0]);
foreach (T model in modelList)
{
DataRow dataRow = dt.NewRow();
//循环实体类所有属性给对应的DataTable字段赋值
foreach (PropertyInfo propertyInfo in typeof(T).GetAllProperties())
{
var res = propertyInfo.GetValue(model);
dataRow[propertyInfo.Name] = res ?? DBNull.Value;
}
dt.Rows.Add(dataRow);
}
return dt;
}
/// <summary>
/// 根据实体类得到表结构
/// </summary>
/// <param name="model">实体类</param>
/// <returns>DataTable</returns>
private static DataTable CreateData<T>(T model) where T : new()
{
DataTable dataTable = new DataTable(typeof(T).Name);
foreach (PropertyInfo propertyInfo in typeof(T).GetAllProperties())
{
if (propertyInfo.PropertyType.IsGenericType)
{
if (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) && propertyInfo.PropertyType.GenericTypeArguments.Length > 0)
{
dataTable.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType.GenericTypeArguments[0]);
continue;
}
else
{
continue;
}
}
dataTable.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType);
}
return dataTable;
}
#endregion
}
}

View File

@ -0,0 +1,66 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using WalkingTec.Mvvm.Core.Extensions;
using WalkingTec.Mvvm.Core.Support.FileHandlers;
namespace WalkingTec.Mvvm.Core
{
public static class IServiceExtension
{
public static IServiceCollection AddWtmContextForConsole(this IServiceCollection services, string jsonFileDir = null, string jsonFileName = null, Func<IWtmFileHandler, string> fileSubDirSelector = null)
{
var configBuilder = new ConfigurationBuilder();
IConfigurationRoot ConfigRoot = configBuilder.WTMConfig(null,jsonFileDir,jsonFileName).Build();
var WtmConfigs = ConfigRoot.Get<Configs>();
services.Configure<Configs>(ConfigRoot);
services.AddLogging(builder =>
{
builder.ClearProviders();
builder.AddConfiguration(ConfigRoot.GetSection("Logging"))
.AddConsole()
.AddDebug()
.AddWTMLogger();
});
var gd = GetGlobalData();
services.AddHttpContextAccessor();
services.AddSingleton(gd);
WtmFileProvider._subDirFunc = fileSubDirSelector;
services.TryAddScoped<IDataContext, NullContext>();
services.AddScoped<WTMContext>();
services.AddScoped<WtmFileProvider>();
services.AddHttpClient();
if (WtmConfigs.Domains != null)
{
foreach (var item in WtmConfigs.Domains)
{
services.AddHttpClient(item.Key, x =>
{
x.BaseAddress = new Uri(item.Value.Url);
x.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
x.DefaultRequestHeaders.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)");
});
}
}
services.AddDistributedMemoryCache();
var cs = WtmConfigs.Connections;
foreach (var item in cs)
{
var dc = item.CreateDC();
dc.Database.EnsureCreated();
}
WtmFileProvider.Init(WtmConfigs, gd);
return services;
}
private static GlobalData GetGlobalData()
{
GlobalData gd = new GlobalData();
gd.AllAssembly = Utils.GetAllAssembly();
return gd;
}
}
}

View File

@ -0,0 +1,62 @@
//using System;
//using System.Diagnostics;
//namespace WalkingTec.Mvvm.Core
//{
// /// <summary>
// /// LogDebug 只有定义了DEBUG常量才会生效可以理解为只在Debug模式下才会输出
// /// </summary>
// public sealed class LogDebug
// {
// /// <summary>
// /// Debug
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("DEBUG")]
// public static void Debug(string message, Exception ex = null)
// {
// LogTrace.Debug(message, ex);
// }
// /// <summary>
// /// Info
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("DEBUG")]
// public static void Info(string message, Exception ex = null)
// {
// LogTrace.Info(message, ex);
// }
// /// <summary>
// /// Warn
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("DEBUG")]
// public static void Warn(string message, Exception ex = null)
// {
// LogTrace.Warn(message, ex);
// }
// /// <summary>
// /// Error
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("DEBUG")]
// public static void Error(string message, Exception ex = null)
// {
// LogTrace.Error(message, ex);
// }
// /// <summary>
// /// Fatal
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("DEBUG")]
// public static void Fatal(string message, Exception ex = null)
// {
// LogTrace.Fatal(message, ex);
// }
// }
//}

View File

@ -0,0 +1,126 @@
//using System;
//using System.Diagnostics;
//using System.Reflection;
//using log4net;
//namespace WalkingTec.Mvvm.Core
//{
// /// <summary>
// /// Trace 只有定义了TRACE常量才会生效可以理解为在Debug与Release下均会输出
// /// </summary>
// public sealed class LogTrace
// {
// private static ILog _logger;
// private static ILog Logger
// {
// get
// {
// if (_logger == null)
// {
// _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// }
// return _logger;
// }
// }
// /// <summary>
// /// Write
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// public static void Write(string message, Exception ex = null)
// {
// OutputWindowWriteLine(message);
// if (ex == null)
// Logger.Debug(message);
// else
// Logger.Debug(message, ex);
// }
// /// <summary>
// /// Debug
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("TRACE")]
// public static void Debug(string message, Exception ex = null)
// {
// Write(message, ex);
// }
// /// <summary>
// /// Info
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("TRACE")]
// public static void Info(string message, Exception ex = null)
// {
// OutputWindowWriteLine(message);
// if (ex == null)
// Logger.Info(message);
// else
// Logger.Info(message, ex);
// }
// /// <summary>
// /// Warn
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("TRACE")]
// public static void Warn(string message, Exception ex = null)
// {
// OutputWindowWriteLine(message);
// if (ex == null)
// Logger.Warn(message);
// else
// Logger.Warn(message, ex);
// }
// /// <summary>
// /// Error
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("TRACE")]
// public static void Error(string message, Exception ex = null)
// {
// OutputWindowWriteLine(message);
// if (ex == null)
// Logger.Error(message);
// else
// Logger.Error(message, ex);
// }
// /// <summary>
// /// Fatal
// /// </summary>
// /// <param name="message"></param>
// /// <param name="ex"></param>
// [Conditional("TRACE")]
// public static void Fatal(string message, Exception ex = null)
// {
// OutputWindowWriteLine(message);
// if (ex == null)
// Logger.Fatal(message);
// else
// Logger.Fatal(message, ex);
// }
// #region Output Window
// [Conditional("DEBUG")]
// private static void OutputWindowWriteLine(string message, int level = 0, string category = null)
// {
// if (System.Diagnostics.Debugger.IsLogging())
// {
// //调用Debugger.Log方法这个方法可以输出信息到DebugView中
// System.Diagnostics.Debugger.Log(level, category, $"{message}\r\n");
// }
// }
// [Conditional("DEBUG")]
// private static void OutputWindowWrite(string message, int level = 0, string category = null)
// {
// if (System.Diagnostics.Debugger.IsLogging())
// {
// System.Diagnostics.Debugger.Log(level, category, message);
// }
// }
// #endregion
// }
//}

View File

@ -0,0 +1,826 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 属性辅助类
/// </summary>
public static class PropertyHelper
{
public static object GetExpressionRootObj(Expression expression)
{
if (expression == null)
{
return "";
}
Expression me = null;
LambdaExpression le = null;
if (expression is MemberExpression)
{
me = expression as MemberExpression;
}
if (expression is LambdaExpression)
{
le = expression as LambdaExpression;
if (le.Body is MemberExpression)
{
me = le.Body as MemberExpression;
}
if (le.Body is UnaryExpression)
{
me = (le.Body as UnaryExpression).Operand as MemberExpression;
}
}
while (me != null && me.NodeType == ExpressionType.MemberAccess)
{
Expression exp = (me as MemberExpression).Expression;
if (exp is MemberExpression)
{
me = exp as MemberExpression;
}
else if (exp is MethodCallExpression)
{
var mexp = exp as MethodCallExpression;
if (mexp.Method.Name == "get_Item")
{
object index = 0;
if (mexp.Arguments[0] is MemberExpression)
{
var obj = ((mexp.Arguments[0] as MemberExpression).Expression as ConstantExpression).Value;
index = obj.GetType().GetField((mexp.Arguments[0] as MemberExpression).Member.Name).GetValue(obj);
}
else
{
index = (mexp.Arguments[0] as ConstantExpression).Value;
}
me = mexp.Object as MemberExpression;
}
}
else
{
me = exp;
break;
}
}
if(me.NodeType == ExpressionType.Constant)
{
return (me as ConstantExpression)?.Value;
}
return null;
}
public static Func<object, object> GetPropertyExpression(Type objtype, string property)
{
property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty);
List<string> level = new List<string>();
if (property.Contains('.'))
{
level.AddRange(property.Split('.'));
}
else
{
level.Add(property);
}
var pe = Expression.Parameter(objtype);
var member = Expression.Property(pe, objtype.GetSingleProperty(level[0]));
for (int i = 1; i < level.Count; i++)
{
member = Expression.Property(member, member.Type.GetSingleProperty(level[i]));
}
return Expression.Lambda<Func<object, object>>(member, pe).Compile();
}
/// <summary>
/// 获取属性名
/// </summary>
/// <param name="expression">属性表达式</param>
/// <param name="getAll">是否获取全部级别名称比如a.b.c</param>
/// <returns>属性名</returns>
public static string GetPropertyName(this Expression expression, bool getAll = true)
{
if (expression == null)
{
return "";
}
MemberExpression me = null;
LambdaExpression le = null;
if (expression is MemberExpression)
{
me = expression as MemberExpression;
}
if (expression is LambdaExpression)
{
le = expression as LambdaExpression;
if (le.Body is MemberExpression)
{
me = le.Body as MemberExpression;
}
if (le.Body is UnaryExpression)
{
me = (le.Body as UnaryExpression).Operand as MemberExpression;
}
}
string rv = "";
if (me != null)
{
rv = me.Member.Name;
}
while (me != null && getAll && me.NodeType == ExpressionType.MemberAccess)
{
Expression exp = me.Expression;
if (exp is MemberExpression)
{
rv = (exp as MemberExpression).Member.Name + "." + rv;
me = exp as MemberExpression;
}
else if (exp is MethodCallExpression)
{
var mexp = exp as MethodCallExpression;
if (mexp.Method.Name == "get_Item")
{
object index = 0;
if (mexp.Arguments[0] is MemberExpression)
{
var obj = ((mexp.Arguments[0] as MemberExpression).Expression as ConstantExpression).Value;
index = obj.GetType().GetField((mexp.Arguments[0] as MemberExpression).Member.Name).GetValue(obj);
}
else
{
index = (mexp.Arguments[0] as ConstantExpression).Value;
}
rv = (mexp.Object as MemberExpression).Member.Name + "[" + index + "]." + rv;
me = mexp.Object as MemberExpression;
}
}
else
{
break;
}
}
return rv;
}
public static Expression GetMemberExp(this ParameterExpression self, Expression member)
{
return self.GetMemberExp(member.GetPropertyName());
}
public static Expression GetMemberExp(this ParameterExpression self, string memberName)
{
var names = memberName.Split(',');
Expression rv = Expression.PropertyOrField(self, names[0]); ;
for (int i = 1; i < names.Length; i++)
{
rv = Expression.PropertyOrField(rv, names[i]);
}
return rv;
}
/// <summary>
/// 获取属性名的Id形式将属性名中的.转换为_适合作为HTML中的Id使用
/// </summary>
/// <param name="expression">属性表达式</param>
/// <param name="getAll">是否获取全部级别名称比如a.b.c</param>
/// <returns>属性Id</returns>
public static string GetPropertyId(this Expression expression, bool getAll = true)
{
return GetPropertyName(expression, getAll).GetIdByName();
}
/// <summary>
/// 获取正则表达式错误
/// </summary>
/// <param name="pi">属性信息</param>
/// <returns>错误文本</returns>
public static string GetRegexErrorMessage(this MemberInfo pi)
{
string rv = "";
if (pi.GetCustomAttributes(typeof(RegularExpressionAttribute), false).FirstOrDefault() is RegularExpressionAttribute dis && !string.IsNullOrEmpty(dis.ErrorMessage))
{
rv = dis.ErrorMessage;
if (CoreProgram._localizer != null)
{
rv = CoreProgram._localizer[rv];
}
}
else
{
rv = "";
}
return rv;
}
/// <summary>
/// 获取属性显示名称
/// </summary>
/// <param name="pi">属性信息</param>
/// <param name="local"></param>
/// <returns>属性名称</returns>
public static string GetPropertyDisplayName(this MemberInfo pi, IStringLocalizer local = null)
{
string rv = "";
if (pi.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() is DisplayAttribute dis && !string.IsNullOrEmpty(dis.Name))
{
rv = dis.Name;
if (local == null)
{
if (CoreProgram._localizer != null)
{
rv = CoreProgram._localizer[rv];
}
}
else
{
rv = local[rv];
}
}
else
{
rv = pi.Name;
}
return rv;
}
/// <summary>
/// 获取属性显示名称
/// </summary>
/// <param name="expression">属性表达式</param>
/// <param name="local"></param>
/// <returns>属性显示名称</returns>
public static string GetPropertyDisplayName(this Expression expression, IStringLocalizer local = null)
{
return GetPropertyDisplayName(expression.GetPropertyInfo(), local);
}
/// <summary>
/// 获取枚举显示名称
/// </summary>
/// <param name="value">枚举值</param>
/// <returns>枚举显示名称</returns>
public static string GetEnumDisplayName(this Enum value)
{
return GetEnumDisplayName(value.GetType(), value.ToString());
}
/// <summary>
/// 获取属性信息
/// </summary>
/// <param name="expression">属性表达式</param>
/// <returns>属性信息</returns>
public static PropertyInfo GetPropertyInfo(this Expression expression)
{
MemberExpression me = null;
LambdaExpression le = null;
if (expression is MemberExpression)
{
me = expression as MemberExpression;
}
if (expression is LambdaExpression)
{
le = expression as LambdaExpression;
if (le.Body is MemberExpression)
{
me = le.Body as MemberExpression;
}
if (le.Body is UnaryExpression)
{
me = (le.Body as UnaryExpression).Operand as MemberExpression;
}
}
PropertyInfo rv = null;
if (me != null)
{
rv = me.Member.DeclaringType.GetSingleProperty(me.Member.Name);
}
return rv;
}
/// <summary>
/// 获取属性值
/// </summary>
/// <param name="exp">属性表达式</param>
/// <param name="obj">属性所在实例</param>
/// <returns>属性值</returns>
public static object GetPropertyValue(this object obj, LambdaExpression exp)
{
//获取表达式的值,并过滤单引号
try
{
var expValue = exp.Compile().DynamicInvoke(obj);
object val = expValue;
return val;
}
catch
{
return "";
}
}
public static object GetPropertyValue(this object obj, string property)
{
//获取表达式的值,并过滤单引号
try
{
return obj.GetType().GetSingleProperty(property).GetValue(obj); ;
}
catch
{
return "";
}
}
public static List<string> GetPropertySiblingValues(this object obj, string propertyName)
{
if(obj == null)
{
return new List<string>();
}
Regex reg = new Regex("(.*?)\\[\\-?\\d?\\]\\.(.*?)$");
var match = reg.Match(propertyName);
if (match.Success)
{
var name1 = match.Groups[1].Value;
var name2 = match.Groups[2].Value;
var levels = name1.Split('.');
var objtype = obj.GetType();
var pe = Expression.Parameter(objtype);
var member = Expression.Property(pe, objtype.GetSingleProperty(levels[0]));
for (int i = 1; i < levels.Length; i++)
{
member = Expression.Property(member, member.Type.GetSingleProperty(levels[i]));
}
var pe2 = Expression.Parameter(member.Type.GetGenericArguments()[0]);
var cast = Expression.Call(typeof(Enumerable), "Cast", new Type[] { pe2.Type }, member);
var name2exp = Expression.Property(pe2, pe2.Type.GetSingleProperty(name2));
var selectexp = Expression.Call(name2exp, "ToString", Type.EmptyTypes);
Expression select = Expression.Call(
typeof(Enumerable),
"Select",
new Type[] { pe2.Type, typeof(string) },
cast,
Expression.Lambda(selectexp, pe2));
var lambda = Expression.Lambda(select, pe);
var rv = new List<string>();
try
{
rv = (lambda.Compile().DynamicInvoke(obj) as IEnumerable<string>)?.ToList();
}
catch { }
return rv;
}
else
{
return new List<string>();
}
}
/// <summary>
/// 判断属性是否必填
/// </summary>
/// <param name="pi">属性信息</param>
/// <returns>是否必填</returns>
public static bool IsPropertyRequired(this MemberInfo pi)
{
bool isRequired = false;
if (pi != null)
{
//如果需要显示星号,则判断是否是必填项,如果是必填则在内容后面加上星号
//所有intfloat。。。这种Primitive类型的肯定都是必填
Type t = pi.GetMemberType();
if (t != null && (t.IsPrimitive() || t.IsEnum() || t == typeof(decimal) || t == typeof(Guid)))
{
isRequired = true;
}
else
{
//对于其他类检查是否有RequiredAttribute如果有就是必填
if (pi.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault() is RequiredAttribute required && required.AllowEmptyStrings == false)
{
isRequired = true;
}
else if (pi.GetCustomAttributes(typeof(KeyAttribute), false).FirstOrDefault() != null)
{
isRequired = true;
}
}
}
return isRequired;
}
/// <summary>
/// 设置属性值
/// </summary>
/// <param name="source">属性所在实例</param>
/// <param name="property">属性名</param>
/// <param name="value">要赋的值</param>
/// <param name="prefix">属性前缀</param>
/// <param name="stringBasedValue">是否为字符串格式的值</param>
public static void SetPropertyValue(this object source, string property, object value, string prefix = null, bool stringBasedValue = false)
{
try
{
property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty);
List<string> level = new List<string>();
if (property.Contains('.'))
{
level.AddRange(property.Split('.'));
}
else
{
level.Add(property);
}
if (!string.IsNullOrWhiteSpace(prefix))
{
level.Insert(0, prefix);
}
object temp = source;
Type tempType = source.GetType();
for (int i = 0; i < level.Count - 1; i++)
{
var member = tempType.GetMember(level[i])[0];
if (member != null)
{
var va = member.GetMemberValue(temp);
if (va != null)
{
temp = va;
}
else
{
var newInstance = member.GetMemberType().GetConstructor(Type.EmptyTypes).Invoke(null);
member.SetMemberValue(temp, newInstance, null);
temp = newInstance;
}
tempType = member.GetMemberType();
}
}
var memberInfos = tempType.GetMember(level.Last());
if (!memberInfos.Any())
{
return;
}
var fproperty = memberInfos[0];
if (value == null || ((value is StringValues s) && StringValues.IsNullOrEmpty(s)))
{
fproperty.SetMemberValue(temp, null, null);
return;
}
bool isArray = false;
if (value != null && value.GetType().IsArray == true)
{
isArray = true;
}
if (stringBasedValue == true)
{
Type propertyType = fproperty.GetMemberType();
if (propertyType.IsGeneric(typeof(List<>)) == true)
{
var list = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null) as IList;
var gs = propertyType.GenericTypeArguments;
try
{
if (value.GetType() == typeof(StringValues))
{
var strVals = (StringValues)value;
var a = strVals.ToArray();
for (int i = 0; i < a.Length; i++)
{
list.Add(a[i].ConvertValue(gs[0]));
}
}
else if (isArray)
{
var a = (value as object[]);
for (int i = 0; i < a.Length; i++)
{
list.Add(a[i].ConvertValue(gs[0]));
}
}
else
{
list = value.ConvertValue(propertyType) as IList;
}
}
catch { }
fproperty.SetMemberValue(temp, list, null);
}
else if (propertyType.IsArray)
{
try
{
var strVals = (StringValues)value;
var eletype = propertyType.GetElementType();
var arr = Array.CreateInstance(eletype, strVals.Count);
for (int i = 0; i < arr.Length; i++)
{
arr.SetValue(strVals[i].ConvertValue(eletype), i);
}
fproperty.SetMemberValue(temp, arr, null);
}
catch { }
}
else
{
if (isArray)
{
var a = (value as object[]);
if (a.Length == 1)
{
value = a[0];
}
}
if (value is string)
{
value = value.ToString().Replace("\\", "/");
}
fproperty.SetMemberValue(temp, value, null);
}
}
else
{
if (value is string)
{
value = value.ToString().Replace("\\", "/");
}
fproperty.SetMemberValue(temp, value, null);
}
}
catch
{
}
}
/// <summary>
/// 根据MemberInfo获取值
/// </summary>
/// <param name="mi">MemberInfo</param>
/// <param name="obj">所在实例</param>
/// <param name="index">如果是数组指定数组下标。默认为null</param>
/// <returns>MemberInfo的值</returns>
public static object GetMemberValue(this MemberInfo mi, object obj, object[] index = null)
{
object rv = null;
if (mi.MemberType == MemberTypes.Property)
{
rv = ((PropertyInfo)mi).GetValue(obj, index);
}
else if (mi.MemberType == MemberTypes.Field)
{
rv = ((FieldInfo)mi).GetValue(obj);
}
return rv;
}
/// <summary>
/// 设定MemberInfo的值
/// </summary>
/// <param name="mi">MemberInfo</param>
/// <param name="obj">所在实例</param>
/// <param name="val">要赋的值</param>
/// <param name="index">如果是数组指定数组下标。默认为null</param>
public static void SetMemberValue(this MemberInfo mi, object obj, object val, object[] index = null)
{
object newval = val;
if (val is string s)
{
if (string.IsNullOrEmpty(s))
{
val = null;
}
}
if (val != null && val.GetType() != mi.GetMemberType())
{
newval = val.ConvertValue(mi.GetMemberType());
}
if (mi.MemberType == MemberTypes.Property)
{
((PropertyInfo)mi).SetValue(obj, newval, index);
}
else if (mi.MemberType == MemberTypes.Field)
{
((FieldInfo)mi).SetValue(obj, newval);
}
}
/// <summary>
/// 获取某个MemberInfo的类型
/// </summary>
/// <param name="mi">MemberInfo</param>
/// <returns>类型</returns>
public static Type GetMemberType(this MemberInfo mi)
{
Type rv = null;
if (mi != null)
{
if (mi.MemberType == MemberTypes.Property)
{
rv = ((PropertyInfo)mi).PropertyType;
}
else if (mi.MemberType == MemberTypes.Field)
{
rv = ((FieldInfo)mi).FieldType;
}
}
return rv;
}
/// <summary>
/// 获取枚举显示名称
/// </summary>
/// <param name="enumType">枚举类型</param>
/// <param name="value">枚举值</param>
/// <returns>枚举显示名称</returns>
public static string GetEnumDisplayName(Type enumType, string value)
{
string rv = "";
FieldInfo field = null;
if (enumType.IsEnum())
{
field = enumType.GetField(value);
}
//如果是nullable的枚举
if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum())
{
field = enumType.GenericTypeArguments[0].GetField(value);
}
if (field != null)
{
var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList();
if (attribs.Count > 0)
{
rv = ((DisplayAttribute)attribs[0]).GetName();
if (CoreProgram._localizer != null)
{
rv = CoreProgram._localizer[rv];
}
}
else
{
rv = value;
}
}
return rv;
}
public static string GetEnumDisplayName(Type enumType, int value)
{
string rv = "";
FieldInfo field = null;
string ename = "";
if (enumType.IsEnum())
{
ename = enumType.GetEnumName(value);
field = enumType.GetField(ename);
}
//如果是nullable的枚举
if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum())
{
ename = enumType.GenericTypeArguments[0].GetEnumName(value);
field = enumType.GenericTypeArguments[0].GetField(ename);
}
if (field != null)
{
var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList();
if (attribs.Count > 0)
{
rv = ((DisplayAttribute)attribs[0]).GetName();
if (CoreProgram._localizer != null)
{
rv = CoreProgram._localizer[rv];
}
}
else
{
rv = ename;
}
}
return rv;
}
/// <summary>
/// 转化值
/// </summary>
/// <param name="value">要转换的值</param>
/// <param name="propertyType">转换后的类型</param>
/// <returns>转换后的值</returns>
public static object ConvertValue(this object value, Type propertyType)
{
object val = null;
if (propertyType.IsGeneric(typeof(Nullable<>)) == true)
{
var gs = propertyType.GenericTypeArguments;
try
{
val = ConvertValue(value, gs[0]);
}
catch { }
}
else if (propertyType.IsEnum())
{
val = Enum.Parse(propertyType, value.ToString());
}
else if (propertyType == typeof(string))
{
val = value?.ToString().Trim();
}
else if (propertyType == typeof(Guid))
{
bool suc = Guid.TryParse(value?.ToString(), out Guid g);
if (suc)
{
val = g;
}
else
{
val = Guid.Empty;
}
}
else if (propertyType == typeof(DateRange))
{
if (DateRange.TryParse(value.ToString(), out var result))
{
val = result;
}
else
{
val = DateRange.Default;
}
}
else
{
try
{
if (value.ToString().StartsWith("`") && value.ToString().EndsWith("`"))
{
string inner = value.ToString().Trim('`').TrimEnd(',');
if (!string.IsNullOrWhiteSpace(inner))
{
val = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null);
string[] pair = inner.Split(',');
var gs = propertyType.GetGenericArguments();
foreach (var p in pair)
{
(val as IList).Add(Convert.ChangeType(p, gs[0]));
}
}
}
else
{
val = Convert.ChangeType(value.ToString(), propertyType);
}
}
catch
{
}
}
return val;
}
public static object MakeList(Type innerType, string propertyName, object[] values)
{
object rv = typeof(List<>).MakeGenericType(innerType).GetConstructor(Type.EmptyTypes).Invoke(null);
var mi = rv.GetType().GetMethod("Add");
var con = innerType.GetConstructor(Type.EmptyTypes);
foreach (var item in values)
{
var newobj = con.Invoke(null);
newobj.SetPropertyValue(propertyName, item);
mi.Invoke(rv, new object[] { newobj });
}
return rv;
}
}
}

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// ListVM接口
/// </summary>
/// <typeparam name="T">ListVM中的Model类</typeparam>
/// <typeparam name="S">ListVM使用的Searcher类</typeparam>
public interface IBasePagedListVM<out T, out S> : IBaseVM
where T : TopBasePoco
where S : ISearcher
{
Type ModelType { get; }
/// <summary>
/// 多级表头深度 默认 1级
/// </summary>
int GetChildrenDepth();
/// <summary>
/// GetHeaders
/// </summary>
/// <returns></returns>
IEnumerable<IGridColumn<T>> GetHeaders();
/// <summary>
/// 页面动作
/// </summary>
List<GridAction> GetGridActions();
/// <summary>
/// 查询并生成Excel
/// </summary>
/// <returns>Excel文件</returns>
byte[] GenerateExcel();
string TotalText { get; set; }
#region Old
event Action<IBasePagedListVM<T, S>> OnAfterInitList;
/// <summary>
///记录批量操作时列表中选择的Id
/// </summary>
List<string> Ids { get; set; }
string SelectorValueField { get; set; }
/// <summary>
/// 获取Model集合
/// </summary>
/// <returns>Model集合</returns>
IEnumerable<T> GetEntityList();
void ClearEntityList();
/// <summary>
/// 获取Searcher
/// </summary>
S Searcher { get; }
/// <summary>
/// GetIsSelected
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
bool GetIsSelected(object item);
/// <summary>
/// 是否已经搜索过
/// </summary>
bool IsSearched { get; set; }
/// <summary>
/// PassSearch
/// </summary>
bool PassSearch { get; set; }
/// <summary>
/// 搜索模式
/// </summary>
ListVMSearchModeEnum SearcherMode { get; set; }
/// <summary>
/// 是否需要分页
/// </summary>
bool NeedPage { get; set; }
/// <summary>
/// 允许导出Excel的最大行数超过行数会分成多个文件最多不能超过100万
/// </summary>
int ExportMaxCount { get; set; }
/// <summary>
/// 根据允许导出的Excel最大行数算出最终导出的Excel个数
/// </summary>
int ExportExcelCount { get; set; }
/// <summary>
/// 移除操作列
/// </summary>
void RemoveActionColumn(object root = null);
void RemoveAction();
/// <summary>
/// 填加错误信息列,用于批量操作的列表
/// </summary>
void AddErrorColumn();
/// <summary>
/// 搜索条件Panel的Id
/// </summary>
string SearcherDivId { get; }
/// <summary>
/// GetSearchQuery
/// </summary>
/// <returns></returns>
IOrderedQueryable<T> GetSearchQuery();
/// <summary>
/// DoSearch
/// </summary>
void DoSearch();
/// <summary>
/// CopyContext
/// </summary>
/// <param name="vm"></param>
void CopyContext(BaseVM vm);
/// <summary>
/// ReplaceWhere
/// </summary>
Expression ReplaceWhere { get; set; }
/// <summary>
/// SetFullRowColor
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
string SetFullRowColor(object entity);
/// <summary>
/// SetFullRowBgColor
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
string SetFullRowBgColor(object entity);
T CreateEmptyEntity();
/// <summary>
/// 用于为子表生成可编辑Grid时内部控件名称前缀
/// </summary>
string DetailGridPrix { get; set; }
void DoInitListVM();
#endregion
}
}

View File

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Caching.Distributed;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// IBaseVM
/// </summary>
public interface IBaseVM
{
#region Property
WTMContext Wtm { get; set; }
/// <summary>
/// UniqueId
/// </summary>
string UniqueId { get; }
/// <summary>
/// WindowIds
/// </summary>
string WindowIds { get;}
/// <summary>
/// ViewDivId
/// </summary>
string ViewDivId { get; set; }
/// <summary>
/// DC
/// </summary>
IDataContext DC { get; set; }
/// <summary>
/// VMFullName
/// </summary>
string VMFullName { get; }
/// <summary>
/// CreatorAssembly
/// </summary>
string CreatorAssembly { get; set; }
/// <summary>
/// CurrentCS
/// </summary>
string CurrentCS { get; }
/// <summary>
/// FC
/// </summary>
Dictionary<string, object> FC { get; set; }
/// <summary>
/// Config
/// </summary>
Configs ConfigInfo { get; }
ISessionService Session { get; }
IDistributedCache Cache { get; }
LoginUserInfo LoginUserInfo { get; }
#endregion
#region Event
/// <summary>
/// InitVM 完成后触发的事件
/// </summary>
event Action<IBaseVM> OnAfterInit;
/// <summary>
/// ReInitVM 完成后触发的事件
/// </summary>
event Action<IBaseVM> OnAfterReInit;
#endregion
#region Method
/// <summary>
/// 调用 InitVM 并触发 OnAfterInit 事件
/// </summary>
void DoInit();
/// <summary>
/// 调用 ReInitVM 并触发 OnAfterReInit 事件
/// </summary>
void DoReInit();
#endregion
}
}

View File

@ -0,0 +1,143 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// IDataContext
/// </summary>
public interface IDataContext : IDisposable
{
/// <summary>
/// IsFake
/// </summary>
bool IsFake { get; set; }
bool IsDebug { get; set; }
DBTypeEnum DBType { get; set; }
/// <summary>
/// AddEntity
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"></param>
void AddEntity<T>(T entity) where T : TopBasePoco;
/// <summary>
/// UpdateEntity
/// </summary>
void UpdateEntity<T>(T entity) where T : TopBasePoco;
/// <summary>
/// UpdateProperty
/// </summary>
void UpdateProperty<T>(T entity, Expression<Func<T, object>> fieldExp) where T : TopBasePoco;
/// <summary>
/// UpdateProperty
/// </summary>
void UpdateProperty<T>(T entity, string fieldName) where T : TopBasePoco;
/// <summary>
/// DeleteEntity
/// </summary>
void DeleteEntity<T>(T entity) where T : TopBasePoco;
/// <summary>
/// CascadeDelete
/// </summary>
void CascadeDelete<T>(T entity) where T : TreePoco;
/// <summary>
/// Set
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
DbSet<T> Set<T>() where T : class;
/// <summary>
/// Model
/// </summary>
IModel Model { get; }
/// <summary>
/// Database
/// </summary>
DatabaseFacade Database { get; }
/// <summary>
/// CSName
/// </summary>
string CSName { get; set; }
#region SaveChange
/// <summary>
/// SaveChanges
/// </summary>
/// <returns></returns>
int SaveChanges();
/// <summary>
/// SaveChanges
/// </summary>
/// <returns></returns>
int SaveChanges(bool acceptAllChangesOnSuccess);
/// <summary>
/// SaveChangesAsync
/// </summary>
/// <returns></returns>
Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// SaveChangesAsync
/// </summary>
/// <returns></returns>
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
#endregion
/// <summary>
/// 初始化
/// </summary>
/// <param name="AllModel"></param>
/// <param name="IsSpa"></param>
/// <returns>返回true即数据新建完成进入初始化操作返回false即数据库已经存在</returns>
Task<bool> DataInit(object AllModel, bool IsSpa);
IDataContext CreateNew();
IDataContext ReCreate();
/// <summary>
/// 执行存储过程返回datatable
/// </summary>
/// <param name="command">存储过程名称</param>
/// <param name="paras">参数</param>
/// <returns></returns>
DataTable RunSP(string command, params object[] paras);
IEnumerable<TElement> RunSP<TElement>(string command, params object[] paras);
/// <summary>
/// 执行sql语句返回datatable
/// </summary>
/// <param name="command">查询sql语句</param>
/// <param name="paras">参数</param>
/// <returns></returns>
DataTable RunSQL(string command, params object[] paras);
IEnumerable<TElement> RunSQL<TElement>(string sql, params object[] paras);
DataTable Run(string sql, CommandType commandType, params object[] paras);
IEnumerable<TElement> Run<TElement>(string sql, CommandType commandType, params object[] paras);
object CreateCommandParameter(string name, object value, ParameterDirection dir);
void SetLoggerFactory(ILoggerFactory factory);
}
}

View File

@ -0,0 +1,12 @@
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// Session接口
/// </summary>
public interface ISessionService
{
T Get<T>(string key);
void Set<T>(string key, T val);
string SessionId { get; }
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WalkingTec.Mvvm.Core
{
public interface IUIService
{
string MakeButton(ButtonTypesEnum buttonType, string url, string buttonText, int? width, int? height, string title = null, string buttonID = null,bool resizable = true, bool max = false, string currentdivid = "", string buttonClass = null, string style = null, RedirectTypesEnum rtype = RedirectTypesEnum.Layer);
string MakeDialogButton(ButtonTypesEnum buttonType, string url, string buttonText, int? width, int? height, string title = null, string buttonID = null, bool showDialog = true, bool resizable = true, bool max = false,string buttonClass = null, string style = null);
string MakeDownloadButton(ButtonTypesEnum buttonType, Guid fileID, string buttonText = null, string _DONOT_USE_CS = "default", string buttonClass = null, string style = null);
string MakeViewButton(ButtonTypesEnum buttonType, Guid fileID, string buttonText = null, int? width = null, int? height = null, string title = null, bool resizable = true, string _DONOT_USE_CS = "default", bool maxed = false, string buttonClass = null, string style = null);
string MakeScriptButton(ButtonTypesEnum buttonType, string buttonText, string script = "", string buttonID = null, string url = null, string buttonClass = null, string style = null);
string MakeCheckBox(bool ischeck, string text = null, string name = null, string value = null, bool isReadOnly = false);
string MakeRadio(bool ischeck, string text = null, string name = null, string value = null, bool isReadOnly = false);
string MakeCombo(string name = null, List<ComboSelectListItem> value = null, string selectedValue = null, string emptyText = null, bool isReadOnly = false);
string MakeTextBox(string name = null, string value = null, string emptyText = null, bool isReadOnly = false);
string MakeDateTime(string name = null, string value = null, string emptyText = null, bool isReadOnly = false);
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace WalkingTec.Mvvm.Core.Implement
{
public class DefaultUIService : IUIService
{
public string MakeDialogButton(ButtonTypesEnum buttonType, string url, string buttonText, int? width, int? height, string title = null, string buttonID = null, bool showDialog = true, bool resizable = true, bool max = false, string buttonClass = null, string style = null)
{
return "";
}
public string MakeDownloadButton(ButtonTypesEnum buttonType, Guid fileID, string buttonText = null, string _DONOT_USE_CS = "default", string buttonClass = null, string style = null)
{
return "";
}
public string MakeCheckBox(bool ischeck, string text = null, string name = null, string value = null, bool isReadOnly = false)
{
return "";
}
public string MakeButton(ButtonTypesEnum buttonType, string url, string buttonText, int? width, int? height, string title = null, string buttonID = null, bool resizable = true, bool max = false, string currentdivid = "", string buttonClass = null, string style = null, RedirectTypesEnum rtype = RedirectTypesEnum.Layer)
{
return "";
}
public string MakeViewButton(ButtonTypesEnum buttonType, Guid fileID, string buttonText = null, int? width = null, int? height = null, string title = null, bool resizable = true, string _DONOT_USE_CS = "default", bool maxed = false, string buttonClass = null, string style = null)
{
return "";
}
public string MakeScriptButton(ButtonTypesEnum buttonType, string buttonText, string script = "", string buttonID = null, string url = null, string buttonClass = null, string style = null)
{
return "";
}
public string MakeRadio(bool ischeck, string text = null, string name = null, string value = null, bool isReadOnly = false)
{
return "";
}
public string MakeCombo(string name = null, List<ComboSelectListItem> value = null, string selectedValue = null, string emptyText = null, bool isReadOnly = false)
{
return "";
}
public string MakeTextBox(string name = null, string value = null, string emptyText = null, bool isReadOnly = false)
{
return "";
}
public string MakeDateTime(string name = null, string value = null, string emptyText = null, bool isReadOnly = false)
{
return "";
}
}
}

View File

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core.Json
{
/// <summary>
/// StringIgnoreLTGTConvert
/// 忽略客户端提交的 &lt;及&gt;字符
/// </summary>
public class BodyConverter : JsonConverter<PostedBody>
{
public override PostedBody Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rv = new PostedBody();
rv.ProNames = new List<string>();
List<string> prefix = new List<string>();
int depth = 0;
string lastObjecName = "";
int insideArray = 0;
JsonTokenType lastToken = JsonTokenType.Null;
while (true)
{
if (reader.TokenType == JsonTokenType.StartArray)
{
insideArray++;
depth++;
prefix.Add(lastObjecName + "[0]");
}
if (reader.TokenType == JsonTokenType.EndArray)
{
insideArray--;
depth--;
prefix.RemoveAt(prefix.Count - 1);
}
if (reader.TokenType == JsonTokenType.StartObject)
{
if (insideArray == 0)
{
depth++;
prefix.Add(lastObjecName);
if (rv.ProNames.Count > 0)
{
rv.ProNames.RemoveAt(rv.ProNames.Count - 1);
}
}
else
{
if (lastToken != JsonTokenType.StartArray)
{
reader.TrySkip();
reader.Read();
continue;
}
}
}
if (reader.TokenType == JsonTokenType.PropertyName)
{
var pname = reader.GetString();
lastObjecName = pname;
var p = prefix.Take(depth).ToSepratedString(seperator: ".");
if (string.IsNullOrEmpty(p) == false)
{
pname = p + "." + pname;
}
if (rv.ProNames.Contains(pname) == false)
{
rv.ProNames.Add(pname);
}
}
if (reader.TokenType == JsonTokenType.EndObject)
{
if (insideArray == 0)
{
depth--;
prefix.RemoveAt(prefix.Count - 1);
}
if (reader.IsFinalBlock == true && reader.CurrentDepth == 0)
{
reader.Read();
break;
}
}
lastToken = reader.TokenType;
reader.Read();
}
return rv;
}
public override void Write(Utf8JsonWriter writer, PostedBody value, JsonSerializerOptions options)
{
return;
}
}
public class PostedBody
{
public List<string> ProNames { get; set; }
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using NPOI.SS.Formula.Functions;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core.Json
{
public class BoolStringConverter :
JsonConverter<bool>
{
public override bool Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
JsonTokenType token = reader.TokenType;
if (token == JsonTokenType.String)
{
var s = reader.GetString() ?? "";
if (s.ToLower() == "true")
{
return true;
}
else if (s.ToLower() == "false")
{
return false;
}
else
{
return false;
}
}
else if (token == JsonTokenType.True || token == JsonTokenType.False)
{
return reader.GetBoolean();
}
else
{
return false;
}
}
public override void Write(
Utf8JsonWriter writer,
bool data,
JsonSerializerOptions options)
{
writer.WriteBooleanValue(data);
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core;
namespace WalkingTec.Mvvm.Core.Json
{
public class DateRangeConverter : JsonConverter<DateRange>
{
public override DateRange Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
try
{
if (reader.TokenType == JsonTokenType.StartArray)
{
reader.Read();
string[] ds = new string[2];
ds[0] = reader.GetString();
reader.Read();
ds[1] = reader.GetString();
reader.Read();
if (DateRange.TryParse(ds, out var dateRange))
{
return dateRange;
}
else
{
return null;
}
}
}
catch (Exception)
{
}
return null;
}
public override void Write(Utf8JsonWriter writer, DateRange value, JsonSerializerOptions options)
{
if (value == null)
{
writer.WriteNullValue();
}
else
{
//writer.WriteStringValue(JsonSerializer.Serialize(value),);
writer.WriteStartArray();
writer.WriteStringValue(value.GetStartTime().ToString());
writer.WriteStringValue(value.GetEndTime().ToString());
writer.WriteEndArray();
}
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace WalkingTec.Mvvm.Core.Json
{
public class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
if (DateTime.TryParse(reader.GetString(), out DateTime date))
return date;
}
return reader.GetDateTime();
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
}

View File

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core.Json
{
public class DynamicDataConverter : JsonConverter<DynamicData>
{
public override DynamicData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
try
{
DynamicData rv = new DynamicData();
rv.Fields = new Dictionary<string, object>();
string currentkey = "";
//object currentvalue;
int level = 0;
while (true)
{
if(reader.TokenType == JsonTokenType.StartObject) {
if(level > 0)
{
var inner = JsonSerializer.Deserialize<DynamicData>(ref reader, options);
rv.Fields.Add(currentkey, inner);
}
level++;
}
if(reader.TokenType == JsonTokenType.EndObject)
{
level--;
}
if (reader.TokenType == JsonTokenType.PropertyName)
{
currentkey = reader.GetString();
}
if(reader.TokenType == JsonTokenType.String || reader.TokenType == JsonTokenType.Number || reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False || reader.TokenType == JsonTokenType.Null)
{
var val = JsonSerializer.Deserialize<object>(ref reader,options);
rv.Fields.Add(currentkey, val);
}
if (reader.IsFinalBlock && level == 0)
{
//reader.Read();
break;
}
reader.Read();
}
return rv;
}
catch
{
return null;
}
}
public override void Write(Utf8JsonWriter writer, DynamicData value, JsonSerializerOptions options)
{
if (value == null || value.Fields == null)
{
writer.WriteNullValue();
}
else
{
writer.WriteStartObject();
foreach (var item in value.Fields)
{
if(item.Value == null)
{
if (options.IgnoreNullValues == false)
{
writer.WriteNull(item.Key);
}
}
else
{
writer.WritePropertyName(item.Key);
JsonSerializer.Serialize(writer, item.Value, options);
}
}
writer.WriteEndObject();
}
}
}
}

View File

@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Text.Unicode;
using System.Threading.Tasks;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core.Json
{
public class PocoConverter : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
return typeof(TopBasePoco).IsAssignableFrom(typeToConvert);
}
public override JsonConverter CreateConverter(
Type type,
JsonSerializerOptions options)
{
var temp = CloneOptions(options);
foreach (var item in options.Converters)
{
if(item.GetType() != typeof(PocoConverter))
{
temp.Converters.Add(item);
}
}
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(PocoConverterInner<>).MakeGenericType(
new Type[] { type }),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: new object[] { temp },
culture: null);
return converter;
}
private JsonSerializerOptions CloneOptions(JsonSerializerOptions op)
{
JsonSerializerOptions rv = new JsonSerializerOptions();
rv.PropertyNamingPolicy = op.PropertyNamingPolicy;
rv.AllowTrailingCommas = op.AllowTrailingCommas;
rv.DefaultBufferSize = op.DefaultBufferSize;
rv.DefaultIgnoreCondition = op.DefaultIgnoreCondition;
rv.DictionaryKeyPolicy = op.DictionaryKeyPolicy;
rv.Encoder = op.Encoder;
rv.IgnoreNullValues = op.IgnoreNullValues;
rv.IgnoreReadOnlyFields = op.IgnoreReadOnlyFields;
rv.IgnoreReadOnlyProperties = op.IgnoreReadOnlyProperties;
rv.IncludeFields = op.IncludeFields;
rv.DefaultIgnoreCondition = op.DefaultIgnoreCondition;
rv.DictionaryKeyPolicy = op.DictionaryKeyPolicy;
rv.MaxDepth = op.MaxDepth;
rv.NumberHandling = op.NumberHandling;
rv.ReadCommentHandling = op.ReadCommentHandling;
rv.ReferenceHandler = op.ReferenceHandler;
rv.WriteIndented = op.WriteIndented;
return rv;
}
private class PocoConverterInner<T> :
JsonConverter<T> where T : TopBasePoco
{
protected readonly JsonSerializerOptions _options;
public PocoConverterInner(JsonSerializerOptions options)
{
_options = options;
}
public override T Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<T>(ref reader, _options);
}
public override void Write(
Utf8JsonWriter writer,
T data,
JsonSerializerOptions options)
{
var _datacache = new Dictionary<string, int>();
RemoveCycleReference(data, _datacache);
JsonSerializer.Serialize(writer, data, typeof(T), _options);
}
private void RemoveCycleReference(object Entity, Dictionary<string, int> datacache)
{
var pros = Entity.GetType().GetAllProperties();
var mainkey = Entity.GetType().FullName + (Entity as TopBasePoco).GetID();
datacache.TryAdd(mainkey, 1);
foreach (var pro in pros)
{
if (typeof(TopBasePoco).IsAssignableFrom(pro.PropertyType))
{
var subentity = pro.GetValue(Entity) as TopBasePoco;
string key = pro.PropertyType.FullName + subentity?.GetID() ?? "";
if (subentity != null && datacache.ContainsKey(key) == false)
{
RemoveCycleReference(subentity, datacache);
}
else
{
pro.SetValue(Entity,null);
}
}
//找到类型为List<xxx>的字段
if (pro.PropertyType.GenericTypeArguments.Count() > 0)
{
//获取xxx的类型
var ftype = pro.PropertyType.GenericTypeArguments.First();
//如果xxx继承自TopBasePoco
if (ftype.IsSubclassOf(typeof(TopBasePoco)))
{
//界面传过来的子表数据
if (pro.GetValue(Entity) is IEnumerable<TopBasePoco> list && list.Count() > 0)
{
bool found = false;
foreach (var newitem in list)
{
if (newitem != null)
{
string subkey = ftype.FullName + newitem?.GetID() ?? "";
if (datacache.ContainsKey(subkey) == false)
{
RemoveCycleReference(newitem, datacache.ToDictionary(x=>x.Key,x=>x.Value));
found = true;
}
else
{
found = false;
break;
}
}
}
if(found == false)
{
pro.SetValue(Entity, null);
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using NPOI.SS.Formula.Functions;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core.Json
{
public class RawStringConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
try
{
if (reader.TokenType == JsonTokenType.String)
{
string rv = reader.GetString();
return rv;
}
}
catch (Exception)
{
}
return null;
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
if (value == null)
{
writer.WriteNullValue();
}
else
{
var txt = JsonEncodedText.Encode($"_raw_{value}_raw_", JavaScriptEncoder.UnsafeRelaxedJsonEscaping);
writer.WriteStringValue(txt);
}
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace System.Text.Json.Serialization
{
public class JsonStringConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
if (reader.TokenType == JsonTokenType.String)
{
return reader.GetString();
}
return null;
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
if (value == null)
{
writer.WriteNullValue();
}
else
{
writer.WriteStringValue(value);
}
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace System.Text.Json.Serialization
{
/// <summary>
/// StringIgnoreLTGTConvert
/// 忽略客户端提交的 &lt;及&gt;字符
/// </summary>
public class StringIgnoreLTGTConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
if (reader.TokenType == JsonTokenType.String)
{
return reader.GetString().Replace("<", string.Empty).Replace(">", string.Empty);
}
return null;
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
if (value == null)
{
writer.WriteNullValue();
}
else
{
writer.WriteStringValue(value);
}
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using NPOI.SS.Formula.Functions;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Core.Json
{
public class TypeConverter : JsonConverter<Type>
{
public override Type Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return null;
}
public override void Write(Utf8JsonWriter writer, Type value, JsonSerializerOptions options)
{
writer.WriteNullValue();
}
}
}

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// DataTableResult
/// </summary>
public class DataTableResult<T> : JsonResultT<IEnumerable<T>>
where T : TopBasePoco
{
/// <summary>
/// Data Count
/// </summary>
public long Count { get; set; }
}
/// <summary>
/// JsonResultT
/// </summary>
public class JsonResultT<T>
{
/// <summary>
/// Status Code
/// <see cref="Microsoft.AspNetCore.Http.StatusCodes">
/// </summary>
public int Code { get; set; }
/// <summary>
/// Message
/// </summary>
public string Msg { get; set; }
/// <summary>
/// Data
/// </summary>
public T Data { get; set; }
}
}

View File

@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using NPOI.SS.Formula.Functions;
using WalkingTec.Mvvm.Core.Support.Json;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 用户登录信息需要保存在Session中所以使用Serializable标记
/// </summary>
public class LoginUserInfo
{
public string UserId { get; set; }
/// <summary>
/// 登录用户
/// </summary>
public string ITCode { get; set; }
public string TenantCode { get; set; }
public string Name { get; set; }
public string Memo { get; set; }
public Guid? PhotoId { get; set; }
public List<SimpleRole> Roles { get; set; }
public List<SimpleGroup> Groups { get; set; }
public Dictionary<string, object> Attributes { get; set; }
/// <summary>
/// 用户的页面权限列表
/// </summary>
public List<SimpleFunctionPri> FunctionPrivileges { get; set; }
/// <summary>
/// 用户的数据权限列表
/// </summary>
public List<SimpleDataPri> DataPrivileges { get; set; }
public async System.Threading.Tasks.Task LoadBasicInfoAsync(WTMContext context)
{
if (string.IsNullOrEmpty(this.ITCode) || context?.DC == null || context.BaseUserQuery == null)
{
return;
}
var DC = context.DC;
var userInfo = await context.BaseUserQuery
.Where(x => x.ITCode.ToLower() == this.ITCode.ToLower() && x.IsValid)
.Select(x => new {
user = x,
UserRoles = DC.Set<FrameworkUserRole>().Where(y => y.UserCode == x.ITCode).ToList(),
UserGroups = DC.Set<FrameworkUserGroup>().Where(y => y.UserCode == x.ITCode).ToList(),
})
.FirstOrDefaultAsync();
if (userInfo != null)
{
// 初始化用户信息
var roleIDs = userInfo.UserRoles.Select(x => x.RoleCode).ToList();
var groupIDs = userInfo.UserGroups.Select(x => x.GroupCode).ToList();
var dataPris = await DC.Set<DataPrivilege>().AsNoTracking()
.Where(x => x.UserCode == userInfo.user.ITCode || (x.GroupCode != null && groupIDs.Contains(x.GroupCode)))
.Distinct()
.ToListAsync();
ProcessTreeDp(dataPris,context);
//查找登录用户的页面权限
var funcPrivileges = await DC.Set<FunctionPrivilege>().AsNoTracking()
.Where(x => x.RoleCode != null && roleIDs.Contains(x.RoleCode))
.Distinct()
.ToListAsync();
var roles = DC.Set<FrameworkRole>().AsNoTracking().Where(x => roleIDs.Contains(x.RoleCode)).ToList();
var groups = DC.Set<FrameworkGroup>().AsNoTracking().Where(x => groupIDs.Contains(x.GroupCode)).ToList();
this.ITCode = userInfo.user.ITCode;
if (string.IsNullOrEmpty(this.Name))
{
this.Name = userInfo.user.Name;
}
if (this.PhotoId == null)
{
this.PhotoId = userInfo.user.PhotoId;
}
if (string.IsNullOrEmpty(this.TenantCode))
{
this.TenantCode = userInfo.user.TenantCode;
}
this.Roles = roles.Select(x => new SimpleRole { ID = x.ID, RoleCode = x.RoleCode, RoleName = x.RoleName }).ToList();
this.Groups = groups.Select(x => new SimpleGroup { ID = x.ID, GroupCode = x.GroupCode, GroupName = x.GroupName }).ToList();
this.DataPrivileges = dataPris.Select(x => new SimpleDataPri { ID = x.ID, RelateId = x.RelateId, TableName = x.TableName, UserCode = x.UserCode, GroupCode = x.GroupCode }).ToList();
this.FunctionPrivileges = funcPrivileges.Select(x => new SimpleFunctionPri { ID = x.ID, RoleCode = x.RoleCode, Allowed = x.Allowed, MenuItemId = x.MenuItemId }).ToList();
}
}
private void ProcessTreeDp(List<DataPrivilege> dps, WTMContext context)
{
var dpsSetting = context.DataPrivilegeSettings;
foreach (var dp in dpsSetting)
{
if (typeof(TreePoco).IsAssignableFrom(dp.ModelType))
{
var ids = dps.Where(x => x.TableName == dp.ModelName).Select(x => x.RelateId).ToList();
if (ids.Count > 0 && ids.Contains(null) == false)
{
var skipids = dp.GetTreeParentIds(context, dps);
List<string> subids = new List<string>();
subids.AddRange(GetSubIds(dp, ids, dp.ModelType, skipids,context));
subids = subids.Distinct().ToList();
subids.ForEach(x => dps.Add(new DataPrivilege
{
TableName = dp.ModelName,
RelateId = x.ToString()
}));
}
}
}
}
private IEnumerable<string> GetSubIds(IDataPrivilege dp, List<string> p_id, Type modelType, List<string> skipids,WTMContext context)
{
var ids = p_id.Where(x => skipids.Contains(x) == false).ToList();
var subids = dp.GetTreeSubIds(context, ids);
if (subids.Count > 0)
{
return subids.Concat(GetSubIds(dp, subids, modelType, skipids,context));
}
else
{
return new List<string>();
}
}
}
}

View File

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 模型状态接口
/// </summary>
public interface IModelStateService
{
/// <summary>
/// 索引
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
List<MsdError> this[string name] { get; }
/// <summary>
/// 添加模型错误
/// </summary>
/// <param name="key">字段名称</param>
/// <param name="errorMessage">错误信息</param>
void AddModelError(string key, string errorMessage);
void RemoveModelError(string key);
int Count { get; }
IEnumerable<string> Keys { get; }
void Clear();
string GetFirstError();
bool IsValid { get; }
}
/// <summary>
/// 记录错误的简单类
/// </summary>
public class MsdError
{
public string ErrorMessage { get; set; }
public Exception Exception { get; set; }
}
public class BasicMSD : IModelStateService
{
private Dictionary<string, string> _states;
public BasicMSD()
{
this._states = new Dictionary<string, string>();
}
public List<MsdError> this[string name]
{
get
{
return _states.Where(x => x.Key == name).Select(x => new MsdError { ErrorMessage = x.Value }).ToList();
}
}
/// <summary>
/// 添加错误信息
/// </summary>
/// <param name="key">错误的字段名</param>
/// <param name="errorMessage">错误信息</param>
public void AddModelError(string key, string errorMessage)
{
_states.Add(key, errorMessage);
}
public void RemoveModelError(string key)
{
_states.Remove(key);
}
public void Clear()
{
_states.Clear();
}
public string GetFirstError()
{
string rv = "";
foreach (var key in Keys)
{
if (this[key].Count > 0)
{
rv = this[key].First().ErrorMessage;
}
}
return rv;
}
public int Count => _states.Count;
public IEnumerable<string> Keys => _states.Keys;
bool IModelStateService.IsValid => _states.Count > 0 ? false : true;
}
}

View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace WalkingTec.Mvvm.Core
{
public enum ActionLogTypesEnum
{
[Display(Name = "_Admin.Normal")]
Normal,
[Display(Name = "_Admin.Exception")]
Exception,
[Display(Name = "_Admin.Debug")]
Debug
};
/// <summary>
/// ActionLog
/// </summary>
[Table("ActionLogs")]
public class ActionLog : BasePoco, ICloneable
{
[Display(Name = "_Admin.Module")]
[StringLength(255, ErrorMessage = "Validate.{0}stringmax{1}")]
public string ModuleName { get; set; }
[Display(Name = "_Admin.Action")]
[StringLength(255, ErrorMessage = "Validate.{0}stringmax{1}")]
public string ActionName { get; set; }
[Display(Name = "_Admin.Account")]
[StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")]
public string ITCode { get; set; }
[Display(Name = "Url")]
[StringLength(250, ErrorMessage = "Validate.{0}stringmax{1}")]
public string ActionUrl { get; set; }
[Display(Name = "_Admin.ActionTime")]
public DateTime ActionTime { get; set; }
[Display(Name = "_Admin.Duration")]
public double Duration { get; set; }
[Display(Name = "_Admin.Remark")]
public string Remark { get; set; }
[StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")]
[Display(Name = "IP")]
public string IP { get; set; }
[Display(Name = "_Admin.LogType")]
public ActionLogTypesEnum LogType { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
public string GetLogString()
{
return $@"
|-{Core.CoreProgram._localizer?["_Admin.ActionTime"]}{this.ActionTime}
|-{Core.CoreProgram._localizer?["_Admin.Account"]}{this.ITCode??""}
|-IP{this.IP??""}
|-{Core.CoreProgram._localizer?["_Admin.Module"]}{this.ModuleName??""}
|-{Core.CoreProgram._localizer?["_Admin.MethodName"]}{this.ActionName ?? ""}
|-Url{this.ActionUrl ?? ""}
|-{Core.CoreProgram._localizer?["_Admin.Duration"]}{this.Duration.ToString("F2")+" s"}
|-{Core.CoreProgram._localizer?["_Admin.Remark"]}{this.Remark}
";
}
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace WalkingTec.Mvvm.Core
{
public interface IBasePoco
{
DateTime? CreateTime { get; set; }
string CreateBy { get; set; }
DateTime? UpdateTime { get; set; }
string UpdateBy { get; set; }
}
/// <summary>
/// Model层的基类所有的model都应该继承这个类。这会使所有的model层对应的数据库表都有一个自增主键
/// </summary>
public class BasePoco : TopBasePoco, IBasePoco
{
/// <summary>
/// CreateTime
/// </summary>
[Display(Name = "_Admin.CreateTime")]
public DateTime? CreateTime { get; set; }
/// <summary>
/// CreateBy
/// </summary>
[Display(Name = "_Admin.CreateBy")]
[StringLength(50,ErrorMessage = "Validate.{0}stringmax{1}")]
public string CreateBy { get; set; }
/// <summary>
/// UpdateTime
/// </summary>
[Display(Name = "_Admin.UpdateTime")]
public DateTime? UpdateTime { get; set; }
/// <summary>
/// UpdateBy
/// </summary>
[Display(Name = "_Admin.UpdateBy")]
[StringLength(50,ErrorMessage = "Validate.{0}stringmax{1}")]
public string UpdateBy { get; set; }
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// DataPrivilege
/// </summary>
[Table("DataPrivileges")]
public class DataPrivilege : BasePoco
{
[Display(Name = "_Admin.User")]
public string UserCode { get; set; }
[Display(Name = "_Admin.Group")]
public string GroupCode { get; set; }
[Required(ErrorMessage = "Validate.{0}required")]
[StringLength(50,ErrorMessage = "Validate.{0}stringmax{1}")]
[Display(Name = "_Admin.TableName")]
public string TableName { get; set; }
public string RelateId { get; set; }
[Display(Name = "_Admin.Domain")]
public string Domain { get; set; }
}
}

View File

@ -0,0 +1,60 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.IO;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core.Models;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// FileAttachment
/// </summary>
[Table("FileAttachments")]
public class FileAttachment : TopBasePoco, IWtmFile, IDisposable
{
[Display(Name = "_Admin.FileName")]
[Required(ErrorMessage = "Validate.{0}required")]
public string FileName { get; set; }
[Display(Name = "_Admin.FileExt")]
[Required(ErrorMessage = "Validate.{0}required")]
[StringLength(10)]
public string FileExt { get; set; }
[Display(Name = "_Admin.Path")]
public string Path { get; set; }
[Display(Name = "_Admin.Length")]
public long Length { get; set; }
public DateTime UploadTime { get; set; }
public string SaveMode { get; set; }
public byte[] FileData { get; set; }
public string ExtraInfo { get; set; }
public string HandlerInfo { get; set; }
[NotMapped]
[JsonIgnore]
public Stream DataStream { get; set; }
public void Dispose()
{
if(DataStream != null)
{
DataStream.Dispose();
}
}
string IWtmFile.GetID()
{
return ID.ToString();
}
}
}

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using System.Xml.Serialization;
namespace WalkingTec.Mvvm.Core
{
[Table("FrameworkGroups")]
public class FrameworkGroup : BasePoco
{
[Display(Name = "_Admin.GroupCode")]
[Required(ErrorMessage = "Validate.{0}required")]
[RegularExpression("^[0-9]*$", ErrorMessage = "Validate.{0}number")]
[StringLength(100, ErrorMessage = "Validate.{0}stringmax{1}")]
public string GroupCode { get; set; }
[Display(Name = "_Admin.GroupName")]
[StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")]
[Required(ErrorMessage = "Validate.{0}required")]
public string GroupName { get; set; }
[Display(Name = "_Admin.Remark")]
public string GroupRemark { get; set; }
[NotMapped]
[Display(Name = "_Admin.UsersCount")]
public int UsersCount { get; set; }
[Display(Name = "_Admin.Tenant")]
public string TenantCode { get; set; }
}
}

View File

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// FrameworkMenu
/// </summary>
[Table("FrameworkMenus")]
public class FrameworkMenu : TreePoco<FrameworkMenu>
{
[Display(Name = "_Admin.PageName")]
[StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")]
[Required(ErrorMessage = "Validate.{0}required")]
public string PageName { get; set; }
[Display(Name = "_Admin.ActionName")]
public string ActionName { get; set; }
[Display(Name = "Codegen.ModuleName")]
public string ModuleName { get; set; }
[Display(Name = "_Admin.FolderOnly")]
[Required(ErrorMessage = "Validate.{0}required")]
public bool FolderOnly { get; set; }
[Display(Name = "_Admin.IsInherit")]
[Required(ErrorMessage = "Validate.{0}required")]
public bool IsInherit { get; set; }
[Display(Name = "_Admin.Privileges")]
public List<FunctionPrivilege> Privileges { get; set; }
/// <summary>
/// ClassName
/// </summary>
/// <value></value>
public string ClassName { get; set; }
/// <summary>
/// MethodName
/// </summary>
/// <value></value>
public string MethodName { get; set; }
[Display(Name = "_Admin.Domain")]
public string Domain { get; set; }
[Display(Name = "_Admin.ShowOnMenu")]
[Required(ErrorMessage = "Validate.{0}required")]
public bool ShowOnMenu { get; set; }
[Display(Name = "_Admin.IsPublic")]
[Required(ErrorMessage = "Validate.{0}required")]
public bool IsPublic { get; set; }
[Display(Name = "_Admin.DisplayOrder")]
[Required(ErrorMessage = "Validate.{0}required")]
public int? DisplayOrder { get; set; }
[Display(Name = "_Admin.IsInside")]
[Required(ErrorMessage = "Validate.{0}required")]
public bool? IsInside { get; set; }
/// <summary>
/// Url
/// </summary>
/// <value></value>
public string Url { get; set; }
[Display(Name = "_Admin.Icon")]
[StringLength(50)]
public string Icon { get; set; }
}
}

View File

@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using System.Xml.Serialization;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// FrameworkRole
/// </summary>
[Table("FrameworkRoles")]
public class FrameworkRole : BasePoco
{
[Display(Name = "_Admin.RoleCode")]
[Required(ErrorMessage = "Validate.{0}required")]
[RegularExpression("^[0-9]*$", ErrorMessage = "Validate.{0}number")]
[StringLength(100, ErrorMessage = "Validate.{0}stringmax{1}")]
public string RoleCode { get; set; }
[Display(Name = "_Admin.RoleName")]
[StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")]
[Required(ErrorMessage = "Validate.{0}required")]
public string RoleName { get; set; }
[Display(Name = "_Admin.Remark")]
public string RoleRemark { get; set; }
[Display(Name = "_Admin.Tenant")]
public string TenantCode { get; set; }
[NotMapped]
[Display(Name = "_Admin.UsersCount")]
public int UsersCount { get; set; }
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Microsoft.EntityFrameworkCore;
using WalkingTec.Mvvm.Core.Support.Json;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// FrameworkUser
/// </summary>
[Table("FrameworkUsers")]
public class FrameworkUserBase : BasePoco
{
[Display(Name = "_Admin.Account")]
[Required(ErrorMessage = "Validate.{0}required")]
[StringLength(50,ErrorMessage = "Validate.{0}stringmax{1}")]
public string ITCode { get; set; }
[Display(Name = "_Admin.Password")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Validate.{0}required")]
[StringLength(32, ErrorMessage = "Validate.{0}stringmax{1}")]
public string Password { get; set; }
[Display(Name = "_Admin.Name")]
[Required(ErrorMessage = "Validate.{0}required")]
[StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")]
public string Name { get; set; }
[Display(Name = "_Admin.IsValid")]
public bool IsValid { get; set; }
[Display(Name = "_Admin.Photo")]
public Guid? PhotoId { get; set; }
[Display(Name = "_Admin.Photo")]
[JsonIgnore]
public FileAttachment Photo { get; set; }
[Display(Name = "_Admin.Tenant")]
public string TenantCode { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core.Attributes;
namespace WalkingTec.Mvvm.Core
{
[Table("FrameworkUserGroups")]
public class FrameworkUserGroup : BasePoco
{
[Required]
public string UserCode { get; set; }
[Display(Name = "_Admin.Group")]
[Required]
public string GroupCode { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core.Attributes;
namespace WalkingTec.Mvvm.Core
{
[Table("FrameworkUserRoles")]
public class FrameworkUserRole : BasePoco
{
[Required]
public string UserCode { get; set; }
[Required]
[Display(Name = "_Admin.Role")]
public string RoleCode { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// FunctionPrivilege
/// </summary>
[Table("FunctionPrivileges")]
public class FunctionPrivilege : BasePoco
{
[Display(Name = "_Admin.Role")]
public string RoleCode { get; set; }
[Display(Name = "_Admin.MenuItem")]
public Guid MenuItemId { get; set; }
[Display(Name = "_Admin.MenuItem")]
public FrameworkMenu MenuItem { get; set; }
[Display(Name = "_Admin.Allowed")]
[Required(ErrorMessage = "Validate.{0}required")]
public bool? Allowed { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More