6

基于SqlSugar的开发框架循序渐进介绍(20)-- 在基于UniApp+Vue的移动端实现多条件查...

 1 year ago
source link: https://www.cnblogs.com/wuhuacong/p/16844606.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在做一些常规应用的时候,我们往往需要确定条件的内容,以便在后台进行区分的进行精确查询,在移动端,由于受限于屏幕界面的情况,一般会对多个指定的条件进行模糊的搜索,而这个搜索的处理,也是和前者强类型的条件查询处理类似的处理过程,因此本篇随笔探讨两种不同查询在前端界面上的展示效果,以及后端基于.netCore的Web API端的基类进行的统一封装处理。

1、前端精确条件的查询处理

在基于Vue3+Typescript+ElementPlus的前端界面中,查询是很多界面需要拥有的功能,如下所示。 

8867-20221031160706445-278939137.png

 展开后的全部查询条件

 

8867-20221031160934711-110189954.png

 以上的查询部分是一个查询函数的处理,如下代码所示。

// 查询列表处理
async function search() {
  pageInfo.pageIndex = 1; // 重置为第一页

  //默认使用当前用户公司
  const userInfo = $u.util.storageSession.getItem('user_info');
  searchForm.company_ID = userInfo?.company_ID; //所属公司
  await getlist(); //获取列表
}

//列表数据获取
async function getlist() {
  loading.value = true;
  var param = {
    // 分页条件
    SkipCount: (pageInfo.pageIndex - 1) * pageInfo.pageSize,
    MaxResultCount: pageInfo.pageSize,
    Sorting: sorting.value,
// 查询过滤条件 Name: searchForm.name, MobilePhone: searchForm.mobilePhone, Email: searchForm.email, QQ: searchForm.qq, Nickname: searchForm.nickname, HandNo: searchForm.handNo, IsExpire: searchForm.isExpire, Title: searchForm.title, dept_ID: searchForm.dept_id, company_ID: searchForm.company_ID }; //日期条件处理 addDateRange(param, searchForm.creationTime); let result = await user.GetList(param); if (result) { list.value = result.items; pageInfo.totalCount = result.totalCount; } setTimeout(() => { loading.value = false; }, 500); }

我们看到,这些条件都是由特定的参数组成的,因此他们是精确性的属性查询。

前端根据框架后端的接口进行前端JS端的类的封装处理,引入了ES6类的概念实现业务基类接口的统一封装,简化代码。

权限模块我们涉及到的用户管理、机构管理、角色管理、菜单管理、功能管理、操作日志、登录日志等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。

8867-20200713152737929-890201160.png

按照这个思路,我们在BaseApi的ES6类里面定义了对应Web API基类里面的操作方法,如下所示。

8867-20221031163834485-1480698046.png

 这样,我们在创建一个业务类的时候,如果没有特殊的自定义接口,只需要继承基类BaseApi即可具有所有的常规基类方法了。

8867-20221031164108567-287403342.png

 我们再来后端看看具体的查询逻辑实现,首先需要了解各个控制器之间的继承关系,如下图所示 。

8867-20221031164802678-1543197848.png

同样,我们基础的查询处理逻辑,主要也是放在BusinessController里面实现,毕竟是通用的逻辑,变化的只是一些实体信息,因此可以通过泛型的模板方法设计模式处理变化的部分。 

 

8867-20221031165128841-451656386.png

 我们可以看到,在BusinessController控制器部分,它也只是对Service层逻辑的简单封装一下,核心的处理逻辑部分,在下面的基类Service层的代码中。

/// <summary>
/// 根据条件获取列表
/// </summary>
/// <param name="input">分页查询条件</param>
/// <returns></returns>
public virtual async Task<PagedResultDto<TEntity>> GetListAsync(TGetListInput input)
{
    var query = CreateFilteredQueryAsync(input);
    var totalCount = await query.CountAsync();

    query = ApplySorting(query, input);
    query = ApplyPaging(query, input);

    var list = await query.ToListAsync();

    return new PagedResultDto<TEntity>(
       totalCount,
       list
   );
}

这里基类Service层主要处理逻辑部分,而具体的构建精确的查询处理条件,下放在了每个具体业务Service类中进行处理了。

UserService是具体对应的业务类的逻辑处理层,该类的定义方法如下所示。

    /// <summary>
    /// 应用层服务接口实现
    /// </summary>
    public class UserService : MyCrudService<UserInfo, int, UserPagedDto>, IUserService

下放在UserService这个具体业务的Service类中的查询处理逻辑,这部分通过代码生成工具生成即可。

/// <summary>
/// 自定义条件处理
/// </summary>
/// <param name="input">查询条件Dto</param>
/// <returns></returns>
protected override ISugarQueryable<UserInfo> CreateFilteredQueryAsync(UserPagedDto input)
{
    var query = base.CreateFilteredQueryAsync(input);
    query = query
        .WhereIF(input.ExcludeId.HasValue, t => t.Id != input.ExcludeId) //不包含排除ID
        .WhereIF(input.PID.HasValue, s => s.PID == input.PID)
        .WhereIF(!input.HandNo.IsNullOrWhiteSpace(), t => t.HandNo.Contains(input.HandNo)) //如需要精确匹配则用Equals
        .WhereIF(!input.Name.IsNullOrWhiteSpace(), t => t.Name.Contains(input.Name)) //如需要精确匹配则用Equals
        .WhereIF(!input.FullName.IsNullOrWhiteSpace(), t => t.FullName.Contains(input.FullName)) //如需要精确匹配则用Equals
        .WhereIF(!input.Nickname.IsNullOrWhiteSpace(), t => t.Nickname.Contains(input.Nickname)) //如需要精确匹配则用Equals
        .WhereIF(input.IsExpire.HasValue, t => t.IsExpire == input.IsExpire) //如需要精确匹配则用Equals
        
        //过期时间区间查询
        .WhereIF(input.ExpireDateStart.HasValue, s => s.ExpireDate >= input.ExpireDateStart.Value)
        .WhereIF(input.ExpireDateEnd.HasValue, s => s.ExpireDate <= input.ExpireDateEnd.Value)
         
        ****//此处省略更多其他条件
        ;
    return query;
}

通过逻辑和具体对象的实现分离,从而构建了很多通用的基类函数,这些函数只需要在子类重写一些规则即可实现更加详细的处理,也称为模板方法的设计模式,这种方式广泛应用于基类函数的抽象处理。

2、前端模糊查询及自定义查询的处理

介绍了前面基于Vue3+Typescript+ElementPlus的前端界面的内容,主要还是用来引出基于UniApp+Vue的移动端实现多条件查询的处理,一般移动端的界面空间比较宝贵,所以往往查询通过组合条件的方式进行模糊查询处理,如下界面所示。

8867-20221031155742900-1375513789.png

 在查询框中输入一些条件,会在后端对多个条件进行模糊匹配,并返回相应的结果列表进行展示,如下所示。

 

8867-20221031155802738-1409890947.png

查询界面只是接受了一个输入值,通过传递该值,在后端进行多字段的匹配查询处理。前端界面如下所示。

async getlist() {
    var params = {
        MaxResultCount: this.pageSize,
        SkipCount: (this.pageIndex - 1) * this.pageSize,
        Sorting: '',
    }
    if (this.isAdvance) {
        let {
            startDate,
            endDate,
            filter,
            deliveryArea,
            line
        } = this.advanceData;
        params.TimeStart = startDate
        params.TimeEnd = endDate
        params.DeliveryAreas = deliveryArea
        params.Lines = line
        params.Filter = filter
    } else {
        params.Filter = this.searchValue;
    }
    console.log(params)

    this.loadding = true;
    this.pullUpOn = true;

    let res = {};
    if (this.isAdvance) {
        res = await sign.GetAllByFilter2(params);
    } else {
        res = await sign.GetAllByFilter(params);
    }
    console.log(res)
    if (this.totalCount == res.totalCount) {
        this.hasmore = false; //没有了
        this.loadding = false;
        this.pullUpOn = false;
        uni.stopPullDownRefresh();
        return;
    }

    this.totalCount = res.totalCount;
    let items = res.items;
    for (var i = 0; i < items.length; i++) {
        this.list.push(items[i]);
    }

    if (this.list.length < res.totalCount) {
        this.pageIndex += 1;
        console.log(res.totalCount)
    } else {
        this.hasmore = false; //没有了
    }

    this.loadding = false;
    this.pullUpOn = false
    uni.stopPullDownRefresh();

    let count = items.length;
    let options = {
        msg: `刷新成功,为你更新了${count}条数据`,
        duration: 2000,
        type: "translucent"
    };
    if (this.pageIndex > 1) {
        setTimeout(() => {
            this.$refs.toast.showTips(options);
        }, 300);
    }
},

有时候,如需要精确一些的条件处理,也可以以自定义条件的方式进行查询处理的界面。

8867-20221031171054707-1879895206.png

 单击【筛选】按钮进入抽屉式的展示页面,弹出高级查询的相关字段属性,可以进行一定的条件设置处理。

8867-20221031155924085-1435010821.png

同样我们在UniApp+Vue的移动前端项目上,也需要设置BaseApi的基础接口,如下所示。

8867-20221031171423002-44121124.png

 而我们的业务类 Sign-Receipt(Sign-Receipt.js )只需要继承BaseApi(base-api.js)类即可,如下所示。

import BaseApi from '@/api/base-api'

// 业务类自定义接口实现, 通用的接口已经在BaseApi中定义
class Api extends BaseApi {
    FindByCode(shopCode) { // GET 根据客户代码获取记录
        var params = {
            shopCode
        };
        return this.httpget(this.baseurl + 'Find-ByCode', params)
    }

    GetAllByFilter2(params) { // 根据条件获取所有记录
        var url = this.baseurl + 'list-filter2';
        return this.httpget(url, params)
    }
}

// 构造接口对象信息 Api实例,并传递业务类接口地址
export default new Api('/api/SignReceipt/')

对应的后端接口,同样也是使用前面介绍精确查询的方式进行处理,在基类Service层里面,有对应通用的模糊查询方法定义。

/// <summary>
/// 根据指定的Filter值分页获取列表
/// </summary>
/// <param name="input">分页查询条件</param>
/// <returns></returns>
public virtual async Task<PagedResultDto<TEntity>> GetListByFilterAsync(PagedSortedAndFilteredInputDto input)
{
    var query = CreateFilteredQueryAsync(input.Filter);
    var totalCount = await query.CountAsync();

    //排序处理
    if (!input.Sorting.IsNullOrWhiteSpace())
    {
        query = query.OrderBy(input.Sorting);
    }
    else
    {
        query = ApplyDefaultSorting(query);
    }

    //分页处理
    query = query.Skip(input.SkipCount).Take(input.MaxResultCount);

    var list = await query.ToListAsync();
    return new PagedResultDto<TEntity>(
       totalCount,
       list
   );
}

那么下放给子类的CreateFilteredQueryAsync 函数就是实现逻辑的关键,毕竟基类是无法构建正确的条件的。

而对应的SignReceiptService类中,是业务类的逻辑处理方法,该类的定义方法如下所示

    /// <summary>
    /// 拍照签收 应用层服务接口实现
    /// </summary>
    public class SignReceiptService : MyCrudService<SignReceiptInfo,string, SignReceiptPagedDto>, ISignReceiptService

因此它里面可以重写模糊查询条件的逻辑,如下代码所示。

/// <summary>
/// 自定义条件处理(根据Filter进行的过滤处理)
/// </summary>
/// <param name="filter">查询条件Dto</param>
/// <returns></returns>
protected override ISugarQueryable<SignReceiptInfo> CreateFilteredQueryAsync(string filter)
{
    var query = base.CreateFilteredQueryAsync(filter);
    query = query.WhereIF(!filter.IsNullOrWhiteSpace(), t => //模糊搜索用Contains, 如需要精确匹配则用Equals
         t.ShopCode.Contains(filter) || t.ShopName.Contains(filter) || t.Line.Contains(filter) ||
         t.DeliveryArea.Contains(filter) || t.SignMan.Contains(filter) || t.DeliverName.Contains(filter) || t.Note.Contains(filter)
         );

    return query;
}

有了这些条件的定义,我们就可以在Web API的后端,对前端的参数进行联合的模糊查询处理,从而为移动前端提供更好的查询接口服务。

而对于高级查询的处理,我们先要定义好对应的通用的实体类信息,如下所示。

8867-20221031172631581-1138291143.png

然后在具体的进行处理查询逻辑即可,这部分和前面的逻辑处理类似,只是无法实现基类通用的处理而已,因此下发到具体的业务类进行定义。

8867-20221031172806263-610461192.png

 最后在控制器部分,进行一个简单的封装处理即可。

8867-20221031172950994-200049199.png

  以上就是基于不同前端,包括基于Vue3+Typescript+ElementPlus的前端界面,以及基于UniApp+Vue的移动端界面,实现一些常见查询的处理,前端和后端的配合处理逻辑。

系列文章:

基于SqlSugar的开发框架的循序渐进介绍(1)--框架基础类的设计和使用

基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理

基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发

基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理 

基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转

基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口 

基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传

 《基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录

基于SqlSugar的开发框架循序渐进介绍(9)-- 结合Winform控件实现字段的权限控制

基于SqlSugar的开发框架循序渐进介绍(10)-- 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理

基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结

基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理

基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用

基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用

 《基于SqlSugar的开发框架循序渐进介绍(15)-- 整合代码生成工具进行前端界面的生成

基于SqlSugar的开发框架循序渐进介绍(16)-- 工作流模块的功能介绍

基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理

 《基于SqlSugar的开发框架循序渐进介绍(18)-- 基于代码生成工具Database2Sharp,快速生成Vue3+TypeScript的前端界面和Winform端界面

基于SqlSugar的开发框架循序渐进介绍(19)-- 基于UniApp+Vue的移动前端的功能介绍

基于SqlSugar的开发框架循序渐进介绍(20)-- 在基于UniApp+Vue的移动端实现多条件查询的处理


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK