考勤系统实训报告

一、考勤系统需求分析

1.背景

随着信息技术的高速发展,各行各业都充分利用信息平台提高自己的管理效率。当今国内各企业已纷纷建立企业局域网,依托局域网使用各种信息管理系统,使管理效率显著提高。

2.系统目标

该系统将实现五大功能(登陆功能、注册功能、打卡功能、查询功能、统计功能),将使考勤管理更加系统化、信息化、高效化、准确化,让管理更上一层台阶;同时满足快速有效的打卡需求,提高员工的出勤率以及积极性。

3.功能需求

各大功能模块

  • 登陆功能模块
  • 注册功能模块
  • 打卡功能模块
  • 查询功能模块
  • 统计功能模块

功能模块图

功能模块图

4.非功能需求

非功能性需求是指除功能性需求以外的所有需求,一般分为部署环境需求,接口需求,安全需求,性能需求,界面需求。

(1)部署环境需求:部署环境一般是指客户所在公司或者部门的IT环境,电脑系统环境,与该软件相关的构件。

(2)接口需求:数据通信协议,比如TCP/IP、UDP协议等。

(3)安全需求:该系统对安全性需求不高,能保证数据不丢失则行。

(4)性能需求:至少可以允许同一个时间20个用户访问系统。查询服务用户通过电脑提交命令道返回结果不超过2秒钟。具有较高的稳定性

(5)界面需求:界面设计应该简洁易懂,该部分需求应该不断优化,直至符合用户习惯。

5.软件与硬件

系统拓扑图

网络拓扑图.jpg

6.设计和实现的限制

对于一个现代化的考勤来说,考勤管理是必须的。如何把每天发生的考勤信息如实地记录下来,保证考勤工作有条理地进行,同时确保相关数据的安全,信息处理的高效,并且保证系统的实用性强。详细设计阶段的根本目标是确定应该怎样具体的实现所要求的系统,也就是说,经过这个阶段的设计工作,应该得出目标系统的精确描述,从而在编码阶段可以把这个描述直接翻译成用某总程序设计语言书写的程序。详细设计的目标不仅仅是逻辑上正确地实现每个模块的功能,更重要的是设计的处理过程应该尽可能简明易懂。

  1. 设计限制
  • 系统体系结构的搭建
  • 开发软件,包括:ASP、IIS、SQL Server、Dreamweaver
  • 数据库的设计,包括:概念结构设计和逻辑结构设计
  • 软硬件平台搭建
  1. 实现限制
  • 登陆功能模块
  • 注册功能模块
  • 打卡功能模块
  • 查询功能模块
  • 统计功能模块

二、考勤系统数据库设计

1.标识实体

  • 打卡机
  • 员工

2.E-R图

ER图

3.数据表

数据表

4.数据库表

  • 一个数据库:kaoqin
  • 三个表,分别是card_machine(打卡机表)、worker(员工表)、statistic(打卡信息表)
create DATABASE kaoqin
use kaoqin
create table card_machine(
number varchar(15) primary key,
location varchar(10),
machine_type varchar(10),
methods varchar(10)
)
use kaoqin
create table worker(
number varchar(15) primary key,
gender varchar(10),
age varchar(5),
department varchar(15)
)
use kaoqin
create table statistic(
number varchar(15) primary key,
machine_number varchar(15),
worker_number varchar(15),
shijian varchar(10),
cishu varchar(10),
foreign key(machine_number) references card_machine(number),
foreign key(worker_number) references worker(number)
)

三、考勤系统界面设计

1.考勤系统功能实现——登录

(1)登录界面设计

登录界面

(2)登录界面实现代码

  • 点击登录按钮实现登录功能
// 点击“登录”按钮则登录系统
        private void bt_Login_Click(object sender, EventArgs e)
        {

            String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
            SqlConnection sqlConn = new SqlConnection(connStr);

            try
            {
                // 连接数据库
                sqlConn.Open();

                // 构造命令发送给数据库
                String sqlStr = "select * from employee where ID=@id and PASSWORD=@pwd";
                SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);

                // 注意是用用户ID登录,而不是用户名,用户名可能会重复
                cmd.Parameters.Add(new SqlParameter("@id", this.tb_User.Text.Trim()));
                cmd.Parameters.Add(new SqlParameter("@pwd", this.tb_Password.Text.Trim()));

                SqlDataReader dr = cmd.ExecuteReader();

                // 如果从数据库中查询到记录,则表示可以登录
                if (dr.HasRows)
                {
                    dr.Read();
                    WorkerInfo.userPwd = dr["PASSWORD"].ToString(); 
                    WorkerInfo.userId = dr["ID"].ToString();
                    WorkerInfo.userDepartment = dr["department"].ToString();
                    WorkerInfo.userGender = dr["gender"].ToString();
                    WorkerInfo.userAuthority = dr["authority"].ToString();
                    WorkerInfo.userName = dr["name"].ToString()
                    MessageBox.Show(WorkerInfo.userAuthority + "登录成功");

                    if (WorkerInfo.userAuthority == "common")
                    {
                        // 显示普通员工员主界面
                        MainFormUser formUser = new MainFormUser();
                        formUser.Show();

                        // 隐藏登录界面
                        this.Hide();
                    }

                    if (WorkerInfo.userAuthority == "manager")
                    {
                        // 显示库管员主界面
                        MainFormAdmin formAdmin = new MainFormAdmin();
                        formAdmin.Show();

                        // 隐藏登录界面
                        this.Hide();
                    }
                }
                else
                {
                    MessageBox.Show("用户名或密码错误", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception exp)
            {
                MessageBox.Show("访问数据库错误:" + exp.Message);
            }
            finally
            {
                sqlConn.Close();
            }
        }

2.考勤系统功能实现——注册

1.员工注册界面设计

注册

2.注册界面实现代码

  • 录入界面加载同时自动给定新员工号
        private void RecordForm2_Load(object sender, EventArgs e)
        {
            String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;

            SqlConnection sqlConn = new SqlConnection(connStr);
            try
            {
                // 连接数据库
                sqlConn.Open();

                // 构造命令发送给数据库
                String sqlStr = "select MAX(id+1) as id from employee";
                SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);


                SqlDataReader dr = cmd.ExecuteReader();
                //取出数据库中的值并赋给文本框
                if (dr.HasRows)
                {
                    dr.Read();
                    this.worker_Id.Text = dr["ID"].ToString();
                }
  
            }
            catch (Exception exp)
            {
                MessageBox.Show("访问数据库错误:" + exp.Message);
            }
            finally
            {
                sqlConn.Close();
            }
        }
  • 点击“录入”按键实现注册功能
        // 点击“确认”按钮,则录入员工
        private void bt_Ok_Click(object sender, EventArgs e)
        {
            String id = this.worker_Id.Text.Trim();
            String name = this.worker_Name.Text.Trim();
            String gender = this.worker_Gender.Text.Trim();
            String department = this.worker_Department.Text.Trim();
            String authority = this.worker_Authority.Text.Trim();
            String password = this.worker_Password.Text.Trim();

            // 更新数据库
            String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
            SqlConnection sqlConn = new SqlConnection(connStr);
            try
            {                

                // 连接数据库
                sqlConn.Open();

                // 构造命令
                
                String sqlStr = "insert into employee(ID, name, gender, department, authority, PASSWORD) values(@id, @name, @gender, @department, @authority, @password)";
                SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
                
                // SQL字符串参数赋值
                cmd.Parameters.Add(new SqlParameter("@id", id));
                cmd.Parameters.Add(new SqlParameter("@name", name));
                cmd.Parameters.Add(new SqlParameter("@gender",gender ));
                cmd.Parameters.Add(new SqlParameter("@department", department));
                cmd.Parameters.Add(new SqlParameter("@authority", authority));
                cmd.Parameters.Add(new SqlParameter("@password", password));

                // 将命令发送给数据库
                int res = cmd.ExecuteNonQuery();

                // 根据返回值判断是否插入成功
                if (res != 0)
                {
                    MessageBox.Show("员工信息录入成功");
                }
                else
                {
                    MessageBox.Show("员工信息录入失败");
                }
            }
            catch (Exception exp)
            {
                MessageBox.Show("访问数据库错误:" + exp.Message);
            }
            finally
            {
                sqlConn.Close();
            }
        }

3.考勤系统功能实现——打卡

1.打卡界面设计

打卡界面

2.打卡界面实现代码

  • 打开串口
        private void buttonOpenCOM_Click(object sender, EventArgs e)
        {
            // 串口已打开,此时需要关闭
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
                this.toolStripStatusLabel1.Text = "已关闭串口" + serialPort1.PortName.ToString();
                buttonOpenCOM.Text = "打开";
                return;
            }
            // 否则打开串口
            else
            {
                serialPort1.PortName = comboBoxCOMList.Text;
                InitSerialPort();

                try
                {
                    serialPort1.Open();
                    this.toolStripStatusLabel1.Text = "已打开串口" + serialPort1.PortName.ToString();
                    buttonOpenCOM.Text = "关闭";
                }
                catch (Exception ex)
                {
                    this.toolStripStatusLabel1.Text = "打开串口失败,原因:" + ex.Message;
                    return;
                }
            }
        }
  • 关闭串口
        private void ServiceForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 如果关闭窗口时,串口仍然为打开状态,则需要关闭串口
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
            }
        }
  • 向卡片写入信息
        private void bt_Register_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen)
            {
                this.toolStripStatusLabel1.Text = "请先打开串口";
                return;
            }

            this.toolStripStatusLabel1.Text = "未找到有效的卡";

            // '666'填充为'00000666'
            string stuffId = this.tb_EmployeeId.Text.PadLeft(8, '0');
            // '00000666'转变成'66060000'
            stuffId = ISO15693CardHandler.CovertEndian(stuffId);

            // 检查输入数据的错误
            // ISO15693为32位,4字节,8字符
            if (stuffId.Length != 8)
            {
                MessageBox.Show("请输入4字节的16进制数据!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // 检查16进制字符错误
            if (!ISO15693CardHandler.CheckValidHexBytes(stuffId))
            {
                MessageBox.Show("写入数据的16进制格式错误!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // [TODO] 寻卡,将RFID卡号读出来
            if (!serialPort1.IsOpen)
            {
                MessageBox.Show("串口未打开!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            string response_card = "";

            /*
             * 每发送完一个指令后,睡眠MILLISECOND_IN_SLEEP毫秒,防止数据无法正常读取
             */
            serialPort1.Write(ISO15693Card.COMMAND_WRITE_REG);
            Thread.Sleep(MILLISECOND_IN_SLEEP);
            if (serialPort1.BytesToRead > 0) response_card = serialPort1.ReadExisting();

            serialPort1.Write(ISO15693Card.COMMAND_SET_AGC);
            Thread.Sleep(MILLISECOND_IN_SLEEP);
            if (serialPort1.BytesToRead > 0) response_card = serialPort1.ReadExisting();

            serialPort1.Write(ISO15693Card.COMMAND_SET_RECV_MODE);
            Thread.Sleep(MILLISECOND_IN_SLEEP);
            if (serialPort1.BytesToRead > 0) response_card = serialPort1.ReadExisting();

            serialPort1.Write(ISO15693Card.COMMAND_INVEN_CARD);//寻卡
            Thread.Sleep(MILLISECOND_IN_SLEEP);
            if (serialPort1.BytesToRead > 0) response_card = serialPort1.ReadExisting();//获取返回的字符串

            List<ISO15693Card> cards = ISO15693CardHandler.InventoryCard(response_card);//解析返回的字符串,获取寻到的卡ID

            // [TODO] 向RFID卡第00块写入职员编号数据,无论成功与否,均应该在状态栏显示提示信息
            //检查输入数据的错误
            //ISO15693为32位,4字节,8字符
            if (tb_EmployeeId.Text.Length != 8)
            {
                MessageBox.Show("请输入4字节的16进制数据!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            //检查16进制字符错误
            if (!ISO15693CardHandler.CheckValidHexBytes(tb_EmployeeId.Text))
            {
                MessageBox.Show("写入数据的16进制格式错误!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            WriteSingleBlock(
                ISO15693CardHandler.CovertEndian(cards[0].ID),
                "00",
                tb_EmployeeId.Text);
        }
  • 卡片打卡(向数据库写入员工号、日期、时间等信息)
            // [TODO] 向数据库中插入一条打卡记录,插入成功后显示打卡成功
            //获取时间、日期等数据;
            string date = DateTime.Now.ToString("yyyy-MM-dd");
            string time = DateTime.Now.ToString("hh:mm:ss");

            // 更新数据库
            String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
            SqlConnection sqlConn = new SqlConnection(connStr);
            try
            {

                // 连接数据库
                sqlConn.Open();

                // 构造命令

                String sqlStr = "insert into record(employee_id, date, time, machine_id) values(@employee_id, @date, @time, @machine_id)";
                SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);

                // SQL字符串参数赋值
                cmd.Parameters.Add(new SqlParameter("@employee_id", stuffId));
                cmd.Parameters.Add(new SqlParameter("@time", time));
                cmd.Parameters.Add(new SqlParameter("@date", date));
                cmd.Parameters.Add(new SqlParameter("@machine_id", ""));

                // 将命令发送给数据库
                int res = cmd.ExecuteNonQuery();

                // 根据返回值判断是否插入成功
                if (res != 0)
                {

                    MessageBox.Show("打卡成功");
                }
                else
                {
                    MessageBox.Show("打卡失败");
                }
            }
            catch (Exception exp)
            {
                MessageBox.Show("访问数据库错误:" + exp.Message);
            }
            finally
            {
                sqlConn.Close();
            }

4.考勤系统功能实现——查询

1.查询界面设计

  • 普通员工查询界面


    普通员工查询界面

    员工查询
  • 管理员查询界面


    管理员查询界面

    管理查询

2.查询界面实现代码

  • 普通员工查询个人考勤信息
        //点击查询,查询个人信息
        private void button1_Click(object sender, EventArgs e)
        {
            // 连接字符串,注意与实际环境保持一致
            String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
            SqlConnection sqlConn = new SqlConnection(connStr);
            try
            {
                // 连接数据库
                sqlConn.Open();

                // 构造命令
                String sqlStr = "select * from record where employee_id = @employee ";
                SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
      
                cmd.Parameters.Add(new SqlParameter("@employee", WorkerInfo.userId));

                // 将该查询过程绑定到DataAdapter
                SqlDataAdapter adp = new SqlDataAdapter();
                adp.SelectCommand = cmd;

                // 将DataSet和DataAdapter绑定
                DataSet ds = new DataSet();
                // 自定义一个表(MyGoods)来标识数据库的record表
                adp.Fill(ds, "record");

                // 指定DataGridView的数据源为DataSet的dgv_kaoqin_m表
                this.dgv_kaoqin_m.DataSource = ds.Tables["record"];
            }
            catch (Exception exp)
            {
                MessageBox.Show("访问数据库错误:" + exp.Message);
            }
            finally
            {
                sqlConn.Close();
            }
        }
  • 管理员查询所有人员的考勤信息
        // 查询数据
        private void bt_Query_Click(object sender, EventArgs e)
        {
            // 连接字符串,注意与实际环境保持一致
            String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
            SqlConnection sqlConn = new SqlConnection(connStr);
            try
            {
                // 连接数据库
                sqlConn.Open();

                // 构造命令
                //符合员工号查询
                if (tb_Id.Text.Trim() != "")
                {
                    String sqlStr = "select * from record where employee_id=@id";

                    SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
                    cmd.Parameters.Add(new SqlParameter("@id", this.tb_Id.Text.Trim()));
                    // 将该查询过程绑定到DataAdapter
                    SqlDataAdapter adp = new SqlDataAdapter();
                    adp.SelectCommand = cmd;

                    // 将DataSet和DataAdapter绑定
                    DataSet ds = new DataSet();
                    // 自定义一个表(MyGoods)来标识数据库的GOODS表
                    adp.Fill(ds, "records");

                    // 指定DataGridView的数据源为DataSet的MyGoods表
                    this.dgv_kaoqin_m.DataSource = ds.Tables["records"];
                }

                //符合日期查询
                if (tb_date.Text != "")
                {
                    String sqlStr1 = "select * from record where date=@date";
                    SqlCommand cmd1 = new SqlCommand(sqlStr1, sqlConn);
                    cmd1.Parameters.Add(new SqlParameter("@date", Convert.ToDateTime(tb_date.Text)));
                    //Convert.ToDateTime(dateTimePicker1.Value)
                    // 将该查询过程绑定到DataAdapter
                    SqlDataAdapter adp = new SqlDataAdapter();
                    adp.SelectCommand = cmd1;

                    // 将DataSet和DataAdapter绑定
                    DataSet ds = new DataSet();
                    // 自定义一个表(MyGoods)来标识数据库的GOODS表
                    adp.Fill(ds, "records");

                    // 指定DataGridView的数据源为DataSet的MyGoods表
                    this.dgv_kaoqin_m.DataSource = ds.Tables["records"];
                }
                //员工号、日期共同查询
                if (tb_date.Text.Trim() != "" && tb_Id.Text.Trim() != "")
                {
                    String sqlStr2 = "select * from record where date=@date and employee_id=@id";
                    SqlCommand cmd2 = new SqlCommand(sqlStr2, sqlConn);
                    cmd2.Parameters.Add(new SqlParameter("@date", Convert.ToDateTime(tb_date.Text)));
                    cmd2.Parameters.Add(new SqlParameter("@id", this.tb_Id.Text.Trim()));
                    // 将该查询过程绑定到DataAdapter
                    SqlDataAdapter adp = new SqlDataAdapter();
                    adp.SelectCommand = cmd2;

                    // 将DataSet和DataAdapter绑定
                    DataSet ds = new DataSet();
                    // 自定义一个表(MyGoods)来标识数据库的GOODS表
                    adp.Fill(ds, "records");

                    // 指定DataGridView的数据源为DataSet的MyGoods表
                    this.dgv_kaoqin_m.DataSource = ds.Tables["records"];
                }

                //无条件查询
                if (tb_date.Text.Trim() == "" &&  tb_Id.Text.Trim() == "")
                {
                    String sqlStr3 = "select * from record where 1=1";
                    SqlCommand cmd3 = new SqlCommand(sqlStr3, sqlConn);
                    
                    //Convert.ToDateTime(dateTimePicker1.Value)
                    // 将该查询过程绑定到DataAdapter
                    SqlDataAdapter adp = new SqlDataAdapter();
                    adp.SelectCommand = cmd3;

                    // 将DataSet和DataAdapter绑定
                    DataSet ds = new DataSet();
                    // 自定义一个表(MyGoods)来标识数据库的GOODS表
                    adp.Fill(ds, "records");

                    // 指定DataGridView的数据源为DataSet的MyGoods表
                    this.dgv_kaoqin_m.DataSource = ds.Tables["records"];
                }

            }
            catch (Exception exp)
            {
                MessageBox.Show("访问数据库错误:" + exp.Message);
            }
            finally
            {
                sqlConn.Close();
            }
        }

5.考勤系统功能实现——统计

1.统计界面设计

统计界面

统计界面

2.统计界面实现代码

        private void bt_Query_Click(object sender, EventArgs e)
        {
            // 连接字符串,注意与实际环境保持一致
            String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
            SqlConnection sqlConn = new SqlConnection(connStr);
            try
            {
                // 连接数据库
                sqlConn.Open();

                // 构造命令
                String sqlStr = @"select t4.department,count(*) as count from(
                                    select t3.*, t.name, t.department from (
                                        select t1.employee_id, t1.date, datediff(n,t1.time,t2.time) as diff
                                        from record t1
                                        inner join record t2
                                        on t1.date = t2.date
                                        and t1.employee_id=t2.employee_id
                                        and t1.machine_id =1
                                        and t2.machine_id =2
                                        and t1.date>=@start
                                        and t1.date<=@end
                                    ) t3,employee t where t3.employee_id=t.id
                                ) t4 where t4.diff<540 group by t4.department";

                SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
                cmd.Parameters.Add(new SqlParameter("@start", this.dtp_start.Value.ToShortDateString()));
                cmd.Parameters.Add(new SqlParameter("@end", this.dtp_stop.Value.ToShortDateString()));

                // 将该查询过程绑定到DataAdapter
                SqlDataAdapter adp = new SqlDataAdapter();
                adp.SelectCommand = cmd;

                // 将DataSet和DataAdapter绑定
                DataSet ds = new DataSet();

                // 自定义一个表来标识数据库的record表
                adp.Fill(ds, "tongjib");

                // 指定DataGridView的数据源为DataSet的cx表
                this.dataGridView1.DataSource = ds.Tables["tongjib"];
            }
            catch (Exception exp)
            {
                MessageBox.Show("访问数据库错误:" + exp.Message);
            }
            finally
            {
                sqlConn.Close();
            }
        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            // 点击查看详情
            if (e.RowIndex != -1 && e.ColumnIndex == 0)
            {
                // 获取部门名称
                string department = this.dataGridView1["department", e.RowIndex].Value.ToString();
                detail detailForm = new detail(department, this.dtp_start.Value, this.dtp_stop.Value);
                detailForm.Show();
            }
        }

        private void aggregate_Load(object sender, EventArgs e)
        {
            // 固定上半部分,下半部分随窗口大小调整
            this.splitContainer1.IsSplitterFixed = false;
            this.splitContainer1.FixedPanel = FixedPanel.Panel1;

            // 设置开始时间默认值
            this.dtp_start.Text = "2014/7/1";
        }

四、考勤系统测试

  • 登录


    登录实现
  • 注册


    注册实现
  • 查询


    查询实现
查询实现1
  • 统计


    统计

五、考勤系统发布和安装

  • 在确认无误后对程序进行发布


    发布
  • 安装程序


    安装

六、实训总结

通过此次的实训,我们深入了解到前端开发的步骤和方法,在考勤系统的搭建中,先制定计划,再进行需求分析,接着拟定开发步骤,一步一个脚印、稳扎稳打地从登录到注册、打卡、查询、统计;虽然开发过程中遇到很多的困难和疑问,但有老师的指导和引领,我们也在其中成长了,也收获了许多。
C#作为面向对象的开发语言,对于前端开发十分重要,相对于web开发,C#有着更易于设计的优势,更易懂的编程语言;但是遗憾的是,C#语言中有许多生僻的变量、属性我们从未接触过,在完成此次实训后,我们对其有了更深的见解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342