#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <graphics.h>
#include <easyx.h>
#include <mmsystem.h>
#include <time.h>
#include <functional>
#include <string>
#include <vector>
#include <iostream>
#include <conio.h>
#include <io.h>
#include <shlwapi.h>
#include <algorithm>
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "shlwapi.lib")
// 解决time_t格式化问题
#ifdef _WIN32
#define TIME_T_FMT "%lld"
#else
#define TIME_T_FMT "%ld"
#endif
// 座位状态常量
#define SEAT_AVAILABLE L"空闲"
#define SEAT_RESERVED L"已预约"
#define SEAT_OCCUPIED L"已占用"
#define SEAT_MAINTAIN L"维护中"
// 数据文件路径
#define SEAT_DATA_FILE L"seats.txt"
#define USER_DATA_FILE L"users.txt"
// 定义Button类,表示一个按钮
class Button
{
private:
int x;
int y;
int width;
int height;
float scale;
bool isMouseOver;
std::wstring text;
std::function<void()> onClick;
public:
Button(int x, int y, int width, int height, const std::wstring& text, const std::function<void()>& onClick)
: x(x), y(y), width(width), height(height), text(text), onClick(onClick), scale(1.0f), isMouseOver(false)
{
}
void checkMouseOver(int mouseX, int mouseY)
{
isMouseOver = (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height);
if (isMouseOver) {
scale = 0.95f;
}
else {
scale = 1.0f;
}
}
bool checkClick(int mouseX, int mouseY)
{
if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height)
{
onClick();
isMouseOver = false;
scale = 1.0f;
return true;
}
return false;
}
void draw()
{
int scaledWidth = static_cast<int>(width * scale);
int scaledHeight = static_cast<int>(height * scale);
int scaledX = x + (width - scaledWidth) / 2;
int scaledY = y + (height - scaledHeight) / 2;
if (isMouseOver)
{
setlinecolor(RGB(0, 120, 215));
setfillcolor(RGB(229, 241, 251));
}
else
{
setlinecolor(RGB(100, 149, 237));
setfillcolor(RGB(173, 216, 230));
}
fillroundrect(scaledX, scaledY, scaledX + scaledWidth, scaledY + scaledHeight, 10, 10);
settextcolor(BLACK);
setbkmode(TRANSPARENT);
settextstyle(static_cast<int>(20 * scale), 0, _T("微软雅黑"));
int textX = scaledX + (scaledWidth - textwidth(text.c_str())) / 2;
int textY = scaledY + (scaledHeight - textheight(_T("T"))) / 2;
outtextxy(textX, textY, text.c_str());
}
};
class Widget
{
public: // 将pages和buttons改为public
std::vector<IMAGE*> pages;
std::vector<std::vector<Button*>> buttons;
private:
int width;
int height;
int currentIndex;
public:
Widget(int width, int height)
:width(width), height(height), currentIndex(-1)
{
}
~Widget()
{
clearPages();
}
void clearPages() {
for (auto page : pages) {
delete page;
}
pages.clear();
for (auto& pageButtons : buttons) {
for (auto button : pageButtons) {
delete button;
}
pageButtons.clear();
}
buttons.clear();
}
void addPage(IMAGE* page)
{
pages.push_back(page);
buttons.push_back({});
}
void addButton(int index, Button* button)
{
if (index >= 0 && index < static_cast<int>(buttons.size()))
{
buttons[index].push_back(button);
}
}
void setCurrentIndex(int index)
{
if (index >= 0 && index < static_cast<int>(pages.size()))
{
currentIndex = index;
}
}
int getCurrentIndex() const {
return currentIndex;
}
void init()
{
initgraph(width, height);
}
void run()
{
ExMessage msg;
BeginBatchDraw();
while (true)
{
if (peekmessage(&msg))
{
int mouseX = msg.x;
int mouseY = msg.y;
switch (msg.message)
{
case WM_LBUTTONDOWN:
if (currentIndex >= 0 && currentIndex < static_cast<int>(buttons.size()))
{
for (Button* button : buttons[currentIndex])
{
if (button->checkClick(mouseX, mouseY)) break;
}
}
break;
case WM_MOUSEMOVE:
if (currentIndex >= 0 && currentIndex < static_cast<int>(buttons.size()))
{
for (Button* button : buttons[currentIndex])
{
button->checkMouseOver(mouseX, mouseY);
}
}
break;
case WM_KEYDOWN:
if (msg.vkcode == VK_ESCAPE) // 按ESC键退出
{
return;
}
break;
}
}
cleardevice();
if (currentIndex >= 0 && currentIndex < static_cast<int>(pages.size()))
{
putimage(0, 0, pages[currentIndex]);
for (Button* button : buttons[currentIndex])
{
button->draw();
}
}
// 添加页面标题
settextcolor(RGB(25, 25, 112));
settextstyle(32, 0, _T("微软雅黑"));
switch (currentIndex) {
case 0:
outtextxy(220, 50, _T("湘潭大学图书馆座位预约系统"));
break;
case 1:
outtextxy(300, 50, _T("用户功能菜单"));
break;
case 2:
outtextxy(300, 50, _T("管理员功能菜单"));
break;
case 3:
outtextxy(300, 50, _T("座位查询功能"));
break;
}
// 添加操作提示
settextcolor(RGB(70, 70, 70));
settextstyle(16, 0, _T("微软雅黑"));
outtextxy(20, height - 30, _T("提示: 鼠标悬停在按钮上可查看效果,ESC键退出系统"));
FlushBatchDraw();
Sleep(10);
}
EndBatchDraw();
}
void close()
{
closegraph();
}
};
// 结构体定义
typedef struct Seats {
wchar_t number[50];
wchar_t state[20];
int floor;
struct Seats* next;
struct Seats* prev;
} Seat;
typedef struct User {
wchar_t studentId[20];
wchar_t password[20];
wchar_t reservedSeat[50];
time_t registerTime;
struct User* next;
} User;
typedef struct SeatQueue {
Seat* front;
Seat* rear;
int count;
} SeatQueue;
// 全局变量
SeatQueue* seatQueue = NULL;
User* userList = NULL;
User* currentUser = NULL;
bool isAdmin = false;
int musicPlaying = 0;
Widget* globalWidget = nullptr;
// 函数声明
SeatQueue* createQueue();
void destroyQueue(SeatQueue* queue);
Seat* createSeat(const wchar_t* number, int floor, const wchar_t* state);
void addSeat(SeatQueue* queue, Seat* seat);
void removeSeat(SeatQueue* queue, Seat* seat);
Seat* findSeatByNumber(SeatQueue* queue, const wchar_t* number);
Seat* findSeatByFloor(SeatQueue* queue, int floor, Seat* startAfter);
Seat* findSeatByState(SeatQueue* queue, const wchar_t* state, Seat* startAfter);
Seat* findRandomAvailableSeat(SeatQueue* queue);
void loadSeats(SeatQueue* queue, const wchar_t* filename);
void saveSeats(SeatQueue* queue, const wchar_t* filename);
int loginUser(User** user);
void addUser(User** head, const wchar_t* id, const wchar_t* password);
void loadUsers(User** head, const wchar_t* filename);
void saveUsers(User* head, const wchar_t* filename);
User* findUser(User* head, const wchar_t* id);
void handleReserveSeat(User* user, const wchar_t* seatNumber); // 移除默认参数
void handleCancelReservation(User* user);
void updateSeatState(Seat* seat, const wchar_t* state);
void displayRandomAvailableSeat();
int adminLogin();
void initGlobalWidget();
void initMainMenuButtons();
void initUserMenuButtons();
void initAdminMenuButtons();
void initSeatQueryButtons();
void cleanup();
void displaySeatList(Seat* startSeat, const wchar_t* title, int maxCount,
std::function<Seat* (Seat*)> getNextFunc,
bool showReserveButtons = false);
void displaySeatListPage(const wchar_t* title,
std::function<Seat* (Seat*)> getFirstFunc,
std::function<Seat* (Seat*)> getNextFunc,
bool showReserveButtons = false);
// 座位队列相关函数实现
SeatQueue* createQueue() {
SeatQueue* queue = (SeatQueue*)malloc(sizeof(SeatQueue));
if (!queue) {
MessageBox(NULL, L"内存分配失败", L"错误", MB_OK | MB_ICONERROR);
exit(1);
}
queue->front = queue->rear = NULL;
queue->count = 0;
return queue;
}
void destroyQueue(SeatQueue* queue) {
if (!queue) return;
Seat* current = queue->front;
while (current) {
Seat* next = current->next;
free(current);
current = next;
}
free(queue);
}
Seat* createSeat(const wchar_t* number, int floor, const wchar_t* state) {
Seat* seat = (Seat*)malloc(sizeof(Seat));
if (!seat) {
MessageBox(NULL, L"内存分配失败", L"错误", MB_OK | MB_ICONERROR);
exit(1);
}
wcscpy_s(seat->number, number);
wcscpy_s(seat->state, state);
seat->floor = floor;
seat->next = seat->prev = NULL;
return seat;
}
void addSeat(SeatQueue* queue, Seat* seat) {
if (!queue || !seat) return;
if (!queue->rear) {
queue->front = queue->rear = seat;
}
else {
queue->rear->next = seat;
seat->prev = queue->rear;
queue->rear = seat;
}
queue->count++;
}
void removeSeat(SeatQueue* queue, Seat* seat) {
if (!queue || !seat) return;
if (seat->prev) seat->prev->next = seat->next;
else queue->front = seat->next;
if (seat->next) seat->next->prev = seat->prev;
else queue->rear = seat->prev;
queue->count--;
free(seat);
}
// 查找座位
Seat* findSeatByNumber(SeatQueue* queue, const wchar_t* number) {
if (!queue || !number) return NULL;
Seat* current = queue->front;
while (current) {
if (wcscmp(current->number, number) == 0) {
return current;
}
current = current->next;
}
return NULL;
}
Seat* findSeatByFloor(SeatQueue* queue, int floor, Seat* startAfter) {
if (!queue) return NULL;
Seat* current = startAfter ? startAfter->next : queue->front;
while (current) {
if (current->floor == floor) {
return current;
}
current = current->next;
}
return NULL;
}
Seat* findSeatByState(SeatQueue* queue, const wchar_t* state, Seat* startAfter) {
if (!queue || !state) return NULL;
Seat* current = startAfter ? startAfter->next : queue->front;
while (current) {
if (wcscmp(current->state, state) == 0) {
return current;
}
current = current->next;
}
return NULL;
}
// 查找随机可用座位
Seat* findRandomAvailableSeat(SeatQueue* queue) {
if (!queue) return NULL;
// 统计可用座位数量
int availableCount = 0;
Seat* current = queue->front;
while (current) {
if (wcscmp(current->state, SEAT_AVAILABLE) == 0) {
availableCount++;
}
current = current->next;
}
if (availableCount == 0) return NULL;
// 随机选择一个可用座位
srand(static_cast<unsigned int>(time(NULL)));
int randomIndex = rand() % availableCount;
int currentIndex = 0;
current = queue->front;
while (current) {
if (wcscmp(current->state, SEAT_AVAILABLE) == 0) {
if (currentIndex == randomIndex) {
return current;
}
currentIndex++;
}
current = current->next;
}
return NULL;
}
// 文件操作函数
void loadSeats(SeatQueue* queue, const wchar_t* filename) {
if (!queue) return;
FILE* file = _wfopen(filename, L"r");
if (!file) {
wprintf(L"座位数据文件不存在,创建默认数据...\n");
// 添加更多初始座位数据
addSeat(queue, createSeat(L"A101", 1, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"A102", 1, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"A103", 1, SEAT_RESERVED));
addSeat(queue, createSeat(L"A104", 1, SEAT_OCCUPIED));
addSeat(queue, createSeat(L"A105", 1, SEAT_MAINTAIN));
addSeat(queue, createSeat(L"A106", 1, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"A107", 1, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"A108", 1, SEAT_RESERVED));
addSeat(queue, createSeat(L"A109", 1, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"A110", 1, SEAT_OCCUPIED));
addSeat(queue, createSeat(L"B201", 2, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"B202", 2, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"B203", 2, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"B204", 2, SEAT_RESERVED));
addSeat(queue, createSeat(L"B205", 2, SEAT_OCCUPIED));
addSeat(queue, createSeat(L"B206", 2, SEAT_MAINTAIN));
addSeat(queue, createSeat(L"B207", 2, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"B208", 2, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"B209", 2, SEAT_RESERVED));
addSeat(queue, createSeat(L"B210", 2, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"C301", 3, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"C302", 3, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"C303", 3, SEAT_RESERVED));
addSeat(queue, createSeat(L"C304", 3, SEAT_RESERVED));
addSeat(queue, createSeat(L"C305", 3, SEAT_MAINTAIN));
addSeat(queue, createSeat(L"C306", 3, SEAT_OCCUPIED));
addSeat(queue, createSeat(L"C307", 3, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"C308", 3, SEAT_AVAILABLE));
addSeat(queue, createSeat(L"C309", 3, SEAT_RESERVED));
addSeat(queue, createSeat(L"C310", 3, SEAT_AVAILABLE));
// 保存初始数据到文件
saveSeats(queue, filename);
return;
}
wchar_t number[50], state[20];
int floor;
while (fwscanf(file, L"%49s %d %19s", number, &floor, state) != EOF) {
addSeat(queue, createSeat(number, floor, state));
}
fclose(file);
}
void saveSeats(SeatQueue* queue, const wchar_t* filename) {
if (!queue) return;
FILE* file = _wfopen(filename, L"w");
if (!file) {
MessageBox(NULL, L"无法保存座位数据", L"错误", MB_OK | MB_ICONERROR);
return;
}
Seat* current = queue->front;
while (current) {
fwprintf(file, L"%s %d %s\n", current->number, current->floor, current->state);
current = current->next;
}
fclose(file);
}
// 用户管理函数
void loadUsers(User** head, const wchar_t* filename) {
FILE* file = _wfopen(filename, L"r");
if (!file) {
wprintf(L"用户数据文件不存在,创建默认用户...\n");
// 添加初始用户数据
addUser(head, L"20250001", L"123456");
addUser(head, L"20250002", L"654321");
addUser(head, L"20250003", L"123456");
// 为部分用户分配预约座位
User* user1 = findUser(*head, L"20250001");
if (user1) {
wcscpy_s(user1->reservedSeat, L"A103");
saveUsers(*head, filename);
}
User* user2 = findUser(*head, L"20250002");
if (user2) {
wcscpy_s(user2->reservedSeat, L"B204");
saveUsers(*head, filename);
}
return;
}
wchar_t id[20], password[20], seat[50];
time_t regTime;
while (fwscanf(file, L"%19s %19s %49s " TIME_T_FMT, id, password, seat, ®Time) != EOF) {
User* user = (User*)malloc(sizeof(User));
if (!user) {
MessageBox(NULL, L"内存分配失败", L"错误", MB_OK | MB_ICONERROR);
continue;
}
wcscpy_s(user->studentId, id);
wcscpy_s(user->password, password);
wcscpy_s(user->reservedSeat, seat);
user->registerTime = regTime;
user->next = *head;
*head = user;
}
fclose(file);
}
void saveUsers(User* head, const wchar_t* filename) {
FILE* file = _wfopen(filename, L"w");
if (!file) {
MessageBox(NULL, L"无法保存用户数据", L"错误", MB_OK | MB_ICONERROR);
return;
}
User* current = head;
while (current) {
fwprintf(file, L"%s %s %s " TIME_T_FMT L"\n",
current->studentId,
current->password,
current->reservedSeat,
current->registerTime);
current = current->next;
}
fclose(file);
}
// 用户登录
int loginUser(User** user) {
wchar_t id[20], password[20];
// 清空当前屏幕
cleardevice();
// 绘制登录界面
IMAGE loginBg;
if (_waccess(_T("login_bg.jpg"), 0) != -1) {
loadimage(&loginBg, _T("login_bg.jpg"), 800, 600, true);
putimage(0, 0, &loginBg);
}
else {
setbkcolor(RGB(240, 248, 255)); // 淡蓝色背景
cleardevice();
}
// 绘制标题
settextstyle(30, 0, _T("微软雅黑"));
settextcolor(RGB(25, 25, 112)); // 深蓝色
outtextxy(220, 50, _T("湘潭大学图书馆座位预约系统"));
settextstyle(20, 0, _T("微软雅黑"));
settextcolor(RGB(0, 0, 139)); // 深蓝色
outtextxy(350, 150, _T("用户登录"));
// 添加操作提示
settextstyle(16, 0, _T("微软雅黑"));
settextcolor(RGB(70, 70, 70));
outtextxy(250, 200, _T("请输入您的学号和密码登录系统"));
outtextxy(250, 230, _T("默认用户: 20250001(123456), 20250002(654321)"));
FlushBatchDraw();
// 输入学号
if (InputBox(id, sizeof(id) / sizeof(wchar_t), _T("请输入学号"), NULL, NULL, 0, FALSE) <= 0) {
return 0; // 用户取消
}
// 输入密码
if (InputBox(password, sizeof(password) / sizeof(wchar_t), _T("请输入密码"), NULL, NULL, 0, TRUE) <= 0) {
return 0; // 用户取消
}
if (wcscmp(id, L"20250001") == 0 && wcscmp(password, L"123456") == 0) {
// 清空登录界面
cleardevice();
// 显示欢迎信息
settextstyle(30, 0, _T("微软雅黑"));
settextcolor(RGB(25, 25, 112));
outtextxy(250, 200, L"登录成功,正在跳转...");
FlushBatchDraw();
Sleep(1500);
return 1;
}
// 从文件验证用户
User* found = findUser(userList, id);
if (found && wcscmp(found->password, password) == 0) {
*user = found;
// 清空登录界面
cleardevice();
// 显示欢迎信息
settextstyle(30, 0, _T("微软雅黑"));
settextcolor(RGB(25, 25, 112));
outtextxy(250, 200, L"登录成功,正在跳转...");
FlushBatchDraw();
Sleep(1500);
return 1;
}
MessageBox(NULL, _T("登录失败,请检查学号和密码"), _T("错误"), MB_OK | MB_ICONERROR);
return 0;
}
// 添加用户
void addUser(User** head, const wchar_t* id, const wchar_t* password) {
if (findUser(*head, id)) {
MessageBox(NULL, _T("该用户已存在"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
User* newUser = (User*)malloc(sizeof(User));
if (!newUser) {
MessageBox(NULL, _T("内存分配失败"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
wcscpy_s(newUser->studentId, id);
wcscpy_s(newUser->password, password);
newUser->reservedSeat[0] = L'\0';
newUser->registerTime = time(NULL);
newUser->next = *head;
*head = newUser;
saveUsers(*head, USER_DATA_FILE);
}
// 查找用户
User* findUser(User* head, const wchar_t* id) {
User* current = head;
while (current) {
if (wcscmp(current->studentId, id) == 0) {
return current;
}
current = current->next;
}
return NULL;
}
// 处理座位预约 - 移除定义中的默认参数
void handleReserveSeat(User* user, const wchar_t* seatNumber) {
if (!user) {
MessageBox(NULL, _T("请先登录"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
if (wcslen(user->reservedSeat) > 0) {
MessageBox(NULL, _T("你已经预约了座位,不能重复预约"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
wchar_t seatNum[50];
if (seatNumber) {
wcscpy_s(seatNum, seatNumber);
}
else {
if (InputBox(seatNum, sizeof(seatNum) / sizeof(wchar_t),
_T("请输入要预约的座位编号(例如:A101)"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消操作
}
}
Seat* seat = findSeatByNumber(seatQueue, seatNum);
if (!seat) {
MessageBox(NULL, _T("未找到该座位,请检查座位编号是否正确"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
if (wcscmp(seat->state, SEAT_AVAILABLE) != 0) {
wchar_t msg[100];
swprintf_s(msg, L"该座位不可预约,当前状态: %s", seat->state);
MessageBox(NULL, msg, _T("错误"), MB_OK | MB_ICONERROR);
return;
}
// 更新座位状态
updateSeatState(seat, SEAT_RESERVED);
wcscpy_s(user->reservedSeat, seatNum);
saveUsers(userList, USER_DATA_FILE);
saveSeats(seatQueue, SEAT_DATA_FILE);
wchar_t msg[100];
swprintf_s(msg, L"成功预约座位: %s", seatNum);
MessageBox(NULL, msg, L"成功", MB_OK);
}
// 处理取消预约
void handleCancelReservation(User* user) {
if (!user) {
MessageBox(NULL, _T("请先登录"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
if (wcslen(user->reservedSeat) == 0) {
MessageBox(NULL, _T("你没有预约任何座位"), _T("提示"), MB_OK);
return;
}
wchar_t msg[100];
swprintf_s(msg, L"确定要取消预约的座位 %s 吗?", user->reservedSeat);
int confirm = MessageBox(NULL, msg, L"确认取消预约", MB_YESNO | MB_ICONQUESTION);
if (confirm != IDYES) return;
Seat* seat = findSeatByNumber(seatQueue, user->reservedSeat);
if (!seat) {
MessageBox(NULL, _T("未找到你预约的座位"), _T("错误"), MB_OK | MB_ICONERROR);
user->reservedSeat[0] = L'\0';
saveUsers(userList, USER_DATA_FILE);
return;
}
// 更新座位状态
updateSeatState(seat, SEAT_AVAILABLE);
user->reservedSeat[0] = L'\0';
saveUsers(userList, USER_DATA_FILE);
saveSeats(seatQueue, SEAT_DATA_FILE);
MessageBox(NULL, _T("成功取消预约"), _T("提示"), MB_OK);
}
// 管理员登录
int adminLogin() {
wchar_t id[20], password[20];
// 清空当前屏幕
cleardevice();
// 绘制登录界面
IMAGE loginBg;
if (_waccess(_T("admin_login_bg.jpg"), 0) != -1) {
loadimage(&loginBg, _T("admin_login_bg.jpg"), 800, 600, true);
putimage(0, 0, &loginBg);
}
else {
setbkcolor(RGB(240, 248, 255)); // 淡蓝色背景
cleardevice();
}
// 绘制标题
settextstyle(30, 0, _T("微软雅黑"));
settextcolor(RGB(25, 25, 112)); // 深蓝色
outtextxy(220, 50, _T("湘潭大学图书馆座位预约系统"));
settextstyle(20, 0, _T("微软雅黑"));
settextcolor(RGB(0, 0, 139)); // 深蓝色
outtextxy(350, 150, _T("管理员登录"));
// 添加操作提示
settextstyle(16, 0, _T("微软雅黑"));
settextcolor(RGB(70, 70, 70));
outtextxy(280, 200, _T("默认账号: admin, 密码: admin123"));
FlushBatchDraw();
// 输入管理员账号
if (InputBox(id, sizeof(id) / sizeof(wchar_t), _T("请输入管理员账号"), NULL, NULL, 0, FALSE) <= 0) {
return 0; // 用户取消
}
// 输入密码
if (InputBox(password, sizeof(password) / sizeof(wchar_t), _T("请输入密码"), NULL, NULL, 0, TRUE) <= 0) {
return 0; // 用户取消
}
// 简单验证,实际应用中应从数据库或配置文件读取
if (wcscmp(id, L"admin") == 0 && wcscmp(password, L"admin123") == 0) {
// 清空登录界面
cleardevice();
// 显示欢迎信息
settextstyle(30, 0, _T("微软雅黑"));
settextcolor(RGB(25, 25, 112));
outtextxy(250, 200, L"管理员登录成功,正在跳转...");
FlushBatchDraw();
Sleep(1500);
return 1;
}
MessageBox(NULL, L"登录失败,请检查账号和密码", L"错误", MB_OK | MB_ICONERROR);
return 0;
}
// 显示随机可用座位
void displayRandomAvailableSeat() {
Seat* randomSeat = findRandomAvailableSeat(seatQueue);
if (!randomSeat) {
MessageBox(NULL, _T("当前没有可用的座位"), _T("提示"), MB_OK);
return;
}
wchar_t info[200];
swprintf_s(info, L"系统为您随机推荐一个可用座位:\n\n座位编号: %s\n楼层: %d层\n状态: %s\n\n是否预约该座位?",
randomSeat->number, randomSeat->floor, randomSeat->state);
int choice = MessageBox(NULL, info, L"随机推荐座位", MB_YESNO | MB_ICONQUESTION);
if (choice == IDYES && currentUser) {
// 更新座位状态
updateSeatState(randomSeat, SEAT_RESERVED);
wcscpy_s(currentUser->reservedSeat, randomSeat->number);
saveUsers(userList, USER_DATA_FILE);
saveSeats(seatQueue, SEAT_DATA_FILE);
wchar_t msg[100];
swprintf_s(msg, L"成功预约座位: %s", randomSeat->number);
MessageBox(NULL, msg, L"成功", MB_OK);
}
}
// 更新座位状态
void updateSeatState(Seat* seat, const wchar_t* state) {
if (!seat || !state) return;
wcscpy_s(seat->state, state);
}
// 初始化全局控件
void initGlobalWidget() {
if (globalWidget) return;
globalWidget = new Widget(800, 600);
globalWidget->init();
// 创建页面0 - 主菜单
IMAGE* mainPage = new IMAGE(800, 600);
if (_waccess(_T("main_bg.jpg"), 0) != -1) {
loadimage(mainPage, _T("main_bg.jpg"), 800, 600, true);
}
else {
mainPage->Resize(800, 600);
DWORD* pBuf = GetImageBuffer(mainPage);
for (int i = 0; i < 800 * 600; i++) {
pBuf[i] = RGB(240, 248, 255); // 淡蓝色背景
}
}
globalWidget->addPage(mainPage);
// 创建页面1 - 用户菜单
IMAGE* userPage = new IMAGE(800, 600);
if (_waccess(_T("user_bg.jpg"), 0) != -1) {
loadimage(userPage, _T("user_bg.jpg"), 800, 600, true);
}
else {
userPage->Resize(800, 600);
DWORD* pBuf = GetImageBuffer(userPage);
for (int i = 0; i < 800 * 600; i++) {
pBuf[i] = RGB(230, 240, 255); // 更浅的蓝色背景
}
}
globalWidget->addPage(userPage);
// 创建页面2 - 管理员菜单
IMAGE* adminPage = new IMAGE(800, 600);
if (_waccess(_T("admin_bg.jpg"), 0) != -1) {
loadimage(adminPage, _T("admin_bg.jpg"), 800, 600, true);
}
else {
adminPage->Resize(800, 600);
DWORD* pBuf = GetImageBuffer(adminPage);
for (int i = 0; i < 800 * 600; i++) {
pBuf[i] = RGB(230, 240, 255); // 更浅的蓝色背景
}
}
globalWidget->addPage(adminPage);
// 创建页面3 - 座位查询菜单
IMAGE* queryPage = new IMAGE(800, 600);
if (_waccess(_T("query_bg.jpg"), 0) != -1) {
loadimage(queryPage, _T("query_bg.jpg"), 800, 600, true);
}
else {
queryPage->Resize(800, 600);
DWORD* pBuf = GetImageBuffer(queryPage);
for (int i = 0; i < 800 * 600; i++) {
pBuf[i] = RGB(230, 240, 255); // 更浅的蓝色背景
}
}
globalWidget->addPage(queryPage);
// 初始化所有按钮
initMainMenuButtons();
initUserMenuButtons();
initAdminMenuButtons();
initSeatQueryButtons();
}
// 初始化主菜单按钮
void initMainMenuButtons() {
// 用户登录按钮
globalWidget->addButton(0, new Button(300, 180, 200, 50, L"用户登录", []() {
if (loginUser(¤tUser)) {
globalWidget->setCurrentIndex(1); // 切换到用户菜单
}
}));
// 管理员登录按钮
globalWidget->addButton(0, new Button(300, 250, 200, 50, L"管理员登录", []() {
if (adminLogin()) {
isAdmin = true;
globalWidget->setCurrentIndex(2); // 切换到管理员菜单
}
}));
// 退出系统按钮
globalWidget->addButton(0, new Button(300, 320, 200, 50, L"退出系统", []() {
cleanup();
exit(0);
}));
// 添加系统说明
globalWidget->addButton(0, new Button(250, 400, 300, 30, L"系统说明", []() {
MessageBox(NULL,
L"欢迎使用湘潭大学图书馆座位预约系统\n\n"
L"1. 用户功能:预约座位、取消预约、查询座位\n"
L"2. 管理员功能:管理座位信息\n"
L"3. 默认用户:20250001(123456), 20250002(654321)\n"
L"4. 管理员账号:admin,密码:admin123\n\n"
L"注意:所有操作会自动保存数据",
L"系统说明", MB_OK | MB_ICONINFORMATION);
}));
}
// 初始化用户菜单按钮
void initUserMenuButtons() {
// 查看个人信息
globalWidget->addButton(1, new Button(300, 150, 200, 50, L"查看个人信息", []() {
wchar_t info[200];
struct tm tm_info;
wchar_t regTimeStr[26];
// 安全的时间格式化
if (localtime_s(&tm_info, ¤tUser->registerTime) == 0) {
wcsftime(regTimeStr, 26, L"%Y-%m-%d %H:%M:%S", &tm_info);
}
else {
wcscpy_s(regTimeStr, L"未知时间");
}
swprintf_s(info, L"学号: %s\n注册时间: %s\n已预约座位: %s",
currentUser->studentId,
regTimeStr,
wcslen(currentUser->reservedSeat) > 0 ? currentUser->reservedSeat : L"无");
// 创建信息窗口
HWND hWnd = GetHWnd();
MessageBox(hWnd, info, L"个人信息", MB_OK);
}));
// 预约座位
globalWidget->addButton(1, new Button(300, 220, 200, 50, L"预约座位", []() {
handleReserveSeat(currentUser, nullptr); // 显式传递nullptr
}));
// 取消预约
globalWidget->addButton(1, new Button(300, 290, 200, 50, L"取消预约", []() {
handleCancelReservation(currentUser);
}));
// 座位查询
globalWidget->addButton(1, new Button(300, 360, 200, 50, L"座位查询", []() {
globalWidget->setCurrentIndex(3); // 切换到查询页面
}));
// 退出登录按钮
globalWidget->addButton(1, new Button(300, 430, 200, 50, L"退出登录", []() {
currentUser = NULL;
globalWidget->setCurrentIndex(0); // 返回主菜单
}));
// 帮助按钮
globalWidget->addButton(1, new Button(300, 500, 200, 30, L"使用帮助", []() {
MessageBox(NULL,
L"用户功能使用指南:\n\n"
L"1. 查看个人信息:查看您的预约信息\n"
L"2. 预约座位:输入座位号预约可用座位\n"
L"3. 取消预约:取消您当前的预约\n"
L"4. 座位查询:按不同条件查询座位状态\n"
L"5. 退出登录:返回主菜单\n\n"
L"提示:在查询界面可以直接预约空闲座位",
L"用户帮助", MB_OK | MB_ICONINFORMATION);
}));
}
// 初始化管理员菜单按钮
void initAdminMenuButtons() {
// 添加座位
globalWidget->addButton(2, new Button(300, 150, 200, 50, L"添加座位", []() {
wchar_t number[50], state[20], floorStr[10];
int floor;
if (InputBox(number, sizeof(number) / sizeof(wchar_t), _T("请输入座位编号(例如:A101)"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
if (InputBox(floorStr, sizeof(floorStr) / sizeof(wchar_t), _T("请输入楼层(1-5)"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
floor = _wtoi(floorStr);
if (floor < 1 || floor > 5) {
MessageBox(NULL, _T("楼层必须在1到5之间"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
if (InputBox(state, sizeof(state) / sizeof(wchar_t), _T("请输入座位状态(空闲/已预约/已占用/维护中)"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
Seat* newSeat = createSeat(number, floor, state);
addSeat(seatQueue, newSeat);
saveSeats(seatQueue, SEAT_DATA_FILE);
wchar_t msg[100];
swprintf_s(msg, L"座位 %s 添加成功", number);
MessageBox(NULL, msg, L"成功", MB_OK);
}));
// 删除座位
globalWidget->addButton(2, new Button(300, 220, 200, 50, L"删除座位", []() {
wchar_t number[50];
if (InputBox(number, sizeof(number) / sizeof(wchar_t), _T("请输入要删除的座位编号"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
Seat* seat = findSeatByNumber(seatQueue, number);
if (!seat) {
MessageBox(NULL, _T("未找到该座位"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
wchar_t msg[100];
swprintf_s(msg, L"确定要删除座位 %s 吗?", number);
int confirm = MessageBox(NULL, msg, L"确认删除", MB_YESNO | MB_ICONQUESTION);
if (confirm != IDYES) return;
removeSeat(seatQueue, seat);
saveSeats(seatQueue, SEAT_DATA_FILE);
swprintf_s(msg, L"座位 %s 删除成功", number);
MessageBox(NULL, msg, L"成功", MB_OK);
}));
// 修改座位状态
globalWidget->addButton(2, new Button(300, 290, 200, 50, L"修改座位状态", []() {
wchar_t number[50], state[20];
if (InputBox(number, sizeof(number) / sizeof(wchar_t), _T("请输入要修改的座位编号"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
Seat* seat = findSeatByNumber(seatQueue, number);
if (!seat) {
MessageBox(NULL, _T("未找到该座位"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
if (InputBox(state, sizeof(state) / sizeof(wchar_t), _T("请输入新的座位状态(空闲/已预约/已占用/维护中)"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
updateSeatState(seat, state);
saveSeats(seatQueue, SEAT_DATA_FILE);
wchar_t msg[100];
swprintf_s(msg, L"座位 %s 状态已更新为 %s", number, state);
MessageBox(NULL, msg, L"成功", MB_OK);
}));
// 查看所有座位
globalWidget->addButton(2, new Button(300, 360, 200, 50, L"查看所有座位", []() {
displaySeatListPage(L"所有座位列表",
[](Seat*) { return seatQueue->front; },
[](Seat* current) { return current->next; });
}));
// 退出登录按钮
globalWidget->addButton(2, new Button(300, 430, 200, 50, L"退出登录", []() {
isAdmin = false;
globalWidget->setCurrentIndex(0); // 返回主菜单
}));
// 帮助按钮
globalWidget->addButton(2, new Button(300, 500, 200, 30, L"使用帮助", []() {
MessageBox(NULL,
L"管理员功能使用指南:\n\n"
L"1. 添加座位:添加新的座位信息\n"
L"2. 删除座位:删除不再使用的座位\n"
L"3. 修改座位状态:更新座位状态\n"
L"4. 查看所有座位:浏览当前所有座位信息\n"
L"5. 退出登录:返回主菜单\n\n"
L"提示:所有更改会自动保存",
L"管理员帮助", MB_OK | MB_ICONINFORMATION);
}));
}
// 通用座位列表显示函数
void displaySeatList(Seat* startSeat, const wchar_t* title, int maxCount,
std::function<Seat* (Seat*)> getNextFunc,
bool showReserveButtons) {
// 绘制标题
settextstyle(30, 0, _T("微软雅黑"));
settextcolor(RGB(25, 25, 112));
outtextxy(300, 20, title);
settextstyle(16, 0, _T("微软雅黑"));
settextcolor(BLACK);
int yPos = 80;
outtextxy(100, yPos, _T("座位编号"));
outtextxy(300, yPos, _T("楼层"));
outtextxy(500, yPos, _T("状态"));
if (showReserveButtons) {
outtextxy(600, yPos, _T("操作"));
}
settextstyle(14, 0, _T("微软雅黑"));
yPos += 40;
Seat* seat = startSeat;
int count = 0;
while (seat && count < maxCount) {
outtextxy(100, yPos, seat->number);
wchar_t floorStr[10];
swprintf_s(floorStr, L"%d层", seat->floor);
outtextxy(300, yPos, floorStr);
// 根据座位状态设置不同颜色
if (wcscmp(seat->state, SEAT_AVAILABLE) == 0) {
settextcolor(GREEN);
}
else if (wcscmp(seat->state, SEAT_RESERVED) == 0) {
settextcolor(BLUE);
}
else if (wcscmp(seat->state, SEAT_OCCUPIED) == 0) {
settextcolor(RED);
}
else {
settextcolor(BLACK);
}
outtextxy(500, yPos, seat->state);
settextcolor(BLACK); // 恢复默认颜色
yPos += 30;
count++;
seat = getNextFunc(seat);
}
// 显示统计信息
wchar_t countStr[100];
swprintf_s(countStr, L"显示 %d 个座位", count);
settextstyle(16, 0, _T("微软雅黑"));
outtextxy(300, 450, countStr);
}
// 创建并显示座位列表页面
void displaySeatListPage(const wchar_t* title,
std::function<Seat* (Seat*)> getFirstFunc,
std::function<Seat* (Seat*)> getNextFunc,
bool showReserveButtons) {
// 保存当前页面索引
int prevPage = globalWidget->getCurrentIndex();
// 创建一个新的临时页面用于显示座位
IMAGE* tempPage = new IMAGE(800, 600);
if (_waccess(_T("result_bg.jpg"), 0) != -1) {
loadimage(tempPage, _T("result_bg.jpg"), 800, 600, true);
}
else {
tempPage->Resize(800, 600);
DWORD* pBuf = GetImageBuffer(tempPage);
for (int i = 0; i < 800 * 600; i++) {
pBuf[i] = RGB(240, 248, 255); // 淡蓝色背景
}
}
globalWidget->pages.push_back(tempPage);
int tempPageIndex = static_cast<int>(globalWidget->pages.size() - 1);
globalWidget->buttons.push_back(std::vector<Button*>()); // 添加空按钮列表
globalWidget->setCurrentIndex(tempPageIndex);
// 添加返回按钮
Button* backBtn = new Button(350, 520, 100, 40, L"返回", [prevPage]() {
globalWidget->setCurrentIndex(prevPage);
});
globalWidget->buttons[tempPageIndex].push_back(backBtn);
// 添加预约按钮(如果需要)
if (showReserveButtons && currentUser) {
Seat* seat = getFirstFunc(nullptr);
int yPos = 120; // 起始Y位置
while (seat) {
if (wcscmp(seat->state, SEAT_AVAILABLE) == 0) {
Button* reserveBtn = new Button(600, yPos - 5, 80, 25, L"预约", [seat]() {
handleReserveSeat(currentUser, seat->number); // 传递座位号
});
globalWidget->buttons[tempPageIndex].push_back(reserveBtn);
}
yPos += 30;
seat = getNextFunc(seat);
}
}
// 进入子循环,等待用户点击返回按钮
ExMessage msg;
bool exitLoop = false;
while (!exitLoop) {
if (peekmessage(&msg)) {
if (msg.message == WM_LBUTTONDOWN) {
bool clicked = false;
for (Button* button : globalWidget->buttons[tempPageIndex]) {
if (button->checkClick(msg.x, msg.y)) {
if (button == backBtn) {
exitLoop = true; // 点击返回按钮时退出循环
}
clicked = true;
break;
}
}
}
else if (msg.message == WM_MOUSEMOVE) {
for (Button* button : globalWidget->buttons[tempPageIndex]) {
button->checkMouseOver(msg.x, msg.y);
}
}
}
// 绘制
cleardevice();
putimage(0, 0, tempPage);
// 绘制所有按钮
for (Button* button : globalWidget->buttons[tempPageIndex]) {
button->draw();
}
// 绘制座位列表
displaySeatList(getFirstFunc(nullptr), title, 10, getNextFunc, showReserveButtons);
FlushBatchDraw();
Sleep(10);
}
// 退出子循环后,删除临时页面和按钮
for (Button* button : globalWidget->buttons[tempPageIndex]) {
delete button;
}
globalWidget->buttons.erase(globalWidget->buttons.begin() + tempPageIndex);
delete tempPage;
globalWidget->pages.erase(globalWidget->pages.begin() + tempPageIndex);
}
// 初始化座位查询按钮
void initSeatQueryButtons() {
// 按楼层查询
globalWidget->addButton(3, new Button(300, 150, 200, 50, L"按楼层查询", []() {
wchar_t input[50];
if (InputBox(input, sizeof(input) / sizeof(wchar_t), _T("请输入楼层(1-5)"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
int floor = _wtoi(input);
if (floor <= 0 || floor > 5) {
MessageBox(NULL, _T("楼层输入无效,请输入1-5之间的数字"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
wchar_t title[100];
swprintf_s(title, L"%d楼座位列表", floor);
displaySeatListPage(title,
[floor](Seat*) { return findSeatByFloor(seatQueue, floor, nullptr); },
[floor](Seat* current) { return findSeatByFloor(seatQueue, floor, current); },
true);
}));
// 按编号查询
globalWidget->addButton(3, new Button(300, 220, 200, 50, L"按编号查询", []() {
wchar_t input[50];
if (InputBox(input, sizeof(input) / sizeof(wchar_t), _T("请输入座位编号(例如:A101)"), NULL, NULL, 0, FALSE) <= 0) {
return; // 用户取消
}
Seat* seat = findSeatByNumber(seatQueue, input);
if (!seat) {
MessageBox(NULL, _T("未找到该座位,请检查座位编号是否正确"), _T("提示"), MB_OK);
return;
}
wchar_t info[200];
swprintf_s(info, L"座位信息:\n\n编号: %s\n楼层: %d层\n状态: %s",
seat->number, seat->floor, seat->state);
// 如果是空闲座位且用户已登录,添加预约选项
if (currentUser && wcscmp(seat->state, SEAT_AVAILABLE) == 0) {
wcscat_s(info, L"\n\n是否预约该座位?");
int choice = MessageBox(NULL, info, L"座位信息", MB_YESNO | MB_ICONQUESTION);
if (choice == IDYES) {
handleReserveSeat(currentUser, seat->number); // 传递座位号
}
}
else {
MessageBox(NULL, info, L"座位信息", MB_OK);
}
}));
// 按状态查询
globalWidget->addButton(3, new Button(300, 290, 200, 50, L"按状态查询", []() {
wchar_t states[4][20] = { SEAT_AVAILABLE, SEAT_RESERVED, SEAT_OCCUPIED, SEAT_MAINTAIN };
// 清空屏幕
cleardevice();
IMAGE stateBg;
if (_waccess(_T("state_bg.jpg"), 0) != -1) {
loadimage(&stateBg, _T("state_bg.jpg"), 800, 600, true);
putimage(0, 0, &stateBg);
}
else {
setbkcolor(RGB(240, 248, 255)); // 淡蓝色背景
cleardevice();
}
// 绘制标题
settextstyle(30, 0, _T("微软雅黑"));
settextcolor(RGB(25, 25, 112));
outtextxy(250, 20, _T("按状态查询座位"));
settextstyle(16, 0, _T("微软雅黑"));
settextcolor(BLACK);
outtextxy(300, 100, _T("请选择查询的状态:"));
outtextxy(300, 150, _T("1. 空闲"));
outtextxy(300, 200, _T("2. 已预约"));
outtextxy(300, 250, _T("3. 已占用"));
outtextxy(300, 300, _T("4. 维护中"));
outtextxy(300, 350, _T("5. 返回"));
FlushBatchDraw();
int stateChoice = _getch() - '0';
if (stateChoice < 1 || stateChoice > 4) return;
wchar_t title[100];
swprintf_s(title, L"%s座位列表", states[stateChoice - 1]);
displaySeatListPage(title,
[stateChoice, states](Seat*) {
return findSeatByState(seatQueue, states[stateChoice - 1], nullptr);
},
[stateChoice, states](Seat* current) {
return findSeatByState(seatQueue, states[stateChoice - 1], current);
},
true);
}));
// 随机推荐可用座位
globalWidget->addButton(3, new Button(300, 360, 200, 50, L"随机推荐可用座位", []() {
displayRandomAvailableSeat();
}));
// 返回按钮
globalWidget->addButton(3, new Button(300, 430, 200, 50, L"返回", []() {
if (currentUser) {
globalWidget->setCurrentIndex(1); // 返回用户菜单
}
else {
globalWidget->setCurrentIndex(0); // 返回主菜单
}
}));
// 帮助按钮
globalWidget->addButton(3, new Button(300, 500, 200, 30, L"查询帮助", []() {
MessageBox(NULL,
L"座位查询功能指南:\n\n"
L"1. 按楼层查询:显示指定楼层的座位\n"
L"2. 按编号查询:查找特定编号的座位\n"
L"3. 按状态查询:按座位状态筛选座位\n"
L"4. 随机推荐:系统推荐可用座位\n"
L"5. 返回:返回上一级菜单\n\n"
L"提示:在查询结果中可以直接预约空闲座位",
L"查询帮助", MB_OK | MB_ICONINFORMATION);
}));
}
// 清理资源
void cleanup() {
if (globalWidget) {
globalWidget->close();
delete globalWidget;
globalWidget = nullptr;
}
if (seatQueue) {
destroyQueue(seatQueue);
seatQueue = NULL;
}
// 释放用户链表
User* current = userList;
while (current) {
User* next = current->next;
free(current);
current = next;
}
userList = NULL;
// 停止背景音乐
if (musicPlaying) {
mciSendString(_T("stop bgm"), NULL, 0, NULL);
mciSendString(_T("close bgm"), NULL, 0, NULL);
musicPlaying = 0;
}
}
// 设置工作目录到程序所在位置
void SetWorkingDirectoryToProgramPath() {
wchar_t path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
PathRemoveFileSpecW(path);
SetCurrentDirectoryW(path);
}
// 主函数
int main() {
// 设置工作目录
SetWorkingDirectoryToProgramPath();
// 初始化座位队列
seatQueue = createQueue();
loadSeats(seatQueue, SEAT_DATA_FILE);
// 初始化用户列表
loadUsers(&userList, USER_DATA_FILE);
// 初始化全局控件
initGlobalWidget();
// 设置初始页面
globalWidget->setCurrentIndex(0);
// 播放背景音乐
if (_waccess(_T("background.mp3"), 0) != -1) {
mciSendString(_T("open \"background.mp3\" alias bgm"), NULL, 0, NULL);
mciSendString(_T("play bgm repeat"), NULL, 0, NULL);
musicPlaying = 1;
}
// 运行主循环
globalWidget->run();
// 释放资源
cleanup();
return 0;
}删掉按状态查询功能,还有删去显示全部座位这个功能