作者:Justin Joyce,LANtek
注意
本文是为 SharePoint 最终用户提供的 四年“获取要点” 博客文章集的一部分。
概述:无代码自定义帐龄报表
SharePoint 网站中经常要求的功能之一是任务或列表项的帐龄报告。 换句话说,距离上次修改此列表项已经过去了多少天/月?
从表面上看,这似乎是一个非常简单的请求。 毕竟,我们有创建和修改项目的日期,当通过事件接收器对项目进行某些更改时,我们能够存储自定义日期。 我们有计算列,我们可以在其中包含类似 Excel 的公式来处理我们的信息。 这似乎是一个非常直接的提议。 我们选择一个日期字段,创建一个计算列,然后按照 [DateField] – [Today] 的行执行一个公式操作。 啊,不过没那么快! 任何尝试过此“简单”任务的人都知道,尝试在计算列中使用类似 [Today] 的内容会导致问题。 尝试在计算列的公式框中插入 [Today] 将提供如下所示的错误消息:
为什么会这样? 嗯,这与计算列的计算方式有关。
我们以一个简单的公式为例:
= IF ( [Column1]<=[Column2], “OK”, “Not OK”)
这就是说,如果 Column1 小于或等于 Column2,则显示 OK,否则显示 Not OK。 对于计算列来说,这是一个相当典型的基本公式,它对包含这些列的列表项进行基本假设: 如果没有列表项上的 Update 事件,Column1 和 Column2 的值将永远无法更改。
没错,计算列仅在更新 (或创建) 时才会重新计算,因为它们假设您正在计算的信息包含在项本身中。 当您尝试使用独立于项字段更改的内容(例如今天的日期)时,这会产生问题。
现在,我没有参加他们决定这是计算列的运作方式的会议,但是,如果我必须做出一个有根据的猜测,我会假设它们以这种方式运作以提高性能。 想象一下,如果您有一个包含数千个项目的列表,每个项目都包含一个需要“实时”更新的计算列。 这意味着某种机制(也许是一个计时器作业)必须每隔一段时间循环访问包含该计算列的每个项并更新其值。 就性能而言,这可能会非常繁重,因为对于更大规模的部署,这项工作可能会不断运行和改变事物。 这只是我的猜测,但如果你仔细想想,这很有道理。
坊间流传着一些类似解决方案的建议,这些解决方案涉及诱使 SharePoint 接受 Today 值,方法是首先创建一个名为 Today 的列,然后将其添加到公式中,然后将其删除。 这些都很好,但请记住我所说的计算列何时更新。 此值只会在更新项时更改,这意味着您的值很快就会不正确,尤其是在一天计算的情况下。
我见过其他人使用巧妙的 JavaScript 将值写入页面。 这也行得通,但是当可以避免时,我几乎断然反对客户端脚本。
实现:
那怎么办呢? 计算列对于像 Today 这样的所谓“易失性”函数来说是不可能的。 我们可以开发一些自定义代码来处理此问题,例如计算列、计时器作业或计划的进程来更新需要进行此计算的每个项目。 不过,这让我们回到了我在上一段中提到的性能问题,而且它是一个脆弱的解决方案,将高度特定于所讨论的站点/列表/列。 除了这两个问题之外,你还必须去找一个书呆子,比如我自己,知道如何编码并说服他为你开发这个解决方案。 但有一个更简单的方法!
如果你有权在网站上创建字段和编辑页面,并且对 XSLT 和创建视图有一些了解,则可以将 XSL 模板放在一起,该模板可以包含在列表视图中,并且每次请求页面时都会忠实地计算值。 此方案消除了我们对性能的担忧,并且不需要通过解决方案开发和部署自定义代码。
非常好。 那么我们该怎么做呢?
- 创建或选择将充当源的字段。 它必须是日期类型。
- 创建字段,作为要计算值的占位符。
- 将这两个字段添加到内容类型,并将该内容类型添加到列表中。
- 创建包含源列和占位符列的列表视图。
- 将 XSL 模板上传到样式库。
- 通过 UI 设置列表视图 Web 部件的“XSL 链接”属性。
- 成功!
让我们探讨一个示例用例并演练实现。 我们的客户希望查看他们的主列表,告诉他们特定列表项在其状态下放置了多长时间。 此列表包含从项类型派生并添加到列表中的自定义网站内容类型。 已经有一个事件接收器,用于捕获列表项上状态字段的每次更改时间,并将该日期保存到名为“日期状态已更改”的列中。 所有这些接线都不是必需的,并且可以使用任何日期字段完成, (碰巧这是我们的实现,但请随意尝试) 。 您最起码需要的是源日期字段和占位符字段来保存您的计算 () 添加到您的列表中的下一段中对此的更多信息,尽管我建议您使用网站列和网站内容类型,以防您希望在网站的其他地方重复使用此解决方案。
因此,我们有了源日期,可用于针对今天的日期进行计算。 现在,我们可以创建一个自定义网站列以用作计算值的容器。 在本例中,我选择使用计算列,因为它将无法在新或编辑项窗体上更改,但可以选择它以显示在视图中,因为我们不希望用户在此列中输入任意值。 对于为什么它没有显示在视图等中可能会令人困惑。
现在我们有了站点列,我们可以将其添加到将在列表中使用的内容类型。 接下来,我们需要创建视图,稍后将使用 XSLT 进行自定义。 确保创建一个标准视图,其中包含源日期列和将充当计算值占位符的新计算列。
我们现在拥有支持自定义龄龄报告所需的一切准备就绪。 剩下的就是创建 XSL 模板,将其上传到网站的样式库,并将其链接到列表视图。 我们将使用的 XSL 模板将包含一些正常的 SharePoint 生成标记,用于生成视图,以及我们自己的自定义标记,用于覆盖其中的某些部分并为我们计算所需的值。
值得称赞的是,我用于此解决方案的实际计算的 XSL 模板是由 MSDN 论坛上的“swirch”慷慨提供的:
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”。 这是我们的三个模板,它们将在视图中进行和显示计算。 如果要使用的字段名称与本文前面指定的字段名称不同,则需要浏览这些模板并替换对其他名称的任何引用。 请记住,为此,您需要使用字段的 INTERNAL 名称,而不是显示名称。
一旦您对模板准备就绪感到满意,请导航到您的样式库并将其上传到“XSL 样式表”文件夹下,然后复制指向文件的链接。 这将使我们能够在以后轻松地对其进行更改,或根据需要将其添加到站点的不同部分。
接下来,转到列表并选择本文前面创建的视图。 从“站点操作”菜单中,单击“编辑页面”。
在页面上找到列表视图 Web 部件,然后单击右上角向下的小箭头打开 Web 部件菜单。 在此菜单中,选择“编辑 Web 部件”。
这将在浏览器窗口的右侧打开 Web 部件的菜单。
单击“杂项”部分的 +,然后找到“XSL 链接”属性。
粘贴到之前复制的样式库中的 XSL 文件的链接 (这可以是相对链接或绝对链接) 。
单击“确定”保存更改,然后单击页面顶部“页面”功能区上的“停止编辑”按钮。
如果一切配置正确,您现在应该会在“状态天数”列中看到数字。
最后,这是不同日期的一些测试数据的样子:
摘要:
这就是:一种格式合理、可靠且性能更好的在 SharePoint 中创建帐龄报告的方式,只需简单的无代码实现即可完成。 除了我们在这里探讨的一个用例之外,这还有很多潜在的应用。 此类报表的另一个常见方案是将其附加到任务列表,以便一目了然地查看自创建任务以来的时长。
祝使用愉快!
--Justin
Justin Joyce,LANtek
批注
缺少步骤
2012/10/8 凌晨 3:51
好的,我按照步骤操作,但一定缺少一些东西 - XSL 如何知道要使用哪个日期,或者将自后的天数添加到哪个字段?如果错过了步骤,那就讨厌它。
无代码,同意!
2012/8/30 中午 12:12
我同意 - 我认为这并不算作“无代码”。
有趣的是,通过对 SharePoint 的一些搞砸,我有一个使用今天...不确定如何或为什么,因为我无法让它再次这样做,但那个仍然在那里并且正在工作。
“状态天数”计算列的公式?
2012/5/2 上午 7:39
Justin - 用于“状态天数”计算的网站列 (占位符列) 使用的公式是什么? 是“=today”吗?
SharePoint 2007
2011/12/2 上午 11:29
目前,我尚未尝试将此解决方案应用于 SharePoint 2007,但我正在研究它。 遗憾的是,Web 部件上没有通过 UI 显示 XslLink 属性。
很棒的帖子
2011/11/30 上午 9:53
你好,
很棒的帖子。
我使用的是 SharePoint 2007。
我没有上面提到的杂项部分。
是否有 SP2007 配置的步骤?
谢谢。
回复:无代码解决方案:显示自上次更改 SharePoint 列表项以来的天数
2011/10/11 上午 8:24
Chris,你好。
好发现!
我希望在今天晚些时候看看你发布的内容,看看我是否可以让这个解决方案更加强大。
我很高兴您喜欢这篇文章,也很高兴您能够找到欧洲日期格式的解决方案。 :)
-Justin
欧洲日期格式的解决方案
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 (的最后一个参数进行各种更改,例如 ddMMyyyyy、MMddyyyy) ,并对子字符串位置参数进行适当调整,但没有成功。
我将不胜感激您提供的任何建议。
谢谢,
Chris
No-Code
2011/9/21 早上 4:27
我不认为 XSL 符合“无代码”解决方案的条件,因为了解 XSL 语言并不适合所有人 - 但它不涉及编程。 除此之外:不错的解决方案,谢谢!