考勤模拟系统平台目录
4.4 数据管理模块(Data Management Module)... 7
4.5 安全模块(Security Module)... 7
4.6 用户界面模块(User Interface Module)... 8
4.7 辅助功能模块(Utility Module)... 9
第一章软件需求分析
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 系统环境
- 系统应在常见的操作系统上运行,如 Windows、Linux 等。
- 系统应使用标准 C 语言编写,确保良好的兼容性。
1.7 数据结构设计
1.7.1 用户(User)
- 用户ID(uid):唯一标识符。
- 密码(password):登录凭证。
1.7.2 打卡记录(Clockin)
- 开始时间(begin_time):打卡开始的具体时间。
- 结束时间(end_time):打卡结束的具体时间。
- 用户打卡状态数组(in):记录哪些用户已打卡。
- 所属组(group_from):打卡记录所属的组。
第二章系统结构设计
2.1 系统架构
系统采用分层架构,主要分为以下几个层次:
- 数据访问层:负责数据的存取,与文件系统交互,实现数据的持久化。
- 业务逻辑层:处理具体的业务需求,如用户注册、登录、打卡等。
- 表示层:提供用户界面,与用户进行交互,接收用户输入并展示处理结果。
2.2 系统组件
- 用户管理组件:
- 负责处理用户的注册、登录和信息管理。
- 与数据访问层的用户数据存储进行交互。
- 组管理组件:
- 允许用户创建组、管理组成员和查看组信息。
- 与数据访问层的组数据存储进行交互。
- 打卡管理组件:
- 处理用户的打卡请求,记录打卡时间。
- 与数据访问层的打卡数据存储进行交互。
- 数据持久化组件:
- 负责将用户数据、组数据和打卡数据存储到文件系统。
- 在系统启动时从文件中恢复数据。
- 安全组件:
- 负责密码加密和权限控制,确保数据安全。
2.3 系统流程
- 启动流程:
- 系统启动时,数据持久化组件从文件中加载数据到内存。
- 用户交互流程:
- 用户通过表示层与系统交互,输入命令或数据。
- 表示层将用户请求转发至业务逻辑层。
- 业务逻辑层处理请求,并与数据访问层交互以执行数据操作。
- 数据操作流程:
- 数据访问层执行数据的增删改查操作。
- 操作结果反馈至业务逻辑层,最终呈现给用户。
第三章数据结构设计
3.1 用户数据结构 (user
)
用户数据结构用于存储用户的基本信息,包括用户ID和密码。每个用户在系统中都是唯一的。
typedef struct user { char uid[30]; // 用户ID,用于唯一标识一个用户 char password[30];// 用户密码,用于登录验证 } user;
3.2 组数据结构 (group
)
组数据结构用于存储关于考勤组的信息,包括组名、成员列表和成员的优先级。
typedef struct group { char group_name[100]; // 组名,标识一个考勤组 int member[MAX_USER]; // 成员列表,记录属于该组的用户ID int priority[MAX_USER]; // 成员优先级,通常管理员的优先级较高 } group;
3.3 打卡记录数据结构 (clockin
)
打卡记录数据结构用于存储关于打卡事件的详细信息,包括打卡的开始和结束时间,以及哪些用户参与了打卡。
typedef struct clockin { time_t begin_time; // 打卡开始时间 time_t end_time; // 打卡结束时间 int in[MAX_USER]; // 用户打卡状态数组,记录哪些用户已打卡 int group_from; // 所属组,标识这个打卡记录属于哪个考勤组 } clockin;
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; // 全局目标组,用于某些操作中的上下文信息
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整体流程图
编辑
5.2用户模块部分流程图
编辑
5.3打卡模块部分流程图
编辑
5.4组模块部分流程图
编辑
5.5数据管理模块部分流程图
编辑
第六章调试与运行结果
6.1显示目前所有打卡
编辑
6.2查看组打卡情况
编辑
6.3管理员权限目录
编辑
6.4正常打卡目录
编辑
6.5打卡时间
编辑
6.6显示成员在组的打卡情况
编辑
6.7显示组的打卡情况
编辑
第七章设计心得
在本章中,我将分享在开发考勤模拟系统过程中的心得体会、遇到的挑战、解决方案以及从中学到的经验。
7.1 项目启动阶段
项目启动初期,需求分析是关键步骤。与团队成员进行多轮讨论,确保对考勤模拟系统的需求有深刻理解。需求分析不仅帮助我们明确了系统目标和功能需求,而且为后续的设计和实现奠定了基础。
7.2 系统设计阶段
系统设计阶段是将需求转化为具体实现的桥梁。在这一阶段,我们采用了分层架构,明确了数据访问层、业务逻辑层和表示层的职责。分层架构的好处在于它提高了代码的可维护性和可扩展性。
7.3 数据结构设计
数据结构的设计是系统设计的核心。我们定义了用户(User)、组(Group)和打卡记录(Clockin)三个主要的数据结构,并在全局变量中维护了这些数据集合的状态。在设计数据结构时,我们注重了数据的一致性和完整性,为后续的数据操作打下了基础。
7.4 模块实现
在模块实现阶段,我们面临了如何高效管理用户、组和打卡数据的挑战。通过实现功能函数如search_user
、read_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(); } } }