無需程式碼的解決方案:顯示清單項目最後一次更改的天數

作者:賈斯汀·喬伊斯,LANtek

注意

這篇文章是 SharePoint 最終用戶 Get the Point 部落格四年來文章合集的一部分。

概述:自訂老化報告無程式碼

SharePoint 網站常被要求的功能性之一是針對任務或清單項目的老化報告。 換句話說,這個清單項目上次修改已經過了多少天/幾個月?

表面上看,這似乎是一個非常簡單的請求。 畢竟,我們有物品創建和修改的日期,也能透過事件接收器儲存特定變更的自訂日期。 我們有計算欄位,可以加入類似 Excel 的公式來配合我們的資訊。 這看起來是一個相當直接的提議。 我們會選擇一個日期欄位,建立一個計算欄位,然後用類似 [DateField] – [Today] 的公式來計算。 啊,不過別那麼快! 任何嘗試過這個「簡單」任務的人都知道,像 [Today] 這樣的計算欄位會造成問題。 試著在計算欄位的公式框中插入 [Today] 會跳出類似這樣的錯誤訊息:

錯誤訊息

為什麼會這樣? 這跟計算欄位的計算方式有關。

讓我們以一個簡單的公式作為例子:

= 若 ( [Column1]<=[Column2], “OK”、“Not OK”)

這只是表示如果第 1 欄小於或等於第 2 欄,則顯示 OK,否則顯示 Not OK。 這是一個相當典型的計算欄位基本公式,並對包含這些欄位的清單項目做出一個基本假設:Column1 和 Column2 的值若沒有清單項目的更新事件,永遠無法改變。

沒錯,計算欄位只有在清單更新 (或) 建立時才會重新計算,因為它們假設你計算的資訊包含在項目本身。 當你嘗試使用會獨立於項目欄位變動的東西(例如今天的日期)時,這會造成問題。

我當時沒參加他們決定計算欄位會用這種方式運作的會議,但如果要我猜,我會認為它們是為了效能才這樣運作。 想像你有一份包含數千項項目的清單,每個項目都包含一欄需要「即時」更新的計算欄位。 這代表某種機制,例如計時器工作,必須定期遍歷包含該計算欄位的項目並更新其值。 這在效能上可能非常吃力,因為大規模部署時,這份工作可能會不斷執行並改變各種功能。 這只是我的猜測,但仔細想想其實蠻合理的。

市面上有一些類似的解決方案建議,方法是先建立一個名為 Today 的欄位,然後加入公式,再刪除,騙 SharePoint 接受 Today 值。 這些都很好,但請記得我之前說過的,計算欄位何時更新。 這個數值只有在項目更新時才會改變,這表示你的數值很快就會錯誤,尤其是在日計算時。

我看過有人用巧妙的 JavaScript 來寫入頁面的數值。 這方法也可行,但我幾乎完全反對用客戶端腳本,只要能避免。

實施:

那該怎麼辦? 對於像 Today 這類所謂的「揮發性」函數,計算欄位是不可能的。 我們也可以開發一些自訂程式碼來處理這件事,例如計算欄位、計時器工作,或排程流程,讓每一項需要計算的項目都能更新。 不過這又回到我上一段提到的效能問題,而且這個解決方案很脆弱,且非常依賴該網站/列表/專欄。 除了這兩個問題,你還得去找像我這樣懂程式的宅男,說服他幫你開發這個解決方案。 但有更簡單的方法!

如果你擁有建立欄位和編輯網站頁面的權利,且對 XSLT 和建立檢視有一定了解,你可以製作一個 XSL 範本,包含在清單檢視中,並且每次頁面被請求時都能忠實計算你的價值。 這個情境消除了我們對效能的擔憂,也不需要透過解決方案開發和部署自訂程式碼。

太棒了。 那我們該怎麼做呢?

  1. 建立或選擇將作為來源的欄位。 一定是日期類型。
  2. 建立我們的欄位,作為計算值的佔位符。
  3. 將這兩個欄位都加入內容類型,並將該內容類型加入清單。
  4. 建立一個包含來源欄和佔位欄的清單檢視。
  5. 將 XSL 範本上傳到 Styles Library。
  6. 透過介面設定「XSL 連結」屬性,為清單檢視的網頁部分設置。
  7. 成功!

讓我們來探討一個範例使用案例,並一步步走進實作過程。 我們的客戶想要查看他們的主清單,以告知某項清單狀態已停留多久。 此清單包含由項目類型衍生並加入清單的自訂網站內容類型。 當時已經有一個事件接收器,會記錄每次該狀態欄位被更改的時間,並將該日期存到一個名為「Date Status Changed」的欄位。 這些布線其實不是必須的,可以用任何日期欄位來做, (碰巧這是我們的實作,但歡迎大家) 嘗試。 你最基本需要的是來源日期欄位和佔位欄位來存放計算, (下一段會) 加入清單,不過我建議你使用網站欄位和網站內容類型,以備你想在網站其他地方重複使用此解決方案。

所以我們有來源日期,可以用來計算今天的日期。 現在我們可以建立自訂網站欄位,作為計算值的容器。 這次我選擇使用計算欄位,因為它無法在新項目表單中更改或編輯項目,但可以選擇顯示在檢視中,因為我們不希望使用者在欄位輸入任意值。 可能會讓人困惑,為什麼它沒有顯示在檢視中等等。

現在我們有了網站欄位,就可以把它加入我們清單中會用到的內容類型中。 接著,我們需要建立檢視,之後會用 XSLT 自訂。 務必建立一個標準檢視,包含來源日期欄位和新計算欄位,作為計算值的佔位符。

我們現在已經具備支持自訂老化報告所需的一切。 剩下的就是建立我們的 XSL 範本,上傳到網站的樣式庫,並連結到我們的清單檢視。 我們將使用的 XSL 模板會包含一些一般 SharePoint 產生的標記來產生視圖,以及我們自己的自訂標記,用來覆蓋部分內容並計算我們想要的值。

為了給出有功勞的地方,MSDN 論壇上「swirch」慷慨提供了我用於此解決方案實際計算的 XSL 範本:
http://social.msdn.microsoft.com/Forums/en-US/sharepointcustomization/thread/aeda905b-9bc6-40c4-bd22-21306c5cb0d2/

我整理好的XSL樣式表 (aging.zip) 請下載於此:
https://OneDrive.live.com/?cid=c262e8e2d59a86d9&permissionsChanged=1&id=C262E8E2D59A86D9!104

打開你喜歡的文字編輯器,你會看到大量正常的 SharePoint XSL 標記,用來渲染視圖,如果你繼續往下捲到 第 357 行,你會看到我加入標記的自訂模板開始,第一個是「DateDiff」範本,接著是「calculate-julian-day」和「FieldRef_printTableCell_EcbAllowed.Days_x0020_At_x0020_Status」。 這是我們的三個範本,用來製作並顯示我們的計算結果。 如果你將使用與本文先前所述不同的欄位名稱,你需要逐一檢視這些範本,並替換所有其他名稱的引用。 記得,這時你會想用欄位的內部名稱,而不是顯示名稱。

當你確認範本準備好後,前往你的樣式庫,並在「XSL Style Sheets」資料夾中上傳,然後複製該檔案的連結。 這樣我們之後就能輕鬆修改,或隨意新增到網站的不同部分。

接著,回到你的清單,選擇你在本文前面建立的視圖。 從「網站操作」選單點選「編輯頁面」。

[網站動作] 功能表上的 [編輯頁面] 命令

在頁面上找到你的清單檢視 Web Part,並點擊右上角向下的小箭頭開啟 Web Part 選單。 從此選單中選擇「編輯網頁部分」。

在 [網頁組件] 功能表上編輯 [網頁組件] 命令

這會顯示在瀏覽器視窗右側的網頁部分選單。

[網頁組件] 功能表

點擊「雜項」區塊的 + 鍵,並找到「XSL 連結」屬性。

[網頁組件] 功能表上的 XSL 連結屬性

把你之前複製下來的 XSL 檔案連結貼上去, (這可以是相對或絕對的連結) 。

貼入的 XSL 檔案連結

點擊「確定」儲存你的更改,然後點擊頁面頂端「頁面」功能區上的「停止編輯」按鈕。

[頁面] 索引標籤上的 [停止編輯] 按鈕

如果所有設定都正確,你現在應該會在「狀態天數」欄位看到數字。

顯示數量的 [狀態天數] 欄

最後,這是使用不同日期測試數據後的樣子:

顯示測試資料的年限報表

摘要:

就是這樣:一個格式化良好、功能完善且效能更好的 SharePoint 報告方式,並附帶簡單的無程式碼實作。 除了我們這裡探討的那個應用案例外,這還有相當多的潛在應用。 另一種常見的做法是將報告附加到任務清單中,這樣你就能一眼看到任務建立了多久。

祝您使用愉快!

——賈斯汀

賈斯汀·喬伊斯,LANtek

註解

缺少步驟
2012/10/8 凌晨3:51
好的,我照著步驟走了,但一定有什麼地方沒做——XSL 怎麼知道該用哪個日期,或是該把天數加進哪個欄位?我討厭錯過步驟。

無代碼,同意!
2012/8/30 中午12:12
我同意——我覺得這不算是「無規範」。
有趣的是,因為 SharePoint 的某些失誤,我用 Today...不知道怎麼回事,因為我無法再讓它出現,但那個還在且能用。

「狀態天數」計算欄位的公式?
2012年5月2日 上午7:39
Justin——你用什麼公式來計算「狀態日數」網站欄位 (佔位欄位) ? 是「=今天」嗎?

SharePoint 2007
2011年12月2日 上午11:29
目前我還沒嘗試將這個解決方案套用到 SharePoint 2007,但我正在研究中。 很遺憾,網頁部分的介面中沒有顯示任何 XslLink 屬性。

很棒的貼文
2011/11/30 上午9:53
您好,
很棒的文章。
我正在使用 SharePoint 2007。
如上所述,我沒有雜項區。
你有 SP2007 配置的步驟嗎?
感謝您。

關於無程式碼解決方案:顯示自 SharePoint 清單項目最後變動的天數
2011/10/11 上午8:24
嗨,Chris。
很棒的發現!
我希望今天晚點能看看你貼的內容,看看能不能讓這個方案更穩健一些。
很高興你喜歡這篇文章,也很高興你找到解決歐洲日期格式的方法。 :)
-賈斯汀

歐洲日期格式解決方案
2011/10/11 上午6:45
又見面了,Justin,
順帶一提,我找到了之前在這個頁面提到的問題解決方案;
https://sharepointbydummies.wordpress.com/2011/07/13/possible-work-around-to-date-format-issue-sharepoint-2010/

歐洲日期格式
2011年10月7日 凌晨3:59
嗨,Justin,
這真的是個很棒的解決方案,謝謝,這正是我過去兩天一直在找的東西! 不過我遇到了一些問題,希望你能幫我解答。
我稍微修改了你的程式碼,讓它計算出發生事情發生前的天數,而不是之後,方法是透過在「DateDiff」函式最後一行切換變數;

<XSL:value-of select=“$JulianToday - $JulianStartDate”></xsl:value-of>

不過我只有一半的時間能正確辨識差異。 例如這個日期 (格式為dd/MM/yyyy) ;

30/12/2011

計算正確,但日期 (格式相同)

12/10/2011

它計算得好像是2011年12月10日,而非2011年10月12日。
我試著簡單地在「JulianStartDate」變數中切換日和月的位置,就像這樣;

<xsl:with-param name=“Month” select=“substring (ddwrt:FormatDateTime (string ($StartDate) , 1033, 'yyyyMMdd') ,7,2) ”/>
<xsl:with-param name=“Day” select=“substring (ddwrt:FormatDateTime (string ($StartDate) , 1033, 'yyyyMMdd') ,5,2) ”/>

這樣第二次約會的問題就解決了,但第一次約會卻錯誤了!
我也嘗試將 FormatDateTime 呼叫改成歐洲 LCID,並對 FormatDateTime (的最後一個參數做了各種修改,例如 ddMMyyyy、MMddyyyy) ,並適當調整了子字串的位置參數,但都沒成功。
我非常感激你能提供的任何建議。
感謝您,
克里斯

No-Code
2011年9月21日 上午4:27
我不認為 XSL 算是「無程式碼」解決方案,因為理解 XSL 語言並非人人適合——但它不涉及程式設計。 除此之外:不錯的解決方案,謝謝你!