mirror of
https://gitee.com/dotnetchina/OpenAuth.Net.git
synced 2026-11-05 19:29:09 +08:00
Compare commits
8
Commits
8.3.5
..
aac40f9e67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aac40f9e67 | ||
|
|
ad18885596 | ||
|
|
6302ad4bca | ||
|
|
f30fe5e11d | ||
|
|
ac49f0e80f | ||
|
|
7d94137b44 | ||
|
|
fb7c1392a1 | ||
|
|
7cd738e7a7 |
@@ -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)||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,8 +189,8 @@ namespace OpenAuth.WebApi.Controllers
|
||||
{
|
||||
return new PagedDynamicDataResp
|
||||
{
|
||||
Message = "未找到指定的节点",
|
||||
Code = 500,
|
||||
Data = new List<OrgView>(),
|
||||
Count = 0
|
||||
};
|
||||
}
|
||||
cascadeId = org.CascadeId;
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
|
||||
如下图:
|
||||

|
||||
|
||||
Reference in New Issue
Block a user