我們都知道,報表有個功能為導出excel,但是有的時候客戶需求往往標准的報表達不到,比如導出excel,其中本月修改的數據字段標紅,如下圖所示。
這就需要我們去寫VF來實現此功能。
需求:將數據表記錄導出成excel,其中excel內容需要本月修改的數據字段自動標紅顯示。
表:Goods__c,字段如下:
設計思路:如果導出excel並且需要跟蹤每個字段的修改時間進行校驗是否標紅,則需要有一個表取跟蹤這個表.有兩種方式進行Track。
1.salesforce中提供了Track History功能,即當表字段小於20個情況下,可以通過設置Track History,那樣系統會自動創建相關表的History表,在這個demo中系統會自動創建Goods_History表。詳細Track History知識可以參看以下鏈接:
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 List<GoodsSign__c> goodsSignList = new List<GoodsSign__c>(); 6 //第一個參數為Goods__c的ID,第二個參數為GoodsSign__c 7 Map<ID,GoodsSign__c> goodsIdToGoodsSignMap = new Map<ID,GoodsSign__c>(); 8 if(trigger.isUpdate) { 9 Set<ID> goodsIdSet = new Set<ID>(); 10 if(goodsSignDescribe.isCreateable() && goodsSignDescribe.isUpdateable()) { 11 List<Goods__c> goodsNewList = trigger.new; 12 List<Goods__c> 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<GoodsSign__c> tempGoodsSignList = Database.query(fetchGoodsSignByGoodsId); 23 for(GoodsSign__c goodsSign : tempGoodsSignList) { 24 goodsIdToGoodsSignMap.put(goodsSign.GoodsId__c,goodsSign); 25 } 26 for(Integer i=0;i<goodsNewList.size();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<Goods__c> goodsList = trigger.old; 64 Set<ID> goodsIdSet = new Set<ID>(); 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<GoodsSign__c> 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 List<Goods__c> goodsList{get;set;} 4 List<GoodsSign__c> goodsSignList{get;set;} 5 public List<GoodsExportObject> exportGoodsList{get;set;} 6 Map<Id,GoodsSign__c> goodsSignMap = new Map<Id,GoodsSign__c>(); 7 public ExportGoodsController() { 8 goodsList = new List<Goods__c>(); 9 goodsSignList = new List<GoodsSign__c>(); 10 exportGoodsList = new List<GoodsExportObject>(); 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 Brand</apex:facet> 12 {!exportGoods.goodsBrand} 13 </apex:column> 14 <apex:column style="background:{!exportGoods.goodsPriceColor};"> 15 <apex:facet name="header">Goods Price</apex:facet> 16 {!exportGoods.goodsPrice} 17 </apex:column> 18 <apex:column style="background:{!exportGoods.goodsCostPriceColor};"> 19 <apex:facet name="header">Goods Cost Price</apex:facet> 20 {!exportGoods.goodsCostPrice} 21 </apex:column> 22 <apex:column style="background:{!exportGoods.goodsDescribeColor};"> 23 <apex:facet name="header">Goods Describe</apex: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。篇中如果有寫的錯誤的地方歡迎指出,如果有疑問地方歡迎留言,轉載請注明出處。