客户需要在OA中实现每日动态功能,能够记录每一位员工的每天的工作动态,我很快想到了时间轴,因为时间轴能很直观的现实员工每一刻的动态。就像Facebook的Timeline效果(点击查看)。 尝试着搜索这个效果,园友的这篇博文正好给我启发,接下来就去实现吧。
成果演示
最终的效果如下所示:
点击每个员工的姓名,即可进入他当天的工作动态(只能看),若点击自己的名字(既能看又能发送/编辑/删除动态),如下所示:
动态的详细页,如下所示:
点击时间轴,即可新增动态,如下所示:
编辑效果,鼠标移至内容区域,现实黄色提醒,如下所示:
单击即可显示编辑界面,如下所示:
移开鼠标,即可自动保存。
当然如果想把一条当太删掉,点击右上角X即可。
实现原理
关于效果的实现原理可以参考这篇文章。
了解了上面提到的这篇文章之后(Masonry.js),接下来就是Sharepoint 客户端对象模型的实现了,比如Ecmascript。
- 根据登陆的用户点击的员工名字获取当天的动态,这儿需要利用CAML拼接出查询条件
function GetCurrentUser(){
//Get the current context
var context=new SP.ClientContext.get_current();
//Load the web object
var web=context.get_web();
//Get current user
this.currentUser=web.get_currentUser();
//load currentUser
context.load(currentUser);
//Make a query call to execute the above statements
context.executeQueryAsync(OnGetCurrentUserSuccess,OnGetCurrentUserFailed);
}
function OnGetCurrentUserSuccess(){
GetDailyWorks();
}
function OnGetCurrentUserFailed(sender,args){
console.log('Request failed. ' args.get_message() 'n' args.get_stackTrace());
}
function GetDailyWorks(){
//Get the current context
var context=new SP.ClientContext.get_current();
//Load the web object
var web=context.get_web();
//Get the list
var list=web.get_lists().getByTitle(listNameForDailyWork);
//Get items by caml in the specific list
var camlQuery=new SP.CamlQuery();
var d=new Date();
//Get specific field name
this.userNameWhenClickView=$("#currentUserHidden").val();
camlQuery.set_viewXml('<View><Query>'
'<Where>'
'<And>'
'<And>'
'<And>'
'<Eq>'
'<FieldRef Name='Title'/>'
'<Value Type='Text'>' userNameWhenClickView '</Value>'
'</Eq>'
'<Eq>'
'<FieldRef Name='CurrentYear'/>'
'<Value Type='Text'>' d.getFullYear() '</Value>'
'</Eq>'
'</And>'
'<Eq>'
'<FieldRef Name='CurrentMonth'/>'
'<Value Type='Text'>' (d.getMonth() 1) '</Value>'
'</Eq>'
'</And>'
'<Eq>'
'<FieldRef Name='CurrentDay'/>'
'<Value Type='Text'>' d.getDate() '</Value>'
'</Eq>'
'</And>'
'</Where>'
'<OrderBy>'
'<FieldRef Name='Created' Ascending='True'/>'
'</OrderBy></Query></View>');
dailyWorks=list.getItems(camlQuery);
//Load the web in the context and retrieve only selected columns to improve perfomance
context.load(dailyWorks,'Include(ID,Title,DailyContent,Created)');
//Make a query call to execute the above statements
context.executeQueryAsync(OnGetDailyWorksSuccess,OnGetDailyWorkFailed);
}
function OnGetDailyWorksSuccess(){
//Get the collection
var dailyWorksCollection=dailyWorks.getEnumerator();
//Iterate through daily works
while(dailyWorksCollection.moveNext()){
//Load the current daily work item in iterate
var workItem=dailyWorksCollection.get_current();
//Add work item to container
addWorkToContainer(workItem.get_item('ID'),workItem.get_item('Title'),workItem.get_item('DailyContent'),workItem.get_item("Created"));
}
//Items has added in container and execute AutoMasonry method
AutoMasonry();
//Init in line edit if current user has permission to edit
if(userNameWhenClickView==currentUser.get_title()){
InitInlineEdit($('.editable, .editable-area'));
}
}
//Error Handler
function OnGetDailyWorkFailed(sender,args){
console.log('Request failed. ' args.get_message() 'n' args.get_stackTrace());
}
- 当然Add一个Item也是比较方便的,当Add Item完毕后,很重要的一点是利用Masonry Reload一下所有的item
function AddNewDailyWorkItem(content){
//get the current context
var context=new SP.ClientContext.get_current();
//Load the web object
var web=context.get_web();
//Get the list
var list =web.get_lists().getByTitle(listNameForDailyWork);
//create the ListItemInfomational object
var listItemInfo=new SP.ListItemCreationInformation();
//add the item to the list
this.listItem=list.addItem(listItemInfo);
//get current user display name
var userDisplayName=currentUser.get_title();
//Assign values for fields
listItem.set_item('Title',userDisplayName);
listItem.set_item('DailyContent',content);
//Get current year ,month,day and assign values for fields
var newObj=new Date();
listItem.set_item('CurrentYear',newObj.getFullYear());
listItem.set_item('CurrentMonth',newObj.getMonth() 1);
listItem.set_item('CurrentDay',newObj.getDate());
//Apply changes to item
listItem.update(listItem);
context.load(listItem);
//Make a query call to execute the above statements
context.executeQueryAsync(AddDailyWorkItemSuccess,AddDailyWorkItemFailed);
}
function AddDailyWorkItemSuccess(sender,args){
var content = $("#update").val();
$('<div class="item"><a href="#" itemId="' listItem.get_id() '" class="deletebox">X</a>' '<div class="inner"><p itemId="' listItem.get_id() '" class="editable-area">' content '</p></div><p class="sendStyle">发送于' (new Date()).getHours() ':' ((new Date()).getMinutes()<10?"0" (new Date()).getMinutes():(new Date()).getMinutes()) '</p></div>').insertBefore("div#popup");
//reload masnory
$("#container").masonry("reload");
//Hiding existing arrows
$(".rightCorner").hide();
$(".leftCorner").hide();
//injecting fresh arrows
Arrow_Points();
//clear popup text box value
$("#update").val("");
//popup hide
$("#popup").hide();
//Init in line edit
$('p[itemId=' listItem.get_id() ']');
InitInlineEdit($('p[itemId=' listItem.get_id() ']'));
}
function AddDailyWorkItemFailed(sender,args){
console.log('Request failed. ' args.get_message() 'n' args.get_stackTrace());
}
- Update 和Add是相同的逻辑,记得最后Reload即可
function UpdateDailyWorkItem(itemId,updateContent){
//If no title is setted then show alert and set focus
/*if(updateContent==''){
$()
}*/
//Get the current context
var context = new SP.ClientContext.get_current();
//Load the web object
var web=context.get_web();
//Get the list
var list=web.get_lists().getByTitle(listNameForDailyWork);
//Get item to update by Id from the specific list
this.listItem=list.getItemById(itemId);
//Set the new property value
listItem.set_item('DailyContent',updateContent);
//Call the update method to commit the change
listItem.update();
context.executeQueryAsync(updateWorkItemSuccess,updateWorkItemFailed);
}
function updateWorkItemSuccess(){
$editable
.removeClass('active-inline')
.children()
.replaceWith(edited);
if ($editable.hasClass('editable-area')) {
rapture($editable);
}
//reload masnory
$("#container").masonry("reload");
//Hiding existing arrows
$(".rightCorner").hide();
$(".leftCorner").hide();
//injecting fresh arrows
Arrow_Points();
}
function updateWorkItemFailed(){
}
- Delete Item,根据item id进行删除,同Add和Update逻辑,删除完毕后也是需要Reload
//Delete daily work item by item id
function deleteDailyWork(workElement){
//Get the daily work item id
var itemId=workElement.attr("itemId");
//Get the current context
var context=new SP.ClientContext.get_current();
//Load the web object
var web=context.get_web();
//Get the list
var list=web.get_lists().getByTitle(listNameForDailyWork);
//Get item to delete by if form the list
var itemToDelete=list.getItemById(itemId);
//Add Delete method to the query
itemToDelete.deleteObject();
//Execute the query to perform the deletion
context.executeQueryAsync(DeleteWorkItemSuccess,DeleteWorkItemFailed);
}
function DeleteWorkItemSuccess(){
//Masonry Reload
}
function DeleteWorkItemFailed(sender,args){
console.log('Request failed. ' args.get_message() 'n' args.get_stackTrace());
}
总结
值得注意的是我将每日的动态存入List中,对于List,他能负担的item的个数和一次从数据库里获取的item都是有限制,对于数据量很大的情况下,是有风险的。