C语言之考勤模拟系统平台(千行代码)

本文涉及的产品
数据管理 DMS,安全协同 3个实例 3个月
推荐场景:
学生管理系统数据库
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: C语言之考勤模拟系统平台(千行代码)

 考勤模拟系统平台目录

第一章软件需求分析... 1

第二章系统结构设计... 3

2.1 系统架构... 3

2.2 系统组件... 3

2.3 系统流程... 3

第三章数据结构设计... 4

第四章模块划分及各模块功能介绍... 6

4.1 用户模块(User Module)... 6

4.2 组模块(Group Module)... 6

4.3 打卡模块(Clockin Module)... 6

4.4 数据管理模块(Data Management Module)... 7

4.5 安全模块(Security Module)... 7

4.6 用户界面模块(User Interface Module)... 8

4.7 辅助功能模块(Utility Module)... 9

第五章流程图... 8

第六章调试与运行结果... 13

第七章设计心得... 16

参考文献... 17

第一章软件需求分析

1.1 项目背景

随着信息技术的快速发展,考勤管理作为组织管理的重要组成部分,需要更加高效、准确的系统来支持。传统的手工考勤方式存在效率低下、容易出错等问题。为了解决这些问题,我们提出了一个考勤模拟系统,旨在通过计算机程序实现自动化的考勤管理。

1.2 系统目标

本系统旨在实现以下目标:

  • 提供一个用户友好的界面,方便用户进行日常的考勤操作。
  • 实现用户登录和注册功能,确保考勤数据的安全性。
  • 支持用户打卡操作,记录用户考勤时间。
  • 允许用户创建和管理考勤组,以适应不同组织的需求。
  • 提供考勤数据的查询和统计功能,方便管理人员进行考勤审核。

1.3 功能需求

1.3.1 用户模块

  • 用户注册:允许新用户创建账户。
  • 用户登录:允许用户通过用户名和密码登录系统。
  • 用户信息管理:允许用户查看和修改个人信息。

1.3.2 组模块

  • 组创建:允许用户创建新的组,并设置组名。
  • 组成员管理:允许管理员邀请新成员加入组,设置成员的优先级。
  • 组成员查看:允许用户查看自己所在的所有组。

1.3.3 打卡模块

  • 打卡记录:允许用户在指定时间内打卡。
  • 打卡数据查看:允许用户查看自己的打卡记录。
  • 打卡事件创建:允许有权限的用户发布新的打卡事件。

1.3.4 数据管理

  • 数据持久化:系统需要将用户数据、组数据和打卡数据存储在文件中。
  • 数据读取:系统启动时需要从文件中读取现有数据。

1.4 性能需求

  • 系统应能够处理至少 MAX_USER 个用户,MAX_GROUP 个组,以及 MAX_CLOCKIN 条打卡记录。
  • 系统应保证数据的一致性和完整性。

1.5 安全需求

  • 用户密码应进行加密存储,保证用户信息安全。
  • 系统应提供基本的权限控制,确保数据访问安全。

1.6 系统环境

  • 系统应在常见的操作系统上运行,如 WindowsLinux 等。
  • 系统应使用标准 C 语言编写,确保良好的兼容性。

1.7 数据结构设计

1.7.1 用户(User

  • 用户IDuid):唯一标识符。
  • 密码(password):登录凭证。

1.7.2 打卡记录(Clockin

  • 开始时间(begin_time):打卡开始的具体时间。
  • 结束时间(end_time):打卡结束的具体时间。
  • 用户打卡状态数组(in):记录哪些用户已打卡。
  • 所属组(group_from):打卡记录所属的组。

第二章系统结构设计

2.1 系统架构

系统采用分层架构,主要分为以下几个层次:

  1. 数据访问层:负责数据的存取,与文件系统交互,实现数据的持久化。
  2. 业务逻辑层:处理具体的业务需求,如用户注册、登录、打卡等。
  3. 表示层:提供用户界面,与用户进行交互,接收用户输入并展示处理结果。

2.2 系统组件

  1. 用户管理组件
  • 负责处理用户的注册、登录和信息管理。
  • 与数据访问层的用户数据存储进行交互。
  1. 组管理组件
  • 允许用户创建组、管理组成员和查看组信息。
  • 与数据访问层的组数据存储进行交互。
  1. 打卡管理组件
  • 处理用户的打卡请求,记录打卡时间。
  • 与数据访问层的打卡数据存储进行交互。
  1. 数据持久化组件
  • 负责将用户数据、组数据和打卡数据存储到文件系统。
  • 在系统启动时从文件中恢复数据。
  1. 安全组件
  • 负责密码加密和权限控制,确保数据安全。

2.3 系统流程

  1. 启动流程
  • 系统启动时,数据持久化组件从文件中加载数据到内存。
  1. 用户交互流程
  • 用户通过表示层与系统交互,输入命令或数据。
  • 表示层将用户请求转发至业务逻辑层。
  • 业务逻辑层处理请求,并与数据访问层交互以执行数据操作。
  1. 数据操作流程
  • 数据访问层执行数据的增删改查操作。
  • 操作结果反馈至业务逻辑层,最终呈现给用户。

第三章数据结构设计

3.1 用户数据结构 (user)

用户数据结构用于存储用户的基本信息,包括用户ID和密码。每个用户在系统中都是唯一的。

typedef struct user {
char uid[30]; // 用户ID,用于唯一标识一个用户
char password[30];// 用户密码,用于登录验证
} user;

image.gif

3.2 组数据结构 (group)

组数据结构用于存储关于考勤组的信息,包括组名、成员列表和成员的优先级。

typedef struct group {
char group_name[100]; // 组名,标识一个考勤组
int member[MAX_USER]; // 成员列表,记录属于该组的用户ID
int priority[MAX_USER]; // 成员优先级,通常管理员的优先级较高
} group;

image.gif

3.3 打卡记录数据结构 (clockin)

打卡记录数据结构用于存储关于打卡事件的详细信息,包括打卡的开始和结束时间,以及哪些用户参与了打卡。

typedef struct clockin {
    time_t begin_time;        // 打卡开始时间
    time_t end_time;          // 打卡结束时间
    int in[MAX_USER];         // 用户打卡状态数组,记录哪些用户已打卡
    int group_from;           // 所属组,标识这个打卡记录属于哪个考勤组
} clockin;

image.gif

3.4 系统级全局变量

系统级全局变量用于维护系统的当前状态和数据集合的规模。

user user_set[MAX_USER];             // 用户集合,存储所有用户的信息
int user_set_length = 0;             // 用户集合的当前大小
group group_set[MAX_GROUP];          // 组集合,存储所有考勤组的信息
int group_set_length = 0;            // 组集合的当前大小
clockin clockin_set[MAX_CLOCKIN];    // 打卡记录集合,存储所有打卡记录
int clockin_set_length = 0;          // 打卡记录集合的当前大小
int current_user = -1;               // 当前登录的用户ID
int global_target_group = -1;         // 全局目标组,用于某些操作中的上下文信息

image.gif

3.5 功能函数

系统还提供了一些功能函数来处理数据集合,例如:

  • search_user(user usr): 在用户集合中搜索特定用户。
  • search_uid(char *uid): 通过用户ID搜索用户。
  • read_user_set() write_user_set(): 从文件读取和写入用户数据集合。
  • read_group_set() write_group_set(): 从文件读取和写入组数据集合。
  • read_clockin_set() write_clockin_set(): 从文件读取和写打卡记录集合。

这些函数实现了数据的持久化和基本的增删查改操作。

第四章模块划分及各模块功能介绍

4.1 用户模块(User Module)

用户模块负责处理与用户相关的所有操作,包括用户注册、登录、信息管理等。

4.1.1 用户注册功能

  • 允许新用户创建账户,输入用户名和密码,并存储到用户数据集中。

4.1.2 用户登录功能

  • 允许用户通过输入用户名和密码登录系统,验证用户凭证。

4.1.3 用户信息管理功能

  • 用户可以查看和修改自己的个人信息,如更改密码等。

4.2 组模块(Group Module)

组模块管理用户的分组信息,包括创建组、管理组成员和查看组信息。

4.2.1 组创建功能

  • 允许用户创建新的组,并设置组名,同时成为该组的管理员。

4.2.2 组成员管理功能

  • 允许管理员邀请新成员加入组,设置成员的优先级(管理员或普通成员)。

4.2.3 组成员查看功能

  • 允许用户查看自己所在的所有组及其成员信息。

4.3 打卡模块(Clockin Module)

打卡模块处理用户的日常打卡操作,包括打卡记录、打卡数据查看和打卡事件创建。

4.3.1 打卡记录功能

  • 允许用户在指定时间内进行打卡操作,记录考勤时间。

4.3.2 打卡数据查看功能

  • 允许用户查看自己的打卡记录,包括打卡时间和打卡状态。

4.3.3 打卡事件创建功能

  • 允许有权限的用户(通常是管理员)发布新的打卡事件,设定打卡的起止时间和参与成员。

4.4 数据管理模块(Data Management Module)

数据管理模块负责系统的数据持久化和读取,确保数据的一致性和完整性。

4.4.1 数据持久化功能

  • 系统需要将用户数据、组数据和打卡数据存储在文件中,保证数据不会因程序关闭而丢失。

4.4.2 数据读取功能

  • 系统启动时需要从文件中读取现有数据,恢复系统状态。

4.5 安全模块(Security Module)

安全模块确保系统的安全性,包括密码加密和权限控制。

4.5.1 密码加密功能

  • 用户密码应进行加密存储,保证用户信息安全。

4.5.2 权限控制功能

  • 系统应提供基本的权限控制,确保用户只能访问授权的数据和功能。

4.6 用户界面模块(User Interface Module)

用户界面模块提供与用户的交互界面,接收用户输入并展示处理结果。

4.6.1 命令行界面

  • 系统通过命令行界面与用户交互,提供清晰的指令和反馈。

4.7 辅助功能模块(Utility Module)

辅助功能模块提供一些辅助性的功能,如搜索、数据验证等。

4.7.1 搜索功能

  • 提供搜索用户、组和打卡记录的功能。

4.7.2 数据验证功能

  • 对用户输入进行验证,确保数据的准确性和有效性。

第五章流程图

5.1整体流程图

image.gif 编辑

5.2用户模块部分流程图

image.gif 编辑

5.3打卡模块部分流程图

image.gif 编辑

5.4组模块部分流程图

image.gif 编辑

5.5数据管理模块部分流程图

image.gif 编辑

 

第六章调试与运行结果

6.1显示目前所有打卡

image.gif 编辑

6.2查看组打卡情况

image.gif 编辑

6.3管理员权限目录

image.gif 编辑

6.4正常打卡目录

image.gif 编辑

6.5打卡时间

image.gif 编辑

6.6显示成员在组的打卡情况

image.gif 编辑

6.7显示组的打卡情况

image.gif 编辑

第七章设计心得

在本章中,我将分享在开发考勤模拟系统过程中的心得体会、遇到的挑战、解决方案以及从中学到的经验。

7.1 项目启动阶段

项目启动初期,需求分析是关键步骤。与团队成员进行多轮讨论,确保对考勤模拟系统的需求有深刻理解。需求分析不仅帮助我们明确了系统目标和功能需求,而且为后续的设计和实现奠定了基础。

7.2 系统设计阶段

系统设计阶段是将需求转化为具体实现的桥梁。在这一阶段,我们采用了分层架构,明确了数据访问层、业务逻辑层和表示层的职责。分层架构的好处在于它提高了代码的可维护性和可扩展性。

7.3 数据结构设计

数据结构的设计是系统设计的核心。我们定义了用户(User)、组(Group)和打卡记录(Clockin)三个主要的数据结构,并在全局变量中维护了这些数据集合的状态。在设计数据结构时,我们注重了数据的一致性和完整性,为后续的数据操作打下了基础。

7.4 模块实现

在模块实现阶段,我们面临了如何高效管理用户、组和打卡数据的挑战。通过实现功能函数如search_userread_user_set等,我们确保了数据操作的便利性和准确性。此外,我们还实现了数据持久化,确保了系统的数据不会因为程序的关闭而丢失。

7.5 用户界面设计

用户界面是用户与系统交互的窗口。我们采用了命令行界面,因为它简单且易于实现。在设计用户界面时,我们注重了用户体验,提供了清晰的指令和反馈,使用户能够轻松地进行考勤操作。

7.6 安全性考虑

安全性是系统设计中不可忽视的一部分。我们意识到用户密码的安全性至关重要,因此在设计安全模块时,我们采用了加密存储密码的策略。此外,我们还实现了基本的权限控制,以确保数据访问的安全性。

7.7 测试与调试

在测试与调试阶段,我们发现并解决了多个问题。通过不断的测试,我们优化了系统的性能,确保了系统的稳定性。调试过程中,我们使用了多种调试工具和技术,以确保及时发现并修复问题。

7.8 项目总结

通过开发考勤模拟系统,我们团队学到了很多宝贵的经验。我们认识到了团队协作的重要性,以及在软件开发过程中持续沟通的必要性。此外,我们也意识到了代码的可读性和可维护性对于长期项目成功的重要性。

7.9 未来展望

考勤模拟系统目前虽然已经实现了基本功能,但仍有改进和扩展的空间。未来,我们计划添加更多的功能,如图形用户界面(GUI)、移动设备兼容性以及更高级的安全特性。

参考文献

C++员工考勤管理系统_c++程序设计课公司员工考勤管理系统-CSDN博客

C++员工管理系统(封装+多态+继承+分类化+函数调用+读写文件+指针+升序降序算法等一系列知识结合) - Bytezero! - 博客园 (cnblogs.com)

C++公司员工考勤管理系统[2023-01-01]_c++实现考勤系统-CSDN博客

simuler/AttendanceSystem: 员工考勤系统(C语言实现) (github.com)

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
// 定义最大用户数、最大组数和最大打卡记录数
#define MAX_USER 100
#define MAX_GROUP 1000
#define MAX_CLOCKIN 1000
// 打卡记录结构体
typedef struct clockin
{
    time_t begin_time; // 打卡开始时间
    time_t end_time;   // 打卡结束时间
    int in[MAX_USER];  // 用户打卡状态数组
    int group_from;    // 该打卡记录所属的组编号
}clockin;
// 用户组结构体
typedef struct group
{
    char group_name[100];  // 组名
    int member[MAX_USER];  // 组成员数组
    int priority[MAX_USER]; // 用户在组中的优先级或角色
}group;
// 用户信息结构体
typedef struct user
{
    char uid[30];    // 用户ID
    char password[30]; // 用户密码
}user;
// 用户集合数组和长度
user user_set[MAX_USER];
int user_set_length = 0;
// 组集合数组和长度
group group_set[MAX_GROUP];
int group_set_length = 0;
// 打卡记录集合数组和长度
clockin clockin_set[MAX_CLOCKIN];
int clockin_set_length = 0;
// 用户界面功能选择变量
int ui_func;
// 当前登录用户编号和目标组编号
int current_user = -1;
int global_target_group = -1;
// 搜索用户函数
int search_user(user usr)
{
    int i;
    for (i = 0; i < user_set_length; i++)
    {
        if (strcmp(user_set[i].uid, usr.uid) == 0)
        {
            return i;
        }
    }
    return -1;
}
// 根据用户ID搜索用户编号
int search_uid(char *uid)
{
    int i;
    for (i = 0; i < user_set_length; i++)
    {
        if (strcmp(user_set[i].uid, uid) == 0)
        {
            return i;
        }
    }
    return -1;
}
// 读取用户数据函数
void read_user_set()
{
    FILE *userdata = fopen("data/user_data", "r+");
    if (userdata == NULL)
    {
        printf("读取用户数据失败\n");
        return;
    }
    fseek(userdata, 0, SEEK_END);
    if (ftell(userdata) == 0)           // 空文件
    {
        return;
    }
    fseek(userdata, 0, SEEK_SET);
    fscanf(userdata, "%d", &user_set_length);
    for (int i = 0 ; i < user_set_length; i++)
    {
        fscanf(userdata, "%s", user_set[i].uid);
        fscanf(userdata, "%s", user_set[i].password);
    }
    fclose(userdata);
    return;
}
// 写入用户数据函数
void write_user_set()
{
    FILE *userdata = fopen("data/user_data", "w");
    if (userdata == NULL)
    {
        printf("读取用户数据失败\n");
        return;
    }
    fprintf(userdata, "%d\n", user_set_length);
    for (int i = 0 ; i < user_set_length; i++)
    {
        fprintf(userdata, "%s\n", user_set[i].uid);
        fprintf(userdata, "%s\n", user_set[i].password);
    }
    fclose(userdata);
    return;
}
// 读取组数据函数
void read_group_set()
{
    FILE *groupdata = fopen("data/group_data", "r+");
    if (groupdata == NULL)
    {
        printf("读取组数据失败\n");
        return;
    }
    fseek(groupdata, 0, SEEK_END);
    if (ftell(groupdata) == 0)           // 空文件
    {
        return;
    }
    fseek(groupdata, 0, SEEK_SET);
    fscanf(groupdata, "%d", &group_set_length);
    for (int j = 0; j < group_set_length; j++)
    {
        char temp_str[110];
        fscanf(groupdata, "%s", &temp_str);
        strcpy(group_set[j].group_name, temp_str);
        fscanf(groupdata, "%s", &temp_str);
        for (int i = 0 ; i < MAX_USER; i++)
        {
            group_set[j].member[i] = temp_str[i] - 48;
        }
        fscanf(groupdata, "%s", &temp_str);
        for (int i = 0 ; i < MAX_USER; i++)
        {
            group_set[j].priority[i] = temp_str[i] - 48;
        }
    }
    fclose(groupdata);
    return;
}
// 写入组数据函数
void write_group_set()
{
    FILE *groupdata = fopen("data/group_data", "w");
    if (groupdata == NULL)
    {
        printf("读取组数据失败\n");
        return;
    }
    fprintf(groupdata, "%d\n", group_set_length);
    for (int i = 0 ; i < group_set_length; i++)
    {
        fprintf(groupdata, "%s\n", group_set[i].group_name);
        for (int j = 0; j < MAX_USER; j++)
        {
            fprintf(groupdata, "%d", group_set[i].member[j]);
        }
        fprintf(groupdata, "\n");
        for (int j = 0; j < MAX_USER; j++)
        {
            fprintf(groupdata, "%d", group_set[i].priority[j]);
        }
        fprintf(groupdata, "\n");
    }
    fclose(groupdata);
    return;
}
// 检查用户是否在组中
int is_usr_in_group(int groupNo, int usr)
{
    return group_set[groupNo].member[usr];
}
// 检查打卡记录是否在组中
int is_clockin_in_group(int groupNo, int clockinNo)
{
    return clockin_set[clockinNo].group_from == groupNo;
}
// 用户ID转换为用户编号
int uid_2_usr(char *uid)
{
    for (int i = 0; i < MAX_USER; i++)
    {
        if (strcmp(user_set[i].uid, uid) == 0)
        {
            return i;
        }
    }
    return -1;
}
// 读取打卡记录数据函数
void read_clockin_set()
{
    FILE *clockindata = fopen("data/clockin_data", "r+");
    if (clockindata == NULL)
    {
        printf("读取打卡数据失败\n");
        return;
    }
    for (int i = 0; i < MAX_CLOCKIN; i++)
    {
        clockin_set[i].group_from = -1;
    }
    fseek(clockindata, 0, SEEK_END);
    if (ftell(clockindata) == 0)           // 空文件
    {
        return;
    }
    fseek(clockindata, 0, SEEK_SET);
    fscanf(clockindata, "%d", &clockin_set_length);
    for (int j = 0; j < clockin_set_length; j++)
    {
        char temp_str[110];
        long temp_long;
        int temp_int;
        fscanf(clockindata, "%ld", &temp_long);
        clockin_set[j].begin_time = temp_long;
        fscanf(clockindata, "%ld", &temp_long);
        clockin_set[j].end_time = temp_long;
        fscanf(clockindata, "%s", &temp_str);
        for (int i = 0 ; i < MAX_USER; i++)
        {
            clockin_set[j].in[i] = temp_str[i] - 48;
        }
        fscanf(clockindata, "%d", &temp_int);
        clockin_set[j].group_from = temp_int;
    }
    fclose(clockindata);
    return;
}
// 写入打卡记录数据函数
void write_clockin_set()
{
    FILE *clockindata = fopen("data/clockin_data", "w");
    if (clockindata == NULL)
    {
        printf("读取打卡数据失败\n");
        return;
    }
    fprintf(clockindata, "%d\n", clockin_set_length);
    for (int i = 0 ; i < clockin_set_length; i++)
    {
        fprintf(clockindata, "%ld\n", clockin_set[i].begin_time);
        fprintf(clockindata, "%ld\n", clockin_set[i].end_time);
        for (int j = 0; j < MAX_USER; j++)
        {
            fprintf(clockindata, "%d", clockin_set[i].in[j]);
        }
        fprintf(clockindata, "\n");
        fprintf(clockindata, "%d\n", clockin_set[i].group_from);
    }
    fclose(clockindata);
    return;
}
// 检查用户是否在打卡记录中
int is_usr_in_clockin(int clockinNo)
{
    return group_set[clockin_set[clockinNo].group_from].member[current_user];
}
int main()
{
    ui_func = -1;
    // -2 -- welcome已登录
    // -1 -- welcome未登录
    // 0 -- 登录界面
    // 1 -- 注册界面
    read_user_set();
    read_group_set();
    read_clockin_set();
    while (1)
    {
        system("cls");
        if (ui_func == 0)           // 登录界面
        {
            user login_user;
            printf("请先登录\n用户名:");
            scanf("%s", login_user.uid);
            printf("密码:");
            scanf("%s", login_user.password);
            fflush(stdin);
            if (search_user(login_user) == -1)  // 未注册
            {
                printf("未找到该用户,是否注册?(y/n)\n");
                int temp_i = 1;
                char temp_c;
                while (temp_i)
                {
                    system("cls");
                    printf("未找到该用户,是否注册?(y/n)\n");
                    scanf("%c", &temp_c);
                    fflush(stdin);
                    if (temp_c == 'y' || temp_c == 'n')
                        break;
                }
                if (temp_c == 'y')
                {
                    ui_func = 1;
                    continue;
                }
                else if (temp_c == 'n')
                {
                    ui_func = -1;
                    continue;
                }
            }
            else
            {
                int No = search_user(login_user);
                if (strcmp(login_user.password, user_set[No].password) == 0)
                {
                    printf("登录成功\n");
                    current_user = No;
                    ui_func = -2;
                }
                else
                {
                    printf("密码错误\n");
                    getchar();
                }
            }
        }
        else if (ui_func == 1)          // 注册界面
        {
            user register_user;
            char re_password[30];
            printf("请先注册\n用户名:");
            scanf("%s", register_user.uid);
            printf("密码:");
            scanf("%s", register_user.password);
            printf("请重复密码:");
            scanf("%s", &re_password);
            fflush(stdin);
            if (search_user(register_user) != -1)
            {
                int temp_i = 1;
                char temp_c;
                while (temp_i)
                {
                    system("cls");
                    printf("该用户已存在,是否跳转到登录?(y/n)\n");
                    scanf("%c", &temp_c);
                    fflush(stdin);
                    if (temp_c == 'y' || temp_c == 'n')
                        break;
                }
                if (temp_c == 'y')
                {
                    ui_func = 0;
                    continue;
                }
                else if (temp_c == 'n')
                {
                    ui_func = -1;
                    continue;
                }
            }
            if (strcmp(re_password, register_user.password) != 0)
            {
                printf("两次密码不相同,请再次输入\n");
                ui_func = 1;
                continue;
            }
            else       
            {
                printf("注册成功,将自动为您登录\n");
                strcpy(user_set[user_set_length].uid, register_user.uid);
                strcpy(user_set[user_set_length].password, register_user.password);
                user_set_length++;
                write_user_set();
                current_user = user_set_length - 1;
                ui_func = -2;
            }
        }
        else if (ui_func == -1)         // welcome未登录
        {          
            char temp_c;
            while (1)
            {
                system("cls");
                printf("这是一句welcome\n输入序号以访问功能\n1 登录\n2 注册\n");
                scanf("%c", &temp_c);
                fflush(stdin);
                if (temp_c == '1' || temp_c == '2')
                    break;
            }
            if (temp_c == '1')
                ui_func = 0;
            else
                ui_func = 1;
        }
        else if (ui_func == -2)         // welcome已登录
        {
            int temp_i;
            while (1)
            {
                system("cls");
                printf("你好%s\n输入序号以访问功能\n1 打卡\n2 发布新的打卡\n3 查看我所在的组\n4 创建组\n5 管理组\n9 退出登录\n", user_set[current_user].uid);  
                scanf("%d", &temp_i);
                fflush(stdin);
                if ((temp_i >= 1 && temp_i <= 5) || temp_i == 9)
                    break;
            }
            if (temp_i == 1)
                ui_func = 20;
            else if (temp_i == 4)
                ui_func = 10;
            else if (temp_i == 3)
                ui_func = 11;
            else if (temp_i == 2)
                ui_func = 21;
            else if (temp_i == 9)
                ui_func = 99;
            else if (temp_i == 5)
                ui_func = 30;
        }
        else if (ui_func == 10)        // 创建组
        {
            const char end_str[10] = "$end";
            char temp_uid[30];
            char temp_group_name[100];
            group_set[group_set_length].member[current_user] = 1;
            group_set[group_set_length].priority[current_user] = 1;
            system("cls");
            printf("请输入小组名称:"); 
            scanf("%s", &temp_group_name); 
            strcpy(group_set[group_set_length].group_name, temp_group_name);
            while (1)
            {
                system("cls");
                printf("小组名称:%s\n", group_set[group_set_length].group_name);  
                printf("请输入其它用户的用户名进行邀请\n管理员:%s\n", user_set[current_user].uid);  
                printf("用户:");
                for (int i = 0; i < MAX_USER; i++)
                {
                    if (group_set[group_set_length].member[i] && i != current_user)
                    {
                        printf("%s  ", user_set[i].uid);
                    }
                }
                printf("\n\n其它用户的用户名(或输入%cend结束):", 36);
                scanf("%s", &temp_uid);
                fflush(stdin);
                if (strcmp(end_str, temp_uid) == 0)
                    break;
                if (search_uid(temp_uid) == -1)
                {
                    printf("未找到该用户(按下回车以继续)");
                    getchar();
                }
                else
                {
                    group_set[group_set_length].member[search_uid(temp_uid)] = 1;
                    group_set[group_set_length].priority[search_uid(temp_uid)] = 0;
                }
            }
            system("cls");
            printf("小组创建完毕\n小组名称:%s\n管理员:%s\n", group_set[group_set_length].group_name, user_set[current_user].uid);  
            printf("用户:");
            for (int i = 0; i < MAX_USER; i++)
            {
                if (group_set[group_set_length].member[i] && i != current_user)
                {
                    printf("%s  ", user_set[i].uid);
                }
            }
            printf("\n");
            group_set_length++;
            write_group_set();
            ui_func = -2;
            printf("按下回车以返回主界面\n");
            getchar();
        }
        else if (ui_func == 11)
        {
            system("cls");  
            printf("%s所在的所有组:\n", user_set[current_user].uid);  
            for (int i = 0; i < MAX_GROUP; i++)
            {
                if (is_usr_in_group(i, current_user))
                {
                    printf("%s\n", group_set[i].group_name);  
                }
            }
            ui_func = -2;
            printf("\n按下回车以返回主界面\n");
            getchar();
        }
        else if (ui_func == 20)
        {
            system("cls");  
            printf("%s目前有的所有打卡:\n", user_set[current_user].uid);  
            for (int i = 0; i < MAX_CLOCKIN; i++)
            {
                if (group_set[clockin_set[i].group_from].member[current_user])
                {
                    struct tm *showtime;
                    printf("打卡编号:%d\n", i);
                    showtime = localtime(&clockin_set[i].begin_time);
                    printf("起始:%s", asctime(showtime));
                    showtime = localtime(&clockin_set[i].end_time);
                    printf("结束:%s", asctime(showtime));
                    if (clockin_set[i].in[current_user] == 1)
                    {
                        printf("已打卡\n\n");
                    }
                    else
                    {
                        printf("未打卡\n\n");
                    } 
                }
            }
            int target_clockin = -2;
            printf("输入打卡编号进行打卡(或输入-1返回主界面)\n");
            scanf("%d", &target_clockin);
            fflush(stdin);
            if (target_clockin == -1 || is_usr_in_clockin(target_clockin))
            {
                if (target_clockin == -1)
                {
                    ui_func = -2;
                    continue;
                }
                else if (clockin_set[target_clockin].in[current_user] == 1)
                {
                    printf("已打卡,请勿重复打卡。\n");
                    getchar();
                    continue;
                }
                else
                {
                    time_t now_time = time(0);
                    time(&now_time);
                    if (now_time >= clockin_set[target_clockin].begin_time && now_time <= clockin_set[target_clockin].end_time)
                    {
                        printf("打卡成功。\n");
                        getchar();
                        clockin_set[target_clockin].in[current_user] = 1;
                        write_clockin_set();
                        continue;
                    }
                    else
                    {
                        printf("打卡失败。未在指定时间\n");
                        getchar();
                        continue;
                    }
                }
            }
            else
            {
                printf("输入有误,请重新输入\n");
                getchar();
            }
        }
        else if (ui_func == 21)
        {
            system("cls");  
            int have_any_p = 0;
            for (int i = 0; i < MAX_GROUP; i++)
            {
                if (is_usr_in_group(i, current_user))
                {
                    if (group_set[i].priority[current_user])
                        have_any_p = 1; 
                }
            }
            if (have_any_p == 0)
            {
                ui_func = -2;
                printf("你目前没有任何权限,即将返回\n");
                getchar();
                continue;
            }
            printf("%s所有有权限的组:\n", user_set[current_user].uid);  
            for (int i = 0; i < MAX_GROUP; i++)
            {
                if (is_usr_in_group(i, current_user))
                {
                    if (group_set[i].priority[current_user])
                        printf("%s\n", group_set[i].group_name);  
                }
            }
            printf("\n输入选择要创建打卡的组的名称:");
            char temp_gn[100];
            scanf("%s", &temp_gn);
            fflush(stdin);
            int target_group = 0;
            int flag = 0;
            for (; target_group < MAX_GROUP && flag == 0; target_group++)
            {
                if (is_usr_in_group(target_group, current_user))
                {
                    if (group_set[target_group].priority[current_user])
                    {
                        if (strcmp(temp_gn, group_set[target_group].group_name) == 0)
                        {
                            flag = 1;
                            break;
                        }
                    }
                }
            }
            if (flag == 0)
            {
                printf("\n未找到该组,请重新输入\n");
                getchar();
                continue;
            }
            else
            {
                clockin_set[clockin_set_length].group_from = target_group;
                
                int holding = 0;            // 分钟
                time_t begin = time(0);
                time_t end = time(0);
                struct tm *time_show;
                time(&begin);
                system("cls"); 
                printf("请输入打卡持续时间(分钟):");
                scanf("%d", &holding);
                fflush(stdin);
                end = begin + holding * 60;
                printf("小组:%s\n", group_set[target_group].group_name);
                time_show = localtime(&begin);
                printf("起始时间:%s", asctime(time_show));
                time_show = localtime(&end);
                printf("结束时间:%s", asctime(time_show));
                clockin_set[clockin_set_length].begin_time = begin;
                clockin_set[clockin_set_length].end_time = end;
                for (int i = 0; i < MAX_USER; i++)
                {
                    clockin_set[clockin_set_length].in[i] = 0;
                }
                clockin_set_length++;
                write_clockin_set();
                ui_func = -2;
                printf("\n打卡创建完毕,回车以返回主界面\n");
                getchar();
            }
            
        }
        else if (ui_func == 99)
        {
            ui_func = -1;
            current_user = -1;
            printf("已退出登录,将返回登录界面\n");
            getchar();
        }
        else if (ui_func == 30)
        {
            system("cls"); 
            printf("%s所在的所有组:\n", user_set[current_user].uid);  
            for (int i = 0; i < MAX_GROUP; i++)
            {
                if (is_usr_in_group(i, current_user))
                {
                    printf("%s\n", group_set[i].group_name);  
                }
            }
            printf("\n输入选择要查看的组的名称(输入$back返回):");
            char temp_gn[100];
            scanf("%s", &temp_gn);
            fflush(stdin);
            if (strcmp("$back", temp_gn) == 0)
            {
                ui_func = -2;
                continue;
            }
            int target_group = 0;
            int flag = 0;
            for (; target_group < MAX_GROUP && flag == 0; target_group++)
            {
                if (is_usr_in_group(target_group, current_user))
                {
                    if (strcmp(temp_gn, group_set[target_group].group_name) == 0)
                    {
                        flag = 1;
                        break;
                    }
                }
            }
            if (flag == 0)
            {
                printf("\n未找到该组,请重新输入\n");
                getchar();
                continue;
            }
            else
            {
                system("cls"); 
                printf("小组:%s\n", group_set[target_group].group_name);
                printf("管理员:");
                for (int i = 0; i < MAX_USER; i++)
                {
                    if (group_set[target_group].member[i] && group_set[target_group].priority[i])
                    {
                        printf("%s  ", user_set[i].uid);
                    }
                }
                printf("\n");
                printf("其它成员:");
                for (int i = 0; i < MAX_USER; i++)
                {
                    if (group_set[target_group].member[i] && group_set[target_group].priority[i] == 0)
                    {
                        printf("%s  ", user_set[i].uid);
                    }
                }
                printf("\n");
                if (group_set[target_group].priority[current_user])
                {
                    ui_func = 31;
                    global_target_group = target_group;
                    continue;
                }
                else
                {
                    printf("您是一般成员\n(回车以返回)");
                    getchar();
                }
            }
        }
        else if (ui_func == 31)
        {
            int temp_i;
            while (1)
            {
                system("cls");
                printf("小组:%s\n", group_set[global_target_group].group_name);
                printf("管理员:");
                for (int i = 0; i < MAX_USER; i++)
                {
                    if (group_set[global_target_group].member[i] && group_set[global_target_group].priority[i])
                    {
                        printf("%s  ", user_set[i].uid);
                    }
                }
                printf("\n");
                printf("其它成员:");
                for (int i = 0; i < MAX_USER; i++)
                {
                    if (group_set[global_target_group].member[i] && group_set[global_target_group].priority[i] == 0)
                    {
                        printf("%s  ", user_set[i].uid);
                    }
                }
                printf("\n您是管理员\n输入序号以访问功能\n1 查看个人数据\n2 查看打卡数据\n9 返回\n");
                scanf("%d", &temp_i);
                fflush(stdin);
                if ((temp_i >= 1 && temp_i <= 2) || temp_i == 9)
                    break;
            }
            if (temp_i == 1)
            {
                char temp_uid[30];
                while (1)
                {
                    system("cls");
                    printf("小组:%s\n", group_set[global_target_group].group_name);
                    printf("全部成员:");
                    for (int i = 0; i < MAX_USER; i++)
                    {
                        if (group_set[global_target_group].member[i])
                        {
                            printf("%s  ", user_set[i].uid);
                        }
                    }
                    printf("\n输入成员的uid以查看其打卡数据\n");
                    scanf("%s", &temp_uid);
                    fflush(stdin);
                    if (is_usr_in_group(global_target_group, uid_2_usr(temp_uid)))
                    {
                        break;
                    }
                    else
                    {
                        printf("\n该成员不在小组中\n");
                        getchar();
                    }
                }
                system("cls");  
                printf("成员:%s目前在组内所有打卡:\n", user_set[uid_2_usr(temp_uid)].uid);  
                int all = 0, intime = 0, outtime = 0;
                for (int i = 0; i < MAX_CLOCKIN; i++)
                {
                    if (group_set[clockin_set[i].group_from].member[uid_2_usr(temp_uid)] && clockin_set[i].group_from == global_target_group)
                    {
                        all++;
                        struct tm *showtime;
                        printf("打卡编号:%d\n", i);
                        showtime = localtime(&clockin_set[i].begin_time);
                        printf("起始:%s", asctime(showtime));
                        showtime = localtime(&clockin_set[i].end_time);
                        printf("结束:%s", asctime(showtime));
                        if (clockin_set[i].in[uid_2_usr(temp_uid)] == 1)
                        {
                            printf("已打卡\n\n");
                            intime++;
                        }
                        else
                        {
                            printf("未打卡\n\n");
                            outtime++;
                        } 
                    }
                }
                printf("\n总打卡%d次,准时%d次,迟到%d次,到勤率%.2lf\n", all, intime, outtime, (double)intime/(double)all);
                getchar();
                continue;
            }
            else if (temp_i == 2)
            {
                int temp_int;
                while (1)
                {
                    system("cls");
                    printf("小组:%s\n", group_set[global_target_group].group_name);
                    printf("全部打卡:\n");
                    for (int i = 0; i < clockin_set_length; i++)
                    {
                        if (clockin_set[i].group_from == global_target_group)
                        {
                            struct tm *showtime;
                            printf("打卡编号:%d\n", i);
                            showtime = localtime(&clockin_set[i].begin_time);
                            printf("起始:%s", asctime(showtime));
                            showtime = localtime(&clockin_set[i].end_time);
                            printf("结束:%s", asctime(showtime));
                        }
                    }
                    printf("\n输入打卡的编号以查看其打卡数据\n");
                    scanf("%d", &temp_int);
                    fflush(stdin);
                    if (is_clockin_in_group(global_target_group, temp_int))
                    {
                        break;
                    }
                    else
                    {
                        printf("\n小组中没有该打卡\n");
                        getchar();
                    }
                }
                struct tm *showtime;
                system("cls");
                printf("打卡编号:%d\n", temp_int);
                showtime = localtime(&clockin_set[temp_int].begin_time);
                printf("起始:%s", asctime(showtime));
                showtime = localtime(&clockin_set[temp_int].end_time);
                printf("结束:%s", asctime(showtime));
                int all = 0, intime = 0, outtime = 0;
                printf("已签到:\n");
                for (int i = 0; i < MAX_USER; i++)
                {
                    if (group_set[global_target_group].member[i])
                    {
                        all++;
                        if (clockin_set[temp_int].in[i])
                        {
                            intime++;
                            printf("%s  ", user_set[i].uid);
                        }
                    }
                }
                printf("\n未签到:\n");
                for (int i = 0; i < MAX_USER; i++)
                {
                    if (group_set[global_target_group].member[i])
                    {
                        if (clockin_set[temp_int].in[i] == 0)
                        {
                            outtime++;
                            printf("%s  ", user_set[i].uid);
                        }
                    }
                }
                printf("\n总共%d人参与打卡,准时%d人,迟到%d人,到勤率%.2lf\n", all, intime, outtime, (double)intime/(double)all);
            }
            else
            {
                global_target_group = -1;
                ui_func = -2;
                continue;
            }
            getchar();
        }
    }
}

image.gif


相关实践学习
MySQL基础-学生管理系统数据库设计
本场景介绍如何使用DMS工具连接RDS,并使用DMS图形化工具创建数据库表。
目录
相关文章
|
1月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
63 16
|
1月前
|
算法 C语言
【C语言程序设计——循环程序设计】求解最大公约数(头歌实践教学平台习题)【合集】
采用欧几里得算法(EuclideanAlgorithm)求解两个正整数的最大公约数。的最大公约数,然后检查最大公约数是否大于1。如果是,就返回1,表示。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。作为新的参数传递进去。这个递归过程会不断进行,直到。有除1以外的公约数;变为0,此时就找到了最大公约数。开始你的任务吧,祝你成功!是否为0,如果是,那么。就是最大公约数,直接返回。
77 18
|
1月前
|
Serverless C语言
【C语言程序设计——循环程序设计】利用循环求数值 x 的平方根(头歌实践教学平台习题)【合集】
根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码,求解出数值x的平方根;运用迭代公式,编写一个循环程序,求解出数值x的平方根。注意:不能直接用平方根公式/函数求解本题!开始你的任务吧,祝你成功!​ 相关知识 求平方根的迭代公式 绝对值函数fabs() 循环语句 一、求平方根的迭代公式 1.原理 在C语言中,求一个数的平方根可以使用牛顿迭代法。对于方程(为要求平方根的数),设是的第n次近似值,牛顿迭代公式为。 其基本思想是从一个初始近似值开始,通过不断迭代这个公式,使得越来越接近。
57 18
|
1月前
|
C语言
【C语言程序设计——循环程序设计】统计海军鸣放礼炮声数量(头歌实践教学平台习题)【合集】
有A、B、C三艘军舰同时开始鸣放礼炮各21响。已知A舰每隔5秒1次,B舰每隔6秒放1次,C舰每隔7秒放1次。编程计算观众总共听到几次礼炮声。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。开始你的任务吧,祝你成功!
52 13
|
9天前
|
监控 关系型数据库 MySQL
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
19 0
|
1月前
|
存储 安全 C语言
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
分支的语句,这可能不是预期的行为,这种现象被称为“case穿透”,在某些特定情况下可以利用这一特性来简化代码,但在大多数情况下,需要谨慎使用。编写一个程序,该程序需输入个人数据,进而预测其成年后的身高。根据提示,在右侧编辑器补充代码,计算并输出最终预测的身高。分支下的语句,提示用户输入无效。常量的值必须是唯一的,且在同一个。语句的作用至关重要,如果遗漏。开始你的任务吧,祝你成功!,程序将会继续执行下一个。常量都不匹配,就会执行。来确保程序的正确性。
52 10
|
1月前
|
小程序 C语言
【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】
目录 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果: 任务描述 相关知识 编程编写一个程序,从键盘输入3个变量的值,例如a=5,b=6,c=7,然后将3个变量的值进行交换,使得a=6,b=7,c=5。面积=sqrt(s(s−a)(s−b)(s−c)),s=(a+b+c)/2。使用输入函数获取半径,格式指示符与数据类型一致,实验一下,不一致会如何。根据提示,在右侧编辑器补充代码,计算并输出圆的周长和面积。
39 10
|
1月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
36 3
|
1月前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
19 2
|
1月前
|
存储 C语言
【C语言程序设计——循环程序设计】利用数列的累加和求 sinx(头歌实践教学平台习题)【合集】
项的累加和,一般会使用循环结构,在每次循环中计算出当前项的值(可能基于通项公式或者递推关系),然后累加到一个用于存储累加和的变量中。在C语言中推导数列中的某一项,通常需要依据数列给定的通项公式或者前后项之间的递推关系来实现。例如,对于一个简单的等差数列,其通项公式为。的级数,其每一项之间存在特定的递推关系(后项的分子是其前项的分子乘上。,计算sinx的值,直到最后一项的绝对值小于。为项数),就可以通过代码来计算出指定项的值。对于更复杂的数列,像题目中涉及的用于近似计算。开始你的任务吧,祝你成功!
42 6

热门文章

最新文章