65.9K
CodeProject 正在变化。 阅读更多。
Home

任务管理系统

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.41/5 (32投票s)

2009年5月20日

CPOL

9分钟阅读

viewsIcon

239886

downloadIcon

17210

一个 Web 应用程序允许用户管理组织的员工、项目和任务,并提供相关报告。

引言

这是一个 Web 应用程序,任何组织都可以通过它来管理员工之间的任务。该项目包含各种小功能,如任务评论、文件上传和下载、任务转交、编辑现有和创建新项目、任务、员工、用户和客户等,以及 Crystal Reports。

这是一个完整的项目。在此项目中,我使用了 C#、SQL Server 和 ASP.NET 的各种组件。阅读本文的读者在使用这些组件时可能会觉得本文很有帮助。我想与大家分享整个项目,包括代码和描述。

项目描述

1. 每个项目都有一定数量的任务和员工。项目下的所有任务只能由这些员工处理。

2. 一次只能将一个任务分配给一个员工。任务可以转交给该项目的其他员工。

3. 员工可以评论自己的任务,上传文件到任务,将任务转交给项目的其他员工,也可以下载任务的附件。

4. 员工有两种类型:管理员和普通用户。两种类型都必须是员工。

5. 用户只能评论自己的任务,上传文件到任务,将任务转交给该项目的其他员工,也可以下载任务的附件。

6. 管理员用户拥有除普通用户所有权限之外的一些额外权限。

  • 管理员可以创建项目、编辑项目信息、添加/删除项目员工,并可以关闭项目。
  • 管理员可以创建任务、编辑任务信息并关闭任务。
  • 管理员可以创建员工、编辑员工信息。
  • 管理员可以设置用户类型。
  • 管理员可以查看项目、任务、任务历史记录、员工报告(Crystal Report)。

**创建项目时,管理员将默认成为项目成员。

**只有当项目的所有任务都已关闭时,项目才能被关闭。

7. 所有类型的用户都必须使用用户 ID 和密码登录。根据他们的类型,将会有不同的权限,如前所述。

使用代码

1. 将数据库附加到您的“SQL Server Management Studio Express”。
2. 在 Microsoft Visual Studio 中将应用程序作为网站运行。
3. 定位 Crystal Reports 的数据库。
4. 阅读“How to.txt”和“Readme.txt”。

 

项目详情

三层架构

在这个项目中,我使用了三层架构。UI 层与 BLL 层协作,BLL 层与 DAL 层协作。我使用三层架构是因为它提供了灵活性。一段时间后,如果某个层需要更改,我只会更改该层。那时我将不必担心其他层。例如,如果我想更改一些业务逻辑,我将只关注业务逻辑层(BLL)。那时我不需要考虑整个项目,而只需要考虑一个特定的层。三层架构也为项目带来了更多的面向对象(OOP)的思维。

3_layer.JPG

登录和主页

每个用户都必须使用其用户名和密码登录。点击登录按钮后,页面的代码隐藏会调用 UserManager 类的一个方法 CheckUserIdAndPassword(userID,password),该方法以用户 ID 和密码作为参数,并在数据库中进行检查。如果找到匹配项,则返回用户类型。如果没有找到匹配项,此方法将返回一个空字符串,这被认为是密码错误。代码还添加了一个会话变量,即用户 ID。

登录页面的代码隐藏。

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;


public partial class UI_LogInUI : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        
        if (!Page.IsPostBack)
        {
            Session.Abandon();
            LoadUserId();
        }
    }

    protected void logInButton_Click(object sender, EventArgs e)
    {
        string userType = null;
        try
        {
            UserManager userManagerObject = new UserManager();
            userType = userManagerObject.CheckUserIdAndPassword(employeeIdDropDownList.SelectedItem.Value, passwordTextBox.Text);
        }
        catch (SqlException sqlExceptionObj)
        {
            Label4.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            Label4.Text = exceptionObj.Message;
        }
        

        switch (userType)
        { 
            case "Admin":
                Session["userID"] = employeeIdDropDownList.SelectedItem.Value;
                Response.Redirect("AdimHomePage.aspx");
                break;
            case "Normal":
                Session["userID"] = employeeIdDropDownList.SelectedItem.Value;
                Response.Redirect("NormalUserUIPage.aspx");
                break;
            default:
                Label4.Text = " Invalid Password! Please retype the Password";
                break;
        }
    }

    /// <summary>
    /// Load employeeIdropDownList with existing users
    /// </summary>
    private void LoadUserId()
    {
        try
        {
            UserManager userManagerObject = new UserManager();
            employeeIdDropDownList.DataSource = userManagerObject.GetUserTable();
            employeeIdDropDownList.DataTextField = "user_Employee_Id";
            employeeIdDropDownList.DataValueField = "user_Employee_Id";
            employeeIdDropDownList.DataBind();
        }
        catch (SqlException sqlExceptionObj)
        {
            Label4.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            Label4.Text = exceptionObj.Message;
        }
    }
}

		

 

登录后,管理员用户和普通用户将根据他们的用户类型看到不同的主页。

管理员主页

我为两种不同的用户类型使用了两个不同的母版页。管理员母版页有一个提供管理权限的菜单。

2.AdminHomeUI.JPG

用户主页

 

3.User_home.JPG

 

 

两个母版页都从会话变量中检索用户 ID,并填充用户的任务和项目列表。

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class UI_MasterPage : System.Web.UI.MasterPage
{
    string employeeId = null;
    string employeeName = null;
    protected void Page_Load(object sender, EventArgs e)
    {

        try
        {
            employeeId = Session["userID"].ToString();
            employeeName = GetEmployeeName();
            userNameLabel.Text = "Admin user : " + employeeName;
            Session["userName"] = employeeName;
        }
        catch (NullReferenceException nullReferenceExceptionObject)
        {
            userNameLabel.Text = "Cant find User Id. Session time may out. "+nullReferenceExceptionObject.Message;
            mainContentPlaceHolder.Visible = false;
            menuMain.Visible = false;
            homeHyperLink.Visible = false;
        }
    }

    private string GetEmployeeName()
    {
        EmployeeManager employeeManagerObject = new EmployeeManager();
        Employee employeeObject= employeeManagerObject.SelectEmployee(employeeId);
        return employeeObject.Name;
    }

} 

 

用户主页包含两个项目符号列表。一个列出所有项目,另一个列出所有开放的任务。项目项目符号列表的显示模式是“文本”,任务项目符号列表的显示模式是“链接按钮”。

我使用任务 ID 作为项目符号列表中项目的 Value 来找出哪个任务被选中。由于项目符号列表包含 List Items,并且项目符号列表不直接提供选定项目的 Value,因此我使用了一个巧妙的解决方案来找出用户点击的项目符号列表项(任务)的 Value。我使用“BulletedListEventArgs e”,它为 System.Web.UI.WebControls.BulletedList.Click 事件提供了数据。我将触发事件的项目保存在一个 List Item 变量中,并从中获取 Value。

 

 

protected void tasksOfUserBulletedList_Click(object sender, BulletedListEventArgs e)
    {
        ListItem listItemObj = tasksOfUserBulletedList.Items[e.Index];
        taskId = listItemObj.Value;
        Session["taskID"] = taskId;
        Response.Redirect("AdminViewTaskUIPage.aspx");
    }

 

任务

如果用户点击一个任务,页面将重定向到另一个页面,在该页面中他将能够看到任务详情、评论和与该任务相关的附件。他可以评论任务,上传文件,以及下载与任务相关的附件。如果用户想将任务转交给任何其他员工,他也可以执行此操作。

这是本项目的主要业务部分。

1.Task_view.JPG 

注释

用户可以评论此任务。此评论可用作备忘录或指示。

2.Task_view_comment1.JPG

请注意,评论与任务一起保存。

3.Task_view_comment2.JPG

上传文件

用户还可以将文件作为附件上传到任务中。

4.Task_view_attach_file1.JPG

请注意,文件已附加到任务中,并列在图片右侧。另外请注意,用户在附件中插入了一条评论,这会说明谁上传了文件以及文件的作用。

5.Task_view_attach_file2.JPG

关于发布评论和上传文件(附件)的代码隐藏。

protected void postCommentButton_Click(object sender, EventArgs e)
    {
        if (DataValidator.IsEmpty(commentTextBox.Text))
        {
            errorLabel.Text = "No comment to post";
            return;
        }
        SaveComment();
        commentTextBox.Text = "";
    }

    /// 
    /// Save a comment
    /// If there a attachment upload it
    /// 
    private void SaveComment()
    {
        try
        {
            Comment commentObj = new Comment();

            if (attachmentFileUpload.PostedFile.FileName != "")
            {
                UploadAttachment();

                string fileName = attachmentFileUpload.FileName;
                string fileDestinationPath = @"Attached files\" + fileName;
                    //In DB attachment File location will be "Attached files\+ fileName"
                    //while downloading the file virtual path will be added to create full path
                commentObj.CommentAttachment = fileDestinationPath;
            }

            commentObj.CommentTaskId = taskObj.Id;
            commentObj.CommentEmployeeName = taskObj.Employee_AssignTo;
            commentObj.CommentEmployeeId = taskObj.Employee_Id;
            commentObj.CommentDate = System.DateTime.Now;
            commentObj.Comments = commentTextBox.Text;
            CommentManager commentManagerObject = new CommentManager();
            commentManagerObject.SaveComment(commentObj);
            LoadAllComments();
        }
        catch (PrimaryKeyException primaryKeyExceptionObj)
        {
            errorLabel.Text = primaryKeyExceptionObj.Message;
        }
        catch (SqlException sqlExceptionObj)
        {
            errorLabel.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            errorLabel.Text = exceptionObj.Message;
        }
    }

    /// 
    /// Upload a attachment
    /// 
    private void UploadAttachment()
    {
        /* All attachment will be saved in 
         * virtual path + \Attached files\ + file name
         * */

        try
        {
            string fileSourcePath = attachmentFileUpload.PostedFile.FileName;
            string fileName = attachmentFileUpload.FileName;
            string fileDestinationPath = Server.MapPath("~/");
            fileDestinationPath = fileDestinationPath + @"Attached files\" + fileName;
            WebClient webClientObj = new WebClient();
            webClientObj.UploadFile(fileDestinationPath, fileSourcePath);
        }
        catch (SqlException sqlExceptionObj)
        {
            errorLabel.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            errorLabel.Text = exceptionObj.Message;
        }
    }

下载文件

用户可以通过点击附件项目符号列表中的文件来下载任务的附件。这将打开一个下载窗口。用户可以将文件保存在其硬盘驱动器上或直接打开。请记住,如果用户 PC 上安装了任何“下载加速器”,它将强制下载 .aspx 页面而不是文件。因此,在尝试下载任何附件之前,请禁用(任何)“下载加速器”。

下载窗口。

6.Task_view_download_attach_file1.JPG

选择下载文件的位置。

7.Task_view_download_attach_file2.JPG

下载完成。

8.Task_view_download_attach_file3.JPG

关于下载文件(附件)的代码隐藏。

 

    protected void attachmentBulletedList_Click(object sender, BulletedListEventArgs e)
    {
        try
        {
            ListItem listItemObj = attachmentBulletedList.Items[e.Index];
            string sourcePath = listItemObj.Value;
            Response.AddHeader("Content-Disposition", "attachment;filename=\"" + listItemObj.Text + "\"");
            Response.ContentType = "application/octet-stream";
            Response.WriteFile(listItemObj.Value);
        }
        catch (SqlException sqlExceptionObj)
        {
            errorLabel.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            errorLabel.Text = exceptionObj.Message;
        }
    }

转交任务

用户还可以将任务转交给项目中的其他员工。要转交任务,用户必须勾选“转交给”复选框。勾选后,将出现一个下拉列表和一个带有“发布并转交”文本的新按钮,而“发布评论”按钮将消失。下拉列表包含项目中的所有员工。如果用户取消勾选“转交给”复选框,“发布并转交”按钮和下拉列表将消失,“发布评论”按钮将重新出现。

请注意,用户正在将任务转交给项目中的另一位员工,名为“Habibur Rahman”。任务只能转交给同一项目中的员工。转交前,用户必须在任务中添加评论,说明下一步操作或任务状态。在转交时也可以附加文件。

9.Task_view_forwarding1.JPG

转交任务后,用户将不再处理该任务,因此该任务将从其主页的任务列表中移除。

10.Task_view_forwarding2.JPG

当任务的新用户“Habibur Rahman”登录时,他将在其任务列表中看到该任务。

请注意,用户名不同。

11.Task_view_forwarding3.JPG

新用户现在可以处理该任务。

12.Task_view_forwarding4.JPG

关于将任务转交给项目其他员工的代码隐藏。

 

    protected void postAndForwardButton_Click(object sender, EventArgs e)
    {
        if (DataValidator.IsEmpty(commentTextBox.Text))
        {
            errorLabel.Text = "Please enter forwarding comment";
            return;
        }
        else if (employeeNameDropDownList.SelectedIndex.Equals(0))  // Item in index 0 is "-Select-" and not a valid item. So must not use
        {
            errorLabel.Text = "Please select an employee";
            return;
        }
        SaveComment();
        ForwardTask();
        commentTextBox.Text = "";
        Response.Redirect("AdimHomePage.aspx");
    }

    /// 
    /// Forward the task to a employee of its project
    /// 
    private void ForwardTask()
    {
        try
        {
            TaskManager taskManagerObj = new TaskManager();
            Task taskObject = new Task();
            taskObject.Id = taskIdTextBox.Text;
            taskObject.Employee_Id = employeeNameDropDownList.SelectedItem.Value;
            taskObject.Employee_AssignTo = employeeNameDropDownList.SelectedItem.Text;
            taskObject.Employee_AssigenBy = taskObj.Employee_Id;
            taskObject.Project_Id = projectIdTextBox.Text;
            taskObject.StartDate = System.DateTime.Now;
            string forwardStatus = taskManagerObj.ForwardATask(taskObject);
        }
        catch (SqlException sqlExceptionObj)
        {
            errorLabel.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            errorLabel.Text = exceptionObj.Message;
        }
    }

关闭任务

管理员可以关闭分配给他的任何任务。管理员不能关闭未分配给他的任务,因为其他员工可能正在处理该任务。

在管理员任务页面,有一个用于关闭任务的链接按钮。如果管理员要关闭任务,他必须点击链接按钮,然后将出现以下页面。

13.Task_view_close_task.JPG

点击“关闭任务”按钮后,页面将重定向到主页,并显示一个带有任务关闭状态的标签。

14.Task_view_close_task_2.JPG

关于关闭任务的代码隐藏。

protected void closeTaskButton_Click(object sender, EventArgs e)
    {
        try
        {
            TaskManager taskManagerObject = new TaskManager();
            taskObj = taskManagerObject.SelectTask(taskId);
            taskObj.TaskStatus = "Close";
            message = taskManagerObject.CloseTask(taskObj);
            SaveClosingComment();
            Response.Redirect("AdimHomePage.aspx?" + "&message=" + Server.UrlEncode(message));
        }
        catch (SqlException sqlExceptionObj)
        {
            errorLabel.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            errorLabel.Text = exceptionObj.Message;
        }
    }

    /// 
    /// saves a comment that will say who and when closed the task
    /// 
    private void SaveClosingComment()
    {
        try
        {
            Comment commentObj = new Comment();
            commentObj.CommentTaskId = taskObj.Id;
            commentObj.CommentEmployeeName = taskObj.Employee_AssignTo;
            commentObj.CommentEmployeeId = taskObj.Employee_Id;
            commentObj.CommentDate = System.DateTime.Now;
            commentObj.Comments = "This task is colsed by admin :" + taskObj.Employee_AssignTo;
            CommentManager commentManagerObject = new CommentManager();
            commentManagerObject.SaveComment(commentObj);
        }
        catch (PrimaryKeyException primaryKeyExceptionObj)
        {
            errorLabel.Text = primaryKeyExceptionObj.Message;
        }
        catch (SqlException sqlExceptionObj)
        {
            errorLabel.Text = sqlExceptionObj.Message;
        }
        catch (Exception exceptionObj)
        {
            errorLabel.Text = exceptionObj.Message;
        }
    }

所有任务(仅查看)

管理员可以查看所有任务(已分配+未分配)。

15.Task_view_All_task.JPG

16.Task_view_All_task_2.JPG

注意最后一条评论。在关闭任务时,它会自动添加。

17.Task_view_All_task_3.JPG

Crystal Reports

本项目有五个 Crystal Reports 和五个 .aspx 页面来查看它们。要在 .aspx 页面中查看 Crystal Report,必须在 .aspx 页面中使用“CrystalReportViewer”。在本例中,每个页面都包含一个“CrystalReportViewer”,用于加载 Crystal Report(.rpt)页面。

Crystal Reports 有:

ReportEmployee.rpt --> 查看所有用户信息
ReportProject.rpt --> 查看所有项目信息
ReportTask.rpt --> 查看所有任务信息
TaskHistory.rpt --> 查看所有任务历史记录
TasksOfProject.rpt --> 查看所有项目及其任务

任务和项目报告

要查看所有项目及其任务,请点击“查看报告”-->“任务和项目”。

18.Task_view_Report1.JPG

此报告显示所有项目及其任务、各个任务的状态(打开/关闭)、项目状态。

19.Task_view_Report_2.JPG

任务历史记录报告

要查看单个任务的历史记录,请点击“查看报告”-->“任务历史记录”。

20.Task_view_Report_3.JPG

此报告显示单个任务的历史记录。用户可以了解谁创建了任务,谁将任务转交给了谁以及何时。

21._Task_view_Report_4.JPG

用户报告

要查看所有用户详细信息,请点击“查看报告”-->“用户”。此报告显示员工 ID、姓名、地址、电子邮件 ID、电话号码、用户类型和用户数量。

23.Report_user2.JPG

项目报告

此报告查看所有项目信息和状态。

25.Report_project2.JPG

任务报告

此报告查看所有任务信息和状态。

27.Report_task2.JPG

在每个 .aspx 页面的代码隐藏页面中是:

 

protected void Page_Load(object sender, EventArgs e)
    {
        string reportSourcePath = Server.MapPath("~/") + @"Reports\ReportProject.rpt";
        projectCrystalReportViewer.ReportSource = reportSourcePath;
    }
请注意,Server.MapPath("~/") 找到虚拟路径,ReportProject.rpt 是 crystal report。

异常

1. 异常
2. SqlException
3. NullReferenceException
4. NonUserEmployeeException
5. OnlyOneAdminException
6. PrimaryKeyException

这些是我在此项目中使用的异常。

PrimaryKeyException

用户定义的异常。

尝试使用现有主键将数据插入数据库时发生的异常。

OnlyOneAdminException

用户定义的异常。

当尝试更改管理员的用户类型(从管理员用户更改为普通用户)时,如果该管理员是某个项目唯一的管理员用户,则无法更改其用户类型,因为只有管理员才能关闭任务和项目。如果唯一的管理员变成普通类型,那么没有人能够关闭任务和项目。此时将发生此异常。

NonUserEmployeeException

用户定义的异常。

当尝试获取员工的用户类型(管理员/普通)时,如果该员工不是用户,则会发生此异常。

注意:并非所有员工都是用户。

NullReferenceException

预定义异常

SqlException

预定义异常

异常

预定义异常

© . All rights reserved.