Просмотр исходного кода

1完善apijson删除功能,增加非id删除,支持批量
2增加jtoken转SugarParameter函数

苏智明 2 лет назад
Родитель
Сommit
37fc243e0e

+ 4 - 4
Admin.NET/Admin.NET.Application/Configuration/APIJSON.json

@@ -7,16 +7,16 @@
         "RoleName": "Role1", // 权限名称 唯一
         "Select": { // 查询
           "Table": [ "*" ], // 可操作的表
-          "Column": [ "tb.*" ], // 可操作的字段
+          "Column": [ "*" ], // 可操作的字段
           "Filter": []
         },
         "Insert": { // 添加
           "Table": [ "table1", "table2", "table3" ],
-          "Column": [ "tb.*", "tb.*", "tb.*" ]
+          "Column": [ "*", "tb.*", "tb.*" ]
         },
         "Update": { // 修改
           "Table": [ "table1", "table2", "table3" ],
-          "Column": [ "tb.*", "tb.*", "tb.*" ]
+          "Column": [ "*", "tb.*", "tb.*" ]
         },
         "Delete": { // 删除
           "Table": [ "table1", "table2", "table3" ]
@@ -26,7 +26,7 @@
         "RoleName": "Role2",
         "Select": {
           "Table": [ "table1" ],
-          "Column": [ "*" ]
+          "Column": [ "tb.*" ]
         }
       }
     ]

+ 1 - 1
Admin.NET/Admin.NET.Application/Configuration/Logging.json

@@ -34,7 +34,7 @@
       "JsonBehavior": "None", // 是否输出Json,默认None(OnlyJson、All)
       "JsonIndented": false, // 是否格式化Json
       "UseUtcTimestamp": false, // 时间格式UTC、LOCAL
-      "ConsoleLog": true // 是否显示控制台日志
+      "ConsoleLog": false // 是否显示控制台日志
     }
   }
 }

+ 1 - 1
Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj

@@ -39,7 +39,7 @@
     <PackageReference Include="SixLabors.ImageSharp.Web" Version="3.1.0" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="3.0.0" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.0.1" />
-    <PackageReference Include="SqlSugarCore" Version="5.1.4.142" />
+    <PackageReference Include="SqlSugarCore" Version="5.1.4.144" />
     <PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.8" />
     <PackageReference Include="UAParser" Version="3.1.47" />
     <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />

+ 6 - 4
Admin.NET/Admin.NET.Core/Extension/ObjectExtension.cs

@@ -257,15 +257,17 @@ public static partial class ObjectExtension
     }
 
     /// <summary>
-    /// 判断是否有值
+    /// 是否有值
     /// </summary>
-    /// <param name="obj"></param>
+    /// <param name="str"></param>
     /// <returns></returns>
-    public static bool IsNullOrEmpty(this object obj)
+    public static bool HasValue(this object str)
     {
-        return obj == null || string.IsNullOrEmpty(obj.ToString());
+        return str != null && !string.IsNullOrEmpty(str.ToString());
     }
 
+
+
     /// <summary>
     /// 字符串掩码
     /// </summary>

+ 187 - 4
Admin.NET/Admin.NET.Core/Service/APIJSON/APIJSONService.cs

@@ -7,6 +7,7 @@
 // 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
 // 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
 
+using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 
 namespace Admin.NET.Core.Service;
@@ -20,6 +21,7 @@ public class APIJSONService : IDynamicApiController, ITransient
     private readonly ISqlSugarClient _db;
     private readonly IdentityService _identityService;
     private readonly TableMapper _tableMapper;
+    private readonly SelectTable _selectTable;
 
     public APIJSONService(ISqlSugarClient db,
         IdentityService identityService,
@@ -28,16 +30,197 @@ public class APIJSONService : IDynamicApiController, ITransient
         _db = db;
         _tableMapper = tableMapper;
         _identityService = identityService;
+        _selectTable = new SelectTable(_identityService, _tableMapper, _db);
     }
 
     /// <summary>
-    /// 统一入口
+    /// 统一查询入口
     /// </summary>
     /// <param name="jobject"></param>
-    /// <remarks>参数:{"[]":{"SYS_LOG_OP":{}}}</remarks>
+    /// <remarks>参数:{"[]":{"SYSLOGOP":{}}}</remarks>
     /// <returns></returns>
-    public JObject Post([FromBody] JObject jobject)
+    [HttpPost("get")]
+    public JObject Query([FromBody] JObject jobject)
     {
-        return new SelectTable(_identityService, _tableMapper, _db).Query(jobject);
+        return _selectTable.Query(jobject);
+    }
+
+
+    [HttpPost("get/{table}")]
+    public async Task<JObject> QueryByTable([FromRoute] string table, [FromBody] JObject jobject)
+    {
+
+        JObject ht = new JObject();
+
+        ht.Add(table + "[]", jobject);
+
+        if (jobject["query"] != null && jobject["query"].ToString() != "0" && jobject["total@"] == null)
+        {
+            //自动添加总计数量
+            ht.Add("total@", "");
+        }
+
+        //每页最大1000条数据
+        if (jobject["count"] != null && int.Parse(jobject["count"].ToString()) > 1000)
+        {
+            throw Oops.Bah("count分页数量最大不能超过1000");
+        }
+
+        bool isDebug = (jobject["@debug"] != null && jobject["@debug"].ToString() != "0");
+        jobject.Remove("@debug");
+
+        bool hasTableKey = false;
+        List<string> ignoreConditions = new List<string> { "page", "count", "query" };
+        JObject tableConditions = new JObject();//表的其它查询条件,比如过滤,字段等
+        foreach (var item in jobject)
+        {
+            if (item.Key.Equals(table, StringComparison.CurrentCultureIgnoreCase))
+            {
+                hasTableKey = true;
+                break;
+            }
+            if (!ignoreConditions.Contains(item.Key.ToLower()))
+            {
+                tableConditions.Add(item.Key, item.Value);
+            }
+        }
+
+        foreach (var removeKey in tableConditions)
+        {
+            jobject.Remove(removeKey.Key);
+        }
+
+        if (!hasTableKey)
+        {
+            jobject.Add(table, tableConditions);
+        }
+
+        return Query(ht);
+    }
+    /// <summary>
+    /// 新增
+    /// </summary>
+    /// <param name="json"></param>
+    /// <returns></returns>
+    [HttpPost("post")]
+    public JObject Add([FromBody] JObject jobject)
+    {
+
+        JObject ht = new JObject();
+
+        foreach (var item in jobject)
+        {
+            string key = item.Key.Trim();
+            var role = _identityService.GetRole();
+            if (!role.Insert.Table.Contains(key, StringComparer.CurrentCultureIgnoreCase))
+            {
+                throw Oops.Bah($"没权限添加{key}");
+            }
+            var dt = new Dictionary<string, object>();
+            foreach (var f in JObject.Parse(item.Value.ToString()))
+            {
+                if (f.Key.ToLower() != "id" && _selectTable.IsCol(key, f.Key) && (role.Insert.Column.Contains("*") || role.Insert.Column.Contains(f.Key, StringComparer.CurrentCultureIgnoreCase)))
+                    dt.Add(f.Key, f.Value);
+            }
+            //todo 自定义id
+            int id = _db.Insertable(dt).AS(key).ExecuteReturnIdentity();
+            ht.Add(key, JToken.FromObject(new { code = 200, msg = "success", id }));
+        }
+
+        return ht;
+    }
+    /// <summary>
+    /// 修改
+    /// </summary>
+    /// <param name="json"></param>
+    /// <returns></returns>
+    [HttpPost("put")]
+    public JObject Edit([FromBody] JObject jobject)
+    {
+        JObject ht = new JObject();
+
+        foreach (var item in jobject)
+        {
+            string key = item.Key.Trim();
+            var role = _identityService.GetRole();
+            if (!role.Update.Table.Contains(key, StringComparer.CurrentCultureIgnoreCase))
+            {
+
+                throw Oops.Bah("没权限修改{key}");
+            }
+            var value = JObject.Parse(item.Value.ToString());
+            if (!value.ContainsKey("id"))
+            {
+
+                throw Oops.Bah("未传主键id");
+            }
+
+            var dt = new Dictionary<string, object>();
+            foreach (var f in value)
+            {
+                if (f.Key.ToLower() != "id" && _selectTable.IsCol(key, f.Key) && (role.Update.Column.Contains("*") || role.Update.Column.Contains(f.Key, StringComparer.CurrentCultureIgnoreCase)))
+                {
+                    dt.Add(f.Key, f.Value.ToString());
+                }
+            }
+            _db.Updateable(dt).AS(key).Where("id=@id", new { id = value["id"].ToString() }).ExecuteCommand();
+            ht.Add(key, JToken.FromObject(new { code = 200, msg = "success", id = value["id"].ToString() }));
+        }
+
+        return ht;
+    }
+    /// <summary>
+    /// 删除 支持非id条件,支持批量
+    /// </summary>
+    /// <param name="jobject"></param>
+    /// <returns></returns>
+    [HttpPost("delete")]
+    public JObject Delete([FromBody] JObject jobject)
+    {
+        JObject ht = new JObject();
+        var role = _identityService.GetRole();
+        foreach (var item in jobject)//每个表执行一次
+        {
+            string talbeName = item.Key.Trim();
+            var value = JObject.Parse(item.Value.ToString());//"id":""            
+            
+            if (role.Delete == null || role.Delete.Table == null)
+            {
+                throw Oops.Bah("delete权限未配置");
+            }
+            if (!role.Delete.Table.Contains(talbeName, StringComparer.CurrentCultureIgnoreCase))
+            {
+                throw Oops.Bah($"没权限删除{talbeName}");
+            }
+            //if (!value.ContainsKey("id"))
+            //{
+            //    throw Oops.Bah("未传主键id");
+            //}
+
+            var sb = new StringBuilder(100);
+            List< SugarParameter > parameters = new List< SugarParameter >();
+            foreach (var f in value)//每个条件
+            {
+                if (f.Value is JArray)//数组
+                {
+                    sb.Append($"{f.Key} in (@{f.Key}) and ");
+                    var paraArray =FuncList.TransJArrayToSugarPara(f.Value);
+                    parameters.Add(new SugarParameter($"@{f.Key}", paraArray));
+                    //sb.Append($"{f.Key} in ({f.Value.ToString().TrimStart("[").TrimEnd("]").TrimInvisible()})  and");
+                }
+                else
+                {
+                    sb.Append($"{f.Key}=@{f.Key} and ");
+                    parameters.Add(new SugarParameter($"@{f.Key}", FuncList.TransJObjectToSugarPara(f.Value)));
+                }
+
+            }
+            string whereSql = sb.ToString().TrimEnd(" and ");
+            int count = _db.Deleteable<object>().AS(talbeName).Where(whereSql,parameters).ExecuteCommand();//无实体删除
+            value.Add("count", count);//命中数量
+            ht.Add(talbeName, value);
+            
+        }
+        return ht;
     }
 }

+ 74 - 0
Admin.NET/Admin.NET.Core/Service/APIJSON/FuncList.cs

@@ -7,6 +7,11 @@
 // 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
 // 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
 
+using NewLife.Reflection;
+using Newtonsoft.Json.Linq;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+
 namespace Admin.NET.Core.Service;
 
 /// <summary>
@@ -46,4 +51,73 @@ public class FuncList
     {
         return a.ToString().Split(',').Contains(b);
     }
+    /// <summary>
+    /// 获取JToken的数据类型,用于SugarParameter里的类型转换
+    /// </summary>
+    /// <param name="jToken"></param>
+    /// <returns></returns>
+    public static Type GetTypeFromJToken(JToken jToken)
+    {
+        JTokenType jTokenType = jToken.Type;
+        return jTokenType switch
+        {
+            JTokenType.Integer => typeof(long),
+            JTokenType.Float => typeof(decimal),
+            JTokenType.Boolean => typeof(bool),
+            JTokenType.Date => typeof(DateTime),
+            JTokenType.Bytes => typeof(byte),
+            JTokenType.Guid => typeof(Guid),
+            JTokenType.TimeSpan => typeof(TimeSpan),
+            _ => jToken.GetType(),
+        };
+    }
+
+    /// <summary>
+    /// 根据jtoken的实际类型来转换SugarParameter,避免全转成字符串
+    /// </summary>
+    /// <param name="jToken"></param>
+    /// <returns></returns>
+    public static dynamic TransJObjectToSugarPara(JToken jToken)
+    {
+        JTokenType jTokenType = jToken.Type;
+        return jTokenType switch
+        {
+            JTokenType.Integer => jToken.ToObject(typeof(long)),
+            JTokenType.Float => jToken.ToObject(typeof(decimal)),
+            JTokenType.Boolean => jToken.ToObject(typeof(bool)),
+            JTokenType.Date => jToken.ToObject(typeof(DateTime)),
+            JTokenType.Bytes => jToken.ToObject(typeof(byte)),
+            JTokenType.Guid => jToken.ToObject(typeof(Guid)),
+            JTokenType.TimeSpan => jToken.ToObject(typeof(TimeSpan)),
+            JTokenType.Array => TransJArrayToSugarPara(jToken),
+            _ => jToken
+        };
+    }
+
+    /// <summary>
+    /// 根据jArray的实际类型来转换SugarParameter,避免全转成字符串
+    /// </summary>
+    /// <param name="jToken"></param>
+    /// <returns></returns>
+    public static dynamic TransJArrayToSugarPara(JToken jToken)
+    {
+        if (jToken is not JArray) return jToken;
+        if (jToken.Any())
+        {
+            JTokenType jTokenType = jToken.First().Type;
+            return jTokenType switch
+            {
+                JTokenType.Integer => jToken.ToObject<long[]>(),
+                JTokenType.Float => jToken.ToObject<decimal[]>(),
+                JTokenType.Boolean => jToken.ToObject<bool[]>(),
+                JTokenType.Date => jToken.ToObject<DateTime[]>(),
+                JTokenType.Bytes => jToken.ToObject<byte[]>(),
+                JTokenType.Guid => jToken.ToObject<Guid[]>(),
+                JTokenType.TimeSpan => jToken.ToObject<TimeSpan[]>(),
+                _ => jToken.ToArray()
+            } ;
+        }
+        else return (JArray)jToken;
+
+    }
 }

+ 182 - 183
Admin.NET/Admin.NET.Core/Service/APIJSON/SelectTable.cs

@@ -11,6 +11,7 @@ namespace Admin.NET.Core.Service;
 
 using AspectCore.Extensions.Reflection;
 using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Schema;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
@@ -28,7 +29,7 @@ public class SelectTable : ISingleton
     private readonly ISqlSugarClient db;
 
     /// <summary>
-    ///
+    /// 
     /// </summary>
     /// <param name="identityService"></param>
     /// <param name="tableMapper"></param>
@@ -39,71 +40,38 @@ public class SelectTable : ISingleton
         _tableMapper = tableMapper;
         db = dbClient;
     }
-
     /// <summary>
     /// 判断表名是否正确
     /// </summary>
     /// <param name="table"></param>
     /// <returns></returns>
-    public bool IsTable(string table)
+    public virtual bool IsTable(string table)
     {
         return db.DbMaintenance.GetTableInfoList().Any(it => it.Name.Equals(table, StringComparison.CurrentCultureIgnoreCase));
     }
-
     /// <summary>
     /// 判断表的列名是否正确
     /// </summary>
     /// <param name="table"></param>
     /// <param name="col"></param>
     /// <returns></returns>
-    public bool IsCol(string table, string col)
+    public virtual bool IsCol(string table, string col)
     {
         return db.DbMaintenance.GetColumnInfosByTableName(table).Any(it => it.DbColumnName.Equals(col, StringComparison.CurrentCultureIgnoreCase));
     }
 
     /// <summary>
-    /// 动态调用方法
-    /// </summary>
-    /// <param name="funcname"></param>
-    /// <param name="param"></param>
-    /// <param name="types"></param>
-    /// <returns></returns>
-    public object ExecFunc(string funcname, object[] param, Type[] types)
-    {
-        var method = typeof(FuncList).GetMethod(funcname);
-
-        var reflector = method.GetReflector();
-        var result = reflector.Invoke(new FuncList(), param);
-        return result;
-    }
-
-    private string ToSql(string subtable, int page, int count, int query, string json)
-    {
-        JObject values = JObject.Parse(json);
-        page = values["page"] == null ? page : int.Parse(values["page"].ToString());
-        count = values["count"] == null ? count : int.Parse(values["count"].ToString());
-        query = values["query"] == null ? query : int.Parse(values["query"].ToString());
-        values.Remove("page");
-        values.Remove("count");
-        subtable = _tableMapper.GetTableName(subtable);
-        var tb = sugarQueryable(subtable, "*", values, null);
-        var xx = tb.Skip((page - 1) * count).Take(10).ToSql();
-        return xx.Key;
-    }
-
-    /// <summary>
-    ///
+    /// 
     /// </summary>
     /// <param name="subtable"></param>
     /// <param name="page"></param>
     /// <param name="count"></param>
-    /// <param name="query"></param>
     /// <param name="json"></param>
     /// <param name="dd"></param>
     /// <returns></returns>
-    /// <exception cref="Exception"></exception>
-    public Tuple<dynamic, int> GetTableData(string subtable, int page, int count, int query, string json, JObject dd)
+    public virtual Tuple<dynamic, int> GetTableData(string subtable, int page, int count, int query, string json, JObject dd)
     {
+
         var role = _identitySvc.GetSelectRole(subtable);
         if (!role.Item1)//没有权限返回异常
         {
@@ -131,6 +99,7 @@ public class SelectTable : ISingleton
                 else
                     //2-以上全部
                     return new Tuple<dynamic, int>(tb.ToPageList(page, count, ref total), total);
+
             }
             else
             {
@@ -142,67 +111,17 @@ public class SelectTable : ISingleton
         }
     }
 
-    /// <summary>
-    ///
-    /// </summary>
-    /// <param name="subtable"></param>
-    /// <param name="json"></param>
-    /// <param name="dd"></param>
-    /// <returns></returns>
-    public dynamic GetFirstData(string subtable, string json, JObject dd)
-    {
-        var role = _identitySvc.GetSelectRole(subtable);
-        if (!role.Item1)//没有权限返回异常
-        {
-            throw new Exception(role.Item2);
-        }
-        string selectrole = role.Item2;
-        subtable = _tableMapper.GetTableName(subtable);
-        JObject values = JObject.Parse(json);
-        values.Remove("page");
-        values.Remove("count");
-        var tb = sugarQueryable(subtable, selectrole, values, dd).First();
-        var dic = (IDictionary<string, object>)tb;
-        foreach (var item in values.Properties().Where(it => it.Name.EndsWith("()")))
-        {
-            if (!item.Value.IsNullOrEmpty())
-            {
-                string func = item.Value.ToString().Substring(0, item.Value.ToString().IndexOf("("));
-                string param = item.Value.ToString().Substring(item.Value.ToString().IndexOf("(") + 1).TrimEnd(')');
-                var types = new List<Type>();
-                var paramss = new List<object>();
-                foreach (var va in param.Split(','))
-                {
-                    types.Add(typeof(object));
-                    paramss.Add(tb.Where(it => it.Key.Equals(va)).Select(i => i.Value));
-                }
-                dic[item.Name] = ExecFunc(func, paramss.ToArray(), types.ToArray());
-            }
-        }
-
-        return tb;
-    }
-
     /// <summary>
     /// 解析并查询
     /// </summary>
-    /// <param name="queryJson"></param>
+    /// <param name="query"></param>
     /// <returns></returns>
-    public JObject Query(string queryJson)
+    public virtual JObject Query(string queryJson)
     {
-        JObject resultObj = new();
-
-        try
-        {
-            JObject queryJobj = JObject.Parse(queryJson);
-            resultObj = Query(queryJobj);
-        }
-        catch (Exception ex)
-        {
-            resultObj.Add("code", "500");
-            resultObj.Add("msg", ex.Message);
-        }
+        JObject resultObj = new JObject();
 
+        JObject queryJobj = JObject.Parse(queryJson);
+        resultObj = Query(queryJobj);
         return resultObj;
     }
 
@@ -212,37 +131,29 @@ public class SelectTable : ISingleton
     /// <param name="queryObj"></param>
     /// <param name="nodeName">返回数据的节点名称  默认为 infos</param>
     /// <returns></returns>
-    public JObject QuerySingle(JObject queryObj, string nodeName = "infos")
+    public virtual JObject QuerySingle(JObject queryObj, string nodeName = "infos")
     {
-        JObject resultObj = new();
-        resultObj.Add("code", "200");
-        resultObj.Add("msg", "success");
-        try
+        JObject resultObj = new JObject();
+
+        int total = 0;
+        foreach (var item in queryObj)
         {
-            int total = 0;
-            foreach (var item in queryObj)
-            {
-                string key = item.Key.Trim();
+            string key = item.Key.Trim();
 
-                if (key.EndsWith("[]"))
-                {
-                    total = QuerySingleList(resultObj, item, nodeName);
-                }
-                else if (key.Equals("func"))
-                {
-                    ExecFunc(resultObj, item);
-                }
-                else if (key.Equals("total@"))
-                {
-                    resultObj.Add("total", total);
-                }
+            if (key.EndsWith("[]"))
+            {
+                total = QuerySingleList(resultObj, item, nodeName);
+            }
+            else if (key.Equals("func"))
+            {
+                ExecFunc(resultObj, item);
+            }
+            else if (key.Equals("total@")|| key.Equals("total"))
+            {
+                resultObj.Add("total", total);
             }
         }
-        catch (Exception ex)
-        {
-            resultObj["code"] = "500";
-            resultObj["msg"] = ex.Message;
-        }
+
         return resultObj;
     }
 
@@ -251,7 +162,7 @@ public class SelectTable : ISingleton
     /// </summary>
     /// <param name="queryObj"></param>
     /// <returns></returns>
-    public string ToSql(JObject queryObj)
+    public virtual string ToSql(JObject queryObj)
     {
         foreach (var item in queryObj)
         {
@@ -268,52 +179,109 @@ public class SelectTable : ISingleton
     /// <summary>
     /// 解析并查询
     /// </summary>
-    /// <param name="queryObj"></param>
+    /// <param name="query"></param>
     /// <returns></returns>
-    public JObject Query(JObject queryObj)
+    public virtual JObject Query(JObject queryObj)
     {
-        JObject resultObj = new();
-        resultObj.Add("code", "200");
-        resultObj.Add("msg", "success");
-        try
+        JObject resultObj = new JObject();
+
+        int total = 0;
+        foreach (var item in queryObj)
         {
-            int total = 0;
-            foreach (var item in queryObj)
-            {
-                string key = item.Key.Trim();
+            string key = item.Key.Trim();
 
-                if (key.Equals("[]"))
-                {
-                    total = QueryMoreList(resultObj, item);
-                }
-                else if (key.EndsWith("[]"))
-                {
-                    total = QuerySingleList(resultObj, item);
-                }
-                else if (key.Equals("func"))
-                {
-                    ExecFunc(resultObj, item);
-                }
-                else if (key.Equals("total@"))
-                {
-                    resultObj.Add("total", total);
-                }
-                else
+            if (key.Equals("[]"))
+            {
+                total = QueryMoreList(resultObj, item);
+            }
+            else if (key.EndsWith("[]"))
+            {
+                total = QuerySingleList(resultObj, item);
+            }
+            else if (key.Equals("func"))
+            {
+                ExecFunc(resultObj, item);
+            }
+            else if (key.Equals("total@") || key.Equals("total"))
+            {
+                resultObj.Add("total", total);
+            }
+            else
+            {
+                var template = GetFirstData(key, item.Value.ToString(), resultObj);
+                if (template != null)
                 {
-                    var template = GetFirstData(key, item.Value.ToString(), resultObj);
-                    if (template != null)
-                    {
-                        resultObj.Add(key, JToken.FromObject(template));
-                    }
+                    resultObj.Add(key, JToken.FromObject(template));
                 }
             }
         }
-        catch (Exception ex)
+
+        return resultObj;
+    }
+
+
+
+    //动态调用方法
+    private object ExecFunc(string funcname, object[] param, Type[] types)
+    {
+        var method = typeof(FuncList).GetMethod(funcname);
+
+        var reflector = method.GetReflector();
+        var result = reflector.Invoke(new FuncList(), param);
+        return result;
+    }
+
+    //生成sql
+    private string ToSql(string subtable, int page, int count, int query, string json)
+    {
+        JObject values = JObject.Parse(json);
+        page = values["page"] == null ? page : int.Parse(values["page"].ToString());
+        count = values["count"] == null ? count : int.Parse(values["count"].ToString());
+        query = values["query"] == null ? query : int.Parse(values["query"].ToString());
+        values.Remove("page");
+        values.Remove("count");
+        subtable = _tableMapper.GetTableName(subtable);
+        var tb = sugarQueryable(subtable, "*", values, null);
+        var sqlObj = tb.Skip((page - 1) * count).Take(10).ToSql();
+        return sqlObj.Key;
+    }
+
+    //
+    private dynamic GetFirstData(string subtable, string json, JObject job)
+    {
+
+        var role = _identitySvc.GetSelectRole(subtable);
+        if (!role.Item1)//没有权限返回异常
         {
-            resultObj["code"] = "500";
-            resultObj["msg"] = ex.Message;
+            throw new Exception(role.Item2);
         }
-        return resultObj;
+        string selectrole = role.Item2;
+        subtable = _tableMapper.GetTableName(subtable);
+        JObject values = JObject.Parse(json);
+        values.Remove("page");
+        values.Remove("count");
+        //todo *
+        var tb = sugarQueryable(subtable, selectrole, values, job).First();
+        var dic = (IDictionary<string, object>)tb;
+        foreach (var item in values.Properties().Where(it => it.Name.EndsWith("()")))
+        {
+            if (item.Value.HasValue())
+            {
+                string func = item.Value.ToString().Substring(0, item.Value.ToString().IndexOf("("));
+                string param = item.Value.ToString().Substring(item.Value.ToString().IndexOf("(") + 1).TrimEnd(')');
+                var types = new List<Type>();
+                var paramss = new List<object>();
+                foreach (var va in param.Split(','))
+                {
+                    types.Add(typeof(object));
+                    paramss.Add(tb.Where(it => it.Key.Equals(va)).Select(i => i.Value));
+                }
+                dic[item.Name] = ExecFunc(func, paramss.ToArray(), types.ToArray());
+            }
+        }
+
+        return tb;
+
     }
 
     //单表查询,返回的数据在指定的NodeName节点
@@ -351,6 +319,7 @@ public class SelectTable : ISingleton
         return total;
     }
 
+    //生成sql
     private string ToSql(KeyValuePair<string, JToken> item)
     {
         string key = item.Key.Trim();
@@ -387,7 +356,7 @@ public class SelectTable : ISingleton
         var query = jb["query"] == null ? 0 : int.Parse(jb["query"].ToString());
         jb.Remove("page"); jb.Remove("count"); jb.Remove("query");
         var htt = new JArray();
-        List<string> tables = new(), where = new();
+        List<string> tables = new List<string>(), where = new List<string>();
         foreach (var t in jb)
         {
             tables.Add(t.Key); where.Add(t.Value.ToString());
@@ -428,11 +397,13 @@ public class SelectTable : ISingleton
                         if (ddf != null)
                         {
                             zht.Add(subtable, JToken.FromObject(ddf));
+
                         }
                     }
                 }
                 htt.Add(zht);
             }
+
         }
         if (query != 1)
         {
@@ -442,6 +413,7 @@ public class SelectTable : ISingleton
         return total;
     }
 
+    //执行方法
     private void ExecFunc(JObject resultObj, KeyValuePair<string, JToken> item)
     {
         JObject jb = JObject.Parse(item.Value.ToString());
@@ -462,6 +434,7 @@ public class SelectTable : ISingleton
         resultObj.Add("func", dataJObj);
     }
 
+    //
     private ISugarQueryable<ExpandoObject> sugarQueryable(string subtable, string selectrole, JObject values, JObject dd)
     {
         if (!IsTable(subtable))
@@ -470,7 +443,8 @@ public class SelectTable : ISingleton
         }
         var tb = db.Queryable(subtable, "tb");
 
-        if (!values["@column"].IsNullOrEmpty())
+
+        if (values["@column"].HasValue())
         {
             ProcessColumn(subtable, selectrole, values, tb);
         }
@@ -479,8 +453,8 @@ public class SelectTable : ISingleton
             tb.Select(selectrole);
         }
 
-        List<IConditionalModel> conModels = new();
-        if (!values["identity"].IsNullOrEmpty())
+        List<IConditionalModel> conModels = new List<IConditionalModel>();
+        if (values["identity"].HasValue())
         {
             conModels.Add(new ConditionalModel() { FieldName = values["identity"].ToString(), ConditionalType = ConditionalType.Equal, FieldValue = _identitySvc.GetUserIdentity() });
         }
@@ -488,7 +462,10 @@ public class SelectTable : ISingleton
         {
             string vakey = va.Key.Trim();
             string fieldValue = va.Value.ToString();
-
+            if (vakey.StartsWith("@"))
+            {
+                continue;
+            }
             if (vakey.EndsWith("$"))//模糊查询
             {
                 FuzzyQuery(subtable, conModels, va);
@@ -497,7 +474,7 @@ public class SelectTable : ISingleton
             {
                 ConditionQuery(subtable, conModels, va);
             }
-            else if (vakey.EndsWith("%"))//between查询
+            else if (vakey.EndsWith("%"))//bwtween查询
             {
                 ConditionBetween(subtable, conModels, va);
             }
@@ -515,6 +492,11 @@ public class SelectTable : ISingleton
                 }
 
                 conModels.Add(new ConditionalModel() { FieldName = vakey.TrimEnd('@'), ConditionalType = ConditionalType.Equal, FieldValue = value });
+
+            }
+            else if (vakey.EndsWith("~"))//不等于
+            {
+                conModels.Add(new ConditionalModel() { FieldName = vakey.TrimEnd('~'), ConditionalType = ConditionalType.NoEqual, FieldValue = fieldValue });
             }
             else if (IsCol(subtable, vakey)) //其他where条件
             {
@@ -527,7 +509,7 @@ public class SelectTable : ISingleton
         ProcessOrder(subtable, values, tb);
 
         //分组
-        ProcessGroup(subtable, values, tb);
+        PrccessGroup(subtable, values, tb);
 
         //Having
         ProcessHaving(values, tb);
@@ -558,10 +540,16 @@ public class SelectTable : ISingleton
                     {
                         throw new Exception("别名不能超过20个字符");
                     }
-                    str.Append(ziduan[0] + " as " + ReplaceSQLChar(ziduan[1]) + ",");
+                    str.Append(ziduan[0] + " as `" + ReplaceSQLChar(ziduan[1]) + "`,");
+                }
+                //不对函数加``,解决sum(*),Count(1)等不能使用的问题
+                else if (ziduan[0].Contains('('))
+                {
+                    str.Append( ziduan[0]+ ",");
                 }
                 else
-                    str.Append(ziduan[0] + ",");
+                    str.Append("`" + ziduan[0] + "`" + ",");
+
             }
         }
         if (string.IsNullOrEmpty(str.ToString()))
@@ -575,10 +563,10 @@ public class SelectTable : ISingleton
     // SQL函数条件,一般和 @group一起用,函数一般在 @column里声明
     private void ProcessHaving(JObject values, ISugarQueryable<ExpandoObject> tb)
     {
-        if (!values["@having"].IsNullOrEmpty())
+        if (values["@having"].HasValue())
         {
-            List<IConditionalModel> hw = new();
-            List<string> havingItems = new();
+            List<IConditionalModel> hw = new List<IConditionalModel>();
+            List<string> havingItems = new List<string>();
             if (values["@having"].HasValues)
             {
                 havingItems = values["@having"].Select(p => p.ToString()).ToList();
@@ -599,17 +587,18 @@ public class SelectTable : ISingleton
                 }
                 else if (and.Contains("<="))
                 {
+
                     model.FieldName = and.Split(new string[] { "<=" }, StringSplitOptions.RemoveEmptyEntries)[0];
                     model.ConditionalType = ConditionalType.LessThanOrEqual;
                     model.FieldValue = and.Split(new string[] { "<=" }, StringSplitOptions.RemoveEmptyEntries)[1];
                 }
-                else if (and.Contains('>'))
+                else if (and.Contains(">"))
                 {
                     model.FieldName = and.Split(new string[] { ">" }, StringSplitOptions.RemoveEmptyEntries)[0];
                     model.ConditionalType = ConditionalType.GreaterThan;
                     model.FieldValue = and.Split(new string[] { ">" }, StringSplitOptions.RemoveEmptyEntries)[1];
                 }
-                else if (and.Contains('<'))
+                else if (and.Contains("<"))
                 {
                     model.FieldName = and.Split(new string[] { "<" }, StringSplitOptions.RemoveEmptyEntries)[0];
                     model.ConditionalType = ConditionalType.LessThan;
@@ -621,7 +610,7 @@ public class SelectTable : ISingleton
                     model.ConditionalType = ConditionalType.NoEqual;
                     model.FieldValue = and.Split(new string[] { "!=" }, StringSplitOptions.RemoveEmptyEntries)[1];
                 }
-                else if (and.Contains('='))
+                else if (and.Contains("="))
                 {
                     model.FieldName = and.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[0];
                     model.ConditionalType = ConditionalType.Equal;
@@ -630,6 +619,8 @@ public class SelectTable : ISingleton
                 hw.Add(model);
             }
 
+            //var d = db.Context.Utilities.ConditionalModelToSql(hw);
+            //tb.Having(d.Key, d.Value);
             tb.Having(string.Join(",", havingItems));
         }
     }
@@ -637,9 +628,9 @@ public class SelectTable : ISingleton
     //"@group":"column0,column1...",分组方式。如果 @column里声明了Table的id,则id也必须在 @group中声明;其它情况下必须满足至少一个条件:
     //1.分组的key在 @column里声明
     //2.Table主键在 @group中声明
-    private void ProcessGroup(string subtable, JObject values, ISugarQueryable<ExpandoObject> tb)
+    private void PrccessGroup(string subtable, JObject values, ISugarQueryable<ExpandoObject> tb)
     {
-        if (!values["@group"].IsNullOrEmpty())
+        if (values["@group"].HasValue())
         {
             var str = new System.Text.StringBuilder(100);
             foreach (var and in values["@group"].ToString().Split(','))
@@ -656,7 +647,7 @@ public class SelectTable : ISingleton
     //处理排序 "@order":"name-,id"查询按 name降序、id默认顺序 排序的User数组
     private void ProcessOrder(string subtable, JObject values, ISugarQueryable<ExpandoObject> tb)
     {
-        if (!values["@order"].IsNullOrEmpty())
+        if (values["@order"].HasValue())
         {
             foreach (var item in values["@order"].ToString().Split(','))
             {
@@ -681,10 +672,10 @@ public class SelectTable : ISingleton
     }
 
     //条件查询 "key{}":"条件0,条件1...",条件为任意SQL比较表达式字符串,非Number类型必须用''包含条件的值,如'a'
-    //&, |, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
-    //   横或纵与:同一字段的值内条件默认 | 或连接,不同字段的条件默认 & 与连接。
-    //   ① & 可用于"key&{}":"条件"等
-    //   ② | 可用于"key|{}":"条件", "key|{}":[] 等,一般可省略
+    //&, |, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。 
+    //   横或纵与:同一字段的值内条件默认 | 或连接,不同字段的条件默认 & 与连接。 
+    //   ① & 可用于"key&{}":"条件"等 
+    //   ② | 可用于"key|{}":"条件", "key|{}":[] 等,一般可省略 
     //   ③ ! 可单独使用,如"key!":Object,也可像&,|一样配合其他功能符使用
     private void ConditionQuery(string subtable, List<IConditionalModel> conModels, KeyValuePair<string, JToken> va)
     {
@@ -692,13 +683,19 @@ public class SelectTable : ISingleton
         string field = vakey.TrimEnd("{}".ToCharArray());
         if (va.Value.HasValues)
         {
-            List<string> inValues = new();
+            List<string> inValues = new List<string>();
             foreach (var cm in va.Value)
             {
                 inValues.Add(cm.ToString());
             }
 
-            conModels.Add(new ConditionalModel() { FieldName = field, ConditionalType = field.EndsWith("!") ? ConditionalType.NotIn : ConditionalType.In, FieldValue = string.Join(",", inValues) });
+            conModels.Add(new ConditionalModel()
+            {
+                FieldName = field.TrimEnd("!".ToCharArray()),
+                ConditionalType = field.EndsWith("!") ? ConditionalType.NotIn : ConditionalType.In,
+                FieldValue = string.Join(",", inValues)
+            });
+
         }
         else
         {
@@ -714,6 +711,7 @@ public class SelectTable : ISingleton
                 }
                 else if (and.StartsWith("<="))
                 {
+
                     model.ConditionalType = ConditionalType.LessThanOrEqual;
                     model.FieldValue = and.TrimStart("<=".ToCharArray());
                 }
@@ -738,7 +736,7 @@ public class SelectTable : ISingleton
     {
         string vakey = va.Key.Trim();
         string field = vakey.TrimEnd("%".ToCharArray());
-        List<string> inValues = new();
+        List<string> inValues = new List<string>();
 
         if (va.Value.HasValues)
         {
@@ -803,7 +801,8 @@ public class SelectTable : ISingleton
         }
     }
 
-    public static string ReplaceSQLChar(string str)
+    //处理sql注入
+    private string ReplaceSQLChar(string str)
     {
         if (str == String.Empty)
             return String.Empty;