一、問提描述
使用elementUI table 官方篩選案例,發現篩選不是服務器端篩選,而是瀏覽器端對每一頁進行單獨篩選。 如何在服務器端篩選?
二、查詢Element UI 官網table組件發現:
1、Afilter-change事件,說明:當表格的篩選條件發生變化的時候會觸發該事件,參數的值是一個對象,對象的 key 是 column 的 columnKey,對應的 value 為用戶選擇的篩選條件的數組。參數:filters。
2、 prop屬性,說明:對應列內容的字段名,也可以使用 property 屬性。類型 string
3、filters屬性,說明:數據過濾的選項,數組格式,數組中的元素需要有 text 和 value 屬性。類型 Array[{test,value}]
4、column-key屬性,說明:column 的 key,如果需要使用 filter-change 事件,則需要此屬性標識是哪個 column 的篩選條件 類型:string
三、用法描述
1.在 el-table 標簽 @filter-change="handleFilterChange" ,
2. 在vue周期函數methods: {}中實現
handleFilterChange 方法:可以監聽整個table中過濾條件變化; --這個事件非常重要,這里它還充當了與服務器進行數據交互的入口。這是過濾方法不能提供的,因為過濾方法逐行執行,執行次數太多。
setFilter方法:按照服務器api需要的格式組裝過濾條件;此處需要在data({returen{ }})中定義一個中間變量this.filter:[] ,用來保存和更新過濾條件。
getList()方法:發送請求;
3 在 el-table-column 列中,當以過濾條件 :filters="userStatusNameFilters"、column-key="UserStatusName"、prop="UserStatusName" 三者缺一不可,且column-key的值必須與prop一致,也就是必須為字段名稱"。若不定義column-key的值,那么handleFilterChange (filter)返回值filter對象的名稱將會是一個自動生成的值。
4 在data(){return{ userStatusNameFilters: [] }} 定義數組 。如果數據是固定不變的可以在js中直接寫入值 serStatusNameFilters: [{text:‘管理員’,value:‘管理員’},{text:‘普通用戶’,value:‘普通用戶’}] 。如果數據可能有變化,需要從服務器端取值。
四、代碼描述:
前端代碼:
<el-table v-loading="listLoading" :key="tableKey" :data="list" :border="false" :stripe="true" size="small" style="width: 100%;" @filter-change="handleFilterChange" > <el-table-column :filters="regionNameFilters" column-key="RegionName" label="行政區域" prop="RegionName" align="center" width="120px" />
methods: {
// 當talbel中任何一列的過濾條件點擊確定和覆蓋時,都會觸發此事件。
handleFilterChange(filters) {
// console.log(filters)
// console.log('篩選條件發生變化')
let row = null
let val = null
// 拷貝filters的值。
for (const i in filters) {
row = i // 保存 column-key的值,如果事先沒有為column-key賦值,系統會自動生成一個唯一且恆定的名稱
val = filters[i]
}
const filter = [{
row: row,
op: 'contains',
value: val
}]
// console.log(filter)
this.setFilter(filter)
},
getList() { this.listLoading = true var filters = [] for (var i in this.filters) { // 去除value數組為空的值 if (this.filters[i].value && this.filters[i].value.length > 0) { filters.push({ 'field': this.filters[i].row, 'op': this.filters[i].op, 'value': this.filters[i].value }) } } if (filters.length > 0) { // 將 JavaScript 值(通常為對象或數組)轉換為 JSON 字符串 this.listQuery.filters = JSON.stringify(filters) } else { this.listQuery.filters = null } this.listQuery.query = this.queryInfo console.log(filters) getList(this.listQuery).then(response => { // console.log(response.data.rows); this.list = response.data.rows this.total = response.data.total this.listLoading = false }) }, // 通過中間變量this.filters數組,保存當前table中所有列過濾條件的變化。 setFilter(filters) { for (var i in filters) { var filter = null for (var j in this.filters) { // 如果filters[i]中存在於this.filter[]相同的值,那么把當前this.filter[i]的引用覆蓋filter的引用. if (filters[i]['row'] === this.filters[j]['row']) { filter = this.filters[j] } } // 如果filter為空,即不存在相同的值,則將當前filter[i]添加到this.filter[] if (filter == null) { this.filters.push({ 'row': filters[i].row, 'op': filters[i].op, 'value': filters[i].value }) } else { // 如果filter不為空,即存在相同的值。則將filter[i] 賦值給filter,本質是更新this.filter[i]的值。 filter.value = filters[i].value filter.op = filters[i].op } } // console.log(this.filters) this.listQuery.page = 1 this.getList() }, getRegionName() { getRegionName().then(response => { var temp = [] for (var i = 0; i < response.data.length; i++) { temp.push({ text: response.data[i].RegionName, value: response.data[i].RegionName }) } this.regionNameFilters = temp.slice(0) // console.log(this.regionNameFilters) }) }, } //getList、getRegionName 是對axios異步請求的封裝。對應后端的一個api,。
table結合分頁顯示:
//element組件 <el-pagination :current-page="listQuery.page" :page-sizes="[10,15,20,30, 50]" :disabled="enumLoading" :page-size="listQuery.limit" :total="total" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> //變量
enumLoading: false, listQuery: { page: 1, //默認從第一頁開始 limit: 15, //默認每頁15行 filters: [] //存儲需要過濾字段名稱和值 }, //方法 handleSizeChange(val) { this.listQuery.limit = val this.getList() }, handleCurrentChange(val) { this.listQuery.page = val this.getList() },
后端代碼(C#、linq實現):
[HttpGet]
[Route("List")]
public ApiResult GetList(int page, int limit, string sort = null, string order = null, string filters = null, string query = null)
{
PageModel p = new PageModel();
if (filters != null)
{
p.filters = Newtonsoft.Json.JsonConvert.DeserializeObject<Filter[]>(filters);
}
p.page = page;
p.rows = limit;
p.sort = sort;
p.order = order;
if (p.page <= 0)
{
p.page = 1;
}
if (p.rows <= 0)
{
p.rows = 10;
}
var data = manage.GetQueryable().Select(d => d);
//過濾
data = data.Where(p.filters);
//搜索條件
if (query != null && query.Length > 0)
{
data = data.Where(new string[] { "UserName", "RealName" }, query);
}
//排序
if (order != "normal" && sort != null)
{
bool isAsc = order == "asc";
data = data.OrderBy(new[] { sort }, new[] { isAsc });
}
else
{
//默認排序
data = data.OrderBy(d => d.UserID);
}
DataModel pageData = new DataModel();
pageData.page = p.page;
pageData.total = data.Count();
pageData.rows = data.Skip((p.page - 1) * p.rows).Take(p.rows).ToList();
ApiResult result = new ApiResult();
result.success = true;
result.data = pageData;
return result;
}
[HttpGet] [Route("RegionName")] public ApiResult GetRegionName() { ApiResult result = new ApiResult(); result.success = true; result.data = manage.GetRegionData().Select(d => new { id = d.RegionID, name = d.RegionName }).ToList(); return result; }
where orderby 重載
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;
namespace PastureSpace.Models
{
public static class QueryableExtension
{
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string[] propertyName, bool[] ascending) where T : class
{
Type type = typeof(T);
for (int i = 0; i < propertyName.Length; i++)
{
PropertyInfo property = type.GetProperty(propertyName[i]);
if (property == null)
throw new ArgumentException("propertyName", "Not Exist");
ParameterExpression param = Expression.Parameter(type, "p");
Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);
string methodName = ascending[i] ? "OrderBy" : "OrderByDescending";
if (i != 0)
{
methodName = ascending[i] ? "ThenBy" : "ThenByDescending";
}
MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));
source = source.Provider.CreateQuery<T>(resultExp);
}
return source;
}
public static IQueryable<T> Where<T>(this IQueryable<T> source, FilterRule[] filterRules) where T : class
{
if (filterRules == null)
{
return source;
}
Type type = typeof(T);
ParameterExpression param = Expression.Parameter(type, "c");
Expression<Func<T, bool>> op = null;
foreach (var rule in filterRules)
{
PropertyInfo property = type.GetProperty(rule.Field);
if (property == null)
{
continue;
}
//c.Field==Value
//c=>c.Field.Contains(Value)
Expression left = Expression.Property(param, property);
Expression right = Expression.Constant(rule.Value);
Type valueType = property.PropertyType;
if (rule.Value == null || rule.Value == "") continue;
DateTime inputDateTime = DateTime.Now;
try
{
if (valueType == typeof(int) || valueType == typeof(int?))
{
right = Expression.Constant(Convert.ToInt32(rule.Value.Split('.')[0]), valueType);
}
else if (valueType == typeof(short) || valueType == typeof(short?))
{
right = Expression.Constant(Convert.ToInt16(rule.Value.Split('.')[0]), valueType);
}
else if (valueType == typeof(byte) || valueType == typeof(byte?))
{
right = Expression.Constant(Convert.ToByte(rule.Value.Split('.')[0]), valueType);
}
else if (valueType == typeof(long) || valueType == typeof(long?))
{
right = Expression.Constant(Convert.ToInt64(rule.Value), valueType);
}
else if (valueType == typeof(float) || valueType == typeof(float?))
{
right = Expression.Constant(Convert.ToSingle(rule.Value), valueType);
}
else if (valueType == typeof(double) || valueType == typeof(double?))
{
right = Expression.Constant(Convert.ToDouble(rule.Value), valueType);
}
else if (valueType == typeof(decimal) || valueType == typeof(decimal?))
{
right = Expression.Constant(Convert.ToDecimal(rule.Value), valueType);
}
else if (valueType == typeof(DateTime) || valueType == typeof(DateTime?))
{
inputDateTime = Convert.ToDateTime(rule.Value);
right = Expression.Constant(Convert.ToDateTime(rule.Value), valueType);
}
else if (valueType == typeof(Guid) || valueType == typeof(Guid?))
{
right = Expression.Constant(Guid.Parse(rule.Value), valueType);
}
else if (valueType == typeof(bool) || valueType == typeof(bool?))
{
right = Expression.Constant(Boolean.Parse(rule.Value), valueType);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
Expression filter = Expression.Equal(left, right);
Expression filter2 = null;
MethodInfo method;
switch (rule.Op)
{
case OP.contains:
//BinaryExpression
if (valueType == typeof(string))
{
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
filter = Expression.Call(left, method, right);
}
else if (valueType == typeof(DateTime) || valueType == typeof(DateTime?))
{
right = Expression.Constant(inputDateTime.Date);
filter = Expression.GreaterThanOrEqual(left, right);
right = Expression.Constant(inputDateTime.Date.AddDays(1));
filter2 = Expression.LessThan(left, right);
}
else
{
filter = Expression.Equal(left, right);
}
break;
case OP.equal:
filter = Expression.Equal(left, right);
break;
case OP.notequal:
filter = Expression.NotEqual(left, right);
break;
case OP.beginwith:
method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
filter = Expression.Call(left, method, right);
break;
case OP.endwith:
method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
filter = Expression.Call(left, method, right);
break;
case OP.less:
filter = Expression.LessThan(left, right);
break;
case OP.lessorequal:
filter = Expression.LessThanOrEqual(left, right);
break;
case OP.greater:
filter = Expression.GreaterThan(left, right);
break;
case OP.greaterorequal:
filter = Expression.GreaterThanOrEqual(left, right);
break;
default:
break;
}
var lambda = Expression.Lambda<Func<T, bool>>(filter, param);
if (op == null)
{
op = lambda;
}
else
{
op = Expression.Lambda<Func<T, bool>>(Expression.And(op.Body, lambda.Body), op.Parameters);
}
if (filter2 != null)
{
var lambda2 = Expression.Lambda<Func<T, bool>>(filter2, param);
op = Expression.Lambda<Func<T, bool>>(Expression.And(op.Body, lambda2.Body), op.Parameters);
}
}
if (op != null)
{
source = source.Where(op);
}
return source;
}
/// <summary>
/// 多條件過濾
/// </summary>
/// <typeparam name="T">泛型,默認傳入類名</typeparam>
/// <param name="source">默認傳入where前的IQueryable語句</param>
/// <param name="filters">存放一或多個過濾條件的數組</param>
/// <returns></returns>
public static IQueryable<T> Where<T>(this IQueryable<T> source, Filter[] filters) where T : class
{
//檢查過濾條件是否存在,不存在則返回where前的IQueryable語句
if (filters == null)
{
return source;
}
//獲取類型
Type type = typeof(T);
ParameterExpression param = Expression.Parameter(type, "c");
Expression<Func<T, bool>> op = null;
foreach (var rule in filters)
{
PropertyInfo property = type.GetProperty(rule.Field);
if (property == null)
{
continue;
}
//c.Field==Value
//c=>(c.Field.Contains(Value) || c.Field.Contains(Value))
Exception outExc = new Exception();
Expression left = Expression.Property(param, property);
Type valueType = property.PropertyType;
if (rule.Value == null || rule.Value.Length <= 0) continue;
Expression<Func<T, bool>> lambdaOut = null;
foreach (var v in rule.Value)
{
if (v == null || v == "") continue;
Expression right = Expression.Constant(v);
DateTime inputDateTime = DateTime.Now;
try
{
if (valueType == typeof(int) || valueType == typeof(int?))
{
right = Expression.Constant(Convert.ToInt32(v.Split('.')[0]), valueType);
}
else if (valueType == typeof(short) || valueType == typeof(short?))
{
right = Expression.Constant(Convert.ToInt16(v.Split('.')[0]), valueType);
}
else if (valueType == typeof(byte) || valueType == typeof(byte?))
{
right = Expression.Constant(Convert.ToByte(v.Split('.')[0]), valueType);
}
else if (valueType == typeof(long) || valueType == typeof(long?))
{
right = Expression.Constant(Convert.ToInt64(v), valueType);
}
else if (valueType == typeof(float) || valueType == typeof(float?))
{
right = Expression.Constant(Convert.ToSingle(v), valueType);
}
else if (valueType == typeof(double) || valueType == typeof(double?))
{
right = Expression.Constant(Convert.ToDouble(v), valueType);
}
else if (valueType == typeof(decimal) || valueType == typeof(decimal?))
{
right = Expression.Constant(Convert.ToDecimal(v), valueType);
}
else if (valueType == typeof(DateTime) || valueType == typeof(DateTime?))
{
inputDateTime = Convert.ToDateTime(v);
right = Expression.Constant(Convert.ToDateTime(v), valueType);
}
else if (valueType == typeof(Guid) || valueType == typeof(Guid?))
{
right = Expression.Constant(Guid.Parse(v), valueType);
}
else if (valueType == typeof(bool) || valueType == typeof(bool?))
{
right = Expression.Constant(Boolean.Parse(v), valueType);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
Expression filter = Expression.Equal(left, right);
Expression filter2 = null;
MethodInfo method;
switch (rule.Op)
{
case OP.contains:
//BinaryExpression
if (valueType == typeof(string))
{
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
filter = Expression.Call(left, method, right);
}
else if (valueType == typeof(DateTime) || valueType == typeof(DateTime?))
{
right = Expression.Constant(inputDateTime.Date);
filter = Expression.GreaterThanOrEqual(left, right);
right = Expression.Constant(inputDateTime.Date.AddDays(1));
filter2 = Expression.LessThan(left, right);
}
else
{
filter = Expression.Equal(left, right);
}
break;
case OP.equal:
filter = Expression.Equal(left, right);
break;
case OP.notequal:
filter = Expression.NotEqual(left, right);
break;
case OP.beginwith:
method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
filter = Expression.Call(left, method, right);
break;
case OP.endwith:
method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
filter = Expression.Call(left, method, right);
break;
case OP.less:
filter = Expression.LessThan(left, right);
break;
case OP.lessorequal:
filter = Expression.LessThanOrEqual(left, right);
break;
case OP.greater:
filter = Expression.GreaterThan(left, right);
break;
case OP.greaterorequal:
filter = Expression.GreaterThanOrEqual(left, right);
break;
default:
break;
}
var lambda = Expression.Lambda<Func<T, bool>>(filter, param);
if (lambdaOut == null)
{
lambdaOut = lambda;
}
else
{
lambdaOut = Expression.Lambda<Func<T, bool>>(Expression.Or(lambdaOut.Body, lambda.Body), lambdaOut.Parameters);
}
if (filter2 != null)
{
var lambda2 = Expression.Lambda<Func<T, bool>>(filter2, param);
lambdaOut = Expression.Lambda<Func<T, bool>>(Expression.And(lambdaOut.Body, lambda2.Body), lambdaOut.Parameters);
}
}
if (rule.Op == OP.range && rule.Value != null && rule.Value.Length == 2)
{
if (!(rule.Value[0] == null || rule.Value[0] == "") && !(rule.Value[1] == null || rule.Value[1] == ""))
{
Expression right1 = Expression.Constant(rule.Value[0]);
Expression right2 = Expression.Constant(rule.Value[1]);
try
{
if (valueType == typeof(int) || valueType == typeof(int?))
{
right1 = Expression.Constant(Convert.ToInt32(rule.Value[0].Split('.')[0]), valueType);
right2 = Expression.Constant(Convert.ToInt32(rule.Value[1].Split('.')[0]), valueType);
}
else if (valueType == typeof(short) || valueType == typeof(short?))
{
right1 = Expression.Constant(Convert.ToInt16(rule.Value[0].Split('.')[0]), valueType);
right2 = Expression.Constant(Convert.ToInt16(rule.Value[1].Split('.')[0]), valueType);
}
else if (valueType == typeof(byte) || valueType == typeof(byte?))
{
right1 = Expression.Constant(Convert.ToByte(rule.Value[0].Split('.')[0]), valueType);
right2 = Expression.Constant(Convert.ToByte(rule.Value[1].Split('.')[0]), valueType);
}
else if (valueType == typeof(long) || valueType == typeof(long?))
{
right1 = Expression.Constant(Convert.ToInt64(rule.Value[0]), valueType);
right2 = Expression.Constant(Convert.ToInt64(rule.Value[1]), valueType);
}
else if (valueType == typeof(float) || valueType == typeof(float?))
{
right1 = Expression.Constant(Convert.ToSingle(rule.Value[0]), valueType);
right2 = Expression.Constant(Convert.ToSingle(rule.Value[1]), valueType);
}
else if (valueType == typeof(double) || valueType == typeof(double?))
{
right1 = Expression.Constant(Convert.ToDouble(rule.Value[0]), valueType);
right2 = Expression.Constant(Convert.ToDouble(rule.Value[1]), valueType);
}
else if (valueType == typeof(decimal) || valueType == typeof(decimal?))
{
right1 = Expression.Constant(Convert.ToDecimal(rule.Value[0]), valueType);
right2 = Expression.Constant(Convert.ToDecimal(rule.Value[1]), valueType);
}
else if (valueType == typeof(DateTime) || valueType == typeof(DateTime?))
{
right1 = Expression.Constant(Convert.ToDateTime(rule.Value[0]), valueType);
right2 = Expression.Constant(Convert.ToDateTime(rule.Value[1]), valueType);
}
else if (valueType == typeof(Guid) || valueType == typeof(Guid?))
{
right1 = Expression.Constant(Guid.Parse(rule.Value[0]), valueType);
right2 = Expression.Constant(Guid.Parse(rule.Value[0]), valueType);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
Expression filter = Expression.GreaterThanOrEqual(left, right1);
Expression filter2 = Expression.LessThanOrEqual(left, right2);
var lambda = Expression.Lambda<Func<T, bool>>(filter, param);
if (lambdaOut == null)
{
lambdaOut = lambda;
}
else
{
lambdaOut = Expression.Lambda<Func<T, bool>>(Expression.Or(lambdaOut.Body, lambda.Body), lambdaOut.Parameters);
}
if (filter2 != null)
{
var lambda2 = Expression.Lambda<Func<T, bool>>(filter2, param);
lambdaOut = Expression.Lambda<Func<T, bool>>(Expression.And(lambdaOut.Body, lambda2.Body), lambdaOut.Parameters);
}
}
}
if (op == null)
{
op = lambdaOut;
}
else
{
if (lambdaOut != null)
{
op = Expression.Lambda<Func<T, bool>>(Expression.And(op.Body, lambdaOut.Body), op.Parameters);
}
}
}
if (op != null)
{
source = source.Where(op);
}
return source;
}
/// <summary>
/// 僅查詢string類型數據
/// </summary>
/// <typeparam name="T">泛型,默認傳入類名</typeparam>
/// <param name="source">默認傳入where前的IQueryable語句</param>
/// <param name="columnNames">存放待查詢列名稱的數組</param>
/// <param name="filterString">查詢內容</param>
/// <returns></returns>
public static IQueryable<T> Where<T>(this IQueryable<T> source, string[] columnNames, string filterString)
{
//獲取覆蓋當前泛型的類型
Type type = typeof(T);
//構建表達式樹的參數c
ParameterExpression param = Expression.Parameter(type, "c");
//構建一個表達式樹節點,存放查詢內容
Expression right = Expression.Constant(filterString);
//1!=1
//Expression op = Expression.NotEqual(Expression.Constant(1), Expression.Constant(1));
//構建一個存放lamdba表達式樹的空對象
Expression<Func<T, bool>> op = null;
//循環遍歷存放查詢列的數組
foreach (var column in columnNames)
{
//反射獲取該列對應屬性的類型
PropertyInfo property = type.GetProperty(column);
//如果不存在該屬性則結束本次循環,進入下次循環
if (property == null)
{
continue;
}
//c.Field==Value
//c=>c.Field.Contains(Value)
//構建一個表示訪問屬性的表達式樹c=>c.Field
Expression left = Expression.Property(param, property);
//獲取屬性類型
Type valueType = property.PropertyType;
//若屬性類型不為string類型,則結束本次循環
if (valueType != typeof(string)) continue;
//若屬性值等於null或字符串長度為0,則結束本次循環
if (filterString == null || filterString == "") continue;
//通過反射獲取string類型的Contains方法
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
//構建一個表示調用參數的方法 c=>c.Field.Contains(Value)
Expression filter = Expression.Call(left, method, right);
//將表達式轉換為lambda表達式
var lambda = Expression.Lambda<Func<T, bool>>(filter, param);
if (op == null)
{
//將構建好的lambda表達式賦值給op對象
op = lambda;
}
else
{
// 若op非空,則以or形式追加本次lambda表達式到op對象
op = Expression.Lambda<Func<T, bool>>(Expression.Or(op.Body, lambda.Body), op.Parameters);
}
}
if (op != null)
{
//如果op不為空,則輸出合並后的語句
source = source.Where(op);
}
return source;
}
}
}
Filter、OP模型類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace PastureSpace.Models
{
public class FilterRule
{
public string Field { get; set; }
public OP Op { get; set; }
public string Value { get; set; }
}
public class Filter
{
public string Field { get; set; }
public OP Op { get; set; }
public string[] Value { get; set; }
}
public enum OP
{
contains, equal, notequal, beginwith, endwith, less, lessorequal, greater, greaterorequal, range
}
}
pageMode模型類
public class PageModel { public int Page { get; set; } public int Rows { get; set; } public string Sort { get; set; } public string Order { get; set; } public string FilterRules { get; set; } public List<FilterRule> FilterRuleList { get { if (FilterRules == null) return null; return JsonConvert.DeserializeObject<List<FilterRule>>(FilterRules); } } }
ApiResult 模型類
public class ApiResult { public bool success { get; set; } public string msg { get; set; } public object data { get; set; } }
以上代碼是從實際項目截取出來的並不是完整的Demo,實際項目測試可行,如有問題請留言。
核心是 從前端element table幾個方法獲取篩選條件 , 服務器端where orderby 重載實現多條件篩選和排序。
