升级wtm基础框架至6.1.0
This commit is contained in:
parent
30bd58b4aa
commit
4f5d897ac1
@ -6,7 +6,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.1">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
@ -22,6 +22,7 @@
|
||||
<script src="/jquery.cookie.js"></script>
|
||||
<script src="/echarts/json-fns.js"></script>
|
||||
<script src="/layui/layui.js"></script>
|
||||
<script src="/layui/xm-select.js"></script>
|
||||
<script src="/echarts/echarts.min.js"></script>
|
||||
<script src="/echarts/chalk.js"></script>
|
||||
<script src="/echarts/essos.js"></script>
|
||||
|
8
IoTGateway/wwwroot/layui/xm-select.js
Normal file
8
IoTGateway/wwwroot/layui/xm-select.js
Normal file
File diff suppressed because one or more lines are too long
@ -56,7 +56,11 @@ namespace WalkingTec.Mvvm.Core
|
||||
}
|
||||
set
|
||||
{
|
||||
_domains = value;
|
||||
_domains = new Dictionary<string, Domain>();
|
||||
foreach (var domain in value)
|
||||
{
|
||||
_domains.Add(domain.Key.ToLower(), domain.Value);
|
||||
}
|
||||
foreach (var item in _domains)
|
||||
{
|
||||
if(item.Value != null)
|
||||
|
@ -177,8 +177,9 @@ namespace WalkingTec.Mvvm.Core
|
||||
var AllModules = allModules as List<SimpleModule>;
|
||||
var roles = new FrameworkRole[]
|
||||
{
|
||||
new FrameworkRole{ ID = Guid.NewGuid(), RoleCode = "001", RoleName = CoreProgram._localizer?["Sys.Admin"]}
|
||||
};
|
||||
new FrameworkRole{ ID = Guid.NewGuid(), RoleCode = "001", CreateBy="Admin" , RoleName = CoreProgram._localizer?["Sys.Admin"]},
|
||||
new FrameworkRole{ ID = Guid.NewGuid(), RoleCode = "002", RoleName = CoreProgram._localizer?["_Admin.User"]},
|
||||
};
|
||||
|
||||
var adminRole = roles[0];
|
||||
if (Set<FrameworkMenu>().Any() == false)
|
||||
@ -1069,7 +1070,8 @@ namespace WalkingTec.Mvvm.Core
|
||||
var AllModules = allModules as List<SimpleModule>;
|
||||
var roles = new FrameworkRole[]
|
||||
{
|
||||
new FrameworkRole{ ID = Guid.NewGuid(), RoleCode = "001", RoleName = CoreProgram._localizer?["Sys.Admin"]}
|
||||
new FrameworkRole{ ID = Guid.NewGuid(), RoleCode = "001", RoleName = CoreProgram._localizer?["Sys.Admin"]},
|
||||
new FrameworkRole{ ID = Guid.NewGuid(), RoleCode = "002", RoleName = CoreProgram._localizer?["_Admin.User"]},
|
||||
};
|
||||
|
||||
var adminRole = roles[0];
|
||||
|
@ -48,7 +48,8 @@ namespace WalkingTec.Mvvm.Core
|
||||
public enum ButtonTypesEnum
|
||||
{
|
||||
Button,
|
||||
Link
|
||||
Link,
|
||||
Img
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
@ -277,6 +277,8 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
private static IQueryable<T> AppendSelfDPWhere<T>(IQueryable<T> query, WTMContext wtmcontext, List<SimpleDataPri> dps) where T : TopBasePoco
|
||||
{
|
||||
var dpsSetting = wtmcontext?.DataPrivilegeSettings;
|
||||
Type modelTye = typeof(T);
|
||||
bool isBasePoco = typeof(IBasePoco).IsAssignableFrom(modelTye);
|
||||
ParameterExpression pe = Expression.Parameter(typeof(T));
|
||||
Expression peid = Expression.Property(pe, typeof(T).GetSingleProperty("ID"));
|
||||
//循环数据权限,加入到where条件中,达到自动过滤的效果
|
||||
@ -293,7 +295,15 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
var ids = dps.Where(x => x.TableName == query.ElementType.Name).Select(x => x.RelateId).ToList();
|
||||
if (ids == null || ids.Count() == 0)
|
||||
{
|
||||
query = query.Where(Expression.Lambda<Func<T, bool>>(Expression.NotEqual(Expression.Constant(1), Expression.Constant(1)), pe));
|
||||
//if (isBasePoco == true)
|
||||
//{
|
||||
// var selfexp = Expression.Equal(Expression.Property(pe, "CreateBy"), Expression.Constant(wtmcontext.LoginUserInfo?.ITCode));
|
||||
// query = query.Where(Expression.Lambda<Func<T, bool>>(selfexp, pe));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
query = query.Where(Expression.Lambda<Func<T, bool>>(Expression.NotEqual(Expression.Constant(1), Expression.Constant(1)), pe));
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -315,35 +325,43 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
/// <param name="wtmcontext"></param>
|
||||
/// <param name="IdFields">关联表外键</param>
|
||||
/// <returns>修改后的查询语句</returns>
|
||||
public static IQueryable<T> DPWhere<T>(this IQueryable<T> baseQuery, WTMContext wtmcontext, params Expression<Func<T, object>>[] IdFields) where T : TopBasePoco
|
||||
{
|
||||
var dps = wtmcontext?.LoginUserInfo?.DataPrivileges;
|
||||
//循环所有关联外键
|
||||
List<string> tableNameList = new List<string>();
|
||||
foreach (var IdField in IdFields)
|
||||
{
|
||||
//public static IQueryable<T> DPWhere<T>(this IQueryable<T> baseQuery, WTMContext wtmcontext, params Expression<Func<T, object>>[] IdFields) where T : TopBasePoco
|
||||
//{
|
||||
// var dps = wtmcontext?.LoginUserInfo?.DataPrivileges;
|
||||
// //循环所有关联外键
|
||||
// List<string> tableNameList = new List<string>();
|
||||
// foreach (var IdField in IdFields)
|
||||
// {
|
||||
|
||||
//将外键 Id 用.分割,循环生成指向最终id的表达式,比如x=> x.a.b.Id
|
||||
var fieldName = IdField.GetPropertyName(false);
|
||||
//获取关联的类
|
||||
string typename = "";
|
||||
//如果外键名称不是‘id’,则根据model层的命名规则,它应该是xxxId,所以抹掉最后的 Id 应该是关联的类名
|
||||
if (fieldName.ToLower() != "id")
|
||||
{
|
||||
fieldName = fieldName.Remove(fieldName.Length - 2);
|
||||
typename = IdField.GetPropertyInfo().DeclaringType.GetSingleProperty(fieldName).PropertyType.Name;
|
||||
}
|
||||
//如果是 Id,则本身就是关联的类
|
||||
else
|
||||
{
|
||||
typename = typeof(T).Name;
|
||||
}
|
||||
tableNameList.Add(typename);
|
||||
// //将外键 Id 用.分割,循环生成指向最终id的表达式,比如x=> x.a.b.Id
|
||||
// var fieldName = IdField.GetPropertyName(false);
|
||||
// //获取关联的类
|
||||
// string typename = "";
|
||||
// //如果外键名称不是‘id’,则根据model层的命名规则,它应该是xxxId,所以抹掉最后的 Id 应该是关联的类名
|
||||
// if (fieldName.ToLower() != "id")
|
||||
// {
|
||||
// fieldName = fieldName.Remove(fieldName.Length - 2);
|
||||
// var dtype = IdField.GetPropertyInfo().DeclaringType;
|
||||
// if (dtype == typeof(TreePoco) && fieldName == "Parent")
|
||||
// {
|
||||
// typename = typeof(T).Name;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// typename = dtype.GetSingleProperty(fieldName).PropertyType.Name;
|
||||
// }
|
||||
// }
|
||||
// //如果是 Id,则本身就是关联的类
|
||||
// else
|
||||
// {
|
||||
// typename = typeof(T).Name;
|
||||
// }
|
||||
// tableNameList.Add(typename);
|
||||
|
||||
}
|
||||
//var test = DPWhere(baseQuery, dps, tableNameList, IdFields);
|
||||
return DPWhere(baseQuery, wtmcontext, tableNameList, IdFields);
|
||||
}
|
||||
// }
|
||||
// //var test = DPWhere(baseQuery, dps, tableNameList, IdFields);
|
||||
// return DPWhere(baseQuery, wtmcontext, tableNameList, IdFields);
|
||||
//}
|
||||
|
||||
#region AddBy YOUKAI 20160310
|
||||
/// <summary>
|
||||
@ -352,10 +370,9 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
/// <typeparam name="T">源数据类</typeparam>
|
||||
/// <param name="baseQuery">源Query</param>
|
||||
/// <param name="wtmcontext">wtm context</param>
|
||||
/// <param name="tableName">关联数据权限的表名,如果关联外键为自身,则参数第一个为自身</param>
|
||||
/// <param name="IdFields">关联表外键</param>
|
||||
/// <returns>修改后的查询语句</returns>
|
||||
public static IQueryable<T> DPWhere<T>(this IQueryable<T> baseQuery, WTMContext wtmcontext, List<string> tableName, params Expression<Func<T, object>>[] IdFields) where T : TopBasePoco
|
||||
public static IQueryable<T> DPWhere<T>(this IQueryable<T> baseQuery, WTMContext wtmcontext, params Expression<Func<T, object>>[] IdFields) where T : TopBasePoco
|
||||
{
|
||||
var dps = wtmcontext?.LoginUserInfo?.DataPrivileges;
|
||||
|
||||
@ -370,79 +387,99 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
//循环所有关联外键
|
||||
foreach (var IdField in IdFields)
|
||||
{
|
||||
bool mtm = false;
|
||||
Expression exp = trueExp;
|
||||
//将外键Id用.分割,循环生成指向最终id的表达式,比如x=> x.a.b.Id
|
||||
var fullname = IdField.GetPropertyName();
|
||||
string[] splits = fullname.Split('.');
|
||||
int leftindex = splits[0].IndexOf('[');
|
||||
if (leftindex > 0)
|
||||
{
|
||||
mtm = true;
|
||||
splits[0] = splits[0].Substring(0, leftindex);
|
||||
}
|
||||
Expression peid = Expression.MakeMemberAccess(pe, pe.Type.GetSingleProperty(splits[0]));
|
||||
Type middletype = null;
|
||||
if (mtm)
|
||||
{
|
||||
middletype = peid.Type.GetGenericArguments()[0];
|
||||
|
||||
}
|
||||
else
|
||||
List<(Expression exp, ParameterExpression pe, bool islist)> data = new System.Collections.Generic.List<(Expression, ParameterExpression, bool)>();
|
||||
Expression iexp = pe;
|
||||
ParameterExpression ipe = pe;
|
||||
|
||||
//格式化idfeild,保存在data中
|
||||
for (int i=0;i<splits.Length;i++)
|
||||
{
|
||||
for (int i = 1; i < splits.Length; i++)
|
||||
var item = splits[i];
|
||||
var proname = item;
|
||||
int lindex = proname.IndexOf('[');
|
||||
bool islist = false;
|
||||
if (lindex > 0)
|
||||
{
|
||||
peid = Expression.MakeMemberAccess(peid, peid.Type.GetSingleProperty(splits[i]));
|
||||
islist = true;
|
||||
proname = proname.Substring(0, lindex);
|
||||
}
|
||||
iexp = Expression.MakeMemberAccess(iexp, iexp.Type.GetSingleProperty(proname));
|
||||
|
||||
Type petype = null;
|
||||
if (islist == true)
|
||||
{
|
||||
petype = iexp.Type.GetGenericArguments()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
petype = iexp.Type;
|
||||
}
|
||||
if (petype == typeof(TreePoco))
|
||||
{
|
||||
petype = typeof(T);
|
||||
}
|
||||
if(islist == true || i == splits.Length-1)
|
||||
{
|
||||
data.Add((iexp, ipe, islist));
|
||||
ipe = Expression.Parameter(petype);
|
||||
iexp = ipe;
|
||||
}
|
||||
middletype = (peid as MemberExpression).Member.DeclaringType;
|
||||
}
|
||||
|
||||
//确定最终关联的表名
|
||||
string tableName = "";
|
||||
if(data.Count > 0)
|
||||
{
|
||||
var last = data.Last().exp as MemberExpression;
|
||||
string fieldname = last?.Member?.Name;
|
||||
if (string.IsNullOrEmpty(fieldname) == false)
|
||||
{
|
||||
if (fieldname.ToLower() == "id")
|
||||
{
|
||||
tableName = last.Member.ReflectedType.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pro2 = wtmcontext.DC.GetPropertyNameByFk(last.Member.ReflectedType, fieldname);
|
||||
if (string.IsNullOrEmpty(pro2) == false)
|
||||
{
|
||||
tableName = last.Member.ReflectedType.GetSingleProperty(pro2).PropertyType.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//如果dps为空,则拼接一个返回假的表达式,这样就查询不出任何数据
|
||||
if (dps == null)
|
||||
if (dps == null || tableName == "")
|
||||
{
|
||||
exp = falseExp;
|
||||
}
|
||||
else
|
||||
{
|
||||
var fieldName = IdField.GetPropertyName(false);
|
||||
//如果外键名称不是‘id’,则根据model层的命名规则,它应该是xxxId,所以抹掉最后的 Id 应该是关联的类名
|
||||
if (fieldName.ToLower() != "id")
|
||||
{
|
||||
fieldName = fieldName.Remove(fieldName.Length - 2);
|
||||
var typeinfo = middletype.GetSingleProperty(fieldName);
|
||||
//var IsTableName = tableName?.Where(x => x == fieldName).FirstOrDefault();
|
||||
var IsTableName = tableName?.Where(x => x.ToLower() == typeinfo.PropertyType.Name.ToLower()).FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(IsTableName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
fieldName = IsTableName;
|
||||
//typename = PropertyHelper.GetPropertyInfo(IdField).DeclaringType.GetProperty(fieldName).PropertyType.Name;
|
||||
}
|
||||
//如果是Id,则本身就是关联的类
|
||||
else
|
||||
{
|
||||
fieldName = tableName[tindex];
|
||||
}
|
||||
var dpsSetting = wtmcontext.DataPrivilegeSettings;
|
||||
|
||||
//循环系统设定的数据权限,如果没有和关联类一样的表,则跳过
|
||||
if (dpsSetting.Where(x => x.ModelName == fieldName).SingleOrDefault() == null)
|
||||
if (dpsSetting.Where(x => x.ModelName == tableName).FirstOrDefault() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//获取dps中关联到关联类的id列表
|
||||
var ids = dps.Where(x => x.TableName == fieldName).Select(x => x.RelateId).ToList();
|
||||
var ids = dps.Where(x => x.TableName == tableName).Select(x => x.RelateId).ToList();
|
||||
//如果没有关联的id,则拼接一个返回假的where,是语句查询不到任何数据
|
||||
if (ids == null || ids.Count() == 0)
|
||||
if (ids == null || ids.Count == 0)
|
||||
{
|
||||
exp = falseExp;
|
||||
//if (peid.Type == typeof(Guid))
|
||||
//bool isBasePoco = typeof(IBasePoco).IsAssignableFrom(data.Last().pe.Type);
|
||||
//if (isBasePoco)
|
||||
//{
|
||||
// exp = Expression.Equal(peid, Expression.Constant(Guid.NewGuid()));
|
||||
// exp = Expression.Equal(Expression.Property(data.Last().pe, "CreateBy"), Expression.Constant(wtmcontext.LoginUserInfo?.ITCode));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// exp = Expression.Equal(peid, Expression.Constant(null));
|
||||
exp = falseExp;
|
||||
//}
|
||||
}
|
||||
//如果有关联 Id
|
||||
@ -452,30 +489,30 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
//如果关联 Id 包括null,则代表可以访问所有数据,就不需要再拼接where条件了
|
||||
if (!ids.Contains(null))
|
||||
{
|
||||
if (mtm == true)
|
||||
for(int i=data.Count-1; i>=0; i--)
|
||||
{
|
||||
ParameterExpression midpe = Expression.Parameter(middletype);
|
||||
Expression middleid = Expression.PropertyOrField(midpe, IdField.GetPropertyName(false));
|
||||
var d = data[i];
|
||||
if(d.islist == true)
|
||||
{
|
||||
var lastd = data[i + 1];
|
||||
var queryable = Expression.Call(
|
||||
typeof(Queryable),
|
||||
"AsQueryable",
|
||||
new Type[] { lastd.pe.Type },
|
||||
d.exp);
|
||||
|
||||
var queryable = Expression.Call(
|
||||
typeof(Queryable),
|
||||
"AsQueryable",
|
||||
new Type[] { middletype },
|
||||
peid);
|
||||
exp = Expression.Call(
|
||||
typeof(Queryable),
|
||||
"Any",
|
||||
new Type[] { lastd.pe.Type },
|
||||
queryable,
|
||||
Expression.Lambda(typeof(Func<,>).MakeGenericType(lastd.pe.Type, typeof(bool)), exp, new ParameterExpression[] { lastd.pe }));
|
||||
|
||||
List<Guid> ddd = new List<Guid>();
|
||||
|
||||
exp = Expression.Call(
|
||||
typeof(Queryable),
|
||||
"Any",
|
||||
new Type[] { middletype },
|
||||
queryable,
|
||||
Expression.Lambda(typeof(Func<,>).MakeGenericType(middletype, typeof(bool)), ids.GetContainIdExpression(middletype, midpe, middleid).Body, new ParameterExpression[] { midpe }));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
exp = ids.GetContainIdExpression(typeof(T), pe, peid).Body;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp = ids.GetContainIdExpression(d.pe.Type, d.pe, d.exp).Body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,10 +355,28 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
/// <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>
|
||||
/// <param name="func">无参有返回委托,返回一个字典</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()
|
||||
public static string GetJson<T>(this IBasePagedListVM<T, BaseSearcher> self, bool PlainText = true, bool enumToString = true, Func<Dictionary<string, object>> func = null) 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}}";
|
||||
if (!self.IsSearched) self.DoSearch();
|
||||
|
||||
StringBuilder builder = new("{", capacity: 1024);
|
||||
var dic = func?.Invoke();
|
||||
|
||||
// 如果用户的附加字典不为空,则添加用户自定义的信息
|
||||
if (dic != null) foreach (var item in dic) builder.Append($"\"{item.Key}\":\"{item.Value}\",");
|
||||
|
||||
// 设置wtm必要的数据
|
||||
builder
|
||||
.Append($"\"Code\":200,")
|
||||
.Append($"\"Count\":{self.Searcher.Count},")
|
||||
.Append($"\"Data\":{self.GetDataJson(PlainText, enumToString)},")
|
||||
.Append($"\"Msg\":\"success\",")
|
||||
.Append($"\"Page\":{self.Searcher.Page},")
|
||||
.Append($"\"PageCount\":{self.Searcher.PageCount}")
|
||||
.Append('}');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static object GetJsonForApi<T>(this IBasePagedListVM<T, BaseSearcher> self, bool PlainText = true) where T : TopBasePoco, new()
|
||||
|
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace WalkingTec.Mvvm.Core.Extensions
|
||||
{
|
||||
public static class RequestExtension
|
||||
{
|
||||
public static async Task<ApiResult<string>> RedirectCall(this HttpRequest request, WTMContext wtm, string domainname)
|
||||
{
|
||||
HttpMethodEnum method = Enum.Parse<HttpMethodEnum>(request.Method.ToString());
|
||||
ApiResult<string> rv = null;
|
||||
if (method == HttpMethodEnum.GET)
|
||||
{
|
||||
rv = await wtm.CallAPI("mainhost", request.Path.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(request.HasFormContentType == true)
|
||||
{
|
||||
Dictionary<string, string> data = new Dictionary<string, string>();
|
||||
foreach (var item in request.Form)
|
||||
{
|
||||
data.Add(item.Key, item.Value);
|
||||
}
|
||||
rv = await wtm.CallAPI<string>("mainhost", request.Path.ToString(), method, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpContent data = new StreamContent(request.Body);
|
||||
rv = await wtm.CallAPI<string>("mainhost", request.Path.ToString(), method, data);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
@ -106,7 +106,7 @@ namespace WalkingTec.Mvvm.Core.Extensions
|
||||
var s = "";
|
||||
if (Format == null)
|
||||
{
|
||||
s = item.ToString();
|
||||
s = item?.ToString()??"";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using WalkingTec.Mvvm.Core.Extensions;
|
||||
using WalkingTec.Mvvm.Core.Support.FileHandlers;
|
||||
using WalkingTec.Mvvm.Core.Support.Quartz;
|
||||
|
||||
namespace WalkingTec.Mvvm.Core
|
||||
{
|
||||
@ -53,6 +54,7 @@ namespace WalkingTec.Mvvm.Core
|
||||
dc.Database.EnsureCreated();
|
||||
}
|
||||
WtmFileProvider.Init(WtmConfigs, gd);
|
||||
services.TryAddSingleton<QuartzHostService>();
|
||||
return services;
|
||||
}
|
||||
|
||||
|
@ -127,10 +127,15 @@ namespace WalkingTec.Mvvm.Core
|
||||
{
|
||||
me = le.Body as MemberExpression;
|
||||
}
|
||||
if (le.Body is UnaryExpression)
|
||||
else if (le.Body is UnaryExpression)
|
||||
{
|
||||
me = (le.Body as UnaryExpression).Operand as MemberExpression;
|
||||
}
|
||||
else if(le.Body is MethodCallExpression mexp && mexp.Method.Name == "get_Item")
|
||||
{
|
||||
object index = 0;
|
||||
me = mexp.Object as MemberExpression;
|
||||
}
|
||||
}
|
||||
string rv = "";
|
||||
if (me != null)
|
||||
|
@ -12,7 +12,9 @@ namespace WalkingTec.Mvvm.Core
|
||||
[Display(Name = "_Admin.Exception")]
|
||||
Exception,
|
||||
[Display(Name = "_Admin.Debug")]
|
||||
Debug
|
||||
Debug,
|
||||
[Display(Name = "_Admin.Job")]
|
||||
Job
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
@ -15,7 +15,7 @@ namespace WalkingTec.Mvvm.Core
|
||||
/// FrameworkUser
|
||||
/// </summary>
|
||||
[Table("FrameworkUsers")]
|
||||
public class FrameworkUserBase : BasePoco
|
||||
public abstract class FrameworkUserBase : BasePoco
|
||||
{
|
||||
[Display(Name = "_Admin.Account")]
|
||||
[Required(ErrorMessage = "Validate.{0}required")]
|
||||
|
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WalkingTec.Mvvm.Core.Support.Quartz
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class QuartzJobAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public QuartzJobAttribute(string name)
|
||||
{
|
||||
this.Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class QuartzGroupAttribute : Attribute
|
||||
{
|
||||
public string Group { get; set; }
|
||||
public QuartzGroupAttribute(string group)
|
||||
{
|
||||
this.Group = group;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class QuartzRepeatAttribute : Attribute
|
||||
{
|
||||
public int Repeat { get; set; }
|
||||
public bool IsForever { get; set; }
|
||||
public int IntervalInSeconds { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="interval">间隔时间,单位秒</param>
|
||||
/// <param name="repeat">重复的次数</param>
|
||||
/// <param name="isForever">是否一直重复</param>
|
||||
public QuartzRepeatAttribute(int interval,int repeat, bool isForever)
|
||||
{
|
||||
this.Repeat = repeat;
|
||||
this.IsForever = isForever;
|
||||
this.IntervalInSeconds = interval;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class QuartzStartAtAttribute : Attribute
|
||||
{
|
||||
public string Cron { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cron">表示复杂格式的日期,详见https://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/crontrigger.html#introduction</param>
|
||||
public QuartzStartAtAttribute(string cron)
|
||||
{
|
||||
this.Cron = cron;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Quartz;
|
||||
using Quartz.Impl;
|
||||
|
||||
namespace WalkingTec.Mvvm.Core.Support.Quartz
|
||||
{
|
||||
public class QuartzHostService : IHostedService
|
||||
{
|
||||
private readonly IServiceProvider _sp;
|
||||
private readonly GlobalData _gd;
|
||||
private IScheduler _scheduler;
|
||||
public QuartzHostService(IServiceProvider sp,GlobalData gd)
|
||||
{
|
||||
_sp = sp;
|
||||
_gd = gd;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
ISchedulerFactory factory = new StdSchedulerFactory();
|
||||
_scheduler = await factory.GetScheduler();
|
||||
foreach (var ass in _gd.AllAssembly)
|
||||
{
|
||||
try
|
||||
{
|
||||
var t = ass.GetExportedTypes().Where(x => typeof(WtmJob).IsAssignableFrom(x) && x.Name != "WtmJob").ToList();
|
||||
int count = 1;
|
||||
foreach (var st in t)
|
||||
{
|
||||
var ci = st.GetConstructor(Type.EmptyTypes);
|
||||
var job = ci?.Invoke(null) as WtmJob;
|
||||
if (job != null)
|
||||
{
|
||||
// job.Sp = _sp;
|
||||
var attrs = st.GetCustomAttributes(true);
|
||||
string jobName = st.Name;
|
||||
string groupName = "group"+count;
|
||||
var nameAttr = attrs.Where(x => x is QuartzJobAttribute).FirstOrDefault() as QuartzJobAttribute;
|
||||
var groupAttr = attrs.Where(x => x is QuartzGroupAttribute).FirstOrDefault() as QuartzGroupAttribute;
|
||||
var repeatAttr = attrs.Where(x => x is QuartzRepeatAttribute).FirstOrDefault() as QuartzRepeatAttribute;
|
||||
var startAttr = attrs.Where(x => x is QuartzStartAtAttribute).FirstOrDefault() as QuartzStartAtAttribute;
|
||||
if (nameAttr != null)
|
||||
{
|
||||
jobName = nameAttr.Name;
|
||||
}
|
||||
if(groupAttr != null)
|
||||
{
|
||||
groupName = groupAttr.Group;
|
||||
}
|
||||
JobDataMap jobDataMap = new JobDataMap();
|
||||
jobDataMap.Add("Sp", _sp);
|
||||
// 创建作业
|
||||
IJobDetail j = JobBuilder.Create(st)
|
||||
.WithIdentity(jobName, groupName)
|
||||
.UsingJobData(jobDataMap)
|
||||
.Build();
|
||||
// 创建触发器,每60s执行一次
|
||||
var builder = TriggerBuilder.Create()
|
||||
.WithIdentity("trigger" + count, "group1");
|
||||
if (startAttr != null)
|
||||
{
|
||||
builder = builder.WithCronSchedule(startAttr.Cron);
|
||||
}
|
||||
else {
|
||||
builder = builder.StartNow();
|
||||
if(repeatAttr != null)
|
||||
{
|
||||
if(repeatAttr.IsForever == true)
|
||||
{
|
||||
builder = builder.WithSimpleSchedule(x => x.WithIntervalInSeconds(repeatAttr.IntervalInSeconds).RepeatForever());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder = builder.WithSimpleSchedule(x => x.WithRepeatCount(repeatAttr.Repeat).WithIntervalInSeconds(repeatAttr.IntervalInSeconds));
|
||||
}
|
||||
}
|
||||
}
|
||||
var trigger = builder.Build();
|
||||
await _scheduler.ScheduleJob(j, trigger);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
// 开始运行
|
||||
await Task.Delay(5000);
|
||||
await _scheduler.Start(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _scheduler.Shutdown(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Quartz;
|
||||
|
||||
namespace WalkingTec.Mvvm.Core.Support.Quartz
|
||||
{
|
||||
public class WtmJob : IJob,IDisposable
|
||||
{
|
||||
private IServiceScope _ss;
|
||||
private WTMContext _wtm;
|
||||
protected WTMContext Wtm
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_wtm == null)
|
||||
{
|
||||
_ss = Sp.CreateScope();
|
||||
_wtm = _ss.ServiceProvider.GetRequiredService<WTMContext>();
|
||||
}
|
||||
return _wtm;
|
||||
}
|
||||
}
|
||||
|
||||
public IServiceProvider Sp { get; set; }
|
||||
|
||||
public virtual async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
await Task.Run(() => { });
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_ss.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Quartz;
|
||||
using Quartz.Spi;
|
||||
|
||||
namespace WalkingTec.Mvvm.Core.Support.Quartz
|
||||
{
|
||||
public class WtmJobFactory : IJobFactory
|
||||
{
|
||||
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
|
||||
{
|
||||
var rv = Activator.CreateInstance(bundle.JobDetail.GetType()) as IJob;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public void ReturnJob(IJob job)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ namespace WalkingTec.Mvvm.Core
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
if(logConfig == null)
|
||||
if(logConfig == null || categoryName == "VueCliMiddleware")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -231,21 +231,21 @@ namespace WalkingTec.Mvvm.Core
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var code = await BaseUserQuery.Where(x => x.ITCode.ToLower() == itcode.ToLower()).Select(x =>new { itcode = x.ITCode, id= x.GetID(), photoid=x.PhotoId, name=x.Name }).SingleOrDefaultAsync();
|
||||
if (code == null)
|
||||
var password = await BaseUserQuery.Where(x => x.ITCode.ToLower() == itcode.ToLower()).Select(x =>x.Password).SingleOrDefaultAsync();
|
||||
if (this.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||||
{
|
||||
return null;
|
||||
var user = await CallAPI<LoginUserInfo>("", GetServerUrl() + "/api/_account/loginjwt", HttpMethodEnum.POST, new { Account = itcode, Password = password, IsReload=true });
|
||||
return user?.Data;
|
||||
}
|
||||
LoginUserInfo rv = new LoginUserInfo
|
||||
else
|
||||
{
|
||||
ITCode = code.itcode,
|
||||
UserId = code.id?.ToString(),
|
||||
Name = code.name,
|
||||
PhotoId = code.photoid
|
||||
};
|
||||
await rv.LoadBasicInfoAsync(this);
|
||||
return rv;
|
||||
Dictionary<string, string> data = new Dictionary<string, string>();
|
||||
data.Add("account", itcode);
|
||||
data.Add("password", password);
|
||||
data.Add("withmenu", "false");
|
||||
var user = await CallAPI<LoginUserInfo>("", this.HttpContext.Request.Scheme + "://" + this.HttpContext.Request.Host.ToString() + "/api/_account/login", HttpMethodEnum.POST, data);
|
||||
return user?.Data;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -459,7 +459,7 @@ namespace WalkingTec.Mvvm.Core
|
||||
return isPublic;
|
||||
}
|
||||
|
||||
public void DoLog(string msg, ActionLogTypesEnum logtype = ActionLogTypesEnum.Normal)
|
||||
public void DoLog(string msg, ActionLogTypesEnum logtype = ActionLogTypesEnum.Normal,string moduleName="", string actionName="", string ip="",string url = "", double duration = 0)
|
||||
{
|
||||
var log = this.Log?.GetActionLog();
|
||||
if (log == null)
|
||||
@ -469,6 +469,15 @@ namespace WalkingTec.Mvvm.Core
|
||||
log.LogType = logtype;
|
||||
log.ActionTime = DateTime.Now;
|
||||
log.Remark = msg;
|
||||
log.ActionUrl = url;
|
||||
log.Duration = duration;
|
||||
log.ModuleName = moduleName;
|
||||
log.ActionName = actionName;
|
||||
log.IP = ip;
|
||||
if(string.IsNullOrEmpty(url) && this.HttpContext?.Request != null)
|
||||
{
|
||||
log.ActionUrl = this.HttpContext.Request.Path.ToString();
|
||||
}
|
||||
LogLevel ll = LogLevel.Information;
|
||||
switch (logtype)
|
||||
{
|
||||
@ -960,6 +969,24 @@ namespace WalkingTec.Mvvm.Core
|
||||
return await CallAPI<string>(domainName, url, method, postdata, timeout, proxy);
|
||||
}
|
||||
|
||||
|
||||
private string GetServerUrl()
|
||||
{
|
||||
var server = ConfigInfo.Domains.Where(x => x.Key.ToLower() == "serverpub").Select(x => x.Value).FirstOrDefault();
|
||||
if (server == null)
|
||||
{
|
||||
server = ConfigInfo.Domains.Where(x => x.Key.ToLower() == "server").Select(x => x.Value).FirstOrDefault();
|
||||
}
|
||||
if (server != null && string.IsNullOrEmpty(server.Address) == false)
|
||||
{
|
||||
return server.Address.TrimEnd('/');
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.HttpContext.Request.Scheme + "://" + this.HttpContext.Request.Host.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
@ -7,21 +7,20 @@
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
|
||||
<PackageReference Include="DotNetCore.NPOI" Version="1.2.3" />
|
||||
<PackageReference Include="Fare" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.DataAnnotations.Validation" Version="3.2.0-rc1.20223.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.1">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.1">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
@ -29,16 +28,17 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.2" />
|
||||
<PackageReference Include="Oracle.EntityFrameworkCore" Version="6.21.5" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.1" />
|
||||
<PackageReference Include="Oracle.EntityFrameworkCore" Version="6.21.4" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.0" />
|
||||
<PackageReference Include="Quartz" Version="3.4.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.3" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -121,11 +121,6 @@ namespace WalkingTec.Mvvm.Mvc.Auth
|
||||
TenantCode = pair[1],
|
||||
};
|
||||
|
||||
// 清理过期 refreshtoken
|
||||
var sql = $"DELETE FROM {DC.GetTableName<PersistedGrant>()} WHERE Expiration<'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}'";
|
||||
_dc.RunSQL(sql);
|
||||
_logger.LogDebug("清理过期的refreshToken:【sql:{0}】", sql);
|
||||
|
||||
// 颁发 token
|
||||
return await IssueTokenAsync(loginUserInfo);
|
||||
}
|
||||
|
@ -2160,7 +2160,14 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
string newname = item.FieldName;
|
||||
if (mpro.PropertyType.IsBoolOrNullableBool())
|
||||
{
|
||||
render = "ComponentType=\"@typeof(Switch)\"";
|
||||
if (mpro.PropertyType.IsNullable())
|
||||
{
|
||||
render = "ComponentType=\"@typeof(NullSwitch)\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
render = "ComponentType=\"@typeof(Switch)\"";
|
||||
}
|
||||
}
|
||||
if (mpro.PropertyType == typeof(DateTime) || mpro.PropertyType == typeof(DateTime?))
|
||||
{
|
||||
@ -2417,7 +2424,14 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
}
|
||||
if (checktype == typeof(bool))
|
||||
{
|
||||
controltype = "Switch";
|
||||
if (proType.IsNullable())
|
||||
{
|
||||
controltype = "NullSwitch";
|
||||
}
|
||||
else
|
||||
{
|
||||
controltype = "Switch";
|
||||
}
|
||||
}
|
||||
else if (checktype.IsEnum())
|
||||
{
|
||||
@ -2543,7 +2557,14 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
}
|
||||
if (checktype == typeof(bool))
|
||||
{
|
||||
controltype = "Switch";
|
||||
if (proType.IsNullable())
|
||||
{
|
||||
controltype = "NullSwitch";
|
||||
}
|
||||
else
|
||||
{
|
||||
controltype = "Switch";
|
||||
}
|
||||
disabled = "IsDisabled=\"true\"";
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ namespace WalkingTec.Mvvm.Mvc.Filters
|
||||
var postDes = ctrlActDesc.MethodInfo.GetCustomAttributes(typeof(HttpPostAttribute), false).Cast<HttpPostAttribute>().FirstOrDefault();
|
||||
var validpostonly = ctrlActDesc.MethodInfo.GetCustomAttributes(typeof(ValidateFormItemOnlyAttribute), false).Cast<ValidateFormItemOnlyAttribute>().FirstOrDefault();
|
||||
|
||||
log.ITCode = ctrl.Wtm.LoginUserInfo?.ITCode ?? string.Empty;
|
||||
//给日志的多语言属性赋值
|
||||
log.ModuleName = ctrlDes?.GetDescription(ctrl) ?? ctrlActDesc.ControllerName;
|
||||
log.ActionName = actDes?.GetDescription(ctrl) ?? ctrlActDesc.ActionName + (postDes == null ? string.Empty : "[P]");
|
||||
|
@ -44,11 +44,11 @@ $columns$
|
||||
<div style="padding-right:10px;">
|
||||
@if (IsAccessable("/api/$modelname$/Edit"))
|
||||
{
|
||||
<TableCellButton Size="Size.ExtraSmall" Color="Color.Success" Icon="fa fa-edit" Text="@WtmBlazor.Localizer["Sys.Edit"]" OnClickCallback="() => OnEditClick(context)" />
|
||||
<TableCellButton Size="Size.ExtraSmall" Color="Color.Success" Icon="fa fa-edit" Text="@WtmBlazor.Localizer["Sys.Edit"]" OnClick="() => OnEditClick(context)" />
|
||||
}
|
||||
@if (IsAccessable("/api/$modelname$/{id}"))
|
||||
{
|
||||
<TableCellButton Size="Size.ExtraSmall" Color="Color.Info" Icon="fa fa-info" Text="@WtmBlazor.Localizer["Sys.Details"]" OnClickCallback="()=>OnDetailsClick(context)" />
|
||||
<TableCellButton Size="Size.ExtraSmall" Color="Color.Info" Icon="fa fa-info" Text="@WtmBlazor.Localizer["Sys.Details"]" OnClick="()=>OnDetailsClick(context)" />
|
||||
}
|
||||
@if (IsAccessable("/api/$modelname$/BatchDelete"))
|
||||
{
|
||||
|
@ -45,6 +45,7 @@ using WalkingTec.Mvvm.Mvc.Helper;
|
||||
using WalkingTec.Mvvm.TagHelpers.LayUI;
|
||||
using Microsoft.AspNetCore.SpaServices.Extensions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using WalkingTec.Mvvm.Core.Support.Quartz;
|
||||
|
||||
namespace WalkingTec.Mvvm.Mvc
|
||||
{
|
||||
@ -71,7 +72,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
private static GlobalData GetGlobalData()
|
||||
{
|
||||
var gd = new GlobalData();
|
||||
|
||||
gd.AllAssembly = Utils.GetAllAssembly();
|
||||
return gd;
|
||||
}
|
||||
|
||||
@ -502,6 +503,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
y.ValueLengthLimit = int.MaxValue - 20480;
|
||||
y.MultipartBodyLengthLimit = conf.FileUploadOptions.UploadLimit;
|
||||
});
|
||||
services.AddHostedService<QuartzHostService>();
|
||||
return services;
|
||||
}
|
||||
public static IServiceCollection AddWtmCrossDomain(this IServiceCollection services, IConfiguration config)
|
||||
@ -553,7 +555,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
public static IServiceCollection AddWtmAuthentication(this IServiceCollection services, IConfiguration config)
|
||||
{
|
||||
var conf = config.Get<Configs>();
|
||||
services.AddSingleton<ITokenService, TokenService>();
|
||||
services.AddScoped<ITokenService, TokenService>();
|
||||
|
||||
var jwtOptions = conf.JwtOptions;
|
||||
|
||||
@ -698,7 +700,6 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
var localfactory = app.ApplicationServices.GetRequiredService<IStringLocalizerFactory>();
|
||||
var lop = app.ApplicationServices.GetService<WtmLocalizationOption>();
|
||||
//获取所有程序集
|
||||
gd.AllAssembly = Utils.GetAllAssembly();
|
||||
//var mvc = GetRuntimeAssembly("WalkingTec.Mvvm.Mvc");
|
||||
//if (mvc != null && gd.AllAssembly.Contains(mvc) == false)
|
||||
//{
|
||||
|
@ -43,7 +43,8 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
_iconFontItems = iconFontHashSet.Select(x => new ComboSelectListItem
|
||||
{
|
||||
Text = x,
|
||||
Value = x
|
||||
Value = x,
|
||||
Icon = x
|
||||
}).ToList();
|
||||
|
||||
_iconFontDicItems = new Dictionary<string, List<MenuItem>>();
|
||||
|
25
WalkingTec.Mvvm/WalkingTec.Mvvm.Mvc/Helper/JwtRefreshJob.cs
Normal file
25
WalkingTec.Mvvm/WalkingTec.Mvvm.Mvc/Helper/JwtRefreshJob.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Quartz;
|
||||
using WalkingTec.Mvvm.Core;
|
||||
using WalkingTec.Mvvm.Core.Extensions;
|
||||
using WalkingTec.Mvvm.Core.Support.Quartz;
|
||||
|
||||
namespace WalkingTec.Mvvm.Mvc.Helper
|
||||
{
|
||||
[QuartzRepeat(3600,0,true)]
|
||||
public class JwtRefreshJob : WtmJob
|
||||
{
|
||||
public override Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sql = $"DELETE FROM {this.Wtm.DC.GetTableName<PersistedGrant>()} WHERE Expiration<'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}'";
|
||||
this.Wtm.DC.RunSQL(sql);
|
||||
Wtm.DoLog("清理过期的refreshToken", ActionLogTypesEnum.Job);
|
||||
}
|
||||
catch { }
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Options;
|
||||
using WalkingTec.Mvvm.Core;
|
||||
using WalkingTec.Mvvm.Core.Extensions;
|
||||
|
||||
namespace WalkingTec.Mvvm.Mvc
|
||||
{
|
||||
@ -20,17 +21,17 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, IOptionsMonitor<Configs> configs)
|
||||
public async Task InvokeAsync(HttpContext context, WTMContext wtm)
|
||||
{
|
||||
var max = context.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
if (max.IsReadOnly == false)
|
||||
{
|
||||
max.MaxRequestBodySize = configs.CurrentValue.FileUploadOptions.UploadLimit;
|
||||
max.MaxRequestBodySize = wtm.ConfigInfo.FileUploadOptions.UploadLimit;
|
||||
}
|
||||
if (context.Request.Path == "/")
|
||||
{
|
||||
context.Response.Cookies.Append("pagemode", configs.CurrentValue.PageMode.ToString());
|
||||
context.Response.Cookies.Append("tabmode", configs.CurrentValue.TabMode.ToString());
|
||||
context.Response.Cookies.Append("pagemode", wtm.ConfigInfo.PageMode.ToString());
|
||||
context.Response.Cookies.Append("tabmode", wtm.ConfigInfo.TabMode.ToString());
|
||||
}
|
||||
if (context.Request.ContentLength > 0 && context.Request.ContentLength < 512000)
|
||||
{
|
||||
@ -48,6 +49,17 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
context.Items["DONOTUSE_REQUESTBODY"] = body;
|
||||
}
|
||||
}
|
||||
//if(wtm.ConfigInfo.Domains != null)
|
||||
//{
|
||||
// var mainHost = wtm.ConfigInfo.Domains.Where(x=>x.Key== "mainhost").Select(x=>x.Value.Address).FirstOrDefault();
|
||||
// if(string.IsNullOrEmpty(mainHost) == false)
|
||||
// {
|
||||
// if(context.Request.RouteValues["controller"]?.ToString()?.ToLower() == "login")
|
||||
// {
|
||||
// var test = await context.Request.RedirectCall(wtm, "mainhost");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
await _next(context);
|
||||
if (context.Response.StatusCode == 404)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ Layout = null;
|
||||
<script src="/jquery.min.js"></script>
|
||||
<script src="/jquery.cookie.js"></script>
|
||||
<script src="/layui/layui.js"></script>
|
||||
<script src="/layui/xm-select.js"></script>
|
||||
<script src="/_js/framework_layui.js?time=@DateTime.Now.Ticks"></script>
|
||||
<script>
|
||||
var DONOTUSE_IGNOREHASH = false;
|
||||
|
@ -18,6 +18,7 @@
|
||||
<script src="/jquery.min.js"></script>
|
||||
<script src="/jquery.cookie.js"></script>
|
||||
<script src="/layui/layui.js"></script>
|
||||
<script src="/layui/xm-select.js"></script>
|
||||
<script src="/_js/framework_layui.js?time=@DateTime.Now.Ticks"></script>
|
||||
<script>
|
||||
var DONOTUSE_IGNOREHASH = false;
|
||||
|
@ -15,6 +15,7 @@ Layout = null;
|
||||
<script src="/jquery.min.js"></script>
|
||||
<script src="/jquery.cookie.js"></script>
|
||||
<script src="/layui/layui.js"></script>
|
||||
<script src="/layui/xm-select.js"></script>
|
||||
<script src="/_js/framework_layui.js?time=@DateTime.Now.Ticks"></script>
|
||||
<script>
|
||||
var DONOTUSE_IGNOREHASH = false;
|
||||
|
@ -10,7 +10,6 @@
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="GeneratorFiles\Spa\Vue\**\*.txt" />
|
||||
<EmbeddedResource Include="Views\**\*.cshtml" />
|
||||
@ -59,12 +58,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta13" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
||||
<PackageReference Include="VueCliMiddleware" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -35,6 +35,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
{
|
||||
|
||||
[HttpPost]
|
||||
[Public]
|
||||
public IActionResult Selector(string _DONOT_USE_VMNAME
|
||||
, string _DONOT_USE_KFIELD
|
||||
, string _DONOT_USE_VFIELD
|
||||
@ -298,7 +299,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
{
|
||||
var FileData = Request.Form.Files[0];
|
||||
var file = fp.Upload(FileData.FileName, FileData.Length, FileData.OpenReadStream(), groupName, subdir, extra, sm, Wtm.CreateDC(cskey: _DONOT_USE_CS));
|
||||
return JsonMore(new { Id = file.GetID(), Name = file.FileName});
|
||||
return JsonMore(new { Id = file.GetID(), Name = file.FileName });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@ -329,7 +330,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
oimage.SaveAsJpeg(ms);
|
||||
ms.Position = 0;
|
||||
|
||||
var file = fp.Upload(FileData.FileName, ms.Length, ms, groupName,subdir,extra,sm, Wtm.CreateDC(cskey: _DONOT_USE_CS));
|
||||
var file = fp.Upload(FileData.FileName, ms.Length, ms, groupName, subdir, extra, sm, Wtm.CreateDC(cskey: _DONOT_USE_CS));
|
||||
oimage.Dispose();
|
||||
ms.Dispose();
|
||||
return JsonMore(new { Id = file.GetID(), Name = file.FileName });
|
||||
@ -413,7 +414,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
rv.Position = 0;
|
||||
if (stream == false)
|
||||
{
|
||||
return File(rv, contenttype, file.FileName ?? (Guid.NewGuid().ToString() + ext));
|
||||
return File(rv, contenttype, file.FileName ?? (Guid.NewGuid().ToString() + ext));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -423,7 +424,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
}
|
||||
else
|
||||
{
|
||||
Response.Headers.TryAdd("Content-Disposition",$"inline; filename=\"{HttpUtility.UrlEncode( file.FileName)}\"");
|
||||
Response.Headers.TryAdd("Content-Disposition", $"inline; filename=\"{HttpUtility.UrlEncode(file.FileName)}\"");
|
||||
await rv.CopyToAsync(Response.Body);
|
||||
rv.Dispose();
|
||||
return new EmptyResult();
|
||||
@ -455,6 +456,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
|
||||
}
|
||||
|
||||
[Public]
|
||||
public IActionResult OutSide(string url)
|
||||
{
|
||||
url = HttpUtility.UrlDecode(url);
|
||||
@ -470,12 +472,12 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
var pmenu = GlobaInfo.AllMenus.Where(x => x.ID == menu.ParentId).FirstOrDefault();
|
||||
if (pmenu != null)
|
||||
{
|
||||
pmenu.PageName = Core.CoreProgram._localizer?[pmenu.PageName];
|
||||
pmenu.PageName = Core.CoreProgram._localizer?[pmenu.PageName];
|
||||
|
||||
pagetitle = pmenu.PageName + " - ";
|
||||
}
|
||||
}
|
||||
menu.PageName = Core.CoreProgram._localizer?[menu.PageName];
|
||||
menu.PageName = Core.CoreProgram._localizer?[menu.PageName];
|
||||
|
||||
pagetitle += menu.PageName;
|
||||
}
|
||||
@ -570,7 +572,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
foreach (var menu in menus)
|
||||
{
|
||||
LocalizeMenu(menu.Children);
|
||||
menu.Title = Core.CoreProgram._localizer?[menu.Title];
|
||||
menu.Title = Core.CoreProgram._localizer?[menu.Title];
|
||||
}
|
||||
}
|
||||
|
||||
@ -720,7 +722,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
{
|
||||
int codeW = 80;
|
||||
int codeH = 30;
|
||||
int fontSize = 20;
|
||||
int fontSize = 16;
|
||||
string chkCode = string.Empty;
|
||||
Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.DarkBlue, Color.PaleGreen };
|
||||
string[] font = { "Times New Roman" };
|
||||
@ -751,8 +753,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
//画验证码
|
||||
for (int i = 0; i < chkCode.Length; i++)
|
||||
{
|
||||
string fnt = font[rnd.Next(font.Length)];
|
||||
Font ft = new Font(SystemFonts.Find(fnt), fontSize);
|
||||
Font ft = new Font(SystemFonts.Families.First(), fontSize);
|
||||
Color clr = color[rnd.Next(color.Length)];
|
||||
bmp.Mutate(x => x.DrawText(chkCode[i].ToString(),ft,clr,new PointF((float)i * 18, (float)0)));
|
||||
}
|
||||
@ -854,7 +855,7 @@ namespace WalkingTec.Mvvm.Mvc
|
||||
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
|
||||
);
|
||||
|
||||
return Content($"<script>window.location.href='{HttpUtility.UrlDecode(redirect)}';</script>","text/html");
|
||||
return Content($"<script>window.location.href='{HttpUtility.UrlDecode(redirect)}';</script>", "text/html");
|
||||
}
|
||||
|
||||
|
||||
|
@ -251,68 +251,10 @@ window.ff = {
|
||||
},
|
||||
|
||||
RenderForm: function (formId) {
|
||||
var comboxs = $(".layui-form[lay-filter=" + formId + "] select[wtm-combo='MULTI_COMBO']");
|
||||
if (comboxs.length === 0) {
|
||||
var comboxs = $(".layui-form[lay-filter=" + formId + "] div[wtm-ctype='combo']");
|
||||
layui.use(['form'], function () {
|
||||
var form = layui.form.render(null, formId);
|
||||
});
|
||||
}
|
||||
else {
|
||||
layui.use(['form', 'formSelects'], function () {
|
||||
var formSelects = layui.formSelects;
|
||||
layui.form.render(null, formId);
|
||||
/* 启用 ComboBox 多选 */
|
||||
for (var i = 0; i < comboxs.length; i++) {
|
||||
var filter = comboxs[i].attributes['lay-filter'].value;
|
||||
var vs = comboxs[i].attributes['wtm-combovalue'].value;
|
||||
var vn = comboxs[i].attributes['wtm-comboname'].value;
|
||||
var arr = [];
|
||||
if (vs !== null && vs != "") {
|
||||
var values = vs.split("`");
|
||||
var names = vn.split("`");
|
||||
for (var a = 0; a < values.length; a++) {
|
||||
arr.push({ name: names[a], val: values[a] });
|
||||
}
|
||||
}
|
||||
var changefunc = "1==1";
|
||||
var chainchange = "";
|
||||
var linkto = false;
|
||||
var url = "";
|
||||
var targetname = "";
|
||||
var changefuncattr = comboxs[i].attributes['wtm-cf'];
|
||||
var linktoattr = comboxs[i].attributes['wtm-linkto'];
|
||||
var urlattr = comboxs[i].attributes['wtm-turl'];
|
||||
if (changefuncattr != undefined) {
|
||||
changefunc = changefuncattr.value + "(a)";
|
||||
}
|
||||
if (urlattr != undefined) {
|
||||
url = urlattr.value;
|
||||
}
|
||||
if (linktoattr != undefined) {
|
||||
linkto = true;
|
||||
}
|
||||
formSelects.on({
|
||||
layFilter: filter, left: '', right: '', separator: ',', arr: arr,
|
||||
url: url, self: comboxs[i], linkto: linkto, cf: changefunc,
|
||||
selectFunc: function (a) {
|
||||
try {
|
||||
if (eval(this.cf) && this.linkto == true) {
|
||||
var u = this.url;
|
||||
if (u.indexOf("?") == -1) {
|
||||
u += "?t=" + new Date().getTime();
|
||||
}
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
u += "&id=" + a[i].val;
|
||||
}
|
||||
ff.ChainChange(u, this.self)
|
||||
}
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
PostForm: function (url, formId, divid, searchervm) {
|
||||
@ -467,6 +409,11 @@ window.ff = {
|
||||
, btn: []
|
||||
, id: windowid //设定一个id,防止重复弹出
|
||||
, content: str
|
||||
//, success: function (layero, index) {
|
||||
// if (height == undefined || height == null || height == '' || max == false){
|
||||
// document.getElementById('layui-layer' + index).getElementsByClassName('layui-layer-content')[0].style.overflow = 'unset';
|
||||
// }
|
||||
//}
|
||||
, resizing: function (layero) {
|
||||
ff.triggerResize();
|
||||
$(layero).find("div[ischart = '1']").each(
|
||||
@ -668,6 +615,8 @@ window.ff = {
|
||||
var targetname = target.attr("wtm-name");
|
||||
var ismulticombo = target.attr("wtm-combo") != undefined;
|
||||
var targetid = target.attr("id");
|
||||
var comboid = targetid;
|
||||
|
||||
if (controltype == undefined) {
|
||||
controltype = "";
|
||||
}
|
||||
@ -678,8 +627,7 @@ window.ff = {
|
||||
//clear
|
||||
switch (controltype) {
|
||||
case "combo":
|
||||
target.html('<option value = "" selected>' + ff.DONOTUSE_Text_PleaseSelect + '</option>');
|
||||
form.render('select', targetfilter);
|
||||
window[comboid].update({ data: [] });
|
||||
break;
|
||||
case "checkbox":
|
||||
target.html('');
|
||||
@ -690,9 +638,7 @@ window.ff = {
|
||||
form.render('radio', targetfilter);
|
||||
break;
|
||||
case "tree":
|
||||
layui.tree.reload(targetid, {
|
||||
data: []
|
||||
});
|
||||
window[comboid].update({ data: [] });
|
||||
break;
|
||||
case "transfer":
|
||||
layui.transfer.reload(targetid, {
|
||||
@ -707,9 +653,7 @@ window.ff = {
|
||||
var item = null;
|
||||
|
||||
if (controltype === "tree") {
|
||||
layui.tree.reload(targetid, {
|
||||
data: ff.getTreeItems(data.Data)
|
||||
});
|
||||
window[comboid].update({ data: ff.getTreeItems(data.Data) });
|
||||
}
|
||||
if (controltype === "transfer") {
|
||||
layui.transfer.reload(targetid, {
|
||||
@ -718,26 +662,7 @@ window.ff = {
|
||||
}
|
||||
|
||||
if (controltype === "combo") {
|
||||
target.html('<option value = "" selected>' + ff.DONOTUSE_Text_PleaseSelect + '</option>');
|
||||
var arr = [];
|
||||
if (data.Data !== undefined && data.Data !== null) {
|
||||
for (i = 0; i < data.Data.length; i++) {
|
||||
item = data.Data[i];
|
||||
var icon = item.Icon !== undefined && item.Icon != null && item.Icon.length > 0 ? ' icon="' + item.Icon + '"' : '';
|
||||
if (item.Selected === true) {
|
||||
target.append('<option value = "' + item.Value + '"' + icon + ' selected>' + item.Text + '</option>');
|
||||
}
|
||||
else {
|
||||
target.append('<option value = "' + item.Value + '" ' + icon + '>' + item.Text + '</option>');
|
||||
}
|
||||
arr.push({ name: item.Text, val: item.Value });
|
||||
}
|
||||
}
|
||||
form.render('select', targetfilter);
|
||||
if (ismulticombo) {
|
||||
var mm = layui.formSelects.selects[target.attr("lay-filter")];
|
||||
ff.refreshcombobox(mm, []);
|
||||
}
|
||||
window[comboid].update({ data: ff.getComboItems(data.Data) });
|
||||
}
|
||||
if (controltype === "checkbox") {
|
||||
for (i = 0; i < data.Data.length; i++) {
|
||||
@ -787,9 +712,7 @@ window.ff = {
|
||||
var item = null;
|
||||
if (controltype === "tree") {
|
||||
var da = ff.getTreeItems(data.Data, svals);
|
||||
layui.tree.reload(controlid, {
|
||||
data: da
|
||||
});
|
||||
window[controlid].update({ data: da });
|
||||
if (cb !== undefined && cb != null) {
|
||||
cb();
|
||||
}
|
||||
@ -800,29 +723,8 @@ window.ff = {
|
||||
});
|
||||
}
|
||||
if (controltype === "combo") {
|
||||
|
||||
target.html('<option value = "" selected>' + ff.DONOTUSE_Text_PleaseSelect + '</option>');
|
||||
var arr = [];
|
||||
if (data.Data !== undefined && data.Data !== null) {
|
||||
for (i = 0; i < data.Data.length; i++) {
|
||||
item = data.Data[i];
|
||||
var icon = item.Icon !== undefined && item.Icon != null && item.Icon.length > 0 ? ' icon="' + item.Icon + '"' : '';
|
||||
if (item.Selected === true || svals.indexOf(item.Value) > -1) {
|
||||
target.append('<option value = "' + item.Value + '"' + icon + ' selected>' + item.Text + '</option>');
|
||||
arr.push({ name: item.Text, val: item.Value });
|
||||
}
|
||||
else {
|
||||
target.append('<option value = "' + item.Value + '" ' + icon + '>' + item.Text + '</option>');
|
||||
}
|
||||
}
|
||||
}
|
||||
layui.form.render('select', targetfilter+"div");
|
||||
if (ismulticombo) {
|
||||
layui.use(['form', 'formSelects'], function () {
|
||||
var mm = layui.formSelects.selects[targetfilter];
|
||||
ff.refreshcombobox(mm, arr);
|
||||
});
|
||||
}
|
||||
var da = ff.getComboItems(data.Data, svals);
|
||||
window[controlid].update({ data: da });
|
||||
}
|
||||
if (controltype === "checkbox") {
|
||||
for (i = 0; i < data.Data.length; i++) {
|
||||
@ -892,6 +794,19 @@ window.ff = {
|
||||
}
|
||||
}
|
||||
|
||||
var xselect = searchForm.find("div[wtm-ctype='tree'],div[wtm-ctype='combo']");
|
||||
layui.each(xselect, function (_, item) {
|
||||
var val = window[item.id].getValue('value');
|
||||
if (val.length > 1) {
|
||||
fieldElem = fieldElem.filter(function (index) {
|
||||
return this.name != item.attributes["wtm-name"].value;
|
||||
})
|
||||
$.each(val, function (i, v) {
|
||||
fieldElem.push({ name: item.attributes["wtm-name"].value, value: v });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var check = {};
|
||||
layui.each(fieldElem, function (_, item) {
|
||||
if (!item.name) return;
|
||||
@ -905,9 +820,6 @@ window.ff = {
|
||||
return;
|
||||
}
|
||||
var itemname = item.name;
|
||||
if (/_WTMMultiCombo_(.*?)_(.*?)$/.test(itemname)) {
|
||||
itemname = RegExp.$2;
|
||||
}
|
||||
if (/_DONOTUSE_(.*?)\[(\d?)\]\.(.*?)$/.test(itemname)) {
|
||||
var name1 = RegExp.$1;
|
||||
var number = RegExp.$2;
|
||||
@ -919,7 +831,7 @@ window.ff = {
|
||||
}
|
||||
if (/_DONOTUSE_(.*?)$/.test(itemname)) {
|
||||
var name1 = RegExp.$1;
|
||||
if (filterback.hasOwnProperty(name1) == false && filter.hasOwnProperty(name1) == false) {
|
||||
if (filterback.hasOwnProperty(name1) == false && filter.hasOwnProperty(name1) == false) {
|
||||
filterback[name1] = 1;
|
||||
}
|
||||
return;
|
||||
@ -957,7 +869,7 @@ window.ff = {
|
||||
}
|
||||
else {
|
||||
filter[itemname] = item.value;
|
||||
if (filterback.hasOwnProperty(itemname) == true) {
|
||||
if (filterback.hasOwnProperty(itemname) == true && item.value != "") {
|
||||
filterback[itemname] = undefined;
|
||||
}
|
||||
}
|
||||
@ -966,6 +878,7 @@ window.ff = {
|
||||
|
||||
for (item in filterback) {
|
||||
if (filterback[item] !== undefined) {
|
||||
filter[item] = undefined;
|
||||
filter[item + ".length"] = "0";
|
||||
}
|
||||
}
|
||||
@ -1248,21 +1161,34 @@ window.ff = {
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var item = {};
|
||||
item.id = data[i].Value;
|
||||
item.title = data[i].Text;
|
||||
item.href = data[i].Url;
|
||||
item.spread = data[i].Expended;
|
||||
item.checked = data[i].Selected || svals.indexOf(data[i].Value) > -1;
|
||||
item.value = data[i].Value;
|
||||
item.name = data[i].Text;
|
||||
item.disabled = data[i].Disabled;
|
||||
item.selected = data[i].Selected || svals.indexOf(data[i].Value) > -1;
|
||||
item.icon = data[i].Icon;
|
||||
|
||||
if (data[i].Children != null && data[i].Children.length > 0) {
|
||||
item.children = this.getTreeItems(data[i].Children, svals);
|
||||
}
|
||||
rv.push(item);
|
||||
}
|
||||
return rv;
|
||||
},
|
||||
|
||||
for (var j = 0; j < item.children.length; j++) {
|
||||
if (item.children[j].checked == true || item.children[j].spread == true) {
|
||||
item.spread = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
getComboItems: function (data, svals) {
|
||||
var rv = [];
|
||||
if (svals == undefined || svals == null) {
|
||||
svals = [];
|
||||
}
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var item = {};
|
||||
item.value = data[i].Value;
|
||||
item.name = data[i].Text;
|
||||
item.disabled = data[i].Disabled;
|
||||
item.selected = data[i].Selected || svals.indexOf(data[i].Value) > -1;
|
||||
item.icon = data[i].Icon;
|
||||
if (data[i].Children != null && data[i].Children.length > 0) {
|
||||
item.children = this.getTreeItems(data[i].Children, svals);
|
||||
}
|
||||
rv.push(item);
|
||||
}
|
||||
@ -1280,7 +1206,7 @@ window.ff = {
|
||||
item.value = data[i].Value;
|
||||
item.title = data[i].Text;
|
||||
item.disabled = data[i].Disabled;
|
||||
item.checked = data[i].Selected || svals.indexOf(data[i].Value) > -1;
|
||||
//item.checked = data[i].Selected || svals.indexOf(data[i].Value) > -1;
|
||||
rv.push(item);
|
||||
}
|
||||
return rv;
|
||||
|
@ -44,6 +44,7 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
|
||||
public string ConfirmTxt { get; set; }
|
||||
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Id))
|
||||
@ -93,7 +94,15 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Content.SetHtmlContent(Text ?? string.Empty);
|
||||
if (string.IsNullOrEmpty(Icon) == false)
|
||||
{
|
||||
output.Attributes.SetAttribute("class", "shortcut");
|
||||
output.Content.SetHtmlContent($"<div><i class=\"{Icon}\"></i></div>{Text ?? ""}");
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Content.SetHtmlContent(Text ?? string.Empty);
|
||||
}
|
||||
}
|
||||
string submitButtonUrl = "";
|
||||
if (this is SubmitButtonTagHelper sbt)
|
||||
|
@ -95,38 +95,38 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (item.LinkField != null || item.LinkId != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(item.TriggerUrl))
|
||||
{
|
||||
output.PostElement.AppendHtml($@"
|
||||
<script>
|
||||
layui.use(['form'],function(){{
|
||||
var form = layui.form;
|
||||
form.on('select({output.Attributes["lay-filter"].Value})', function(data){{
|
||||
{FormatFuncName(item.ChangeFunc)};
|
||||
ff.ChainChange('{item.TriggerUrl}/'+data.value,data.elem)
|
||||
ff.changeComboIcon(data);
|
||||
}});
|
||||
}})
|
||||
</script>
|
||||
");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output.PostElement.AppendHtml($@"
|
||||
<script>
|
||||
layui.use(['form'],function(){{
|
||||
var form = layui.form;
|
||||
form.on('select({output.Attributes["lay-filter"].Value})', function(data){{
|
||||
{FormatFuncName(item.ChangeFunc)};
|
||||
ff.changeComboIcon(data);
|
||||
}});
|
||||
}})
|
||||
</script>
|
||||
");
|
||||
}
|
||||
// if (item.LinkField != null || item.LinkId != null)
|
||||
// {
|
||||
// if (!string.IsNullOrEmpty(item.TriggerUrl))
|
||||
// {
|
||||
// output.PostElement.AppendHtml($@"
|
||||
//<script>
|
||||
//layui.use(['form'],function(){{
|
||||
// var form = layui.form;
|
||||
// form.on('select({output.Attributes["lay-filter"].Value})', function(data){{
|
||||
// {FormatFuncName(item.ChangeFunc)};
|
||||
// ff.ChainChange('{item.TriggerUrl}/'+data.value,data.elem)
|
||||
// ff.changeComboIcon(data);
|
||||
// }});
|
||||
//}})
|
||||
//</script>
|
||||
//");
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// output.PostElement.AppendHtml($@"
|
||||
//<script>
|
||||
//layui.use(['form'],function(){{
|
||||
// var form = layui.form;
|
||||
// form.on('select({output.Attributes["lay-filter"].Value})', function(data){{
|
||||
// {FormatFuncName(item.ChangeFunc)};
|
||||
// ff.changeComboIcon(data);
|
||||
// }});
|
||||
//}})
|
||||
//</script>
|
||||
//");
|
||||
// }
|
||||
break;
|
||||
case CheckBoxTagHelper item:
|
||||
if (string.IsNullOrEmpty(item.ChangeFunc) == false)
|
||||
|
@ -96,20 +96,29 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
if (!(this is DisplayTagHelper) && ((Field.Metadata.IsRequired && Field.Name.Contains("[-1]")==false) || Required == true))
|
||||
{
|
||||
requiredDot = "<font color='red'>*</font>";
|
||||
if (!(this is UploadTagHelper || this is RadioTagHelper || this is CheckBoxTagHelper || this is MultiUploadTagHelper || this is ColorPickerTagHelper || this is TreeTagHelper || this is SliderTagHelper)) // 上传组件自定义验证
|
||||
if (!(this is UploadTagHelper || this is RadioTagHelper || this is CheckBoxTagHelper || this is MultiUploadTagHelper || this is ColorPickerTagHelper || this is SliderTagHelper || this is TransferTagHelper)) // 上传组件自定义验证
|
||||
{
|
||||
//richtextbox不需要进行必填验证
|
||||
if (output.Attributes["isrich"] == null)
|
||||
{
|
||||
if (this is ComboBoxTagHelper combo && combo.MultiSelect.Value == true)
|
||||
//combobox和tree用xmselect控件的验证
|
||||
if (this is ComboBoxTagHelper combo || this is TreeTagHelper)
|
||||
{
|
||||
output.Attributes.Add("lay-verify", "selectRequired");
|
||||
var script = $@"
|
||||
<script>
|
||||
window['{this.Id}'].update({{
|
||||
layVerify:'required',
|
||||
layReqText:'{THProgram._localizer["Validate.{0}required", Field?.Metadata?.DisplayName ?? Field?.Metadata?.Name]}'
|
||||
}});
|
||||
</script>
|
||||
";
|
||||
output.PostElement.AppendHtml(script);
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Attributes.Add("lay-verify", "required");
|
||||
output.Attributes.Add("lay-reqText", $"{THProgram._localizer["Validate.{0}required", Field?.Metadata?.DisplayName ?? Field?.Metadata?.Name]}");
|
||||
}
|
||||
output.Attributes.Add("lay-reqText", $"{THProgram._localizer["Validate.{0}required", Field?.Metadata?.DisplayName ?? Field?.Metadata?.Name]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,7 +155,7 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
|
||||
preHtml += $@"
|
||||
<div {(this is DisplayTagHelper ? "style=\"margin-bottom:0px;\"" : "")} class=""layui-form-item layui-form"" lay-filter=""{layfilter}div"">
|
||||
<label for=""{Id}"" class=""layui-form-label"" {(LabelWidth == null ? string.Empty : "style='width:" + LabelWidth + "px'")}>{lb}</label>
|
||||
<label for=""{Id}"" class=""layui-form-label"" {(LabelWidth == null ? "style='min-height:21px;'" : "style='min-height:21px;width:" + LabelWidth + "px'")}>{lb}</label>
|
||||
<div class=""{ (string.IsNullOrEmpty(PaddingText) ? "layui-input-block" : "layui-input-inline")}"" {(LabelWidth == null || string.IsNullOrEmpty(PaddingText)==false ? "" : "style='margin-left:" + (LabelWidth + 30) + "px'")}>
|
||||
";
|
||||
}
|
||||
|
@ -165,7 +165,38 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI.Common
|
||||
|
||||
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 MakeDialogButton(buttonType, $"/_Framework/ViewFile/{fileID}?_DONOT_USE_CS={_DONOT_USE_CS}&width={width}", buttonText, width, height, title, null, true, resizable, maxed,buttonClass, style);
|
||||
var buttonID = Guid.NewGuid().ToString();
|
||||
var innerClick = "";
|
||||
string windowid = Guid.NewGuid().ToString();
|
||||
var url = $"/_Framework/GetFile/{fileID}?_DONOT_USE_CS={_DONOT_USE_CS}";
|
||||
innerClick = $"layui.layer.photos({{photos: {{data: [{{src: '{url}'}}]}},anim: 5}});";
|
||||
string funcname = $"x{buttonID.Replace("-", "")}click";
|
||||
var click = $"<script>function {funcname}(){{{innerClick};return false;}}</script>";
|
||||
string rv = "";
|
||||
if (buttonType == ButtonTypesEnum.Link)
|
||||
{
|
||||
rv = $"<a id='{buttonID}' onclick='{funcname}()' style='{style ?? "color:blue;cursor:pointer"}' class='{buttonClass ?? ""}'>{buttonText}</a>";
|
||||
}
|
||||
if (buttonType == ButtonTypesEnum.Button)
|
||||
{
|
||||
rv = $"<a id='{buttonID}' onclick='{funcname}()' style='{style ?? ""}' class='layui-btn {(string.IsNullOrEmpty(buttonClass) ? "layui-btn-primary layui-btn-xs" : $"{buttonClass}")}'>{buttonText}</a>";
|
||||
}
|
||||
switch (buttonType)
|
||||
{
|
||||
case ButtonTypesEnum.Button:
|
||||
rv = $"<a id='{buttonID}' onclick='{funcname}()' style='{style ?? ""}' class='layui-btn {(string.IsNullOrEmpty(buttonClass) ? "layui-btn-primary layui-btn-xs" : $"{buttonClass}")}'>{buttonText}</a>";
|
||||
break;
|
||||
case ButtonTypesEnum.Link:
|
||||
rv = $"<a id='{buttonID}' onclick='{funcname}()' style='{style ?? "color:blue;cursor:pointer"}' class='{buttonClass ?? ""}'>{buttonText}</a>";
|
||||
break;
|
||||
case ButtonTypesEnum.Img:
|
||||
rv = $"<img src='{url}&width={width??50}&height={height??50}' id='{buttonID}' onclick='{funcname}()' style='{style ?? "color:blue;cursor:pointer"}' class='{buttonClass ?? ""}'/>";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rv += click;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public string MakeScriptButton(ButtonTypesEnum buttonType, string buttonText, string script = "", string buttonID = null, string url = null, string buttonClass = null, string style=null)
|
||||
|
@ -610,6 +610,7 @@ layui.use(['table'], function(){{
|
||||
if(res.Code != undefined && res.Code != 200){{ layui.layer.alert(res.Msg,{{title:'{THProgram._localizer["Sys.Error"]}'}});}}
|
||||
var tab = $('#{Id} + .layui-table-view');tab.find('table').css('border-collapse','separate');
|
||||
{(Height == null ? $"tab.css('overflow','hidden').addClass('donotuse_fill donotuse_pdiv');tab.children('.layui-table-box').addClass('donotuse_fill donotuse_pdiv').css('height','100px');tab.find('.layui-table-main').addClass('donotuse_fill');tab.find('.layui-table-header').css('min-height','{maxDepth*38}px');ff.triggerResize();" : string.Empty)}
|
||||
{(LineHeight.HasValue == true ? $"tab.find('td .layui-table-cell').css('height','{LineHeight}px')" : string.Empty)}
|
||||
{(MultiLine == true ? $"tab.find('.layui-table-cell').css('height','auto').css('white-space','normal');" : string.Empty)}
|
||||
tab.find('div [lay-event=\'LAYTABLE_COLS\']').attr('title','{THProgram._localizer["Sys.ColumnFilter"]}');
|
||||
tab.find('div [lay-event=\'LAYTABLE_PRINT\']').attr('title','{THProgram._localizer["Sys.Print"]}');
|
||||
|
@ -28,7 +28,7 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
/// 启用搜索
|
||||
/// 注意:多选与搜索不能同时启用
|
||||
/// </summary>
|
||||
public bool EnableSearch { get; set; }
|
||||
public bool? EnableSearch { get; set; }
|
||||
|
||||
public ModelExpression Items { get; set; }
|
||||
|
||||
@ -40,9 +40,9 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
/// <summary>
|
||||
/// 是否多选
|
||||
/// 默认根据Field 绑定的值类型进行判断。Array or List 即多选,否则单选
|
||||
/// 注意:多选与搜索不能同时启用
|
||||
/// </summary>
|
||||
public bool? MultiSelect { get; set; }
|
||||
public bool AutoRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 改变选择时触发的js函数,func(data)格式;
|
||||
@ -65,16 +65,19 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
{
|
||||
EmptyText = THProgram._localizer["Sys.PleaseSelect"];
|
||||
}
|
||||
EnableSearch = configs.CurrentValue.UIOptions.ComboBox.DefaultEnableSearch;
|
||||
if (EnableSearch == null)
|
||||
{
|
||||
EnableSearch = configs.CurrentValue.UIOptions.ComboBox.DefaultEnableSearch;
|
||||
}
|
||||
_wtm = wtm;
|
||||
}
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.TagName = "select";
|
||||
output.TagName = "div";
|
||||
output.Attributes.Add("id", Id);
|
||||
output.TagMode = TagMode.StartTagAndEndTag;
|
||||
output.Attributes.Add("name", Field.Name);
|
||||
output.Attributes.Add("lay-filter", $"_WTMMultiCombo_{Guid.NewGuid()}_" + Field.Name);
|
||||
output.Attributes.Add("wtm-name", Field.Name);
|
||||
output.Attributes.Add("wtm-ctype", "combo");
|
||||
if (Disabled == true)
|
||||
@ -92,14 +95,6 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
MultiSelect = true;
|
||||
}
|
||||
}
|
||||
if (MultiSelect.Value)
|
||||
{
|
||||
output.Attributes.Add("wtm-combo", "MULTI_COMBO");
|
||||
}
|
||||
if (!MultiSelect.Value && EnableSearch)
|
||||
{
|
||||
output.Attributes.Add("lay-search", string.Empty);
|
||||
}
|
||||
if (string.IsNullOrEmpty(ChangeFunc) == false)
|
||||
{
|
||||
output.Attributes.Add("wtm-cf", FormatFuncName(ChangeFunc, false));
|
||||
@ -122,12 +117,8 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
output.Attributes.Add("wtm-turl", TriggerUrl);
|
||||
}
|
||||
var contentBuilder = new StringBuilder();
|
||||
if (string.IsNullOrEmpty(EmptyText) == false)
|
||||
{
|
||||
contentBuilder.Append($"<option value=''>{EmptyText}</option>");
|
||||
}
|
||||
|
||||
output.PostElement.AppendHtml($@"<input type=""hidden"" name=""_DONOTUSE_{Field.Name}"" value=""1"" />");
|
||||
output.PreElement.AppendHtml($@"<input type=""hidden"" name=""_DONOTUSE_{Field.Name}"" value=""1"" />");
|
||||
|
||||
|
||||
#region 添加下拉数据 并 设置默认选中
|
||||
@ -239,44 +230,109 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MultiSelect == true)
|
||||
{
|
||||
foreach (var item in listItems)
|
||||
{
|
||||
contentBuilder.Append($"<option value='{item.Value}'{(string.IsNullOrEmpty(item.Icon) ? string.Empty : $" icon='{item.Icon}'")}>{item.Text}</option>");
|
||||
}
|
||||
|
||||
// 添加默认选中项
|
||||
var selected = listItems.Where(x => x.Selected).ToList();
|
||||
var mulvalues = selected.ToSepratedString(x => x.Value, seperator: "`");
|
||||
var mulnamess = selected.ToSepratedString(x => x.Text, seperator: "`");
|
||||
output.Attributes.Add("wtm-combovalue", $"{mulvalues}");
|
||||
output.Attributes.Add("wtm-comboname", $"{mulnamess}");
|
||||
}
|
||||
else // 添加用户设置的设置源
|
||||
{
|
||||
foreach (var item in listItems)
|
||||
{
|
||||
if (item.Selected == true)
|
||||
{
|
||||
if (Disabled == true)
|
||||
{
|
||||
output.PostElement.AppendHtml($"<input name='{Field.Name}' value='{item.Value}' text='{item.Text}' type='hidden' />");
|
||||
}
|
||||
contentBuilder.Append($"<option value='{item.Value}'{(string.IsNullOrEmpty(item.Icon) ? string.Empty : $" icon='{item.Icon}'")} selected>{item.Text}</option>");
|
||||
}
|
||||
else
|
||||
{
|
||||
contentBuilder.Append($"<option value='{item.Value}'{(string.IsNullOrEmpty(item.Icon) ? string.Empty : $" icon='{item.Icon}'")} {(item.Disabled == true ? "disabled=\"\"" : string.Empty)}>{item.Text}</option>");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
output.Content.SetHtmlContent(contentBuilder.ToString());
|
||||
var script = $@"
|
||||
<script>
|
||||
var {Id} = xmSelect.render({{
|
||||
el: '#{Id}',
|
||||
name:'{Field.Name}',
|
||||
tips:'{EmptyText}',
|
||||
disabled: {Disabled.ToString().ToLower()},
|
||||
{(THProgram._localizer["Sys.LayuiDateLan"] =="CN"? "language:'zn'," : "language:'en',")}
|
||||
autoRow: {AutoRow.ToString().ToLower()},
|
||||
filterable: {EnableSearch.ToString().ToLower()},
|
||||
template({{ item, sels, name, value }}){{
|
||||
if(item.icon !== undefined && item.icon != """"&& item.icon != null){{
|
||||
return '<i class=""'+item.icon+'""></i>' + item.name;
|
||||
}}
|
||||
else{{
|
||||
return item.name;
|
||||
}}
|
||||
}},
|
||||
{(MultiSelect == false ? $@"
|
||||
radio: true,
|
||||
clickClose: true,
|
||||
model: {{
|
||||
label: {{
|
||||
type: 'abc' ,
|
||||
abc: {{
|
||||
template: function(item, sels){{
|
||||
if(sels[0].icon !== undefined && sels[0].icon != """" && sels[0].icon != null){{
|
||||
return '<i class=""'+sels[0].icon+'""></i>' + sels[0].name;
|
||||
}}
|
||||
else{{
|
||||
return sels[0].name;
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}},
|
||||
toolbar: {{
|
||||
show: true,
|
||||
list: ['CLEAR']}}," : $@"
|
||||
toolbar: {{show: true,list: ['ALL', 'REVERSE', 'CLEAR']}},
|
||||
model: {{
|
||||
label: {{
|
||||
block: {{
|
||||
template: function(item, sels){{
|
||||
if(item.icon !== undefined && item.icon != """"&& item.icon != null){{
|
||||
return '<i class=""'+item.icon+'""></i>' + item.name;
|
||||
}}
|
||||
else{{
|
||||
return item.name;
|
||||
}}
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
}},
|
||||
")}
|
||||
height: '400px',
|
||||
on:function(data){{
|
||||
debugger;
|
||||
{((LinkField != null || string.IsNullOrEmpty(LinkId) == false)?@$"
|
||||
if (eval(""{(string.IsNullOrEmpty(ChangeFunc)?"1==1":FormatFuncName(ChangeFunc))}"") != false) {{
|
||||
var u = ""{(TriggerUrl??"")}"";
|
||||
if (u.indexOf(""?"") == -1) {{
|
||||
u += ""?t="" + new Date().getTime();
|
||||
}}
|
||||
for (var i = 0; i < data.arr.length; i++) {{
|
||||
u += ""&id="" + data.arr[i].value;
|
||||
}}
|
||||
ff.ChainChange(u, $('#{Id}')[0])
|
||||
}}" : FormatFuncName(ChangeFunc))}
|
||||
}},
|
||||
data: {JsonSerializer.Serialize(GetLayuiTree(listItems,selectVal))}
|
||||
}})
|
||||
</script>
|
||||
";
|
||||
output.PostElement.AppendHtml(script);
|
||||
#endregion
|
||||
|
||||
|
||||
base.Process(context, output);
|
||||
}
|
||||
|
||||
private List<LayuiTreeItem> GetLayuiTree(IEnumerable<ComboSelectListItem> tree, List<string> values)
|
||||
{
|
||||
List<LayuiTreeItem> rv = new List<LayuiTreeItem>();
|
||||
foreach (var s in tree)
|
||||
{
|
||||
var news = new LayuiTreeItem
|
||||
{
|
||||
Id = s.Value.ToString(),
|
||||
Title = s.Text,
|
||||
Disabled = s.Disabled,
|
||||
Checked = s.Selected,
|
||||
Icon = s.Icon
|
||||
};
|
||||
if (values.Contains(s.Value.ToString().ToLower()))
|
||||
{
|
||||
news.Checked = true;
|
||||
}
|
||||
rv.Add(news);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using WalkingTec.Mvvm.Core;
|
||||
@ -200,8 +201,8 @@ $('#{search.SearchBtnId}').on('click', function () {{
|
||||
{
|
||||
firstkey = key;
|
||||
}
|
||||
output.PostElement.AppendHtml($@"
|
||||
$(""#{Id}"").find(""button[type=submit]:first"").parent().prepend(""<div class='layui-input-block' style='text-align:left'><label style='color:red'>{error.ErrorMessage}</label></div>"");
|
||||
output.PostElement.AppendHtml($@"
|
||||
$(""#{Id}"").find(""button[type=submit]:first"").parent().prepend(""<div class='layui-input-block' style='text-align:left'><label style='color:red'>{Regex.Replace(error.ErrorMessage,"<script>","", RegexOptions.IgnoreCase)}</label></div>"");
|
||||
");
|
||||
}
|
||||
if (haserror == true)
|
||||
|
@ -44,7 +44,14 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
List<string> values = new List<string>();
|
||||
if (modeltype.IsBoolOrNullableBool())
|
||||
{
|
||||
values.Add(Field.Model.ToString());
|
||||
if (Field.Model == null)
|
||||
{
|
||||
values.Add("False");
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add(Field.Model.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -147,9 +147,15 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
}
|
||||
if(selectVal.Count > 0)
|
||||
{
|
||||
DefaultValue = null;
|
||||
DefaultValue = $"[{string.Join(",", selectVal.Select(x => "'" + x + "'"))}]";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(string.IsNullOrEmpty(DefaultValue) == false)
|
||||
{
|
||||
DefaultValue = $"[{string.Join(",", DefaultValue.Split(",").Select(x => "'" + x + "'"))}]";
|
||||
}
|
||||
}
|
||||
|
||||
var title = $"['{(string.IsNullOrEmpty(LeftTitle) ? THProgram._localizer["Sys.ForSelect"] : LeftTitle)}','{(string.IsNullOrEmpty(RightTitle) ? THProgram._localizer["Sys.Selected"] : RightTitle)}']";
|
||||
var content = $@"
|
||||
<script>
|
||||
|
@ -5,7 +5,7 @@ using WalkingTec.Mvvm.Core.Extensions;
|
||||
|
||||
namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
{
|
||||
[HtmlTargetElement("wt:image", Attributes = REQUIRED_ATTR_NAME, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("wt:image", TagStructure = TagStructure.WithoutEndTag)]
|
||||
public class ImageTagHelper : BaseFieldTag
|
||||
{
|
||||
|
||||
@ -26,7 +26,7 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
{
|
||||
//TODO 若 image 组件未在form中该如何解决 _DONOT_USE_CS 的问题?
|
||||
}
|
||||
if (string.IsNullOrEmpty(Url) && Field.Model != null)
|
||||
if (string.IsNullOrEmpty(Url) && Field?.Model != null)
|
||||
{
|
||||
Url = $"/_Framework/GetFile/{Field.Model}";
|
||||
if (vm != null)
|
||||
@ -36,7 +36,7 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
}
|
||||
output.TagName = "img";
|
||||
output.TagMode = TagMode.SelfClosing;
|
||||
output.Attributes.Add("name", Field.Name + "img");
|
||||
output.Attributes.Add("name", Field?.Name + "img");
|
||||
output.Attributes.Add("id", Id + "img");
|
||||
if (!string.IsNullOrEmpty(Url))
|
||||
output.Attributes.Add("src", Url);
|
||||
|
@ -7,17 +7,44 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
{
|
||||
public class LayuiTreeItem
|
||||
{
|
||||
[JsonPropertyName("title")]
|
||||
[JsonPropertyName("name")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonPropertyName("children")]
|
||||
public List<LayuiTreeItem> Children { get; set; }
|
||||
|
||||
[JsonPropertyName("href")]
|
||||
public string Url { get; set; }
|
||||
|
||||
[JsonPropertyName("spread")]
|
||||
public bool Expand { get; set; }
|
||||
|
||||
[JsonPropertyName("selected")]
|
||||
public bool Checked { get; set; }
|
||||
|
||||
[JsonPropertyName("disabled")]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
[JsonPropertyName("icon")]
|
||||
public string Icon { get; set; }
|
||||
}
|
||||
|
||||
public class LayuiTreeItem2
|
||||
{
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonPropertyName("children")]
|
||||
public List<LayuiTreeItem> Children { get; set; }
|
||||
public List<LayuiTreeItem2> Children { get; set; }
|
||||
|
||||
[JsonPropertyName("href")]
|
||||
public string Url { get; set; }
|
||||
@ -31,4 +58,5 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
levelfieldname = Regex.Replace(levelfieldname, ".*?Searcher\\.", "");
|
||||
cusmtomclick = $@"
|
||||
$.extend({gridid}defaultfilter.where,{{'{idfieldname}':data.data.id, '{levelfieldname}':data.data.level }});
|
||||
layui.table.reload('{gridid}',{{where: {gridid}defaultfilter.where}});
|
||||
layui.table.reload('{gridid}',{{url:{gridid}url, where: {gridid}defaultfilter.where}});
|
||||
";
|
||||
}
|
||||
}
|
||||
@ -109,7 +109,7 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
{
|
||||
cusmtomclick = $"{FormatFuncName(ClickFunc)};";
|
||||
}
|
||||
List<LayuiTreeItem> treeitems = GetLayuiTree(mm);
|
||||
List<LayuiTreeItem2> treeitems = GetLayuiTree(mm);
|
||||
var onclick = $@"
|
||||
,click: function(data){{
|
||||
var ele = null;
|
||||
@ -167,16 +167,15 @@ layui.use(['tree'],function(){{
|
||||
base.Process(context, output);
|
||||
}
|
||||
|
||||
private List<LayuiTreeItem> GetLayuiTree(IEnumerable<TreeSelectListItem> tree, int level = 0)
|
||||
private List<LayuiTreeItem2> GetLayuiTree(IEnumerable<TreeSelectListItem> tree, int level = 0)
|
||||
{
|
||||
List<LayuiTreeItem> rv = new List<LayuiTreeItem>();
|
||||
List<LayuiTreeItem2> rv = new List<LayuiTreeItem2>();
|
||||
foreach (var s in tree)
|
||||
{
|
||||
var news = new LayuiTreeItem
|
||||
var news = new LayuiTreeItem2
|
||||
{
|
||||
Id = s.Value.ToString(),
|
||||
Title = s.Text,
|
||||
Icon = s.Icon,
|
||||
Url = s.Url,
|
||||
Expand = s.Expended,
|
||||
Level = level,
|
||||
@ -196,7 +195,7 @@ layui.use(['tree'],function(){{
|
||||
return rv;
|
||||
}
|
||||
|
||||
private LayuiTreeItem GetSelectedItem(List<LayuiTreeItem> tree)
|
||||
private LayuiTreeItem2 GetSelectedItem(List<LayuiTreeItem2> tree)
|
||||
{
|
||||
foreach (var item in tree)
|
||||
{
|
||||
|
@ -6,12 +6,14 @@ using WalkingTec.Mvvm.Core;
|
||||
using WalkingTec.Mvvm.Core.Extensions;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
{
|
||||
[HtmlTargetElement("wt:tree", TagStructure = TagStructure.WithoutEndTag)]
|
||||
public class TreeTagHelper : BaseFieldTag
|
||||
{
|
||||
public string EmptyText { get; set; }
|
||||
public ModelExpression Items { get; set; }
|
||||
public bool ShowLine { get; set; } = true;
|
||||
/// <summary>
|
||||
@ -46,66 +48,32 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public string CheckFunc { get; set; }
|
||||
public bool AutoRow { get; set; }
|
||||
public bool? EnableSearch { get; set; }
|
||||
|
||||
public TreeTagHelper(IOptionsMonitor<Configs> configs)
|
||||
{
|
||||
if (EmptyText == null)
|
||||
{
|
||||
EmptyText = THProgram._localizer["Sys.PleaseSelect"];
|
||||
}
|
||||
if (EnableSearch == null)
|
||||
{
|
||||
EnableSearch = configs.CurrentValue.UIOptions.ComboBox.DefaultEnableSearch;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
bool MultiSelect = false;
|
||||
var type = Field.Metadata.ModelType;
|
||||
if (type.IsArray || (type.IsGenericType && typeof(List<>).IsAssignableFrom(type.GetGenericTypeDefinition())))// Array or List
|
||||
if (Field.Name.Contains("[") || type.IsArray || type.IsList())// Array or List
|
||||
{
|
||||
MultiSelect = true;
|
||||
}
|
||||
string oncheck = "";
|
||||
string onclick = "";
|
||||
if (MultiSelect != true)
|
||||
{
|
||||
var formid = "";
|
||||
if (context.Items.ContainsKey("formid"))
|
||||
{
|
||||
formid = $",'{context.Items["formid"]}form'";
|
||||
}
|
||||
|
||||
onclick = $@"
|
||||
,click: function(data){{
|
||||
var ele = data.elem.find('.layui-tree-main:first');
|
||||
if(last{Id} != null){{
|
||||
last{Id}.css('background-color','');
|
||||
last{Id}.find('.layui-tree-txt').css('color','');
|
||||
}}
|
||||
$('#tree{Id}hidden').html('');
|
||||
if(last{Id} != null && last{Id}.is(ele)){{
|
||||
last{Id} = null;
|
||||
}}
|
||||
else{{
|
||||
ele.css('background-color','#5fb878');
|
||||
ele.find('.layui-tree-txt').css('color','#fff');
|
||||
$('#tree{Id}hidden').append(""<input type='hidden' name='{Field?.Name}' value='""+data.data.id+""'/>"");
|
||||
last{Id} = ele;
|
||||
}}
|
||||
{FormatFuncName(CheckFunc)};
|
||||
}}";
|
||||
}
|
||||
else
|
||||
{
|
||||
onclick = $@"
|
||||
,click: function(data){{
|
||||
{FormatFuncName(ClickFunc)};
|
||||
}}";
|
||||
|
||||
}
|
||||
oncheck = $@"
|
||||
,oncheck: function(data){{
|
||||
if(loaded{Id} == false) return;
|
||||
var checkData = layui.tree.getChecked('{Id}');
|
||||
var ids = ff.getTreeChecked(checkData);
|
||||
$('#tree{Id}hidden').html('');
|
||||
for(var i=0;i<ids.length;i++){{
|
||||
$('#tree{Id}hidden').append(""<input type='hidden' name='{Field?.Name}' value='""+ids[i]+""'/>"");
|
||||
}}
|
||||
{FormatFuncName(CheckFunc)};
|
||||
}}";
|
||||
|
||||
output.TagName = "div";
|
||||
output.Attributes.Add("id", "div" + Id);
|
||||
output.Attributes.Add("id", Id);
|
||||
output.TagMode = TagMode.StartTagAndEndTag;
|
||||
output.Attributes.Add("wtm-ctype", "tree");
|
||||
output.Attributes.Add("wtm-name", Field.Name);
|
||||
@ -134,31 +102,66 @@ namespace WalkingTec.Mvvm.TagHelpers.LayUI
|
||||
}
|
||||
var script = $@"
|
||||
<script>
|
||||
layui.use(['tree'],function(){{
|
||||
var last{Id} = null;
|
||||
var loaded{Id} = false;
|
||||
layui.tree.render({{
|
||||
id:'{Id}',elem: '#div{Id}',onlyIconControl:{(!MultiSelect).ToString().ToLower()}, showCheckbox:{MultiSelect.ToString().ToLower()},showLine:{ShowLine.ToString().ToLower()}
|
||||
,data: {JsonSerializer.Serialize(treeitems)} {oncheck} {onclick}
|
||||
}});
|
||||
loaded{Id} = true;";
|
||||
|
||||
var defaultselect = "";
|
||||
if (Field.Model != null) {
|
||||
defaultselect = $@"
|
||||
var selected = $(""div[data-id='{Field.Model.ToString()}']"");
|
||||
var selected2 = selected.find('.layui-tree-main:first');
|
||||
selected2.css('background-color','#5fb878');
|
||||
selected2.find('.layui-tree-txt').css('color','#fff');
|
||||
last{Id} = selected2;
|
||||
";
|
||||
}
|
||||
|
||||
if (MultiSelect == false && Field.Model != null)
|
||||
{
|
||||
script += defaultselect;
|
||||
}
|
||||
script += $@"
|
||||
var {Id} = xmSelect.render({{
|
||||
el: '#{Id}',
|
||||
name:'{Field.Name}',
|
||||
tips:'{EmptyText}',
|
||||
{(THProgram._localizer["Sys.LayuiDateLan"] == "CN" ? "language:'zn'," : "language:'en',")}
|
||||
autoRow: {AutoRow.ToString().ToLower()},
|
||||
filterable: {EnableSearch.ToString().ToLower()},
|
||||
template({{ item, sels, name, value }}){{
|
||||
if(item.icon !== undefined && item.icon != """"&& item.icon != null){{
|
||||
return '<i class=""'+item.icon+'""></i>' + item.name;
|
||||
}}
|
||||
else{{
|
||||
return item.name;
|
||||
}}
|
||||
}},
|
||||
{(MultiSelect == false ? $@"
|
||||
radio: true,
|
||||
clickClose: true,
|
||||
model: {{
|
||||
label: {{
|
||||
type: 'abc' ,
|
||||
abc: {{
|
||||
template: function(item, sels){{
|
||||
if(sels[0].icon !== undefined && sels[0].icon != """" && sels[0].icon != null){{
|
||||
return '<i class=""'+sels[0].icon+'""></i>' + sels[0].name;
|
||||
}}
|
||||
else{{
|
||||
return sels[0].name;
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}},
|
||||
toolbar: {{
|
||||
show: true,
|
||||
list: ['CLEAR']}}," : $@"
|
||||
toolbar: {{show: true,list: ['ALL', 'REVERSE', 'CLEAR']}},
|
||||
model: {{
|
||||
label: {{
|
||||
block: {{
|
||||
template: function(item, sels){{
|
||||
if(item.icon !== undefined && item.icon != """"&& item.icon != null){{
|
||||
return '<i class=""'+item.icon+'""></i>' + item.name;
|
||||
}}
|
||||
else{{
|
||||
return item.name;
|
||||
}}
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
}},
|
||||
")} tree: {{
|
||||
strict: false,
|
||||
show: true,
|
||||
showFolderIcon: true,
|
||||
showLine: true,
|
||||
indent: 20
|
||||
}},
|
||||
height: '400px',
|
||||
data: {JsonSerializer.Serialize(treeitems)}
|
||||
}})
|
||||
</script>
|
||||
";
|
||||
@ -167,7 +170,6 @@ layui.use(['tree'],function(){{
|
||||
{
|
||||
output.PostElement.AppendHtml($@"<script>
|
||||
ff.LoadComboItems('tree','{ItemUrl}','{Id}','{Field.Name}',{JsonSerializer.Serialize(vals)},function(){{
|
||||
{defaultselect}
|
||||
}})
|
||||
|
||||
</script>");
|
||||
@ -206,6 +208,8 @@ ff.LoadComboItems('tree','{ItemUrl}','{Id}','{Field.Name}',{JsonSerializer.Seria
|
||||
Title = s.Text,
|
||||
Url = s.Url,
|
||||
Expand = s.Expended,
|
||||
Disabled = s.Disabled,
|
||||
Icon = s.Icon
|
||||
//Children = new List<LayuiTreeItem>()
|
||||
};
|
||||
if (values.Contains(s.Value.ToString()))
|
||||
|
@ -7,7 +7,6 @@
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Runtime" Version="2.2.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user