WPF開發查詢加班小工具


  先說一下,我們公司是六點下班,超過7點開始算加班,但是加班的時間是從六點開始計算,以0.5個小時為計數,就是你到了六點半,不算加班半小時,但是加班到七點半,就是加班了一個半小時。

一、打卡記錄

  首先,看一下我們公司的打卡記錄,公司的打卡工具是不區分上下班的,而且一天可以打多次,也可能忘記打卡,這都是有可能的,人在觀察這些數據的時候,可以輕易的分辨出什么是上班時間,什么是下班時間,並且是不是我忘打卡了,但是一旦放到程序里,判斷的邏輯就復雜了。

二、加班申請單

  加班申請單,也就是程序最后需要導出的Word文件,樣子是這樣的,頁眉處是公司的LOGO,中部是標題,然后是一個表格

三、小工具效果演示

  姓名部分如果不用選擇按鈕,選擇部門人員名單的話,也可以手動填寫

  備注、申請人和申請時間是可以不填寫的,如果不填寫,則最后導出的Word相應的位置就是空。

四、開發過程

1、由於我們的加班申請單,是有固定的幾個部分組成的,姓名,加班類型,加班時間起、止,小時數和備注,因此,創建了一個實體類OverTimeModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections;

namespace SelectWorkOvertime
{
    public class OverTimeModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void INotifyPropertyChanged(string name)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        private string name;//姓名
        private string overtimeType;//加班類型
        private string overtimeStart;//加班時間起
        private string overtimeEnd;//加班時間止
        private string overtimeHours;//小時數
        private string remark;//備注

        public string Name//姓名
        {
            get
            {
                return name;
            }

            set
            {
                name = value;
                INotifyPropertyChanged("Name");
            }
        }        

        public string OvertimeType//加班類型
        {
            get
            {
                return overtimeType;
            }

            set
            {
                overtimeType = value;
                INotifyPropertyChanged("OvertimeType");
            }
        }

        public string OvertimeStart//加班時間起
        {
            get
            {
                return overtimeStart;
            }

            set
            {
                overtimeStart = value;
                INotifyPropertyChanged("OvertimeStart");
            }
        }

        public string OvertimeEnd//加班時間止
        {
            get
            {
                return overtimeEnd;
            }

            set
            {
                overtimeEnd = value;
                INotifyPropertyChanged("OvertimeEnd");
            }
        }

        public string OvertimeHours//小時數
        {
            get
            {
                return overtimeHours;
            }

            set
            {
                overtimeHours = value;
                INotifyPropertyChanged("OvertimeHours");
            }
        }

        public string Remark//備注
        {
            get
            {
                return remark;
            }

            set
            {
                remark = value;
                INotifyPropertyChanged("Remark");
            }
        }
    }
}
OverTimeModel

2、需要寫要給工具類,這個工具類包含的內容如下:

  讀取Excel(打卡記錄是Excel文件)

  讀取TXT文檔(部門人員名單是TXT文件)

  判斷Excel中的所有時間是工作日還周末,還是節假日(加班類型是有這三種的,因為有的時候節假日加班我們不用調休,給雙倍工資)

  計算兩個時間的小時差、獲取上一天等

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace SelectWorkOvertime
{
    public class Tools
    {
        /// <summary>
        /// 讀取TXT文檔
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public string ReadTxt(string path)
        {
            string lines = "";
            StreamReader streamReader = new StreamReader(path, Encoding.Default);
            string line;
            while ((line = streamReader.ReadLine()) != null)
            {
                lines += line.ToString() + " ";
            }
            return lines;
        }
        /// <summary>
        /// 調用遠程接口
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public string IsHoliday(string date)
        {
            string url = @"http://www.easybots.cn/api/holiday.php?d=";
            url = url + date;
            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
            httpRequest.Timeout = 20000;
            httpRequest.Method = "GET";
            HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            StreamReader sr = new StreamReader(httpResponse.GetResponseStream(), System.Text.Encoding.GetEncoding("gb2312"));
            string result = sr.ReadToEnd();
            result = result.Replace("\r", "").Replace("\n", "").Replace("\t", "");
            int status = (int)httpResponse.StatusCode;
            sr.Close();
            return result;
        }
        /// <summary>
        /// 讀取Excel到Dataset
        /// </summary>
        /// <param name="Path"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public DataSet ExcelToDS(string Path, string fileName)
        {
            string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + Path + ";" + "Extended Properties=Excel 8.0;";
            OleDbConnection conn = new OleDbConnection(strConn);
            conn.Open();
            string strExcel = "";
            OleDbDataAdapter myCommand = null;
            DataSet ds = null;
            strExcel = "select * from [" + fileName + "$]";
            myCommand = new OleDbDataAdapter(strExcel, strConn);
            ds = new DataSet();
            myCommand.Fill(ds, "table1");
            return ds;
        }
        /// <summary>
        /// 獲取日期的類型,是工作日,周末或節假日
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public string getDateType(string dateTime)
        {
            string date = Convert.ToDateTime(dateTime.Split(' ')[0].ToString()).ToString("yyyyMMdd");//獲得到日期
            string isHoliday = IsHoliday(date);
            string numHoliday = isHoliday.Substring(isHoliday.Length - 3, 1);
            if (numHoliday == "1" || numHoliday == "2")//判斷是不是節假日{2},或者周末{1}
            {
                return numHoliday;
            }
            else
                return "0";//返回工作日{0}
        }
        /// <summary>
        /// 獲取小時值
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public string getTimeHour(string dateTime)
        {
            string timeSFM = dateTime.Split(' ')[1].ToString();//時分秒
            string timeHour = timeSFM.Split(':')[0].ToString();
            return timeHour;
        }
        /// <summary>
        /// 計算小時差值 正常情況
        /// </summary>
        /// <param name="dateStart"></param>
        /// <param name="dateEnd"></param>
        /// <returns></returns>
        public string CalTimesNormal(DateTime dateStart, DateTime dateEnd)
        {
            string numTime;
            TimeSpan ts = dateEnd.Subtract(dateStart);
            if (ts.Minutes >= 30)
            {
                numTime = (ts.Hours + 0.5).ToString();
            }
            else
            {
                numTime = ts.Hours.ToString();
            }
            return numTime;
        }
        /// <summary>
        /// 計算小時差值 上班時間在12點之前的加班要減去1小時
        /// </summary>
        /// <param name="dateStart"></param>
        /// <param name="dateEnd"></param>
        /// <returns></returns>
        public string CalTimesAllDay(DateTime dateStart, DateTime dateEnd)
        {
            string numTime;
            TimeSpan ts = dateEnd.Subtract(dateStart);
            if (ts.Minutes >= 30)
            {
                numTime = (ts.Hours + 0.5 - 1).ToString();
            }
            else
            {
                numTime = (ts.Hours - 1).ToString();
            }
            return numTime;
        }
        /// <summary>
        /// 獲取上一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public string getDateBefore(string dateTime)
        {
            string dateBefore = Convert.ToDateTime(dateTime).AddDays(-1).ToString();
            return dateBefore;
        }
        /// <summary>
        /// 比較兩個時間是否相同
        /// </summary>
        /// <param name="dateTime1"></param>
        /// <param name="dateTime2"></param>
        /// <returns></returns>
        public int getCompareDate(string dateTime1, string dateTime2)
        {
            DateTime dt1 = Convert.ToDateTime(dateTime1.Split(' ')[0].ToString());
            DateTime dt2 = Convert.ToDateTime(dateTime2.Split(' ')[0].ToString());
            if (dt1 == dt2)
                return 1;
            return 0;
        }
    }
}
Tool

3、寫一個設定加班開始時間的類

  因為由於規則不一樣,因此加班的開始時間是不一樣的,例如:

  周一到周五 18:00以后下班,加班不超過當天或者加班到第二天

  周末或者假日 上班時間為9:00 之前或9:00之后

  周末或者假日 打卡時間在12點到13點之間

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SelectWorkOvertime
{
    /// <summary>
    /// 計算在不同的規則下加班的開始時間
    /// </summary>
    public class OverTimeStart
    {
        Tools tools = new Tools();

        /// <summary>
        /// 周一到周五 18:00以后下班,加班不超過當天
        /// </summary>
        /// <param name="dateTime">當天下班打卡時間</param>
        /// <returns></returns>
        public string OverTimeStart1(string dateTime)
        {
            DateTime dateTimeStart = Convert.ToDateTime(dateTime.Split(' ')[0].ToString() + " 18:00:00");
            return dateTimeStart.ToString("yyyy-MM-dd HH:mm");
        }
        /// <summary>
        /// 周一到周五 18:00以后下班,加班到第二天
        /// </summary>
        /// <param name="dateTime">當天下班打卡時間</param>
        /// <returns></returns>
        public string OverTimeStart2(string dateTime)
        {
            DateTime dateTimeStart = Convert.ToDateTime(tools.getDateBefore(dateTime).Split(' ')[0].ToString() + " 18:00:00");
            return dateTimeStart.ToString("yyyy-MM-dd HH:mm");
        }
        /// <summary>
        /// 周末或者假日 上班時間為9:00 之前
        /// </summary>
        /// <param name="dateTime">當天上班打卡時間</param>
        /// <returns></returns>
        public string OverTimeStart3(string dateTime)
        {
            DateTime dateTimeStart = Convert.ToDateTime(dateTime.Split(' ')[0].ToString() + " 9:00:00");
            return dateTimeStart.ToString("yyyy-MM-dd HH:mm");
        }
        /// <summary>
        /// 周末或者假日 上班時間為9:00 之后 
        /// </summary>
        /// <param name="dateTime">當天上班打卡時間</param>
        /// <returns></returns>
        public string OverTimeStart4(string dateTime)
        {
            DateTime dateTimeStart = Convert.ToDateTime(dateTime);
            return dateTimeStart.ToString("yyyy-MM-dd HH:mm");
        }
        /// <summary>
        /// 周末或者假日 打卡時間在12點到13點之間
        /// </summary>
        /// <param name="dateTime">當天上班打卡時間</param>
        /// <returns></returns>
        public string OverTimeStart5(string dateTime)
        {
            DateTime dateTimeStart = Convert.ToDateTime(dateTime.Split(' ')[0].ToString() + " 13:00:00");
            return dateTimeStart.ToString("yyyy-MM-dd HH:mm");
        }
    }
}
OverTimeStart

4、寫主頁面的內容

  由於公司沒有重名的,因此在讀取了Excel后,只從里面取了姓名和時間字段,其他字段都拋棄掉,而加班申請表上的“加班類型,加班時間起、止,小時數”這四列,都是根據時間字段來進行計算得出的。

  由於打卡時間本身的問題,我在前面也提到了,可能存在重復打卡,漏打的問題,所以,在計算加班上,就會出現不准的現象,所以為了提醒小伙伴,就用了一個轉換器,把加班小於0的,顯示為紅色;小於0.5小時的,顯示為黃色;大於12小時的顯示為綠色,大於12小時是有可能正確的,但是一般不會出現,所以提醒一下比較好,而小於0的,就是數據不正確了,如圖

  小冉和王哥對應的周末加班上,由於顏色標注,就知道應該是數據方面可能存在問題了,這樣就要去查看原始的打卡記錄,如圖

  小冉的是沒有問題的

  王哥是因為都打了兩次卡,導致軟件在邏輯判別時出現了問題,所以加班記錄里的那條負值就可以在導出的Word里刪除掉了。

5、導出

  導出Word的話,就是常用的C#操作Word,沒什么。

6、總結

  軟件本身在技術上不是很難,用到異步線程、Linq、對文件的操作、轉換器,基本都是常用的技術,難點其實就是在邏輯的判斷上,無法做到全面的無誤的去合理的計算出加班時間和加班類型,十分感謝彭哥,因為在寫第一個版本的時候,讓邏輯都快搞崩潰了,是彭哥告訴我,可以寫每一個小的邏輯,然后再把小的邏輯組合成大的邏輯。總起來說,做這個小軟件還有有技術上和思維上的收獲的,仁者見仁智者見智吧,最起碼,以后基本上不需要人手動的去寫加班申請了,誰讓懶是程序員的天性呢。

注:軟件存在以下BUG

  1、還是邏輯上不完善

  2、由於是調用的WEB上提供的接口去判斷,是工作日、節假日、周末,例如閱兵就是節假日,所以,軟件運行時需要聯網

 

GitHub源碼

希望園里的朋友批評指正,大家一起探討,共同進步。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM