SharePoint:扩展DVWP - 第25部分:通过SPServices创建列表项实现审计跟踪

回顾在本系列第14部分中,我们提到“如何将PreSaveAction()与jQuery配合使用”。PreSaveAction()允许我们在保存记录前做一些事情,当时我快速的列了一些在现实场景中可能会用jQuery做的事。我们举了一个审计跟踪的例子。当主列表发生变更时,向另一个列表中写入主列表的变更信息。最终实现的效果是我们有两块体现真实信息的地方:(1)当前视图(2)一个关于变更的历史记录,展示达到当前视图所经历的过程。

在本文中,我打算花一点时间剥开一层洋葱皮,看一下具体如何实现当列表项被创建,修改或删除时在另一个列表中写记录。

在列表B中创建一条来源与列表A的记录

有太多的项目中需要我们在列表中插入,编辑,或删除列表项,没准你现在进行的项目中就有类似的需求吧。或许你以前做过订单处理解决方案,其中订单产生后我们需要更新库存信息。又或许是一个图书借阅系统,当有人借出一本书时你需要更新该书的状态。

要给另一个列表更新信息我们有很多选择。但如果你是要创建一个条全新的列表项,就像审计跟踪例子中需要的那样,要面临哪些挑战呢?显然,你必要决定什么数据需要抓取到审计跟踪记录里。在主列表中的每一个需要记录变更的栏,都必须在审计列表中存在对应的栏。

从本例的设计初衷出发,我们会选取主列表中几乎所有的栏记录其变更,进行审计。

 

主列表——FTE(全日制雇员,Full-time Employees)

 

FTE的审计跟踪列表

其中的名称和顺序没必要完全吻合。对于本例来说,栏的对应关系如下:

主列表(显示名称| 内部名称)

审计列表(显示名称| 内部名称)

Location | @LocDept

Location | @Location

Group | @Group12

Group | @Group

Position | @Positions

Position | @Position

Worker | @Title

Employee | @Title

Work Shift | @Workshift

Work Shift | @WorkShift

FTE | @FTE

FTE |@FTE

EffDate | @EffDate

Effective Date | @EffDate

Old Location | @Old%5Fx0020%5FLocation

 

Last Change | @Audit

 

 

Change Type | @ChangeType

 

Month | @Month

 

Year | @Year

 

From/To | @FromTo

创建者(Created By) 和 修改者(Modified By) 会由 SharePoint 自动填写,所以在两个列表中我们都不考虑这两个字段。

注意:两个列表的定义有以下几点不同:

  • 在主列表中有一些查阅项类型的栏,对应到审计跟踪列表时变成了单行文本。
  • 我在主列表中添加了一个Last Change栏。我们将用于保存最新一条审计记录的ID,并显示其修改时间字段。这里与Effective Date不同。
  • 在审计列表中,我添加了:
    • Change Type:一个选项型的栏(New,Update,Terminate,Resign,Transfer)——当一条列表项被插入,该值为New;对于编辑,如果Location发生了修改,则该值为Transfer;任何其他的修改都设为Update。如果列表项被删除,我们将记录是有公司解雇的(Terminate)还是有雇员提出辞职的(Resign)。【标注:在这里做一个记号,将来当我们讨论创建一个备用编辑模版时还会提及】
    • From/To:选项型的栏(From,To)——用于显示记录变更前/后的视图,即一次修改会创建两条记录。
    • Month:计算栏,用来取出Effective Date的月份,方便进行排序/分组。[公式: =TEXT([Effective Date],"mm – mmmm")]
    • Year:计算栏,用来取出Effective Date的年,方便排序。 [公式:=TEXT([Effective Date],"yyyy")]

 

FTE 变更审计

回到jQuery部分的工作

这里的jQuery脚本也是来自与第14部分(有关变量的创建,请参考第13部分),其中用到了Marc Anderson的SPServices库:

  function PreSaveAction() {
  var txtChangeType = "Update";

  var txtNewName = $("input[name*=$ff1_]").val();
  var txtOldName = $("span[id*=_ff9_]").text();

  var txtNewPos = $("input[name*=$ff3_]").val();
  var txtOldPos = $("span[id*=_ff11_]").text();

  var txtNewShift = $("select[name*=$ff4_]").val();
  var txtOldShift = $("span[id*=_ff12_]").text();

  var txtNewFTE = $("input[name*=$ff5_]").val();
  var txtOldFTE = $("span[id*=_ff13_]").text();

  var txtNewGrp = $("input[name*=$ff2_]").val();
  var txtOldGrp = $("span[id*=_ff10_]").text();

  var txtNewLoc = $("input[name*=$ff6_]").val();
  var txtOldLoc = $("span[id*=_ff14_]").text();

  var txtEffDate = $("input[name*=$ff7_]").val();

  if (txtNewLoc != txtOldLoc) txtChangeType = "Transfer";
  $().SPServices({
  operation: "UpdateListItems",
  async: false,
  listName: "FTE Change Audit",
  updates: "<Batch OnError='Continue' PreCalc='TRUE'>" +
    "<Method ID='1' Cmd='New'>" +
      "<Field Name='FromTo'>From</Field>" +
      "<Field Name='Title'>" + txtOldName + "</Field>" +
      "<Field Name='Location'>" + txtOldLoc + "</Field>" +
      "<Field Name='Group'>" + txtOldGrp + "</Field>" +
      "<Field Name='Position'>" + txtOldPos + "</Field>" +
      "<Field Name='WorkShift'>" + txtOldShift + "</Field>" +
      "<Field Name='FTE'>" + txtOldFTE + "</Field>" +
      "<Field Name='EffDate'>" + txtEffDate + "</Field>" +
      "<Field Name='ChangeType'>" + txtChangeType + "</Field>" +
     "</Method>" +
    "</Batch>",
  completefunc: function(xData, Status) {
  }
  });

  $().SPServices({
  operation: "UpdateListItems",
  async: false,
  listName: "FTE Change Audit",
  updates: "<Batch OnError='Continue' PreCalc='TRUE'>" +
    "<Method ID='1' Cmd='New'>" +
      "<Field Name='FromTo'>To</Field>" +
      "<Field Name='Title'>" + txtNewName + "</Field>" +
      "<Field Name='Location'>" + txtNewLoc + "</Field>" +
      "<Field Name='Group'>" + txtNewGrp + "</Field>" +
      "<Field Name='Position'>" + txtNewPos + "</Field>" +
      "<Field Name='WorkShift'>" + txtNewShift + "</Field>" +
      "<Field Name='FTE'>" + txtNewFTE + "</Field>" +
      "<Field Name='EffDate'>" + txtEffDate + "</Field>" +
      "<Field Name='ChangeType'>" + txtChangeType + "</Field>" +
     "</Method>" +
    "</Batch>",
  completefunc: function(xData, Status) {
  }
  });

  return true;
  };
  </script>

拆开来看

假设表单操作按钮已经被我们改为调用PreSaveAction(),那么这段脚本就会把变更保存至到审计列表。下面是整个过程的慢动作回放:

修改类型

var txtChangeType = "Update";

大多数的变更为Update类型。但是当Location发生修改时,类型就变成了Transfer(不考虑其他栏是否发生了修改...你的场景可能于此不同)。在我们设置所有的变量前,应对该项进行检查。

    var txtNewLoc = $("input[name*=$ff6_]").val();
    var txtOldLoc = $("span[id*=_ff14_]").text();

    . . .

    if (txtNewLoc != txtOldLoc) txtChangeType = "Transfer";

Effective Date

由于Effective Date的变更只涉及到本身,所以这种情况下From和To两个变更版本是相同的。

SPServices

现在,我们得到了变更前的“旧”值和变更后的“新”值,接下来直接通过SPServices调用UpdateListItems创建两条记录就可以了。在上面的29行到41行,我们告诉函数创建一条新记录。然后,我们只需加载上CAML把值填入审计列表的相应的栏即可。

或者,我们可以用下面的语法替换updates中使用的CAML:

        batchCmd: "New",
        valuepairs: [["FromTo", "From"],
                     ["Title", txtOldName],
                     ["Location", txtOldLoc],
                     ["Group", txtOldGrp],
                     ["Position", txtOldPos],
                     ["WorkShift", txtOldShift],
                     ["FTE", txtOldFTE],
                     ["EffDate", txtEffDate],
                     ["ChangeType", txtChangeType]],

注意到其中listName是目标列表的显示名称:

        listName: "FTE Change Audit",

接下来对应FromTo="To"再重复一遍上面的过程。我们就完成了两条审计跟踪记录的创建。

插入和删除

你可以在新建时使用相同的技术,但如果用工作流来处理“新建项目时”会更容易些。如果你需要我对这两种方式进行详细讲解的话请发表评论。

 

我们会在将来讲到添加一个备用编辑模版时使用Resign和Terminate变更类型。

 

下一次:如果你需要在DVWP中从一个关联的列表更新数据该怎么办?在接下来的扩展DVWP系列中,我们会公布谜底。

 

参考资料

SharePoint:Extending the DVWP - Part 25:Using an Audit Trail by Creating List Items with SPServices

posted @ 2010-09-16 00:00  Sunmoonfire  阅读(1834)  评论(0编辑  收藏  举报