我们都知道,报表有个功能为导出excel,但是有的时候客户需求往往标准的报表达不到,比如导出excel,其中本月修改的数据字段标红,如下图所示。

这就需要我们去写VF来实现此功能。

需求:将数据表记录导出成excel,其中excel内容需要本月修改的数据字段自动标红显示。

表:Goods__c,字段如下:

设计思路:如果导出excel并且需要跟踪每个字段的修改时间进行校验是否标红,则需要有一个表取跟踪这个表.有两种方式进行Track。

1.salesforce中提供了Track History功能,即当表字段小于20个情况下,可以通过设置Track History,那样系统会自动创建相关表的History表,在这个demo中系统会自动创建Goods_History表。详细Track History知识可以参看以下链接:

https://help.salesforce.com/apex/HTFederatedSearchResults#q=Track%20History&t=TopResultTab&sort=relevancy&f:@sflanguage=[en_US]

2.当表的字段超过20个,则通过Track History便无法满足需求了,这种情况我们需要自己创建一个sObject来和需要track的sObject进行关联,如下图所示:

页面显示均使用标准生成的页面,在Goods__c修改情况下,需要设置Trigger自动插入此条Goods__c记录对应的GoodsSign__c记录,如果某个字段有修改,则设置某个字段相对应的Date信息为System.today().

制作步骤:

1.写GoodsTrigger.Trigger代码如下所示:

 trigger GoodsTrigger on Goods__c (before delete, before update) {
if(trigger.isBefore) {
//get the Schema Information of GoodsSign to check whether current user has access to operate the data
Schema.DescribeSObjectResult goodsSignDescribe = GoodsSign__c.sObjectType.getDescribe();
List<GoodsSign__c> goodsSignList = new List<GoodsSign__c>();
//第一个参数为Goods__c的ID,第二个参数为GoodsSign__c
Map<ID,GoodsSign__c> goodsIdToGoodsSignMap = new Map<ID,GoodsSign__c>();
if(trigger.isUpdate) {
Set<ID> goodsIdSet = new Set<ID>();
if(goodsSignDescribe.isCreateable() && goodsSignDescribe.isUpdateable()) {
List<Goods__c> goodsNewList = trigger.new;
List<Goods__c> goodsOldList = trigger.old;
for(Goods__c goods : goodsNewList) {
goodsIdSet.add(goods.Id);
}
String fetchGoodsSignByGoodsId = 'SELECT CreatedById, CreatedDate,' +
' IsDeleted, GoodsBrandDate__c, GoodsCostPriceDate__c,' +
' GoodsDescribeDate__c, GoodsId__c, GoodsNameDate__c,' +
' GoodsPriceDate__c, Name, LastModifiedById, LastModifiedDate,' +
' OwnerId, Id, SystemModstamp FROM GoodsSign__c ' +
' where GoodsId__c in :goodsIdSet';
List<GoodsSign__c> tempGoodsSignList = Database.query(fetchGoodsSignByGoodsId);
for(GoodsSign__c goodsSign : tempGoodsSignList) {
goodsIdToGoodsSignMap.put(goodsSign.GoodsId__c,goodsSign);
}
for(Integer i=0;i<goodsNewList.size();i++) {
Goods__c goodsNew = goodsNewList.get(i);
Goods__c goodsOld = goodsOldList.get(i);
GoodsSign__c goodsSign = new GoodsSign__c();
Id goodsId = goodsNew.Id;
if(goodsIdToGoodsSignMap.get(goodsId) != null) {
goodsSign = goodsIdToGoodsSignMap.get(goodsId);
} if(goodsNew.GoodsName__c != goodsOld.GoodsName__c) {
goodsSign.GoodsNameDate__c = System.today();
}
if(goodsNew.GoodsPrice__c != goodsOld.GoodsPrice__c) {
goodsSign.GoodsPriceDate__c = System.today();
}
if(goodsNew.GoodsCostPrice__c != goodsOld.GoodsCostPrice__c) {
goodsSign.GoodsCostPriceDate__c = System.today();
}
if(goodsNew.GoodsBrand__c != goodsOld.GoodsBrand__c) {
goodsSign.GoodsBrandDate__c = System.today();
}
if(goodsNew.GoodsDescribe__c != goodsOld.GoodsDescribe__c) {
goodsSign.GoodsDescribeDate__c = System.today();
}
if(goodsSign.GoodsId__c == null) {
goodsSign.GoodsId__c = goodsId;
}
goodsSignList.add(goodsSign);
}
if(goodsSignList.size() > 0) {
upsert goodsSignList;
}
} } else if(trigger.isDelete) {
//cascade delete
if(goodsSignDescribe.isDeletable()) {
List<Goods__c> goodsList = trigger.old;
Set<ID> goodsIdSet = new Set<ID>();
for(Goods__c currentGoods : goodsList) {
if(!goodsIdSet.contains(currentGoods.Id)) {
goodsIdSet.add(currentGoods.Id);
}
}
String fetchGoodsSignByGoodsIdSet = 'SELECT CreatedById, CreatedDate,' +
' IsDeleted, GoodsBrandDate__c, GoodsCostPriceDate__c, GoodsDescribeDate__c,' +
' GoodsId__c, GoodsNameDate__c, GoodsPriceDate__c, Name, LastModifiedById,' +
' LastModifiedDate, OwnerId, Id, SystemModstamp FROM GoodsSign__c' +
' where GoodsId__c in :goodsIdSet';
List<GoodsSign__c> goodsSignNeedDeleteList = Database.query(fetchGoodsSignByGoodsIdSet);
delete goodsSignNeedDeleteList;
}
}
}
}

此Trigger有两个功能:

1.当进行修改操作并且Goods__c记录有字段改变时,如果有相对应的GoodsSign__c进行对应,则update此记录,否则新建记录,并记录哪些字段有修改;

2.当进行删除操作时,如果有相对应的GoodsSign__c进行对应,则级联删除。

两者操作均需要当前用户有GoodsSign的操作权限。

2.新建一个类用来记录导出的字段以及导出的字段的颜色。

 public with sharing class GoodsExportObject {
public String goodsName{get;set;}
public String goodsNameColor{get;set;}
public String goodsBrand{get;set;}
public String goodsBrandColor{get;set;}
public String goodsPrice{get;set;}
public String goodsPriceColor{get;set;}
public String goodsCostPrice{get;set;}
public String goodsCostPriceColor{get;set;}
public String goodsDescribe{get;set;}
public String goodsDescribeColor{get;set;}
}

3.新建Controller,此Controller用来获取显示到excel的数据。

 public with sharing class ExportGoodsController {

     List<Goods__c> goodsList{get;set;}
List<GoodsSign__c> goodsSignList{get;set;}
public List<GoodsExportObject> exportGoodsList{get;set;}
Map<Id,GoodsSign__c> goodsSignMap = new Map<Id,GoodsSign__c>();
public ExportGoodsController() {
goodsList = new List<Goods__c>();
goodsSignList = new List<GoodsSign__c>();
exportGoodsList = new List<GoodsExportObject>();
String fetchAllGoods = 'SELECT CreatedById, CreatedDate, IsDeleted,' +
' Name, GoodsBrand__c, GoodsCostPrice__c, GoodsDescribe__c, GoodsName__c,' +
' GoodsPrice__c, LastActivityDate, LastModifiedById, LastModifiedDate,' +
' OwnerId, Id, SystemModstamp FROM Goods__c';
goodsList = Database.query(fetchAllGoods);
String fetchAllGoodsSign = 'SELECT CreatedById, CreatedDate, IsDeleted,' +
' GoodsBrandDate__c, GoodsCostPriceDate__c, GoodsDescribeDate__c,' +
' GoodsId__c, GoodsNameDate__c, GoodsPriceDate__c, Name, LastModifiedById,' +
' LastModifiedDate, OwnerId, Id, SystemModstamp FROM GoodsSign__c';
goodsSignList = Database.query(fetchAllGoodsSign);
for(GoodsSign__c goodsSign : goodsSignList) {
if(!goodsSignMap.containsKey(goodsSign.GoodsId__c)) {
goodsSignMap.put(goodsSign.GoodsId__c,goodsSign);
}
}
} public PageReference exportGoods() {
String bgColor = 'red';
Integer nowMonth = System.today().month();
for(Goods__c currentGoods : goodsList) {
GoodsSign__c goodsSign = goodsSignMap.get(currentGoods.Id);
GoodsExportObject tempGoodsExportObject = new GoodsExportObject();
tempGoodsExportObject.goodsName = currentGoods.GoodsName__c;
tempGoodsExportObject.goodsBrand = currentGoods.GoodsBrand__c;
tempGoodsExportObject.goodsPrice = String.valueOf(currentGoods.GoodsPrice__c);
tempGoodsExportObject.goodsCostPrice = String.valueOf(currentGoods.GoodsCostPrice__c);
tempGoodsExportObject.goodsDescribe = currentGoods.GoodsDescribe__c;
if(goodsSign != null) {
if(goodsSign.GoodsNameDate__c != null && goodsSign.GoodsNameDate__c.month() == nowMonth) {
tempGoodsExportObject.goodsNameColor = bgColor;
}
if(goodsSign.GoodsBrandDate__c != null && goodsSign.GoodsBrandDate__c.month() == nowMonth) {
tempGoodsExportObject.goodsBrandColor = bgColor;
}
if(goodsSign.GoodsPriceDate__c != null && goodsSign.GoodsPriceDate__c.month() == nowMonth) {
tempGoodsExportObject.goodsPriceColor = bgColor;
}
if(goodsSign.GoodsCostPriceDate__c != null && goodsSign.GoodsCostPriceDate__c.month() == nowMonth) {
tempGoodsExportObject.goodsCostPriceColor = bgColor;
}
if(goodsSign.GoodsDescribeDate__c != null && goodsSign.GoodsDescribeDate__c.month() == nowMonth) {
tempGoodsExportObject.goodsDescribeColor = bgColor;
}
}
exportGoodsList.add(tempGoodsExportObject);
} return new PageReference('/apex/ExportGoodsPage');
} }

4.新建显示的VF页面

IsExportPage.page:此VF页面用于显示一个按钮,当点击按钮后,执行Excel生成操作。

 <apex:page controller="ExportGoodsController">
<apex:form >
<apex:commandButton action="{!exportGoods}" value="exportGoods"/>
</apex:form>
</apex:page>

ExportGoodsPage:生成Excel

 <apex:page controller="ExportGoodsController" cache="true" contenttype="application/x-excel# GenExcel.xls" showheader="false">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
</head>
<apex:dataTable value="{!exportGoodsList}" var="exportGoods" border="1">
<apex:column style="background:{!exportGoods.goodsNameColor};">
<apex:facet name="header">Goods Name </apex:facet>
{!exportGoods.goodsName}
</apex:column>
<apex:column style="background:{!exportGoods.goodsBrandColor};">
<apex:facet name="header">Goods Brand</apex:facet>
{!exportGoods.goodsBrand}
</apex:column>
<apex:column style="background:{!exportGoods.goodsPriceColor};">
<apex:facet name="header">Goods Price</apex:facet>
{!exportGoods.goodsPrice}
</apex:column>
<apex:column style="background:{!exportGoods.goodsCostPriceColor};">
<apex:facet name="header">Goods Cost Price</apex:facet>
{!exportGoods.goodsCostPrice}
</apex:column>
<apex:column style="background:{!exportGoods.goodsDescribeColor};">
<apex:facet name="header">Goods Describe</apex:facet>
{!exportGoods.goodsDescribe}
</apex:column>
</apex:dataTable>
</apex:page>

5.配置Button,并显示到列表页面上。

结果样式显示:

点击Goods Reports按钮,跳转到导出 记录的按钮页面

点击exportGoods则可以生成Excel。以下为Excel的生成界面,其中红色为修改的记录字段。

总结:上述demo只是演示当字段Tracking超过20个需要额外创建表的情况处理,当小于20个情况下可以直接通过History的表进行查询,有兴趣的可以自己尝试,生成页面因为使用DataTable,所以对于导出的记录行数有要求,必须不大于1000条,超过则应该会报Error。篇中如果有写的错误的地方欢迎指出,如果有疑问地方欢迎留言,转载请注明出处。

salesforce 零基础学习(二十三)数据记录导出至excel(自定义报表导出)的更多相关文章

  1. salesforce零基础学习(八十二)审批邮件获取最终审批人和审批意见

    项目中,审批操作无处不在.配置审批流时,我们有时候会用到queue,related user设置当前步骤的审批人,审批人可以一个或者多个.当审批人有多个时,邮件中获取当前记录的审批人和审批意见就不能随 ...

  2. salesforce 零基础学习(五十二)Trigger使用篇(二)

    第十七篇的Trigger用法为通过Handler方式实现Trigger的封装,此种好处是一个Handler对应一个sObject,使本该在Trigger中写的代码分到Handler中,代码更加清晰. ...

  3. salesforce零基础学习(一百一十三)Trigger中获取IP地址的过程

    本篇参考: https://developer.salesforce.com/docs/atlas.en-us.228.0.apexcode.meta/apexcode/apex_class_Auth ...

  4. salesforce 零基础学习(六十八)http callout test class写法

    此篇可以参考: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restfu ...

  5. 【转】【Salesforce】salesforce 零基础学习(十七)Trigger用法

    看本篇之前可以相应阅读以下Trigger相关文章: 1.https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigge ...

  6. salesforce零基础学习(一百零五)Change Data Capture

    本篇参考: https://developer.salesforce.com/docs/atlas.en-us.232.0.api_streaming.meta/api_streaming/using ...

  7. salesforce零基础学习(八十)使用autoComplete 输入内容自动联想结果以及去重实现

    项目中,我们有时候会需要实现自动联想功能,比如我们想输入用户或者联系人名称,去联想出系统中有的相关的用户和联系人,当点击以后获取相关的邮箱或者其他信息等等.这种情况下可以使用jquery ui中的au ...

  8. salesforce零基础学习(八十七)Apex 中Picklist类型通过Control 字段值获取Dependent List 值

    注:本篇解决方案内容实现转自:http://mysalesforceescapade.blogspot.com/2015/03/getting-dependent-picklist-values-fr ...

  9. salesforce零基础学习(八十九)使用 input type=file 以及RemoteAction方式上传附件

    在classic环境中,salesforce提供了<apex:inputFile>标签用来实现附件的上传以及内容获取.salesforce 零基础学习(二十四)解析csv格式内容中有类似的 ...

  10. salesforce零基础学习(九十六)Platform Event浅谈

    本篇参考:https://developer.salesforce.com/blogs/2018/07/which-streaming-event-do-i-use.html https://trai ...

随机推荐

  1. Linux系统简介

    1.操作系统包括 系统调用.内核. Linux 也就是系统调用和内核那两层,当然直观的来看,我们使用的操作系统还包含一些在 其上运行的应用程序,比如文本编辑器,浏览器,电子邮件. 2.Linux 本身 ...

  2. Android Sqlite数据库相关——实现将 Sqlite 数据库复制到SD 卡

    确定 sqlite 数据库所在位置(一般在data/data/com.pagename/databases/ 下,其中 com.pagename为当前项目包名) 确定 sqlite 数据库名称,拼接到 ...

  3. IAR之文件路径设置

    1.命令解释 $PROJ_DIR$表示工程所在路径 $TOOLKIT_DIR$表示IAR安装目录所在头文件路径 \..\表示返回上一级目录. 2.头文件路径设置 打开工程文件,找到"opti ...

  4. Centos配置查看

    Reference: [1] http://www.centoscn.com/CentOS/help/2013/0928/1743.html [2] http://www.cnblogs.com/hi ...

  5. js二级导航下拉菜单

    <!DOCTYPE html> <html> <head> <title>导航列表</title> <meta http-equiv= ...

  6. Mac OS环境下配置Myeclipse2015的经验

    反复测试装了多次,现在把成功安装的方法陈列如下: 1. 相关的资源: (1)下载 myeclipse-2015-stable-2.0-offline-installer-macosx.dmg 链接:h ...

  7. hdu 5104 素数打表水题

    http://acm.hdu.edu.cn/showproblem.php?pid=5104 找元组数量,满足p1<=p2<=p3且p1+p2+p3=n且都是素数 不用素数打表都能过,数据 ...

  8. 解决Win7下VC6.0插入ActiveX控件对话框为空的问题

    在Win7环境下,编写MFC应用程序,Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中Gallery文件为空,也就无法 ...

  9. Await, and UI, and deadlocks! Oh my!

    It’s been awesome seeing the level of interest developers have had for the Async CTP and how much us ...

  10. GP调用arctoolbox 以Clip为例

    GP的功能非常强大,也是GIS建模的一个很重要的工具.在Arcengine中,实现Clip功能很多种方法,可以用IBasicGeoprocessor的clip方法,但是GP无疑是最简单的. publi ...