mirror of
https://gitee.com/dotnetchina/OpenAuth.Net.git
synced 2026-07-28 14:17:59 +08:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4938027aa5 | ||
|
|
c8db5cb0b0 | ||
|
|
958a455dc4 | ||
|
|
c5149d33c4 | ||
|
|
86aad6337c | ||
|
|
099e695c27 | ||
|
|
a909d723a2 | ||
|
|
2b38807d2d | ||
|
|
d49ed28b13 | ||
|
|
c54fff5c34 | ||
|
|
763bd2ff1b | ||
|
|
360182b297 | ||
|
|
d923e708a4 | ||
|
|
16ba86ee71 | ||
|
|
cdc4f60c71 | ||
|
|
00cbe87ef5 | ||
|
|
1b290ad917 | ||
|
|
51c3eccedb | ||
|
|
250658b445 | ||
|
|
5940280aed | ||
|
|
161d3bfd76 | ||
|
|
bdbab080dc | ||
|
|
cbbdbf2fca | ||
|
|
8dfca5254d | ||
|
|
1863e833a2 | ||
|
|
35ff148b68 | ||
|
|
71a8a8e25d | ||
|
|
8ffa18dc04 | ||
|
|
cc227fa7fa | ||
|
|
975cd6c0a7 | ||
|
|
6b2e78a807 | ||
|
|
8314e88bd9 | ||
|
|
2f968ce08c | ||
|
|
43296f3504 | ||
|
|
4979666871 | ||
|
|
ac36928666 | ||
|
|
440ccd50d5 | ||
|
|
01a9b4e803 | ||
|
|
86d687f433 | ||
|
|
fb8f6ebb7e | ||
|
|
55dccb00bc | ||
|
|
734bde82b2 | ||
|
|
e6ecbc633f | ||
|
|
ff35c5d303 | ||
|
|
062c2b36e0 | ||
|
|
e07d7e0cd2 | ||
|
|
71b72ca06e |
@@ -83,9 +83,6 @@ Category="1.Database" Description="可以选择一个或多个表(使用Ctrl
|
||||
<%@ Register Name="ModifyReqGenerateClass"
|
||||
Template="ApiGenerate\ModifyReq.cst"
|
||||
MergeProperties="False" %>
|
||||
<%@ Register Name="ControllerGenerateClass"
|
||||
Template="ApiGenerate\Controller.cst"
|
||||
MergeProperties="False" %>
|
||||
|
||||
开始创建OpenAuth.Core WebApi相关代码 ...
|
||||
<% Generate(); %>
|
||||
@@ -105,7 +102,6 @@ Category="1.Database" Description="可以选择一个或多个表(使用Ctrl
|
||||
}
|
||||
|
||||
CreateEntityClasses();
|
||||
CreateControllerClass();
|
||||
CreateApplicationClass();
|
||||
CreateReqClass();
|
||||
CreateContextClass();
|
||||
@@ -154,24 +150,6 @@ Category="1.Database" Description="可以选择一个或多个表(使用Ctrl
|
||||
}
|
||||
|
||||
|
||||
//创建控制器,如UserManagerController.cs
|
||||
public void CreateControllerClass()
|
||||
{
|
||||
ControllerGenerateClass generatedClass = this.Create<ControllerGenerateClass>();
|
||||
this.CopyPropertiesTo(generatedClass);
|
||||
|
||||
|
||||
foreach(TableSchema table in tables)
|
||||
{
|
||||
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.WebApi\\Controllers\\"+ table.Name + "sController.cs";
|
||||
|
||||
generatedClass.ModuleName = table.Name;
|
||||
|
||||
Response.WriteLine("已生成"+generatedFile);
|
||||
generatedClass.RenderToFile(generatedFile, generatedFile, true);
|
||||
}
|
||||
}
|
||||
|
||||
//创建APP层,如UserManagerApp.cs
|
||||
public void CreateApplicationClass()
|
||||
{
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
<%--
|
||||
Name: Database Table Properties
|
||||
Author: yubaolee
|
||||
Description: Create a list of properties from a database table
|
||||
--%>
|
||||
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="True" Description="控制器" %>
|
||||
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
|
||||
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
|
||||
<%@ Assembly Name="SchemaExplorer" %>
|
||||
<%@ Import Namespace="SchemaExplorer" %>
|
||||
|
||||
using System;
|
||||
using Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenAuth.App;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
|
||||
namespace OpenAuth.WebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// <%=ModuleName%>操作
|
||||
/// </summary>
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class <%=ModuleName%>sController : ControllerBase
|
||||
{
|
||||
private readonly <%=ModuleName%>App _app;
|
||||
|
||||
/// <summary>
|
||||
/// //获取详情
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public Response<<%=ModuleName%>> Get(string id)
|
||||
{
|
||||
var result = new Response<<%=ModuleName%>>();
|
||||
try
|
||||
{
|
||||
result.Result = _app.Get(id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public Response Add(AddOrUpdate<%=ModuleName%>Req obj)
|
||||
{
|
||||
var result = new Response();
|
||||
try
|
||||
{
|
||||
_app.Add(obj);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public Response Update(AddOrUpdate<%=ModuleName%>Req obj)
|
||||
{
|
||||
var result = new Response();
|
||||
try
|
||||
{
|
||||
_app.Update(obj);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载列表
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public TableData Load([FromQuery]Query<%=ModuleName%>ListReq request)
|
||||
{
|
||||
return _app.Load(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量删除
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public Response Delete([FromBody]string[] ids)
|
||||
{
|
||||
var result = new Response();
|
||||
try
|
||||
{
|
||||
_app.Delete(ids);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException?.Message ?? ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public <%=ModuleName%>sController(<%=ModuleName%>App app)
|
||||
{
|
||||
_app = app;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ namespace Infrastructure
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filterjson))
|
||||
{
|
||||
var filterGroup = JsonHelper.Instance.Deserialize<FilterGroup>(filterjson);
|
||||
var filterGroup = JsonHelper.Instance.Deserialize<QueryObject>(filterjson);
|
||||
query = GenerateFilter(query, parametername, filterGroup);
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace Infrastructure
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filterjson))
|
||||
{
|
||||
var filterGroup = JsonHelper.Instance.Deserialize<FilterGroup>(filterjson);
|
||||
var filterGroup = JsonHelper.Instance.Deserialize<QueryObject>(filterjson);
|
||||
query = GenerateFilter(query, parametername, filterGroup);
|
||||
}
|
||||
|
||||
@@ -199,13 +199,13 @@ namespace Infrastructure
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="parametername"></param>
|
||||
/// <param name="filterGroup"></param>
|
||||
/// <param name="queryObject"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> GenerateFilter<T>(this IQueryable<T> query, string parametername,
|
||||
FilterGroup filterGroup)
|
||||
QueryObject queryObject)
|
||||
{
|
||||
var param = CreateLambdaParam<T>(parametername);
|
||||
Expression result = ConvertGroup<T>(filterGroup, param);
|
||||
Expression result = ConvertGroup<T>(queryObject, param);
|
||||
query = query.Where(param.GenerateTypeLambda<T>(result));
|
||||
return query;
|
||||
}
|
||||
@@ -215,14 +215,14 @@ namespace Infrastructure
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="parametername"></param>
|
||||
/// <param name="filterGroup"></param>
|
||||
/// <param name="queryObject"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static ISugarQueryable<T> GenerateFilter<T>(this ISugarQueryable<T> query, string parametername,
|
||||
FilterGroup filterGroup)
|
||||
QueryObject queryObject)
|
||||
{
|
||||
var param = CreateLambdaParam<T>(parametername);
|
||||
Expression result = ConvertGroup<T>(filterGroup, param);
|
||||
Expression result = ConvertGroup<T>(queryObject, param);
|
||||
query = query.Where(param.GenerateTypeLambda<T>(result));
|
||||
return query;
|
||||
}
|
||||
@@ -230,62 +230,62 @@ namespace Infrastructure
|
||||
/// <summary>
|
||||
/// 转换filtergroup为表达式
|
||||
/// </summary>
|
||||
/// <param name="filterGroup"></param>
|
||||
/// <param name="queryObject"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression ConvertGroup<T>(FilterGroup filterGroup, ParameterExpression param)
|
||||
public static Expression ConvertGroup<T>(QueryObject queryObject, ParameterExpression param)
|
||||
{
|
||||
if (filterGroup == null) return null;
|
||||
if (queryObject == null) return null;
|
||||
|
||||
if (filterGroup.Filters.Length == 1 &&(filterGroup.Children == null || !filterGroup.Children.Any())) //只有一个条件
|
||||
if (queryObject.Filters.Length == 1 &&(queryObject.Children == null || !queryObject.Children.Any())) //只有一个条件
|
||||
{
|
||||
return param.GenerateBody<T>(filterGroup.Filters[0]);
|
||||
return param.GenerateBody<T>(queryObject.Filters[0]);
|
||||
}
|
||||
|
||||
Expression result = ConvertFilters<T>(filterGroup.Filters, param, filterGroup.Operation);
|
||||
Expression gresult = ConvertGroup<T>(filterGroup.Children, param, filterGroup.Operation);
|
||||
Expression result = ConvertFilters<T>(queryObject.Filters, param, queryObject.Operation);
|
||||
Expression gresult = ConvertGroup<T>(queryObject.Children, param, queryObject.Operation);
|
||||
if (gresult == null) return result;
|
||||
if (result == null) return gresult;
|
||||
|
||||
if (filterGroup.Operation == "and")
|
||||
if (queryObject.Operation == "and")
|
||||
{
|
||||
return result.AndAlso(gresult);
|
||||
}
|
||||
else //or
|
||||
{
|
||||
return result.Or(gresult);
|
||||
return Expression.OrElse( result, gresult);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换FilterGroup[]为表达式,不管FilterGroup里面的Filters
|
||||
/// </summary>
|
||||
/// <param name="groups"></param>
|
||||
/// <param name="queryObjs"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="operation"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
private static Expression ConvertGroup<T>(FilterGroup[] groups, ParameterExpression param, string operation)
|
||||
private static Expression ConvertGroup<T>(QueryObject[] queryObjs, ParameterExpression param, string operation)
|
||||
{
|
||||
if (groups == null || !groups.Any()) return null;
|
||||
if (queryObjs == null || !queryObjs.Any()) return null;
|
||||
|
||||
Expression result = ConvertGroup<T>(groups[0], param);
|
||||
Expression result = ConvertGroup<T>(queryObjs[0], param);
|
||||
|
||||
if (groups.Length == 1) return result;
|
||||
if (queryObjs.Length == 1) return result;
|
||||
|
||||
if (operation == "and")
|
||||
{
|
||||
foreach (var filter in groups.Skip(1))
|
||||
foreach (var filter in queryObjs.Skip(1))
|
||||
{
|
||||
result = result.AndAlso(ConvertGroup<T>(filter, param));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var filter in groups.Skip(1))
|
||||
foreach (var filter in queryObjs.Skip(1))
|
||||
{
|
||||
result = result.Or(ConvertGroup<T>(filter, param));
|
||||
result = Expression.OrElse(result, ConvertGroup<T>(filter, param));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ namespace Infrastructure
|
||||
{
|
||||
foreach (var filter in filters.Skip(1))
|
||||
{
|
||||
result = result.Or(param.GenerateBody<T>(filter));
|
||||
result = Expression.OrElse(result, param.GenerateBody<T>(filter));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,64 @@
|
||||
namespace Infrastructure
|
||||
{
|
||||
|
||||
public class Filter
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Contrast { get; set; }
|
||||
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
public class FilterGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// or /and
|
||||
/// </summary>
|
||||
public string Operation { get; set; }
|
||||
public Filter[] Filters { get; set; }
|
||||
public FilterGroup[] Children { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace Infrastructure
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 查询表达式中的最小单元,如:
|
||||
/// new Filter {Key = "name", Value = "yubaolee", Contrast = "=="},
|
||||
/// new Filter {Key = "name", Value = "yubaolee", Contrast = "contains"},
|
||||
/// new Filter {Key = "age", Value = "10,20,30", Contrast = "in"},
|
||||
/// new Filter {Key = "10,20,30", Value = "40", Contrast = "intersect"}
|
||||
/// </summary>
|
||||
public class Filter
|
||||
{
|
||||
/// <summary>
|
||||
/// 过滤条件的关键字。
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通常为值,如:yubaolee、10、10,20,30等。
|
||||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通常为运算符,如:==、contains、in、intersect等。
|
||||
/// </summary>
|
||||
public string Contrast { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对于特殊值的说明
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询对象类,用于封装查询条件。
|
||||
/// </summary>
|
||||
public class QueryObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作类型,定义了查询条件之间的逻辑关系,如OR、AND。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该属性决定了如何组合多个过滤条件,以构建复杂的查询逻辑。
|
||||
/// </remarks>
|
||||
public string Operation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过滤器数组,包含一组过滤条件。
|
||||
/// </summary>
|
||||
public Filter[] Filters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子查询对象数组,支持嵌套查询。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 通过嵌套查询对象,可以构建复杂的查询逻辑,处理更复杂的数据关系。
|
||||
/// </remarks>
|
||||
public QueryObject[] Children { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
51
Infrastructure/QueryObjExtension.cs
Normal file
51
Infrastructure/QueryObjExtension.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// 查询对象FilterGroup扩展,将对象转换为sql查询
|
||||
/// </summary>
|
||||
public static class QueryObjExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据过滤器组构建查询。
|
||||
/// </summary>
|
||||
public static string BuildQuery(this QueryObject query)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BuildQuery(query, sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归构建查询字符串。
|
||||
/// </summary>
|
||||
private static void BuildQuery(QueryObject query, StringBuilder sb)
|
||||
{
|
||||
// 构建当前过滤器组的过滤条件
|
||||
if (query.Filters != null && query.Filters.Length > 0)
|
||||
{
|
||||
string filters = string.Join($" {query.Operation} ", query.Filters.Select(f => $"{f.Key} {f.Contrast} '{f.Value}'"));
|
||||
sb.Append($"({filters})");
|
||||
}
|
||||
|
||||
// 构建当前过滤器组的子过滤器组
|
||||
if (query.Children != null && query.Children.Length > 0)
|
||||
{
|
||||
// 如果当前字符串不为空,则添加操作符连接子过滤器组
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
sb.Append($" {query.Operation} ");
|
||||
}
|
||||
// 使用递归方式构建子过滤器组的查询字符串,并连接到当前字符串
|
||||
string children = string.Join($" {query.Operation} ", query.Children.Select(child =>
|
||||
{
|
||||
StringBuilder childSb = new StringBuilder();
|
||||
BuildQuery(child, childSb);
|
||||
return childSb.ToString();
|
||||
}));
|
||||
sb.Append($"({children})");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Infrastructure.Test
|
||||
[Test]
|
||||
public void Convert()
|
||||
{
|
||||
FilterGroup sub = new FilterGroup
|
||||
QueryObject sub = new QueryObject
|
||||
{
|
||||
Operation = "or"
|
||||
};
|
||||
@@ -19,22 +19,22 @@ namespace Infrastructure.Test
|
||||
new Filter {Key = "c3", Value = "10,20,30", Contrast = "in"}
|
||||
};
|
||||
|
||||
FilterGroup filterGroup = new FilterGroup
|
||||
QueryObject queryObject = new QueryObject
|
||||
{
|
||||
Operation = "and"
|
||||
};
|
||||
filterGroup.Filters = new[]
|
||||
queryObject.Filters = new[]
|
||||
{
|
||||
new Filter {Key = "c1", Value = "name", Contrast = "contains"},
|
||||
new Filter {Key = "10,20,30", Value = "40", Contrast = "intersect"}
|
||||
};
|
||||
|
||||
filterGroup.Children = new[]
|
||||
queryObject.Children = new[]
|
||||
{
|
||||
sub
|
||||
};
|
||||
|
||||
var expression = DynamicLinq.ConvertGroup<TestOjb>(filterGroup,
|
||||
var expression = DynamicLinq.ConvertGroup<TestOjb>(queryObject,
|
||||
Expression.Parameter(typeof(TestOjb), "c"));
|
||||
|
||||
Console.WriteLine(expression.ToString());
|
||||
|
||||
@@ -44,8 +44,10 @@ namespace OpenAuth.App
|
||||
var moduleIds = SugarClient.Queryable<Relevance>().Where(
|
||||
u =>
|
||||
(u.Key == Define.ROLEMODULE && _userRoleIds.Contains(u.FirstId))).Select(u => u.SecondId).ToList();
|
||||
var elementIds = GetElementIds();
|
||||
|
||||
return SugarClient.Queryable<ModuleView>().Where(m =>moduleIds.Contains(m.Id)).Includes(x=>x.Elements).ToList();
|
||||
return SugarClient.Queryable<ModuleView>().Where(m =>moduleIds.Contains(m.Id))
|
||||
.Includes(x=>x.Elements.Where(u=>elementIds.Contains(u.Id)).ToList()).ToList();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -54,14 +56,24 @@ namespace OpenAuth.App
|
||||
{
|
||||
get
|
||||
{
|
||||
var elementIds = SugarClient.Queryable<Relevance>().Where(
|
||||
u =>
|
||||
(u.Key == Define.ROLEELEMENT && _userRoleIds.Contains(u.FirstId))).Select(u => u.SecondId).ToList();
|
||||
var elementIds = GetElementIds();
|
||||
var usermoduleelements = SugarClient.Queryable<ModuleElement>().Where(u => elementIds.Contains(u.Id));
|
||||
return usermoduleelements.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取角色可访问的菜单Id
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private List<string> GetElementIds()
|
||||
{
|
||||
var elementIds = SugarClient.Queryable<Relevance>().Where(
|
||||
u =>
|
||||
(u.Key == Define.ROLEELEMENT && _userRoleIds.Contains(u.FirstId))).Select(u => u.SecondId).ToList();
|
||||
return elementIds;
|
||||
}
|
||||
|
||||
public List<Role> Roles
|
||||
{
|
||||
get { return SugarClient.Queryable<Role>().Where(u => _userRoleIds.Contains(u.Id)).ToList(); }
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace OpenAuth.App
|
||||
string.Join(',',orgs));
|
||||
}
|
||||
return UnitWork.Find<T>(null).GenerateFilter(parametername,
|
||||
JsonHelper.Instance.Deserialize<FilterGroup>(rule.PrivilegeRules));
|
||||
JsonHelper.Instance.Deserialize<QueryObject>(rule.PrivilegeRules));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace OpenAuth.App
|
||||
|
||||
public T Get(string id)
|
||||
{
|
||||
if (SugarClient.CurrentConnectionConfig.DbType == DbType.PostgreSQL)
|
||||
if (SugarClient.CurrentConnectionConfig.DbType == DbType.PostgreSQL
|
||||
|| SugarClient.CurrentConnectionConfig.DbType == DbType.Oracle)
|
||||
{
|
||||
return SugarClient.Queryable<T>().Where("\"Id\"=@id", new {id = id}).First();
|
||||
}
|
||||
@@ -74,7 +75,7 @@ namespace OpenAuth.App
|
||||
string.Join(',',orgs));
|
||||
}
|
||||
return SugarClient.Queryable<T>().GenerateFilter(parametername,
|
||||
JsonHelper.Instance.Deserialize<FilterGroup>(rule.PrivilegeRules));
|
||||
JsonHelper.Instance.Deserialize<QueryObject>(rule.PrivilegeRules));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -30,7 +30,13 @@ namespace OpenAuth.App
|
||||
var columnFields = loginContext.GetTableColumns("Category");
|
||||
if (columnFields == null || columnFields.Count == 0)
|
||||
{
|
||||
throw new Exception("请在代码生成界面配置Category表的字段属性");
|
||||
//因为分类字典值需要在别的地方使用,必需初始化有值
|
||||
columnFields = new List<BuilderTableColumn>
|
||||
{
|
||||
new() { ColumnName = "Name", ColumnType = "string" },
|
||||
new() { ColumnName = "DtCode", ColumnType = "string" },
|
||||
new() { ColumnName = "DtValue", ColumnType = "string" }
|
||||
};
|
||||
}
|
||||
|
||||
var result = new TableData();
|
||||
|
||||
@@ -120,6 +120,10 @@ namespace OpenAuth.App
|
||||
{
|
||||
return GetSqlServerStructure(tableName);
|
||||
}
|
||||
else if (dbtype == Define.DBTYPE_PostgreSQL)
|
||||
{
|
||||
return GetPostgreStructure(tableName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetOracleStructure(tableName);
|
||||
@@ -258,6 +262,82 @@ order by column_id; ";
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取Mysql表结构信息
|
||||
/// </summary>
|
||||
private IList<SysTableColumn> GetPostgreStructure(string tableName)
|
||||
{
|
||||
var sql = $@"select attr.attrelid
|
||||
, schema.nspname as schemaname
|
||||
, class.relname as tablename --表名
|
||||
, attr.attname as columnname --列名
|
||||
, attr.atttypid --类型ID
|
||||
, attr.atttypmod
|
||||
, case when con.conname is not null then 1 else 0 end as iskey --是否主键
|
||||
, case when attr.attnotnull is true then 0 else 1 end as isnull --可空
|
||||
, t.typname columntype --类型名称
|
||||
, case
|
||||
when typname in ('BIT', 'BOOL', 'bit', 'bool') then
|
||||
'bool'
|
||||
when typname in ('smallint', 'SMALLINT') then 'short'
|
||||
when typname in ('tinyint', 'TINYINT') then 'bool'
|
||||
when typname in ('int4', 'int', 'INT') then
|
||||
'int'
|
||||
when typname in ('BIGINT', 'bigint') then
|
||||
'bigint'
|
||||
when typname in ('FLOAT', 'DOUBLE', 'DECIMAL', 'float', 'double', 'decimal') then
|
||||
'decimal'
|
||||
when typname in ('varchar', 'text') then
|
||||
'string'
|
||||
when typname in ('Date', 'DateTime', 'TimeStamp', 'date', 'datetime', 'timestamp') then
|
||||
'DateTime'
|
||||
else 'string'
|
||||
end as entitytype
|
||||
, comment.description as comment
|
||||
, 1 as iscolumndata
|
||||
, case
|
||||
when t.typname = 'varchar' or t.typname = 'bpchar' then attr.atttypmod - 4
|
||||
else 10
|
||||
end as columnwidth
|
||||
, 0 as orderno
|
||||
, case
|
||||
when t.typname = 'varchar' or t.typname = 'bpchar' then attr.atttypmod - 4
|
||||
else 10
|
||||
end as maxlength
|
||||
, case
|
||||
when attname in ('createid', 'modifyid', '')
|
||||
or con.conname is null then 0
|
||||
else 1
|
||||
end as isdisplay --是否显示
|
||||
from pg_catalog.pg_class class
|
||||
inner join pg_catalog.pg_attribute attr on attr.attrelid = class.oid
|
||||
left join pg_catalog.pg_constraint con
|
||||
on con.conrelid = class.oid and attr.attnum = any (con.conkey) and con.contype = 'p'
|
||||
left join pg_catalog.pg_type t on attr.atttypid = t.oid
|
||||
inner join pg_catalog.pg_description comment
|
||||
on comment.objoid = attr.attrelid and comment.objsubid = attr.attnum
|
||||
inner join pg_catalog.pg_namespace schema on schema.oid = class.relnamespace
|
||||
where attr.attnum > 0
|
||||
and not attr.attisdropped
|
||||
and schema.nspname = 'public' -- replace 'your_schema' with your schema name
|
||||
and class.relname = '{tableName}'";
|
||||
|
||||
foreach (var context in _contexts)
|
||||
{
|
||||
var columns = context.Set<SysTableColumn>().FromSqlRaw(sql);
|
||||
var columnList = columns?.ToList();
|
||||
if (columnList != null && columnList.Any())
|
||||
{
|
||||
return columnList;
|
||||
}
|
||||
}
|
||||
|
||||
return new List<SysTableColumn>();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取SqlServer表结构信息
|
||||
/// </summary>
|
||||
|
||||
@@ -68,6 +68,9 @@ namespace OpenAuth.App.Flow
|
||||
case DataCompare.LessEqual:
|
||||
result &= frmvalue <= value;
|
||||
break;
|
||||
case DataCompare.NotEqual:
|
||||
result &= frmvalue != value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else //如果只是字符串,只判断相等
|
||||
@@ -79,7 +82,28 @@ namespace OpenAuth.App.Flow
|
||||
}
|
||||
else
|
||||
{
|
||||
result &= compare.Value == fieldVal;
|
||||
switch (compare.Operation)
|
||||
{
|
||||
case DataCompare.Equal:
|
||||
result &= compare.Value == fieldVal;
|
||||
break;
|
||||
case DataCompare.Larger:
|
||||
result &= string.Compare(compare.Value, fieldVal, false) > 0;
|
||||
break;
|
||||
case DataCompare.Less:
|
||||
result &= string.Compare(compare.Value, fieldVal, false) < 0;
|
||||
break;
|
||||
case DataCompare.LargerEqual:
|
||||
result &= string.Compare(compare.Value, fieldVal, false) >= 0;
|
||||
break;
|
||||
case DataCompare.LessEqual:
|
||||
result &= string.Compare(compare.Value, fieldVal, false) <= 0;
|
||||
break;
|
||||
case DataCompare.NotEqual:
|
||||
result &= compare.Value != fieldVal;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ using System.Linq.Expressions;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Infrastructure.Const;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -54,7 +55,8 @@ namespace OpenAuth.App
|
||||
IRepository<FlowInstance, OpenAuthDBContext> repository
|
||||
, RevelanceManagerApp app, FlowSchemeApp flowSchemeApp, FormApp formApp,
|
||||
IHttpClientFactory httpClientFactory, IAuth auth, IServiceProvider serviceProvider,
|
||||
SysMessageApp messageApp, DbExtension dbExtension, UserManagerApp userManagerApp, OrgManagerApp orgManagerApp)
|
||||
SysMessageApp messageApp, DbExtension dbExtension, UserManagerApp userManagerApp,
|
||||
OrgManagerApp orgManagerApp)
|
||||
: base(unitWork, repository, auth)
|
||||
{
|
||||
_revelanceApp = app;
|
||||
@@ -135,8 +137,15 @@ namespace OpenAuth.App
|
||||
if (flowInstance.FrmType == 1) //如果是开发者自定义的表单
|
||||
{
|
||||
var t = Type.GetType("OpenAuth.App." + flowInstance.DbName + "App");
|
||||
ICustomerForm icf = (ICustomerForm) _serviceProvider.GetService(t);
|
||||
icf.Add(flowInstance.Id, flowInstance.FrmData);
|
||||
ICustomerForm icf = (ICustomerForm)_serviceProvider.GetService(t);
|
||||
try
|
||||
{
|
||||
icf.Add(flowInstance.Id, flowInstance.FrmData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception("流程表单数据解析失败,请检查表单是否填写完整");
|
||||
}
|
||||
}
|
||||
|
||||
//如果工作流配置的表单配置有对应的数据库
|
||||
@@ -247,7 +256,7 @@ namespace OpenAuth.App
|
||||
if (form.FrmType == 1) //如果是开发者自定义的表单,更新对应数据库表数据
|
||||
{
|
||||
var t = Type.GetType("OpenAuth.App." + req.DbName + "App");
|
||||
ICustomerForm icf = (ICustomerForm) _serviceProvider.GetService(t);
|
||||
ICustomerForm icf = (ICustomerForm)_serviceProvider.GetService(t);
|
||||
icf.Update(req.Id, req.FrmData);
|
||||
}
|
||||
else if (form.FrmType == 2 && !string.IsNullOrEmpty(form.DbName)) //拖拽表单定义了关联数据库
|
||||
@@ -274,6 +283,7 @@ namespace OpenAuth.App
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
updatestr += $"{column.ColumnName} = '{val}',";
|
||||
}
|
||||
|
||||
@@ -321,13 +331,6 @@ namespace OpenAuth.App
|
||||
throw new Exception("当前用户没有审批该节点权限");
|
||||
}
|
||||
|
||||
FlowInstanceOperationHistory flowInstanceOperationHistory = new FlowInstanceOperationHistory
|
||||
{
|
||||
InstanceId = instanceId,
|
||||
CreateUserId = tag.UserId,
|
||||
CreateUserName = tag.UserName,
|
||||
CreateDate = DateTime.Now
|
||||
}; //操作记录
|
||||
FlowRuntime wfruntime = new FlowRuntime(flowInstance);
|
||||
|
||||
#region 会签
|
||||
@@ -340,7 +343,7 @@ namespace OpenAuth.App
|
||||
|
||||
string canCheckId = ""; //寻找当前登录用户可审核的节点Id
|
||||
foreach (string fromForkStartNodeId in wfruntime.FromNodeLines[wfruntime.currentNodeId]
|
||||
.Select(u => u.to))
|
||||
.Select(u => u.to))
|
||||
{
|
||||
var fromForkStartNode = wfruntime.Nodes[fromForkStartNodeId]; //与会前开始节点直接连接的节点
|
||||
canCheckId = GetOneForkLineCanCheckNodeId(fromForkStartNode, wfruntime, tag);
|
||||
@@ -351,10 +354,11 @@ namespace OpenAuth.App
|
||||
{
|
||||
throw (new Exception("审核异常,找不到审核节点"));
|
||||
}
|
||||
|
||||
flowInstanceOperationHistory.Content =
|
||||
|
||||
var content =
|
||||
$"{user.Account}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}审批了【{wfruntime.Nodes[canCheckId].name}】" +
|
||||
$"结果:{(tag.Taged == 1 ? "同意" : "不同意")},备注:{tag.Description}";
|
||||
AddOperationHis(instanceId, tag, content);
|
||||
|
||||
wfruntime.MakeTagNode(canCheckId, tag); //标记审核节点状态
|
||||
string res = wfruntime.NodeConfluence(canCheckId, tag);
|
||||
@@ -382,78 +386,33 @@ namespace OpenAuth.App
|
||||
flowInstance.MakerList = GetForkNodeMakers(wfruntime, wfruntime.currentNodeId);
|
||||
AddTransHistory(wfruntime);
|
||||
}
|
||||
|
||||
flowInstance.SchemeContent = JsonHelper.Instance.Serialize(wfruntime.ToSchemeObj());
|
||||
}
|
||||
|
||||
#endregion 会签
|
||||
|
||||
|
||||
#region 一般审核
|
||||
|
||||
else
|
||||
{
|
||||
wfruntime.MakeTagNode(wfruntime.currentNodeId, tag);
|
||||
if (tag.Taged == (int) TagState.Ok)
|
||||
{
|
||||
bool canNext = true;
|
||||
if (wfruntime.currentNode.setInfo.NodeDesignate == Setinfo.RUNTIME_MANY_PARENTS)
|
||||
{
|
||||
var roles = _auth.GetCurrentUser().Roles;
|
||||
//如果是连续多级直属上级且还没到指定的角色,只改变执行人,不到下一个节点
|
||||
if (!wfruntime.currentNode.setInfo.NodeDesignateData.roles.Intersect(roles.Select(u =>u.Id)).Any())
|
||||
{
|
||||
canNext = false;
|
||||
var parentId = _userManagerApp.GetParent(user.Id);
|
||||
flowInstance.MakerList = parentId;
|
||||
}
|
||||
}
|
||||
|
||||
if (canNext)
|
||||
{
|
||||
flowInstance.PreviousId = flowInstance.ActivityId;
|
||||
flowInstance.ActivityId = wfruntime.nextNodeId;
|
||||
flowInstance.ActivityType = wfruntime.nextNodeType;
|
||||
flowInstance.ActivityName = wfruntime.nextNode.name;
|
||||
flowInstance.MakerList = wfruntime.nextNodeType == 4 ? "" : GetNextMakers(wfruntime, request);
|
||||
flowInstance.IsFinish = (wfruntime.nextNodeType == 4
|
||||
? FlowInstanceStatus.Finished
|
||||
: FlowInstanceStatus.Running);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
flowInstance.IsFinish = FlowInstanceStatus.Disagree; //表示该节点不同意
|
||||
wfruntime.nextNodeId = "-1";
|
||||
wfruntime.nextNodeType = 4;
|
||||
}
|
||||
|
||||
AddTransHistory(wfruntime);
|
||||
|
||||
flowInstanceOperationHistory.Content =
|
||||
$"{user.Account}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}审批了【{wfruntime.currentNode.name}】" +
|
||||
$"结果:{(tag.Taged == 1 ? "同意" : "不同意")},备注:{tag.Description}";
|
||||
VerifyNode(request, tag, flowInstance);
|
||||
}
|
||||
|
||||
#endregion 一般审核
|
||||
|
||||
flowInstance.SchemeContent = JsonHelper.Instance.Serialize(wfruntime.ToSchemeObj());
|
||||
|
||||
if (!string.IsNullOrEmpty(request.FrmData))
|
||||
//自定义开发表单,需要更新对应的数据库
|
||||
if (!string.IsNullOrEmpty(request.FrmData) && flowInstance.FrmType == 1)
|
||||
{
|
||||
flowInstance.FrmData = request.FrmData;
|
||||
|
||||
if (flowInstance.FrmType == 1) //如果是开发者自定义的表单,更新对应数据库表数据
|
||||
{
|
||||
var t = Type.GetType("OpenAuth.App." + flowInstance.DbName + "App");
|
||||
ICustomerForm icf = (ICustomerForm) _serviceProvider.GetService(t);
|
||||
icf.Update(flowInstance.Id, flowInstance.FrmData);
|
||||
}
|
||||
var t = Type.GetType("OpenAuth.App." + flowInstance.DbName + "App");
|
||||
ICustomerForm icf = (ICustomerForm)_serviceProvider.GetService(t);
|
||||
icf.Update(flowInstance.Id, flowInstance.FrmData);
|
||||
}
|
||||
|
||||
UnitWork.Update(flowInstance);
|
||||
UnitWork.Add(flowInstanceOperationHistory);
|
||||
|
||||
//给流程创建人发送通知信息
|
||||
_messageApp.SendMsgTo(flowInstance.CreateUserId,
|
||||
$"你的流程[{flowInstance.CustomName}]已被{user.Name}处理。处理情况如下:{flowInstanceOperationHistory.Content}");
|
||||
$"你的流程[{flowInstance.CustomName}]已被{user.Name}处理。");
|
||||
|
||||
UnitWork.Save();
|
||||
|
||||
@@ -461,6 +420,72 @@ namespace OpenAuth.App
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 普通的节点审批
|
||||
/// </summary>
|
||||
private void VerifyNode(VerificationReq request, Tag tag, FlowInstance flowInstance)
|
||||
{
|
||||
var user = _auth.GetCurrentUser().User;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.FrmData))
|
||||
{
|
||||
flowInstance.FrmData = request.FrmData;
|
||||
}
|
||||
|
||||
FlowRuntime wfruntime = new FlowRuntime(flowInstance);
|
||||
wfruntime.MakeTagNode(wfruntime.currentNodeId, tag);
|
||||
if (tag.Taged == (int)TagState.Ok)
|
||||
{
|
||||
bool canNext = true;
|
||||
if (wfruntime.currentNode.setInfo.NodeDesignate == Setinfo.RUNTIME_MANY_PARENTS)
|
||||
{
|
||||
var roles = _auth.GetCurrentUser().Roles;
|
||||
//如果是连续多级直属上级且还没到指定的角色,只改变执行人,不到下一个节点
|
||||
if (!wfruntime.currentNode.setInfo.NodeDesignateData.roles.Intersect(roles.Select(u => u.Id)).Any())
|
||||
{
|
||||
canNext = false;
|
||||
var parentId = _userManagerApp.GetParent(user.Id);
|
||||
flowInstance.MakerList = parentId;
|
||||
}
|
||||
}
|
||||
|
||||
if (canNext)
|
||||
{
|
||||
flowInstance.PreviousId = flowInstance.ActivityId;
|
||||
flowInstance.ActivityId = wfruntime.nextNodeId;
|
||||
flowInstance.ActivityType = wfruntime.nextNodeType;
|
||||
flowInstance.ActivityName = wfruntime.nextNode.name;
|
||||
flowInstance.MakerList = wfruntime.nextNodeType == 4 ? "" : GetNextMakers(wfruntime, request);
|
||||
flowInstance.IsFinish = (wfruntime.nextNodeType == 4
|
||||
? FlowInstanceStatus.Finished
|
||||
: FlowInstanceStatus.Running);
|
||||
}
|
||||
}
|
||||
else //审批结果为不同意
|
||||
{
|
||||
flowInstance.IsFinish = FlowInstanceStatus.Disagree;
|
||||
wfruntime.nextNodeId = "-1";
|
||||
wfruntime.nextNodeType = 4;
|
||||
}
|
||||
|
||||
var content =
|
||||
$"{user.Account}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}审批了【{wfruntime.currentNode.name}】" +
|
||||
$"结果:{(tag.Taged == 1 ? "同意" : "不同意")},备注:{tag.Description}";
|
||||
AddOperationHis(flowInstance.Id, tag, content);
|
||||
flowInstance.SchemeContent = JsonHelper.Instance.Serialize(wfruntime.ToSchemeObj());
|
||||
|
||||
//如果审批通过,且下一个审批人是自己,则自动审批
|
||||
if (tag.Taged == (int)TagState.Ok)
|
||||
{
|
||||
if (flowInstance.MakerList != "1" && (!flowInstance.MakerList.Contains(user.Id)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VerifyNode(request, tag, flowInstance);
|
||||
}
|
||||
}
|
||||
|
||||
//会签时,获取一条会签分支上面是否有用户可审核的节点
|
||||
private string GetOneForkLineCanCheckNodeId(FlowNode fromForkStartNode, FlowRuntime wfruntime, Tag tag)
|
||||
{
|
||||
@@ -507,7 +532,7 @@ namespace OpenAuth.App
|
||||
var tag = new Tag
|
||||
{
|
||||
Description = reqest.VerificationOpinion,
|
||||
Taged = (int) TagState.Reject,
|
||||
Taged = (int)TagState.Reject,
|
||||
UserId = user.Id,
|
||||
UserName = user.Name
|
||||
};
|
||||
@@ -593,7 +618,7 @@ namespace OpenAuth.App
|
||||
|
||||
makerList = GenericHelpers.ArrayToString(request.NodeDesignates, makerList);
|
||||
}
|
||||
else if (wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_PARENT
|
||||
else if (wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_PARENT
|
||||
|| wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_MANY_PARENTS)
|
||||
{
|
||||
//如果是上一节点执行人的直属上级或连续多级直属上级
|
||||
@@ -606,8 +631,12 @@ namespace OpenAuth.App
|
||||
//当审批流程时,能进到这里,表明当前登录用户已经有审批当前节点的权限,完全可以直接用登录用户的直接上级
|
||||
var user = _auth.GetCurrentUser().User;
|
||||
var parentId = _userManagerApp.GetParent(user.Id);
|
||||
|
||||
makerList = GenericHelpers.ArrayToString(new[]{parentId}, makerList);
|
||||
if (StringExtension.IsNullOrEmpty(parentId))
|
||||
{
|
||||
throw new Exception("无法找到当前用户的直属上级");
|
||||
}
|
||||
|
||||
makerList = GenericHelpers.ArrayToString(new[] { parentId }, makerList);
|
||||
}
|
||||
else if (wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_CHAIRMAN)
|
||||
{
|
||||
@@ -664,7 +693,7 @@ namespace OpenAuth.App
|
||||
{
|
||||
if (node.setInfo != null && node.setInfo.Taged != null)
|
||||
{
|
||||
if (node.type != FlowNode.FORK && node.setInfo.Taged != (int) TagState.Ok) //如果节点是不同意或驳回,则不用再找了
|
||||
if (node.type != FlowNode.FORK && node.setInfo.Taged != (int)TagState.Ok) //如果节点是不同意或驳回,则不用再找了
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -710,7 +739,8 @@ namespace OpenAuth.App
|
||||
}
|
||||
else if (node.setInfo != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(node.setInfo.NodeDesignate) ||node.setInfo.NodeDesignate == Setinfo.ALL_USER) //所有成员
|
||||
if (string.IsNullOrEmpty(node.setInfo.NodeDesignate) ||
|
||||
node.setInfo.NodeDesignate == Setinfo.ALL_USER) //所有成员
|
||||
{
|
||||
makerList = "1";
|
||||
}
|
||||
@@ -751,7 +781,7 @@ namespace OpenAuth.App
|
||||
CheckNodeDesignate(request);
|
||||
}
|
||||
|
||||
bool isReject = TagState.Reject.Equals((TagState) Int32.Parse(request.VerificationFinally));
|
||||
bool isReject = TagState.Reject.Equals((TagState)Int32.Parse(request.VerificationFinally));
|
||||
if (isReject) //驳回
|
||||
{
|
||||
NodeReject(request);
|
||||
@@ -815,7 +845,7 @@ namespace OpenAuth.App
|
||||
// 加入搜索自定义标题
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
waitExp = waitExp.And(t => t.CustomName.Contains(request.key));
|
||||
waitExp = PredicateBuilder.And(waitExp, t => t.CustomName.Contains(request.key));
|
||||
}
|
||||
|
||||
result.count = await UnitWork.Find(waitExp).CountAsync();
|
||||
@@ -849,7 +879,7 @@ namespace OpenAuth.App
|
||||
// 加入搜索自定义标题
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
myFlowExp = myFlowExp.And(t => t.CustomName.Contains(request.key));
|
||||
myFlowExp = PredicateBuilder.And(myFlowExp, t => t.CustomName.Contains(request.key));
|
||||
}
|
||||
|
||||
result.count = await UnitWork.Find(myFlowExp).CountAsync();
|
||||
@@ -882,6 +912,20 @@ namespace OpenAuth.App
|
||||
});
|
||||
}
|
||||
|
||||
private void AddOperationHis(string instanceId, Tag tag, string content)
|
||||
{
|
||||
FlowInstanceOperationHistory flowInstanceOperationHistory = new FlowInstanceOperationHistory
|
||||
{
|
||||
InstanceId = instanceId,
|
||||
CreateUserId = tag.UserId,
|
||||
CreateUserName = tag.UserName,
|
||||
CreateDate = DateTime.Now,
|
||||
Content = content
|
||||
}; //操作记录
|
||||
|
||||
UnitWork.Add(flowInstanceOperationHistory);
|
||||
}
|
||||
|
||||
public List<FlowInstanceOperationHistory> QueryHistories(QueryFlowInstanceHistoryReq request)
|
||||
{
|
||||
return UnitWork.Find<FlowInstanceOperationHistory>(u => u.InstanceId == request.FlowInstanceId)
|
||||
|
||||
@@ -85,7 +85,8 @@ namespace OpenAuth.App
|
||||
}
|
||||
|
||||
var columnnames = columnFields.Select(u => u.ColumnName);
|
||||
if (SugarClient.CurrentConnectionConfig.DbType == DbType.PostgreSQL)
|
||||
if (SugarClient.CurrentConnectionConfig.DbType == DbType.PostgreSQL
|
||||
|| SugarClient.CurrentConnectionConfig.DbType == DbType.Oracle)
|
||||
{
|
||||
columnnames = columnFields.Select(u => "\"" + u.ColumnName +"\"");
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace OpenAuth.App
|
||||
}
|
||||
|
||||
var columnnames = columnFields.Select(u => u.ColumnName);
|
||||
if (SugarClient.CurrentConnectionConfig.DbType == DbType.PostgreSQL)
|
||||
if (SugarClient.CurrentConnectionConfig.DbType == DbType.PostgreSQL
|
||||
|| SugarClient.CurrentConnectionConfig.DbType == DbType.Oracle)
|
||||
{
|
||||
columnnames = columnFields.Select(u => "\"" + u.ColumnName +"\"");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace OpenAuth.App.Test
|
||||
var services = new ServiceCollection();
|
||||
|
||||
var cachemock = new Mock<ICacheContext>();
|
||||
cachemock.Setup(x => x.Get<UserAuthSession>("tokentest")).Returns(new UserAuthSession { Account = "Systems" });
|
||||
cachemock.Setup(x => x.Get<UserAuthSession>("tokentest")).Returns(new UserAuthSession { Account = "admin" });
|
||||
services.AddScoped(x => cachemock.Object);
|
||||
|
||||
var httpContextAccessorMock = new Mock<IHttpContextAccessor>();
|
||||
@@ -37,7 +37,7 @@ namespace OpenAuth.App.Test
|
||||
{
|
||||
var app = _autofacServiceProvider.GetService<ResourceApp>();
|
||||
var result = app.Load(new QueryResourcesReq());
|
||||
Console.WriteLine(JsonHelper.Instance.Serialize(result));
|
||||
Console.WriteLine(JsonHelper.Instance.Serialize(result.Result));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -46,7 +46,7 @@ namespace OpenAuth.App.Test
|
||||
var auth = _autofacServiceProvider.GetService<IAuth>();
|
||||
var app = _autofacServiceProvider.GetService<DataPrivilegeRuleApp>();
|
||||
//该测试解析为:针对资源列表,【管理员】可以看到所有,角色为【神】或【测试】的只能看到自己创建的
|
||||
var filterGroup = new FilterGroup
|
||||
var filterGroup = new QueryObject
|
||||
{
|
||||
Operation = "or"
|
||||
};
|
||||
@@ -61,7 +61,7 @@ namespace OpenAuth.App.Test
|
||||
};
|
||||
filterGroup.Children = new[]
|
||||
{
|
||||
new FilterGroup //登录用户角色包含【测试】或包含【神】的,只能看到自己的
|
||||
new QueryObject //登录用户角色包含【测试】或包含【神】的,只能看到自己的
|
||||
{
|
||||
Operation = "and",
|
||||
Filters = new Filter[]
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
var _hmt = _hmt || [];
|
||||
(function () {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "//hm.baidu.com/hm.js?0558502420ce5fee054b31425e77ffa6";
|
||||
hm.src = "//hm.baidu.com/hm.js?93a7b9a145222f9b7109d643a0c58f8d";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
|
||||
@@ -446,28 +446,6 @@
|
||||
<None Include="wwwroot\layui\images\face\8.gif" />
|
||||
<None Include="wwwroot\layui\images\face\9.gif" />
|
||||
<None Include="wwwroot\layui\layui.js" />
|
||||
<None Include="wwwroot\layui\lay\dest\layui.all.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\carousel.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\code.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\colorpicker.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\element.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\flow.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\form.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\jquery.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\laydate.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\layedit.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\layer.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\layim.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\laypage.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\laytpl.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\mobile.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\rate.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\slider.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\table.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\transfer.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\tree.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\upload.js" />
|
||||
<None Include="wwwroot\layui\lay\modules\util.js" />
|
||||
<None Include="wwwroot\userJs\assignModule.js" />
|
||||
<None Include="wwwroot\userJs\assignResource.js" />
|
||||
<None Include="wwwroot\userJs\assignRole.js" />
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
@section header
|
||||
{
|
||||
<link rel="stylesheet" href="/css/treetable.css" />
|
||||
<link rel="stylesheet" href="/js/dtree/dtree.css" />
|
||||
<link rel="stylesheet" href="/js/dtree/font/dtreefont.css" />
|
||||
<link rel="stylesheet" href="/css/treetable.css"/>
|
||||
<link rel="stylesheet" href="/js/dtree/dtree.css"/>
|
||||
<link rel="stylesheet" href="/js/dtree/font/dtreefont.css"/>
|
||||
}
|
||||
|
||||
<blockquote class="layui-elem-quote news_search toolList" id="menus">
|
||||
</blockquote>
|
||||
|
||||
@@ -18,46 +19,45 @@
|
||||
lay-data="{height: 'full-80', id:'mainList'}"
|
||||
lay-filter="list" lay-size="sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th lay-data="{checkbox:true, fixed: true}"></th>
|
||||
<th lay-data="{field:'Name', width:120, sort: true, fixed: true}">模块名称</th>
|
||||
<th lay-data="{field:'Status', width:100,templet: '#statusTpl'}">导航栏展示</th>
|
||||
<th lay-data="{field:'IsSys', width:100,templet: '#sysTpl'}">模块类型</th>
|
||||
<th lay-data="{field:'IconName', width:60,templet: '#iconTpl'}">图标</th>
|
||||
<th lay-data="{field:'CascadeId', width:80}">层级ID</th>
|
||||
<th lay-data="{field:'Code', width:80}">模块标识</th>
|
||||
<th lay-data="{field:'Url', width:200}">Url</th>
|
||||
<th lay-data="{field:'ParentName', width:135}">父节点名称</th>
|
||||
<th lay-data="{field:'SortNo', width:80}">排序号</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th lay-data="{checkbox:true, fixed: true}"></th>
|
||||
<th lay-data="{field:'Name', width:120, sort: true, fixed: true}">模块名称</th>
|
||||
<th lay-data="{field:'Status', width:100,templet: '#statusTpl'}">导航栏展示</th>
|
||||
<th lay-data="{field:'IsSys', width:100,templet: '#sysTpl'}">模块类型</th>
|
||||
<th lay-data="{field:'IconName', width:60,templet: '#iconTpl'}">图标</th>
|
||||
<th lay-data="{field:'CascadeId', width:80}">层级ID</th>
|
||||
<th lay-data="{field:'Code', width:80}">模块标识</th>
|
||||
<th lay-data="{field:'Url', width:200}">Url</th>
|
||||
<th lay-data="{field:'ParentName', width:135}">父节点名称</th>
|
||||
<th lay-data="{field:'SortNo', width:80}">排序号</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<script type="text/html" id="iconTpl">
|
||||
{{# if( d.IconName != null && d.IconName != ''){ }}
|
||||
{{# if( d.IconName != null && d.IconName != ''){ }}
|
||||
<i class="layui-icon {{ d.IconName }}"></i>
|
||||
{{# } else { }}
|
||||
{{# } else { }}
|
||||
{{ d.IconName }}
|
||||
{{# } }}
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="statusTpl">
|
||||
{{# if( d.Status == -1){ }}
|
||||
{{# if( d.Status == -1){ }}
|
||||
<span style="color:red">隐藏</span>
|
||||
{{# } else { }}
|
||||
{{# } else { }}
|
||||
<span style="color:green">显示</span>
|
||||
{{# } }}
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="sysTpl">
|
||||
{{# if( d.IsSys == 1){ }}
|
||||
<script type="text/html" id="sysTpl">
|
||||
{{# if( d.IsSys == 1){ }}
|
||||
<span class="layui-badge">内置</span>
|
||||
{{# } else { }}
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-green">自定义</span>
|
||||
{{# } }}
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div class="layui-col-xs">
|
||||
<div class="layui-col-xs3">
|
||||
<!--菜单列表-->
|
||||
<table class="layui-table"
|
||||
lay-data="{height: 'full-80', id:'menuList', text: { none: '单击模块列表数据行查看菜单' }}"
|
||||
@@ -69,32 +69,31 @@
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
|
||||
<script type="text/html" id="menuTpl">
|
||||
<button class="layui-btn layui-btn-xs {{ d.Class }} layui-btn-fluid" alt="{{ d.DomId }}"> <i class="layui-icon {{ d.Icon }}"></i> {{ d.Name }}</button>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!--模块添加/编辑窗口-->
|
||||
<div id="divEdit" style="display: none">
|
||||
<form class="layui-form layui-form-pane" action="" id="formEdit">
|
||||
<form class="layui-form layui-form-pane" action="" id="formEdit" lay-filter="formEdit">
|
||||
|
||||
<input type="hidden" name="Id" v-model="tmp.Id" />
|
||||
<input type="hidden" name="Id"/>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模块名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Name" v-model="tmp.Name" required lay-verify="required"
|
||||
<input type="text" name="Name" required lay-verify="required"
|
||||
placeholder="请输入模块名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">导航栏展示</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="Status" v-model="tmp.Status" required lay-verify="required">
|
||||
<option value="0" selected="selected" >正常</option>
|
||||
<select name="Status" required lay-verify="required">
|
||||
<option value="0" selected="selected">正常</option>
|
||||
<option value="-1">隐藏</option>
|
||||
</select>
|
||||
|
||||
@@ -103,27 +102,27 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模块标识</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Code" v-model="tmp.Code"
|
||||
<input type="text" name="Code"
|
||||
placeholder="比如:Module" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">URL地址</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Url" v-model="tmp.Url" required lay-verify="required"
|
||||
<input type="text" name="Url" required lay-verify="required"
|
||||
placeholder="请输入URL" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图标</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="IconName" name="IconName" v-model="tmp.IconName" lay-filter="iconPicker" class="layui-input">
|
||||
<input type="text" id="IconName" name="IconName" lay-filter="iconPicker" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="SortNo" v-model="tmp.SortNo" required lay-verify="required"
|
||||
<input type="text" name="SortNo" required lay-verify="required"
|
||||
placeholder="请输入排序号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
@@ -131,9 +130,8 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">所属模块</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="ParentName" name="ParentName" v-model="tmp.ParentName" class="layui-input" />
|
||||
<input id="ParentId" name="ParentId" v-model="tmp.ParentId" type="hidden" />
|
||||
|
||||
<input id="ParentName" name="ParentName" class="layui-input"/>
|
||||
<input id="ParentId" name="ParentId" type="hidden"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -148,15 +146,15 @@
|
||||
|
||||
<!--添加菜单窗口-->
|
||||
<div id="divMenuEdit" style="display: none">
|
||||
<form class="layui-form layui-form-pane" action="" id="mfromEdit">
|
||||
<form class="layui-form layui-form-pane" action="" id="mfromEdit" lay-filter="mfromEdit">
|
||||
|
||||
<input type="hidden" name="Id" v-model="tmp.Id" />
|
||||
<input type="hidden" name="ModuleId" v-model="tmp.ModuleId" />
|
||||
<input type="hidden" name="Id"/>
|
||||
<input type="hidden" name="ModuleId"/>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Name" v-model="tmp.Name" required lay-verify="required"
|
||||
<input type="text" name="Name" required lay-verify="required"
|
||||
placeholder="请输入名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
@@ -164,28 +162,28 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">DomId</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="DomId" v-model="tmp.DomId" required lay-verify="required"
|
||||
<input type="text" name="DomId" required lay-verify="required"
|
||||
placeholder="请输入DomId" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图标</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="Icon" name="Icon" v-model="tmp.Icon" lay-filter="btnIconPicker" class="layui-input">
|
||||
<input type="text" id="Icon" name="Icon" lay-filter="btnIconPicker" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">样式</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Class" v-model="tmp.Class"
|
||||
<input type="text" name="Class"
|
||||
placeholder="菜单的样式,如:layui-btn-danger" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Sort" v-model="tmp.Sort" required lay-verify="required"
|
||||
<input type="text" name="Sort" required lay-verify="required"
|
||||
placeholder="请输入排序号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
@@ -200,4 +198,4 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/layui/layui.js"></script>
|
||||
<script type="text/javascript" src="/userJs/modules.js"></script>
|
||||
<script type="text/javascript" src="/userJs/modules.js?v2"></script>
|
||||
@@ -56,21 +56,21 @@
|
||||
|
||||
<!--用户添加/编辑窗口-->
|
||||
<div id="divEdit" style="display: none">
|
||||
<form class="layui-form layui-form-pane" action="" id="formEdit">
|
||||
<form class="layui-form layui-form-pane" action="" id="formEdit" lay-filter="formEdit">
|
||||
|
||||
<input type="hidden" name="Id" v-model="tmp.Id" />
|
||||
<input type="hidden" name="Id" />
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">账号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Account" v-model="tmp.Account" required lay-verify="required"
|
||||
<input type="text" name="Account" required lay-verify="required"
|
||||
placeholder="请输入登录账号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">姓名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="Name" v-model="tmp.Name" required lay-verify="required"
|
||||
<input type="text" name="Name" required lay-verify="required"
|
||||
placeholder="请输入昵称或姓名" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,8 +78,8 @@
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">所属部门</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="Organizations" name="Organizations" v-model="tmp.Organizations" required lay-verify="required" class="layui-input" />
|
||||
<input id="OrganizationIds" name="OrganizationIds" v-model="tmp.OrganizationIds" required lay-verify="required" type="hidden" />
|
||||
<input id="Organizations" name="Organizations" required lay-verify="required" class="layui-input" />
|
||||
<input id="OrganizationIds" name="OrganizationIds" required lay-verify="required" type="hidden" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,14 +87,14 @@
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">性别</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="Sex" value="1" title="男" v-model="tmp.Sex" >
|
||||
<input type="radio" name="Sex" value="0" title="女" v-model="tmp.Sex" >
|
||||
<input type="radio" name="Sex" value="1" title="男" >
|
||||
<input type="radio" name="Sex" value="0" title="女" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">禁用</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="Status" v-model="tmp.Status" lay-skin="switch" value="1">
|
||||
<input type="checkbox" name="Status" lay-skin="switch" value="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
@@ -107,4 +107,4 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/layui/layui.js"></script>
|
||||
<script type="text/javascript" src="/userJs/users.js?v2.0"></script>
|
||||
<script type="text/javascript" src="/userJs/users.js?v3.0"></script>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -44,7 +44,7 @@ layui.config({
|
||||
var _hmt = _hmt || [];
|
||||
(function () {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "//hm.baidu.com/hm.js?0558502420ce5fee054b31425e77ffa6";
|
||||
hm.src = "https://hm.baidu.com/hm.js?93a7b9a145222f9b7109d643a0c58f8d";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
|
||||
@@ -1,62 +1,39 @@
|
||||
layui.config({
|
||||
base: "/js/"
|
||||
}).use(['form','vue', 'ztree', 'layer', 'jquery', 'table', 'droptree', 'openauth', 'iconPicker', 'utils'], function () {
|
||||
}).use(['form', 'ztree', 'layer', 'jquery', 'table', 'droptree', 'openauth', 'iconPicker', 'utils'], function () {
|
||||
var form = layui.form,
|
||||
layer = layui.layer,
|
||||
$ = layui.jquery;
|
||||
var iconPicker = layui.iconPicker;
|
||||
var btnIconPicker = layui.iconPicker;
|
||||
var vmMenu = new Vue({
|
||||
el: "#mfromEdit",
|
||||
data(){
|
||||
return {
|
||||
tmp: {}
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
tmp(val){
|
||||
this.$nextTick(function () {
|
||||
form.render(); //刷新select等
|
||||
btnIconPicker.checkIcon('btnIconPicker', this.tmp.Icon);
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
form.render();
|
||||
}
|
||||
});
|
||||
var vmModule = new Vue({
|
||||
el: "#formEdit",
|
||||
data(){
|
||||
return {
|
||||
tmp: {} //使用一个tmp封装一下,后面可以直接用vm.tmp赋值
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
tmp(val){
|
||||
this.$nextTick(function () {
|
||||
form.render(); //刷新select等
|
||||
layui.droptree("/UserSession/GetModules", "#ParentName", "#ParentId", false);
|
||||
|
||||
iconPicker.checkIcon('iconPicker', this.tmp.IconName);
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
form.render();
|
||||
layui.droptree("/UserSession/GetModules", "#ParentName", "#ParentId", false);
|
||||
}
|
||||
});
|
||||
var moduleInitVal = { //模块初始化的值
|
||||
Id: "",
|
||||
SortNo: 1,
|
||||
IconName: 'layui-icon-app',
|
||||
ParentId: '',
|
||||
ParentName: '',
|
||||
Name: '',
|
||||
Url: '',
|
||||
Status: 0,
|
||||
Remark: '',
|
||||
Code: ''
|
||||
};
|
||||
var menuInital={ //菜单初始化的值
|
||||
Id: "",
|
||||
ModuleId: "",
|
||||
Name:'',
|
||||
DomeId:'',
|
||||
Class:'',
|
||||
Sort: 1,
|
||||
Icon: 'layui-icon-app'
|
||||
}
|
||||
|
||||
iconPicker.render({
|
||||
// 选择器,推荐使用input
|
||||
elem: '#IconName',
|
||||
type: 'fontClass',
|
||||
// 每个图标格子的宽度:'43px'或'20%'
|
||||
cellWidth: '43px',
|
||||
// 点击回调
|
||||
click: function (data) {
|
||||
vmModule.tmp.IconName = data.icon;
|
||||
}
|
||||
});
|
||||
btnIconPicker.render({ //按钮的图标
|
||||
// 选择器,推荐使用input
|
||||
@@ -64,19 +41,15 @@ layui.config({
|
||||
type: 'fontClass',
|
||||
// 每个图标格子的宽度:'43px'或'20%'
|
||||
cellWidth: '43px',
|
||||
// 点击回调
|
||||
click: function (data) {
|
||||
vmMenu.tmp.Icon = data.icon;
|
||||
}
|
||||
});
|
||||
|
||||
var table = layui.table;
|
||||
var openauth = layui.openauth;
|
||||
|
||||
|
||||
$("#menus").loadMenus("Module");
|
||||
|
||||
//主列表加载,可反复调用进行刷新
|
||||
var config= {}; //table的参数,如搜索key,点击tree的id
|
||||
var config = {}; //table的参数,如搜索key,点击tree的id
|
||||
var mainList = function (options) {
|
||||
if (options != undefined) {
|
||||
$.extend(config, options);
|
||||
@@ -86,7 +59,7 @@ layui.config({
|
||||
where: config
|
||||
, response: {
|
||||
statusCode: 200 //规定成功的状态码,默认:0
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,7 +74,7 @@ layui.config({
|
||||
where: menucon
|
||||
, response: {
|
||||
statusCode: 200 //规定成功的状态码,默认:0
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -110,7 +83,7 @@ layui.config({
|
||||
var url = '/UserSession/GetModules';
|
||||
var zTreeObj;
|
||||
var setting = {
|
||||
view: { selectedMulti: false },
|
||||
view: {selectedMulti: false},
|
||||
data: {
|
||||
key: {
|
||||
name: 'Name',
|
||||
@@ -125,17 +98,17 @@ layui.config({
|
||||
},
|
||||
callback: {
|
||||
onClick: function (event, treeId, treeNode) {
|
||||
mainList({ pId: treeNode.Id });
|
||||
mainList({pId: treeNode.Id});
|
||||
}
|
||||
}
|
||||
};
|
||||
var load = function () {
|
||||
$.getJSON(url, function (json) {
|
||||
zTreeObj = $.fn.zTree.init($("#tree"), setting);
|
||||
var newNode = { Name: "根节点", Id: null, ParentId: "" };
|
||||
var newNode = {Name: "根节点", Id: null, ParentId: ""};
|
||||
json.Result.push(newNode);
|
||||
zTreeObj.addNodes(null, json.Result);
|
||||
mainList({ pId: "" });
|
||||
mainList({pId: ""});
|
||||
zTreeObj.expandAll(true);
|
||||
});
|
||||
};
|
||||
@@ -146,35 +119,35 @@ layui.config({
|
||||
}();
|
||||
$("#tree").height($("div.layui-table-view").height());
|
||||
//添加(编辑)模块对话框
|
||||
var editDlg = function() {
|
||||
var update = false; //是否为更新
|
||||
var show = function (data) {
|
||||
var editDlg = function () {
|
||||
var show = function (update, data) {
|
||||
var title = update ? "编辑信息" : "添加";
|
||||
layer.open({
|
||||
title: title,
|
||||
area: ["500px", "480px"],
|
||||
type: 1,
|
||||
content: $('#divEdit'),
|
||||
success: function() {
|
||||
if(data.Id ==''){
|
||||
for(var key in vmModule.tmp){
|
||||
delete vmModule.tmp[key];
|
||||
}
|
||||
success: function () {
|
||||
layui.droptree("/UserSession/GetModules", "#ParentName", "#ParentId", false);
|
||||
if (data == undefined) {
|
||||
form.val("formEdit", moduleInitVal);
|
||||
} else {
|
||||
form.val("formEdit", data);
|
||||
iconPicker.checkIcon('iconPicker', data.IconName);
|
||||
}
|
||||
vmModule.tmp = Object.assign({}, vmModule.tmp,data)
|
||||
},
|
||||
end: mainList
|
||||
});
|
||||
var url = "/moduleManager/Add";
|
||||
if (update) {
|
||||
url = "/moduleManager/Update";
|
||||
url = "/moduleManager/Update";
|
||||
}
|
||||
//提交数据
|
||||
form.on('submit(formSubmit)',
|
||||
function(data) {
|
||||
function (data) {
|
||||
$.post(url,
|
||||
data.field,
|
||||
function(data) {
|
||||
function (data) {
|
||||
layer.msg(data.Message);
|
||||
if ((!update) && data.Code == 200) { //添加成功要刷新左边的树
|
||||
ztree.reload();
|
||||
@@ -185,25 +158,18 @@ layui.config({
|
||||
});
|
||||
}
|
||||
return {
|
||||
add: function() { //弹出添加
|
||||
update = false;
|
||||
show({
|
||||
Id: "",
|
||||
SortNo: 1,
|
||||
IconName:'layui-icon-app'
|
||||
});
|
||||
add: function () { //弹出添加
|
||||
show(false);
|
||||
},
|
||||
update: function(data) { //弹出编辑框
|
||||
update = true;
|
||||
show(data);
|
||||
update: function (data) { //弹出编辑框
|
||||
show(true,data);
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
//添加菜单对话框
|
||||
var meditDlg = function () {
|
||||
var update = false; //是否为更新
|
||||
var show = function (data) {
|
||||
var show = function (update, data) {
|
||||
var title = update ? "编辑信息" : "添加";
|
||||
layer.open({
|
||||
title: title,
|
||||
@@ -211,12 +177,12 @@ layui.config({
|
||||
type: 1,
|
||||
content: $('#divMenuEdit'),
|
||||
success: function () {
|
||||
if(data.Id ==''){
|
||||
for(var key in vmMenu.tmp){
|
||||
delete vmMenu.tmp[key];
|
||||
}
|
||||
if (data == undefined) {
|
||||
form.val("mfromEdit", menuInital);
|
||||
} else {
|
||||
form.val("mfromEdit", data);
|
||||
btnIconPicker.checkIcon('btnIconPicker', data.Icon);
|
||||
}
|
||||
vmMenu.tmp = Object.assign({}, vmMenu.tmp,data)
|
||||
},
|
||||
end: menuList
|
||||
});
|
||||
@@ -238,24 +204,17 @@ layui.config({
|
||||
}
|
||||
return {
|
||||
add: function (moduleId) { //弹出添加
|
||||
update = false;
|
||||
show({
|
||||
Id: "",
|
||||
ModuleId:moduleId,
|
||||
Sort: 1,
|
||||
Icon:'layui-icon-app'
|
||||
});
|
||||
show(false);
|
||||
},
|
||||
update: function (data) { //弹出编辑框
|
||||
update = true;
|
||||
show(data);
|
||||
show(true,data);
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
//监听行单击事件
|
||||
table.on('row(list)', function(obj){
|
||||
menuList({moduleId:obj.data.Id});
|
||||
table.on('row(list)', function (obj) {
|
||||
menuList({moduleId: obj.data.Id});
|
||||
});
|
||||
|
||||
//监听页面主按钮操作
|
||||
@@ -264,7 +223,9 @@ layui.config({
|
||||
var checkStatus = table.checkStatus('mainList')
|
||||
, data = checkStatus.data;
|
||||
openauth.del("/moduleManager/Delete",
|
||||
data.map(function (e) { return e.Id; }),
|
||||
data.map(function (e) {
|
||||
return e.Id;
|
||||
}),
|
||||
function () {
|
||||
mainList();
|
||||
ztree.reload();
|
||||
@@ -274,7 +235,9 @@ layui.config({
|
||||
var checkStatus = table.checkStatus('menuList')
|
||||
, data = checkStatus.data;
|
||||
openauth.del("/moduleManager/DelMenu",
|
||||
data.map(function (e) { return e.Id; }),
|
||||
data.map(function (e) {
|
||||
return e.Id;
|
||||
}),
|
||||
menuList);
|
||||
}
|
||||
, btnAdd: function () { //添加模块
|
||||
@@ -289,15 +252,15 @@ layui.config({
|
||||
}
|
||||
meditDlg.add(data[0].Id);
|
||||
}
|
||||
, btnEdit: function () { //编辑
|
||||
var checkStatus = table.checkStatus('mainList')
|
||||
, data = checkStatus.data;
|
||||
if (data.length != 1) {
|
||||
layer.msg("请选择编辑的行,且同时只能编辑一行");
|
||||
return;
|
||||
}
|
||||
editDlg.update(data[0]);
|
||||
}
|
||||
, btnEdit: function () { //编辑
|
||||
var checkStatus = table.checkStatus('mainList')
|
||||
, data = checkStatus.data;
|
||||
if (data.length != 1) {
|
||||
layer.msg("请选择编辑的行,且同时只能编辑一行");
|
||||
return;
|
||||
}
|
||||
editDlg.update(data[0]);
|
||||
}
|
||||
|
||||
, btnEditMenu: function () { //编辑菜单
|
||||
var checkStatus = table.checkStatus('menuList')
|
||||
@@ -310,9 +273,9 @@ layui.config({
|
||||
}
|
||||
|
||||
, search: function () { //搜索
|
||||
mainList({ key: $('#key').val() });
|
||||
mainList({key: $('#key').val()});
|
||||
}
|
||||
, btnRefresh: function() {
|
||||
, btnRefresh: function () {
|
||||
mainList();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,6 +7,16 @@ layui.config({
|
||||
var table = layui.table;
|
||||
var openauth = layui.openauth;
|
||||
var toplayer = (top == undefined || top.layer === undefined) ? layer : top.layer; //顶层的LAYER
|
||||
|
||||
var initVal = { //初始化数据
|
||||
Id: '',
|
||||
Account:'',
|
||||
Name:'',
|
||||
Organizations:'',
|
||||
OrganizationIds:'',
|
||||
Sex:'',
|
||||
Status:0
|
||||
};
|
||||
|
||||
$("#menus").loadMenus("User");
|
||||
|
||||
@@ -68,9 +78,7 @@ layui.config({
|
||||
|
||||
//添加(编辑)对话框
|
||||
var editDlg = function() {
|
||||
var vm;
|
||||
var update = false; //是否为更新
|
||||
var show = function (data) {
|
||||
var show = function (update, data) {
|
||||
var title = update ? "编辑信息" : "添加";
|
||||
layer.open({
|
||||
title: title,
|
||||
@@ -78,34 +86,18 @@ layui.config({
|
||||
type: 1,
|
||||
content: $('#divEdit'),
|
||||
success: function() {
|
||||
if(vm == undefined){
|
||||
vm = new Vue({
|
||||
el: "#formEdit",
|
||||
data(){
|
||||
return {
|
||||
tmp:data //使用一个tmp封装一下,后面可以直接用vm.tmp赋值
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
tmp(val){
|
||||
this.$nextTick(function () {
|
||||
form.render(); //刷新select等
|
||||
//layui.droptree("/UserSession/GetOrgs", "#Organizations", "#OrganizationIds");
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
form.render();
|
||||
var _this = this;
|
||||
layui.droptree("/UserSession/GetOrgs", "#Organizations", "#OrganizationIds", true,function (ids, names) {
|
||||
_this.tmp.OrganizationIds = ids;
|
||||
_this.tmp.Organizations = names;
|
||||
});
|
||||
}
|
||||
if (data == undefined) {
|
||||
form.val("formEdit", initVal);
|
||||
} else {
|
||||
layui.droptree("/UserSession/GetOrgs", "#Organizations", "#OrganizationIds", true,function (ids, names) {
|
||||
form.val("formEdit", {
|
||||
Organizations: names,
|
||||
OrganizationIds: ids
|
||||
});
|
||||
});
|
||||
}else{
|
||||
vm.tmp = Object.assign({}, vm.tmp,data)
|
||||
}
|
||||
form.val("formEdit", data);
|
||||
|
||||
}
|
||||
},
|
||||
end: mainList
|
||||
});
|
||||
@@ -127,22 +119,15 @@ layui.config({
|
||||
|
||||
//重置
|
||||
$("#reset").click(function(){
|
||||
vm.tmp = {
|
||||
OrganizationIds:'',
|
||||
Organizations:''
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
return {
|
||||
add: function() { //弹出添加
|
||||
update = false;
|
||||
show({
|
||||
Id: ''
|
||||
});
|
||||
show(false);
|
||||
},
|
||||
update: function(data) { //弹出编辑框
|
||||
update = true;
|
||||
show(data);
|
||||
show(true,data);
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace OpenAuth.Repository.Domain
|
||||
/// 前端界面是否缓存
|
||||
/// </summary>
|
||||
/// [Description("前端界面是否缓存")]
|
||||
public bool KeepAlive { get; set; }
|
||||
public bool? KeepAlive { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,29 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Infrastructure;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Utilities;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using OpenAuth.Repository.Domain;
|
||||
using OpenAuth.Repository.QueryObj;
|
||||
|
||||
namespace OpenAuth.Repository
|
||||
{
|
||||
|
||||
public partial class OpenAuthDBContext : DbContext
|
||||
{
|
||||
|
||||
private ILoggerFactory _LoggerFactory;
|
||||
private IHttpContextAccessor _httpContextAccessor;
|
||||
private IConfiguration _configuration;
|
||||
private IOptions<AppSetting> _appConfiguration;
|
||||
|
||||
public OpenAuthDBContext(DbContextOptions<OpenAuthDBContext> options, ILoggerFactory loggerFactory,
|
||||
IHttpContextAccessor httpContextAccessor, IConfiguration configuration, IOptions<AppSetting> appConfiguration)
|
||||
IHttpContextAccessor httpContextAccessor, IConfiguration configuration,
|
||||
IOptions<AppSetting> appConfiguration)
|
||||
: base(options)
|
||||
{
|
||||
_LoggerFactory = loggerFactory;
|
||||
@@ -37,7 +34,7 @@ namespace OpenAuth.Repository
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.EnableSensitiveDataLogging(true); //允许打印参数
|
||||
optionsBuilder.EnableSensitiveDataLogging(true); //允许打印参数
|
||||
optionsBuilder.UseLoggerFactory(_LoggerFactory);
|
||||
InitTenant(optionsBuilder);
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
@@ -46,10 +43,9 @@ namespace OpenAuth.Repository
|
||||
//初始化多租户信息,根据租户id调整数据库
|
||||
private void InitTenant(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
|
||||
var tenantId = _httpContextAccessor.GetTenantId();
|
||||
string connect = _configuration.GetConnectionString(tenantId);
|
||||
if(string.IsNullOrEmpty(connect))
|
||||
if (string.IsNullOrEmpty(connect))
|
||||
{
|
||||
throw new Exception($"未能找到租户{tenantId}对应的连接字符串信息");
|
||||
}
|
||||
@@ -59,15 +55,15 @@ namespace OpenAuth.Repository
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
var dbType = dbtypes[tenantId];
|
||||
if(dbType == Define.DBTYPE_SQLSERVER)
|
||||
if (dbType == Define.DBTYPE_SQLSERVER)
|
||||
{
|
||||
optionsBuilder.UseSqlServer(connect);
|
||||
}
|
||||
else if(dbType == Define.DBTYPE_MYSQL) //mysql
|
||||
else if (dbType == Define.DBTYPE_MYSQL) //mysql
|
||||
{
|
||||
optionsBuilder.UseMySql(connect, new MySqlServerVersion(new Version(8, 0, 11)));
|
||||
}
|
||||
else if(dbType == Define.DBTYPE_PostgreSQL) //PostgreSQL
|
||||
else if (dbType == Define.DBTYPE_PostgreSQL) //PostgreSQL
|
||||
{
|
||||
optionsBuilder.UseNpgsql(connect);
|
||||
}
|
||||
@@ -75,15 +71,33 @@ namespace OpenAuth.Repository
|
||||
{
|
||||
optionsBuilder.UseOracle(connect, options => options.UseOracleSQLCompatibility("11"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<DataPrivilegeRule>()
|
||||
.HasKey(c => new { c.Id });
|
||||
.HasKey(c => new {c.Id});
|
||||
modelBuilder.Entity<SysTableColumn>().HasNoKey();
|
||||
modelBuilder.Entity<QueryStringObj>().HasNoKey();
|
||||
|
||||
//converting between PostgreSQL smallint and .NET Boolean types
|
||||
if (Database.ProviderName == "Npgsql.EntityFrameworkCore.PostgreSQL"
|
||||
|| Database.ProviderName == "Oracle.EntityFrameworkCore")
|
||||
{
|
||||
var boolToSmallIntConverter = new ValueConverter<bool, short>(
|
||||
v => v ? (short) 1 : (short) 0,
|
||||
v => v != 0);
|
||||
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||||
{
|
||||
foreach (var property in entityType.GetProperties())
|
||||
{
|
||||
if (property.ClrType == typeof(bool))
|
||||
{
|
||||
property.SetValueConverter(boolToSmallIntConverter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual DbSet<Application> Applications { get; set; }
|
||||
@@ -112,13 +126,11 @@ namespace OpenAuth.Repository
|
||||
public virtual DbSet<WmsInboundOrderTbl> WmsInboundOrderTbls { get; set; }
|
||||
public virtual DbSet<OpenJob> OpenJobs { get; set; }
|
||||
public virtual DbSet<BuilderTable> BuilderTables { get; set; }
|
||||
|
||||
public virtual DbSet<BuilderTableColumn> BuilderTableColumns { get; set; }
|
||||
|
||||
//非数据库表格
|
||||
public virtual DbSet<QueryStringObj> QueryStringObjs { get; set; }
|
||||
public virtual DbSet<SysTableColumn> SysTableColumns { get; set; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ namespace OpenAuth.Repository.Test
|
||||
[Test]
|
||||
public void TestDynamic()
|
||||
{
|
||||
FilterGroup sub = new FilterGroup
|
||||
QueryObject sub = new QueryObject
|
||||
{
|
||||
Operation = "or"
|
||||
};
|
||||
@@ -69,24 +69,24 @@ namespace OpenAuth.Repository.Test
|
||||
new Filter {Key = "Sex", Value = "10", Contrast = "=="}
|
||||
};
|
||||
|
||||
FilterGroup filterGroup = new FilterGroup
|
||||
QueryObject queryObject = new QueryObject
|
||||
{
|
||||
Operation = "and"
|
||||
};
|
||||
filterGroup.Filters = new[]
|
||||
queryObject.Filters = new[]
|
||||
{
|
||||
new Filter {Key = "Account", Value = "name", Contrast = "=="},
|
||||
new Filter {Key = "Password", Value = "10", Contrast = "=="}
|
||||
};
|
||||
|
||||
filterGroup.Children = new[]
|
||||
queryObject.Children = new[]
|
||||
{
|
||||
sub
|
||||
};
|
||||
|
||||
var dbcontext = _autofacServiceProvider.GetService<OpenAuthDBContext>();
|
||||
|
||||
var query = dbcontext.Users.GenerateFilter("c",JsonHelper.Instance.Serialize(filterGroup));
|
||||
var query = dbcontext.Users.GenerateFilter("c",JsonHelper.Instance.Serialize(queryObject));
|
||||
Console.WriteLine(query.Expression.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace OpenAuth.Repository.Test
|
||||
[Test]
|
||||
public void TestDynamic()
|
||||
{
|
||||
FilterGroup sub = new FilterGroup
|
||||
QueryObject sub = new QueryObject
|
||||
{
|
||||
Operation = "or"
|
||||
};
|
||||
@@ -83,24 +83,24 @@ namespace OpenAuth.Repository.Test
|
||||
new Filter {Key = "Sex", Value = "10", Contrast = "=="}
|
||||
};
|
||||
|
||||
FilterGroup filterGroup = new FilterGroup
|
||||
QueryObject queryObject = new QueryObject
|
||||
{
|
||||
Operation = "and"
|
||||
};
|
||||
filterGroup.Filters = new[]
|
||||
queryObject.Filters = new[]
|
||||
{
|
||||
new Filter {Key = "Account", Value = "name", Contrast = "=="},
|
||||
new Filter {Key = "Password", Value = "10", Contrast = "=="}
|
||||
};
|
||||
|
||||
filterGroup.Children = new[]
|
||||
queryObject.Children = new[]
|
||||
{
|
||||
sub
|
||||
};
|
||||
|
||||
var sugarClient = _autofacServiceProvider.GetService<ISqlSugarClient>();
|
||||
|
||||
var query = sugarClient.Queryable<User>().GenerateFilter("c",filterGroup);
|
||||
var query = sugarClient.Queryable<User>().GenerateFilter("c",queryObject);
|
||||
Console.WriteLine(query.ToSqlString());
|
||||
}
|
||||
}
|
||||
|
||||
31
README.md
31
README.md
@@ -1,18 +1,5 @@
|
||||
🔥.Net权限管理及快速开发框架、最好用的权限工作流系统。源于Martin Fowler企业级应用开发思想及最新技术组合(SqlSugar、EF、Quartz、AutoFac、WebAPI、Swagger、Mock、NUnit、Vue2/3、Element-ui/plus、IdentityServer等)。核心模块包括:角色授权、代码生成、智能打印、表单设计、工作流、定时任务等。架构易扩展,是中小企业的首选。
|
||||
|
||||
## ❤❤❤郑重声明❤❤❤
|
||||
|
||||
主分支main运行环境默认为.Net SDK 6.0,如果你使用vs2019作为开发工具,请注意查看:[VS2019打开6.0及以后版本](http://doc.openauth.net.cn/core/faq.html#vs2019%E6%89%93%E5%BC%806-0%E5%8F%8A%E4%BB%A5%E5%90%8E%E7%89%88%E6%9C%AC)
|
||||
|
||||
需要.Net SDK 4.0/4.5开发环境的同学请查看本项目4.0分支,已停止维护
|
||||
|
||||
使用.Net Core 2.1--3.1的请看:
|
||||
|
||||
**GitHub** https://github.com/yubaolee/OpenAuth.Core
|
||||
|
||||
**码云** https://gitee.com/yubaolee/OpenAuth.Core
|
||||
|
||||
|
||||

|
||||
|
||||
**logo图标含义** OpenAuth中OA字母的结合体;整体像鱼,授人以渔;你非说像咸鱼,那也是积极向上的咸鱼;中心是个笑脸,微笑面对生活(✿◡‿◡)。
|
||||
@@ -21,7 +8,6 @@
|
||||
|
||||
**官方文档** http://doc.openauth.net.cn
|
||||
|
||||
|
||||

|
||||

|
||||

|
||||
@@ -41,6 +27,23 @@
|
||||

|
||||

|
||||
|
||||
## ❤❤❤郑重声明❤❤❤
|
||||
|
||||
主分支main运行环境默认为.Net SDK 6.0,支持.NET未来版本,需要.Net SDK 4.0/4.5开发环境的同学请查看本项目4.0分支,已停止维护
|
||||
|
||||
使用.Net Core 2.1-3.1的请进:https://gitee.com/yubaolee/OpenAuth.Core ,已停止维护
|
||||
|
||||
## OpenAuth.Net系列视频火热更新中
|
||||
|
||||
[OpenAuth.Net视频合集--系统结构及代码下载](https://www.bilibili.com/video/BV1Z1421q7xU/)
|
||||
|
||||
[OpenAuth.Net视频合集--基于RBAC体系的权限管理介绍](https://www.bilibili.com/video/BV1M9KeejENf/)
|
||||
|
||||
[OpenAuth.Net视频合集--企业版代码启动](https://www.bilibili.com/video/BV1KSuQebEek/)
|
||||
|
||||
[OpenAuth.Net视频合集--使用企业版代码生成器](https://www.bilibili.com/video/BV1JCuyeaEFp/)
|
||||
|
||||
[OpenAuth.Net视频合集--表单设计](https://www.bilibili.com/video/BV1dagEeFEVA/)
|
||||
|
||||
|
||||
## 关于OpenAuth.Net企业版/高级版的说明:
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/*
|
||||
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
|
||||
* @Date: 2023-08-12 10:48:24
|
||||
* @LastEditTime: 2023-12-30 21:10:18
|
||||
* @LastEditTime: 2024-06-19 20:48:12
|
||||
* @Description:
|
||||
* @
|
||||
* @Copyright (c) 2023 by yubaolee | ahfu~ , All Rights Reserved.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
title: 'OpenAuth.Net',
|
||||
description: '最好用的.net权限工作流框架,最好用的.net vue前后分离框架',
|
||||
@@ -13,7 +14,15 @@ module.exports = {
|
||||
['link', {
|
||||
rel: 'icon',
|
||||
href: '/logo.png'
|
||||
}]
|
||||
}],['script',{},
|
||||
`var _hmt = _hmt || [];
|
||||
(function () {
|
||||
var hm = document.createElement('script')
|
||||
hm.src = 'https://hm.baidu.com/hm.js?93a7b9a145222f9b7109d643a0c58f8d'
|
||||
var s = document.getElementsByTagName('script')[0]
|
||||
s.parentNode.insertBefore(hm, s)
|
||||
})();
|
||||
`]
|
||||
],
|
||||
extendMarkdown: (md) => {
|
||||
md.set({
|
||||
|
||||
28
docs/.vuepress/enhanceApp.js
Normal file
28
docs/.vuepress/enhanceApp.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
|
||||
* @Date: 2024-06-19 20:41:42
|
||||
* @LastEditTime: 2024-06-19 20:48:04
|
||||
* @Description:
|
||||
* @
|
||||
* @Copyright (c) 2024 by yubaolee | ahfu~ , All Rights Reserved.
|
||||
*/
|
||||
// .vuepress/enhanceApp.js
|
||||
export default ({ router }) => {
|
||||
if (process.env.NODE_ENV === 'production' && typeof window !== 'undefined') {
|
||||
// 百度统计代码
|
||||
var _hmt = _hmt || []
|
||||
;(function () {
|
||||
var hm = document.createElement('script')
|
||||
hm.src = 'https://hm.baidu.com/hm.js?93a7b9a145222f9b7109d643a0c58f8d'
|
||||
var s = document.getElementsByTagName('script')[0]
|
||||
s.parentNode.insertBefore(hm, s)
|
||||
})();
|
||||
|
||||
// 路由切换时触发百度统计
|
||||
router.afterEach(function (to) {
|
||||
if (window._hmt) {
|
||||
window._hmt.push(['_trackPageview', to.fullPath])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,18 @@ CodeSmith Generator Studio 8.0或以上
|
||||
|
||||
如下图,使用CodeSmith文件夹中的模板,右击【ApiGenerate.cst】--【Execute】,选择需要生成的表(本文以Stock为例)及相关的上下文命名空间,点击【Generate】
|
||||
|
||||

|
||||

|
||||
|
||||
注意,有两个配置项:
|
||||
|
||||
* WholeDb: 如果选中,则按数据库中所有表生成实体及逻辑;否则,按选择的表生成
|
||||
|
||||
* HeaderModel:会生成主、从表结构,类似 WmsInboundOrderTbl / WmsInboundOrderDtbl
|
||||
|
||||
|
||||
生成成功后,在CodeSmith/Csharp文件夹下面会有Stock实体相关文档,如下图:
|
||||
|
||||

|
||||

|
||||
|
||||
把CSharp\OpenAuth.App覆盖到自己项目对应目录
|
||||
|
||||
@@ -51,7 +58,6 @@ CodeSmith Generator Studio 8.0或以上
|
||||
|
||||
**把CSharp\OpenAuth.Repository\OpenAuthDBContext.cs中的内容添加到自己项目的文件中,千万不要直接覆盖文件!!!**
|
||||
|
||||
**其他文件夹的内容为WebAPI项目使用,可以不管。**
|
||||
|
||||
## 添加界面
|
||||
|
||||
@@ -69,7 +75,15 @@ userJs直接覆盖到OpenAuth.Mvc/wwwroot中
|
||||
|
||||
## 添加模块
|
||||
|
||||
编写完上面代码后,运行系统,使用System账号登录系统,在【模块管理】中,添加`仓储管理`模块,并为它添加菜单,这里我只添加一个菜单【btnAdd】,如下图:
|
||||
编写完上面代码后,运行系统,使用System账号登录系统,在【模块管理】中,添加`仓储管理`模块,
|
||||
|
||||

|
||||
|
||||
::: warning 注意
|
||||
因为生成的Controller名称类似XXXsController,所以模块的Url地址应该是XXXs/Index
|
||||
:::
|
||||
|
||||
并为它添加菜单,这里我只添加一个菜单【btnAdd】,如下图:
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
# 概念
|
||||
|
||||
## 会签
|
||||
|
||||
会签又称为联名签署,指需要得到两个或多个相关参与者的签名批准。目前支持两种模式:全部通过和至少一个通过,在【会签开始】节点进行配置。如下:
|
||||

|
||||
|
||||
全部通过:会签中的所有人员都通过,节点审批通过。
|
||||
|
||||
至少一个通过:会签中任何一个人通过,节点即审批通过。
|
||||
|
||||
具体的会签人员或角色,需要在【会签开始】和【会签结束】之间的连线配置,如上图中的admin、test。
|
||||
|
||||
::: warning 特别注意
|
||||
|
||||
【会签开始】【会签结束】执行权限配置为所有人
|
||||
|
||||
会签不能在分支上加判断条件
|
||||
:::
|
||||
|
||||
## 条件分支
|
||||
|
||||
有时需要根据提交数据不同(如报销金额、请假天数等)流程转向不同的审批者。这时需要在连线上面配置分支条件,如下图:
|
||||
|
||||

|
||||
|
||||
# 基本操作
|
||||
|
||||
一个完整的工作流包括流程设计及流程实例处理。分别对应系统中【基础配置/流程设计】及【流程中心】两个板块。具体包含以下几个步骤:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
OpenAuth.Pro是一套全新的前端界面,基于vue-element-admin,采用VUE全家桶(VUE+VUEX+VUE-ROUTER)单页面SPA开发。它使用开源版OpenAuth.Net的API接口(即:OpenAuth.WebApi)提供数据服务。二者的关系如下:
|
||||
|
||||

|
||||

|
||||
|
||||
企业版代码获取方式:[http://www.openauth.net.cn/question/detail.html?id=a2be2d61-7fcb-4df8-8be2-9f296c22a89c](http://www.openauth.net.cn/question/detail.html?id=a2be2d61-7fcb-4df8-8be2-9f296c22a89c)
|
||||
|
||||
@@ -8,6 +8,16 @@ OpenAuth.Pro是一套全新的前端界面,基于vue-element-admin,采用VUE
|
||||
|
||||
企业H5版本演示(请使用浏览器移动模式或直接用手机打开):[http://demo.openauth.net.cn:1804/](http://demo.openauth.net.cn:1804/)
|
||||
|
||||
## OpenAuth.Net系列教学视频
|
||||
|
||||
[OpenAuth.Net视频合集--系统结构及代码下载](https://www.bilibili.com/video/BV1Z1421q7xU/)
|
||||
|
||||
[OpenAuth.Net视频合集--企业版代码启动](https://www.bilibili.com/video/BV1KSuQebEek/)
|
||||
|
||||
[OpenAuth.Net视频合集--使用企业版代码生成器](https://www.bilibili.com/video/BV1JCuyeaEFp/)
|
||||
|
||||
[OpenAuth.Net视频合集--权限管理介绍](https://www.bilibili.com/video/BV1M9KeejENf/)
|
||||
|
||||
|
||||
## 工具准备
|
||||
|
||||
@@ -60,19 +70,24 @@ OpenAuth.Pro v4.3及以前的版本使用Node 14
|
||||
|
||||
:::
|
||||
|
||||
使用npm run dev 命令运行。如下图:
|
||||

|
||||
|
||||
启动成功后,使用浏览器访问[http://localhost:1803/](http://localhost:1803/) 即可打开企业版界面
|
||||
|
||||
::: warning 注意事项
|
||||
开发环境配置文件为`.env.dev`,调试前请调整为自己的接口地址:
|
||||
修改配置文件`.env.dev`对应的后端接口地址,调整为自己的接口地址:
|
||||
|
||||
```javascript
|
||||
VUE_APP_BASE_API = http://localhost:52789/api
|
||||
VUE_APP_BASE_IMG_URL = http://localhost:52789
|
||||
```
|
||||
|
||||
::: warning 注意事项
|
||||
如果是发布打包,调整的文件为`.env.prod`
|
||||
:::
|
||||
|
||||
使用npm run dev 命令运行。如下图:
|
||||

|
||||
|
||||
启动成功后,使用浏览器访问[http://localhost:1803/](http://localhost:1803/) 即可打开企业版界面
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# 企业版代码生成器
|
||||
|
||||
本章节视频讲解请参考:[OpenAuth.Net视频合集--使用企业版代码生成器](https://www.bilibili.com/video/BV1JCuyeaEFp/)
|
||||
|
||||
## 术语解释
|
||||
|
||||
在添加新功能之前,需要先了解OpenAuth.Net生成代码时的两个概念:动态头部和固定头部
|
||||
@@ -49,17 +51,21 @@ initCfg() {
|
||||
-- mysql示例
|
||||
create table stock
|
||||
(
|
||||
createtime datetime not null comment '操作时间',
|
||||
status int not null comment '出库/入库',
|
||||
price decimal(10, 1) not null comment '产品单价',
|
||||
number int not null comment '产品数量',
|
||||
name text not null comment '产品名称',
|
||||
orgid varchar(50) null comment '组织ID',
|
||||
user varchar(50) not null comment '操作人',
|
||||
viewable varchar(50) not null comment '可见范围',
|
||||
id varchar(50) not null comment '数据ID'
|
||||
primary key
|
||||
Id varchar(50) not null comment '数据ID'
|
||||
primary key,
|
||||
Name text not null comment '产品名称',
|
||||
Number int not null comment '产品数量',
|
||||
Price decimal(10, 1) not null comment '产品单价',
|
||||
Status int not null comment '出库/入库',
|
||||
Viewable varchar(50) not null comment '可见范围',
|
||||
User varchar(50) not null comment '操作人',
|
||||
Time datetime not null comment '操作时间',
|
||||
OrgId varchar(50) null comment '组织ID'
|
||||
)
|
||||
comment '出入库信息表' charset = utf8
|
||||
row_format = COMPACT;
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
@@ -80,6 +86,7 @@ create table stock
|
||||
|
||||
这时,编辑字段具体的属性。如是否【可显示】【可编辑】等。
|
||||
|
||||
|
||||
## 子表添加
|
||||
|
||||
::: warning 注意
|
||||
@@ -135,6 +142,10 @@ src\views\stocks\index.vue
|
||||
|
||||

|
||||
|
||||
## 其他
|
||||
|
||||
当采用动态头部时,如果数据库新加了字段,需要使用【同步结构】功能把新字段同步到代码生成器中。为了防止对已有的配置造成影响,该功能只新增字段,不会对已有字段进行调整。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user