首页 人力资源管理系统的设计—免费毕业设计论文

人力资源管理系统的设计—免费毕业设计论文

举报
开通vip

人力资源管理系统的设计—免费毕业设计论文人力资源管理系统的设计—免费毕业设计论文 IT企业人力资源管理系统 摘 要 人力资源管理系统是一个企业单位不可缺少的部分,是适应现代企业制度,推动企业人力资源管理走向科学化、规范化、自动化的必要条件。它的内容对于企业的决策者和管理者来说都至关重要,所以人力资源管理系统应该能够为用户提供充足的信息和快捷的查询手段,以帮助企业领导了解企业现有的人力资源状况。但一直以来人们使用传统人工的方式管理文件档案,这种管理方式存在许多缺点,如:效率低、安全性差、时间一长就会产生大量的文件和数据积压,这对于查找、更新和维护都带...

人力资源管理系统的设计—免费毕业设计论文
人力资源管理系统的 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 —免费毕业设计论文 IT企业人力资源管理系统 摘 要 人力资源管理系统是一个企业单位不可缺少的部分,是适应现代企业制度,推动企业人力资源管理走向科学化、规范化、自动化的必要条件。它的内容对于企业的决策者和管理者来说都至关重要,所以人力资源管理系统应该能够为用户提供充足的信息和快捷的查询手段,以帮助企业领导了解企业现有的人力资源状况。但一直以来人们使用传统人工的方式管理文件档案,这种管理方式存在许多缺点,如:效率低、安全性差、时间一长就会产生大量的文件和数据积压,这对于查找、更新和维护都带来了不少的困难。 因此,为了加快企业的信息化步伐,提高企业的管理水平以在激烈的社会竞争中立于不败之地,建设和完善人力资源管理系统已经变得十分必要和迫切。 本系统详细介绍了企业人力资源管理系统的开发与设计,包括了开发一个管理信息系统的5个阶段:系统开始和可行性研究、系统分析和设计、程序设计、系统测试和技术培训、项目总结和评估。 其中,引言部分说明本课题的意义、目的、研究范围及要达到的技术要求;简述本课题在国内外的发展概况及存在的问题;说明本课题的指导思想;阐述本课题应解决的主要问题。 系统分析阶段主要说明了系统的需求分析,开发工具的选择和环境的配置。 系统开发阶段主要说明了系统的界面开发和程序编码的设计。在程序编码中给出了其设计思想以及主要代码。 在设计当中,我们使用了现在广泛流行的Web浏览方式将一个通用型的企业人力资源管理系统展现给用户,提供给用户很好的界面和操作平台。 关键字:人力资源管理;信息系统 1 The IT business enterprise human resource manages system ABSTRACT The human resources management system is an enterprise unit essential part, adapts the modern enterprise system, impels the enterprise human resources management to move towards scientific, standardized, the automated essential condition. It’s content regarding enterprise's policy-makers and the superintendent all very important, therefore the human resources management system should be able to provide the sufficient information and the quick inquiry method for the user, helps the head of undertaking understanding enterprise existing human resources condition. But the people have since always used the traditional artificial way management document file, this management way has many shortcomings, for example: The efficiency low, the security bad, the time one long can produce the massive documents and the data backlog, this regarding the search, the renewal and the maintenance has all brought many difficulties. Therefore, in order to speed up the enterprise the informationization step, enhances the enterprise the management level by to be in an impregnable position in the intense social competition, the construction and the consummation human resources management system already became extremely essential and urgent. This system introduced in detail the enterprise human resources management system development and the design, including has developed a management information system 5 stages: The system starts with the feasibility study, the system analysis and the design, the programming, the system test and technical training, the project summary and the appraisal. Among them, the introduction part explained this topic the significance, the goal, the research scope and must achieve specification; Summarizes this topic in the domestic and foreign development survey and the existence question; Explains this topic the guiding ideology; Elaborated this topic should solve main question. The system analysis stage mainly showed the system demand analysis, the development kit choice and the environment disposition. The system phase of exploitation mainly showed the system contact surface development and the procedure code design. Has given its design concept as well as the main code in the procedure code. Middle the design, we use the present widespread popular Web browser mode to give a general enterprise human resources management system development the user, provided for the user the very good contact surface and the platform. Key words: Human resources management; Information system 2 目 录 1 引 言 ................................................................................................................. 3 1.1 研究课题的目的与背景 ................................................................................. 3 1.2 人力资源管理的内容和目标 ......................................................................... 3 1.3 研究课题的意义 ............................................................................................. 4 2 系统分析 ........................................................................................................... 5 2.1 可行性研究 ..................................................................................................... 5 2.1.1 技术可行性 .................................................................................................. 5 2.1.2 社会可行性 .................................................................................................. 5 2.1.3 开发环境分析 .............................................................................................. 5 2.1.4 系统性能需求分析 ...................................................................................... 6 2.2 开发环境介绍 ................................................................................................. 7 2.2.1 ASP介绍 ...................................................................................................... 7 2.2.2 Access介绍 ................................................................................................... 8 3 系统设计 ......................................................................................................... 10 3.1 系统总体结构与功能 ................................................................................... 10 3.1.1 系统结构 .................................................................................................... 10 3.1.2 系统各功能内容简介及主要功能模块分析 ............................................. 12 3.2 数据库设计 ................................................................................................... 19 3.2.1 数据库的需求分析 .................................................................................... 19 3.2.2 数据库的表设计 ........................................................................................ 19 4 程序设计 ......................................................................................................... 21 1 4.1 登陆系统模块 ............................................................................................... 21 4.2 工作 计划 项目进度计划表范例计划下载计划下载计划下载课程教学计划下载 模块 ............................................................................................... 22 4.3通告管理模块 ................................................................................................ 23 4.4 公文管理模块 ............................................................................................... 24 4.5 人力管理模块 ............................................................................................... 25 4.6 考勤管理模块 ............................................................................................... 28 5 系统实施和维护 .............................................................................................. 31 5.1系统测试 ....................................................................................................... 31 5.1.1 IIS的安装 ................................................................................................... 31 5.1.2 后台数据库的配置 .................................................................................... 33 5.2 系统维护....................................................................................................... 37 6 设计总结与心得 .............................................................................................. 37 谢 辞 ................................................................................................................... 38 参 考 文 献 ....................................................................................................... 39 附录A 外文翻译—原文部分 ............................................................................. 40 附录B 外文翻译—译文部分 ............................................................................. 47 2 1 引 言 1.1 研究课题的目的与背景 知识经济时代, 以不确定性为特征的竞争环境向现代企业提出了新的挑战, 人力资源管理作为管理学的一个分支, 在企业管理活动中的地位越来越重要。企业要实现利润最大化, 有效开发人力资源, 就必须更新观念, 实现向人力资源管理的转变。 知识经济的兴起和信息技术的日新月异, 消除了人类知识、信息传递的障碍, 也带来了经营意识、管理观念的巨大转变。随着西方先进管理思想的引进, 现代人力资源管理对我国现有的劳动人事 管理制度 档案管理制度下载食品安全管理制度下载三类维修管理制度下载财务管理制度免费下载安全设施管理制度下载 形成了冲击, 并将最终取而代之。同传统的劳动人事管理相比, 人力资源管理在我国企业的应用刚刚起步, 对国外有关理论的认识还停留在“点”的阶段, 远未做到系统引进, 消化吸收, 实现真正意义上的“从劳动人事管理向人力资源管理”的功能性转变。因此, 企业管理人员应对这种转变所面临的挑战和机遇有一个全面的、清醒的认识, 努力探索一条适合中国国情的人力资源管理之路。 现代人力资源管理是建立在市场经济基础之上, 按照市场经济法则, 对人力资源的招聘录用、绩效考评和培训发展等进行全过程的、主动的、动态的管理, 其各个环节紧密结合, 主动地对人力资源的各个方面进行开发利用。人力资源各个时期的管理规划、培训开发总是与企业各个阶段的人力资源状况和目标紧密相连。人才市场体系的建立, 使得人力资源流动渠道畅通, 员工进出变得容易, 辞职或被辞退变得正常, 企业能不断地吐故纳新, 保持活力。全过程的、动态的、主动的人力资源管理符合市场经济以市场实现对资源进行有效配置的原则。 现代人力资源管理在传统劳动人事管理的基础上增加了人力资源规划、人力资源开发、岗位与组织设计、行为管理和员工终身教育培训等内容, 使现代人力资源的管理更具计划性、战略性、整体性和未来性。 1.2 人力资源管理的内容和目标 现代人力资源的内容十分丰富, 涉及到人力资源的诸多方面, 其主要内容有:人力资源的规划和选拔、培训和发展、激励、绩效考评、薪酬管理、安全与福利等方面。人力资源管理始终是围绕着如何充分开发人力资源这一核心目标展开活动。人力资源管理的主要目标有: (1) 充分调动员工的积极性 据调查研究发现, 在自然状态下, 员工只能发挥20% ,30%的能力, 如果充分调动员工的积极性, 其潜力可发挥到80%,90%。所以, 为了充分、全面、有 3 效地开发人力资源, 调动员工的积极性就成了实现企业目标的有效手段。而员工的积极性常受到员工在企业中的发展空间、自我实现机会、薪酬福利状况和人际关系等因素的影响, 企业应尽力对这些因素进行调整, 使之有利于充分调动员工的积极性, 实现企业目标。 (2) 扩展企业的人力资本 企业拥有三大资源, 即人力资源、物质资源和财力资源。其中, 物质资源和财力资源的利用归根结底是通过与人力资源的结合实现的, 实现的程度受企业人力资源中人力资本的数量、利用程度以及人力资源管理的优劣的影响。扩展企业人力资本、增加人力资本的存量, 成为人力资源管理的一大目标。美国通用电气公司堪称实现这一目标的典范。该公司有一套专门负责培训, 增加企业的人力资本形成初级班人才开发、高级班人才开发等一系列完善的扩展人力资本的体系, 为企业的技术开发、营销管理奠定了坚实的人才基础。因此, 美国通用电气公司1998 年名列全球500 强中第9 位, 纯利润突破100 亿美元, 资本利润率高达25%。这些成绩与其先进的人力资源管理是分不开的。 (3) 实现企业利润最大化 在企业的日常管理中, 只有使人力资源的使用效率最大化才能实现企业利润的最大化。可表述为: 人的最大使用价值=最大限度地发挥人的有效技能 人的有效技能=人的劳动技能×适用率×发挥率×有效率 人力资源管理就是通过提高人的技能的适用率、发挥率和有效率, 达到人尽 其才、人 尽其能, 最大限度地发挥人的潜能, 最终实现企业利润最大化的目标。 1.3 研究课题的意义 本课题主要是设计一个针对中小型IT企业的人力资源管理系统。该系统不仅是面向人力资源管理部门的简单的管理信息系统,而是一个面向整个企业所有员工的信息管理中心和人事安排辅助系统。从而建立科学的人力资源开发和员工工作绩效考核评价体系,对员工进行有效激励。现代企业应探索建立企业文化、经营理念和知识技能培训协调统一的培训开发机制,采取灵活多样的培训方式,加强和开展不同层次的员工培训,注重培训效果。在员工工作绩效考核评价方面, 探索建立科学的具有目的、内容、方法、程序、标准和要求的量化考核体系、评价方式和方法, 运用正强化和负强化手段把员工的绩效考评与奖惩结合起来, 真正做到依据员工的工作绩效决定员工的岗位、薪酬、晋升和培训, 有效激励员工提高工作效率。 人力资源管理系统是一个企业单位不可缺少的部分,是适应现代企业制度, 4 推动企业人力资源管理走向科学化、规范化、自动化的必要条件。它的内容对于企业的决策者和管理者来说都至关重要,所以人力资源管理系统应该能够为用户提供充足的信息和快捷的查询手段,以帮助企业领导了解企业现有的人力资源状况。 因此,为了加快公司的信息化步伐,提高公司的管理水平以在激烈的社会竞争中立于不败之地,建设和完善人力资源管理系统已变得十分必要和迫切。 2 系统分析 2.1 可行性研究 系统开始和可行性研究是为系统开发做前期准备。在对一个项目的开发之前,我们总是要对其进行一个可行性分析与需求分析,通过开发组全体成员和指导老师的共同分析得出了可行性开发计划。对于需求分析我们作了如下调查分析的需求。 2.1.1 技术可行性 随着软件编程技术的不断增加,功能的不断加强,和网络技术的不断成熟,信息安全的不断完善以及开发工具的日益进步,采用计算机系统来管理人事信息要求数据的采集、更新能够完整、准确和及时。所以开发通用的企业人力资源管理系统已经完全可以做到。 2.1.2 社会可行性 随着经济全球化的到来, “哪个组织学习的快, 哪个组织就能生存, 哪个组织就能赢得竞争优势。”美国学者指出,未来最成功的企业将是学习型组织,因为未来唯一持久的优势是比你的竞争对手学得更快的能力。只有把企业建成学习型组织, 才能充分体现“以人为本”的管理理念, 提高员工创新能力, 为员工发展自我提供广阔的空间, 实现知识共享, 提高企业的整体人力资源管理水平。 2.1.3 开发环境分析 本系统是属于管理信息系统,管理信息系统(MIS,Management Information System)可以保存用户信息,通过对信息进行分析和处理,可以帮助用户制定计划、规范管理或提供决策依据。 管理信息系统通常可以采用浏览器/服务器(B/S)结构开发。随着Internet的推广和普及,开发B/S结构的管理信息系统也在很多领域得到了应用。它的主要优势在于用户无需安装客户端软件,只要使用IE浏览器就可以使用管理信息 5 系统。当然,B/S结构的管理信息系统的主要操作都在服务器上完成,对服务器的要求比较高。 ASP是Microsoft公司开发的Web服务器端脚本开发工具,使用它可以生成动态、高效的Web应用程序。使用ASP制作B/S结构应用程序的框架如图1.1所示。 申请服务 用户 Web服务器 .asp文件 HTTP通信 浏览器 协议文件下载 图 2.1 B/S结构示意图 要运行和开发ASP应用程序,必须安装以下软件: (1) Microsoft Internet Information Service(IIS5.1)及其以上版本。 (2) Microsoft Office Access 2003或以上版本。 (3) Microsoft Internet Explorer 5.0或更高版本。 2.1.4 系统性能需求分析 整个系统规模比较大,信息量大,因此对系统的性能提出了较高的要求。这个系统的性能包括: (1) 可靠性。系统对数据需要有较高的判断能力,在输入数据不合理的情况下能给出错误警告,以避免数据库的数据发生混乱。 (2) 易维护性。随着技术和业务的发展,系统维护需要简单、易行。 (3) 安全性。该系统中数据库起着非常重要的作用,不能随意存取或改动,因此必须对数据库的存取和改动进行严格的控制,对系统数据进行有效的保护,防止对数据库的非法操作,防止计算机病毒对数据的破坏,定期对数据库进行备份。 (4) 可扩展性。该系统是根据目前条件进行设计的,随着周围环境的改善,该系统也应该很容易地被扩展。 (5) 易操作性。本系统是企业人力资源管理系统,直接供企业用户使用,而非计算机专业人员。本系统应该适用于不同水平的使用者,包括企业各级人员,同时系统不应太复杂和烦琐,因此要求系统的操作尽可能简单易行。 6 2.2 开发环境介绍 2.2.1 ASP介绍 本系统采用在Windows XP Professional下基于IIS5.1下的ASP + Access编写。 ASP (Active Server Pages) 是 Microsoft 推出的一种服务器端命令执行环境,ASP内含于IIS中,通过ASP可以轻松地结合 HTML Web 页面、脚本(Script)程序和 ActiveX 组件建立或执行动态、交互式 Web 服务器应用程序。你不需要写入复杂的程序,就可以开发站点应用程序。ASP 让你只要学习使用 VBScript 或 JScript 等简单的 script 语言,结合 HTML 码、ASP 对象和内置或自行制作的 ActiveX Server component(ActiveX 服务器组件),数十条简单的 Script 程序码,即可快速地开发出各种于站点服务器执行的站点应用程序。 选择ASP编程是因为它有着如下的优点: (1) ASP的特点 ? 易用性 ASP使用VBScript 和JavaScript等简单易学的脚本语言,结合HTML代码,即可快速地开发网站的应用程序。而且无须编译即可在服务器端直接执行,使用普通的记事本程序即可实际应用程序。 ? 兼容性 ASP可与任何ActiveX语言兼容,特别是通过plug-in方式,可以使用第三方提供的其它脚本语言。 ? 安全性 ASP的源程序不会被传递到客户浏览器,避免他人剽窃或者修改源程序,从而提高了程序的安全性。 ? 可扩充性 ASP具有无限可扩充性,可以使用Visual Basic、Java 、Visual C++和COBOL等编程语言编写所需要的服务器控件。 (2) ASP的6大内部对象 ASP提供了6个功能强大的内部对象,每个对象具有各自的属性(Property)、方法(Method),有的还拥有数据集合(Collection)与事件(Event),它们共同完成Web中的一些重要工作。这6个对象及其功能描述如表2.2所示。 表2.2 内部对象及其功能 对象名称 功能描述 Request 从客户端取得信息 Response 将信息送给客户端 7 Server 提供一些Web服务器工具 Session 储存在一个Session内的用户信息,该信息仅可被该用户访问 Application 在一个ASP-Application中让不同的客户端共享信息 ObjectContext 配合Microsoft Transaction服务器进行分布式事务处理 (3) ASP访问数据库的原理 ASP是服务器端的脚本执行环境,可用来产生和执行动态的高性能的WEB服务器程序。 当用户使用浏览器请求ASP主页时,WEB服务器响应,调用ASP引擎来执行ASP文件,并解释其中的脚本语言(JScript 或VBScript),通过ODBC连接数据库,由数据库访问组件ADO(ActiveX Data Objects)完成数据库操作,最后ASP生成包含有资料查询结果的HTML主页返回客户端显示。 由于ASP在服务器端运行,运行结果以HTML主页形式返回用户浏览器,因而ASP源程序不会泄密,增加了系统的安全保密性。此外,ASP是面向对象的脚本环境,用户可自行增加ActiveX组件来扩充其功能,拓展应用范围。 (4) ASP页面的结构 ASP的程序代码简单、通用,文件名由.asp结尾,ASP文件通常由四部分构成: 1) 标准的HTML标记:所有的HTML标记均可使用。 2) ASP语法命令:位于<% %> 标签内的ASP代码。 3) 服务器端的include语句:可用#include语句调入其它ASP代码,增强了编程的灵活性。 4) 脚本语言:ASP自带JScript和VBScript两种脚本语言,增加了ASP的编程功能。 2.2.2 Access介绍 Access是一个前后台结合的“软件”。也就是说Access既拥有用户界面;也拥有逻辑、流程处理,即VBA语言;又可以存储数据,即在“表”中存储数据。而所有这些都存储在一个 MDB 格式的文件中(当然,也可以是 MDE 等格式)。因此ACCESS具有快速开发的优点。Access 2003是微软公司推出的Office 2003组件之一,与低版本的Access数据管理系统相比,Access 2003着重加强了在因特网上进行数据交流的功能,同时它还继承了以往界面清晰,操作简单等诸多优点。 Access数据库包含7种对象:表、查询、窗体、报表、Web页、宏和模块。与其它的数据库系统不同的是:Access的每一个对象都不能独立保存,而只能作为Access中的一部分。Access本身即可自动完成对各种文件的管理工作。 8 Access2003就是关系数据库开发工具,数据库能汇集各种信息以供查询、存储和检索。Access 的优点在于它能使用数据表示图或自定义窗体收集信息。数据表示图提供了一种类似于 Excel 的电子表格,可以使数据库一目了然。 Microsoft Access 2003的功能: (1) 数据库窗口 Access2003的“数据库”窗口提供了下列用于查看和处理数据库对象的功能。 使用对象栏:在“对象”栏中可查看数据库对象,新的“对象”栏的纵向排列方式更易于使用。 使用新的对象快捷方式:在数据库窗口中,使用向导可快速创建新的数据库对象, 或是在设计视图中打开一个新的数据库对象。 自定义在数据库窗口中选择及打开对象的方式:选择“工具” “选项” “视图” “数据库窗口中的鼠标动作”,选中“单击打开”单选钮,则可以更改默认的“双击打开”方式。 (2) 数据使用和数据库设计 自动更正字段重命名产生的错误:“名称自动更正”功能可自动更正在为窗体、报表、表、查询、字段、文本框或其他控件重命名时产生的错误。 打印关系:在Access数据库中打印出现在“关系”窗口中的关系的报表。 通过键盘处理关系:通过键盘创建、编辑及删除关系和连接。 使用ActiveX数据对象(ADO):通过任何OLE DB提供者,使用ActiveX数据对象(ADO)访问和处理数据库服务器中的数据。 (3) 窗体和报表 组合文本框和其他控件:使用“格式”菜单中的“组合”命令,可以将窗体或报表上的相关文本框和其他控件组合。 为文本框和其他控件定义条件格式规则:使用“格式”菜单中的“条件格式”命令,可以定义字体颜色、字体大小、控件背景颜色和其他可视信息,这些内容可以为在窗体中输入数据的用户提供反馈。 为SQL Server数据库创建窗体和报表:在Access项目中,为SQL Server数据库创建窗体和报表,所使用的工具与在Access数据库中创建窗体和报表所使用的工具相同。 为没有Access的用户发布报表:将Access报表导出为报表快照(.snp)文件格式。可以使用Snapshot Viewer查看、打印和邮递报表快照。 (4) 工具栏、菜单栏和快捷菜单 使用自定义菜单和工具栏:展开菜单显示所有的命令,选择要添加到自定义菜单的命令。Access2003允许调整菜单和工具栏,以便只将常用的命令和工具栏 9 按钮显示出来。 顺序放置工具栏:如果工具栏上没有足够的空间来显示所需的按钮,可单击“其他按钮”。若希望放置更多控件,可调整工具栏的尺寸。 3 系统设计 3.1 系统总体结构与功能 IT企业人力资源管理系统是非常通用的管理信息系统,是企事业单位实现人力合理有效和办公自动化的前提和基础,本节将对人力资源管理系统进行总体设计,介绍系统的总体功能和模块划分。 3.1.1 系统结构 IT企业人力资源管理系统包含如下主要功能。 (1) 用户认证 对试图访问系统资源的用户进行身份认证(本系统主要有系统管理员、各个部门的管理员和各部门的员工)。 (2) 用户身份管理 为每个用户建立相互之间的关系树,表示每个员工在企业内部的级别、部门等信 10 息以及横向、纵向关系。 (3) 员工权限管理 为整个系统中的不同信息资源进行分类,并对各种信息的访问修改权限进行等级划分,并将权限管理应用于不同身份用户。 (4) 人事信息管理 添加员工的基本信息,包括员工编号、姓名、性别、生日、所在部门等信息。 修改员工基本信息。 删除员工基本信息。 查看员工基本信息。 (5) 人事部门安排管理 员工当前工作安排信息设置,并根据该信息决定员工的工作安排。 添加部门调转信息,包括新部门名称、调转日期、新职务等信息。 修改部门调转信息。 删除部门调转信息。 查看部门调转信息。 (6) 人事流动管理 新增员工、员工离开等行为的设置,要求人事部门和员工能够参与该类行为。 (7) 员工绩效管理 根据员工的基本信息、考勤信息、人事安排等信息,对员工工作绩效进行综合评价。 添加员工考评信息,包括考评日期、被考评人、考评主题、考评结果和考评分数等。 修改员工考评信息。 删除员工考评信息。 查看员工考评信息。 (8) 员工工资管理 根据员工工作绩效,以及员工身份和其他信息,计算员工的工资。 添加薪资调整信息,包括调薪日期、员工姓名、部门名称、调薪原因等。 删除薪资调整信息。 删除薪资调整信息。 查看薪资调整信息。 (9) 员工考勤管理 记录每个员工的考勤记录,迟到、早退、未到等情况,以便对员工进行考核、工作绩效考评等。 设置考勤时间。 11 日考勤统计信息。 月考勤统计信息。 (10) 公文、通告的管理 主要是发布一些企业的公文资料,以便每个员工对企业的制度更了解,通告主要是对某些员工的成绩等进行表扬和批评以及一些企业对每个员工的通知等消息。 公文、通告的管理。 公文、通告的发布。 公文、通告的浏览。 (11) 档案资料的管理 主要是对企业内部的档案资料进行管理。 档案资料类别的管理。 档案资料的录入。 档案资料库。 (12) 企业资源的管理 主要是对企业的一些公用资源进行管理,以便员工能够很好的利用。 系统的总体功能模块如图3.1所示。 用户身份权限的认证 用户身份的管理 员工权限管理 人人员员员公档企 事事工工工文案业 信流绩工考、资资 息动效资勤通料源 管管管管管告的的 理 理 理 理 理 的管管 管理 理 理 图3.1 系统总体模块关系图 3.1.2 系统各功能内容简介及主要功能模块分析 进入系统主界面后,主要划分为5个区域,包含了该设计需要的主要功能模块,以下主要介绍本人负责的个人办公区域和系统设置管理两大块,还有部分系统界面的设计。 12 (1) 用户认证 用户登陆系统时,会提示输入用户名和密码,当用户输入用户名和密码时,系统会把用户输入的数据和存在数据库中的数据进行比对,核实正确后,用户登陆系统,否则提示错误。 运行系统 输入用户名和密码 存在正确 不存在或错误 查询存在且正确 进入系统 提示错误,重新输入 图3.2 用户登陆流程图 (2) 用户身份管理 为系统中的每个用户建立相互之间的关系,表示每个员工在企业内部的级别、部门等信息以及他们之间横向和纵向的关系。系统管理员负责分配系统中的每个用户的管理权限以及添加和删除用户,是整个系统中的第一层用户。第二层用户是各个部门的经理,他们具有系统管理员分配的权限以及管理本部门员工的权限,各个部门之间是平等相互的关系。最后一层用户是每个部门的员工,每个员工具有最基本的权限,不能修改删除个人信息。 13 系统管理员 管理修改 删除 添加 已技人市( 新 存术事场( 用 在部部部( 户 用门门门 户 经经经 理 理 理 管管管管 理 理 理 理 其他部门员工 技术部员工 人事部员工 市场部员工 图3.3 系统用户关系示意图 (3) 员工权限管理 为整个系统中的不同信息资源进行分类,并对各种信息的访问修改权限进行等级划分,并将权限管理应用于不同身份用户。系统管理员具有用户管理权限,负责管理整个系统的用户,包括添加、删除、修改每个用户的权限。管理员还具有 工作计划 幼儿园家访工作计划关于小学学校工作计划班级工作计划中职财务部门工作计划下载关于学校后勤工作计划 权限、系统维护权限、帮助管理权限等等,同时他还赋予考勤管理权限、员工基本档案权限以及员工的奖惩、考核、工资编辑权限给人事管理专员。人事专员管理每个部门的经理权限,每个部门的经理管理本部门员工的权限。 14 用户管理权限 应用 系统管理员 分配 具有 基奖考通公帮系工 本惩勤告文助统作 档、管管管管维计 案考理理理理护划 权核权权权权权权 限 限 限 限 限 限 限 、 工 资 编 辑 权 限 具有 各部门经理 人事管理专员 管理 图3.4 员工权限关系示意图 (4) 工作计划模块 工作计划模块包括个人工作计划和员工工作任务分配。 个人工作计划主要是系统管理员对自己的最近几天进行任务安排计划,以便提醒自己不要忘记,可随时浏览,如今天的工作计划在系统管理员登陆系统后就可看到提醒,如果今天没有工作计划,登陆系统后就不会显示,系统管理员也可添加和修改自己的工作任务。 15 用户 编辑 设置 员工工作任务 个人工作计划 图3.5 工作计划关系示意图 (4) 通告管理模块 通告管理模块包括发布、管理、浏览通告。 发布通告的内容主要是对员工业绩的表扬和批评和一些企业的及时消息(通告标题应是大于1位小于50位),当正确的填写了通告内容后点“发布”,即可返回“新通告成功发布”的页面。 通告信息管理子模块主要是系统管理员对发布的通告进行删除等编辑,如果通告是在当日发布的,会在通告标题后面有“NEW”图片的提示,方便大家的浏览查看最新的通告。 浏览通告子模块主要是对所有的历史通告进行查看阅读,该模块只具有查看相关内容链接的功能。 系统管理员 发管浏 布 理 览 通告 图3.6 通告管理关系示意图 (5) 公文管理模块 16 公文管理模块主要包括公文管理、发送公文、已发公文和已收公文。 公文管理模块主要包括对已发布的公文进行删除等编辑管理,其中系统管理员还可以 对公文类型进行添加,删除,修改等操作。 系发送 统 公管 文 理 员 管理 接收 其他企业 部门 部门 发送 图3.7 公文管理关系示意图 (6) 人力管理模块 人力管理模块是整个系统的主要模块,包括了个人基本档案、员工基本档案、员工职位变动、员工奖惩情况、员工考核情况、员工工资档案。该模块记录了企业每个员工的基本情况,并且系统会根据的员工的考核,奖惩等情况来对员工的工资进行设置,不仅保证了员工本身的公平、透明,更能有效的激励员工,对企业也是很大的帮助。 17 人事专员 管理 个员员员员员 人工工工工工 基基职奖考工 本本位惩核资 档档变情情档 案 案 动 况 况 案 图3.8 人事管理关系示意图 (7) 考勤管理模块 考勤管理模块是本设计的另外一个重要的模块,它包括了整个企业的所有员工的每天的考勤记录,其中每天会有专员对每个员工进行日考察记录,等月末的时候会有一张月统计记录情况表,它把每个员工的这个月的考勤记录如实的反映。考勤管理不仅可以记录员工每天的上班情况,企业还可以根据这个月的考勤统计表来对员工进行考核、以及作为计算工资的一个具体依据。该模块包括设置考勤时间、日考勤统计和月考勤统计等。其中设置考勤时间是系统管理员的权限,他对本企业的上班和下班时间做了明确的规定,一般不做改动。 每天的考勤统计由负责考勤的工作人员来进行,分别对各个部门的每个员工进行考勤,考勤记录是一个企业必不可少的工作,所以考勤工作人员必须每天按时准确的对每个员工进行考勤统计。 月考勤统计是负责考勤的工作人员把本月每天的每个员工的考勤记录统计成一张表,便于计算员工的这个月的迟到、早退、未到的次数。 系统管理员 管理设置 日考勤统计 考勤时间 月考勤统计 18 图3.9 考勤管理关系示意图 3.2 数据库设计 数据库在一个管理信息系统中占有非常重要的地位,数据库结构设计的好坏将直接对应用系统的效率以及实现的效果产生影响。合理的数据库结构设计可以提高数据存储的效率,保证数据的完整和一致,同时,合理的数据库也将有利于程序的实现。 设计数据库系统时应该充分了解用户各个方面的需求,包括现有的以及将来可能增加的需求。 3.2.1 数据库的需求分析 所谓的“数据库”是指依照一定的格式存放在一起的数据记录文件。数据库以数据作为工作对象,指为了满足某种特定应用的需要,按照一定的数据模型在计算机系统中组织、存储和使用数据的数据集合。数据库系统就是管理大量的、持久的、可靠的和共享的数据的工具。 Access数据库的建立方法可以分成两个阶段,第一个阶段是根据要输入的数据性质,新增表并设置表的字段名称、数据类型和语句,第二个阶段是在表内输入数据。 根据系统需求,可以列出以下数据项和数据结构: 公文信息:包括标题、发布时间、公文内容、公文序号等。 文件上传索引:包括关键字、文件名、文件大小、内容所在地址等。 文件类型信息:包括文件类型名等。 考勤信息:包括上午开始考勤时间、上午结束考勤时间、下午开始考勤时间、下午结束考勤时间等。 每月考勤信息:包括用户名、员工姓名、职位、考勤时间、到达时间、离开时间、迟到原因等。 3.2.2 数据库的表设计 本系统采用两种数据存储方式,一种是把数据保存在cookies,一种是把数据保存在Access表中,以下介绍保存在Access中的各表。 (1) 用户信息表 表3.1 用户信息表 19 (2) 公文信息表 表3.2 公文信息表 (3) 员工信息表 表3.3 员工信息表 (4) 文件上传索引表 表3.4 文件上传索引表 20 (5) 考勤信息表 表3.5考勤信息表 (6) 每月考勤信息表 表3.6 每月考勤信息表 表3.5是1月份的考勤信息表,每月的考勤表与此表相同。 4 程序设计 系统用Microsoft Access设计数据,以Dreamweaver MX 2004为开发平台,通过Asp实现网页及动态操作,其中运用了Java Script和VB Script脚本,基本实现其功能。以下介绍本人完成模块的主要程序设计。 4.1 登陆系统模块 当我们建立了一个完整的系统时,尤其是运用于一个企业管理的系统,对于进入每个系统的人员我们都要对他进行身份验证,因为该系统是保护企业内部资料以及每个员工基本信息的,我们当然不希望有任何人进入该系统进行恶意的破坏,对系统中的数据进行修改,维护该系统的系统管理员也不希望有任何麻烦,所以对系统进行安全保护显的很重要,无论对于谁,系统的安全问题是首要的。 为了解决这个问题,有一个简单、实用,但是老套的方法,就是口令加密。 21 在此我们使用ASP技术对口令加密。简单的讲,就是将用户提供的口令加密之后,然后让它和存放于系统中的数据比较,如果相同,则通过验证,否则该用户就不允许进入。 在ASP中,只能使用外部的对象来进行加密。在本系统中,我设计用户名,密码等信息存储在数据库里,当用户输入用户名和密码的时候系统会使用conn.asp来和数据库进行连接查询,如果相同,则通过验证进入系统。也可以存储在cookies中,因为查询存在cookies中的数据使用的时间较少,不用重复查询数据库中数据,这样减轻了程序冗余的压力。 模块功能:用户身份认证 实现页面:default.asp 数据定义:username,password 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select * from userinf where username=" & sqlstr(username) & " and password=" & sqlstr(password) & " and forbid='no'" 4.2 工作计划模块 该模块主要是实现安排个人工作计划和增加员工工作任务。当系统管理员增加工作任务时,首先在数据库userinf中查找该员工的用户名,存在则增加工作任务,包括用户名、工作任务的日期、工作任务的标题等。 模块功能:个人工作计划和增加员工工作任务 实现页面:addworkrep.asp 数据定义:title,recdate,username,superior,remark,imp,finished 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select name from userinf where username=" & sqlstr(username) sql = "Insert Into workrep (username,recdate,title,remark,superior) Values( " sql = sql & SqlStr(username) & ", " sql = sql & "#" & recdate & "#" & ", " sql = sql & SqlStr(title) & ", " sql = sql & SqlStr(remark) & ", " 22 sql = sql & SqlStr(superior) & ")" 4.3通告管理模块 系统管理员发布通告时,在数据库newnotice中插入发送者用户名、新通告 的标题和描述事件等,当删除通告的时候,取得该通告发布的时间,然后在数据库中删除该通告的所有内容。 通告管理模块包括发布通告、管理通告和浏览通告3个子模块。 (1) 子模块1 模块功能:发布通告 实现页面:broadcast_notice.asp 数据定义:sendusername,title,content,noticedate,readuserid,sort 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") 2) 数据库查询 sql = "Insert Into newnotice (sendusername,title,content) Values( " sql=sql & SqlStr(oabusyusername) & "," sql = sql & SqlStr(title) & ", " sql = sql & SqlStr(content) & ")" (2) 子模块2 模块功能:管理通告 实现页面:manage_notice.asp 数据定义:sendusername,title,content,noticedate,readuserid,sort 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=Server.CreateObject("ADODB.recordset") 2) 数据库查询 '删除数据库中的记录 sql = "delete * from newnotice where " & condition sql="select * from newnotice order by id desc" (3) 子模块3 模块功能:浏览通告 实现页面:looknotice.asp 数据定义:sendusername,title,content,noticedate,readuserid,sort 23 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=Server.CreateObject("ADODB.recordset") 2) 数据库查询 sql="select * from newnotice order by id desc" 4.4 公文管理模块 公文管理模块包括管理公文、发送公文、已发公文和已收公文。主要是传递 企业内部部门之间的一些公文。 模块功能:管理公文、发送公文、已发公文和已收公文 (1) 子模块1 模块功能:管理公文 实现页面:article_managel.asp 数据定义:senddate,texttype, senddate.documenttype,texttype.number,sender, recipientusername 关键代码: 1) 数据库连接ADO set rs=Server.CreateObject("ADODB.recordset") 2) 数据库查询 sql="select * from senddate,texttype where reid=0 and senddate.documenttype=texttype.number order by id desc" sql="select name from userinf where username=" & sqlstr(rs("sender")) sql="select name from userinf where username=" & sqlstr(rs("recipientusername")) (2) 子模块2 模块功能:发送公文 实现页面:sendarticle.asp 数据定义:userdept,name,username 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select DISTINCT userdept from userinf" sql="select name,username from userinf where userdept=" & sqlstr(firstdept) & " and forbid='no'" (3) 子模块3 24 模块功能:已发公文 实现页面:havesendarticle.asp 数据定义:senddate,texttype, senddate.documenttype,texttype.number,sender, recipientusername 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=Server.CreateObject("ADODB.recordset") 2) 数据库查询 sql="select * from senddate,texttype where senddate.sender=" & sqlstr(oabusyusername) & " and senddate.reid=0 and texttype.number=senddate.documenttype order by id desc" sql="select name from userinf where username=" & sqlstr(rs("recipientusername")) (4) 子模块4 模块功能:已收公文 实现页面:haverecievearticle.asp 数据定义:senddate,texttype, senddate.documenttype,texttype.number,sender, recipientusername 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=Server.CreateObject("ADODB.recordset") 2) 数据库查询 sql="select * from senddate,texttype where (senddate.recipientusername=" & sqlstr(oabusyusername) & " or (senddate.recipientusername='所有人' and senddate.recipientuserdept=" & sqlstr(oabusyuserdept) & ")) and senddate.sender<>" & sqlstr(oabusyusername) & " and senddate.reid=0 and senddate.documenttype=texttype.number order by id desc" sql="select name,userdept from userinf where username=" & sqlstr(rs("sender")) 4.5 人力管理模块 人力管理模块包括了删除、编辑和修改个人基本档案、员工基本档案、员工 职位变动、员工奖惩情况、员工考核情况、员工工资档案。 模块功能:个人基本档案、员工基本档案、员工职位变动、员工奖惩情况、员工 考核情况、员工工资档案 (1) 子模块1 模块功能:基本档案 实现页面:Doc_Manage.asp, Doc_Display.asp, Doc_Edit.asp, Doc_Find, Doc_Input, 25 Doc_List, TypeManage 数据定义:username,inputdate,updatedate,a1,…a33,photo 关键代码: 1) 数据库连接ADO set conn=openconn("conn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 SQL="insertinto ContentTable(TypeName,Title,KeyWord,Dept,SendDate,AvailabilityDate,Content) values("&sqlstr(Doc_TypeName)&","&sqlstr(Doc_Title)&","&sqlstr(Doc_KeyWord)&","&sqlstr(Doc_Dept)&",#"&Doc_SendDate&"#,#"&Doc_SxDate&"#,"&sqlstr(Doc_Content)&")" (2) 子模块2 模块功能:职位变动 实现页面:addchangjob.asp 数据定义:oldjob, changjob, changdate, changfile, changsort, changtype, changreason, recusername, pdateusername 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select name from userinf where username=" & sqlstr(request.form("username")) sql="InsertIntochangjob (username,oldjob,changjob,changdate,changfile,changsort,changtype,changreason,recusername,updateusername) Values( username, oldjob, changjob, changdate, changfile, changsort, changtype, changreason, recusername, pdateusername) (3) 子模块3 模块功能:奖惩情况 实现页面:punish.asp 数据定义: username,rewpunname,rewpundate,rewpunfile,rewpunsort,rewpuntype,remark, recname,recdate,updatename,updatedate 关键代码: 1) 数据库连接ADO 26 set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select * from rewpuninf where username=" & sqlstr(username) (4) 子模块4 模块功能:考核情况 实现页面:rewpuninf.asp 数据定义: username,rewpunname,rewpundate,rewpunfile,rewpunsort,rewpuntype,remark, recname,recdate,updatename,updatedate 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select allow_edit_all_rewpuninf from userinf where username=" & sqlstr(oabusyusername) sql="select DISTINCT userdept from userinf" sql="select name from userinf where username=" & sqlstr(username) sql="select * from rewpuninf where username=" & sqlstr(username) (5) 子模块5 模块功能:工资档案 实现页面:salary.asp 数据定义:wagelevel,baselevel,stafjob,workyear,workyearwage,rentwage,carwage, prize,insurance,… 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select * from userinf where username=" & sqlstr(oabusyusername) sql="select DISTINCT userdept from userinf" sql="select name,username from userinf where userdept=" & sqlstr(firstdept) & " and forbid='no'" sql="select name from userinf where username=" & sqlstr(username) 27 sql="select * from wageinf where username=" & sqlstr(username) 4.6 考勤管理模块 考勤管理模块主要包括设置考勤时间和记录每天的考勤情况,设置考勤时间是把已存在数据库中的时间数据进行修改,调用数据库中inittime进行修改。 查看今天的考勤记录信息流程如下图所示: Begin case no amall amandcome amallandpmcome amandpm getamexplain disposeamcometime N amgonokq=0 Y disposeamgotime N pmcomenokq=0 Y disposepmcometime N pmgonokq=0 Y End disposepmgotime 图4.1 查看今日考勤流程图 模块功能:设置考勤时间、开始考勤、今日考勤统计、日考勤统计、月考勤统计等。 28 (1) 子模块1 模块功能:设置考勤时间 实现页面:settime.asp 数据定义: amcometime,amoffdutytime,amgotime&,pmondutytime,pmcometime&,pmoffdutytime, pmgotime&,ondutydelaytime,comedelaytime,offdutyaheadtime,goaheadtime,kqtimephase,&kqtimephase&,amgonokq,&amgonokq,pmcomenokq,pmcomenokq,pmgonokq,pmgonokq 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="updateinittimeset amondutytime=#"&amcometime&"#,amoffdutytime=#"&amgotime&"#,pmondutytime=#"&pmcometime&"#,pmoffdutytime=#"&pmgotime&"#,ondutydelaytime="&comedelaytime&",offdutyaheadtime="&goaheadtime&",kqtimephase="&kqtimephase&",amgonokq="&amgonokq&",pmcomenokq="&pmcomenokq&",pmgonokq="&pmgonokq (2) 子模块2 模块功能:开始考勤 实现页面:nowkqinfo.asp 数据定义: amcometime,amoffdutytime,amgotime&,pmondutytime,pmcometime&,pmoffdutytime, pmgotime&,ondutydelaytime,comedelaytime,offdutyaheadtime,goaheadtime,kqtimephase,&kqtimephase&,amgonokq,&amgonokq,pmcomenokq,pmcomenokq,pmgonokq,pmgonokq 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select DISTINCT userdept from userinf" sql="select name,username from userinf where userdept=" & sqlstr(userdept) sql="select * from inittime" (3) 子模块3 模块功能:日考勤统计 29 实现页面:daykqinfo.asp 数据定义: amcometime,amoffdutytime,amgotime&,pmondutytime,pmcometime&,pmoffdutytime, pmgotime&,ondutydelaytime,comedelaytime,offdutyaheadtime,goaheadtime,kqtimephase,&kqtimephase&,amgonokq,&amgonokq,pmcomenokq,pmcomenokq,pmgonokq,pmgonokq 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select name,username from userinf where userdept=" & sqlstr(userdept) sql="select * from inittime" (4) 子模块4 模块功能:月考勤统计 实现页面:monthkqinfo.asp 数据定义: amcometime,amoffdutytime,amgotime&,pmondutytime,pmcometime&,pmoffdutytime, pmgotime&,ondutydelaytime,comedelaytime,offdutyaheadtime,goaheadtime,kqtimephase,&kqtimephase&,amgonokq,&amgonokq,pmcomenokq,pmcomenokq,pmgonokq,pmgonokq 关键代码: 1) 数据库连接ADO set conn=opendb("oabusy","conn","accessdsn") set rs=server.createobject("adodb.recordset") 2) 数据库查询 sql="select DISTINCT username,name from userinf where userdept='"&userdept&"'" sql="select DISTINCT userdept from userinf" 30 5 系统实施和维护 本次系统设计完成后,尽管在设计的时候已经分别测试了系统的各个模块,但这并不能保证把它们结合成一个整体时系统也同样会正常工作。因此,最后需要完成整个系统的测试。在此期间,我们将测试运行信息系统,整理开发过程中编写的各个模块,以便通过质量认证和验收。为了保证企业人力资源管理系统的质量和可靠性,在分析、设计等各个开发阶段结束前,对它进行严格的技术评审。 5.1系统测试 本系统是非常具有代表性的企业管理信息系统,企业内部服务对象是企业内的员工,运行的环境为企业的内部网络,因此需要设置一台Web服务器,用于运行本系统。并安装Microsoft Office Access 2003作为后台数据库。 5.1.1 IIS的安装 Internet Information Sever)是Microsoft公司主推的Web服务器。在IIS( Windows XP安装光盘中包含IIS5.1。IIS与Windows NT Sever 完全集成在一起,所以用户能够利用Windows NT Server和NTFS内置的安全特性,建立强大、灵活而安全的Interner 或Intranet站点。IIS的一个重要特性是支持ASP。 在Windows XP Professional版中,需要手动安装IIS方法如下: (1)依次选择“开始”/“设置”/“控制面板”/“添加/删除程序”,打开“添加/删除程序”对话框。 (2)单击左侧的“添加/删除Windows组件”按钮,打开“Windows组件向导”对话框,如图5.1所示。 31 图5.1Windows组件向导 (3)选中“Internet信息服务(IIS)”,然后单击“下一步”按钮。安装IIS需要13.4MB的磁盘空间。 安装程序开始配置组件并复制文件,安装过程将持续一段时间,安装完毕后,打开“控制面板”中的“管理工具”页面,可以看到“Internet服务管理器”图标。双击此图标,将打开IIS管理窗口,在IIS窗口中可以看到,使用IIS可以管理Web站点等。 在左侧窗格中选择“默认Web站点”节点,在右侧的窗格中将会显示默认Web主目录下的目录和文件信息。如图5.2所示。 图5.2 IIS管理窗口 在“Web站点”选项卡中,可以设置Web站点的IP地址和TCP端口,默认的端口号为80。单击“主目录”选项卡,可以设置Web站点的主目录,缺省情况下,主目录为C:\inetpub\wwwroot。可以将主目录设置为本地计算机上的其他 32 目录,也可以设置为其他计算机上的目录或者重定向到其他网址。 图5.3 设置Web站点的主目录 5.1.2 后台数据库的配置 后台数据库可以使用SQL Server或Access,数据库服务器和web服务器可以配置在同一台计算机上,也可以在两台计算机以上,以上两种情况对于开发的过程来说是类似的,只需在web服务器上配置好ODBC的系统数据源就可以了。本系统是在Windows XP professional下开发的,开发数据库使用的是Access 2003。 建立一个ODBC数据源,步骤如下: (1) 选择“控制面板”中的“ODBC数据源管理”选项,选择“系统DSN”选项卡,单击“添加”按钮。 图5.4 ODBC数据源管理器 (2) 在“创建新数据源”窗口中,选择“Driver do Microsoft Access(*.mdb)”作为数据库的驱动程序,然后单击“完成”按钮。 33 图5.5 创建新数据源 (3) 在“ODBC Microsoft Access安装”窗口中,数据源名称为“new” 。 这是asp程序中将要引用的。单击“选择„„”按纽,从弹出的文件窗口中选择new.mdb文件所在位置,其他选项不改变。 图5.6 ODBC数据源的安装 (4) 单击“确定”按钮,就完成了Access数据库的ODBC数据源配置。 以下是测试用户登陆系统的结果(测试数据:username:admin,password:admin),表明测试成功。 图5.7 登陆系统界面 图5.8是编辑员工档案的界面,编辑成功。 34 8 编辑员工档案界面 图5. 图5.9是编辑员工职位变动信息界面,编辑成功。 图5.9 员工职位变动信息界面 图5.10是增加员工奖惩情况界面,增加成功。 图5.10 员工奖惩情况界面 图5.11是编辑员工考核档案界面,编辑成功。 35 图5.11 编辑员工考核档案界面 图5.12是编辑员工工资档案界面,编辑成功。 图5.12 编辑员工工资档案界面 图5.13是管理公告信息的界面,测试成功。 图5.13 管理公告信息界面 36 以上各个模块测试基本符合要求,达到了系统的需求,系统测试成功。 5.2 系统维护 尽管系统能够按照我们设计的运行了,但是也有我们存在的不足,说不定什么时候在运行的时候就会凸显出来,这就需要我们对系统不断的进行维护和管理,加强系统的安全技术,增进系统的功能,完善系统的浏览界面,是每个用户都能够方便的使用该系统,尤其对于一个企业,我们设计基本属于一个通用企业的人力资源管理的系统,在该系统中我们没有太多考虑IT这个字眼,基本符合了一个小型企业人力管理的要求。 6 设计总结与心得 本次设计的主要目的是用ASP这种服务器端脚本语言,进行网络编程。开发基于Web的企业人力资源管理系统。本文围绕开发IT企业人力资源管理系统的页面设计、用户操作、管理员管理等部分,实现系统的技术 方案 气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载 。并在此基础上,了解了系统实现的关键部分及其实现原理。主要的研究成果体现在以下几个方面: (1) 经过阶段性的可行性分析研究,设计出了本平台系统的动态主页面,为用户提供一个友好的Web浏览界面。 (2) 进行了B/S模式下的企业人力资源管理的需求分析,确定了B/S模式下的系统的一般需求,并在此基础上得出了系统开发目标,提出了系统和各子模块的功能组成,设计了B/S模式下的系统的总体模块、数据库开发与设计。 (3) 对B/S模式下的系统的各子模块的结构和用户功能进行了分析和设计。 (4) 完成了B/S模式下的系统的用户操作页面、管理员管理页面等部分的设计工作,提出了实现其关键部分的技术解决方法。 (5) B/S模式下的系统的总体构架和特点,实现了预期任务书各点功能并对其中的特点有了详细的了解。 (6) 阶段性的训练,对总体设计思路的掌握,动手能力,分析和发现问题等能力都得到加强。 (7) 完成了系统的功能设计,使得自己对B/S的应用和开发动态网站技术有一定收获和经验。 由于所使用的开发语言是我第一次接触使用,很多功能我还不能完全熟练灵 37 活的运用,但通过这次毕业设计我学习到了很多知识,了解了建立一个MIS(管理信息系统)的开发过程和具体步骤,真正收获了不少知识。 总之,这次毕业设计是很成功的。通过这次毕业设计,我不仅掌握了许多新知识,更为重要的是,我的自学能力和把所学知识应用于实践的能力也有了很大的提高,为今后的学习和工作奠定了良好的基础。 谢 辞 时间如梭,大学四年马上就要结束了,在这四年的学习生活中,我学习到了很多知识,专业知识方面更是有了很大的提高,是我这一生当中最宝贵的财富,是不断超越自我的历程。在这最后的阶段,我衷心的向学校的各位老师和我的同学表示我最衷心的感谢,感谢他们在这四年当中对我的帮助和关心。 很感谢学校能够提供我们这个锻炼自我的机会,给我们一个能够使大学四年所学到的知识加以实践的机会。 感谢从大一到大四所有的授课教师,他们孜孜不倦的教导我们,使我们真正的学习到了知识。 感谢我的毕业设计辅导老师,王珏老师,在他的帮助下我们才能顺利的完成这次设计,他耐心的辅导我们,对待我们提出的任何问题都耐心的帮助作答,我真的很感谢王珏老师。 更感谢我的同组设计同学高平伟同学,在他的大力合作和帮助之下,我们合理的分工,我们才能顺利有效的完成这次设计,没有他的努力,就没有我们的成果 最后感谢帮助过我的每一个人,没有他们就没有我的今天。 38 参 考 文 献 [1] 启明工作室(MIS系统开发与应用(ASP+SQL Server版)(北京:人民邮电出版社,2005 [2] 刘臣宇,朱海秦(管理信息系统的开发与应用(国防科技出版社 [3] 王龙,黄峰(ASP管理信息系统项目开发实践(科学出版社 [4] 李严,于亚芳,王国辉(ASP数据库开发实例解析(北京:机械工业出版社,2005(1 [5] 周宏敏,高翔,朱敬(新世纪Dreamweaver MX 2004应用培训教程(北京:电子工业出版社,2004 [6] 胡绪英,李梓,郑传生(Access 2003数据库技术及应用(北京:科学出版社,2003 [7] [美]Eric A. Smith(Active Server Pages宝典(电子工业出版社,2000(5 [8] 网冠科技(动态网页设计师ASP(机械工业出版社,2001(1 [9] 林志强(ASP电子商务设计实务(中国铁道出版社,2000(1 [10] A.Keyton Weissinger(ASP in a Nutsbell(中国电力出版社,2001 [11] 天创工作室(ASP网页制作实战步步通(人民邮电出版,2001(6 [12] 石志国 王志良等(ASP精解案例教程(清华大学出版社,2004(1 39 附录A 外文翻译—原文部分 SQL server User-defined Functions Auser-defined function (UDF) is a prepared code segment that can accept parameters, process some logic, and then return some data. According to SQL Server Books Online, UDFs in SQL Server? 2000 can accept anywhere from 0 to 1024 parameters, although I must confess I have never tried to pass 1024 parameters into a UDF. Another key characteristic of UDFs is that they return a value. Depending on the type of UDF, the value can be used by the calling routine to continue processing its data. Thus, if a UDF returns a single value (a scalar value), the calling routine can use that value anywhere a standard variable or a literal value can be used. If a UDF returns a rowset, the calling routine can loop through the rowset, join to it, or simply select columns from it. While most programming languages have supported functions for a while now, UDFs were only introduced with SQL Server 2000. Stored procedures and views have been available in SQL Server much longer than UDFs, but each of these objects has their niche in SQL Server development. Stored procedures are great for processing complex SQL logic, securing and controlling access to data, and returning a rowset to a calling routine whether that routine is a 40 Visual Basic?-based program or another Transact-SQL (T-SQL) batch. Unlike views, stored procedures are compiled, making them ideal candidates to represent and process frequently run SQL statements. Views are great for controlling access to data, but they do it differently than stored procedures. Views are limited to only certain columns and rows from the underlying SELECT statement that generated the view. Thus a view is often used to represent a commonly used SELECT statement that may join several tables, employ a WHERE clause, and expose specific columns. Views are often found in the FROM clause of a SQL statement joined to other tables and views. At their core, UDFs resemble both views and stored procedures. Like views, UDFs can return a rowset that can be used in a JOIN. Therefore, when a UDF returns a rowset and accepts parameters, it's like a stored procedure that you can join to, or a parameterized view. But, as I will demonstrate, UDFs can be this and much more. There are two main types of UDFs: scalar value-returning UDFs and table value-returning UDFs. Within table value UDFs you'll find UDFs that return inline tables and multistatement tables.In the following sections I'll take a look at each. Scalar value-returning UDFs are most similar to what many programming languages refer to as functions. They return a single value consisting of a scalar datatype such as integer, varchar(n), char(n), money, datetime, bit, and so on. UDFs can also return user-defined datatypes (UDDTs) if they are based on a scalar datatype. With UDFs that return either inline or multistatement tables, a rowset can be returned via the table datatype. However, not all datatypes can be returned from UDFs. For example, a UDF cannot return a value of any of these datatypes: text, ntext, image, cursor, or timestamp. Scalar datatype-returning UDFs can be used in various situations to make the code more maintainable, reusable, and less complex. This can be very useful when the same segment of T-SQL code is used in several places, perhaps by several stored procedures and batch SQL statements. For example, let's say several parts of an application need to find whether a product must be reordered. In each of the places this is required, the code could check the reorder level and compare it to the units in stock plus the number of units on order. However, since this code is used in several places, a UDF could be used instead to reduce the code blocks and make it easier to maintain this function in case it ever needs to change. Such a UDF might look something like the code in and could be called with the following SQL statement: SELECT ProductID, ReorderLevel, UnitsInStock, UnitsOnOrder, 41 dbo.fnNeedToReorder(ReorderLevel, UnitsInStock, UnitsOnOrder) AS sNeedToReorder FROM Products the fnNeedToReorder UDF performs the calculation and returns the appropriate value. This could have been accomplished via a CASE statement inside the SELECT clause, but the code is much more compact when a UDF is used instead. Plus it's easier to propagate to other places that may require the same logic. Assuming that there are several sections of an application that need to determine whether to reorder products, the UDF in really becomes valuable as it makes the application easier to maintain when the logic changes. For example, it doesn't make a lot of sense to reorder a product that has been discontinued. Thus, by changing the UDF in order to account for this business rule, the logic is changed in one place , and can be run with the following code: SELECT ProductID, ReorderLevel, UnitsInStock, UnitsOnOrder, dbo.fnNeedToReorder(ReorderLevel, UnitsInStock, UnitsOnOrder, Discontinued) AS sNeedToReorder FROM Products Notice that the UDF is called using the two-part name of object owner and object name. The object's owner is required when using a UDF that returns a scalar datatype value. Granted, by adding the fourth parameter (Discontinued) to the UDF, all of the places that call the UDF must also be changed. For easier maintenance, I could rewrite the UDF to retrieve the data itself using the ProductID for each row, This technique is easier to maintain because it does not require any of the calling routines to change how the UDF is called when the logic changes—as long as the data can be pulled in from the current Products table row. However, to gain this maintainability there is a performance trade-off. The UDF has to retrieve a row from the Products table for every row that is returned from the calling routine. Since the calling routine is retrieving every row from the Products table already, if the table has 77 rows, the code will execute 77 SELECT statements, one for each row returned from the main SELECT statement. While each SELECT is selecting based on the primary key field (ProductID) and hence is very fast, performance can be adversely affected when the rowset is very large or the SELECT statement is less efficient. The code in can be called by using the following SQL snippet: SELECT ProductID, ReorderLevel, UnitsInStock, 42 UnitsOnOrder, dbo.fnNeedToReorder(ProductId) AS sNeedToReorder FROM Products An alternative to using this function in a SELECT statement is to create a computed column in the Products table called NeedToReorder. This column would be defined not as a datatype but as the return value of the fnNeedToReorder UDF from. To add this column, I can alter the Products table as follows to indicate that the column should be computed: ALTER TABLE Products ADD NeedToReorder AS dbo.fnNeedToReorder(ReorderLevel, UnitsInStock, UnitsOnOrder, Discontinued) This way the column is defined in the table itself, but is automatically calculated using the UDF. Common UDFs and Nesting Thus far I have shown several ways to tackle the same issue using a UDF that returns a scalar value. There are other useful applications of UDFs including functions that are not readily available in T-SQL. One example is a specialized formatting function. For instance, phone numbers are commonly stored without their formatting characters in char(10) columns that represent the area code and phone number (assuming it's a United States number). A UDF could be used to retrieve the phone number in a formatted structure. Thus, retrieving and formatting a phone number is as simple as this: SELECT dbo.fnCOM_FormatTelephoneNumber ('3335558888') Any common function can be created using this technique to augment the regiment of functions available in SQL Server. Another example is a function that formats a date to the MM/DD/YYYY format with leading zeros: CREATE FUNCTION fnCOM_StandardDate (@dtDate DATETIME) RETURNS VARCHAR(10) AS BEGIN RETURN dbo.fnCOM_2Digits (CAST(MONTH(@dtDate) AS VARCHAR(2))) + '/' + dbo.fnCOM_2Digits (CAST(DAY(@dtDate) AS VARCHAR(2))) + '/' + CAST(YEAR(@dtDate) AS VARCHAR(4)) END The fnCOM_StandardDate UDF accepts a datetime value and returns a varchar(10) in a MM/DD/YYYY format. Pretty simple, of course, and if your application requires a particular format often, this technique could make it easier to maintain. One key component to notice in the 43 previous code is the use of a nested UDF. The fnCOM_StandardDate UDF calls the fnCOM_2Digits UDF (shown in the next sample) twice, both times to put a leading zero in front of days or months less than 10. CREATE FUNCTION fnCOM_2Digits (@sValue VARCHAR(2)) RETURNS VARCHAR(2) AS BEGIN IF (LEN(@sValue) < 2) SET @sValue = '0' + @sValue RETURN @sValue END UDFs can be nested within each other as long as the inside UDF is created first. One catch with nesting functions is that built-in functions that are nondeterministic, such as the getdate function, cannot be nested inside of another UDF (otherwise, a SQL Server error is raised). A nondeterministic function is one which may not return the same result when called multiple times with exactly the same parameters. The getdate function falls into this category since every time it is called, it returns the new current date and time. Another commonly used nondeterministic built-in function is the NewID function. It is also nondeterministic as it always returns a unique GUID and, as such, the NewID function is not allowed to be nested within a UDF. Table-valued UDFs Within the category of table-valued UDFs there are two sub-types: inline table value-returning UDFs and multistatement table value-returning UDFs. UDFs that return inline tables return a rowset via the SQL Server table datatype. They are defined with a single SELECT statement making up the body of the function. Inline table value-returning UDFs cannot contain additional T-SQL logic outside of the SQL SELECT statement that defines the table it will return. However, they are simpler to create than UDFs that return multistatement tables since they do not have to define the exact table structure to be returned. UDFs that return inline tables extrapolate the structure of the rowset from the SELECT statement itself. Thus, the columns that the UDF will return are determined by the columns in the SELECT list. The following code shows the fnGetEmployeesByCity UDF, which accepts a city and returns a table containing all employees' first name, last name, and address: CREATE FUNCTION fnGetEmployeesByCity (@sCity VARCHAR(30)) RETURNS TABLE AS 44 RETURN ( SELECT FirstName, LastName, Address FROM Employees WHERE City = @sCity ) GO This inline table value-returning UDF can be selected from or even joined to because it returns a rowset via the table datatype, as shown here: SELECT * FROM dbo.fnGetEmployeesByCity('seattle') Notice that the UDF is called using the two-part name of object owner and object name. However, the object's owner is not required (but is acceptable) when using a UDF that returns a table datatype value. Table-valued UDFs are quite flexible in that they can be used like a prepared and parameterized view (if one existed). In table-valued UDFs you can use parameters, achieve the performance of a prepared query, and join or select from the resulting rowset (or table in this case). Although this type of UDF is compact, it is important to remember that if additional logic needs to be added to the UDF, it will have to be converted to a multistatement table value-returning UDF. Also, inline table value-returning UDFs cannot have an ORDER BY clause on the SELECT statement either (unless it is used in conjunction with the TOP clause). A UDF that returns multistatement tables explicitly defines the structure of the table to return. It does so by defining the column names and datatypes right in the RETURNS clause. Thus it takes a bit more code to get it set up than an inline table value-returning UDF. However, it has several advantages over inline table value-returning UDFs including the ability to house more complicated, numerous T-SQL logic blocks. As their name suggests, multistatement table value-returning UDFs allow multiple statements to define the UDF. Thus statements such as control of flow, assignments, cursors, SELECTS, INSERTS, UPDATES, and DELETES are allowed and can all exist in a single UDF. So, as opposed to UDFs that return inline tables, their multistatement brethren are not limited to a single SELECT statement nor are they prohibited from ordering the returning rowset.shows how to rewrite the inline table value-returning UDF from the code snippet I just showed as a multistatement table value-returning UDF. Thus the multistatement type can do anything the inline type can do. A more complicated use of a UDF that returns multistatement tables could involve retrieving all employees by city, but if no customers match the given city then a dummy row is returned where the Address field is filled with "No matching employees found in the specified city," as shown in. 45 It's a Wrap There are some other key factors that can help create a powerful UDF of any type, one of which is recursion. Recursion is supported with UDFs such that a UDF can call itself from within itself. Basically, recursion is just nesting a UDF except that the UDF you are nesting is the same one you are in. This can be very useful in certain situations including when you're creating a UDF that must compute a factorial or evaluate each character in a string. There is a limited depth of 32 levels of recursion in SQL Server 2000, after which an error is raised. It is also important to point out that a UDF can be bound to the schema of the underlying objects to which it refers. To do this, the UDF must be created using the WITH SCHEMABINDING clause. If the UDF is created this way and someone attempts to alter one of the underlying objects' schema without first removing the schema binding, an error will be generated and raised. Using this option will help you ensure that no UDFs break inadvertently due to changes in an underlying object's schema. When evaluating UDFs it is vital to consider the balance between performance and maintainability. While UDFs can reduce the amount of common code, be used as part of a common function library, can promote shorter code blocks, and are generally easier to maintain than additional versions of the same SQL logic, it would be reckless to use a UDF without first taking into consideration any of the drawbacks. It would be a bad idea to use a UDF if performance suffers tremendously. For example, assume that there is a UDF that performs a SQL SELECT statement that takes one second to execute. If this UDF is used in a SELECT or a WHERE clause it will be executed for every row. Thus the time the main query takes to execute could increase drastically depending on such factors as the number of rows evaluated and returned and the types of indices in place. Before using a UDF in this type of situation, carefully weigh the options and do some performance testing. However, using a UDF that performs a calculation such as the one shown in barely affects the performance of query. As with any tool, when used properly and evaluated accordingly prior to going live, UDFs offer great convenience and maintainability. 46 附录B 外文翻译—译文部分 SQL Server 用户定义的函数 用户定义的函数 (UDF) 是准备好的代码片段,它可以接受参数,处理逻辑,然后返回某些数据。根据 SQL Server Books Online,SQL Server 2000 中的 UDF 可以接受从 0 到 1024 的任意个数的参数,不过我必须承认,我还未尝试将 1024 个参数传递到 UDF 中。UDF 的另一个关键特征是返回一个值。取决于 UDF 的类型,调用例程可以使用这个值来继续处理它的数据。因此,如果 UDF 返回单一值(标量值),调用例程就可以在任何能够使用标准变量或文字值的地方使用这个值。如果 UDF 返回一个行集,则调用例程可以循环访问该行集,联接到该行集,或简单地从该行集中选择列。 虽然现在大多数编程语言已经暂时支持函数,但只有 SQL Server 2000 引入了 UDF。存储过程和视图在 SQL Server 中可用的时间远早于 UDF,但这些对象中的每一个在 SQL Server 开发中都有自己适当的位置。存储过程可以很好地用于处理复杂的 SQL 逻辑、保证和控制对数据的访问,以及将行集返回到调用例程,无论此例程是基于 Visual Basic? 的程序,还是另一个 Transact-SQL (T-SQL) 批处理文件。与视图不同,存储过程是已编译的,这使得它们成为用来表示和处理频繁运行的 SQL 语句的理想候选者。视图可以很好地用于控制对数据的访问,但它们的控制方式与存储过程不同。视图仅限于生成该视图的基础 SELECT 语句中的某些列和行。因而视图常用于表示常用的 SELECT 语句,该语句可以联接多个表、使用 WHERE 子句,以及公开特定的列。在联接到其他表和视图的 SQL 语句的 FROM 子句中经常会发现视图。 在其核心部分,UDF 既类似于视图,也类似于存储过程。像视图一样,UDF 可以返回一个行集,该行集可用于 JOIN 中。因此,当 UDF 返回一个行集并接受参数时,它像一个您可以联接到的存储过程、或者一个参数化的视图。但是,正如我将演示的,UDF 可以做到这一点,甚至更多。 有两种主要的 UDF 类型:返回标量值的 UDF 和返回表值的 UDF。在表值 UDF 中,您将找到返回内联表和多语句表的 UDF。在以下部分中,我将对每种类型都加以关注。 标量 UDF 返回标量值的 UDF 最类似于许多编程语言所引用的作为函数的内容。它们返回由标量数据类型(例如,integer、varchar(n)、char(n)、money、datetime、bit,等等)组成的单一值。如果用户定义的数据类型 (UDDT) 基于标量数据类型,UDF 也可以返回这些数据类型。使用返回内联或多语句表的 UDF,可以通过表数据类型返回行集。然而,并非所有的数据类 47 型都可以从 UDF 中返回。例如,UDF 无法返回下列数据类型中任何一个的值:text、ntext、image、cursor、或 timestamp。 返回标量数据类型的 UDF 可以用于多种情况,以使代码具有更好的可维护性、可重用性和更少的复杂性。当 T-SQL 代码的相同段在几个地方(可能由几个存储过程和批 SQL 语句)使用时,这会非常有用。例如,假定一个应用程序中的几个部分都需要查找产品是否必须重新订购。在每个需要此操作的地方,代码可以检查重新订购等级,并将它与库存量加订购量的和相比较。然而,因为这个代码在几个地方用到,所以可以改为使用 UDF 以减少代码块,并使得万一需要更改时维护函数更加容易。这样的 UDF 可能看起来像图中的代码,并可以使用以下 SQL 语句进行调用: SELECT ProductID, ReorderLevel, UnitsInStock, UnitsOnOrder, dbo.fnNeedToReorder(ReorderLevel, UnitsInStock, UnitsOnOrder) AS sNeedToReorder FROM Products fnNeedToReorder UDF 执行计算并返回适当的值。这本来可以通过 CASE 语句在 SELECT 子句内完成,但如果改为使用 UDF,代码就会简洁得多。而且更容易传播到其他可能需要相同逻辑的地方。假定一个应用程序中有几个部分需要确定是否要重新订购产品, UDF 确实变得有价值,因为它使得当逻辑改变时应用程序更容易维护。例如,重新订购已经终止的产品并不是很有意义。因此,通过更改 UDF 以说明这个业务规则,可以在一个地方更改此逻辑并使用下列代码运行: SELECT ProductID, ReorderLevel, UnitsInStock, UnitsOnOrder, dbo.fnNeedToReorder(ReorderLevel, UnitsInStock, UnitsOnOrder, Discontinued) AS sNeedToReorder FROM Products 请注意,UDF 是使用由两个部分(对象所有者和对象名)组成的名称调用的。当使用返回标量数据类型值的 UDF 时需要该对象的所有者。可以授权所有调用 UDF 的地方也必须加以更改,方法是将第四个参数 (Discontinued) 添加到 UDF 中。为了更容易维护,我可以重新编写 UDF,以便使用每一行的 ProductID 来检索数据本身,这种技术更容易维护,因为它不需要任何调用例程来更改逻辑改变时更改 UDF 的方式,只要可以从当前 Products 表行中提取数据即可。然而,要获得这种可维护性,会有性能方面的损失。中的 UDF 必须 48 为每个从调用例程中返回的行从 Products 表中检索行。因为调用例程已经从 Products 表中 检索每个行,所以如果该表有 77 行,则代码将执行 77 次 SELECT 语句(从主 SELECT 语句中返回每行一次)。虽然每个 SELECT 都是基于主键字段 (ProductID) 进行选择的, 因而会很快,但是当行集非常大或者 SELECT 语句效率较低时,性能就会受到负面影响。 中的代码可以通过以下 SQL 片段来调用: SELECT ProductID, ReorderLevel, UnitsInStock, UnitsOnOrder, dbo.fnNeedToReorder(ProductId) AS sNeedToReorder FROM Products 在 SELECT 语句中使用这个函数的可选方法是,在名为 NeedToReorder 的 Products 表中创建一个计算所得的列。该列并不定义为一种数据类型,而是定义为如所示的 fnNeedToReorder UDF 的返回值。要添加此列,我可以按以下方式更改 Products 表,以指 示应计算这个列: ALTER TABLE Products ADD NeedToReorder AS dbo.fnNeedToReorder(ReorderLevel, UnitsInStock, UnitsOnOrder, Discontinued) 通用 UDF 和嵌套 至此,我已经展示了使用返回标量值的 UDF 解决同一问题的几种方式。还有其他有用的 UDF 应用程序,其中包括 T-SQL 中还未准备好可用的函数。一个例子是专用格式化函数。例如,电话号码通常存储(不带格式化字符)在 char(10) 列中,这些列表示区号和电 话号码(假定这是一个美国的号码)。UDF 可以用于在格式化结构中检索电话号码。因此,检索和格式化电话号码像下面一样简单: SELECT dbo.fnCOM_FormatTelephoneNumber ('3335558888') 可以使用这种技术创建任何常用函数,以增加 SQL Server 中可用函数的数量。另一个示例 是将日期格式化为带有前导零的 MM/DD/YYYY 格式的函数: CREATE FUNCTION fnCOM_StandardDate (@dtDate DATETIME) RETURNS VARCHAR(10) AS BEGIN RETURN dbo.fnCOM_2Digits (CAST(MONTH(@dtDate) AS VARCHAR(2))) + '/' + dbo.fnCOM_2Digits (CAST(DAY(@dtDate) AS VARCHAR(2))) + '/' + CAST(YEAR(@dtDate) AS VARCHAR(4)) 49 END fnCOM_StandardDate UDF 接受日期时间值,并返回 MM/DD/YYYY 格式的 varchar(10) 值。当然,这很简单,如果您的应用程序常常需要特定格式,那么这种技术就可以使它更容易维护。在前面的代码中需要注意的一个关键部分是嵌套 UDF 的使用。 fnCOM_StandardDate UDF 两次调用 fnCOM_2Digits UDF(在下一个示例中显示),每次都在小于 10 的日或月前放置一个前导零。 CREATE FUNCTION fnCOM_2Digits (@sValue VARCHAR(2)) RETURNS VARCHAR(2) AS BEGIN IF (LEN(@sValue) < 2) SET @sValue = '0' + @sValue RETURN @sValue END UDF 可以互相嵌套,只要其中的 UDF 是先创建的即可。使用嵌套函数的一个 catch 是非确定性内置函数(例如 getdate 函数),不能在另一个 UDF 内嵌套(否则会引发 SQL Server 错误)。非确定性函数是用完全相同的参数调用多次时可能返回不同结果的函数。getdate 函数属于这一类,因为每次调用时,它会返回新的当前日期和时间。另一个常用的非确定性内置函数是 NewID 函数。它也是非确定性的,因为它总是返回唯一的 GUID,所以 NewID 函数同样不允许在 UDF 内嵌套。 表值 UDF 表值 UDF 的类别中有两种子类型:返回内联表值的 UDF 和返回多语句表值的 UDF。返回内联表的 UDF 通过 SQL Server 表数据类型返回一个行集。它们使用构成函数体的单一 SELECT 语句进行定义。返回内联表值的 UDF 不能在定义它将返回的表的 SQL SELECT 语句之外包含其他 T-SQL 逻辑。然而,它们比返回多语句表的 UDF 要容易创建,因为它们不必定义要返回的确切表结构。返回内联表的 UDF 从 SELECT 语句本身推断行集的结构。因此,UDF 将返回的列由 SELECT 列表中的列确定。下列代码显示了 fnGetEmployeesByCity UDF,它接受一个城市,并返回包含所有员工名字、姓和地址的表: CREATE FUNCTION fnGetEmployeesByCity (@sCity VARCHAR(30)) RETURNS TABLE AS RETURN ( SELECT FirstName, LastName, Address FROM Employees 50 WHERE City = @sCity ) GO 可以从这个返回内联表值的 UDF 中选择或者甚至联接到它,因为它通过表数据类型返回一个行集,如下所示: SELECT * FROM dbo.fnGetEmployeesByCity('seattle') 请注意,UDF 是使用由对象所有者和对象名这两个部分组成的名称调用的。然而,当使用返回表数据类型值的 UDF 时,对象所有者不是必需的(但却是可接受的)。表值 UDF 非常灵活,因为它们可以像准备好的和参数化的视图(如果存在)一样使用。在表值 UDF 中,您可以使用参数,获得准备好的查询的性能,并从得到的行集(或本例中的表)中联接或选择。 尽管这种 UDF 类型是简洁的,但重要的是要记住,如果您要向这种 UDF 中添加其他逻辑,就必须将其转换成返回多语句表值的 UDF。另外,返回内联表值的 UDF 在 SELECT 语句中也不能有 ORDER BY 子句(除非它与 TOP 子句一起使用)。 返回多语句表的 UDF 显式定义要返回的表的结构。它通过在 RETURNS 子句中正确定义列名称和数据类型来做到这一点。因此,它会使用比返回内联表值的 UDF 稍多的代码来建立表结构。然而,与返回内联表值的 UDF 相比,它有几个优点,其中包括容纳更复杂的、更大量的 T-SQL 逻辑块的功能。顾名思义,返回多语句表值的 UDF 允许多个语句定义 UDF。因此,诸如流控制、分配、游标、SELECTS、INSERTS、UPDATES 和 DELETES 等语句都是允许的,并且都可以存在于单个 UDF 中。所以,与返回内联表的 UDF 相反,返回多语句表的 UDF 并不限定于单个 SELECT 语句,也不禁止对返回行集进行排序。 显示了如何将返回内联表值的 UDF(我刚才展示的代码片段中的)重新编写为返回多语句表值的 UDF。因此,内联类型能做到的,多语句类型都能做到。返回多语句表的 UDF 的更复杂的用途包括按城市检索所有员工,但如果没有客户与特定的城市相匹配,就返回一个虚行,其中的 Address 字段填写“在指定的城市中未找到匹配的员工”。 还有其他一些关键因素可以帮助创建任何类型的功能强大的 UDF,其中的一种便是递归。UDF 支持递归,以便一个 UDF 可以从自身中调用自身。基本上,递归只是嵌套 UDF,唯一不同的地方在于您所嵌套的 UDF 正是您所在的 UDF。这在某些情况中可能非常有用,包括在创建一个必须计算某个因子或评估一个字符串中每个字符的 UDF 时。在 SQL Server 2000 中,递归的限制深度为 32 层,超出限制会引发错误。 还需要指出的是,一个 UDF 可以绑定到它所引用的基础对象架构。为此,UDF 必须使用 WITH SCHEMABINDING 子句来进行创建。如果 UDF 是以这种方式创建的,则当有人试图更改一个基础对象架构而没有先删除架构绑定时,就会生成并引发错误。采用这种选择将有助于确保不会因为基础对象架构中的更改而引起意外的 UDF 中断。 51 当评估 UDF 时,考虑性能和可维护性之间的平衡是至关重要的。虽然 UDF 可以减少 常用代码的数量(用作常用函数库的一部分),可以提升更短的代码块,并且通常比相同 SQL 逻辑的其他类型更容易维护,但是,如果不先考虑任何缺点就使用 UDF,这将是不计后果 的。 如果性能严重降低,那么使用 UDF 就不是一个好主意。例如,假定有一个执行 SQL SELECT 语句的 UDF,执行该语句需要一秒钟。如果此 UDF 在 SELECT 或 WHERE 子 句中使用,它将为每一行执行。因此,执行主查询所花费的时间会急剧增加,这取决于评估 和返回的行数以及适当的索引类型这样的因素。如果是这种情况,则在使用 UDF 之前,要 仔细地权衡所作的选择并进行一些性能测试。然而,使用执行计算的 UDF几乎不影响查询 性能。正如任何工具一样,如果在实际投入之前正确地使用并进行相应地评估,那么UDF 会 提供极大的便利和可维护性。 When I was quite small I would sometimes dream of a city — which was strange because it began before I even knew what a city was. But this city, clustered on the curve of a big blue bay, would come into my mind. I could see the streets, and the buildings that lined them, the waterfront, even boats in the harbour; yet, waking, I had never seen the sea, or a boat. ... And the buildings were quite unlike any I knew. The traffic in the streets was strange, carts running with no horses to pull them; and sometimes there were things in the sky, shiny fish-shaped things that certainly were not birds. Most often I would see this wonderful place by daylight, but occasionally it was by night when the lights lay like strings of glow-worms along the shore, and a few of them seemed to be sparks drifting on the water, or in the air. It was a beautiful, fascinating place, and once, when I was still young enough to know no better, I asked my eldest sister, Mary, where this lovely city could be. She shook her head, and told me that there was no such place — not now. But, perhaps, she suggested, I could somehow be dreaming about times long ago. Dreams were funny things, and there was no accounting for them; so it might be that what I was seeing was a bit of the world as it had been once upon a time — the wonderful world that the Old People had lived in; as it had been before God sent Tribulation. But after that she went on to warn me very seriously not to mention it to anyone else; other people, as far as she knew, did not have such pictures in their heads, either sleeping or waking, so it would be unwise to mention them. That was good advice, and luckily I had the sense to take it. People in our district had a very sharp eye for the odd, or the unusual, so that even my left-handedness caused slight disapproval. So, at that time, and for some years afterwards, I did not mention it to anyone — indeed, I almost forgot about it, for as I grew older the dream came less frequently, and then very rarely. But the advice stuck. Without it I might have mentioned the curious understanding I had with my cousin Rosalind, and that would certainly have led us both into very grave trouble — if anyone had happened to believe me. Neither I nor she, I think, paid much attention to it at that time: we simply had the habit of caution. I certainly did not feel unusual. I was a normal little boy, growing up in a normal way, taking the ways of the world about me for granted. And I kept on like that until the day I met Sophie. Even then, the difference was not immediate. It is hind-sight that enables me to fix that as the day when my first small doubts started to germinate. That day I had gone off by myself, as I often did. I was, I suppose, nearly ten years old. My next sister, Sarah, was five years older, and the gap meant that I played a great deal alone. I had made my way down the cart-track to the south, along the borders of several fields until I came to the high bank, and then along the top of the bank for quite a way. The bank was no puzzle to me then: it was far too big for me to think of as a thing that men could have built, nor had it ever occurred to me to connect it with the wondrous doings of the Old People whom I sometimes heard about. It was simply the bank, coming round in a wide curve, and then running straight as an arrow towards the distant hills; just a part of the world, and no more to be wondered at than the river, the sky, or the hills themselves. I had often gone along the top of it, but seldom explored on the farther side. For some reason I regarded the country there as foreign — not so much hostile, as outside my territory. But there was a place I had discovered where the rain, in running down the far side of the bank, had worn a sandy gully. If one sat in the start of that and gave a good push off, one could go swishing down at a fine 52 speed, and finally fly a few feet through the air to land in a pile of soft sand at the bottom. I must have been there half a dozen times before, and there had never been anyone about, but on this occasion, when I was picking myself up after my third descent and preparing for a fourth, a voice said: ' Hullo!' I looked round. At first I could not tell where it came from; then a shaking of the top twigs in a bunch of bushes caught my eye. The branches parted, and a face looked out at me. It was a small face, sunburned, and clustered about by dark curls. The expression was somewhat serious, but the eyes sparkled. We regarded one another for a moment, then: 'Hallo,' I responded. She hesitated, then pushed the bushes farther apart. I saw a girl a little shorter than I was, and perhaps a little younger. She wore reddish-brown dungarees with a yellow shirt. The cross stitched to the front of the dungarees was of a darker brown material. Her hair was tied on either side of her head with yellow ribbons. She stood still for a few seconds as though uncertain about leaving the security of the bushes, then curiosity got the better of her caution, and she stepped out. I stared at her because she was completely a stranger. From time to time there were gatherings or parties which brought together all the children for miles around, so that it was astonishing to encounter one that I had never seen before. A grain of sand, teetering on the brink of the pit, trembled and fell in; the ant lion at the bottom angrily flung it out again. For a moment there was quiet. Then the entire pit, and a square meter of sand around it, shifted drunkenly while two coconut palms bent to watch. The sand rose, pivoting at one edge, and the scarred head of a boy appeared-a stubble of brown hair threatened to erase the marks of the sutures; with dilated eyes hypnotically dark he paused, his neck just where the ant lion's had been; then, as though goaded from below, he vaulted up and onto the beach, turned, and kicked sand into the dark hatchway from which he had emerged. It slammed shut. The boy was about fourteen. For a time he squatted, pushing the sand aside and trying to find the door. A few centimeters down, his hands met a gritty, solid material which, though neither concrete nor sandstone, shared the qualities of both sand-filled organic plastic. On it he scraped his fingers raw, but he could not locate the edges of the hatch. Then he stood and looked about him, his head moving continually as the heads of certain reptiles go back and forth, with no pauses at the terminations of the movements. He did this constantly, ceaselessly always-and for that reason it will not often be described again, just as it will not be mentioned that he breathed. He did; and as he did, his head, like a rearing snake's, turned from side to side. The boy was thin, and naked as a frog. Ahead of him the sand sloped gently down toward sapphire water; there were coconuts on the beach, and seashells, and a scuttling crab that played with the finger-high edge of each dying wave. Behind him there were only palms and sand for a long distance, the palms growing ever closer together as they moved away from the water until the forest of their columniated trunks seemed architectural; like some palace maze becoming as it progressed more and more draped with creepers and lianas with green, scarlet, and yellow leaves, the palms interspersed with bamboo and deciduous trees dotted with flaming orchids until almost at the limit of his sight the whole ended in a spangled wall whose predominant color was blackgreen. The boy walked toward the beach, then down the beach until he stood in knee-deep water as warm as blood. He dipped his fingers and, tasted it-it was fresh, with no hint of the disinfectants to which he was accustomed. He waded out again and sat on the sand about five meters up from the high-water mark, and after ten minutes, during which he heard no sound but the wind and the murmuring of the surf, he threw back his head and began to scream. His screaming was high-pitched, and each breath ended in a gibbering, ululant note, after which came the hollow,- iron gasp of the next indrawn breath. On one occasion he had screamed in this way, without cessation, for fourteen hours and twenty-two minutes, at the end of which a nursing nun with an exemplary record stretching back seventeen years had administered an injection without the permission of the attending physician. After a time the boy paused-not because he was tired, but in order to listen better. There was, still, only the sound of the wind in the palm fronds and the murmuring surf, yet he felt that he had heard a voice. The boy could be quiet as well as noisy, and he was quiet now, his left hand sifting white sand as clean as salt between its fingers while his right tossed tiny pebbles like beach-glass beads into the surf. "Hear me," said the surf. "Hear me. Hear me." hit in the soft sand. He walked to the beach again and stood staring out at the water. Far off he could see it curving up and up, the distant combers breaking in white .foam until the sea became white-flecked sky. To his left and his right the beach curved away, bending almost infinitesimally until it disappeared. He began to walk, then saw, almost at the point where perception was lost, a human figure. He broke into a run; a moment 53 later, he halted and turned around. Far ahead another walker, almost invisible, strode the beach; Nicholas ignored him; he ` found a coconut and tried to open it, then threw it aside and walked on. From time to time fish jumped, ;. and occasionally he saw a wheeling sea bird dive. The light grew dimmer. He was aware that he had not eaten for some time, but he was not in the strict sense hungry-or rather, he enjoyed his hunger now in the same way that he might, at another time, have gashed his arm to watch himself bleed. Once he said, "Dr. Island!" loudly as he passed a coconut palm, and then later began to chant, "Dr. Island, Dr. Island, Dr. Island," as he walked until the words had lost all meaning. He swam in the sea as he had been taught to swim in the great quartanary treatment tanks on Callisto to improve his coordination, and spluttered and snorted until he learned to deal with the waves. When it was so dark he could see only the white sand and the white foam of the breakers, he drank from the sea and fell asleep, on the beach, the right. side of his taut, ugly face relaxing first, so that it seemed asleep even while the left eye was open and staring; his head rolling from side to side; the left corner of his mouth preserving, like a death mask, his characteristic expression -angry, remote, tinged with that inhuman quality that is found nowhere but in certain human faces. When he woke it was not yet light, but the night was fading to a gentle gray. Headless, the palms stood like tall ghosts up and down the beach, their tops lost in fog and the lingering dark. He was cold. His hands rubbed his sides; he danced on the sand and sprinted down the edge of the lapping water in an effort to get warm; ahead of him a pinpoint of red light became a fire, and he slowed. A man who looked about twenty-five crouched over the fire. Tangled black hair hung aver this man's shoulders, and he had a sparse beard; otherwise he was as naked as Nicholas himself. His eyes were dark, and large and empty, like the ends of broken pipes; he poked at his fire, and the smell of roasting fish came with the smoke. For a time Nicholas stood at a distance, watching. Saliva ran from a corner of the man's mouth, and he wiped it away with one hand, leaving a smear of ash on his face. Nicholas edged closer until he stood on the opposite side of the fire. The fish had been wrapped in broad leaves and mud, and lay in the center of the coals. "I'm Nicholas," Nicholas said. "Who are you?" The young man did not look at him, had never looked at him. "Hey, I'd like a piece of your fish. Not much. All right?" The young man raised his head, looking not at Nicholas but at some point far beyond him; he dropped his eyes again. Nicholas smiled. The smile emphasized the disjointed quality of his expression, his mouth's uneven curve. "Just a little piece? Is it about done?" Nicholas crouched, imitating the young man, and as though this were a signal, the young man sprang for him across the fire. Nicholas jumped backward, but the jump was too late-the young man's body struck his and sent him sprawling on the sand; fingers clawed for his throat. Screaming, Nicholas rolled free, into the water; the young man splashed after him; Nicholas dove. He swam underwater, his belly almost grazing the r wave-rippled sand until he found deeper water; then he surfaced, gasping for breath, and saw the young man, who saw him as well. He dove again, this time surfacing far off, in deep water. Treading water, he could see the fire on the beach, and the young man when he . returned to it, stamping out of the sea in the early .t light. Nicholas then swam until he was five hundred meters or more down the beach, then waded in to shore and began walking back toward the fire. The young man saw him when he was still some distance off, but he continued to sit, eating pink-tinted tidbits from his fish, watching Nicholas. "What's the matter?" Nicholas said while he was still a safe distance away. "Are you mad at me?" From the forest, birds warned, "Be careful, Nicholas;" "I won't hurt you," the young man said. He stood up, wiping his oily hands on his chest, and gestured toward the fish at his feet. "You want some?" Nicholas nodded, smiling his crippled smile. "Come then." Nicholas waited, hoping the young man would move away from the fish, but he did not; neither did he smile in return. "Nicholas," the little waves at his feet whispered, "this is Ignacio." 54 "Listen," Nicholas said, "is it really all right for me to have some?" Ignacio nodded, unsmiling. Cautiously Nicholas came forward; as he was bending to pick up the fish, Ignacio's strong hands took him; he tried to wrench free but was thrown down, Ignacio on top of him. "Please!" he yelled. "Please!" Tears started into his eyes. He tried to yell again, but he had no breath; the tongue was being forced, thicker than his wrist, from his throat. Then Ignacio let go and struck him in the face with his clenched fist. Nicholas had been slapped and pummeled before, had been beaten, had fought, sometimes savagely, with other boys; but he had never been struck by a man as men fight. Ignacio hit him again and his lips gushed blood. He lay a long time on the sand beside the dying fire. Consciousness returned slowly; he blinked, drifted back into the dark, blinked again. His mouth was full of blood, and when at last he spit it out onto the sand, it seemed a soft flesh, dark and polymerized in strange shapes; his left cheek was hugely swollen, and he could scarcely see out of his left eye. After a time he crawled to the water; a long time after that, he left it and walked shakily back to the ashes of the fire. Ignacio was gone, and there was nothing left of the fish but bones. "Ignacio is gone," Dr. Island said with lips of waves. Nicholas sat on the sand, cross-legged. "You handled him very well." . "You saw us fight?" "I saw you; I see everything, Nicholas." "This is the worst place," Nicholas said; he was talking to his lap. "What do you mean by that?" "I've been in bad places before-places where they hit you or squirted big hoses of ice water that knocked you down. But not where they would let someone else-" 's Karen doing in Iraq?" Mother asked. "Negotiating a Palestinian homeland." "And meanwhile her granddaughter is ruining her life," she said irrelevantly. "Did you tell Viola? "I told you, Mother. I thought Perdita should tell all of you herself." "Well, she didn't. And this morning one of my patients, Carol Chen, called me and demanded to know what I was keeping from her. I had no idea what she was talking about." "How did Carol Chen find out?" "From her daughter, who almost joined the Cyclists last year. Her family talked her out of it," she said accusingly. "Carol was convinced the medical community had discovered some terrible side-effect of ammenerol and were covering it up. I cannot believe you didn't tell me, Traci." And I cannot believe I didn't have Bysshe tell her I was in court, I thought. "I told you Mother. I thought it was Perdita's place to tell you. After all, it's her decision." "Oh, Traci!" Mother said. "You cannot mean that!" In the first fine flush of freedom after the Liberation, I had entertained hopes that it would change everything--that it would somehow do away with inequality and matriarchal dominance and those humorless women determined to eliminate the word "manhole" and third-person singular pronouns from the language. Of course it didn't. Men still make more money, "herstory" is still a blight on the semantic landscape, and my mother can still say, "Oh, Traci!" in a tone that reduces me to pre-adolescence. "Her decision!" Mother said. "Do you mean to tell me you plan to stand idly by and allow your daughter to make the mistake of her life?" "What can I do? She's twenty-two years old and of sound mind." "If she were of sound mind she wouldn't be doing this. Didn't you try to talk her out of it?" "Of course I did, Mother." "And?" "And I didn't succeed. She's determined to become a Cyclist." 55 "Well, there must be something we can do. Get an injunction or hire a deprogrammer or sue the Cyclists for brainwashing. You're a judge, there must be some law you can invoke--" "The law is called personal sovereignty, Mother, and since it was what made the Liberation possible in the first place, it can hardly be used against Perdita. Her decision meets all the criteria for a case of personal sovereignty: it's a personal decision, it was made by a sovereign adult, it affects no one else--" "What about my practice? Carol Chen is convinced shunts cause cancer." "Any effect on your practice is considered an indirect effect. Like secondary smoke. It doesn't apply. Mother, whether we like it or not, Perdita has a perfect right to do this, and we don't have any right to interfere. A free society has to be based on respecting others' opinions and leaving each other alone. We have to respect Perdita's right to make her own decisions." All of which was true. It was too bad I hadn't said any of it to Perdita when she called. What I had said, in a tone that sounded exactly like my mother's, was "Oh, Perdita!" "This is all your fault, you know," Mother said. "I told you you shouldn't have let her get that tattoo over her shunt. And don't tell me it's a free society. What good is a free society when it allows my granddaughter to ruin her life?" She hung up. I handed the receiver back to Bysshe. "I really liked what you said about respecting your daughter's right to make her own decisions," he said. He held out my robe. "And about not interfering in her life." "I want you to research the precedents on deprogramming for me," I said, sliding my arms in the sleeves. "And find out if the Cyclists have been charged with any free choice violations-- brainwashing, intimidation, coercion." The phone sang, another universal. "Hello, who's calling?" Bysshe said cautiously. His voice became suddenly friendlier. "Just a minute." He put his hand over the receiver. "It's your daughter Viola." I took the receiver. "Hello, Viola." "I just talked to Grandma," she said. "You will not believe what Perdita's done now. She's joined the Cyclists." "I know," I said. "You know? And you didn't tell me? I can't believe this. You never tell me anything." "I thought Perdita should tell you herself," I said tiredly. "Are you kidding? She never tells me anything either. That time she had eyebrow implants she didn't tell me for three weeks, and when she got the laser tattoo she didn't tell me at all. Twidge told me. You should have called me. Did you tell Grandma Karen?" "She's in Baghdad," I said. "I know," Viola said. "I called her." "Oh, Viola, you didn't!" "Unlike you, Mom, I believe in telling members of our family about matters that concern them." "What did she say?" I asked, a kind of numbness settling over me now that the shock had worn off. "I couldn't get through to her. The phone service over there is terrible. I got somebody who didn't speak English, and then I got cut off, and when I tried again they said the whole city was down." Thank you, I breathed silently. Thank you, thank you, thank you. "Grandma Karen has a right to know, Mother. Think of the effect this could have on Twidge. She thinks Perdita's wonderful. When Perdita got the eyebrow implants, Twidge glued LED's to hers, and I almost never got them off. What if Twidge decides to join the Cyclists, too?" "Twidge is only nine. By the time she's supposed to get her shunt, Perdita will have long since quit." I hope, I added silently. Perdita had had the tattoo for a year and a half now and showed no signs of tiring of it. "Besides, Twidge has more sense." "It's true. Oh, Mother, how could Perdita do this? Didn't you tell her about how awful it was?" "Yes," I said. "And inconvenient. And unpleasant and unbalancing and painful. None of it made the slightest impact on her. She told me she thought it would be fun." Bysshe was pointing to his watch and mouthing, "Time for court." "Fun!" Viola said. "When she saw what I went through that time? Honestly, Mother, sometimes I think she's completely brain-dead. Can't you have her declared incompetent and locked up or something?" "No," I said, trying to zip up my robe with one hand. "Viola, I have to go. I'm late for court. I'm afraid there's nothing we can do to stop her. She's a rational adult." "Rational!" Viola said. "Her eyebrows light up, Mother. She has Custer's Last Stand lased on her arm." I handed the phone to Bysshe. "Tell Viola I'll talk to her tomorrow." I zipped up my robe. "And then call Baghdad and see how long they expect the phones to be out." I started into the courtroom. "And if there are any more universal calls, make sure they're local before you answer." not a cult. There's no religious connection. They seem to have grown out of a pre- Liberation women's group," he said, looking at his notes, "although there are also links to the pro-choice movement, the University of Wisconsin, and the Museum of Modern Art." "What?" 56 "They call their group leaders 'docents.' Their philosophy seems to be a mix of pre-Liberation radical feminism and the environmental primitivism of the eighties. They're floratarians and they don't wear shoes." "Or shunts," I said. We pulled up in front of McGregor's and got out of the car. "Any mind control convictions?" I asked hopefully. "No. A bunch of suits against individual members, all of which they won." "On grounds of personal sovereignty." "Yeah. And a criminal one by a member whose family tried to deprogram her. The deprogrammer was sentenced to twenty years, and the family got twelve." "Be sure to tell Mother about that one," I said, and opened the door to McGregor's. It was one of those restaurants with a morning glory vine twining around the maitre d's desk and garden plots between the tables. "Perdita suggested it," Mother said, guiding Bysshe and I past the onions to our table. "She told me a lot of the Cyclists are floratarians." "Is she here?" I asked, sidestepping a cucumber frame. "Not yet." She pointed past a rose arbor. "There's our table." Our table was a wicker affair under a mulberry tree. Viola and Twidge were seated on the far side next to a trellis of runner beans, looking at menus. "What are you doing here, Twidge?" I asked. "Why aren't you in school?" "I am," she said, holding up her LCD slate. "I'm remoting today." "I thought she should be part of this discussion," Viola said. "After all, she'll be getting her shunt soon." "My friend Kensy says she isn't going to get one, like Perdita," Twidge said. "I'm sure Kensy will change her mind when the time comes," Mother said. "Perdita will change hers, too. Bysshe, why don't you sit next to Viola?" Bysshe slid obediently past the trellis and sat down in the wicker chair at the far end of the table. Twidge reached across Viola and handed him a menu. "This is a great restaurant," she said. "You don't have to wear shoes." She held up a bare foot to illustrate. "And if you get hungry while you're waiting, you can just pick something." She twisted around in her chair, picked two of the green beans, gave one to Bysshe, and bit into the other one. "I bet she doesn't. Kensy says a shunt hurts worse than braces." "It doesn't hurt as much as not having one," Viola said, shooting me a Now-Do-You-See-What-My-Sister's-Caused? look. "Traci, why don't you sit across from Viola?" Mother said to me. "And we'll put Perdita next to you when she comes." "If she comes," Viola said. "I told her one o'clock," Mother said, sitting down at the near end. "So we'd have a chance to plan our strategy before she gets here. I talked to Carol Chen--" "Her daughter nearly joined the Cyclists last year," I explained to Bysshe and Viola. "She said they had a family gathering, like this, and simply talked to her daughter, and she decided she didn't want to be a Cyclist after all." She looked around the table. "So I thought we'd do the same thing with Perdita. I think we should start by explaining the significance of the Liberation and the days of dark oppression that preceded it--" 57
本文档为【人力资源管理系统的设计—免费毕业设计论文】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_044822
暂无简介~
格式:doc
大小:407KB
软件:Word
页数:89
分类:
上传时间:2018-03-19
浏览量:31