Quellcode durchsuchen

1、新增通用接口CommonDynamicSelect

MY vor 6 Monaten
Ursprung
Commit
5bd340266f

+ 49 - 0
JLHHJSvr/Com/CommonDynamicSelect.cs

@@ -0,0 +1,49 @@
+using LJLib.Net.SPI.Com;
+using LJLib.Net.SPI.Server;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JLHHJSvr.Com
+{
+    public class CommonDynamicSelectRequest : ILJRequest<CommonDynamicSelectResponse>
+    {
+        public string token { get; set; }
+        public string clienttype { get; set; }
+        /// <summary>
+        /// xml名称
+        /// </summary>
+        public string dsname { get; set; }
+        public JObject queryparams { get; set; }
+        public string orderstr { get; set; }
+        public int pageindex { get; set; }
+        public int pagesize { get; set; }
+        /// <summary>
+        /// 用户习惯dwname
+        /// </summary>
+        public string dwname { get; set; }
+        /// <summary>
+        /// 用户习惯itemname
+        /// </summary>
+        public string itemname { get; set; }
+        /// <summary>
+        /// 用户习惯是否压缩
+        /// </summary>
+        public byte ifcompress { get; set; }
+        public string GetApiName()
+        {
+            return "CommonDynamicSelect";
+        }
+    }
+    public class CommonDynamicSelectResponse : LJResponse
+    {
+        public JArray datatable { get; set; }
+        public JObject tableinfo { get; set; }
+        public int totalcnt { get; set; }
+        public int pageindex { get; set; }
+        public int pagesize { get; set; }
+    }
+}

+ 299 - 1
JLHHJSvr/DBA/DAL_SQLite/Utils/SqlStrHelper.cs

@@ -1,5 +1,9 @@
-using System;
+using LJLib.Method;
+using System;
 using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
 using System.Text.RegularExpressions;
 
 namespace LJLib.DAL.SQL
@@ -286,5 +290,299 @@ DROP TABLE #tmp_sorttable";
             }
             return outCmdStr;
         }
+
+        public static string RemoveComment(string source)
+        {
+            var sb = new StringBuilder();
+            using (StringReader reader = new StringReader(source))
+            {
+                string line;
+                while ((line = reader.ReadLine()) != null)
+                {
+                    if (line.Contains("--"))
+                    {
+                        int commentstart = -1;
+                        var instr = false;
+                        for (var i = 0; i < line.Length; i++)
+                        {
+                            var curchar = line[i];
+                            if (curchar == '\'')
+                            {
+                                instr = !instr;
+                            }
+                            else if (!instr)
+                            {
+                                if (curchar == '-')
+                                {
+                                    if (i + 1 < line.Length)
+                                    {
+                                        if (line[i + 1] == '-')
+                                        {
+                                            commentstart = i;
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        if (commentstart >= 0)
+                        {
+                            line = line.Substring(0, commentstart);
+                        }
+                    }
+                    sb.AppendLine(line);
+                }
+            }
+            return sb.ToString().TrimEnd('\n').TrimEnd('\r');
+        }
+        public static ParseResult ParseSelectStr(string orgSelectStr)
+        {
+            var rslt = new ParseResult();
+            orgSelectStr = RemoveComment(orgSelectStr);
+            var indexchars = GetIndexChar(orgSelectStr);
+
+            var regex = new Regex(@"\bselect\s+(distinct\s+)?(top\b)?", RegexOptions.IgnoreCase | RegexOptions.Singleline);
+            #region 查找select关键字
+
+            var selectMatch = regex.Match(orgSelectStr);
+
+            if (!selectMatch.Success)
+            {
+                throw new Exception(string.Format("查找select关键字失败,表达式[{0}],请检查:{1}", regex, orgSelectStr));
+            }
+
+            var stateIndex = indexchars.Keys.GetFirstIndexBefore(selectMatch.Index);
+            if (stateIndex >= 0)
+            {
+                throw new Exception(string.Format("第{0}个字符的select关键字前面不允许存在括号或字符串,表达式[{1}],请检查:{2}", selectMatch.Index, regex,
+                    orgSelectStr));
+            }
+
+            if (!string.IsNullOrEmpty(selectMatch.Groups[2].Value))
+            {
+                throw new Exception(string.Format("第{0}位,不应该包含TOP关键字,请使用分页参数,请检查:{1}", selectMatch.Groups[2].Index,
+                    orgSelectStr));
+            }
+
+            rslt.selectStr = orgSelectStr.Substring(0, selectMatch.Index + selectMatch.Length);
+
+            #endregion
+
+            regex = new Regex(@"\bfrom\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
+            #region 查找from关键字
+
+            var match = regex.Match(orgSelectStr);
+            int fromIndex = -1;
+            while (match.Success)
+            {
+                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
+                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
+                {
+                    fromIndex = match.Index;
+                    break;
+                }
+                match = match.NextMatch();
+            }
+
+            if (fromIndex < 0)
+            {
+                throw new Exception(string.Format("最外层查找from字句失败,请检查:{0}", orgSelectStr));
+            }
+
+            #endregion
+
+            #region 分析返回字段
+            Dictionary<string, string> orgFields = new Dictionary<string, string>();
+            Dictionary<string, string> orgOrderFields = new Dictionary<string, string>();
+            var parts = SpliteSelectStr(orgSelectStr);
+            var orgFieldStr = parts[0];
+            AnalyseFields(orgFieldStr, orgFields, orgOrderFields);
+            rslt.selectFieldsDic = orgFields;
+            #endregion
+
+            regex = new Regex(@"\where\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
+            #region 查找where关键字
+
+            int whereIndex = -1;
+            match = regex.Match(orgSelectStr, fromIndex);
+            while (match.Success)
+            {
+                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
+                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
+                {
+                    whereIndex = match.Index;
+                    break;
+                }
+                match = match.NextMatch();
+            }
+
+            #endregion
+
+
+            regex = new Regex(@"\bgroup\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
+            #region 查找group关键字
+
+            int groupIndex = -1;
+            match = regex.Match(orgSelectStr, fromIndex);
+            while (match.Success)
+            {
+                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
+                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
+                {
+                    groupIndex = match.Index;
+                    break;
+                }
+                match = match.NextMatch();
+            }
+
+            #endregion
+
+            regex = new Regex(@"\border\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);
+            #region 查找order关键字
+
+            int orderindex = -1;
+            match = regex.Match(orgSelectStr, fromIndex);
+            while (match.Success)
+            {
+                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);
+                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')
+                {
+                    orderindex = match.Index;
+                    break;
+                }
+                match = match.NextMatch();
+            }
+
+
+            #endregion
+
+            rslt.fromStr = string.Empty;
+            var fromStopIndexs = new List<int> { whereIndex, groupIndex, orderindex }.Where(x => x > 0);
+            if (fromStopIndexs.Any())
+            {
+                rslt.fromStr = orgSelectStr.Substring(fromIndex, fromStopIndexs.Min() - fromIndex);
+            }
+            else
+            {
+                rslt.fromStr = orgSelectStr.Substring(fromIndex);
+            }
+            rslt.whereStr = string.Empty;
+            if (whereIndex > 0)
+            {
+                var whereStopIndexs = new List<int> { groupIndex, orderindex }.Where(x => x > 0);
+                if (whereStopIndexs.Any())
+                {
+                    rslt.whereStr = orgSelectStr.Substring(whereIndex, whereStopIndexs.Min() - whereIndex);
+                }
+                else
+                {
+                    rslt.whereStr = orgSelectStr.Substring(whereIndex);
+                }
+            }
+
+            rslt.orderStr = string.Empty;
+            if (orderindex > 0)
+            {
+                rslt.orderStr = orgSelectStr.Substring(orderindex);
+            }
+            rslt.groupStr = string.Empty;
+            if (groupIndex > 0)
+            {
+                if (orderindex > 0)
+                {
+                    rslt.groupStr = orgSelectStr.Substring(groupIndex, orderindex - groupIndex);
+                }
+                else
+                {
+                    rslt.groupStr = orgSelectStr.Substring(groupIndex);
+                }
+            }
+            return rslt;
+        }
+
+        /// <summary>
+        /// 获取SQL中括号与字符串的转换位置
+        /// </summary>
+        /// <param name="sqlStr"></param>
+        /// <returns></returns>
+        public static SortedList<int, char> GetIndexChar(string sqlStr)
+        {
+            var rslt = new SortedList<int, char>();
+
+            Stack<char> states = new Stack<char>();
+            char curstate = ' ';
+            for (int i = 0; i < sqlStr.Length; i++)
+            {
+                char cur = sqlStr[i];
+
+                if (curstate == '\'')
+                {
+                    if (cur == '\'')
+                    {
+                        states.Pop();
+                        curstate = states.Count > 0 ? states.Peek() : ' ';
+                        rslt[i] = curstate;
+                    }
+                    continue;
+                }
+
+                if (curstate == '(')
+                {
+                    if (cur == ')')
+                    {
+                        states.Pop();
+                        curstate = states.Count > 0 ? states.Peek() : ' ';
+                        rslt[i] = curstate;
+                        continue;
+                    }
+                }
+
+                if (curstate == '[')
+                {
+                    if (cur == ']')
+                    {
+                        states.Pop();
+                        curstate = states.Count > 0 ? states.Peek() : ' ';
+                        rslt[i] = curstate;
+                        continue;
+                    }
+                }
+
+                if (cur == '(' || cur == '\'' || cur == '[')
+                {
+                    states.Push(cur);
+                    curstate = cur;
+                    rslt[i] = curstate;
+                    continue;
+                }
+
+                if (cur == ')')
+                {
+                    throw new Exception(string.Format("第{0}位\")\"没有找到对应的\"(\",请检查:{1}", i, sqlStr));
+                }
+
+                if (cur == ']')
+                {
+                    throw new Exception(string.Format("第{0}位\"]\"没有找到对应的\"[\",请检查:{1}", i, sqlStr));
+                }
+            }
+            if (states.Count > 0)
+            {
+                throw new Exception(string.Format("第{0}位\"{1}\"没有找到对应的结束符,请检查:{2}", rslt.Keys[rslt.Count - 1], rslt.Values[rslt.Count - 1], sqlStr));
+            }
+            return rslt;
+        }
+
+        public class ParseResult
+        {
+            public string selectStr { get; set; }
+            //public List<string> selectFields { get; set; }
+            //public List<string> selectTitles { get; set; }
+            public Dictionary<string, string> selectFieldsDic { get; set; }
+            public string fromStr { get; set; }
+            public string whereStr { get; set; }
+            public string groupStr { get; set; }
+            public string orderStr { get; set; }
+        }
     }
 }

+ 29 - 0
JLHHJSvr/DataStore/Example.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<select>
+  <selectstr>
+SELECT u_pricelist.pricelistname,   
+	 u_pricelist.createtime,   
+	 u_pricelist.dscrp,
+	 u_pricelist.flag,
+	 u_pricelist.moddate,
+	 u_pricelist.modemp,
+	 u_pricelist.auditemp,
+	 u_pricelist.auditdate
+FROM u_pricelist
+  </selectstr>
+  <where>
+  </where>
+  <orderstr>
+  </orderstr>
+  <displayfields>
+	<field field="pid" compute="getrow()">序</field>
+	<field field="pricelistname">价格表名称</field>
+	<field field="dscrp">备注</field>
+	<field field="createtime">建立时间</field>
+	<field field="flag">审核</field>
+	<field field="modemp">修改人</field>
+	<field field="moddate">修改时间</field>
+	<field field="auditemp">审核人</field>
+	<field field="auditdate">审核时间</field>
+  </displayfields>
+</select>

+ 926 - 0
JLHHJSvr/Excutor/CommonDynamicSelectExcutor.cs

@@ -0,0 +1,926 @@
+using DirectService.Tools;
+using JLHHJSvr.BLL;
+using JLHHJSvr.Com;
+using JLHHJSvr.LJException;
+using LJLib.DAL.SQL;
+using LJLib.Net.SPI.Server;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.SqlClient;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace JLHHJSvr.Excutor
+{
+    internal class CommonDynamicSelectExcutor : ExcutorBase<CommonDynamicSelectRequest, CommonDynamicSelectResponse>
+    {
+        protected override void ExcuteInternal(CommonDynamicSelectRequest request, object state, CommonDynamicSelectResponse rslt)
+        {
+            var tokendata = BllHelper.GetToken(request.token);
+            if (tokendata == null)
+            {
+                rslt.ErrMsg = "会话已经中断";
+                return;
+            }
+            if (request.queryparams == null)
+            {
+                throw new ArgumentNullException("queryparams");
+            }
+            if (string.IsNullOrEmpty(request.dsname))
+            {
+                throw new ArgumentNullException("dsname");
+            }
+
+            using (var con = new SqlConnection(GlobalVar.ConnectionString))
+            using (var cmd = con.CreateCommand())
+            {
+                con.Open();
+
+                var rsltgroup = GetXmlResult(cmd, request.dsname, request, tokendata, false);
+                rslt.datatable = rsltgroup.datatable;
+                rslt.tableinfo = rsltgroup.tableinfo;
+                rslt.totalcnt = rsltgroup.totalcnt;
+                rslt.pageindex = rsltgroup.pageindex;
+                rslt.pagesize = rsltgroup.pagesize;
+            }
+        }
+        private const string _mapperAppend = "_Mapper_";
+        private Regex _staticParmReg = new Regex("[\\$]+[\\w]+[\\$]*");
+        private Regex _listParmReg = new Regex("@@[\\w]+@@");
+        private Dictionary<string, string> _xmlEscapeMap = new Dictionary<string, string>
+        {
+            {"&", "&amp;"},
+            {"'", "&apos;"},
+            {"\"", "&quot;"},
+            {">", "&gt;"},
+            {"<", "&lt;"},
+        };
+        private Regex _computeRefReg = new Regex("([A-Za-z_][\\w]+)([\\s]*)([(]*)");
+        private QueryResult GetXmlResult(SqlCommand cmd, string dsname, CommonDynamicSelectRequest request, TokenData tokendata, bool ifmapper)
+        {
+            var rslt = new QueryResult();
+            var rootPath = GlobalVar.App_Data + "\\DataStore\\";
+#if DEBUG
+            rootPath = rootPath.Substring(0, rootPath.IndexOf("\\bin\\")) + "\\DataStore\\";
+#endif
+            var filePath = rootPath + dsname + ".xml";
+            if (!File.Exists(filePath))
+            {
+                throw new LJCommonException("缺失接口文件:" + dsname + ".xml");
+            }
+            var queryParams = request.queryparams;
+
+            var wholexml = File.ReadAllText(filePath);
+            var treatedsb = new StringBuilder();
+            // 逐行扫描,检查全局变量与转义符
+            var staticParmDic = new Dictionary<string, string>();
+            using (StringReader reader = new StringReader(wholexml))
+            {
+                var incomment = false;
+                string line;
+                while ((line = reader.ReadLine()) != null)
+                {
+                    var lineTrim = line.Trim();
+                    if (line.Contains("<!--"))
+                    {
+                        incomment = true;
+                        var commentStartIndex = line.IndexOf("<!--");
+                        if (commentStartIndex > 0)
+                        {
+                            treatedsb.AppendLine(line.Substring(0, commentStartIndex));
+                        }
+                    }
+                    if (incomment)
+                    {
+                        if (line.Contains("-->"))
+                        {
+                            incomment = false;
+                            var commenttail = line.Substring(line.IndexOf("-->") + 3);
+                            if (!string.IsNullOrEmpty(commenttail))
+                            {
+                                treatedsb.AppendLine(commenttail);
+                            }
+                        }
+                        continue;
+                    }
+                    // 处理$标记的全局变量
+                    var staticMatches = _staticParmReg.Matches(line);
+                    var staticMatchesStr = new HashSet<string>();
+                    foreach (var match in staticMatches)
+                    {
+                        var matchstr = match.ToString();
+                        staticMatchesStr.Add(matchstr);
+                        if (matchstr.StartsWith("$$"))
+                        {
+
+                        }
+                        else if (matchstr.StartsWith("$"))
+                        {
+                            var newname = "@" + matchstr.Substring(1);
+                        }
+                    }
+                    //$$开头$$结束为全局数组变量,直接作字符串替换
+                    foreach (var item in staticMatchesStr.Where(x => x.StartsWith("$$")))
+                    {
+                        if (!staticParmDic.ContainsKey(item))
+                        {
+                            var staticParm = item.Trim('$');
+                            var staticVal = string.Empty;
+                            staticVal = staticVal ?? string.Empty;
+                            staticParmDic[item] = staticVal.Trim(new[] { '(', ')' });
+                        }
+                        if (lineTrim.StartsWith("<") && lineTrim.EndsWith(">"))
+                        {
+                            //xml标签
+                        }
+                        else
+                        {
+                            var staticVal = staticParmDic[item];
+                            line = line.Replace(item, staticVal);
+                        }
+                    }
+                    // $开头的全局变量转换为@开头的变量
+                    foreach (var item in staticMatchesStr.Where(x => x.StartsWith("$") && !x.StartsWith("$$")))
+                    {
+                        var staticParm = item.Trim('$');
+                        if (!queryParams.ContainsKey(staticParm))
+                        {
+                            if (staticParm.StartsWith("user_"))
+                            {
+                                // 查询用户权限值
+                                var keyStr = staticParm.Substring("user_".Length);
+                                var userKeyStr = "0";
+
+                                cmd.CommandText = @"select " + keyStr + " from u_user_jlhprice where empid = @empid";
+                                cmd.Parameters.Clear();
+                                cmd.Parameters.AddWithValue("@empid", tokendata.userid);
+                                using (var UserReader = cmd.ExecuteReader())
+                                {
+                                    if (UserReader.Read())
+                                    {
+                                        userKeyStr = Convert.ToString(UserReader[keyStr]).Trim();
+                                    }
+                                }
+                                queryParams[staticParm] = userKeyStr;
+                            }
+                            else
+                            {
+                                throw new NotImplementedException(staticParm);
+                            }
+                        }
+                        line = line.Replace(item, "@" + item.Substring(1));
+                    }
+                    if (lineTrim.StartsWith("<") && lineTrim.EndsWith(">"))
+                    {
+                        //xml标签
+                        line = line.Replace(" $", " ");
+                        line = line.Replace(" @", " ");
+                        line = line.Replace("!=\"", "_notequals=\"");
+                    }
+                    else
+                    {
+                        // 处理@@标记的数组变量
+                        var listParmMatches = _listParmReg.Matches(line);
+                        foreach (var match in listParmMatches)
+                        {
+                            var matchstr = match.ToString();
+                            var pname = matchstr.Trim('@');
+                            if (!queryParams.ContainsKey(pname))
+                            {
+                                continue;
+                                //throw new LJCommonException($"未提供参数" + pname);
+                            }
+                            if (queryParams.GetValue(pname).Type != JTokenType.Array)
+                            {
+                                continue;
+                            }
+                            var listval = queryParams.Value<JArray>(pname).Select(x => "'" + x + "'");
+                            var pval = string.Join(",", listval);
+                            line = line.Replace(matchstr, pval);
+                        }
+                        // 处理转义字符
+                        foreach (var escapeItem in _xmlEscapeMap)
+                        {
+                            line = line.Replace(escapeItem.Key, escapeItem.Value);
+                        }
+                    }
+                    treatedsb.AppendLine(line);
+                }
+            }
+            var treatedxml = treatedsb.ToString();
+
+            var xmlDoc = new XmlDocument();
+            xmlDoc.LoadXml(treatedxml);
+            XmlNode selectNode = null;
+            XmlNode rootNode = null;
+            foreach (XmlNode rchild in xmlDoc.ChildNodes)
+            {
+                if (rchild.Name != "xml")
+                {
+                    rootNode = rchild;
+                    break;
+                }
+            }
+            if (rootNode == null)
+            {
+                throw new LJCommonException("格式错误,不存在根节点");
+            }
+            if (rootNode.Name == "data")
+            {
+                var dataChild = rootNode.FirstChild;
+                if (dataChild == null)
+                {
+                    throw new LJCommonException("格式错误,data不存在根节点");
+                }
+                if (dataChild.Name == "json")
+                {
+                    var dataJson = dataChild.InnerText;
+                    rslt.datatable = JsonConvert.DeserializeObject<JArray>(dataJson);
+                    return rslt;
+                }
+                else
+                {
+                    throw new LJCommonException("未支持的data节点:" + dataChild.Name);
+                }
+            }
+            else if (rootNode.Name == "select")
+            {
+                selectNode = rootNode;
+            }
+            else
+            {
+                throw new LJCommonException("未支持的根节点:" + rootNode.Name);
+            }
+
+            var selectbase = string.Empty;
+            var selectstr = selectNode.SelectSingleNode("selectstr")?.InnerText;
+            var orderstr = selectNode.SelectSingleNode("orderstr")?.InnerText;
+            var whereList = new List<string>();
+            var whereNode = selectNode.SelectSingleNode("where");
+            if (whereNode != null)
+            {
+                foreach (XmlNode whereChild in whereNode.ChildNodes)
+                {
+                    if (whereChild.Name == "when")
+                    {
+                        var match = true;
+                        foreach (XmlAttribute attr in whereChild.Attributes)
+                        {
+                            var attrname = attr.Name;
+                            var attrval = attr.Value;
+                            JToken valjtoken = null;
+                            if (attrval.StartsWith("@"))
+                            {
+                                var pname = attrval.Replace("@", "");
+                                attrval = null;
+                                if (queryParams.ContainsKey(pname))
+                                {
+                                    valjtoken = queryParams[pname];
+                                    switch (valjtoken.Type)
+                                    {
+                                        case JTokenType.Null:
+                                        case JTokenType.None:
+                                        case JTokenType.Undefined:
+                                            attrval = null;
+                                            break;
+                                        case JTokenType.Object:
+                                        case JTokenType.Array:
+                                            attrval = valjtoken.ToString();
+                                            break;
+                                        default:
+                                            attrval = valjtoken.ToString();
+                                            break;
+                                    }
+                                }
+                            }
+                            if (attrname == "notnull")
+                            {
+                                if (attrval == null)
+                                {
+                                    match = false;
+                                    break;
+                                }
+                            }
+                            else if (attrname == "notempty")
+                            {
+                                if (string.IsNullOrEmpty(attrval))
+                                {
+                                    match = false;
+                                    break;
+                                }
+                                if (valjtoken.Type == JTokenType.Array)
+                                {
+                                    if ((valjtoken as JArray).Count == 0)
+                                    {
+                                        match = false;
+                                        break;
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                var ifnot = false;
+                                var attrnameVal = attrname.TrimStart('@');
+                                if (attrnameVal.EndsWith("_notequals"))
+                                {
+                                    ifnot = true;
+                                    attrnameVal = attrnameVal.Substring(0, attrnameVal.IndexOf("_notequals"));
+                                }
+                                if (!queryParams.ContainsKey(attrnameVal))
+                                {
+                                    throw new NotImplementedException(attr.ToString());
+                                }
+                                attrnameVal = queryParams[attrnameVal].ToString();
+                                if (string.Equals(attrnameVal, attrval) != !ifnot)
+                                {
+                                    match = false;
+                                    break;
+                                }
+                            }
+                        }
+                        if (match)
+                        {
+                            whereList.Add(whereChild.InnerText.Trim());
+                        }
+                    }
+                    else
+                    {
+                        throw new NotImplementedException();
+                    }
+                }
+            }
+
+            var wherestr = ListEx.GetWhereStr(whereList);
+            var parmDic = new Dictionary<string, object>();
+            foreach (var item in queryParams)
+            {
+                if (item.Value is JArray)
+                {
+                }
+                else
+                {
+                    parmDic[item.Key] = item.Value.ToString();
+                }
+            }
+
+            var displayfields = selectNode.SelectSingleNode("displayfields");
+            var uncomputefields = new Dictionary<string, string>();
+            string rownumfield = null;
+            foreach (XmlNode fieldNode in displayfields)
+            {
+                string field = null;
+                XmlAttribute computeAttr = null;
+                foreach (XmlAttribute attr in fieldNode.Attributes)
+                {
+                    if (string.Equals(attr.Name, "field", StringComparison.OrdinalIgnoreCase))
+                    {
+                        field = attr.Value;
+                    }
+                    else if (string.Equals(attr.Name, "compute", StringComparison.OrdinalIgnoreCase))
+                    {
+                        computeAttr = attr;
+                    }
+                }
+                if (computeAttr != null)
+                {
+                    var computeexpr = computeAttr.Value;
+                    if (!string.IsNullOrEmpty(computeexpr))
+                    {
+                        if (computeexpr.IndexOf("getrow(", StringComparison.OrdinalIgnoreCase) >= 0)
+                        {
+                            rownumfield = field;
+                        }
+                        else
+                        {
+                            uncomputefields[field] = computeexpr;
+                        }
+                        fieldNode.Attributes.Remove(computeAttr);
+                    }
+                }
+            }
+            var parseResult = SqlStrHelper.ParseSelectStr(selectstr);
+            if (parseResult.selectStr.ToUpper().Contains("DISTINCT"))
+            {
+                throw new NotImplementedException("未支持DISTINCT");
+            }
+            /*if (uncomputefields.Count > 0)
+            {
+                // 多次循环,防因嵌套解析失败
+                var checkcnt = uncomputefields.Count;
+                for (var i = 0; i < checkcnt; i++)
+                {
+                    if (uncomputefields.Count == 0)
+                    {
+                        break;
+                    }
+                    var flist = uncomputefields.Keys.ToList();
+                    foreach (var compf in flist)
+                    {
+                        if (!uncomputefields.ContainsKey(compf))
+                        {
+                            continue;
+                        }
+                        var waitnext = false;
+                        var computeexpr = uncomputefields[compf];
+                        var refMatches = _computeRefReg.Matches(computeexpr);
+                        var refFields = new HashSet<string>();
+                        foreach (Match refmatch in refMatches)
+                        {
+                            if (string.IsNullOrEmpty(refmatch.Groups[3].ToString()))
+                            {
+                                var refField = refmatch.Groups[1].ToString();
+                                if (!parseResult.selectFieldsDic.ContainsKey(refField))
+                                {
+                                    waitnext = true;
+                                    break;
+                                }
+                                refFields.Add(refField);
+                            }
+                        }
+                        if (waitnext)
+                        {
+                            continue;
+                        }
+                        var refSorts = refFields.OrderByDescending(x => x.Length).ToList();
+                        var holderid = -1;
+                        foreach (var reff in refSorts)
+                        {
+                            holderid++;
+                            computeexpr = computeexpr.Replace(reff, "{" + holderid.ToString("000") + "}");
+                        }
+                        for (var hindex = 0; hindex <= holderid; hindex++)
+                        {
+                            var reff = refSorts[hindex];
+
+                            var refselect = parseResult.selectFieldsDic[reff];
+                            var asIndex = refselect.LastIndexOf(" as ", StringComparison.OrdinalIgnoreCase);
+                            if (asIndex > 0)
+                            {
+                                var asname = refselect.Substring(asIndex + " as ".Length).Trim();
+                                if (string.Equals(asname, reff, StringComparison.OrdinalIgnoreCase))
+                                {
+                                    refselect = refselect.Substring(0, asIndex).Trim();
+                                }
+                            }
+                            computeexpr = computeexpr.Replace("{" + hindex.ToString("000") + "}", "(" + refselect + ")");
+                        }
+                        parseResult.selectFieldsDic[compf] = computeexpr + " AS " + compf;
+                        uncomputefields.Remove(compf);
+                    }
+                }
+                if (uncomputefields.Count > 0)
+                {
+                    throw new LJCommonException($"解析计算列失败:[{string.Join(",", uncomputefields.Keys)}]");
+                }
+            }*/
+            if (!string.IsNullOrEmpty(request.orderstr?.Trim()))
+            {
+                var orderArr = request.orderstr.Split(',');
+                var orderlist = new List<string>();
+                foreach (var orderitem in orderArr)
+                {
+                    var orderfield = orderitem.Trim();
+                    var descIndex = orderfield.IndexOf(" desc");
+                    if (descIndex > 0)
+                    {
+                        orderfield = orderfield.Substring(0, descIndex).Trim();
+                    }
+                    var ascIndex = orderfield.IndexOf(" asc");
+                    if (ascIndex > 0)
+                    {
+                        orderfield = orderfield.Substring(0, ascIndex).Trim();
+                    }
+                    if (!parseResult.selectFieldsDic.ContainsKey(orderfield))
+                    {
+                        throw new LJCommonException($"排序失败,数据列中不包含[{orderfield}]");
+                    }
+                    var dbfield = parseResult.selectFieldsDic[orderfield];
+                    dbfield = RemoveAS(dbfield);
+                    if (descIndex > 0)
+                    {
+                        dbfield += " desc";
+                    }
+                    orderlist.Add(dbfield);
+                }
+                orderstr = string.Join(",", orderlist);
+            }
+            var outputFields = string.Join(",", parseResult.selectFieldsDic.Keys);
+            var mergesql = SqlStrHelper.BuildSelectStr(selectstr, ref outputFields, wherestr, orderstr, request.pageindex, request.pagesize);
+            cmd.CommandText = mergesql;
+            cmd.CommandType = CommandType.Text;
+            cmd.Parameters.Clear();
+            if (queryParams != null)
+            {
+                foreach (var item in queryParams)
+                {
+                    if (item.Value == null)
+                    {
+                        cmd.Parameters.AddWithValue("@" + item.Key, DBNull.Value);
+                    }
+                    else
+                    {
+                        cmd.Parameters.AddWithValue("@" + item.Key, item.Value.ToString());
+                    }
+                }
+            }
+            rslt.datatable = new JArray();
+            var dbcolnames = parseResult.selectFieldsDic.Keys.ToList();
+            var rownum = (request.pageindex - 1) * request.pagesize;
+            if (rownum < 0)
+            {
+                rownum = 0;
+            }
+            using (var reader = cmd.ExecuteReader())
+            {
+                while (reader.Read())
+                {
+                    rownum++;
+                    var row = new JObject();
+                    if (rownumfield != null)
+                    {
+                        row.Add(rownumfield, rownum);
+                    }
+                    for (var i = 0; i < dbcolnames.Count; i++)
+                    {
+                        var p = dbcolnames[i];
+                        var dbval = reader[p];
+                        if (ifmapper)
+                        {
+                            if (i == 0)
+                            {
+                                p = "value";
+                            }
+                            else if (i == 1)
+                            {
+                                p = "label";
+                            }
+                        }
+                        if (dbval == DBNull.Value)
+                        {
+                            row.Add(p, null);
+                        }
+                        else if (dbval is string)
+                        {
+                            row.Add(p, (dbval as string).Trim());
+                        }
+                        else if (dbval is DateTime)
+                        {
+                            row.Add(p, (DateTime)dbval);
+                        }
+                        else
+                        {
+                            row.Add(p, dbval.ToString());
+                        }
+                    }
+                    rslt.datatable.Add(row);
+                }
+            }
+            // 处理总行数
+            if (!ifmapper)
+            {
+                string countstr = parseResult.selectStr + " COUNT(0) " + parseResult.fromStr;
+                if (!string.IsNullOrEmpty(wherestr))
+                {
+                    countstr += " WHERE " + wherestr;
+                }
+                cmd.CommandText = countstr;
+                try
+                {
+                    var totalcnt = Convert.ToInt32(cmd.ExecuteScalar());
+                    rslt.totalcnt = totalcnt;
+                    rslt.pageindex = request.pageindex;
+                    rslt.pagesize = request.pagesize;
+                }
+                catch (Exception ex)
+                {
+                    throw new Exception(string.Format("ex:{0}\r\ncmd:{1}", ex, cmd.CommandText));
+                }
+            }
+
+            //处理列信息,集成用户习惯
+            if (request.pageindex <= 1 && !ifmapper)
+            {
+                var preferenceobj = new JObject();
+                var preferencejson = BllHelper.GetValue(cmd,tokendata.userid, request.dwname, request.itemname, string.Empty, request.ifcompress == 1 ? true : false);
+                if (string.IsNullOrEmpty(preferencejson))//如果没有自己的布局方案,尝试获取系统的布局方案
+                {
+                    preferencejson = BllHelper.GetValue(cmd,-1, request.dwname, request.itemname, string.Empty, request.ifcompress == 1 ? true : false);
+                }
+                //preferencejson = "{tableprop:{enabled:false,oSize:0,mode:\"default\"},columns:[{field:\"printid\",search:{order:1,labelposition:\"left\"}}]}";
+                if (!string.IsNullOrEmpty(preferencejson))
+                {
+                    try
+                    {
+                        preferenceobj = JsonConvert.DeserializeObject<JObject>(preferencejson);
+                    }
+                    catch (Exception e)
+                    {
+                        Trace.Write("解析json失败" + preferenceobj);
+                    }
+                }
+                var oldcolDic = new Dictionary<string, JObject>(StringComparer.OrdinalIgnoreCase);
+                var colSortDic = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
+                var sortid = 0;
+                if (preferenceobj.ContainsKey("columns"))
+                {
+                    var oldcols = preferenceobj.GetValue("columns") as JArray;
+                    foreach (JObject col in oldcols)
+                    {
+                        var field = col["field"].ToString();
+                        oldcolDic[field] = col;
+                        sortid++;
+                        colSortDic[field] = sortid;
+                    }
+                }
+                var cols = new List<JObject>();
+                var colSortDicDefault = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
+                sortid = 0;
+                foreach (XmlNode fieldNode in displayfields.ChildNodes)
+                {
+                    var col = new JObject();
+                    string field = null;
+                    string mapper = null;
+                    foreach (XmlAttribute attr in fieldNode.Attributes)
+                    {
+                        if (string.Equals(attr.Name, "mapper", StringComparison.OrdinalIgnoreCase))
+                        {
+                            mapper = attr.Value;
+                            continue;
+                        }
+                        col.Add(attr.Name, attr.Value);
+                        if (string.Equals(attr.Name, "field", StringComparison.OrdinalIgnoreCase))
+                        {
+                            field = attr.Value;
+                        }
+                    }
+                    string dbField = null;
+                    var title = fieldNode.InnerText.Trim();
+                    if (field == rownumfield)
+                    {
+                        dbField = string.Empty;
+                    }
+                    else if (parseResult.selectFieldsDic.ContainsKey(field))
+                    {
+                        dbField = parseResult.selectFieldsDic[field];
+                    }
+                    else
+                    {
+                        throw new LJCommonException("语法错误:" + field + ":" + title + ",输出项无法匹配对应sql数据");
+                    }
+                    col.Add("title", title);
+                    handleCustomTitle(cmd, tokendata.userid, col, dbField);
+                    if (!string.IsNullOrEmpty(field) && oldcolDic.ContainsKey(field))
+                    {
+                        var oldInfo = oldcolDic[field];
+                        foreach (var prop in oldInfo.Properties())
+                        {
+                            if (string.Equals(prop.Name, "field", StringComparison.OrdinalIgnoreCase))
+                            {
+                                continue;
+                            }
+                            if (string.Equals(prop.Name, "title", StringComparison.OrdinalIgnoreCase))
+                            {
+                                continue;
+                            }
+                            //col.Add(prop.Name, prop.Value);
+                            col[prop.Name] = prop.Value;
+                        }
+                    }
+                    if (mapper != null)
+                    {
+                        if (string.IsNullOrEmpty(mapper))
+                        {
+                            mapper = RemoveAS(dbField);
+                        }
+                        var mappername = mapper;
+                        if (mappername.Contains("."))
+                        {
+                            mappername = mappername.Substring(mappername.IndexOf(".") + 1);
+                        }
+                        if (!File.Exists(rootPath + _mapperAppend + mappername + ".xml"))
+                        {
+                            mappername = mapper.Replace(".", "_");
+                            if (!File.Exists(rootPath + _mapperAppend + mappername + ".xml"))
+                            {
+                                throw new LJCommonException("未匹配到mapper对应的xml:" + mapper);
+                            }
+                        }
+                        var mapperreq = new CommonDynamicSelectRequest
+                        {
+                            queryparams = queryParams
+                        };
+                        var mapperrslt = GetXmlResult(cmd, _mapperAppend + mappername, mapperreq, tokendata, true);
+                        col.Add("enum", mapperrslt.datatable);
+                    }
+                    cols.Add(col);
+                    sortid++;
+                    colSortDicDefault[field] = sortid;
+                }
+                var colSort = cols.OrderBy(x =>
+                {
+                    var field = x.GetValue("field")?.ToString();
+                    if (colSortDic.ContainsKey(field))
+                    {
+                        return colSortDic[field];
+                    }
+                    else
+                    {
+                        return int.MaxValue;
+                    }
+                }).ThenBy(x =>
+                {
+                    var field = x.GetValue("field")?.ToString();
+                    if (colSortDicDefault.ContainsKey(field))
+                    {
+                        return colSortDicDefault[field];
+                    }
+                    else
+                    {
+                        return int.MaxValue;
+                    }
+                });
+                var colSortJArr = new JArray();
+                foreach (var col in colSort)
+                {
+                    colSortJArr.Add(col);
+                }
+                preferenceobj["columns"] = colSortJArr;
+                rslt.tableinfo = preferenceobj;
+            }
+            return rslt;
+        }
+        private void handleCustomTitle(SqlCommand cmd, int empid, JObject col, string dbfield)
+        {
+            var field = col.GetValue("field")?.ToString();
+            var title = col.GetValue("title")?.ToString();
+            var custitle = title;
+            var visibleLimited = false;
+            // 处理标题文本
+            /*if (field.Contains("status") && title.Contains("配置"))
+            {
+                var opTitle = OptionHelper.GetOpString(cmd, "029");
+                if (!string.IsNullOrEmpty(opTitle))
+                {
+                    custitle = custitle.Replace("配置", opTitle);
+                }
+            }
+            else if (field.Contains("woodcode") && title.Contains("配置1"))
+            {
+                var opTitle = OptionHelper.GetOpString(cmd, "027");
+                if (!string.IsNullOrEmpty(opTitle))
+                {
+                    custitle = custitle.Replace("配置1", opTitle);
+                }
+            }
+            else if (field.Contains("pcode") && title.Contains("配置2"))
+            {
+                var opTitle = OptionHelper.GetOpString(cmd, "028");
+                if (!string.IsNullOrEmpty(opTitle))
+                {
+                    custitle = custitle.Replace("配置2", opTitle);
+                }
+            }
+            else if (field.Contains("mtrlsectype"))
+            {
+                var opTitle = OptionHelper.GetOpString(cmd, "041");
+                if (!string.IsNullOrEmpty(opTitle))
+                {
+                    custitle = opTitle;
+                }
+            }
+            else if (field.Contains("zxmtrlmode"))
+            {
+                var opTitle = OptionHelper.GetOpString(cmd, "042");
+                if (!string.IsNullOrEmpty(opTitle))
+                {
+                    custitle = opTitle;
+                }
+            }
+            else if (field.Contains("usermtrlmode"))
+            {
+                var opTitle = OptionHelper.GetOpString(cmd, "128");
+                if (!string.IsNullOrEmpty(opTitle))
+                {
+                    custitle = opTitle;
+                }
+            }
+            else if (field.Contains("otheramt"))
+            {
+                string opTitle = null;
+                if (dbfield.Contains("u_outware.otheramt") || dbfield.Contains("u_saletask.otheramt"))
+                {
+                    opTitle = OptionHelper.GetOpString(cmd, "050");
+                }
+                else if (dbfield.Contains("u_inware.otheramt"))
+                {
+                    opTitle = OptionHelper.GetOpString(cmd, "136");
+                }
+                if (!string.IsNullOrEmpty(opTitle))
+                {
+                    custitle = opTitle;
+                }
+            }
+            else if (field.Contains("excolumn"))
+            {
+                var dbcolname = field;
+                var inputType = 0;
+                dbcolname = RemoveAS(dbcolname);
+                if (dbcolname.Contains("."))
+                {
+                    dbcolname = dbcolname.Substring(dbcolname.LastIndexOf(".") + 1);
+                }
+                cmd.CommandText = @"SELECT replacename,inputtype,ifuse FROM u_ext_billcolumn where ifuse = 1 AND columnname = @columnname";
+                cmd.Parameters.Clear();
+                cmd.Parameters.AddWithValue("@columnname", dbcolname);
+                using (var reader = cmd.ExecuteReader())
+                {
+                    if (reader.Read() && Convert.ToInt32(reader["ifuse"]) == 1)
+                    {
+                        custitle = reader["replacename"].ToString().Trim();
+                        inputType = Convert.ToInt32(reader["inputtype"]);
+                    }
+                    else
+                    {
+                        visibleLimited = true;
+                    }
+                }
+                switch (inputType)
+                {
+                    case 0: // 未指定
+                        break;
+                    case 1: // 数值
+                        col["datatype"] = "number";
+                        break;
+                    case 2: // 文本
+                        break;
+                    case 3: // 日期
+                        col["datatype"] = "date";
+                        break;
+                    case 4: // 复合
+                        break;
+                    default:
+                        break;
+                }
+            }*/
+            if (!string.Equals(title, custitle))
+            {
+                col["title"] = custitle;
+            }
+            //处理显示权限
+            /*if (!col.ContainsKey("funcid"))
+            {
+                if (dbfield.Contains("u_spt.name") || dbfield.Contains("sptname"))
+                {
+                    if (!title.Contains("甲方名称"))
+                    {
+                        col.Add("funcid", 6535);
+                    }
+                }
+            }
+            if (col.ContainsKey("funcid"))
+            {
+                var funcid = Convert.ToInt32(col.GetValue("funcid").ToString());
+                if (!FuncPowerHelper.CheckFuncPower(cmd, empid, funcid))
+                {
+                    visibleLimited = true;
+                }
+            }
+            if (col.ContainsKey("funcid_notequals"))
+            {
+                var funcid = Convert.ToInt32(col.GetValue("funcid_notequals").ToString());
+                if (!FuncPowerHelper.CheckFuncPower(cmd, empid, funcid))
+                {
+                    visibleLimited = true;
+                }
+            }*/
+            if (visibleLimited)
+            {
+                col.Add("limited", true);
+            }
+        }
+        private string RemoveAS(string oristr)
+        {
+            var asindex = oristr.IndexOf(" as ", StringComparison.OrdinalIgnoreCase);
+            if (asindex > 0)
+            {
+                return oristr.Substring(0, asindex);
+            }
+            return oristr;
+        }
+        private class QueryResult
+        {
+            public JArray datatable { get; set; }
+            public JObject tableinfo { get; set; }
+            public int totalcnt { get; set; }
+            public int pageindex { get; set; }
+            public int pagesize { get; set; }
+        }
+    }
+}

+ 2 - 0
JLHHJSvr/GlobalVar/GlobalVar.cs

@@ -110,6 +110,8 @@ namespace JLHHJSvr
 
                 excutorManager.AddMap("GetPriceList", typeof(GetPriceListRequest), new GetPriceListExcutor());
 
+                excutorManager.AddMap("CommonDynamicSelect", typeof(CommonDynamicSelectRequest), new CommonDynamicSelectExcutor());
+
 
 
                 excutorManager.AddMap("SavePermitList", typeof(SavePermitListRequest), new SavePermitListExcutor());//保存车位

+ 3 - 1
JLHHJSvr/JLHHJSvr.csproj

@@ -63,6 +63,7 @@
     <Compile Include="Com\APP\SaveBill.cs" />
     <Compile Include="Com\APP\TmpGetRoadList.cs" />
     <Compile Include="Com\APP\TmpSavePermit.cs" />
+    <Compile Include="Com\CommonDynamicSelect.cs" />
     <Compile Include="Com\DelCarList.cs" />
     <Compile Include="Com\DelPermitList.cs" />
     <Compile Include="Com\DelRoadList.cs" />
@@ -74,7 +75,6 @@
     <Compile Include="Com\GetPriceList.cs" />
     <Compile Include="Com\Model\u_pricelist.cs" />
     <Compile Include="Com\SetSysUserFileString.cs" />
-    <Compile Include="Com\GetUserInfo.cs" />
     <Compile Include="Com\GetOptionList.cs" />
     <Compile Include="Com\GetPermitList.cs" />
     <Compile Include="Com\GetRoadList.cs" />
@@ -126,6 +126,7 @@
     <Compile Include="Excutor\APP\SaveBillExcutor.cs" />
     <Compile Include="Excutor\APP\TmpGetRoadListExcutor.cs" />
     <Compile Include="Excutor\APP\TmpSavePermitExcutor.cs" />
+    <Compile Include="Excutor\CommonDynamicSelectExcutor.cs" />
     <Compile Include="Excutor\DelCarListExcutor.cs" />
     <Compile Include="Excutor\DelPermitListExcutor.cs" />
     <Compile Include="Excutor\DelRoadListExcutor.cs" />
@@ -154,6 +155,7 @@
     <Compile Include="Excutor\SetOptionExcutor.cs" />
     <Compile Include="ImgHelper\ImgHelper.cs" />
     <Compile Include="LJFrameWork\LJException\LJException.cs" />
+    <Compile Include="LJFrameWork\LJLib.Method\SortedListEx.cs" />
     <Compile Include="LJLib.HttpServer\IFileDBModel.cs" />
     <Compile Include="LJLib.HttpServer\SimpleHttpServer.cs" />
     <Compile Include="LJLib.HttpServer\LJHttpProcessor.cs" />

+ 115 - 0
JLHHJSvr/LJFrameWork/LJLib.Method/SortedListEx.cs

@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace LJLib.Method
+{
+    public static class SortedListEx
+    {
+        /// <summary>
+        /// 在有序列表中查找最大的小于等于dt的值的位置
+        /// </summary>
+        /// <typeparam name="T">有序列类型</typeparam>
+        /// <param name="sortedList">有序列表</param>
+        /// <param name="dt">查询值</param>
+        /// <returns>位置,找不到返回-1</returns>
+        public static int GetFirstIndexBefore<T>(this IList<T> sortedList, T dt) where T : IComparable<T>
+        {
+            if (sortedList.Count > 0)
+            {
+                return sortedList.GetFirstIndexBefore(dt, 0, sortedList.Count - 1);
+            }
+            return -1;
+        }
+
+        private static int GetFirstIndexBefore<T>(this IList<T> sortedList, T dt, int min, int max) where T : IComparable<T>
+        {
+            Trace.Assert(min <= max, string.Format("min <= max不正确,min:{0},max:{1}", min, max));
+
+            if (dt.CompareTo(sortedList[max]) >= 0)
+            {
+                return max;
+            }
+
+            if (dt.CompareTo(sortedList[min]) < 0)
+            {
+                return -1;
+            }
+
+            Trace.Assert(min < max, string.Format("min < max不正确,min:{0},max:{1}", min, max));
+
+            int mid = (min + max - 1) / 2;
+
+            if (dt.CompareTo(sortedList[mid]) >= 0)
+            {
+                return GetFirstIndexBefore(sortedList, dt, mid, max - 1);
+            }
+            return GetFirstIndexBefore(sortedList, dt, min, mid - 1);
+        }
+
+        /// <summary>
+        /// 在有序列表中查找最小的大于等于dt的值的位置
+        /// </summary>
+        /// <typeparam name="T">有序列类型</typeparam>
+        /// <param name="sortedList">有序列表</param>
+        /// <param name="dt">查询值</param>
+        /// <returns>位置,找不到返回-1</returns>
+        public static int GetFirstIndexAfter<T>(this IList<T> sortedList, T dt) where T : IComparable<T>
+        {
+            if (sortedList.Count > 0)
+            {
+                return GetFirstIndexAfter(sortedList, dt, 0, sortedList.Count - 1);
+            }
+            return -1;
+        }
+
+        private static int GetFirstIndexAfter<T>(this IList<T> sortedList, T dt, int min, int max) where T : IComparable<T>
+        {
+            Trace.Assert(min <= max, string.Format("min <= max不正确,min:{0},max:{1}", min, max));
+            if (dt.CompareTo(sortedList[min]) <= 0)
+            {
+                return min;
+            }
+
+            if (dt.CompareTo(sortedList[max]) > 0)
+            {
+                return -1;
+            }
+            Trace.Assert(min < max, string.Format("min < max不正确,min:{0},max:{1}", min, max));
+
+            int mid = (min + 1 + max) / 2;
+
+            if (dt.CompareTo(sortedList[mid]) <= 0)
+            {
+                return GetFirstIndexAfter(sortedList, dt, min + 1, mid);
+            }
+            return GetFirstIndexAfter(sortedList, dt, mid + 1, max);
+        }
+
+        public static double GetQty(this SortedList<DateTime, double> line, DateTime end, int first)
+        {
+            Trace.Assert(first >= 0 && first < line.Count, "first >= 0 && first < line.Count");
+            Trace.Assert(end >= line.Keys[first], "end >= line.Keys[first]");
+
+            if (first < 0 || first >= line.Count)
+            {
+                throw new ArgumentException("参数异常", "first");
+            }
+
+            if (end < line.Keys[first])
+            {
+                throw new ArgumentException("参数异常", "end");
+            }
+
+            if (first + 1 == line.Count)
+            {
+                return line.Values[first];
+            }
+
+            return (line.Values[first + 1] - line.Values[first]) *
+                   (end - line.Keys[first]).TotalHours /
+                   (line.Keys[first + 1] - line.Keys[first]).TotalHours
+                   + line.Values[first];
+        }
+    }
+}

+ 5 - 2
JLHHJSvr/LJLib.HttpServer/SimpleHttpServer.cs

@@ -13,6 +13,7 @@ using LJLib.Tools.Utils;
 using JLHHJSvr.LJLib.HttpServer;
 using System.Web;
 using System.Linq;
+using Newtonsoft.Json;
 
 namespace LJLib.HttpServer
 {
@@ -278,8 +279,10 @@ namespace LJLib.HttpServer
                     Trace.Write(requestlist.GetApiName() + ":" + responselist.ErrMsg);
                 }
 
-                Dictionary<string, byte[]> fil = new Dictionary<string, byte[]>();
-                str = parser.ToJson(responselist, fil, "/img.ashx?filename=");
+                //Dictionary<string, byte[]> fil = new Dictionary<string, byte[]>();
+                //str = parser.ToJson(responselist, fil, "/img.ashx?filename=");
+
+                str = JsonConvert.SerializeObject(responselist);
             }
             catch (Exception ex)
             {

+ 18 - 0
JLHHJSvr/Tools/ListEx.cs

@@ -41,5 +41,23 @@ namespace DirectService.Tools
             listString = sb.ToString().TrimEnd(',')+')';
             return listString;
         }
+
+        public static string GetWhereStr(List<string> whereList, string connector = "AND")
+        {
+            string connectStr = " " + connector + " ";
+            var whereStr = string.Empty;
+            for (int i = 0; i < whereList.Count; i++)
+            {
+                if (i == 0)
+                {
+                    whereStr += "(" + whereList[i] + ")";
+                }
+                else
+                {
+                    whereStr += connectStr + "(" + whereList[i] + ")";
+                }
+            }
+            return whereStr;
+        }
     }
 }