我们都知道,报表有个功能为导出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代码如下所示:
1 trigger GoodsTrigger on Goods__c (before delete, before update) { 2 if(trigger.isBefore) { 3 //get the Schema Information of GoodsSign to check whether current user has access to operate the data 4 Schema.DescribeSObjectResult goodsSignDescribe = GoodsSign__c.sObjectType.getDescribe(); 5 ListgoodsSignList = new List (); 6 //第一个参数为Goods__c的ID,第二个参数为GoodsSign__c 7 Map goodsIdToGoodsSignMap = new Map (); 8 if(trigger.isUpdate) { 9 Set goodsIdSet = new Set (); 10 if(goodsSignDescribe.isCreateable() && goodsSignDescribe.isUpdateable()) { 11 List goodsNewList = trigger.new; 12 List goodsOldList = trigger.old; 13 for(Goods__c goods : goodsNewList) { 14 goodsIdSet.add(goods.Id); 15 } 16 String fetchGoodsSignByGoodsId = 'SELECT CreatedById, CreatedDate,' + 17 ' IsDeleted, GoodsBrandDate__c, GoodsCostPriceDate__c,' + 18 ' GoodsDescribeDate__c, GoodsId__c, GoodsNameDate__c,' + 19 ' GoodsPriceDate__c, Name, LastModifiedById, LastModifiedDate,' + 20 ' OwnerId, Id, SystemModstamp FROM GoodsSign__c ' + 21 ' where GoodsId__c in :goodsIdSet'; 22 List tempGoodsSignList = Database.query(fetchGoodsSignByGoodsId); 23 for(GoodsSign__c goodsSign : tempGoodsSignList) { 24 goodsIdToGoodsSignMap.put(goodsSign.GoodsId__c,goodsSign); 25 } 26 for(Integer i=0;i ) { 27 Goods__c goodsNew = goodsNewList.get(i); 28 Goods__c goodsOld = goodsOldList.get(i); 29 GoodsSign__c goodsSign = new GoodsSign__c(); 30 Id goodsId = goodsNew.Id; 31 if(goodsIdToGoodsSignMap.get(goodsId) != null) { 32 goodsSign = goodsIdToGoodsSignMap.get(goodsId); 33 } 34 35 if(goodsNew.GoodsName__c != goodsOld.GoodsName__c) { 36 goodsSign.GoodsNameDate__c = System.today(); 37 } 38 if(goodsNew.GoodsPrice__c != goodsOld.GoodsPrice__c) { 39 goodsSign.GoodsPriceDate__c = System.today(); 40 } 41 if(goodsNew.GoodsCostPrice__c != goodsOld.GoodsCostPrice__c) { 42 goodsSign.GoodsCostPriceDate__c = System.today(); 43 } 44 if(goodsNew.GoodsBrand__c != goodsOld.GoodsBrand__c) { 45 goodsSign.GoodsBrandDate__c = System.today(); 46 } 47 if(goodsNew.GoodsDescribe__c != goodsOld.GoodsDescribe__c) { 48 goodsSign.GoodsDescribeDate__c = System.today(); 49 } 50 if(goodsSign.GoodsId__c == null) { 51 goodsSign.GoodsId__c = goodsId; 52 } 53 goodsSignList.add(goodsSign); 54 } 55 if(goodsSignList.size() > 0) { 56 upsert goodsSignList; 57 } 58 } 59 60 } else if(trigger.isDelete) { 61 //cascade delete 62 if(goodsSignDescribe.isDeletable()) { 63 List goodsList = trigger.old; 64 Set goodsIdSet = new Set (); 65 for(Goods__c currentGoods : goodsList) { 66 if(!goodsIdSet.contains(currentGoods.Id)) { 67 goodsIdSet.add(currentGoods.Id); 68 } 69 } 70 String fetchGoodsSignByGoodsIdSet = 'SELECT CreatedById, CreatedDate,' + 71 ' IsDeleted, GoodsBrandDate__c, GoodsCostPriceDate__c, GoodsDescribeDate__c,' + 72 ' GoodsId__c, GoodsNameDate__c, GoodsPriceDate__c, Name, LastModifiedById,' + 73 ' LastModifiedDate, OwnerId, Id, SystemModstamp FROM GoodsSign__c' + 74 ' where GoodsId__c in :goodsIdSet'; 75 List goodsSignNeedDeleteList = Database.query(fetchGoodsSignByGoodsIdSet); 76 delete goodsSignNeedDeleteList; 77 } 78 } 79 } 80 }
此Trigger有两个功能:
1.当进行修改操作并且Goods__c记录有字段改变时,如果有相对应的GoodsSign__c进行对应,则update此记录,否则新建记录,并记录哪些字段有修改;
2.当进行删除操作时,如果有相对应的GoodsSign__c进行对应,则级联删除。
两者操作均需要当前用户有GoodsSign的操作权限。
2.新建一个类用来记录导出的字段以及导出的字段的颜色。
1 public with sharing class GoodsExportObject { 2 public String goodsName{get;set;} 3 public String goodsNameColor{get;set;} 4 public String goodsBrand{get;set;} 5 public String goodsBrandColor{get;set;} 6 public String goodsPrice{get;set;} 7 public String goodsPriceColor{get;set;} 8 public String goodsCostPrice{get;set;} 9 public String goodsCostPriceColor{get;set;} 10 public String goodsDescribe{get;set;} 11 public String goodsDescribeColor{get;set;} 12 }
3.新建Controller,此Controller用来获取显示到excel的数据。
1 public with sharing class ExportGoodsController { 2 3 ListgoodsList{get;set;} 4 List goodsSignList{get;set;} 5 public List exportGoodsList{get;set;} 6 Map goodsSignMap = new Map (); 7 public ExportGoodsController() { 8 goodsList = new List (); 9 goodsSignList = new List (); 10 exportGoodsList = new List (); 11 String fetchAllGoods = 'SELECT CreatedById, CreatedDate, IsDeleted,' + 12 ' Name, GoodsBrand__c, GoodsCostPrice__c, GoodsDescribe__c, GoodsName__c,' + 13 ' GoodsPrice__c, LastActivityDate, LastModifiedById, LastModifiedDate,' + 14 ' OwnerId, Id, SystemModstamp FROM Goods__c'; 15 goodsList = Database.query(fetchAllGoods); 16 String fetchAllGoodsSign = 'SELECT CreatedById, CreatedDate, IsDeleted,' + 17 ' GoodsBrandDate__c, GoodsCostPriceDate__c, GoodsDescribeDate__c,' + 18 ' GoodsId__c, GoodsNameDate__c, GoodsPriceDate__c, Name, LastModifiedById,' + 19 ' LastModifiedDate, OwnerId, Id, SystemModstamp FROM GoodsSign__c'; 20 goodsSignList = Database.query(fetchAllGoodsSign); 21 for(GoodsSign__c goodsSign : goodsSignList) { 22 if(!goodsSignMap.containsKey(goodsSign.GoodsId__c)) { 23 goodsSignMap.put(goodsSign.GoodsId__c,goodsSign); 24 } 25 } 26 } 27 28 29 public PageReference exportGoods() { 30 String bgColor = 'red'; 31 Integer nowMonth = System.today().month(); 32 for(Goods__c currentGoods : goodsList) { 33 GoodsSign__c goodsSign = goodsSignMap.get(currentGoods.Id); 34 GoodsExportObject tempGoodsExportObject = new GoodsExportObject(); 35 tempGoodsExportObject.goodsName = currentGoods.GoodsName__c; 36 tempGoodsExportObject.goodsBrand = currentGoods.GoodsBrand__c; 37 tempGoodsExportObject.goodsPrice = String.valueOf(currentGoods.GoodsPrice__c); 38 tempGoodsExportObject.goodsCostPrice = String.valueOf(currentGoods.GoodsCostPrice__c); 39 tempGoodsExportObject.goodsDescribe = currentGoods.GoodsDescribe__c; 40 if(goodsSign != null) { 41 if(goodsSign.GoodsNameDate__c != null && goodsSign.GoodsNameDate__c.month() == nowMonth) { 42 tempGoodsExportObject.goodsNameColor = bgColor; 43 } 44 if(goodsSign.GoodsBrandDate__c != null && goodsSign.GoodsBrandDate__c.month() == nowMonth) { 45 tempGoodsExportObject.goodsBrandColor = bgColor; 46 } 47 if(goodsSign.GoodsPriceDate__c != null && goodsSign.GoodsPriceDate__c.month() == nowMonth) { 48 tempGoodsExportObject.goodsPriceColor = bgColor; 49 } 50 if(goodsSign.GoodsCostPriceDate__c != null && goodsSign.GoodsCostPriceDate__c.month() == nowMonth) { 51 tempGoodsExportObject.goodsCostPriceColor = bgColor; 52 } 53 if(goodsSign.GoodsDescribeDate__c != null && goodsSign.GoodsDescribeDate__c.month() == nowMonth) { 54 tempGoodsExportObject.goodsDescribeColor = bgColor; 55 } 56 } 57 exportGoodsList.add(tempGoodsExportObject); 58 } 59 60 return new PageReference('/apex/ExportGoodsPage'); 61 } 62 63 64 65 66 }
4.新建显示的VF页面
IsExportPage.page:此VF页面用于显示一个按钮,当点击按钮后,执行Excel生成操作。
1 <apex:page controller="ExportGoodsController"> 2 <apex:form > 3 <apex:commandButton action="{!exportGoods}" value="exportGoods"/> 4 apex:form> 5 apex:page>
ExportGoodsPage:生成Excel
1 <apex:page controller="ExportGoodsController" cache="true" contenttype="application/x-excel# GenExcel.xls" showheader="false"> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> 4 head> 5 <apex:dataTable value="{!exportGoodsList}" var="exportGoods" border="1"> 6 <apex:column style="background:{!exportGoods.goodsNameColor};"> 7 <apex:facet name="header">Goods Name apex:facet> 8 {!exportGoods.goodsName} 9 apex:column> 10 <apex:column style="background:{!exportGoods.goodsBrandColor};"> 11 <apex:facet name="header">Goods Brandapex:facet> 12 {!exportGoods.goodsBrand} 13 apex:column> 14 <apex:column style="background:{!exportGoods.goodsPriceColor};"> 15 <apex:facet name="header">Goods Priceapex:facet> 16 {!exportGoods.goodsPrice} 17 apex:column> 18 <apex:column style="background:{!exportGoods.goodsCostPriceColor};"> 19 <apex:facet name="header">Goods Cost Priceapex:facet> 20 {!exportGoods.goodsCostPrice} 21 apex:column> 22 <apex:column style="background:{!exportGoods.goodsDescribeColor};"> 23 <apex:facet name="header">Goods Describeapex:facet> 24 {!exportGoods.goodsDescribe} 25 apex:column> 26 apex:dataTable> 27 apex:page>
5.配置Button,并显示到列表页面上。
结果样式显示:
点击Goods Reports按钮,跳转到导出 记录的按钮页面
点击exportGoods则可以生成Excel。以下为Excel的生成界面,其中红色为修改的记录字段。
总结:上述demo只是演示当字段Tracking超过20个需要额外创建表的情况处理,当小于20个情况下可以直接通过History的表进行查询,有兴趣的可以自己尝试,生成页面因为使用DataTable,所以对于导出的记录行数有要求,必须不大于1000条,超过则应该会报Error。篇中如果有写的错误的地方欢迎指出,如果有疑问地方欢迎留言,转载请注明出处。