牛刀小试、用SharePoint 实现请假管理功能

转:http://www.cr173.com/html/15518_1.html

“请假管理”应用,应该算是 SharePoint 的“Hello World!”、川菜里面的鱼香肉丝、粤菜里面的蛋炒饭 。。。吧?

怎么样才能做出简易、实用的请假管理,一直都是都是一个问题。完全 code free 不写代码是搞不出来的,完全写代码实现的话又何必用 SharePoint?简洁、轻快的解决方案才是我们追求的。

问题

通常的“请假管理” SharePoint 实现存在这样几个问题:

权限。
要么就是所有人都可以看见你的请假单,要么就是只有你自己可以看到,要了命了。参见 这里 的描述。常见的解决方案,要么就是直接忽略这个问题,或者用视图来过滤筛选,但这不是根本的办法。

预先指定审批人员。
而实用的要求,其实是动态的指定审批人员。而且,往往并不是先由上级职能经理审批,而是先由所在项目的项目经理审批、职能经理一般只要项目经理没意见都会同意的。

年假天数约束。
假别里面如果是年假,则应该有天数的限制,且每年重置。软件应当自动对剩余年假天数做核对,避免需要人工再去查年假天数。

孤立。
没有和 SharePoint 其它应用配合,比如项目、日历。

目标

实用的“请假管理”应该什么样子呢?

1、所有人都可以提出请假申请。如下图所示:

2、自动查找合适的审批人。在项目中则项目经理就是审批人(直接去项目列表中找“项目经理”字段对应的用户),否则就是职能部门经理(如下图所示)。

3、不能申请超出可用年假天数的年假。

4、但是,一旦提交申请,就只有本人、审批人、管理员可以看到。而且审批人有“批准”权限。

注意:SharePoint 只允许每个列表拥有 8000 个独立权限的列表项。所以,后面要配合列表的信息管理策略将完成的请假单转移到别的地方。

5、申请人发起请假流程。

6、审批人审批请假申请。

7、审批完成后不能再修改申请。

配置信息管理策略将“声明为记录”的项在1个月后移动到其它的文档库,避免拥有独立权限的项目超过 SharePoint 对每个列表 8000 条的限制。

8、如果同意了年假申请,那么,自动从当年年假中扣除。

9、申请同意后自动加入请假日历。

该日历可以和其它日历合并在内网门户上显示。

实现

说实话,实现起来并不简单。但是,通过努力,可以保持解决方案的干净、轻快,与整个架构体系融合在一起。

1、所有人都可以提出请假申请。
直接断开“请假单”列表的权限继承,为所有用户设置“参与讨论”权限级别即可。
具体操作参见这里 中断列表或库的权限继承。

2、自动查找合适的审批人。
开发自定义字段,加入“请假单”列表。
此自定义字段将获取申请人所在项目的项目经理或者申请人的上级职能经理。
创建自定义字段类型的文章在这里 创建自定义 SharePoint 2010 字段类型。
获取当前用户的上级职能经理。需要用到 UserProfileManager 对象。

UserProfileManager upm = new UserProfileManager(SPServiceContext.Current);
if (upm.UserExists(user.LoginName))
{   
    UserProfile u = upm.GetUserProfile(user.LoginName);
    UserProfile[] managers = u.GetManagers();
    if (managers != null)
    {
        foreach(UserProfile manager in managers){
            SPUser u_manager = web.SiteUsers[manager[PropertyConstants.AccountName].Value.ToString()];
            // 其它自定义代码。
        }
    }
}


3、不能申请超出可用年假天数的年假。
这里需要用 SharePoint Designer 修改“请假单”列表的“NewForm.aspx”文件,利用 JavaScript 脚本调用 SharePoint 的 Client Object Model 获取剩余年假并显示在界面上。
首先,需要引入几个 js 库:jQuery 和 jQuery.SPServices。jQuery 已经放入 masterpage。

<SharePoint:ScriptLink Name="SP.js" runat="server" OnDemand="true" Localizable="false" />
<script src="http://www.cnblogs.com/DocLib/spservices/jquery.SPServices-0.7.1a.min.js" type="text/javascript"></script>

然后,在选择假别的下拉框内容改变时,读取可用年假天数。 (我当时为什么要用 lj 做变量名?我也很奇怪。)

$('select[title="假别"]').change(function(){var lj=$(this).val();if(lj=='年假'){ExecuteOrDelayUntilScriptLoaded(get_annual_leave_days, "sp.js");        }else{$("nobr:contains('请假天数')").children().each(function(){$(this).html("*");});}
});

get_annual_leave_days 方法将读取当前用户所剩余年假天数。下面函数中变量命名方法并不统一,这是这些代码来自多个不同时期的不同项目的印记啊!软件开发是个手艺活儿。
"_x5269__x4f59__x5e74__x5047__x59" 是字段“剩余年假天数”的 InnerName。

var _ctx = null;
var _items = null;
function get_annual_leave_days(){_ctx = new SP.ClientContext.get_current();var web = _ctx.get_web();var lists = web.get_lists();var list_annual_leave = lists.getByTitle("年假汇总");var currentDate = new Date();var year = currentDate.getFullYear();var currentUserID = $().SPServices.SPGetCurrentUser({fieldName: "ID",debug: false});var camlQuery = new SP.CamlQuery();var strCaml = "<View>" +"<Query>" +"<Where>"+"<And>"+"<Eq>"+"<FieldRef Name='_x4eba__x5458_' LookupId='TRUE' />"+"<Value Type='Lookup'>"+currentUserID+"</Value>"+"</Eq>"+"<Eq>"+"<FieldRef Name='_x5e74__x4efd_' />"+"<Value Type='Integer'>"+year+"</Value>"+"</Eq>"+"</And>"+"</Where>"+"</Query>" +"</View>";camlQuery.set_viewXml(strCaml);this._items = list_annual_leave.getItems(camlQuery);_ctx.load(_items);_ctx.executeQueryAsync(Function.createDelegate(this, this.onSuccess), Function.createDelegate(this, this.onFail));
}
function onSuccess(sender, args) {var listItemEnumerator = this._items.getEnumerator();while(listItemEnumerator.moveNext()) {var oListItem = listItemEnumerator.get_current();var days = oListItem.get_item("_x5269__x4f59__x5e74__x5047__x59");$("nobr:contains('请假天数')").children().each(function(){$(this).html("(剩余 "+days+" 天)*");});}
}
function onFail(sender, args) {alert('获取年假天数时出错:' + args.get_message());
}

更多的技术细节可以参考 ECMAScript 对象模型系列,这个系列讲解很细致了。另外,JS 脚本调用 SharePoint 的 JSCOM 时是异步操作,回调次数多了代码会很乱,这篇 使用Jscex增强SharePoint 2010 JavaScript Client Object Model (JSOM) 提供了一优化代码的解决方案可供参考。


4、但是,一旦提交申请,就只有本人、审批人、管理员可以看到。而且审批人有“批准”权限。
为实现这个功能,需要处理列表的 Create 事件。
先断开现有的继承权限。

item.BreakRoleInheritance(false);


然后,绑定新的权限。

protected void bind_role(SPListItem item, SPPrincipal principal, SPRoleDefinition definition)
{try{SPRoleAssignment assignment = new SPRoleAssignment(principal);assignment.RoleDefinitionBindings.Add(definition);item.RoleAssignments.Add(assignment);}catch (Exception ex){throw ex;}
}

对某个用户执行绑定角色的操作。

bind_role(item, user, web.RoleDefinitions["参与讨论"]);

5、申请人发起请假流程。
用 SharePoint Designer 建立请假流程。


6、审批人审批请假申请。
审批即可。可以用 InfoPath Designer 从 SPD 中打开美化一下任务界面。
如果需要对任务也实施和“请假单”相同的权限控制,可以参考对“请假单”的处理一样进行。


7、审批完成后不能再修改申请。
需要开发处理工作流事件的代码,声明当前项目为记录。

SPWorkflow wf = new SPWorkflow(web, properties.InstanceId);
SPList list = web.Lists[wf.ListId];
if (list.Title == "请假单") 
{SPListItem item = list.Items.GetItemById(wf.ItemId);title = item.Title;if (!Records.IsRecord(item)){Records.DeclareItemAsRecord(item);}
}

还需要配置信息管理策略,自动备份已经完成流程的“请假单”到归档库中。


8、如果同意了年假申请,那么,自动从当年年假中扣除。
同样在工作流事件代码中处理,扣除年假天数。做减法即可。由于申请人本人没有直接修改年假天数的权限(这是当然的),所以需要提升权限才能操作。而这也意味着要服务器场解决方案,“全程沙盒方案”梦想破灭。


9、申请同意后自动加入请假日历。
在 SPD 工作流中处理。

10、签入代码和 SPD 文件(导出来备份,或者直接 stsadm –o backup 备份网站集),写好部署操作手册。完工。

 

转载于:https://www.cnblogs.com/jackljf/p/3589223.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399860.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js遍历json对象

原生js遍历json对象 遍历json对象&#xff1a; 无规律&#xff1a; <script> var json [ {dd:SB,AA:东东,re1:123}, {cccc:dd,lk:1qw} ]; for(var i0,ljson.length;i<l;i){ for(var key in json[i]){ alert(key:json[i][key]); } } </script> 有规律&…

JS-封装js让一个div或者img的移动

/* * 运动函数 * 参数&#xff1a; * elem 操作的元素节点 * obj 操作的元素节点上的css属性和css属性值 * attr 操作的元素节点上的css属性 * target 操作的元素节点上的css属性的目标值 * fn 运动结束后的所要执行的函数 */function startMove(elem, obj, fn){ // 开定时器 …

linux如何查看mysql是否启动

linux下有很多服务&#xff0c;今天就写一下如何查看服务是否启动&#xff0c;以mysql为例子 使用命令 # service mysqld status 或者 # service mysql status 命令来查看mysql 的启动状态 如果是 mysqld is stopped 那就说明mysql服务是停止状态&#xff0c; 如果是 mysqld is…

django时区设置问题

2019独角兽企业重金招聘Python工程师标准>>> 最近用Django开发项目&#xff0c;在使用datetime类获取.now()时&#xff0c;获取的时间比实际时间相差8小时左右&#xff08;感觉是UTC时间&#xff09;&#xff0c;服务器使用的时区是“Asia/Shanghai”&#xff08;08…

js文件中声明的一个json对象, 在另一个js文件中可以直接使用。

1. 如在 AAA.js 文件中声明一个json对象。 var world_geo_json {"type":"FeatureCollection","offset":{"x":170,"y":90},"features":[ ] }; 2. 调用。 <html lang"en"> <head> &l…

Objective-C模版方法(TemplateMethod)

什么是模版方法&#xff1f; 官方&#xff1a;定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模版方法使子类可以重新定义算法的某些步骤而不改变算法的结构。 个人理解&#xff1a;模版方法没必要刻意去理解&#xff0c;平时的编码过程中不知不觉就会用到…

微信小程序+TP5——token令牌生成

token令牌的作用&#xff1a;客户端每次登录服务器端都会生成一个唯一的token令牌值&#xff0c;并返回到客户端&#xff0c;而服务器端会默认将token令牌值作为key, 用户信息作为value&#xff0c;一一对应存入缓存中&#xff0c;当用户每一次发送请求时&#xff0c;都要携带这…

vs code 代码格式化整理

On Windows Shift Alt F On Mac Shift Option F On Ubuntu Ctrl Shift I 但是自带的格式化并不能满足我的需求&#xff0c;这个时候&#xff0c;不得不说插件大法好。 1、代码格式化为eslint风格&#xff08;参考自这里&#xff09; 需要插件&#xff1a;eslint 在设置…

基于live555实现的RTSPServer对底层进行性能优化的方法

在博客《EasyIPCamera高性能摄像机RTSP服务器RTSPServer解决方案》我介绍了基于live555实现的一套RTSPServer功能组件&#xff0c;当时开发者经过几个月的调试&#xff0c;已经将底层的性能调试到了一个业界非常优秀的程度&#xff0c;主要优化的几点&#xff1a; 发送优化调度…

sqlite 字符串 转 整型 cast 函数 (强制类型转换 )

sqlite 字符串 转 整型使用 cast 函数 语法&#xff1a; cast(col_name as type) 例子&#xff1a; 表&#xff1a;JobInfo 表内字段&#xff1a;Salary 薪水 select * from JobInfo where cast(substr(Salary,1,5)as int)>10000 结果集&#xff1a; 转载于:https://www.cn…

2018.2.2PHPstrom破解版

--------------------- 作者&#xff1a;聽の雨ぷ 来源&#xff1a;CSDN 原文&#xff1a;https://blog.csdn.net/qq_39439751/article/details/82758330 版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请附上博文链接&#xff01; 首先将我为大家事先准备好的打…

python-上传下载文件

https://www.cnblogs.com/jessicaxu/p/7891372.html python-上传下载文件 一、服务端接口 import flask, os,sys,time from flask import request, send_from_directoryinterface_path os.path.dirname(__file__) sys.path.insert(0, interface_path) #将当前文件的父目录加…

Quartz.net 2.0的使用说明

Quartz.NET是一个开源的作业调度框架&#xff0c;是OpenSymphony 的 Quartz API的.NET移植&#xff0c;它用C#写成&#xff0c;可用于WinForm和ASP.NET应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而 创建简单的或复杂的调度。它有很多特征&#x…

Android View滚动、拉伸到顶/底部弹性回弹复位

&#xfeff;&#xfeff;《Android View滚动、拉伸到顶/底部弹性回弹复位》 我在上一篇文章介绍了如何实现一个Android ListView拉到顶/底部后&#xff0c;像橡皮筋一样弹性回弹复位&#xff08;《Android ListView拉到顶/底部&#xff0c;像橡皮筋一样弹性回弹复位》&#xf…

JavaScript If...Else 语句

条件语句用于基于不同的条件来执行不同的动作。 条件语句 通常在写代码时&#xff0c;您总是需要为不同的决定来执行不同的动作。您可以在代码中使用条件语句来完成该任务。 在 JavaScript 中&#xff0c;我们可使用以下条件语句&#xff1a; if 语句 - 只有当指定条件为 true …

使用手机游戏的新闻推送

使用手机游戏的新闻推送——WeCloud 团队 消息推送是游戏开发人员与玩家沟通最直接的桥梁。开发人员能够通过推送一条消息直观地在手机屏幕上把信息传达给玩家。可是因为开发人员一些不恰当推送或者对于推送细节的疏忽大意&#xff0c;使得大多数的玩家都选择了彻底关闭推送消息…

Python -- post方式上传文件

说明 使用第三方库Request&#xff0c;安装方法为&#xff1a; pip install requests 具体安装方法参考http://docs.python-requests.org/en/master/user/install/。 代码 import requestsurl http://127.0.0.1/upload files {file: open(D:/test.apk, rb)} da…

WeakReference与SoftReference

WeakReference与SoftReference都可以用来保存对象的实例引用&#xff0c;这两个类与垃圾回收有关。 WeakReference是弱引用&#xff0c;其中保存的对象实例可以被GC回收掉。这个类通常用于在某处保存对象引用&#xff0c;而又不干扰该对象被GC回收&#xff0c;通常用于Debug、内…

TCP是如何保证包的顺序传输

转自&#xff1a;http://blog.csdn.net/ggxxkkll/article/details/7894112 大家都知道&#xff0c;TCP提供了最可靠的数据传输&#xff0c;它给发送的每个数据包做顺序化&#xff08;这看起来非常烦琐&#xff09;&#xff0c;然而&#xff0c;如果TCP没有这样烦琐的操作&#…