ui.h
cs
#ifndef UI_H
#define UI_H
#include "entity.h"
void usermenu();
void adminmenu();
void clearScreen();
void inputPassword(char* password, int maxLen);
void formatTimestamp(time_t t, char* buf, int size);
void browseMovies();
void searchMovie();
void view_all_users();
void findPassword();
void showSeatMatrix(int hallId, int timeIdx);
#endif
ui.c
cs
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include "entity.h"
#include "dal.h"
#include "bll.h"
#include "ui.h"
// 管理员菜单
void adminmenu() {
int choice;
do {
clearScreen();
printf("\n====================================\n");
printf(" - 管理员控制面板\n");
printf("====================================\n");
printf("【座位状态说明】\n");
printf(" O: 空座(可选择)\n");
printf(" X: 已占座(有人坐)\n");
printf("------------------------------------\n");
printf("1. 电影管理(新增/删除/修改/浏览)\n");
printf("2. 影厅座位总控\n");
printf("3. 系统管理(用户/数据/密码)\n");
printf("0. 退出登录\n");
printf("------------------------------------\n");
printf("请选择操作: ");
while (getchar() != '\n');
scanf("%d", &choice);
switch (choice) {
case 1: {
int movieChoice;
do {
clearScreen();
printf("\n===== 电影管理面板 =====\n");
printf("1. 浏览所有电影\n");
printf("2. 新增电影\n");
printf("3. 删除电影\n");
printf("4. 修改电影信息\n");
printf("0. 返回上一级\n");
printf("------------------------\n");
printf("请选择操作: ");
while (getchar() != '\n');
scanf("%d", &movieChoice);
switch (movieChoice) {
case 1: browseMovies(); break;
case 2: addMovie(); break;
case 3: deleteMovie(); break;
case 4: updateMovie(); break;
case 0: clearScreen(); break;
default:
clearScreen();
printf("输入错误!请选择0-4的数字!\n");
getchar(); getchar();
clearScreen();
break;
}
} while (movieChoice != 0);
break;
}
case 2:
clearScreen();
updateSeatStatus();
break;
case 3: {
clearScreen();
int sysChoice;
do {
printf("\n===== 系统管理面板 =====\n");
printf("1. 查看所有用户\n");
printf("2. 修改管理员密码\n");
printf("3. 初始化座位列表\n");
printf("0. 返回上一级\n");
printf("------------------------\n");
printf("请选择操作: ");
while (getchar() != '\n');
scanf("%d", &sysChoice);
switch (sysChoice) {
case 1: view_all_users(); break;
case 2: changePassword(); break;
case 3:
initSeatList();
printf("座位列表初始化完成!\n");
getchar(); getchar();
break;
case 0: clearScreen(); break;
default:
clearScreen();
printf("输入错误!请选择0-3的数字!\n");
getchar(); getchar();
clearScreen();
break;
}
} while (sysChoice != 0);
break;
}
case 0: clearScreen(); printf("管理员已退出登录!\n"); getchar(); break;
default:
clearScreen();
printf("输入错误!请选择0-3的数字选项!\n");
getchar(); getchar();
break;
}
} while (choice != 0);
}
void usermenu() {
int choice;
do {
clearScreen();
printf("╔════════════════════╗\n");
printf("║ 用户菜单 ║\n");
printf("╠════════════════════╣\n");
printf("║ 1. 浏览电影信息 ║\n");
printf("║ 2. 搜索电影 ║\n");
printf("║ 3. 购票 ║\n");
printf("║ 4. 我的订单 ║\n");
printf("║ 5. 查看座位 ║\n");
printf("║ 6. 退票 ║\n");
printf("║ 7. 修改密码 ║\n");
printf("║ 0. 退出登录 ║\n");
printf("╚════════════════════╝\n");
printf("请选择: ");
while (getchar() != '\n'); // 清空输入缓冲
scanf("%d", &choice);
switch (choice) {
case 1: clearScreen(); browseMovies(); break;
case 2: clearScreen(); searchMovie(); break;
case 3: clearScreen(); buyTicket(); break;
case 4: clearScreen(); myOrders(); break;
// ================= 查看座位 =================
case 5: {
clearScreen();
int h, t;
printf("请选择要查看的影厅(1-%d):", HALLS);
scanf("%d", &h);
printf("请选择场次(1-%d):1=10:00 2=14:00 3=18:00 4=21:00\n", TIMES);
scanf("%d", &t);
if (h >= 1 && h <= HALLS && t >= 1 && t <= TIMES) {
int hallId = h - 1;
int timeIdx = t - 1; // 转换为链表索引
// 查找节点
SeatNode* node = findSeatNode(hallId, timeIdx);
if (!node) {
// 节点不存在,初始化影厅场次
initSeatList();
node = findSeatNode(hallId, timeIdx);
if (!node) {
printf("场次初始化失败!\n");
getchar(); getchar();
break;
}
}
showSeatMatrix(hallId, timeIdx);
}
else {
printf("输入错误!影厅或场次超出范围。\n");
}
getchar(); getchar(); // 等待回车
break;
}
case 6: clearScreen(); refundTicket(); break;
case 7: clearScreen(); changePassword(); break;
case 0: clearScreen(); printf("正在退出登录...\n"); break;
default:
clearScreen();
printf("输入错误!请选择0-%d之间的数字\n", 7);
getchar(); getchar();
}
} while (choice != 0);
}
//// 显示:当前影厅 + 当前场次 的座位矩阵(独立座位)
//void showSeatMatrix(int hallId, int timeIdx)
//{
// // 找到当前场次的座位链表节点
// SeatNode* node = findSeatNode(hallId, timeIdx);
// if (!node)
// {
// printf("场次未初始化!\n");
// return;
// }
//
// printf("\n=======================================\n");
// printf(" 影厅 %d | 场次 %d\n", hallId + 1, timeIdx + 1);
// printf("=======================================\n");
//
// printf(" ");
// for (int j = 0; j < COLS; j++)
// {
// printf("%2d ", j + 1);
// }
// printf("\n");
//
// for (int i = 0; i < ROWS; i++)
// {
// printf("%c ", 'A' + i);
// for (int j = 0; j < COLS; j++)
// {
// printf("%c ", node->seats[i][j] ? 'X' : 'O');
// }
// printf("\n");
// }
// printf("=======================================\n");
// printf(" O = 可售 X = 已售\n");
// printf("=======================================\n\n");
//}
// 忽略大小写子串匹配
bool isSubsequenceIgnoreCase(const char* str, const char* sub) {
if (*sub == '\0') return true;
while (*str != '\0') {
char c1 = (*str >= 'A' && *str <= 'Z') ? (*str + 32) : *str;
char c2 = (*sub >= 'A' && *sub <= 'Z') ? (*sub + 32) : *sub;
if (c1 == c2) {
sub++;
if (*sub == '\0') return true;
}
str++;
}
return false;
}
// 搜索电影
void searchMovie() {
clearScreen();
int searchType;
char keyword[50] = { 0 };
printf("===== 电影搜索 =====\n");
printf("1. 按电影名称搜索\n");
printf("2. 按电影类型搜索\n");
printf("请选择搜索方式:");
while (getchar() != '\n');
scanf("%d", &searchType);
while (getchar() != '\n');
printf("请输入搜索关键词:");
fgets(keyword, sizeof(keyword), stdin);
keyword[strcspn(keyword, "\n")] = '\0';
if (strlen(keyword) == 0) {
printf("\n 搜索关键词不能为空!\n");
getchar();
clearScreen();
return;
}
movie* p = movieList;
int found = 0;
printf("\n===== 搜索结果 =====\n");
printf("电影ID\t名称\t\t价格\t类型\t\t上映状态\n");
printf("------------------------------------------------------------\n");
while (p != NULL) {
int match = 0;
switch (searchType) {
case 1: match = isSubsequenceIgnoreCase(p->title, keyword); break;
case 2: match = isSubsequenceIgnoreCase(p->type, keyword); break;
default:
printf(" 搜索方式错误!\n");
getchar();
clearScreen();
return;
}
if (match) {
found = 1;
time_t now = time(NULL);
const char* status = (now >= p->startTime && now <= p->endTime) ? "正在上映" : "未上映/已下映";
printf("%-6d%-15s%-8.2f%-12s%-20s\n", p->id, p->title, p->price, p->type, status);
}
p = p->next;
}
if (!found) {
printf("\n 未找到符合「%s」条件的电影\n", keyword);
}
printf("\n按任意键继续...\n");
getchar();
clearScreen();
}
// 查看所有用户
void view_all_users() {
clearScreen();
user* p = head;
if (p == NULL) {
printf("暂无注册用户\n");
printf("按任意键继续...\n");
getchar(); getchar();
clearScreen();
return;
}
printf("用户ID\t用户名\t\t身份\n");
printf("--------------------------------\n");
while (p != NULL) {
printf("%-6d%-16s%-10s\n", p->id, p->name, p->isAdmin ? "管理员" : "普通用户");
p = p->next;
}
printf("\n按任意键继续...\n");
getchar(); getchar();
clearScreen();
}
// 登录
void login() {
clearScreen();
char name[50];
char password[50];
int trycount = 0;
const int maxtry = 5;
user* p = NULL;
while (p == NULL) {
printf("\n===== 用户登录 =====\n");
printf("请输入用户名: ");
scanf("%s", name);
p = head;
while (p != NULL) {
if (strcmp(p->name, name) == 0)
break;
p = p->next;
}
if (p == NULL) {
printf("用户不存在!请重新输入用户名\n");
}
}
trycount = 0;
while (trycount < maxtry) {
printf("请输入密码: ");
inputPassword(password, 15);
printf("\n");
if (strcmp(p->password, password) == 0) {
printf("登录成功!\n");
currentUser = p;
clearScreen();
p->isAdmin ? adminmenu() : usermenu();
return;
}
else {
trycount++;
printf("密码错误!剩余 %d 次机会\n", maxtry - trycount);
}
}
printf("登录失败!密码错误次数过多\n");
while (getchar() != '\n');
clearScreen();
}
// 注册
void reg() {
clearScreen();
int admin;
printf("\n====================================\n");
printf(" 用户注册\n");
printf("====================================\n");
printf("0. 管理员\n1. 普通用户\n选择:");
scanf("%d", &admin);
char name[50];
printf("用户名: ");
scanf("%s", name);
user* p = head;
while (p != NULL) {
if (strcmp(p->name, name) == 0) {
printf("用户名已存在!\n");
getchar(); getchar();
clearScreen();
return;
}
p = p->next;
}
user* newuser = (user*)malloc(sizeof(user));
memset(newuser, 0, sizeof(user));
newuser->isAdmin = (admin == 0) ? 1 : 0;
int count = 0;
p = head;
while (p) { count++; p = p->next; }
newuser->id = count + 1;
char password[50];
printf("设置密码:");
inputPassword(password, 15);
printf("\n");
getchar();
printf("密保问题:");
fgets(newuser->securityQuestion, 100, stdin);
newuser->securityQuestion[strcspn(newuser->securityQuestion, "\n")] = 0;
printf("密保答案:");
fgets(newuser->securityAnswer, 100, stdin);
newuser->securityAnswer[strcspn(newuser->securityAnswer, "\n")] = 0;
strcpy(newuser->name, name);
strcpy(newuser->password, password);
newuser->next = head;
head = newuser;
printf("注册成功!\n");
save_to_file();
printf("1. 立即登录\n2. 稍后\n选择:");
int ch;
scanf("%d", &ch);
if (ch == 1) {
clearScreen();
login();
}
else {
getchar(); getchar();
clearScreen();
}
}
// 找回密码
void findPassword() {
clearScreen();
char name[50];
printf("请输入用户名:");
scanf("%s", name);
user* p = head;
while (p) {
if (strcmp(p->name, name) == 0) {
printf("\n密保问题:%s\n", p->securityQuestion);
char ans[100];
getchar();
printf("答案:");
fgets(ans, 100, stdin);
ans[strcspn(ans, "\n")] = 0;
if (!strcmp(ans, p->securityAnswer)) {
printf("验证成功!新密码:");
inputPassword(p->password, 50);
printf("\n修改成功!\n");
save_to_file();
}
else {
printf("答案错误!\n");
}
getchar();
return;
}
p = p->next;
}
printf("用户不存在!\n");
getchar();
}
// 电影浏览(自动分 热映 / 即将 / 下架)
void browseMovies() {
clearScreen();
time_t now = time(NULL);
printf("===== 正在热映 =====\n");
for (movie* p = movieList; p; p = p->next)
if (now >= p->startTime && now <= p->endTime)
printf("%d. %s %s %d分钟 厅:%d\n",
p->id, p->title, p->type, p->duration, p->fixedHall + 1);
printf("\n===== 即将上映 =====\n");
for (movie* p = movieList; p; p = p->next)
if (now < p->startTime)
printf("%d. %s\n", p->id, p->title);
printf("\n===== 已下架 =====\n");
for (movie* p = movieList; p; p = p->next)
if (now > p->endTime)
printf("%d. %s\n", p->id, p->title);
printf("\n按回车返回...\n");
while (getchar() != '\n'); getchar();
clearScreen();
}
影院票务管理系统功能与用户界面设计总结
本项目实现了一个完整的影院票务管理系统,覆盖管理员和普通用户的操作功能,提供电影管理、购票、座位管理、订单管理及用户账户管理等功能。本文将结合系统 UI 模块详细说明各功能模块及交互流程。
系统角色与操作界面;管理员与普通用户
系统主要角色:
-
管理员:具备电影信息管理、座位总控、用户及系统管理权限
-
普通用户:可浏览电影信息、搜索电影、购票、退票、查看订单及修改密码
界面设计采用 菜单式交互,分为管理员菜单和用户菜单,使用清晰的编号选择操作。
管理员菜单;电影、座位与系统管理
管理员菜单功能:
-
电影管理
;浏览电影:展示当前电影列表,包括热映、即将上映、已下架
;新增电影:填写电影名称、票价、类型、上映时间、导演、主演及固定影厅
;删除电影:根据电影ID删除指定电影
;修改电影信息:可修改上映时间、状态及其他信息
-
影厅座位总控
;管理员可查看和修改任意影厅×场次座位状态
;座位矩阵显示:
O=可售,X=已占座;支持动态初始化场次座位节点
-
系统管理
;查看所有注册用户及身份信息
;修改管理员密码
;初始化座位列表,确保所有影厅×场次座位节点完整
操作流程使用循环菜单,输入数字选择功能,错误输入提供提示并重新输入。
用户菜单;购票与订单管理
普通用户菜单功能:
-
浏览电影信息
;自动区分热映、即将上映、已下架
-
搜索电影
;支持按电影名称或类型搜索
;忽略大小写匹配,提高搜索容错性
-
购票
;选择电影 → 场次 → 座位
;生成订单及唯一取票码
-
我的订单
;显示用户所有购票记录
-
查看座位
;显示影厅×场次座位矩阵
;自动初始化未存在的场次节点
-
退票
;根据订单ID退票,并释放座位
-
修改密码
;支持安全验证并修改密码
用户菜单同样采用编号选择操作,确保交互简洁、直观。
登录、注册与找回密码;安全与便捷
-
登录
;用户名验证 → 密码验证(5次机会限制)
;管理员登录进入管理员菜单,普通用户进入用户菜单
-
注册
;设置用户名、密码、密保问题与答案
;选择身份(管理员或普通用户)
;注册成功后可立即登录
-
找回密码
;根据用户名显示密保问题
;验证答案正确后可修改密码
;保证账户安全性
电影浏览与搜索;智能分类
-
浏览电影
;系统根据当前时间自动将电影分类为热映、即将上映、已下架
;显示电影ID、名称、类型、时长及固定影厅
-
搜索电影
;支持按名称或类型搜索
;使用忽略大小写的子串匹配函数
isSubsequenceIgnoreCase;结果展示电影ID、名称、价格、类型及上映状态
这种设计便于用户快速查找感兴趣的电影,提高操作体验。
座位管理与可视化;直观操作
-
使用二维数组
seats[ROWS][COLS]表示座位 -
座位显示矩阵清晰标注
O=可选座位,X=已售 -
用户和管理员都可查看座位状态
-
管理员可修改座位状态,实现灵活控制
座位节点通过链表管理,保证多影厅、多场次场景下的灵活扩展。
系统交互设计亮点;友好与安全
-
菜单式操作:数字选择,简洁明了
-
输入验证:对数字范围、座位选择、密码输入均做有效性判断
-
安全性:登录限制次数、密保找回密码、管理员权限控制
-
交互提示:操作结果明确,成功或错误信息及时反馈
-
灵活扩展:座位初始化、动态生成订单、自动分类电影
这些设计保证了系统使用的便捷性与安全性,同时方便后续扩展功能,如在线支付、优惠活动等。
总结;系统价值与使用体验
本项目通过合理的模块化设计,完成了一个功能完善的影院票务管理系统:
-
支持管理员与普通用户不同角色操作
-
提供全面的电影、座位及订单管理功能
-
交互清晰,易于操作
-
数据安全与持久化保障系统稳定性
-
UI模块与业务逻辑层、数据访问层紧密结合
系统不仅适合作为 C语言项目练手,也可作为小型影院管理系统的原型,具有较高的实用价值与学习参考意义。
entity.h
cs
#ifndef ENTITY_H
#define ENTITY_H
#include <time.h>
#define HALLS 7
#define TIMES 4
#define ROWS 5
#define COLS 8
typedef enum {
HALL_1, HALL_2, HALL_3, HALL_4, HALL_5, HALL_6, HALL_7
} HallScene;
typedef struct user {
int id;
char name[50];
char password[50];
int isAdmin;
char securityQuestion[100];
char securityAnswer[100];
struct user* next;
} user;
typedef enum {
MOVIE_AVAILABLE = 1,
MOVIE_PLAYING,
MOVIE_PREVIEW,
MOVIE_OFF
} MovieStatus;
typedef struct movie {
int id;
char title[50];
float price;
char type[50];
MovieStatus status;
time_t startTime;
time_t endTime;
int duration;
char director[50];
char actor[100];
HallScene fixedHall;
struct movie* next;
} movie;
// ======================
// 你要的:场次座位节点
// ======================
typedef struct SeatNode {
int hallId; // 影厅编号
int timeIdx; // 场次编号
int seats[ROWS][COLS];// 本场次座位矩阵
struct SeatNode* next;
} SeatNode;
typedef struct order {
int id;
int userId;
int movieId;
char movieName[50];
int quantity;
float totalPrice;
int hallId;
int timeIdx;
int row;
int col;
time_t timestamp;
char ticketCode[10];
struct order* next;
} order;
extern user* head;
extern user* currentUser;
extern movie* movieList;
extern order* orderList;
extern SeatNode* seatList; // 场次座位链表
#endif
common.c
cs
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "entity.h"
#include "dal.h"
#include"ui.h"
#include "bll.h"
void clearScreen() {
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
void inputPassword(char* password, int maxLen)
{
int i = 0;
char ch;
while (1)
{
ch = _getch();
if (ch == 13) {
password[i] = '\0';
break;
}
else if (ch == 8) {
if (i > 0) {
i--;
printf("\b \b");
}
}
else if (i < maxLen - 1) {
password[i++] = ch;
printf("*");
}
}
}
void formatTimestamp(time_t timestamp, char* outBuf, int bufSize) {
// 1. 安全判断
if (outBuf == NULL || bufSize <= 0) {
return;
}
// 2. 先清空缓冲区,防止乱码
memset(outBuf, 0, bufSize);
// 3. 缓冲区太小直接返回
if (bufSize < 20) {
strcpy(outBuf, "时间格式错误");
return;
}
// 4. 获取时间
struct tm* tinfo = localtime(×tamp);
if (tinfo == NULL) {
strcpy(outBuf, "无效时间");
return;
}
// 5. 标准格式,不严格、不报错
strftime(outBuf, bufSize, "%Y-%m-%d %H:%M:%S", tinfo);
}
源.c
cs
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "entity.h"
#include "dal.h"
#include "ui.h"
#include"bll.h"
int main()
{
load_from_file();
int choice;
do {
clearScreen();
printf("\n====================================\n");
printf(" 影院票务管理系统\n");
printf("====================================\n");
printf(" 1. 用户登录\n");
printf(" 2. 用户注册\n");
printf(" 3. 找回密码\n");
printf(" 0. 退出系统\n");
printf("====================================\n");
printf("请选择:");
scanf("%d", &choice);
while (getchar() != '\n');
switch (choice)
{
case 1: login(); break;
case 2: reg(); break;
case 3: findPassword(); break;
case 0:
save_to_file();
printf("\n已保存数据,欢迎下次使用!\n");
break;
default:
printf("\n输入错误,请重新选择!\n");
getchar();
break;
}
} while (choice != 0);
return 0;
}
肝不动了,好累,明天加工