ABP 多模块关联查询、分组统计、列转行、Vue 复合表头动态列

本文记录了一次使用abp Core5 ,vue 开发复杂报表的经历。

0、需求概述

业务需求是:统计一个化工厂车队形式记录数据中异常停车的报表,维度可以按照车俩、驾驶员两个维度进行统计,统计的元素有:

TLX01 堵车|TLX02 限行|TLX03 途中车辆维修|TLX04 停车休息|TLX05 雨雾天气|TLX06 装卸货或装卸货排队|TLX07 围栏停留|TLX08 吃饭|TLX09 加油|TLX10 洗车加水。

原始报表样式:
在这里插入图片描述

解决思路是:
在这里插入图片描述

1、sqlserver 分析数据源

1.1 表数据

整个报表牵扯的5张表, 分表示,停车日志、明细、要统计的停车事件类型、驾驶员信息,如下:

select * from TruckAwaitLog where LogId=‘F02D9B3E-D172-473A-8D01-FFF28A92B17C’ //停车日志
select * from TruckAwaitLogDetail where MainId=‘F02D9B3E-D172-473A-8D01-FFF28A92B17C’ //明细
select * from TruckAwaitLogType //停车事件类型
select * from [人员信息] where [人员信息].userid=‘0640’

1.2 统计数据源的sql脚本

  • —异常停留类型统计表(按车俩)
SELECT truck.cCode_Name,truck.cCode, TruckAwaitLog.MainTruckId as 主驾驶,
TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName,
	SUM(TruckAwaitLog.TotalDuration) as 时长, count(truck.cCode) AS  次数
	FROM TruckAwaitLog 
	left join TruckAwaitLogType
	on TruckAwaitLog.TypeId= TruckAwaitLogType.TypeId 	
	left join [YDDATA].[dbo].[车辆] as truck
	on  truck.cCode = TruckAwaitLog.MainTruckId
	GROUP BY  truck.cCode_Name ,truck.cCode,TruckAwaitLog.MainTruckId,
	TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName order by  TruckAwaitLog.MainTruckId

在这里插入图片描述

  • –异常停留类型统计表(按驾驶员)
SELECT  TruckAwaitLog.TruckEscortUserId as 主驾驶,Human.cCode_Name,
   	TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName,
   	SUM(TruckAwaitLog.TotalDuration) as 时长,
   	count(TruckAwaitLog.LogId) AS  次数
   FROM TruckAwaitLog 
   left join TruckAwaitLogType
   on TruckAwaitLog.TypeId= TruckAwaitLogType.TypeId 	
   inner join [YDDATA].[dbo].[V人员信息] as Human
   on  Human.userid = TruckAwaitLog.MainUserId
   GROUP BY  Human.cCode_Name, TruckAwaitLog.TruckEscortUserId,TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName

在这里插入图片描述经分析后,使用多表查询,达到的报表要求, 还需处理行专列问题,由于开发框架采用ABP的DDD模式,尽量不使用原生sql,所以使用仓储模式,多模块关联,linq处理数据问题,行专列使用动态 Linq.Dynamic 构建行转列。

2、Abp 中Efcore的多模块关联查询

2.1回顾ABP 架构模型

在这里插入图片描述

2.2 回顾abp 的代码分层模型

在这里插入图片描述

2.3 回顾abp 的分层调用关系模型

在这里插入图片描述

2.3 ABP 模块构建

2.3.1 构建领域对象

 /// <summary>
    /// TruckAwaitLog,领域对象
    /// </summary>
    [Table("TruckAwaitLog")]
    public class TruckAwaitLog : Entity<Guid>
    { 
        /// <summary>
        /// 默认构造函数(需要初始化属性的在此处理)
        /// </summary>
	    public TruckAwaitLog()
		{
		}

        #region Property Members
        [Column("LogId")]
        public override Guid Id { get; set; }
        //[Required]
        //[Required]
        //public virtual Guid LogId { get; set; }

		//[Required]
        public virtual string AccId { get; set; }

		//[Required]
        public virtual string VouchId { get; set; }

		//[Required]
        [Required]
        public virtual string MainUserId { get; set; }

		//[Required]
        public virtual string SubUserId { get; set; }

		//[Required]
        public virtual string TruckEscortUserId { get; set; }

ABP 重写主键ID
由于ABP设计的领域对象 Entity : IEntity有主键默认名称:id

namespace Abp.Domain.Entities
{
    //
    // 摘要:
    //     Basic implementation of IEntity interface. An entity can inherit this class of
    //     directly implement to IEntity interface.
    //
    // 类型参数:
    //   TPrimaryKey:
    //     Type of the primary key of the entity
    [Serializable]
    public abstract class Entity<TPrimaryKey> : IEntity<TPrimaryKey>
    {
        //
        // 摘要:
        //     Unique identifier for this entity.
        public virtual TPrimaryKey Id
        {
            get;
            set;
        }

        //
        // 摘要:
        //     Checks if this entity is transient (it has not an Id).
        //
        // 返回结果:
        //     True, if this entity is transient
        public virtual bool IsTransient()
        {
            if (EqualityComparer<TPrimaryKey>.Default.Equals(Id, default(TPrimaryKey)))
            {
                return true;
            }

            if (typeof(TPrimaryKey) == typeof(int))
            {
                return Convert.ToInt32(Id) <= 0;
            }

            if (typeof(TPrimaryKey) == typeof(long))
            {
                return Convert.ToInt64(Id) <= 0;
            }

            return false;
        }

        public virtual bool EntityEquals(object obj)
        {
            if (obj == null || !(obj is Entity<TPrimaryKey>))
            {
                return false;
            }

            if (this == obj)
            {
                return true;
            }

            Entity<TPrimaryKey> entity = (Entity<TPrimaryKey>)obj;
            if (IsTransient() && entity.IsTransient())
            {
                return false;
            }

            Type type = GetType();
            Type type2 = entity.GetType();
            if (!type.GetTypeInfo().IsAssignableFrom(type2) && !type2.GetTypeInfo().IsAssignableFrom(type))
            {
                return false;
            }

            if (this is IMayHaveTenant && entity is IMayHaveTenant && this.As<IMayHaveTenant>().TenantId != entity.As<IMayHaveTenant>().TenantId)
            {
                return false;
            }

            if (this is IMustHaveTenant && entity is IMustHaveTenant && this.As<IMustHaveTenant>().TenantId != entity.As<IMustHaveTenant>().TenantId)
            {
                return false;
            }

            return Id.Equals(entity.Id);
        }

        public override string ToString()
        {
            return $"[{GetType().Name} {Id}]";
        }
    }
}

所以我们表设计主键不是id的情况下要改写,规则如下。

[Column(“你那表的源主键名”)] public override leixing Id{ get; set; }>

  • 重写ID [Column(“数据库指定的ID”)]>

[Column(“CarTypeID”)]
public override int Id { get; set; }

  • 2.映射中指定 这里用的是AutoMapper

第一个UserID是Dto模型里面的 第二个Id是实体类中我们重写的那个Id

1 var carTypeDtoMapper = mapperConfig.CreateMap<CarType,
CarTypeDto>(); 2 carTypeDtoMapper.ForMember(dto => dto.CarTypeID, map
=> map.MapFrom(m => m.Id));
3.对于多表查询外键ID无效的情况 可以在实体中指定外键

1 [ForeignKey(“CarBrand”)] 2 public int? BrandID { get; set; }
对于ForeignKeyVS给我们做了良好的解释>
1 //如果将 ForeigKey 特性添加到外键属性,则应指定关联的导航属性的名称。如果将 ForeigKey
特性添加到导航属性,则应指定关联的外键的名称。如果导航属性具有多个外键,则使用逗号分隔的外键名称列表。
public ForeignKeyAttribute(string name);
4.获取数据 将数据返回 这里用的是DTO模型传输数据>
1 var list = _carTypeRepository.GetAllList();
2 将POCO对象转为DTO对象
3 return list.MapTo<List>();

2.3.2 构建基础设施对象

 public partial class SecondDbContext : AbpZeroDbContext<Tenant, Role, User, SecondDbContext>, IAbpPersistedGrantDbContext

    {
           /// <summary>
        /// TruckAwaitLog,数据表对象
        /// </summary>
        public virtual DbSet<TruckAwaitLog> TruckAwaitLogs { get; set; }
        /// <summary>
        /// TruckAwaitLogDetail,数据表对象
        /// </summary>
        public virtual DbSet<TruckAwaitLogDetail> TruckAwaitLogDetails { get; set; }
        /// <summary>
        /// TruckAwaitLogType,数据表对象
        /// </summary>
        public virtual DbSet<TruckAwaitLogType> TruckAwaitLogTypes { get; set; }
        /// <summary>
        /// TruckStatus,数据表对象
        /// </summary>
        public virtual DbSet<TruckStatus> TruckStatuss { get; set; }

        /// <summary>
        /// 车辆,数据表对象
        /// </summary>
        public virtual DbSet<车辆> 车辆s { get; set; }
        /// <summary>
        /// V人员信息,数据表对象
        /// </summary>
        public virtual DbSet<V人员信息> V人员信息s { get; set; }

        //IdentityServer接口实现
        public virtual DbSet<PersistedGrantEntity> PersistedGrants { get; set; }

        public SecondDbContext(DbContextOptions<SecondDbContext> options) : base(options)
        {

        }

    }
}

2.3.2 构建应用层对象

    /// <summary>
    /// TruckAwaitLog,应用层服务接口实现
    /// </summary>
    [DisableAuditing]
    [AbpAuthorize]
    public class TruckAwaitLogAppService : MyAsyncServiceBase<TruckAwaitLog, TruckAwaitLogDto, Guid, TruckAwaitLogPagedDto, CreateTruckAwaitLogDto, TruckAwaitLogDto>, ITruckAwaitLogAppService
    {
        private readonly IRepository<TruckAwaitLog, Guid> _truckAwaitLogRepository;

        private readonly IRepository<TruckAwaitLogDetail, string> _truckAwaitLogDetailRepository;

        private readonly IRepository<TruckAwaitLogType, string> _truckAwaitLogTypeRepository;

        private readonly IRepository<车辆, string> _truckRepository;

        private readonly IRepository<V人员信息, string> _renYuanRepository;

        private readonly IRepository<User, long> _userRepository;//用户信息仓储对象

        public TruckAwaitLogAppService(
            IRepository<TruckAwaitLog, Guid> truckAwaitLogRepository,
            IRepository<TruckAwaitLogDetail, string> truckAwaitLogDetailRepository,
            IRepository<TruckAwaitLogType, string> truckAwaitLogTypeRepository,
            IRepository<车辆, string> truckRepository,
            IRepository<V人员信息, string> renYuanRepository,
            IRepository<User, long> userRepository) : base(truckAwaitLogRepository)
        {
            _truckAwaitLogRepository = truckAwaitLogRepository;
            _truckAwaitLogDetailRepository = truckAwaitLogDetailRepository;
            _truckAwaitLogTypeRepository = truckAwaitLogTypeRepository;
            _truckRepository = truckRepository;
            _renYuanRepository = renYuanRepository;



            _userRepository = userRepository;

        }

2.4 多模块关联查询、分组统计、列转行

-在 Application.Service 模块构建联合查询

 //Linq 构建关联查询 -异常停留类型统计表(按车俩)
//构建关联查询
                var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()
                            join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Id
                            join truck in _truckRepository.GetAll() on truckAwaitLog.MainTruckId equals truck.Id
                            where truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEnd

                            select new TruckAwaitLogQueryDto
                            {
                                NameID = truck.Id,
                                Name = truck.CCode_Name,
                                // StopEventAreaTypeID = truckAwaitLogType.TypeId,
                                StopEventArea = truckAwaitLogType.TypeName,
                                TotalDuration = truckAwaitLog.TotalDuration
                            };
//构建关联查询结构上实现分组统计
                var queryColumn = (from m in query
                                   group m by
                                    //new { m.NameID, m.Name, m.StopEventArea, m.StopEventAreaTypeID }
                                    new { m.NameID, m.Name, m.StopEventArea }
                                   into g
                                   select new TruckAwaitLogQueryDto
                                   {
                                       NameID = g.Key.NameID,
                                       Name = g.Key.Name + g.Key.NameID,
                                       // StopEventAreaTypeID = g.Key.StopEventAreaTypeID,
                                       StopEventArea = g.Key.StopEventArea,
                                       TotalDuration = g.Sum(p => p.TotalDuration),
                                       Numbers = g.Count()

                                   }).ToList();
```csharp
//Linq 构建关联查询 -异常停留类型统计表(按驾驶员)
 //构建关联查询
                var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()
                            join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Id
                            join renyuan in _renYuanRepository.GetAll() on truckAwaitLog.MainUserId equals renyuan.Id
                            where truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEnd

                            select new TruckAwaitLogQueryDto
                            {
                                NameID = renyuan.Id,
                                Name = renyuan.CCode_Name,
                              //  StopEventAreaTypeID = truckAwaitLogType.TypeId,
                                StopEventArea = truckAwaitLogType.TypeName,
                                TotalDuration = truckAwaitLog.TotalDuration
                            };
//构建关联查询结构上实现分组统计
                var queryColumn = (from m in query
                                   group m by
                                   new { m.NameID, m.Name, m.StopEventArea }
                                   into g
                                   select new TruckAwaitLogQueryDto
                                   {
                                       NameID = g.Key.NameID,
                                       Name = g.Key.Name + g.Key.NameID,
                                       // StopEventAreaTypeID = g.Key.StopEventAreaTypeID,
                                       StopEventArea = g.Key.StopEventArea,
                                       TotalDuration = g.Sum(p => p.TotalDuration),
                                       Numbers = g.Count()

                                   }).ToList();

-在 Application.Service 封装完整代码供客户端调用

/// <summary>
        /// 自定义条件处理,暴漏API
        /// </summary>
        /// <param name="input">查询条件Dto</param>
        /// <returns></returns>
        [DisableAuditing]
        public async Task<List<dynamic>> CreateReportDataSourceWithUserQueryAsync(TruckAwaitLogPagedDto input)
        {    
            //报表统计的维度 : 前台传过来分组维度和动态列字段
            //DEMO: 分组维度:{DimensionList:['Name']  车辆|人员
            //动态列字段:DynamicColumn:'StopEventArea'}
            List<string> DimensionList = new List<string>() { "Name" };
            string DynamicColumn = "StopEventArea";
            List<string> AllDynamicColumn = null;

            if (input.QueryType == "按车辆")//按车辆
            {
                //构建关联查询
                var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()
                            join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Id
                            join truck in _truckRepository.GetAll() on truckAwaitLog.MainTruckId equals truck.Id
                            where truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEnd

                            select new TruckAwaitLogQueryDto
                            {
                                NameID = truck.Id,
                                Name = truck.CCode_Name,
                                // StopEventAreaTypeID = truckAwaitLogType.TypeId,
                                StopEventArea = truckAwaitLogType.TypeName,
                                TotalDuration = truckAwaitLog.TotalDuration
                            };

                var queryColumn = (from m in query
                                   group m by
                                    //new { m.NameID, m.Name, m.StopEventArea, m.StopEventAreaTypeID }
                                    new { m.NameID, m.Name, m.StopEventArea }
                                   into g
                                   select new TruckAwaitLogQueryDto
                                   {
                                       NameID = g.Key.NameID,
                                       Name = g.Key.Name + g.Key.NameID,
                                       // StopEventAreaTypeID = g.Key.StopEventAreaTypeID,
                                       StopEventArea = g.Key.StopEventArea,
                                       TotalDuration = g.Sum(p => p.TotalDuration),
                                       Numbers = g.Count()

                                   }).ToList();


                return await Task.FromResult(MyProject.Application.HY.OLAP.Report.Helper.ReportUtility.
                    DynamicRow2ColeByLinq(queryColumn, DimensionList, DynamicColumn, out AllDynamicColumn));

               

            }
            else if (input.QueryType == "按驾驶员")//按人员
            {
                //构建关联查询
                var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()
                            join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Id
                            join renyuan in _renYuanRepository.GetAll() on truckAwaitLog.MainUserId equals renyuan.Id
                            where truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEnd

                            select new TruckAwaitLogQueryDto
                            {
                                NameID = renyuan.Id,
                                Name = renyuan.CCode_Name,
                              //  StopEventAreaTypeID = truckAwaitLogType.TypeId,
                                StopEventArea = truckAwaitLogType.TypeName,
                                TotalDuration = truckAwaitLog.TotalDuration
                            };

                var queryColumn = (from m in query
                                   group m by
                                   new { m.NameID, m.Name, m.StopEventArea }
                                   into g
                                   select new TruckAwaitLogQueryDto
                                   {
                                       NameID = g.Key.NameID,
                                       Name = g.Key.Name + g.Key.NameID,
                                       // StopEventAreaTypeID = g.Key.StopEventAreaTypeID,
                                       StopEventArea = g.Key.StopEventArea,
                                       TotalDuration = g.Sum(p => p.TotalDuration),
                                       Numbers = g.Count()

                                   }).ToList();

       //动态Linq方式实现行转列
                return await Task.FromResult(MyProject.Application.HY.OLAP.Report.Helper.ReportUtility.
              DynamicRow2ColeByLinq(queryColumn, DimensionList, DynamicColumn, out AllDynamicColumn));

               // return result   List<dynamic> result = ;
            }
            return null;
        }

2.5.使用Linq.Dynamic 构建行转列为报表提供数据源

需要nuget 引入 Linq.Dynamic。
传入原始数据源在这里插入图片描述

    /// <summary>
    /// 报表工具类
    /// 须在nuget引入System.Linq.Dynamic
    /// </summary>
    public class ReportUtility
    {        // <summary>
        /// 动态Linq方式实现行转列
        /// </summary>
        /// <param name="listSource">原始数据集合</param>
        /// <param name="DimensionList">维度列(分组列)</param>
        /// <param name="DynamicColumn">动态列(要生成的列)</param>
        /// <returns>行转列后数据</returns>
        //private List<TruckAwaitLogQueryDto> GetTruckAwaitLogQueryDtoList(List<TruckAwaitLogType> listTypes, List<EntityTruckAwaitLogByVehicleUser> entityTruckAwaitLogBies)
        public static List<dynamic> DynamicRow2ColeByLinq<T>(List<T> listSource, List<string> DimensionList, string DynamicColumn, out List<string> AllDynamicColumn) where T : class
        {
            //获取所有动态列
            var columnGroup = listSource.GroupBy(DynamicColumn, "new(it as Vm)") as IEnumerable<IGrouping<dynamic, dynamic>>;
            List<string> AllColumnList = new List<string>();
            foreach (var item in columnGroup)
            {
                if (!string.IsNullOrEmpty(item.Key))
                {
                    AllColumnList.Add(item.Key);
                }
            }
            AllDynamicColumn = AllColumnList;
            var dictFunc = new Dictionary<string, Func<T, bool>>();
            foreach (var column in AllColumnList)
            {
                var func = DynamicExpression.ParseLambda<T, bool>(string.Format("{0}==\"{1}\"", DynamicColumn, column)).Compile();
                dictFunc[column] = func;
            }
            //获取实体所有属性
            Dictionary<string, PropertyInfo> PropertyInfoDict = new Dictionary<string, PropertyInfo>();
            Type type = typeof(T);
            var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            //数值列
            List<string> AllNumberField = new List<string>();
            foreach (var item in propertyInfos)
            {
                PropertyInfoDict[item.Name] = item;
                if (item.PropertyType == typeof(int) || item.PropertyType == typeof(double) || item.PropertyType == typeof(float))
                {
                    AllNumberField.Add(item.Name);
                }
            }
            //分组
            var dataGroup = listSource.GroupBy(string.Format("new ({0})", string.Join(",", DimensionList)), "new(it as Vm)") as IEnumerable<IGrouping<dynamic, dynamic>>;
            List<dynamic> listResult = new List<dynamic>();
            IDictionary<string, object> itemObj = null;
            T vm2 = default(T);
            foreach (var group in dataGroup)
            {
                itemObj = new ExpandoObject();
                var listVm = group.Select(e => e.Vm as T).ToList();
                //维度列赋值
                vm2 = listVm.FirstOrDefault();
                foreach (var key in DimensionList)
                {
                    itemObj[key] = PropertyInfoDict[key].GetValue(vm2);
                }
                foreach (var column in AllColumnList)
                {
                    vm2 = listVm.FirstOrDefault(dictFunc[column]);
                    if (vm2 != null)
                    {
                        foreach (string name in AllNumberField)
                        {
                            itemObj[name + column] = PropertyInfoDict[name].GetValue(vm2);
                        }
                    }
                }
                listResult.Add(itemObj);   
            }
            return listResult;
        }

    }

该方法处理后的数据如下。
在这里插入图片描述

3、 VUE TABLE 多级表头实现

数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。

3.1 导入业务API对象

import truckAwaitLog from '@/api/HYReport/truckawaitlog'	// 停车数据业务操作对象
import truckAwaitLogType from '@/api/HYReport/truckawaitlogtype'	// 停车事件业务操作对象

```css
class Api extends BaseApi {
  GetReportDataSource(data) {
    return request({
      url: this.baseurl + 'CreateReportDataSourceWithUserQueryAsync',
      method: 'get',
      params: data
    })
  }
class Api extends BaseApi {  
  GetStopEventAreas() {
    return request({
      url: this.baseurl + 'GetTruckAwaitLogType',
      method: 'get'
    })
  }

3.2 vue 查询面板

查询面板值得是查询功能区布局,包含查询条件的组合,功能按钮等, 比如多条件下拉组合、时间选择、类型选择等。
在这里插入图片描述

       <pane min-size="10" max-size="20">
        <el-card class="box-card" style="background-color:#eef1f6">
          <div slot="header" class="clearfix" style="text-align:center">
            <span>
              <i class="el-icon-s-grid" />
              异常停留类型查询面板
              <i class="el-icon-s-grid" />
            </span>
          </div>
        </el-card>
        <el-card class="box-card" style="background-color:#eef1f6">
          <!--查询条件区域 -->
          <el-form ref="searchForm" :model="searchForm" label-width="100px" :inline="true">
            <template>
              <el-form-item label="统计时间">
                <el-date-picker v-model="searchForm.AddDate" type="daterange" align="right" unlink-panels range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="pickerOptions" />
              </el-form-item>
            </template>
            <template>
              <div>
                <el-radio-group v-model="radiorules">
                  <el-radio-button label="按驾驶员" />
                  <el-radio-button label="按车辆" />
                </el-radio-group>
              </div>
            </template>
          </el-form>
        </el-card>
        <el-card class="box-card" style="background-color:#eef1f6">
          <template>
            <!--功能操作按钮 -->
            <el-row style="float:right;padding-bottom:10px">
              <el-button-group>
                <el-button icon="el-icon-search" type="primary" size="mini" round @click="search()">查询</el-button>
                <el-button icon="el-icon-refresh-left" type="warning" size="mini" round plain @click="resetSeachForm('searchForm')">重置</el-button>
              </el-button-group>
              <el-button-group>
                <el-button icon="el-icon-download" :loading="downloadLoading" type="primary" size="mini" round @click="handleDownload()">导出</el-button>
              </el-button-group>
            </el-row>
          </template>
        </el-card>
      </pane>

3.2 vue 查询数据展示区

实际的数据查询结果。
在这里插入图片描述组合表头,列合并分组
嵌套实现组合
动态列表头的生成

StopEventArea 是通过import truckAwaitLogType from ‘@/api/HYReport/truckawaitlogtype’ // 停车事件业务操作对象获取的事件类型。

动态列表头的数据源关联获取

  <el-table-column v-for="(item,i) in StopEventArea" :key="i" :prop="item.typeId" :label="item.typeName" align="center">
            <el-table-column :key="item.typeId" :prop="`Numbers`+item.typeName" label="次数" :formatter="NumbersFun" />
            <el-table-column :key="item.typeId" :prop="`TotalDuration`+item.typeName" label="时长(分)" :formatter="TotalDurationFun" />
          </el-table-column>

:label=“item.typeName”
:prop=“Numbers+item.typeName”

完整代码

这里注意返回数据的结构, vue遍历的时候动态变量赋值问题。

<pane style="background-color:#fff" title="异常停留类型统计表">
        <!--表格列表信息 -->
        <el-table v-loading="listLoading" :data="listSources" border fit stripe highlight-current-row :header-cell-style="{background:'#eef1f6',color:'#606266'}" @selection-change="selectionChange" @sort-change="sortChange">
          <el-table-column align="center" sortable="custom" prop="Name" :label="this.radioVal" width="155">
            <template slot-scope="scope">
              <router-link tag="a" :to="{path:'/orderDetail',query:{id:scope.row.NameID}}">{{ scope.row.Name }}
              </router-link>
            </template>
          </el-table-column>

          <el-table-column v-for="(item,i) in StopEventArea" :key="i" :prop="item.typeId" :label="item.typeName" align="center">
            <el-table-column :key="item.typeId" :prop="`Numbers`+item.typeName" label="次数" :formatter="NumbersFun" />
            <el-table-column :key="item.typeId" :prop="`TotalDuration`+item.typeName" label="时长(分)" :formatter="TotalDurationFun" />
          </el-table-column>

        </el-table>

        <!--分页部分 -->
        <div class="block" style="height:70px;">
          <el-pagination :current-page="pageinfo.pageindex" :page-size="pageinfo.pagesize" :total="pageinfo.total" :page-sizes="[10,20,30,40]" layout="total, sizes, prev, pager, next" @size-change="sizeChange" @current-change="currentChange" />
        </div>
      </pane>
      


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是刘彦宏吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值