diff --git a/Tiobon.Core.Api/Controllers/DbFirst/DbFirstController.cs b/Tiobon.Core.Api/Controllers/DbFirst/DbFirstController.cs
index 00b0f2ae..4d6f4fd7 100644
--- a/Tiobon.Core.Api/Controllers/DbFirst/DbFirstController.cs
+++ b/Tiobon.Core.Api/Controllers/DbFirst/DbFirstController.cs
@@ -160,7 +160,7 @@ namespace Tiobon.Core.Controllers
data.response += $"库{ConnID}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
//data.response += $"库{ConnID}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
data.response += $"库{ConnID}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
- data.response += $"库{ConnID}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ //data.response += $"库{ConnID}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
data.response += $"库{ConnID}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
// 切回主库
_sqlSugarClient.ChangeDatabase(MainDb.CurrentDbConnId.ToLower());
diff --git a/Tiobon.Core.Api/Controllers/Ghra_GradeController.cs b/Tiobon.Core.Api/Controllers/Ghra_GradeController.cs
new file mode 100644
index 00000000..5d5bf019
--- /dev/null
+++ b/Tiobon.Core.Api/Controllers/Ghra_GradeController.cs
@@ -0,0 +1,100 @@
+namespace Tiobon.Core.Api.Controllers
+{
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ [Authorize(Permissions.Name)]
+ public class Ghra_GradeController : ControllerBase
+ {
+ #region 初始化
+ ///
+ /// 服务器接口,因为是模板生成,所以首字母是大写的,自己可以重构下
+ ///
+ private readonly IGhra_GradeServices _ghra_GradeServices;
+
+ public Ghra_GradeController(IGhra_GradeServices Ghra_GradeServices)
+ {
+ _ghra_GradeServices = Ghra_GradeServices;
+ }
+ #endregion
+
+ #region 基础接口
+
+ #region 查询
+ [HttpGet]
+ public async Task>> Get([FromFilter] QueryFilter filter)
+ {
+ return new MessageModel>()
+ {
+ msg = "获取成功",
+ success = true,
+ response = await _ghra_GradeServices.QueryFilterPage(filter)
+ };
+ }
+
+ [HttpGet("{id}")]
+ public async Task> Get(string id)
+ {
+ return new MessageModel()
+ {
+ msg = "获取成功",
+ success = true,
+ response = await _ghra_GradeServices.QueryById(id)
+ };
+ }
+ #endregion
+
+ #region 新增
+ [HttpPost]
+ public async Task> Post([FromBody] Ghra_Grade request)
+ {
+ var data = new MessageModel();
+
+ var id = await _ghra_GradeServices.Add(request);
+ data.success = id > 0;
+ if (data.success)
+ {
+ data.response = id.ObjToString();
+ data.msg = "添加成功";
+ }
+
+ return data;
+ }
+ #endregion
+
+ #region 新增
+ [HttpPut]
+ public async Task> Put([FromBody] Ghra_Grade request)
+ {
+ var data = new MessageModel();
+ data.success = await _ghra_GradeServices.Update(request);
+ if (data.success)
+ {
+ data.msg = "更新成功";
+ data.response = request?.Id.ObjToString();
+ }
+
+ return data;
+ }
+ #endregion
+
+ #region 删除
+ [HttpDelete]
+ public async Task> Delete(int id)
+ {
+ var data = new MessageModel();
+ var model = await _ghra_GradeServices.QueryById(id);
+ model.IsEnable = 1;
+ // data.success = await _departmentServices.Update(model);
+ if (data.success)
+ {
+ data.msg = "删除成功";
+ data.response = model?.Id.ObjToString();
+ }
+
+ return data;
+ }
+ #endregion
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Tiobon.Core.Api/GlobalUsings.cs b/Tiobon.Core.Api/GlobalUsings.cs
index e1792547..cd7a8892 100644
--- a/Tiobon.Core.Api/GlobalUsings.cs
+++ b/Tiobon.Core.Api/GlobalUsings.cs
@@ -15,3 +15,4 @@ global using Tiobon.Core.Model;
global using Tiobon.Core.Model.Models;
global using Tiobon.Core.Model.ViewModels;
global using Tiobon.Core.Repository.UnitOfWorks;
+global using Microsoft.AspNetCore.Mvc;
diff --git a/Tiobon.Core.Api/Tiobon.Core.Model.xml b/Tiobon.Core.Api/Tiobon.Core.Model.xml
index b162395e..da2d9e18 100644
--- a/Tiobon.Core.Api/Tiobon.Core.Model.xml
+++ b/Tiobon.Core.Api/Tiobon.Core.Model.xml
@@ -34,165 +34,212 @@
所有
-
+
- 以下model 来自ids4项目,多库模式,为了调取ids4数据
- 角色表
+
-
-
- 排序
-
+
+
+ Desc:
+ Default:
+ Nullable:False
+
-
+
- 是否激活
+ Desc:
+ Default:
+ Nullable:True
-
+
- 创建ID
+ Desc:
+ Default:
+ Nullable:True
-
+
- 创建者
+ Desc:
+ Default:
+ Nullable:True
-
+
- 创建时间
+ Desc:
+ Default:
+ Nullable:True
-
+
- 修改ID
+ Desc:
+ Default:
+ Nullable:True
-
+
- 修改者
+ Desc:
+ Default:1
+ Nullable:False
-
+
- 修改时间
+ Desc:
+ Default:1
+ Nullable:False
-
+
- 以下model 来自ids4项目,多库模式,为了调取ids4数据
- 用户表
+ Desc:
+ Default:1
+ Nullable:False
-
+
- 这是爱
+ Desc:
+ Default:0
+ Nullable:True
-
+
- id
+ Desc:
+ Default:0
+ Nullable:False
-
+
- 姓名
+ Desc:
+ Default:DateTime.Now
+ Nullable:False
-
+
- 年龄
+ Desc:
+ Default:
+ Nullable:True
-
+
- 通用返回信息类
+ Desc:
+ Default:
+ Nullable:True
-
+
- 状态码
+ Desc:
+ Default:
+ Nullable:True
-
+
- 操作是否成功
+ Desc:
+ Default:
+ Nullable:True
-
+
- 返回信息
+ Desc:
+ Default:
+ Nullable:True
-
+
- 开发者信息
+ Desc:
+ Default:
+ Nullable:True
-
+
- 返回数据集合
+ Desc:
+ Default:
+ Nullable:True
-
+
- 返回成功
+ Desc:
+ Default:
+ Nullable:True
- 消息
-
-
+
- 返回成功
+ Desc:
+ Default:
+ Nullable:True
- 消息
- 数据
-
-
+
- 返回失败
+ Desc:
+ Default:
+ Nullable:True
- 消息
-
-
+
- 返回失败
+ Desc:
+ Default:
+ Nullable:True
- 消息
- 数据
-
-
+
- 返回消息
+ Desc:
+ Default:
+ Nullable:True
- 失败/成功
- 消息
- 数据
-
-
+
- 状态码
+ Desc:
+ Default:
+ Nullable:True
-
+
- 操作是否成功
+ Desc:
+ Default:
+ Nullable:True
-
+
- 返回信息
+ Desc:
+ Default:
+ Nullable:True
-
+
- 返回数据集合
+ Desc:
+ Default:
+ Nullable:True
+
+
+
+
+ Desc:
+ Default:
+ Nullable:True
@@ -1790,6 +1837,167 @@
修改时间
+
+
+ 以下model 来自ids4项目,多库模式,为了调取ids4数据
+ 角色表
+
+
+
+
+ 排序
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 以下model 来自ids4项目,多库模式,为了调取ids4数据
+ 用户表
+
+
+
+
+ 这是爱
+
+
+
+
+ id
+
+
+
+
+ 姓名
+
+
+
+
+ 年龄
+
+
+
+
+ 通用返回信息类
+
+
+
+
+ 状态码
+
+
+
+
+ 操作是否成功
+
+
+
+
+ 返回信息
+
+
+
+
+ 开发者信息
+
+
+
+
+ 返回数据集合
+
+
+
+
+ 返回成功
+
+ 消息
+
+
+
+
+ 返回成功
+
+ 消息
+ 数据
+
+
+
+
+ 返回失败
+
+ 消息
+
+
+
+
+ 返回失败
+
+ 消息
+ 数据
+
+
+
+
+ 返回消息
+
+ 失败/成功
+ 消息
+ 数据
+
+
+
+
+ 状态码
+
+
+
+
+ 操作是否成功
+
+
+
+
+ 返回信息
+
+
+
+
+ 返回数据集合
+
+
部门表
diff --git a/Tiobon.Core.Api/Tiobon.Core.xml b/Tiobon.Core.Api/Tiobon.Core.xml
index 87e917fb..91b45fa3 100644
--- a/Tiobon.Core.Api/Tiobon.Core.xml
+++ b/Tiobon.Core.Api/Tiobon.Core.xml
@@ -1216,6 +1216,11 @@
+
+
+ 服务器接口,因为是模板生成,所以首字母是大写的,自己可以重构下
+
+
服务管理
diff --git a/Tiobon.Core.Common/Attribute/FromFilterAttribute.cs b/Tiobon.Core.Common/Attribute/FromFilterAttribute.cs
new file mode 100644
index 00000000..67ac1cbb
--- /dev/null
+++ b/Tiobon.Core.Common/Attribute/FromFilterAttribute.cs
@@ -0,0 +1,276 @@
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace Tiobon.Core.Common
+{
+ public class FilterHeaderBinder : IModelBinder
+ {
+ public Task BindModelAsync(ModelBindingContext bindingContext)
+ {
+ if (bindingContext == null)
+ {
+ throw new ArgumentNullException(nameof(bindingContext));
+ }
+
+ var name = bindingContext.FieldName;
+
+ var headers = bindingContext.HttpContext.Request.Headers;
+
+ QueryFilter queryFilter;
+
+ if (!headers.ContainsKey(name))
+ {
+ queryFilter = QueryFilter.Default;
+ bindingContext.Result = ModelBindingResult.Success(queryFilter);
+ return Task.CompletedTask;
+ }
+
+ string filter = headers[name];
+
+ if (bindingContext.ModelType == typeof(string))
+ {
+ bindingContext.Result = ModelBindingResult.Success(filter);
+ return Task.CompletedTask;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty(filter) || filter == "%22%22" || filter.ToLower() == "%7b%7d")
+ {
+ queryFilter = QueryFilter.Default;
+ }
+ else if (filter.Trim() == "undefined" || filter.Trim() == "null")
+ {
+ queryFilter = QueryFilter.Default;
+ //LoggerHelper.SendLogError($"QueryFilter 反序列化异常: {filter}\r\n请求地址: {bindingContext.HttpContext.Request.GetEncodedUrl()}");
+ }
+ else
+ {
+ queryFilter = JsonConvert.DeserializeObject(System.Web.HttpUtility.UrlDecode(filter));
+ SetPredicateValues(queryFilter, bindingContext);
+ }
+
+ bindingContext.Result = ModelBindingResult.Success(queryFilter ?? QueryFilter.Default);
+ }
+ catch
+ {
+ //LoggerHelper.SendLogError($"QueryFilter 反序列化失败: {filter}\r\n请求地址: {bindingContext.HttpContext.Request.GetEncodedUrl()}");
+ bindingContext.Result = ModelBindingResult.Success(QueryFilter.Default);
+ }
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 设置 PredicateValues 的值类型
+ ///
+ ///
+ ///
+ private static void SetPredicateValues(QueryFilter queryFilter, ModelBindingContext bindingContext)
+ {
+ if (queryFilter?.PredicateValues == null || queryFilter.PredicateValues.Length == 0)
+ {
+ return;
+ }
+
+ for (int i = 0; i < queryFilter.PredicateValues.Length; i++)
+ {
+ if (queryFilter.PredicateValues[i] is JObject jObj)
+ {
+ var prop = jObj.Properties()?.FirstOrDefault();
+ if (prop == null)
+ continue;
+ var type = StringConvertToType(prop.Name);
+ if (type == null)
+ continue;
+ try
+ {
+ var v = JsonConvert.DeserializeObject(prop.Value?.ToString(), type);
+ if (v != null)
+ {
+ queryFilter.PredicateValues[i] = v;
+ }
+ }
+ catch (Exception ex)
+ {
+ //LoggerHelper.SendLogError($"QueryFilter.PredicateValues[{i}] [{queryFilter.PredicateValues[i]}] 反序列化失败\r\n" +
+ // $"请求地址: {bindingContext.HttpContext.Request.GetEncodedUrl()}\r\n" +
+ // $"错误信息: {ex}");
+ }
+ }
+ }
+ }
+
+
+ #region 字符串获取类型
+ ///
+ /// 根据 获取 类型
+ ///
+ ///
+ ///
+ public static Type StringConvertToType(string name)
+ {
+ if (string.IsNullOrEmpty(name))
+ {
+ return default;
+ }
+
+ switch (name.Trim().ToUpper())
+ {
+ case "INT":
+ case "INT32":
+ return typeof(int);
+ case "INT?":
+ case "INT32?":
+ return typeof(int?);
+ case "INT[]":
+ case "INT32[]":
+ return typeof(int[]);
+ case "INT?[]":
+ case "INT32?[]":
+ return typeof(int?[]);
+ case "LIST":
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ case "LIST":
+ return typeof(List);
+
+ case "LONG":
+ case "INT64":
+ return typeof(long);
+ case "LONG?":
+ case "INT64?":
+ return typeof(long?);
+ case "LONG[]":
+ case "INT64[]":
+ return typeof(long[]);
+ case "LONG?[]":
+ case "INT64?[]":
+ return typeof(long?[]);
+ case "LIST":
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ case "LIST":
+ return typeof(List);
+
+ case "FLOAT":
+ case "SINGLE":
+ return typeof(float);
+ case "FLOAT?":
+ case "SINGLE?":
+ return typeof(float?);
+ case "FLOAT[]":
+ case "SINGLE[]":
+ return typeof(float[]);
+ case "FLOAT?[]":
+ case "SINGLE?[]":
+ return typeof(float?[]);
+ case "LIST":
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ case "LIST":
+ return typeof(List);
+
+ case "DOUBLE":
+ return typeof(double);
+ case "DOUBLE?":
+ return typeof(double?);
+ case "DOUBLE[]":
+ return typeof(double[]);
+ case "DOUBLE?[]":
+ return typeof(double?[]);
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ return typeof(List);
+
+ case "DECIMAL":
+ return typeof(decimal);
+ case "DECIMAL?":
+ return typeof(decimal?);
+ case "DECIMAL[]":
+ return typeof(decimal[]);
+ case "DECIMAL?[]":
+ return typeof(decimal?[]);
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ return typeof(List);
+
+ case "DATETIME":
+ return typeof(DateTime);
+ case "DATETIME?":
+ return typeof(DateTime?);
+ case "DATETIME[]":
+ return typeof(DateTime[]);
+ case "DATETIME?[]":
+ return typeof(DateTime?[]);
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ return typeof(List);
+
+ case "GUID":
+ return typeof(Guid);
+ case "GUID?":
+ return typeof(Guid?);
+ case "GUID[]":
+ return typeof(Guid[]);
+ case "GUID?[]":
+ return typeof(Guid?[]);
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ return typeof(List);
+
+ case "BOOL":
+ return typeof(bool);
+ case "BOOL?":
+ return typeof(bool?);
+ case "BOOL[]":
+ return typeof(bool[]);
+ case "BOOL?[]":
+ return typeof(bool?[]);
+ case "LIST":
+ return typeof(List);
+ case "LIST":
+ return typeof(List);
+
+ case "STRING":
+ return typeof(string);
+ case "STRING[]":
+ return typeof(string[]);
+ case "LIST":
+ return typeof(List);
+
+ default:
+ break;
+ }
+
+ return Type.GetType(name);
+ }
+ #endregion
+ }
+
+ ///
+ /// 从 Header 自动反序列化 QueryFilter 并绑定
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
+ public class FromFilterAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider, IBinderTypeProviderMetadata
+ {
+ public FromFilterAttribute()
+ {
+ }
+
+ public BindingSource BindingSource => BindingSource.Header;
+
+ public string Name { get; set; }
+
+ public Type BinderType => typeof(FilterHeaderBinder);
+ }
+
+
+}
diff --git a/Tiobon.Core.Common/Attribute/QueryFilter.cs b/Tiobon.Core.Common/Attribute/QueryFilter.cs
new file mode 100644
index 00000000..bfa45dc4
--- /dev/null
+++ b/Tiobon.Core.Common/Attribute/QueryFilter.cs
@@ -0,0 +1,89 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Tiobon.Core.Common
+{
+ ///
+ /// 动态查询条件
+ ///
+ public class QueryFilter
+ {
+ private int _pageIndex;
+ ///
+ /// 起始位置(e.g. 0)
+ ///
+ [Required]
+ public int PageIndex
+ {
+ get { return _pageIndex; }
+ set
+ {
+ //前端默认从分页显示默认1开始,所以后端需要-1
+ if (value >= 1)
+ value -= 1;
+ _pageIndex = value;
+ }
+ }
+ ///
+ /// 每页数量(e.g. 10)
+ ///
+ [Required]
+ public int PageSize { get; set; }
+ private string _predicate;
+ ///
+ /// 查询条件表达式(e.g. LoginName.Contains(@0))
+ ///
+ public string Predicate
+ {
+ get { return _predicate; }
+ set
+ {
+ //前端默认从分页显示默认1开始,所以后端需要-1
+ if (value == "1=1")
+ value = null;
+ _predicate = value;
+ }
+ }
+ ///
+ /// 查询条件表达式参数(e.g. LoginName)
+ ///
+ public object[] PredicateValues { get; set; }
+ ///
+ /// 排序条件表达式(e.g. LoginName ASC,Name DESC)
+ ///
+ public string Sorting { get; set; }
+ /////
+ ///// 患者关键字(姓名、别名、拼音、五笔)模糊查询
+ /////
+ //public string PatientKey { get; set; }
+ /////
+ ///// 报表患者过滤条件
+ /////
+ //public PatientFilter PatientFilter { get; set; }
+ /////
+ ///// 分组条件(e.g. [10,20,30])
+ /////
+ //public List GroupValues { get; set; }
+ /////
+ ///// 导出字段,按照顺序填写(e.g. [{ Key: 'PatientNameFull', Name: '患者姓名' }, { Key: 'DeviceCode', Name: '设备编号' }])
+ /////
+ //public List ExportFields { get; set; }
+ /////
+ ///// 导出字段的宽度(默认20),按照顺序与字段一一对应填写(e.g. [20,50,20])
+ /////
+ //public List ExportFieldsWidth { get; set; }
+ ///
+ /// 缺省值
+ ///
+ public static QueryFilter Default => new QueryFilter
+ {
+ PageIndex = 1,
+ PageSize = 100000,
+ Sorting = string.Empty,
+ Predicate = string.Empty,
+ PredicateValues = Array.Empty