14 Commits

Author SHA1 Message Date
yubaolee
d2c8f783e1 🔄refactor: 调整为SqlSugar 2026-05-24 23:34:27 +08:00
yubaolee
237fc49f2f 调整为Sqlsugar 2026-05-24 21:28:25 +08:00
yubaolee
684b6e0fea 调整为SqlSugar 2026-05-24 21:20:08 +08:00
yubaolee
ea658e3cba Merge branch 'main' of https://gitee.com/dotnetchina/OpenAuth.Net into main 2026-05-24 20:04:56 +08:00
yubaolee
92eda330e5 增加通用skills 2026-05-24 20:04:35 +08:00
yubaolee
aac40f9e67 🐛fix: #IDJIPY 修复字典排序 2026-01-16 14:40:33 +08:00
yubaolee
ad18885596 🐛fix: #IDJIPY 删除全部部门提示异常 2026-01-15 17:33:02 +08:00
yubaolee
6302ad4bca 🐛fix: #ICZD3Z 2026-01-10 13:46:31 +08:00
yubaolee
f30fe5e11d 🐛fix: #ICZD3Z 2026-01-10 11:15:33 +08:00
wintel
ac49f0e80f 🐛fix: issue #IDAVK1 自定义表单在流程中无法编辑 2025-12-21 17:40:21 +08:00
yubaolee
7d94137b44 🐛fix: 修复动态API大小写问题 2025-11-30 21:27:19 +08:00
yubaolee
fb7c1392a1 🐛fix: 动态API参数大小写的问题 2025-11-30 21:22:10 +08:00
wintel
7cd738e7a7 📃docs: 增加vform字段校验 2025-11-23 22:33:10 +08:00
yubaolee
e86be33910 🐛fix: #ID7OD0 frmDataJson被意外清空 2025-11-21 20:21:52 +08:00
23 changed files with 980 additions and 364 deletions

View File

@@ -1,33 +1,7 @@
---
alwaysApply: false
name: dev
description: OpenAuth.Net开发规范
---
# OpenAuth.Net Cursor Rules
## 项目概述
OpenAuth.Net是一个基于.NET 9的企业级权限管理和快速开发框架采用Martin Fowler企业级应用开发思想集成了最新的技术栈。
## 技术栈
- **后端**: .NET 9, ASP.NET Core WebAPI
- **ORM**: SqlSugar (主要) + Entity Framework Core (兼容)
- **依赖注入**: Autofac
- **数据库**: 支持SqlServer、MySQL、Oracle、PostgreSQL
- **定时任务**: Quartz.NET
- **缓存**: Redis, MemoryCache
- **前端**: Vue2 + Element-UI
- **测试**: NUnit
- **文档**: Swagger
## 项目架构
```
📦OpenAuth.Net
┣ 📂Infrastructure # 基础设施层 - 工具类、扩展方法、帮助类
┣ 📂OpenAuth.Repository # 数据访问层 - 实体定义、数据访问
┣ 📂OpenAuth.App # 应用服务层 - 业务逻辑
┣ 📂OpenAuth.WebApi # 表示层 - WebAPI控制器
┣ 📂OpenAuth.Identity # 身份认证服务 - IdentityServer4
┣ 📂Vue2 # 前端项目
┗ 📂数据库脚本 # 数据库初始化脚本
```
## 编码规范
@@ -54,7 +28,33 @@ OpenAuth.Net是一个基于.NET 9的企业级权限管理和快速开发框架
- 复杂业务逻辑必须添加行内注释
- 使用/// <summary>标记方法说明
- 参数使用/// <param name="参数名">说明</param>
- 返回值使用/// <returns>说明</returns>
- 返回值使用/// <returns>说明</returns>
## 项目概述
OpenAuth.Net是一个基于.NET 9的企业级权限管理和快速开发框架采用Martin Fowler企业级应用开发思想集成了最新的技术栈。
## 技术栈
- **后端**: .NET 9, ASP.NET Core WebAPI
- **ORM**: SqlSugar (主要) + Entity Framework Core (兼容)
- **依赖注入**: Autofac
- **数据库**: 支持SqlServer、MySQL、Oracle、PostgreSQL
- **定时任务**: Quartz.NET
- **缓存**: Redis, MemoryCache
- **前端**: Vue2 + Element-UI
- **测试**: NUnit
- **文档**: Swagger
## 项目架构
```
📦OpenAuth.Net
┣ 📂Infrastructure # 基础设施层 - 工具类、扩展方法、帮助类
┣ 📂OpenAuth.Repository # 数据访问层 - 实体定义、数据访问
┣ 📂OpenAuth.App # 应用服务层 - 业务逻辑
┣ 📂OpenAuth.WebApi # 表示层 - WebAPI控制器
┣ 📂OpenAuth.Identity # 身份认证服务 - IdentityServer4
┣ 📂Vue2 # 前端项目
┗ 📂数据库脚本 # 数据库初始化脚本
```
## 分层架构规则

View File

@@ -1,27 +0,0 @@
{
"mcpServers": {
"PostgreSQL": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres",
"postgresql://postgres:AwxBRx1_5kljfy@172.30.144.46/openauthpro"
],
"env": {}
},
"openauthpro": {
"command": "powershell",
"args": [
"-Command",
"npx -y @f4ww4z/mcp-mysql-server"
],
"env": {
"MYSQL_HOST": "localhost",
"MYSQL_PORT": "3306",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "000000",
"MYSQL_DATABASE": "openauthpro"
}
}
}
}

View File

@@ -65,7 +65,8 @@ namespace Infrastructure.Middleware
// 启用倒带功能,就可以让 Request.Body 可以再次读取
request.EnableBuffering();
// 文件上传 记录文件信息
if (path.Contains("/upload"))
var contentType = request.ContentType?? "";
if (path.Contains("/upload") || contentType.Contains("multipart/form-data"))
{
var content = string.Join(",", request.Form.Files.Select(item => item.FileName));
logData.Add("request.body", $"收到上传文件:{content}");
@@ -73,7 +74,6 @@ namespace Infrastructure.Middleware
else
{
var sr = new StreamReader(request.Body, Encoding.UTF8);
//string content = sr.ReadToEnd(); //.Net Core 3.0 默认不再支持
var content = sr.ReadToEndAsync().Result;
logData.Add("request.body", content);
request.Body.Position = 0;

View File

@@ -11,6 +11,7 @@ using OpenAuth.Repository.Domain;
using SqlSugar;
using Autofac;
using Infrastructure.Extensions.AutofacManager;
using MySql.Data.MySqlClient.Memcached;
namespace OpenAuth.App
{
@@ -69,7 +70,15 @@ namespace OpenAuth.App
if (loginUser.User.Account == Define.SYSTEM_USERNAME) return SugarClient.Queryable<T>(); //超级管理员特权
var moduleName = typeof(T).Name;
var rule = SugarClient.Queryable<DataPrivilegeRule>().First(u => u.SourceCode == moduleName);
//数据权限永远只用默认连接字符串,避免租户隔离
ISqlSugarClient defualtClient = SugarClient;
var currentConfigId = SugarClient.CurrentConnectionConfig.ConfigId;
if(currentConfigId != null && currentConfigId.ToString() !=""){
defualtClient = SugarClient.AsTenant().GetConnection("");
}
var rule = defualtClient.Queryable<DataPrivilegeRule>().First(u => u.SourceCode == moduleName);
if (rule == null) return SugarClient.Queryable<T>(); //没有设置数据规则,那么视为该资源允许被任何主体查看
if (rule.PrivilegeRules.Contains(Define.DATAPRIVILEGE_LOGINUSER) ||
rule.PrivilegeRules.Contains(Define.DATAPRIVILEGE_LOGINROLE)||

View File

@@ -11,7 +11,6 @@ using Infrastructure;
using Infrastructure.Extensions;
using Infrastructure.Helpers;
using Infrastructure.Utilities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Options;
using OpenAuth.App.Interface;
@@ -20,12 +19,12 @@ using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Core;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
public class BuilderTableApp : BaseStringApp<BuilderTable, OpenAuthDBContext>
public class BuilderTableApp : SqlSugarBaseApp<BuilderTable>
{
private BuilderTableColumnApp _builderTableColumnApp;
private CategoryApp _categoryApp;
@@ -34,9 +33,9 @@ namespace OpenAuth.App
private string _startName = "";
private IOptions<AppSetting> _appConfiguration;
public BuilderTableApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<BuilderTable, OpenAuthDBContext> repository,
public BuilderTableApp(ISqlSugarClient client,
RevelanceManagerApp app, IAuth auth, DbExtension dbExtension, BuilderTableColumnApp builderTableColumnApp,
IOptions<AppSetting> appConfiguration, CategoryApp categoryApp) : base(unitWork, repository, auth)
IOptions<AppSetting> appConfiguration, CategoryApp categoryApp) : base(client, auth)
{
_dbExtension = dbExtension;
_builderTableColumnApp = builderTableColumnApp;
@@ -87,7 +86,7 @@ namespace OpenAuth.App
}
var result = new PagedListDataResp<BuilderTable>();
var objs = UnitWork.Find<BuilderTable>(null);
var objs = SugarClient.Queryable<BuilderTable>();
if (!string.IsNullOrEmpty(request.key))
{
objs = objs.Where(u => u.Id.Contains(request.key));
@@ -126,7 +125,6 @@ namespace OpenAuth.App
Check(req);
var obj = AddTableAndColumns(req.MapTo<BuilderTable>());
UnitWork.Save();
return obj.Id;
}
@@ -143,8 +141,7 @@ namespace OpenAuth.App
var user = _auth.GetCurrentUser().User;
obj.CreateUserId = user.Id;
obj.CreateUserName = user.Name;
UnitWork.Add(obj);
UnitWork.Save(); //需要先保存表结构,后面才能正常判定
Repository.Insert(obj);
_dbExtension.ProcessExternalDb(obj.Id); //先处理外部数据库连接
var columns = _dbExtension.GetDbTableStructure(obj.TableName);
@@ -175,7 +172,7 @@ namespace OpenAuth.App
CreateUserName = user.Name,
CreateTime = DateTime.Now
};
UnitWork.Add(builderColumn);
SugarClient.Insertable(builderColumn).ExecuteCommand();
}
return obj;
@@ -185,7 +182,7 @@ namespace OpenAuth.App
{
Check(obj);
var user = _auth.GetCurrentUser().User;
UnitWork.Update<BuilderTable>(u => u.Id == obj.Id, u => new BuilderTable
Repository.Update(u => new BuilderTable
{
TableName = obj.TableName,
Remark = obj.Remark,
@@ -204,7 +201,7 @@ namespace OpenAuth.App
UpdateUserId = user.Id,
UpdateUserName = user.Name,
ExternalDataSourceId = obj.ExternalDataSourceId //外部数据源ID
});
}, u => u.Id == obj.Id);
}
/// <summary>
@@ -213,12 +210,10 @@ namespace OpenAuth.App
/// <param name="ids"></param>
public void DelTableAndcolumns(string[] ids)
{
UnitWork.ExecuteWithTransaction(() =>
{
UnitWork.Delete<BuilderTable>(u => ids.Contains(u.Id));
UnitWork.Delete<BuilderTableColumn>(u => ids.Contains(u.TableId));
UnitWork.Save();
});
SugarClient.Ado.BeginTran();
SugarClient.Deleteable<BuilderTable>().Where(u => ids.Contains(u.Id)).ExecuteCommand();
SugarClient.Deleteable<BuilderTableColumn>().Where(u => ids.Contains(u.TableId)).ExecuteCommand();
SugarClient.Ado.CommitTran();
}
@@ -228,7 +223,7 @@ namespace OpenAuth.App
/// <returns></returns>
public void CreateEntity(CreateEntityReq req)
{
var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id);
var sysTableInfo = SugarClient.Queryable<BuilderTable>().First(u => u.Id == req.Id);
var tableColumns = _builderTableColumnApp.Find(req.Id);
if (sysTableInfo == null
|| tableColumns == null
@@ -247,7 +242,7 @@ namespace OpenAuth.App
/// <returns></returns>
public void CreateBusiness(CreateBusiReq req)
{
var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id);
var sysTableInfo = SugarClient.Queryable<BuilderTable>().First(u => u.Id == req.Id);
var mainColumns = _builderTableColumnApp.Find(req.Id);
if (sysTableInfo == null
|| mainColumns == null
@@ -319,7 +314,7 @@ namespace OpenAuth.App
string domainContent = string.Empty;
//查找是否存在子表的情况
var subTable = Repository.FirstOrDefault(u => u.ParentTableId == sysTableInfo.Id);
var subTable = SugarClient.Queryable<BuilderTable>().First(u => u.ParentTableId == sysTableInfo.Id);
if (subTable == null) //如果子表不存在,则用单模版生成
{
@@ -386,21 +381,7 @@ namespace OpenAuth.App
{
throw new Exception($"未能找到表{sysTableInfo.TableName}的主键字段");
}
if (primarykey.ColumnType == "decimal" || primarykey.ColumnType == "numeric") //是否为数字
{
if (primarykey.IsIncrement) //是否自增
{
domainContent = domainContent.Replace("{BaseAppName}", "BaseIntAutoGenApp");
}
else //普通的雪花算法生成id
{
domainContent = domainContent.Replace("{BaseAppName}", "BaseLongApp");
}
}
else
{
domainContent = domainContent.Replace("{BaseAppName}", "BaseStringApp");
}
domainContent = domainContent.Replace("{BaseAppName}", "SqlSugarBaseApp");
FileHelper.WriteFile($"{appRootPath}\\{sysTableInfo.ModuleCode}", $"{sysTableInfo.ModuleCode}.cs", domainContent);
}
@@ -465,7 +446,7 @@ namespace OpenAuth.App
}
//查找是否存在子表的情况
var subTable = Repository.FirstOrDefault(u => u.ParentTableId == sysTableInfo.Id);
var subTable = SugarClient.Queryable<BuilderTable>().First(u => u.ParentTableId == sysTableInfo.Id);
if (subTable != null) //如果子表存在,需要加子表的请求参数
{
@@ -705,7 +686,7 @@ namespace OpenAuth.App
{
var types = AssemblyLoadContext.Default
.LoadFromAssemblyName(new AssemblyName(compilation.Name))
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
.GetTypes().Where(x => System.Reflection.IntrospectionExtensions.GetTypeInfo(x).BaseType != null
&& x.BaseType == typeof(StringEntity));
foreach (var entity in types)
{
@@ -736,7 +717,7 @@ namespace OpenAuth.App
{
throw new Exception("请提供vue项目的根目录,如C:\\OpenAuth.Pro\\Client");
}
var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id);
var sysTableInfo = SugarClient.Queryable<BuilderTable>().First(u => u.Id == req.Id);
if (!string.IsNullOrEmpty(sysTableInfo.ParentTableId))
{
@@ -753,7 +734,7 @@ namespace OpenAuth.App
string domainContent = string.Empty;
//查找是否存在子表额情况
var subTable = Repository.FirstOrDefault(u => u.ParentTableId == req.Id);
var subTable = SugarClient.Queryable<BuilderTable>().First(u => u.ParentTableId == req.Id);
if (subTable == null) //如果子表不存在,则用单模版生成
{
@@ -868,7 +849,7 @@ namespace OpenAuth.App
{
throw new Exception("请提供vue项目的根目录,如C:\\OpenAuth.Pro\\Client");
}
var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id);
var sysTableInfo = SugarClient.Queryable<BuilderTable>().First(u => u.Id == req.Id);
var tableColumns = _builderTableColumnApp.Find(req.Id);
if (sysTableInfo == null
|| tableColumns == null
@@ -890,7 +871,7 @@ namespace OpenAuth.App
public async Task<PagedDynamicDataResp> AllMain()
{
var result = new PagedDynamicDataResp();
var objs = UnitWork.Find<BuilderTable>(u => string.IsNullOrEmpty(u.ParentTableId)).Select(u => new
var objs = SugarClient.Queryable<BuilderTable>().Where(u => string.IsNullOrEmpty(u.ParentTableId)).Select(u => new
{
Id = u.Id,
Name = u.TableName

View File

@@ -55,7 +55,7 @@ namespace OpenAuth.App
var propertyStr = string.Join(',', columnFields.Select(u =>u.ColumnName));
result.ColumnFields = columnFields;
result.Data = objs.OrderBy(u => u.DtCode)
result.Data = objs.OrderBy(u => u.SortNo).OrderBy(u => u.DtCode)
.Skip((request.page - 1) * request.limit)
.Take(request.limit).Select($"{propertyStr}").ToList();
result.Count = await objs.CountAsync();

View File

@@ -3,18 +3,16 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
public class CategoryTypeApp : BaseStringApp<CategoryType,OpenAuthDBContext>
public class CategoryTypeApp : SqlSugarBaseApp<CategoryType>
{
private RevelanceManagerApp _revelanceApp;
@@ -24,7 +22,7 @@ namespace OpenAuth.App
public async Task<PagedDynamicDataResp> Load(QueryCategoryTypeListReq request)
{
var result = new PagedDynamicDataResp();
var objs = UnitWork.Find<CategoryType>(null);
var objs = SugarClient.Queryable<CategoryType>();
if (!string.IsNullOrEmpty(request.key))
{
objs = objs.Where(u => u.Id.Contains(request.key) || u.Name.Contains(request.key));
@@ -42,39 +40,37 @@ namespace OpenAuth.App
var obj = req.MapTo<CategoryType>();
//todo:补充或调整自己需要的字段
obj.CreateTime = DateTime.Now;
Repository.Add(obj);
Repository.Insert(obj);
}
public void Update(AddOrUpdateCategoryTypeReq obj)
{
var user = _auth.GetCurrentUser().User;
UnitWork.Update<CategoryType>(u => u.Id == obj.Id, u => new CategoryType
Repository.Update(u => new CategoryType
{
Name = obj.Name,
CreateTime = DateTime.Now
//todo:补充或调整自己需要的字段
});
}, u => u.Id == obj.Id);
}
public new void Delete(string[] ids)
{
UnitWork.ExecuteWithTransaction(() =>
{
UnitWork.Delete<CategoryType>(u=>ids.Contains(u.Id));
UnitWork.Delete<Category>(u=>ids.Contains(u.TypeId));
UnitWork.Save();
});
SugarClient.Ado.BeginTran();
SugarClient.Deleteable<CategoryType>().Where(u=>ids.Contains(u.Id)).ExecuteCommand();
SugarClient.Deleteable<Category>().Where(u=>ids.Contains(u.TypeId)).ExecuteCommand();
SugarClient.Ado.CommitTran();
}
public List<CategoryType> AllTypes()
{
return UnitWork.Find<CategoryType>(null).ToList();
return SugarClient.Queryable<CategoryType>().ToList();
}
public CategoryTypeApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<CategoryType,OpenAuthDBContext> repository,
RevelanceManagerApp app, IAuth auth) : base(unitWork, repository,auth)
public CategoryTypeApp(ISqlSugarClient client,
RevelanceManagerApp app, IAuth auth) : base(client, auth)
{
_revelanceApp = app;
}

View File

@@ -31,6 +31,59 @@ namespace OpenAuth.App
this.logger = logger;
}
#region -
/// <summary>
/// 将普通字典转换为大小写不敏感的字典
/// </summary>
private Dictionary<string, object> ToIgnoreCaseDict(Dictionary<string, object> source)
{
var result = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
if (source != null)
{
foreach (var kvp in source)
{
result[kvp.Key] = kvp.Value;
}
}
return result;
}
/// <summary>
/// 检查字典中是否包含指定键(大小写不敏感)
/// </summary>
private bool ContainsKeyIgnoreCase(Dictionary<string, object> dict, string key)
{
return dict.Keys.Any(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 获取字典中指定键的值(大小写不敏感)
/// </summary>
private object GetValueIgnoreCase(Dictionary<string, object> dict, string key)
{
var kvp = dict.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
return kvp.Value;
}
/// <summary>
/// 设置字典中指定键的值(保留原始键名,大小写不敏感查找)
/// </summary>
private void SetValueIgnoreCase(Dictionary<string, object> dict, string key, object value)
{
var existingKey = dict.Keys.FirstOrDefault(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase));
if (existingKey != null)
{
dict[existingKey] = value;
}
else
{
dict[key] = value;
}
}
#endregion
/// <summary>
/// 获取表数据列表
/// </summary>
@@ -154,37 +207,42 @@ namespace OpenAuth.App
return result;
}
// 将对象转换为字典
var dict = JsonHelper.Instance.Deserialize<Dictionary<string, Object>>(req.Obj);
// 将对象转换为字典(使用大小写不敏感的反序列化)
var rawDict = JsonHelper.Instance.Deserialize<Dictionary<string, object>>(req.Obj);
var dict = ToIgnoreCaseDict(rawDict);
// 设置ID
if (!dict.ContainsKey("Id"))
{
dict["Id"] = Guid.NewGuid().ToString();
}
else if (string.IsNullOrEmpty(dict["Id"]?.ToString()))
// 设置ID(大小写不敏感检查)
if (!ContainsKeyIgnoreCase(dict, "Id"))
{
dict["Id"] = Guid.NewGuid().ToString();
}
else
{
//如果Id不为空,需要判断Id是否存在
var entity = await _client.Queryable<dynamic>()
.AS(req.TableName)
.Where("Id = @id", new { id = dict["Id"] })
.FirstAsync();
if (entity != null)
var idValue = GetValueIgnoreCase(dict, "Id");
if (string.IsNullOrEmpty(idValue?.ToString()))
{
result.Code = 500;
result.Message = "Id已存在";
return result;
SetValueIgnoreCase(dict, "Id", Guid.NewGuid().ToString());
}
else
{
//如果Id不为空,需要判断Id是否存在
var entity = await _client.Queryable<dynamic>()
.AS(req.TableName)
.Where("Id = @id", new { id = idValue })
.FirstAsync();
if (entity != null)
{
result.Code = 500;
result.Message = "Id已存在";
return result;
}
}
}
//如果有CreateTime字段自动设置
if (dict.ContainsKey("CreateTime"))
//如果有CreateTime字段自动设置(大小写不敏感)
if (ContainsKeyIgnoreCase(dict, "CreateTime"))
{
dict["CreateTime"] = DateTime.Now.ToString();
SetValueIgnoreCase(dict, "CreateTime", DateTime.Now.ToString());
}
// 添加数据
@@ -222,30 +280,44 @@ namespace OpenAuth.App
return result;
}
// 将对象转换为字典
var dict = JsonHelper.Instance.Deserialize<Dictionary<string, Object>>(req.Obj);
// 将对象转换为字典(使用大小写不敏感的反序列化)
var rawDict = JsonHelper.Instance.Deserialize<Dictionary<string, object>>(req.Obj);
var dict = ToIgnoreCaseDict(rawDict);
// 检查ID是否存在
if (!dict.ContainsKey("Id"))
// 检查ID是否存在(大小写不敏感)
if (!ContainsKeyIgnoreCase(dict, "Id"))
{
result.Code = 500;
result.Message = "更新数据必须包含Id字段";
return result;
}
// 如果有UpdateTime字段自动设置
if (dict.ContainsKey("UpdateTime"))
// 确保字典中有 "Id" 键(用于 SqlSugar 的 WhereColumns
if (!dict.ContainsKey("Id"))
{
dict["UpdateTime"] = DateTime.Now.ToString();
var idValue = GetValueIgnoreCase(dict, "Id");
// 移除原始的小写 id 键
var originalKey = dict.Keys.FirstOrDefault(k => string.Equals(k, "Id", StringComparison.OrdinalIgnoreCase));
if (originalKey != null && originalKey != "Id")
{
dict.Remove(originalKey);
dict["Id"] = idValue;
}
}
// 如果有用户信息,设置更新用户
// 如果有UpdateTime字段自动设置大小写不敏感
if (ContainsKeyIgnoreCase(dict, "UpdateTime"))
{
SetValueIgnoreCase(dict, "UpdateTime", DateTime.Now.ToString());
}
// 如果有用户信息,设置更新用户(大小写不敏感)
var currentUser = _auth.GetCurrentUser();
if (dict.ContainsKey("UpdateUserId") && currentUser != null)
if (ContainsKeyIgnoreCase(dict, "UpdateUserId") && currentUser != null)
{
// 设置更新用户信息
dict["UpdateUserId"] = currentUser.User.Id;
dict["UpdateUserName"] = currentUser.User.Name;
SetValueIgnoreCase(dict, "UpdateUserId", currentUser.User.Id);
SetValueIgnoreCase(dict, "UpdateUserName", currentUser.User.Name);
}
// 更新数据
@@ -387,27 +459,21 @@ namespace OpenAuth.App
try
{
var json = request.Parameters;
// 检查参数名是否存在于JSON中
if (json.Contains($"\"{param.Name}\""))
// 解析完整的JSON对象使用大小写不敏感的字典
var jsonObj = JsonHelper.Instance.Deserialize<Dictionary<string, object>>(json);
var ignoreCaseDict = ToIgnoreCaseDict(jsonObj);
// 从JSON对象中获取参数值大小写不敏感查找
if (ContainsKeyIgnoreCase(ignoreCaseDict, param.Name))
{
// 解析完整的JSON对象
var jsonObj = JsonHelper.Instance.Deserialize<Dictionary<string, object>>(json);
// 获取参数对应的JSON值并序列化为字符串
var rawValue = GetValueIgnoreCase(ignoreCaseDict, param.Name);
var paramValue = JsonHelper.Instance.Serialize(rawValue);
// JSON对象中获取参数值
if (jsonObj.ContainsKey(param.Name))
{
// 获取参数对应的JSON值并序列化为字符串
var paramValue = JsonHelper.Instance.Serialize(jsonObj[param.Name]);
// 将JSON字符串反序列化为目标类型
var deserializeMethod = typeof(JsonHelper).GetMethod("Deserialize").MakeGenericMethod(param.ParameterType);
paramValues[i] = deserializeMethod.Invoke(JsonHelper.Instance, new object[] { paramValue });
}
else
{
// 参数名存在但获取不到,使用默认值
paramValues[i] = param.HasDefaultValue ? param.DefaultValue : null;
}
// JSON字符串反序列化为目标类型
var deserializeMethod = typeof(JsonHelper).GetMethod("Deserialize").MakeGenericMethod(param.ParameterType);
paramValues[i] = deserializeMethod.Invoke(JsonHelper.Instance, new object[] { paramValue });
}
else
{

View File

@@ -7,31 +7,29 @@ using Infrastructure;
using Infrastructure.Extensions;
using Infrastructure.Helpers;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
/// <summary>
/// 文件管理
/// </summary>
public class FileApp : BaseStringApp<UploadFile,OpenAuthDBContext>
public class FileApp : SqlSugarBaseApp<UploadFile>
{
private ILogger<FileApp> _logger;
private string _filePath;
private string _dbFilePath; //数据库中的文件路径
private string _dbThumbnail; //数据库中的缩略图路径
public FileApp(IOptions<AppSetting> setOptions, IUnitWork<OpenAuthDBContext> unitWork, IRepository<UploadFile,OpenAuthDBContext> repository,
public FileApp(IOptions<AppSetting> setOptions, ISqlSugarClient client,
ILogger<FileApp> logger, IAuth auth)
: base(unitWork, repository, auth)
: base(client, auth)
{
_logger = logger;
_filePath = setOptions.Value.UploadPath;
@@ -47,7 +45,7 @@ namespace OpenAuth.App
public async Task<PagedDynamicDataResp> Load(QueryFileListReq request)
{
var result = new PagedDynamicDataResp();
var objs = UnitWork.Find<UploadFile>(null);
var objs = SugarClient.Queryable<UploadFile>();
if (!string.IsNullOrEmpty(request.key))
{
objs = objs.Where(u => u.FileName.Contains(request.key) || u.FilePath.Contains(request.key));
@@ -112,7 +110,7 @@ namespace OpenAuth.App
FileType = Path.GetExtension(fileName),
Extension = Path.GetExtension(fileName)
};
Repository.Add(filedb);
Repository.Insert(filedb);
return filedb;
}
}
@@ -126,9 +124,9 @@ namespace OpenAuth.App
/// 删除附件
/// </summary>
/// <param name="ids"></param>
public override void Delete(string[] ids)
public new void Delete(string[] ids)
{
var files = base.Repository.Find(u => ids.Contains(u.Id)).ToList();
var files = SugarClient.Queryable<UploadFile>().Where(u => ids.Contains(u.Id)).ToList();
for (int i = 0; i < files.Count(); i++)
{
var uploadPath = Path.Combine(_filePath, files[i].FilePath);
@@ -137,7 +135,7 @@ namespace OpenAuth.App
{
FileHelper.FileDel(Path.Combine(_filePath, files[i].Thumbnail));
}
Repository.Delete(u =>u.Id == files[i].Id);
SugarClient.Deleteable<UploadFile>().Where(u =>u.Id == files[i].Id).ExecuteCommand();
}
}

View File

@@ -130,8 +130,12 @@ namespace OpenAuth.App.Flow
var properties = frmDataJson.Properties().ToList();
foreach (var property in properties)
{
frmDataJson[property.Name.ToLower()] = property.Value;
frmDataJson.Remove(property.Name);
// 只有当属性名不是小写时才进行转换
if (property.Name != property.Name.ToLower())
{
frmDataJson[property.Name.ToLower()] = property.Value;
frmDataJson.Remove(property.Name);
}
}
foreach (var l in lines)

View File

@@ -3,9 +3,8 @@ using System.Linq;
using System.Text;
using Infrastructure;
using Newtonsoft.Json.Linq;
using OpenAuth.Repository;
using OpenAuth.Repository.Interface;
using OpenAuth.Repository.QueryObj;
using SqlSugar;
namespace OpenAuth.App
{
/// <summary>
@@ -13,10 +12,10 @@ namespace OpenAuth.App
/// </summary>
public class DragForm: IForm
{
private IUnitWork<OpenAuthDBContext> _unitWork;
public DragForm(IUnitWork<OpenAuthDBContext> unitWork)
private ISqlSugarClient _sugarClient;
public DragForm(ISqlSugarClient sugarClient)
{
_unitWork = unitWork;
_sugarClient = sugarClient;
}
/**
* 功能: 创建表单数据表格基于sql server
@@ -29,7 +28,7 @@ namespace OpenAuth.App
var jsonArray = JsonHelper.Instance.Deserialize<JObject>(form.ContentData)["widgetList"];
string tableName = form.DbName;
//如果数据库已经存在该表,则不用创建
var exist = _unitWork.FromSql<QueryStringObj>($"select '1' as value from sysobjects where name = '{tableName}' and type = 'U'").SingleOrDefault();
var exist = _sugarClient.Ado.SqlQuery<QueryStringObj>($"select '1' as value from sysobjects where name = '{tableName}' and type = 'U'").SingleOrDefault();
if (exist != null) return string.Empty;
// 如果数据库没有指定的表,则创建表
StringBuilder sql = new StringBuilder($"CREATE TABLE {tableName} ( [Id] varchar(50) COLLATE Chinese_PRC_CI_AS NOT NULL,"); //主键
@@ -62,7 +61,7 @@ namespace OpenAuth.App
var jsonArray = JsonHelper.Instance.Deserialize<JObject>(form.ContentData)["widgetList"];
string tableName = form.DbName;
//如果数据库已经存在该表,则不用创建
var exist = _unitWork.FromSql<QueryStringObj>($"select distinct table_name as value from information_schema.tables where table_name ='{tableName}'").SingleOrDefault();
var exist = _sugarClient.Ado.SqlQuery<QueryStringObj>($"select distinct table_name as value from information_schema.tables where table_name ='{tableName}'").SingleOrDefault();
if (exist != null) return string.Empty;
// 如果数据库没有指定的表,则创建表
StringBuilder sql = new StringBuilder($"create table if not exists `{tableName}` ( Id varchar(50) not null primary key,"); //主键

View File

@@ -4,19 +4,17 @@ using System.Threading.Tasks;
using Infrastructure;
using Infrastructure.Utilities;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
public class FormApp : BaseStringApp<Form,OpenAuthDBContext>
public class FormApp : SqlSugarBaseApp<Form>
{
private IOptions<AppSetting> _appConfiguration;
private IHttpContextAccessor _httpContextAccessor;
@@ -44,19 +42,21 @@ namespace OpenAuth.App
var user = _auth.GetCurrentUser().User;
obj.CreateUserId = user.Id;
obj.CreateUserName = user.Name;
UnitWork.Add(obj);
Repository.Insert(obj);
if (!string.IsNullOrEmpty(obj.DbName))
{
var dbtype = _appConfiguration.Value.DbTypes[_httpContextAccessor.GetTenantId()];
UnitWork.ExecuteSql(FormFactory.CreateForm(obj, this.UnitWork).GetSql(obj, dbtype));
var sql = FormFactory.CreateForm(obj, SugarClient).GetSql(obj, dbtype);
if (!string.IsNullOrEmpty(sql))
{
SugarClient.Ado.ExecuteCommand(sql);
}
}
UnitWork.Save();
}
public void Update(Form obj)
{
Repository.Update(u => u.Id == obj.Id, u => new Form
Repository.Update(u => new Form
{
FrmType = obj.FrmType,
ContentData = obj.ContentData,
@@ -69,12 +69,16 @@ namespace OpenAuth.App
Description = obj.Description,
OrgId = obj.OrgId,
ModifyDate = DateTime.Now
});
}, u => u.Id == obj.Id);
if (!string.IsNullOrEmpty(obj.DbName))
{
var dbtype = _appConfiguration.Value.DbTypes[_httpContextAccessor.GetTenantId()];
UnitWork.ExecuteSql(FormFactory.CreateForm(obj,this.UnitWork).GetSql(obj, dbtype));
var sql = FormFactory.CreateForm(obj, SugarClient).GetSql(obj, dbtype);
if (!string.IsNullOrEmpty(sql))
{
SugarClient.Ado.ExecuteCommand(sql);
}
}
}
@@ -84,8 +88,8 @@ namespace OpenAuth.App
return form.MapTo<FormResp>();
}
public FormApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Form,OpenAuthDBContext> repository,
IAuth auth, IOptions<AppSetting> appConfiguration, IHttpContextAccessor httpContextAccessor) : base(unitWork, repository, auth)
public FormApp(ISqlSugarClient client,
IAuth auth, IOptions<AppSetting> appConfiguration, IHttpContextAccessor httpContextAccessor) : base(client, auth)
{
_auth = auth;
_appConfiguration = appConfiguration;

View File

@@ -1,25 +1,24 @@
using System;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using Infrastructure;
using SqlSugar;
namespace OpenAuth.App
{
public class FormFactory
{
public static IForm CreateForm(Form form, IUnitWork<OpenAuthDBContext> unitWork)
public static IForm CreateForm(Form form, ISqlSugarClient sugarClient)
{
if (form.FrmType == Define.FORM_TYPE_DYNAMIC)
{
return new LeipiForm(unitWork);
return new LeipiForm(sugarClient);
}else if (form.FrmType == Define.FORM_TYPE_DEVELOP)
{
throw new Exception("自定义表单不需要创建数据库表");
}
else
{
return new DragForm(unitWork);
return new DragForm(sugarClient);
}
}
}

View File

@@ -2,17 +2,16 @@
using System.Text;
using Infrastructure;
using Newtonsoft.Json.Linq;
using OpenAuth.Repository;
using OpenAuth.Repository.Interface;
using OpenAuth.Repository.QueryObj;
using SqlSugar;
namespace OpenAuth.App
{
public class LeipiForm : IForm
{
private IUnitWork<OpenAuthDBContext> _unitWork;
public LeipiForm(IUnitWork<OpenAuthDBContext> unitWork)
private ISqlSugarClient _sugarClient;
public LeipiForm(ISqlSugarClient sugarClient)
{
_unitWork = unitWork;
_sugarClient = sugarClient;
}
/**
* 功能: 创建表单数据表格基于sql server
@@ -25,7 +24,7 @@ namespace OpenAuth.App
var jsonArray = JArray.Parse(form.ContentData);
// 数据库名称
string tableName = form.DbName;
var exist = _unitWork.FromSql<QueryStringObj>($"select '1' as value from sysobjects where name = '{tableName}' and type = 'U'").SingleOrDefault();
var exist = _sugarClient.Ado.SqlQuery<QueryStringObj>($"select '1' as value from sysobjects where name = '{tableName}' and type = 'U'").SingleOrDefault();
if (exist != null) return string.Empty;
// 创建数据表
StringBuilder sql = new StringBuilder($"CREATE TABLE {tableName} ( [Id] varchar(50) COLLATE Chinese_PRC_CI_AS NOT NULL,"); //主键
@@ -61,7 +60,7 @@ namespace OpenAuth.App
var jsonArray = JArray.Parse(form.ContentData);
// 数据库名称
string tableName = form.DbName;
var exist = _unitWork.FromSql<QueryStringObj>($"select distinct table_name as value from information_schema.tables where table_name ='{tableName}'").SingleOrDefault();
var exist = _sugarClient.Ado.SqlQuery<QueryStringObj>($"select distinct table_name as value from information_schema.tables where table_name ='{tableName}'").SingleOrDefault();
if (exist != null) return string.Empty;
// 创建数据表
StringBuilder sql = new StringBuilder($"create table if not exists `{tableName}` ( Id varchar(50) not null primary key,"); //主键

View File

@@ -1,17 +1,15 @@
using System.Threading.Tasks;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
public class FrmLeaveReqApp : BaseStringApp<FrmLeaveReq,OpenAuthDBContext>, ICustomerForm
public class FrmLeaveReqApp : SqlSugarBaseApp<FrmLeaveReq>, ICustomerForm
{
private RevelanceManagerApp _revelanceApp;
@@ -22,18 +20,20 @@ namespace OpenAuth.App
{
return new PagedDynamicDataResp
{
Count = await Repository.CountAsync(null),
Data = await Repository.Find(request.page, request.limit, "Id desc").ToListAsync()
Count = await SugarClient.Queryable<FrmLeaveReq>().CountAsync(),
Data = await SugarClient.Queryable<FrmLeaveReq>().OrderByDescending(u => u.Id)
.Skip((request.page - 1) * request.limit)
.Take(request.limit).ToListAsync()
};
}
public void Add(FrmLeaveReq obj)
{
Repository.Add(obj);
Repository.Insert(obj);
}
public FrmLeaveReqApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<FrmLeaveReq,OpenAuthDBContext> repository,
RevelanceManagerApp app,IAuth auth) : base(unitWork, repository, auth)
public FrmLeaveReqApp(ISqlSugarClient client,
RevelanceManagerApp app,IAuth auth) : base(client, auth)
{
_revelanceApp = app;
}
@@ -48,13 +48,13 @@ namespace OpenAuth.App
public void Update(string flowInstanceId, string frmData)
{
var req = JsonHelper.Instance.Deserialize<FrmLeaveReq>(frmData);
UnitWork.Update<FrmLeaveReq>(u => u.FlowInstanceId == flowInstanceId, u => new FrmLeaveReq
Repository.Update(u => new FrmLeaveReq
{
UserName = req.UserName,
RequestComment = req.RequestComment,
RequestType = req.RequestType
//补充其他需要更新的字段
});
}, u => u.FlowInstanceId == flowInstanceId);
}
}
}

View File

@@ -3,13 +3,12 @@ using System.Linq;
using Infrastructure;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
public class ModuleManagerApp : BaseTreeApp<Module,OpenAuthDBContext>
public class ModuleManagerApp : SqlSugarBaseTreeApp<Module>
{
private RevelanceManagerApp _revelanceApp;
@@ -23,7 +22,7 @@ namespace OpenAuth.App
CaculateCascade(model);
Repository.Add(model);
Repository.Insert(model);
AddDefaultMenus(model);
//当前登录用户的所有角色自动分配模块
@@ -52,9 +51,9 @@ namespace OpenAuth.App
/// <param name="roleId">The role unique identifier.</param>
public IEnumerable<Module> LoadForRole(string roleId)
{
var moduleIds = UnitWork.Find<Relevance>(u => u.FirstId == roleId && u.RelKey == Define.ROLEMODULE)
.Select(u => u.SecondId);
return UnitWork.Find<Module>(u => moduleIds.Contains(u.Id)).OrderBy(u => u.SortNo);
var moduleIds = SugarClient.Queryable<Relevance>().Where(u => u.FirstId == roleId && u.RelKey == Define.ROLEMODULE)
.Select(u => u.SecondId).ToArray();
return SugarClient.Queryable<Module>().Where(u => moduleIds.Contains(u.Id)).OrderBy(u => u.SortNo).ToList();
}
//获取角色可访问的模块字段
@@ -68,14 +67,14 @@ namespace OpenAuth.App
/// </summary>
public IEnumerable<ModuleElement> LoadMenusForRole(string moduleId, string roleId)
{
var elementIds = _revelanceApp.Get(Define.ROLEELEMENT, true, roleId);
var query = UnitWork.Find<ModuleElement>(u => elementIds.Contains(u.Id));
var elementIds = _revelanceApp.Get(Define.ROLEELEMENT, true, roleId).ToArray();
var query = SugarClient.Queryable<ModuleElement>().Where(u => elementIds.Contains(u.Id));
if (!string.IsNullOrEmpty(moduleId))
{
query = query.Where(u => u.ModuleId == moduleId);
}
return query;
return query.ToList();
}
#endregion /
@@ -87,9 +86,9 @@ namespace OpenAuth.App
/// <returns></returns>
public IEnumerable<SysPrinterPlan> LoadPrinterPlans(string moduleId)
{
var planids = _revelanceApp.Get(Define.MODULEPRINTERPLAN, true, moduleId);
var query = UnitWork.Find<SysPrinterPlan>(u => planids.Contains(u.Id));
return query;
var planids = _revelanceApp.Get(Define.MODULEPRINTERPLAN, true, moduleId).ToArray();
var query = SugarClient.Queryable<SysPrinterPlan>().Where(u => planids.Contains(u.Id));
return query.ToList();
}
/// <summary>
@@ -99,9 +98,9 @@ namespace OpenAuth.App
/// <returns></returns>
public IEnumerable<FlowScheme> LoadFlowSchemes(string moduleId)
{
var planids = _revelanceApp.Get(Define.MODULE_FLOWSCHEME, true, moduleId);
var query = UnitWork.Find<FlowScheme>(u => planids.Contains(u.Id));
return query;
var planids = _revelanceApp.Get(Define.MODULE_FLOWSCHEME, true, moduleId).ToArray();
var query = SugarClient.Queryable<FlowScheme>().Where(u => planids.Contains(u.Id));
return query.ToList();
}
@@ -113,8 +112,7 @@ namespace OpenAuth.App
/// <param name="ids"></param>
public void DelMenu(string[] ids)
{
UnitWork.Delete<ModuleElement>(u => ids.Contains(u.Id));
UnitWork.Save();
SugarClient.Deleteable<ModuleElement>().Where(u => ids.Contains(u.Id)).ExecuteCommand();
}
@@ -130,28 +128,29 @@ namespace OpenAuth.App
throw new CommonException("登录已过期", Define.INVALID_TOKEN);
}
UnitWork.ExecuteWithTransaction(() =>
SugarClient.Ado.BeginTran();
if (model.KeyIsNull())
{
UnitWork.Add(model);
model.GenerateDefaultKeyVal();
}
SugarClient.Insertable(model).ExecuteCommand();
//当前登录用户的所有角色自动分配菜单
loginContext.Roles.ForEach(u =>
//当前登录用户的所有角色自动分配菜单
loginContext.Roles.ForEach(u =>
{
_revelanceApp.Assign(new AssignReq
{
_revelanceApp.Assign(new AssignReq
{
type = Define.ROLEELEMENT,
firstId = u.Id,
secIds = new[] {model.Id}
});
type = Define.ROLEELEMENT,
firstId = u.Id,
secIds = new[] {model.Id}
});
UnitWork.Save();
});
SugarClient.Ado.CommitTran();
}
public void UpdateMenu(ModuleElement model)
{
UnitWork.Update<ModuleElement>(model);
UnitWork.Save();
SugarClient.Updateable(model).ExecuteCommand();
}
//添加默认按钮
@@ -197,8 +196,8 @@ namespace OpenAuth.App
#endregion
public ModuleManagerApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Module,OpenAuthDBContext> repository
, RevelanceManagerApp app, IAuth auth) : base(unitWork, repository, auth)
public ModuleManagerApp(ISqlSugarClient client
, RevelanceManagerApp app, IAuth auth) : base(client, auth)
{
_revelanceApp = app;
}

View File

@@ -6,17 +6,15 @@ using Infrastructure.Helpers;
using Microsoft.Extensions.Logging;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
public class RevelanceManagerApp : BaseStringApp<Relevance,OpenAuthDBContext>
public class RevelanceManagerApp : SqlSugarBaseApp<Relevance>
{
private readonly ILogger<RevelanceManagerApp> _logger;
public RevelanceManagerApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Relevance,OpenAuthDBContext> repository, IAuth auth, ILogger<RevelanceManagerApp> logger) : base(unitWork,
repository, auth)
public RevelanceManagerApp(ISqlSugarClient client, IAuth auth, ILogger<RevelanceManagerApp> logger) : base(client, auth)
{
_logger = logger;
}
@@ -38,7 +36,7 @@ namespace OpenAuth.App
/// <param name="idMaps"></param>
public void Assign(string key, ILookup<string, string> idMaps)
{
UnitWork.BatchAdd((from sameVals in idMaps
SugarClient.Insertable((from sameVals in idMaps
from value in sameVals
select new Relevance
{
@@ -46,8 +44,7 @@ namespace OpenAuth.App
FirstId = sameVals.Key,
SecondId = value,
OperateTime = TimeHelper.Now
}).ToArray());
UnitWork.Save();
}).ToArray()).ExecuteCommand();
}
/// <summary>
@@ -82,7 +79,7 @@ namespace OpenAuth.App
_logger.LogInformation($"start=> delete {key} {sameVals.Key} {value}");
try
{
UnitWork.Delete<Relevance>(u => u.RelKey == key && u.FirstId == sameVals.Key && u.SecondId == value);
SugarClient.Deleteable<Relevance>().Where(u => u.RelKey == key && u.FirstId == sameVals.Key && u.SecondId == value).ExecuteCommand();
}
catch (Exception e)
{
@@ -95,7 +92,7 @@ namespace OpenAuth.App
public void DeleteBy(string key, params string[] firstIds)
{
UnitWork.Delete<Relevance>(u => firstIds.Contains(u.FirstId) && u.RelKey == key);
SugarClient.Deleteable<Relevance>().Where(u => firstIds.Contains(u.FirstId) && u.RelKey == key).ExecuteCommand();
}
@@ -110,12 +107,12 @@ namespace OpenAuth.App
{
if (returnSecondIds)
{
return Repository.Find(u => u.RelKey == key
return SugarClient.Queryable<Relevance>().Where(u => u.RelKey == key
&& ids.Contains(u.FirstId)).Select(u => u.SecondId).ToList();
}
else
{
return Repository.Find(u => u.RelKey == key
return SugarClient.Queryable<Relevance>().Where(u => u.RelKey == key
&& ids.Contains(u.SecondId)).Select(u => u.FirstId).ToList();
}
}
@@ -129,7 +126,7 @@ namespace OpenAuth.App
/// <returns></returns>
public List<string> Get(string key, string firstId, string secondId)
{
return Repository.Find(u => u.RelKey == key && u.FirstId == firstId && u.SecondId == secondId)
return SugarClient.Queryable<Relevance>().Where(u => u.RelKey == key && u.FirstId == firstId && u.SecondId == secondId)
.Select(u => u.ThirdId).ToList();
}
@@ -157,8 +154,7 @@ namespace OpenAuth.App
});
}
UnitWork.BatchAdd(relevances.ToArray());
UnitWork.Save();
SugarClient.Insertable(relevances).ExecuteCommand();
}
/// <summary>
@@ -182,10 +178,10 @@ namespace OpenAuth.App
{
foreach (var property in request.Properties)
{
UnitWork.Delete<Relevance>(u => u.RelKey == Define.ROLEDATAPROPERTY
SugarClient.Deleteable<Relevance>().Where(u => u.RelKey == Define.ROLEDATAPROPERTY
&& u.FirstId == request.RoleId
&& u.SecondId == request.ModuleCode
&& u.ThirdId == property);
&& u.ThirdId == property).ExecuteCommand();
}
}
}
@@ -196,21 +192,19 @@ namespace OpenAuth.App
/// <param name="request"></param>
public void AssignRoleUsers(AssignRoleUsers request)
{
UnitWork.ExecuteWithTransaction(() =>
{
//删除以前的所有用户
UnitWork.Delete<Relevance>(u => u.SecondId == request.RoleId && u.RelKey == Define.USERROLE);
//批量分配用户角色
UnitWork.BatchAdd((from firstId in request.UserIds
SugarClient.Ado.BeginTran();
//删除以前的所有用户
SugarClient.Deleteable<Relevance>().Where(u => u.SecondId == request.RoleId && u.RelKey == Define.USERROLE).ExecuteCommand();
//批量分配用户角色
SugarClient.Insertable((from firstId in request.UserIds
select new Relevance
{
RelKey = Define.USERROLE,
FirstId = firstId,
SecondId = request.RoleId,
OperateTime = TimeHelper.Now
}).ToArray());
UnitWork.Save();
});
}).ToArray()).ExecuteCommand();
SugarClient.Ado.CommitTran();
}
/// <summary>
@@ -219,21 +213,19 @@ namespace OpenAuth.App
/// <param name="request"></param>
public void AssignOrgUsers(AssignOrgUsers request)
{
UnitWork.ExecuteWithTransaction(() =>
{
//删除以前的所有用户
UnitWork.Delete<Relevance>(u => u.SecondId == request.OrgId && u.RelKey == Define.USERORG);
//批量分配用户角色
UnitWork.BatchAdd((from firstId in request.UserIds
SugarClient.Ado.BeginTran();
//删除以前的所有用户
SugarClient.Deleteable<Relevance>().Where(u => u.SecondId == request.OrgId && u.RelKey == Define.USERORG).ExecuteCommand();
//批量分配用户角色
SugarClient.Insertable((from firstId in request.UserIds
select new Relevance
{
RelKey = Define.USERORG,
FirstId = firstId,
SecondId = request.OrgId,
OperateTime = TimeHelper.Now
}).ToArray());
UnitWork.Save();
});
}).ToArray()).ExecuteCommand();
SugarClient.Ado.CommitTran();
}
/// <summary>
@@ -242,21 +234,19 @@ namespace OpenAuth.App
/// <param name="request"></param>
public void AssignRoleResources(AssignRoleResources request)
{
UnitWork.ExecuteWithTransaction(() =>
{
//删除以前的所有资源
UnitWork.Delete<Relevance>(u => u.FirstId == request.RoleId && u.RelKey == Define.ROLERESOURCE);
//批量分配角色资源
UnitWork.BatchAdd((from firstId in request.ResourceIds
SugarClient.Ado.BeginTran();
//删除以前的所有资源
SugarClient.Deleteable<Relevance>().Where(u => u.FirstId == request.RoleId && u.RelKey == Define.ROLERESOURCE).ExecuteCommand();
//批量分配角色资源
SugarClient.Insertable((from firstId in request.ResourceIds
select new Relevance
{
RelKey = Define.ROLERESOURCE,
FirstId = request.RoleId,
SecondId = firstId,
OperateTime = TimeHelper.Now
}).ToArray());
UnitWork.Save();
});
}).ToArray()).ExecuteCommand();
SugarClient.Ado.CommitTran();
}
}
}

View File

@@ -1,17 +1,15 @@
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using SqlSugar;
namespace OpenAuth.App
{
public class SysLogApp : BaseStringApp<SysLog,OpenAuthDBContext>
public class SysLogApp : SqlSugarBaseApp<SysLog>
{
/// <summary>
@@ -20,7 +18,7 @@ namespace OpenAuth.App
public async Task<PagedDynamicDataResp> Load(QuerySysLogListReq request)
{
var result = new PagedDynamicDataResp();
var objs = UnitWork.Find<SysLog>(null);
var objs = SugarClient.Queryable<SysLog>();
if (!string.IsNullOrEmpty(request.key))
{
objs = objs.Where(u => u.Content.Contains(request.key) || u.Id.Contains(request.key));
@@ -37,19 +35,19 @@ namespace OpenAuth.App
{
//程序类型取入口应用的名称,可以根据自己需要调整
obj.Application = Assembly.GetEntryAssembly().FullName.Split(',')[0];
Repository.Add(obj);
Repository.Insert(obj);
}
public void Update(SysLog obj)
{
UnitWork.Update<SysLog>(u => u.Id == obj.Id, u => new SysLog
Repository.Update(u => new SysLog
{
//todo:要修改的字段赋值
});
}, u => u.Id == obj.Id);
}
public SysLogApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<SysLog,OpenAuthDBContext> repository) : base(unitWork, repository, null)
public SysLogApp(ISqlSugarClient client) : base(client, null)
{
}
}

View File

@@ -2,20 +2,18 @@
using System.Linq;
using System.Threading.Tasks;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using Infrastructure.Helpers;
using SqlSugar;
namespace OpenAuth.App
{
public class SysMessageApp : BaseStringApp<SysMessage,OpenAuthDBContext>
public class SysMessageApp : SqlSugarBaseApp<SysMessage>
{
private RevelanceManagerApp _revelanceApp;
private readonly ILogger<SysMessageApp> _logger;
@@ -32,7 +30,7 @@ namespace OpenAuth.App
}
var result = new PagedDynamicDataResp();
var objs = UnitWork.Find<SysMessage>(u =>u.ToId == loginContext.User.Id && u.ToStatus != -1);
var objs = SugarClient.Queryable<SysMessage>().Where(u =>u.ToId == loginContext.User.Id && u.ToStatus != -1);
if (!string.IsNullOrEmpty(request.key))
{
@@ -54,7 +52,7 @@ namespace OpenAuth.App
public void Add(SysMessage obj)
{
Repository.Add(obj);
Repository.Insert(obj);
}
/// <summary>
@@ -75,14 +73,14 @@ namespace OpenAuth.App
}
else
{
sysUser = UnitWork.FirstOrDefault<SysUser>(u => u.Id == userId);
sysUser = SugarClient.Queryable<SysUser>().First(u => u.Id == userId);
}
if (sysUser == null)
{
_logger.LogError($"未能找到用户{userId},不能给该用户发送消息");
return;
}
Repository.Add(new SysMessage
Repository.Insert(new SysMessage
{
ToId = sysUser.Id,
ToName = sysUser.Name,
@@ -101,10 +99,10 @@ namespace OpenAuth.App
/// <param name="msgid"></param>
public void Read(ReadMsgReq req)
{
UnitWork.Update<SysMessage>(u => u.Id == req.Id, u => new SysMessage
Repository.Update(u => new SysMessage
{
ToStatus = 1
});
}, u => u.Id == req.Id);
}
/// <summary>
/// 消息采用逻辑删除
@@ -112,15 +110,15 @@ namespace OpenAuth.App
/// <param name="ids"></param>
public void Del(string[] ids)
{
UnitWork.Update<SysMessage>(u => ids.Contains(u.Id), u => new SysMessage
Repository.Update(u => new SysMessage
{
ToStatus = -1 //逻辑删除
});
}, u => ids.Contains(u.Id));
}
public SysMessageApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<SysMessage,OpenAuthDBContext> repository,
RevelanceManagerApp app,IAuth auth, ILogger<SysMessageApp> logger) : base(unitWork, repository, auth)
public SysMessageApp(ISqlSugarClient client,
RevelanceManagerApp app,IAuth auth, ILogger<SysMessageApp> logger) : base(client, auth)
{
_revelanceApp = app;
_logger = logger;

View File

@@ -11,8 +11,17 @@ using OpenAuth.App.SSO;
namespace OpenAuth.App.Test
{
class TestDynamicApiApp :TestBase
/// <summary>
/// DynamicApiApp 单元测试
/// 测试表noentity (id varchar(50), name varchar(255), age int)
/// 支持 MySQL 和 SqlServer 数据库
/// 测试大小写混合属性命名
/// </summary>
[TestFixture]
public class TestDynamicApiApp : TestBase
{
private const string TEST_TABLE = "noentity";
public override ServiceCollection GetService()
{
var services = new ServiceCollection();
@@ -28,55 +37,628 @@ namespace OpenAuth.App.Test
return services;
}
#region CRUD
/// <summary>
/// 测试添加数据 - 标准属性名PascalCase
/// </summary>
[Test]
public async Task TestAdd()
public async Task TestAdd_PascalCase()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var obj = await app.Add(new AddOrUpdateDynamicEntityReq { TableName = "noentity", Obj = "{\"P1\":\"测试\",\"Id\":\"12\"}" });
Console.WriteLine(JsonHelper.Instance.Serialize(obj));
var id = Guid.NewGuid().ToString();
var result = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"测试PascalCase\",\"Age\":25}}"
});
Console.WriteLine($"添加结果PascalCase: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"添加失败: {result.Message}");
}
/// <summary>
/// 测试添加数据 - 小写属性名camelCase
/// </summary>
[Test]
public async Task TestAdd_CamelCase()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
var result = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"id\":\"{id}\",\"name\":\"测试camelCase\",\"age\":30}}"
});
Console.WriteLine($"添加结果camelCase: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"添加失败: {result.Message}");
}
/// <summary>
/// 测试添加数据 - 大写属性名UPPERCASE
/// </summary>
[Test]
public async Task TestAdd_UpperCase()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
var result = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"ID\":\"{id}\",\"NAME\":\"测试UPPERCASE\",\"AGE\":35}}"
});
Console.WriteLine($"添加结果UPPERCASE: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"添加失败: {result.Message}");
}
/// <summary>
/// 测试添加数据 - 混合大小写属性名MixedCase
/// </summary>
[Test]
public async Task TestAdd_MixedCase()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
// 混合使用不同大小写Id(PascalCase), name(camelCase), AGE(UPPERCASE)
var result = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"name\":\"测试MixedCase\",\"AGE\":40}}"
});
Console.WriteLine($"添加结果MixedCase: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"添加失败: {result.Message}");
}
/// <summary>
/// 测试获取单条数据
/// </summary>
[Test]
public async Task TestGet()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
// 先添加数据
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"测试获取\",\"Age\":28}}"
});
// 获取数据
var result = await app.Get(new QueryDynamicEntityReq
{
TableName = TEST_TABLE,
Id = id
});
Console.WriteLine($"获取结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"获取失败: {result.Message}");
Assert.That(result.Data, Is.Not.Null, "未找到数据");
var obj = await app.Get(new QueryDynamicEntityReq { TableName = "noentity", Id = "1" });
Console.WriteLine(JsonHelper.Instance.Serialize(obj));
}
/// <summary>
/// 测试获取列表
/// </summary>
[Test]
public async Task TestGetList()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var obj = await app.GetList(new QueryDynamicListReq { TableName = "noentity", page = 1, limit = 10, key = "" });
Console.WriteLine(JsonHelper.Instance.Serialize(obj));
var result = await app.GetList(new QueryDynamicListReq
{
TableName = TEST_TABLE,
page = 1,
limit = 10,
key = ""
});
Console.WriteLine($"列表查询结果: 总数={result.Count}, 数据条数={result.Data?.Count ?? 0}");
Console.WriteLine($"详细结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"查询失败: {result.Message}");
}
/// <summary>
/// 测试带关键字搜索的列表查询
/// </summary>
[Test]
public async Task TestInvoke()
public async Task TestGetList_WithKey()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
var searchKey = "搜索测试_" + DateTime.Now.Ticks;
// 先添加测试数据
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"{searchKey}\",\"Age\":22}}"
});
// 查询
var result = await app.GetList(new QueryDynamicListReq
{
TableName = TEST_TABLE,
page = 1,
limit = 10,
key = searchKey
});
Console.WriteLine($"带关键字搜索结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"查询失败: {result.Message}");
Assert.That(result.Count, Is.GreaterThanOrEqualTo(1), "应该至少找到一条数据");
// 清理测试数据
await CleanupTestData(app, id);
}
/// <summary>
/// 测试更新数据 - 标准属性名PascalCase
/// </summary>
[Test]
public async Task TestUpdate_PascalCase()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
// 先添加数据
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"原始名称\",\"Age\":20}}"
});
// 更新数据
var result = await app.Update(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"更新后PascalCase\",\"Age\":21}}"
});
Console.WriteLine($"更新结果PascalCase: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"更新失败: {result.Message}");
// 验证更新结果
var getResult = await app.Get(new QueryDynamicEntityReq { TableName = TEST_TABLE, Id = id });
Console.WriteLine($"更新后数据: {JsonHelper.Instance.Serialize(getResult)}");
}
/// <summary>
/// 测试更新数据 - 小写属性名camelCase
/// </summary>
[Test]
public async Task TestUpdate_CamelCase()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
// 先添加数据
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"id\":\"{id}\",\"name\":\"原始名称\",\"age\":20}}"
});
// 更新数据
var result = await app.Update(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"id\":\"{id}\",\"name\":\"更新后camelCase\",\"age\":22}}"
});
Console.WriteLine($"更新结果camelCase: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"更新失败: {result.Message}");
}
/// <summary>
/// 测试更新数据 - 混合大小写属性名
/// </summary>
[Test]
public async Task TestUpdate_MixedCase()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
// 先添加数据使用PascalCase
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"原始名称\",\"Age\":20}}"
});
// 更新数据(使用混合大小写)
var result = await app.Update(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"name\":\"更新后MixedCase\",\"AGE\":23}}"
});
Console.WriteLine($"更新结果MixedCase: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"更新失败: {result.Message}");
}
/// <summary>
/// 测试删除单条数据
/// </summary>
[Test]
public async Task TestDelete_Single()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
// 先添加数据
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"待删除\",\"Age\":99}}"
});
// 删除数据
var result = await app.Delete(new DelDynamicReq
{
TableName = TEST_TABLE,
Ids = new[] { id }
});
Console.WriteLine($"删除结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"删除失败: {result.Message}");
// 验证删除结果
var getResult = await app.Get(new QueryDynamicEntityReq { TableName = TEST_TABLE, Id = id });
Assert.That(getResult.Data, Is.Null, "数据应该已被删除");
}
/// <summary>
/// 测试批量删除
/// </summary>
[Test]
public async Task TestDelete_Batch()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var ids = new[] { Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), Guid.NewGuid().ToString() };
// 添加多条测试数据
foreach (var id in ids)
{
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"批量删除测试_{id.Substring(0, 8)}\",\"Age\":50}}"
});
}
// 批量删除
var result = await app.Delete(new DelDynamicReq
{
TableName = TEST_TABLE,
Ids = ids
});
Console.WriteLine($"批量删除结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"批量删除失败: {result.Message}");
// 验证删除结果
foreach (var id in ids)
{
var getResult = await app.Get(new QueryDynamicEntityReq { TableName = TEST_TABLE, Id = id });
Assert.That(getResult.Data, Is.Null, $"数据 {id} 应该已被删除");
}
}
#endregion
#region CRUD
/// <summary>
/// 测试完整的 CRUD 流程
/// </summary>
[Test]
public async Task TestCRUD_FullFlow()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
Console.WriteLine("=== 开始完整 CRUD 流程测试 ===");
// 1. Create - 创建数据
Console.WriteLine("\n1. 创建数据...");
var addResult = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"CRUD测试\",\"Age\":18}}"
});
Console.WriteLine($"创建结果: {JsonHelper.Instance.Serialize(addResult)}");
Assert.That(addResult.Code, Is.EqualTo(200), $"创建失败: {addResult.Message}");
// 2. Read - 读取数据
Console.WriteLine("\n2. 读取数据...");
var getResult = await app.Get(new QueryDynamicEntityReq
{
TableName = TEST_TABLE,
Id = id
});
Console.WriteLine($"读取结果: {JsonHelper.Instance.Serialize(getResult)}");
Assert.That(getResult.Code, Is.EqualTo(200), $"读取失败: {getResult.Message}");
Assert.That(getResult.Data, Is.Not.Null, "数据不应为空");
// 3. Update - 更新数据
Console.WriteLine("\n3. 更新数据...");
var updateResult = await app.Update(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"CRUD测试_已更新\",\"Age\":19}}"
});
Console.WriteLine($"更新结果: {JsonHelper.Instance.Serialize(updateResult)}");
Assert.That(updateResult.Code, Is.EqualTo(200), $"更新失败: {updateResult.Message}");
// 验证更新
var getResult2 = await app.Get(new QueryDynamicEntityReq { TableName = TEST_TABLE, Id = id });
Console.WriteLine($"更新后数据: {JsonHelper.Instance.Serialize(getResult2)}");
// 4. Delete - 删除数据
Console.WriteLine("\n4. 删除数据...");
var deleteResult = await app.Delete(new DelDynamicReq
{
TableName = TEST_TABLE,
Ids = new[] { id }
});
Console.WriteLine($"删除结果: {JsonHelper.Instance.Serialize(deleteResult)}");
Assert.That(deleteResult.Code, Is.EqualTo(200), $"删除失败: {deleteResult.Message}");
// 验证删除
var getResult3 = await app.Get(new QueryDynamicEntityReq { TableName = TEST_TABLE, Id = id });
Assert.That(getResult3.Data, Is.Null, "数据应该已被删除");
Console.WriteLine("\n=== 完整 CRUD 流程测试完成 ===");
}
#endregion
#region Invoke
/// <summary>
/// 测试 Invoke 调用 - 获取父级用户
/// </summary>
[Test]
public async Task TestInvoke_GetParent()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var obj = await app.Invoke(new InvokeDynamicReq { ServiceName = "UserManagerApp", MethodName = "GetParent",
Parameters = "{\"userid\":\"0ceff0f8-f848-440c-bc26-d8605ac858cd\"}" });
Console.WriteLine(JsonHelper.Instance.Serialize(obj));
var result = await app.Invoke(new InvokeDynamicReq
{
ServiceName = "UserManagerApp",
MethodName = "GetParent",
Parameters = "{\"userid\":\"0ceff0f8-f848-440c-bc26-d8605ac858cd\"}"
});
Console.WriteLine($"Invoke GetParent 结果: {JsonHelper.Instance.Serialize(result)}");
}
/// <summary>
/// 测试 Invoke 调用 - 加载用户列表
/// </summary>
[Test]
public async Task TestInvoke2()
public async Task TestInvoke_Load()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var obj = await app.Invoke(new InvokeDynamicReq {
ServiceName = "UserManagerApp",
MethodName = "Load",
Parameters = "{\"request\":{\"page\":1,\"limit\":10,\"key\":\"dddd\"}}"
});
Console.WriteLine(JsonHelper.Instance.Serialize(obj));
}
var result = await app.Invoke(new InvokeDynamicReq
{
ServiceName = "UserManagerApp",
MethodName = "Load",
Parameters = "{\"request\":{\"page\":1,\"limit\":10,\"key\":\"\"}}"
});
Console.WriteLine($"Invoke Load 结果: {JsonHelper.Instance.Serialize(result)}");
}
/// <summary>
/// 测试 Invoke 调用 - 参数大小写混合
/// </summary>
[Test]
public async Task TestInvoke_MixedCaseParameters()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
// 使用混合大小写的参数
var result = await app.Invoke(new InvokeDynamicReq
{
ServiceName = "UserManagerApp",
MethodName = "Load",
Parameters = "{\"Request\":{\"Page\":1,\"Limit\":10,\"Key\":\"\"}}"
});
Console.WriteLine($"Invoke MixedCase 结果: {JsonHelper.Instance.Serialize(result)}");
}
#endregion
#region
/// <summary>
/// 测试不存在的表
/// </summary>
[Test]
public async Task TestNonExistentTable()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var result = await app.GetList(new QueryDynamicListReq
{
TableName = "non_existent_table_12345",
page = 1,
limit = 10
});
Console.WriteLine($"查询不存在的表结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(500), "应该返回错误");
Assert.That(result.Message, Does.Contain("表不存在"), "错误信息应包含'表不存在'");
}
/// <summary>
/// 测试更新不包含Id的数据
/// </summary>
[Test]
public async Task TestUpdate_WithoutId()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var result = await app.Update(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = "{\"Name\":\"没有Id的更新\",\"Age\":99}"
});
Console.WriteLine($"无Id更新结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(500), "应该返回错误");
Assert.That(result.Message, Does.Contain("Id"), "错误信息应包含'Id'");
}
/// <summary>
/// 测试添加重复Id的数据
/// </summary>
[Test]
public async Task TestAdd_DuplicateId()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var id = Guid.NewGuid().ToString();
// 第一次添加
await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"第一次添加\",\"Age\":1}}"
});
// 第二次添加相同Id
var result = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = $"{{\"Id\":\"{id}\",\"Name\":\"第二次添加\",\"Age\":2}}"
});
Console.WriteLine($"重复Id添加结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(500), "应该返回错误");
Assert.That(result.Message, Does.Contain("Id已存在"), "错误信息应包含'Id已存在'");
// 清理测试数据
await CleanupTestData(app, id);
}
/// <summary>
/// 测试获取不存在的记录
/// </summary>
[Test]
public async Task TestGet_NonExistent()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
var result = await app.Get(new QueryDynamicEntityReq
{
TableName = TEST_TABLE,
Id = "non_existent_id_12345"
});
Console.WriteLine($"获取不存在记录结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(500), "应该返回错误");
Assert.That(result.Message, Does.Contain("未找到"), "错误信息应包含'未找到'");
}
#endregion
#region ID测试
/// <summary>
/// 测试添加数据时自动生成Id
/// </summary>
[Test]
public async Task TestAdd_AutoGenerateId()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
// 不传Id
var result = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = "{\"Name\":\"自动生成Id测试\",\"Age\":33}"
});
Console.WriteLine($"自动生成Id结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"添加失败: {result.Message}");
// 查询并验证确实有数据被添加
var listResult = await app.GetList(new QueryDynamicListReq
{
TableName = TEST_TABLE,
page = 1,
limit = 100,
key = "自动生成Id测试"
});
Console.WriteLine($"查询结果: {JsonHelper.Instance.Serialize(listResult)}");
Assert.That(listResult.Count, Is.GreaterThan(0), "应该能查到数据");
}
/// <summary>
/// 测试添加数据时Id为空字符串应自动生成
/// </summary>
[Test]
public async Task TestAdd_EmptyId()
{
var app = _autofacServiceProvider.GetService<DynamicApiApp>();
// 传空Id
var result = await app.Add(new AddOrUpdateDynamicEntityReq
{
TableName = TEST_TABLE,
Obj = "{\"Id\":\"\",\"Name\":\"空Id测试\",\"Age\":34}"
});
Console.WriteLine($"空Id测试结果: {JsonHelper.Instance.Serialize(result)}");
Assert.That(result.Code, Is.EqualTo(200), $"添加失败: {result.Message}");
}
#endregion
#region
/// <summary>
/// 清理测试数据
/// </summary>
private async Task CleanupTestData(DynamicApiApp app, string id)
{
try
{
await app.Delete(new DelDynamicReq
{
TableName = TEST_TABLE,
Ids = new[] { id }
});
}
catch (Exception ex)
{
Console.WriteLine($"清理测试数据失败: {ex.Message}");
}
}
#endregion
}
}

View File

@@ -189,8 +189,8 @@ namespace OpenAuth.WebApi.Controllers
{
return new PagedDynamicDataResp
{
Message = "未找到指定的节点",
Code = 500,
Data = new List<OrgView>(),
Count = 0
};
}
cascadeId = org.CascadeId;

View File

@@ -1,7 +1,7 @@
<!--
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
* @Date: 2021-06-01 14:10:29
* @LastEditTime: 2024-02-23 11:36:24
* @LastEditTime: 2025-12-21 17:39:13
* @Description: 处于草稿和驳回状态的流程可以进行编辑
* 可以编辑流程的基本信息和提交的表单内容
* @
@@ -171,7 +171,7 @@ export default {
.then((response) => {
this.postObj = response.data
this.formData = JSON.parse(response.data.frmData)
this.formJson = JSON.parse(response.data.frmContentData)
if (this.postObj.frmType === 1) {
// 用户自定义的页面,即Vue组件
@@ -179,6 +179,8 @@ export default {
loadComp().then(res => {
this.userDefineComp = res.default
})
}else{
this.formJson = JSON.parse(response.data.frmContentData)
}
})
.catch((err) => {

View File

@@ -4,25 +4,29 @@ createTime: 2025/04/23 23:43:26
permalink: /pro/dragformdetail/
---
企业版可拖拽表单使用的是VForm Pro版本详细的配置可参考:[https://www.vform666.com/](https://www.vform666.com/) 本节只做常用的配置说明。
企业版可拖拽表单使用的是 VForm Pro 版本,详细的配置可参考:[https://www.vform666.com/](https://www.vform666.com/) 本节只做常用的配置说明。
## 后端加载下拉列表值
官网推荐通过数据源的方式给下拉列表赋值,简单点的方式是使用组件的`onCreated`事件。新建一个下拉先选框,唯一名称改为:`SelectVals`,在组件的`onCreated`事件中添加以下代码:
```javascript
var selectVals = this.getWidgetRef('SelectVals');
var addressAPI= 'http://localhost:52789/api/SelectVals/'
axios.get(addressAPI).then(function(res) {
if (res.data.code==200) {
selectVals.loadOptions(res.data.result);
}
}).catch(function(error) {
console.error(error)
})
var selectVals = this.getWidgetRef("SelectVals");
var addressAPI = "http://localhost:52789/api/SelectVals/";
axios
.get(addressAPI)
.then(function (res) {
if (res.data.code == 200) {
selectVals.loadOptions(res.data.result);
}
})
.catch(function (error) {
console.error(error);
});
```
基于OpenAuth.WebApi返回的数据格式
基于 OpenAuth.WebApi 返回的数据格式:
```javascript
{
"result": [{
@@ -35,4 +39,19 @@ axios.get(addressAPI).then(function(res) {
"message": "操作成功",
"code": 200
}
```
```
## 多字段校验
使用场景:拖动表单中有多个表单组件需要联动校验,比如两个日期组件校验开始日期小于等于结束日期。
具体做法:在表单设计的【全局设置】里面配置`onFormValidate`事件:
```javascript
if (formModel.startDate > formModel.endDate) {
this.$message.error("开始日期必须小于结束日期");
return false;
}
```
如下图:
![2025-11-23-22-30-21](http://pic.openauth.net.cn/2025-11-23-22-30-21.png)