欢迎光临
我们一直在努力

金蝶云星空开发~第四篇:报表篇——账表开发与数据分析

前言:让数据说话

前三篇我们完成了单据的建模和插件开发,业务数据已经能够正常录入和流转。但企业的管理层和业务人员真正关心的是数据分析和决策支持——本月报价了多少?哪些物料被询价最多?报价转化率是多少?这些问题的答案,都需要通过报表来呈现。

金蝶云星空提供了丰富的报表开发体系,从最简单的SQL账表到复杂的数据分析看板,满足不同层级的报表需求。本篇的目标是:让你掌握三种主流报表的开发方法——SQL账表、简单账表、万能报表,并理解各自的适用场景和性能优化策略。全程以“销售报价分析报表”为实战案例,从最基础的SQL查询开始,逐步演进到可交互的综合看板。


第1章:账表开发体系概述

1.1 三种账表类型对比

金蝶云星空支持三种账表开发方式,各有优劣:

报表类型开发方式适用场景难度性能
SQL账表 直接编写SQL语句 数据来源单一、逻辑清晰、对性能要求高 ⭐⭐ ⭐⭐⭐⭐⭐
简单账表 BOS IDE可视设计+插件扩展 需要参数过滤、列排序、导出等交互 ⭐⭐⭐ ⭐⭐⭐⭐
万能报表 配置化拖拽设计 业务人员自助分析、灵活字段组合 ⭐⭐⭐

选型建议:

  • 如果报表逻辑固定、数据量大、对响应速度要求极高 → 选择SQL账表
  • 如果报表需要交互式过滤、排序、需要与插件配合做复杂格式化 → 选择简单账表
  • 如果是业务人员临时分析、字段组合多变 → 选择万能报表

1.2 账表插件的服务器端继承类

无论是SQL账表还是简单账表,都支持通过插件扩展报表行为。常用基类:

基类用途关键方法
SysReportBase SQL账表服务端插件基类 Initialize、BuildSql
SimpleReportBase 简单账表服务端插件基类 Initialize、BuildQuerySql
ReportListPlugIn 账表列表插件基类(客户端) 同列表插件,用于格式化显示

第2章:SQL账表开发

SQL账表是最直接的报表开发方式——你写什么SQL,系统就展示什么数据。适合逻辑明确、对性能有极致要求的报表。

2.1 编写SQL查询语句与参数化

实战场景:开发一张“销售报价分析报表”,展示各客户的报价数量、金额、转化率。

步骤一:编写SQL查询

— 销售报价分析报表 – 核心SQL
SELECT
C.FName AS 客户名称,
COUNT(DISTINCT Q.FBillNo) AS 报价单数,
SUM(EF.FAmount) AS 报价总金额,
SUM(EF.FTaxAmount) AS 报价含税总金额,
AVG(EF.FQty) AS 平均数量,
— 转化率计算:已确认的报价单数 / 总报价单数
CAST(SUM(CASE WHEN Q.FQuoteStatus = '2' THEN 1 ELSE 0 END) AS DECIMAL(10,2))
/ NULLIF(COUNT(DISTINCT Q.FBillNo), 0) * 100 AS 转化率,
MIN(Q.FDate) AS 最早报价日期,
MAX(Q.FDate) AS 最近报价日期
FROM T_DEM_SaleQuote Q
INNER JOIN T_BD_Customer C ON Q.FCustomerId = C.FID
INNER JOIN T_DEM_SaleQuoteEntry EF ON Q.FID = EF.FID
WHERE Q.FDate BETWEEN @BeginDate AND @EndDate
AND Q.FQuoteStatus IN ('1', '2', '3') — 排除草稿
GROUP BY C.FName
ORDER BY 报价总金额 DESC

关键设计要点:

  • 使用参数@BeginDate和@EndDate支持日期范围筛选
  • 使用NULLIF避免除零错误
  • 使用CAST控制小数位数
  • 状态过滤排除了"草稿"状态的报价单,让分析更有意义

步骤二:在BOS IDE中创建SQL账表

  • 打开BOS IDE → 新建 → 选择"SQL账表"
  • 输入名称:“销售报价分析报表”,编码:DEM_SaleQuoteAnalysisReport
  • 在"SQL语句"编辑框中粘贴上述SQL
  • 点击"解析SQL",系统自动识别结果集字段
  • 2.2 账表数据源配置

    配置参数(过滤条件):

    SQL账表支持在界面上设置查询参数,参数会自动替换SQL中的变量。

  • 在BOS IDE中打开报表设计器 → 切换到"参数"页签
  • 点击"新增",配置日期参数:
  • 参数名称标识类型默认值
    开始日期 BeginDate 日期 本月1日
    结束日期 EndDate 日期 今天
  • 在SQL语句中,用@BeginDate和@EndDate引用参数
  • 配置字段显示:

    在"字段"页签中,可以配置每个列的显示格式:

    • 字段名称:自定义列标题(如"客户名称")
    • 字段宽度:控制列宽
    • 对齐方式:左对齐/居中/右对齐(数字建议右对齐)
    • 格式化字符串:如数字保留2位小数#,##0.00

    2.3 SQL增强报表支持的样式

    SQL账表支持通过简单配置实现高级效果:

    分组汇总:
    在报表属性中设置"分组字段",系统会自动按该字段分组并显示小计。

    — 增加组织维度分组
    SELECT
    O.FName AS 组织,
    C.FName AS 客户名称,
    ...
    FROM T_DEM_SaleQuote Q
    INNER JOIN T_ORG_Organizations O ON Q.FOrgId = O.FID
    ...
    GROUP BY O.FName, C.FName

    在BOS IDE中设置"分组字段"为组织,报表会自动按组织分组展示。

    交叉表(行转列):

    如果需要按月份横向展示数据,SQL中可做行列转换:

    — 按月份展开报价金额
    SELECT
    C.FName AS 客户名称,
    SUM(CASE WHEN MONTH(Q.FDate) = 1 THEN EF.FAmount ELSE 0 END) AS 一月,
    SUM(CASE WHEN MONTH(Q.FDate) = 2 THEN EF.FAmount ELSE 0 END) AS 二月,
    — … 以此类推到十二月
    SUM(EF.FAmount) AS 合计
    FROM ...
    GROUP BY C.FName

    💡 性能提示:SQL账表的性能完全取决于SQL语句的质量。复杂查询务必在SQL Server Management Studio中先用真实数据量测试执行计划,确认索引命中情况。


    第3章:简单账表与插件开发

    简单账表相比于SQL账表,提供了更丰富的交互能力:列排序、列过滤、数据导出、自定义按钮等。同时通过插件可以动态干预查询逻辑和显示格式。

    3.1 简单账表的设计器使用

    创建步骤:

  • BOS IDE → 新建 → 选择"简单账表"
  • 输入名称:“销售报价明细账表”,编码:DEM_SaleQuoteDetailReport
  • 设计界面布局(与单据设计类似):
    • 顶部:查询条件区域(日期范围、客户、报价状态等)
    • 底部:表格区域(展示数据)
  • 配置数据源:

    简单账表的数据源绑定一个查询对象(Query Object),而不是直接写SQL:

  • 在"数据源"属性中,选择或新建一个查询对象
  • 查询对象中关联"销售报价单"主表和明细表
  • 选择需要展示的字段:单据编号、日期、客户、物料、数量、单价、金额等
  • 这种方式的好处是:系统自动处理分页、排序、过滤,不需要手动编写SQL。

    3.2 账表插件:数据预处理与格式化

    简单账表的插件扩展主要有两个场景:

  • 动态修改查询条件:根据当前用户上下文自动添加过滤
  • 数据格式化:在数据展示前做额外处理(如计算衍生字段)
  • 代码示例:简单账表插件

    using Kingdee.BOS.Core.Report.PlugIn;
    using Kingdee.BOS.Core.Report.PlugIn.Args;
    using Kingdee.BOS.Core.List.PlugIn.Args;

    namespace DEM.SCM.PlugIn
    {
    public class SaleQuoteDetailReportPlugin : SimpleReportBase
    {
    /// <summary>
    /// 初始化报表:设置默认查询条件
    /// </summary>
    public override void Initialize(InitializeArgs e)
    {
    base.Initialize(e);

    // 默认日期范围:本月
    DateTime firstDayOfMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
    DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(1);

    // 设置查询参数默认值
    this.ReportParameter.SetParamValue("FBeginDate", firstDayOfMonth);
    this.ReportParameter.SetParamValue("FEndDate", lastDayOfMonth);

    // 默认只显示"已确认"和"已提交"的报价单
    this.ReportParameter.SetParamValue("FQuoteStatus", new object[] { "1", "2" });
    }

    /// <summary>
    /// 构建查询SQL之前:动态添加过滤条件
    /// </summary>
    public override void BeforeBuildQuerySql(BeforeBuildQuerySqlArgs e)
    {
    base.BeforeBuildQuerySql(e);

    // 场景1:普通用户只能看自己部门的报价单
    if (!IsAdministrator())
    {
    string currentDept = this.Context.User.DeptId?.ToString() ?? "";
    e.SqlBuilder.AppendCondition($"Q.FDeptId = '{currentDept}'");
    }

    // 场景2:如果选择了客户,自动加过滤
    object customerParam = this.ReportParameter.GetParamValue("FCustomerId");
    if (customerParam != null && !string.IsNullOrEmpty(customerParam.ToString()))
    {
    e.SqlBuilder.AppendCondition($"Q.FCustomerId = {customerParam}");
    }
    }

    /// <summary>
    /// 数据绑定后:格式化额外字段
    /// </summary>
    public override void AfterBindRowData(AfterBindRowDataArgs e)
    {
    base.AfterBindRowData(e);

    // 计算"是否超期"标记
    DateTime? quoteDate = e.RowData["FDate"] as DateTime?;
    int? validDays = e.RowData["FValidDays"] as int?;

    if (quoteDate.HasValue && validDays.HasValue)
    {
    DateTime expireDate = quoteDate.Value.AddDays(validDays.Value);
    bool isOverdue = DateTime.Now.Date > expireDate.Date;

    // 添加一个计算列(如果数据源中不存在)
    e.RowData["FIsOverdue"] = isOverdue ? "是" : "否";
    e.RowData["FExpireDate"] = expireDate.ToString("yyyy-MM-dd");
    }
    }

    /// <summary>
    /// 行格式化:超期行标红
    /// </summary>
    public override void OnFormatRowCondition(FormatRowConditionArgs e)
    {
    base.OnFormatRowCondition(e);

    string isOverdue = e.RowData["FIsOverdue"]?.ToString() ?? "";
    if (isOverdue == "是")
    {
    e.RowStyle.BackColor = System.Drawing.Color.LightPink;
    }
    }

    private bool IsAdministrator()
    {
    // 判断当前用户是否管理员
    return this.Context.User.IsAdministrator;
    }
    }
    }

    3.3 账表扩展方法与常见问题

    扩展方法一:添加自定义按钮

    在简单账表工具栏中添加自定义操作按钮(与单据插件类似):

    public override void BarItemClick(BarItemClickEventArgs e)
    {
    base.BarItemClick(e);

    if (e.BarItemKey == "btnExportExcel")
    {
    // 触发自定义导出逻辑
    ExportToExcelWithFormat();
    }
    }

    private void ExportToExcelWithFormat()
    {
    // 获取当前报表数据
    var data = this.ReportData;

    // 自定义Excel导出(可使用NPOI等库)
    // 注意:大数据量时考虑异步处理
    this.View.ShowMessage("Excel导出完成!");
    }

    扩展方法二:报表钻取(点击跳转)

    双击报表行,跳转到对应的单据详情页:

    public override void EntityRowDoubleClick(EntityRowDoubleClickEventArgs e)
    {
    base.EntityRowDoubleClick(e);

    if (e.EntityKey == "FReportTable")
    {
    int rowIndex = e.RowIndex;
    string billNo = this.ReportData[rowIndex]["FBillNo"]?.ToString() ?? "";

    if (!string.IsNullOrEmpty(billNo))
    {
    // 打开销售报价单详情
    DynamicFormShowParameter showParam = new DynamicFormShowParameter();
    showParam.FormId = "DEM_SaleQuote";
    showParam.ParentPageId = this.View.PageId;
    showParam.PKey = "FBillNo";
    showParam.PKeyValue = billNo;

    this.View.ShowForm(showParam);
    }
    }
    }


    第4章:万能报表与轻分析

    万能报表和轻分析是金蝶云星空面向业务人员的数据分析工具,配置化程度极高,开发人员了解后可以更好地支持业务团队。

    4.1 万能报表配置与使用

    万能报表的定位是:让业务人员通过拖拽配置,快速生成数据分析报表。

    配置流程:

  • 系统路径:主控台 → 供应链 → 报表分析 → 万能报表
  • 点击"新建报表" → 选择数据源(可选择单据或基础资料)
  • 维度配置:拖拽字段到行或列(如"客户"行、"物料"列)
  • 度量配置:选择统计方式(求和、计数、平均值等),如"报价金额求和"
  • 过滤条件:设置数据范围
  • 保存并发布报表
  • 适用场景:

    • 业务部门临时数据分析需求
    • 管理层综合看板
    • 多维交叉分析

    开发人员职责:

    • 确保业务对象发布了正确的字段和关联关系
    • 对性能问题做优化(大数据量时万能报表可能较慢)

    4.2 轻分析平台介绍与数据建模

    轻分析(Light Analysis)是金蝶云星空的高级BI平台,支持:

    • 多数据源整合(金蝶内部+外部数据)
    • 可视化拖拽建模
    • 丰富的图表类型(柱状图、折线图、饼图、地图等)
    • 仪表板组合展示

    轻分析开发流程:

  • 数据建模:在轻分析平台中建立数据模型,关联多张表
  • 创建数据集:选择维度和度量,构建分析数据集
  • 设计看板:将数据集以图表形式展示在仪表板中
  • 发布分享:将看板发布给目标用户
  • 4.3 轻分析性能调优指南

    轻分析在大数据量场景下容易遇到性能瓶颈,以下是调优要点:

    问题解决方案
    数据加载慢 减少数据集行数(增加过滤条件);使用汇总表而非明细表
    图表渲染卡顿 减少图表数据点数量(如只显示Top 20)
    多维分析响应慢 预创建分析立方体(Cube),定时刷新
    跨数据源关联慢 在数据建模时进行预关联,避免运行时Join

    建议:对于超过10万行的数据,轻分析推荐使用汇总表(Aggregation Table) 方式——在数据库中预先按维度汇总数据,轻分析直接读取汇总结果而非原始明细。


    本章实战总结:销售报价报表体系

    至此,我们为"销售报价单"构建了完整的报表体系:

    • ✅ SQL账表(销售报价分析报表):

      • 客户维度汇总:报价单数、总金额、转化率
      • 支持日期范围参数
      • 按报价总金额降序排列
      • 使用了分组汇总和行列转换
    • ✅ 简单账表(销售报价明细账表):

      • 展示了所有报价单的明细数据
      • 查询条件:日期范围、客户、状态
      • 插件实现了:部门级数据隔离、超期标记计算、行标红提示
      • 双击跳转到单据详情
    • ✅ 万能报表/轻分析:

      • 为业务人员配置了多维分析看板
      • 按物料、客户、月份多维度分析

    报表开发最佳实践清单

    最佳实践说明
    优先考虑SQL账表 逻辑明确、数据量大的报表优先使用SQL账表
    避免全表扫描 所有查询必须带上索引字段的过滤条件
    合理使用分页 列表型报表默认分页,每页50-100行
    避免复杂子查询 复杂逻辑用临时表或CTE(公用表表达式)分解
    缓存常用数据 基础资料名称等可通过缓存减少重复查询
    设置查询超时 报表查询超时建议设置为180秒以上
    考虑导出性能 大数据量导出建议异步处理,通过消息通知下载

    常见问题速查

    问题解决方案
    SQL账表查询超时 检查SQL执行计划,添加索引,或拆分查询
    简单账表数据量太大 增加查询条件的必填项,减少默认数据范围
    报表参数不生效 检查SQL中参数引用格式是否正确(@参数名)
    报表显示乱码 检查数据库字符集设置,使用Unicode类型字段
    钻取跳转无效 确认目标单据的FormId和主键字段是否正确

    下一篇预告

    第五篇将进入工作流与业务流开发——教你如何为"销售报价单"配置审批流程,以及如何通过单据转换(BOTP)实现报价单转销售订单的业务流。这是金蝶云星空实现业务流程自动化的核心能力。


    练习题:

  • 为"销售报价分析报表"增加一个"物料维度"的SQL账表版本,展示每个物料的报价次数、平均单价、报价总数量
  • 在简单账表中增加一个"导出汇总Excel"按钮,导出时自动按客户汇总(而不是导出明细)
  • 在轻分析中创建一个仪表板,包含:报价趋势折线图(按月)、客户报价排行柱状图、报价状态分布饼图
  • 赞(0)
    未经允许不得转载:171主机测评 » 金蝶云星空开发~第四篇:报表篇——账表开发与数据分析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址