系统架构概述
本系统主要包括三类角色和模块:
- 管理员:负责管理食物菜单、查看与修改商品、设置促销折扣等。
- 用户:负责点餐、查询商品、查看订单等。
- 疯狂星期四促销:管理员可以在此活动中修改折扣、添加或删除优惠商品。
1. 用户管理
系统首先提供一个登录界面,用户可以选择通过已有账户登录,或新用户进行注册。登录后,用户根据身份(管理员或普通用户)进入不同的操作界面。
用户注册与登录流程:
- 用户通过输入用户名和密码进行身份验证。
- 注册时,系统会检查用户名是否已被占用,并且验证用户输入的密码是否一致。
1.登录流程
void handleLogin(UserList* userList) {
User u1;
printf("请选择登录身份(1-管理员 2-点餐用户):\n");
int input = -1;
scanf("%d", &input);
printf("请输入您的用户名(注意区分大小写):\n");
scanf("%s", u1.username);
//管理员
if (input == 1)
{
int ret_n = findUser(userList, u1.username, input);
printf("请输入您的密码(注意区分大小写):\n");
scanf("%s", u1.password);
int ret_w = findUser_(userList, u1.password, input, ret_n - 1);
if (!ret_n)
{
printf("登陆失败!该用户未注册!\n");
}
else if (ret_n && (!ret_w))
{
printf("登陆失败!用户名或密码错误!\n");
}
else
{
printf("登陆成功!\n\n");
print_food_admin();
}
}
//点餐用户
if (input == 2)
{
int ret_n = findUser(userList, u1.username, input);
printf("请输入您的密码(注意区分大小写):\n");
scanf("%s", u1.password);
int ret_w = findUser_(userList, u1.password, input, ret_n - 1);
if (!ret_n)
{
printf("登陆失败!该用户未注册!\n");
}
else if (ret_n && (!ret_w))
{
printf("登陆失败!用户名或密码错误!\n");
}
else
{
printf("登陆成功!\n\n");
print_food_user();
}
}
}
2.注册流程
void handleRegistration(UserList* userList) {
User u1;
User u2;
int ret = 0;
int ret_ = 0;
int flag = 1;
int flag_ = 1;
while (1)
{
printf("请选择注册用户的身份(1-管理员 2-点餐用户):\n");
scanf("%d", &ret);
if (ret == 1 || ret == 2)
{
while (flag)
{
printf("请输入新的用户名:\n");
scanf("%s", u1.username);
ret_ = findUser(userList, u1.username, 1) | findUser(userList, u1.username, 0);
if (!ret_)
{
while (1)
{
printf("请输入密码:\n");
scanf("%s", u1.username);
printf("确认密码:\n");
scanf("%s", u2.username);
flag_ = strcmp(u1.password, u2.password);
if (!flag_)
{
u1.isAdmin = ret;
addUser(userList, u1);
printf("注册成功!按ENTER键进入用户登录\n");
break;
}
else
{
printf("密码与确认密码不一致!\n");
}
}
flag = 0;
}
else
{
printf("该用户名已被注册!请重新输入\n");
}
}
break;
}
else
printf("非法输入,请重新输入\n");
}
}
2. 管理员操作
管理员的操作界面提供了一些功能来管理食物菜单、查看所有商品、修改价格、下架商品等。管理员还可以管理“疯狂星期四”促销活动,设置折扣和优惠商品。
管理员操作流程:
- 新品上架:输入商品编号、名称和价格,管理员可以将新的食物添加到菜单。
- 商品下架:管理员可以选择下架不再供应的商品。
- 折扣设置:管理员可以启用疯狂星期四活动,设置折扣并应用到商品上。
1.打印管理员操作菜单
void print_food_admin()
{
int op = 0;
printf("=======================================\n");
printf(" KFC肯德基管理系统\n");
printf("=======================================\n\n");
printf("1. 新品上架\n");
printf("2. 商品下架\n");
printf("3. 疯狂星期四\n");
printf("4. 查看所有商品\n");
printf("5. 商品价格修改\n");
printf("6. 查找商品\n");
printf("0. 返回,重新登陆\n\n");
printf("请选择需要的服务:\n");
scanf("%d", &op);
food_admin(op);
}
2.管理员操作处理
void food_admin(int ret)
{
int flag = 1;
int op = 0;
FoodItem item;
switch (ret)
{
case 1:
while (flag)
{
printf("请输入商品编号:\n");
scanf("%d", &item.id);
if (findFoodItem(foodList, item.id))
{
printf("商品编号重复,请重新输入\n");
}
else
{
while (flag)
{
printf("请输入商品名称:\n");
scanf("%s", item.name);
if (findFoodItem_(foodList, item.name))
{
printf("商品名称重复,请重新输入\n");
}
else
{
while (flag)
{
printf("请输入商品价格:\n");
scanf("%f", &item.price);
if (item.price <= 0)
{
printf("商品价格必须大于0,请重新输入\n");
}
else
{
addFoodItem(foodList, item);
flag = 0;
}
}
}
}
}
}
print_food_admin();
break;
case 2:
printf("请输入商品编号:\n");
scanf("%d", &item.id);
if (!findFoodItem(foodList, item.id)) printf("下架失败!该商品不存在或已下架!\n");
else
{
int index = findFoodItem(foodList, item.id) - 1; // 假设findFoodItem函数返回数组中的位置
printf("您将要下架的是:\n");
printf("商品编号:%d\n", foodList->items[index].id);
printf("商品名称:%s\n", foodList->items[index].name);
printf("价格:%.2f\n", foodList->items[index].price);
printf("是否确认下架?(1. 确认 2.取消)\n");
scanf("%d", &op);
if (op)
{
deleteFoodItem(foodList, item.id);
printf("下架成功!\n");
}
else
printf("下架取消!\n");
print_food_admin();
}
break;
case 3:
print_food_admin_crazy();
break;
case 4:
writeFoodListToFile(foodList, "foodlist.txt");
printf("商品编号 商品名称 商品价格\n");
for (int i = 0; i < foodList->size; i++) {
printf("%d %s %.2f\n",
foodList->items[i].id,
foodList->items[i].name,
foodList->items[i].price);
}
print_food_admin();
break;
case 5:
printf("请输入商品编号:\n");
scanf("%d", &item.id);
if (findFoodItem(foodList, item.id))
{
printf("请输入修改价格:\n");
scanf("%f", &foodList->items[findFoodItem(foodList, item.id) - 1].price);
writeFoodListToFile(foodList, "foodlist.txt");
int index = findFoodItem(foodList, item.id) - 1;
printf("修改成功!修改后该商品信息如下:\n");
printf("商品编号 商品名称 商品价格\n");
printf("%d %s %.2f\n",
foodList->items[index].id,
foodList->items[index].name,
foodList->items[index].price);
}
else printf("该商品不存在!\n");
print_food_admin();
break;
case 6:
printf("请输入要查找的商品编号:\n");
scanf("%d", &item.id);
if (findFoodItem(foodList, item.id))
{
int index = findFoodItem(foodList, item.id) - 1; // 假设findFoodItem函数返回数组中的位置
printf("商品编号 商品名称 商品价格\n");
printf("%d %s %.2f\n",
foodList->items[index].id,
foodList->items[index].name,
foodList->items[index].price);
}
else printf("该商品不存在!\n");
print_food_admin();
break;
case 0:
print_login_ident();
break;
}
}
3. 疯狂星期四促销活动
疯狂星期四是一个特殊的促销活动,管理员可以在该活动期间设置折扣、查看折扣商品,甚至添加或删除优惠商品。此部分功能通过flag_crazy
和discount
变量来控制促销的开关与折扣比例。
疯狂星期四管理:
- 开启/关闭:管理员可以启用或关闭该活动。
- 设置折扣:管理员可以设置不同的折扣值,例如 8 折、7 折等。
- 优惠商品管理:管理员可以选择哪些商品参与到此次促销中,或者从优惠商品列表中删除商品。
1.打印疯狂星期四操作页面
void print_food_admin_crazy() //管理员操作界面-疯狂星期四
{
printf("=======================================\n");
printf(" KFC肯德基管理系统-疯狂星期四\n");
printf("=======================================\n\n");
printf("1. 修改疯狂星期四状态\n");
printf("2. 修改折扣\n");
printf("3. 添加优惠商品\n");
printf("4. 删除优惠商品\n");
printf("5. 查看疯狂星期四详情\n");
printf("0. 返回管理员操作界面\n\n");
printf("请选择需要的服务:\n");
int op = 0;
scanf("%d", &op);
food_admin_crazy(op);
}
2.疯狂星期四操作处理
void food_admin_crazy(int ret)
{
FoodItem item;
switch (ret)
{
case 1:
printf("请选择疯狂星期四状态(1.开启 0.关闭):\n");
scanf("%d", &flag_crazy);
print_food_admin_crazy();
break;
case 2:
printf("请输入优惠折扣(例:八折输入0.8):\n");
scanf("%f", &discount);
print_food_admin_crazy();
break;
case 3:
printf("请选择需要优惠的商品:\n");
printf("请输入商品编号:\n");
scanf("%d", &item.id);
if (findFoodItem(foodList, item.id))
{
discout_admin_add(dis_arr, item.id);
printf("添加成功!\n");
}
else printf("商品不存在!\n");
print_food_admin_crazy();
break;
case 4:
printf("请选择需要取消优惠的商品:\n");
printf("请输入商品编号:\n");
scanf("%d", &item.id);
if (findFoodItem(foodList, item.id))
{
discout_admin_dele(dis_arr, item.id);
printf("删除成功!\n");
}
else printf("商品不存在!\n");
print_food_admin_crazy();
break;
case 5:
printf("当前疯狂星期四状态为:\n%d", flag_crazy);
printf("当前折扣为:\n%f", discount);
printf("\n当前优惠商品信息,以及折扣价格如下:\n");
printf("商品编号 商品名称 折扣价格\n");
for (int i = 0; i < foodList->size; i++)
{
printf("%d %s %.2f\n",
foodList->items[i].id,
foodList->items[i].name,
foodList->items[i].price * discount);
}
print_food_admin_crazy();
break;
case 0:
print_food_admin();
}
}
4. 用户点餐
用户在登录后,可以进入点餐界面。用户可以按编号顺序查看菜单、按价格排序查看商品、或者通过商品编号直接查找商品。用户还可以查看已点商品,修改订单,或者进行支付。
用户操作流程:
- 查看菜单:用户可以查看所有菜品,或者按价格、编号进行排序。
- 加菜与退菜:用户可以将选中的菜品添加到订单中,或者退掉已选菜品。
- 确认支付:用户可以查看订单的总价并进行支付。
1.打印用户点餐界面
void print_food_user() //用户点餐界面 (其他:储值消费)
{
printf("=======================================\n");
printf(" KFC肯德基点餐\n");
printf("=======================================\n\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\n");
printf("请选择需要的服务:\n");
int op = 0;
scanf("%d", &op);
food_user(op);
}
2.用户操作处理
void food_user(int ret)
{
FoodItem item;
MenuItem item_;
switch (ret)
{
case 1:
printf("商品编号 商品名称 商品价格\n");
printFoodItemsById(&foodList);
print_food_user();
break;
case 2:
printf("商品编号 商品名称 商品价格\n");
printFoodItemsByPrice(&foodList);
print_food_user();
break;
case 3:
printf("请输入需要查找的商品编号:\n");
scanf("%d", &item.id);
if (-1 != findItemById(*foodList, item.id))
{
int index = findItemById(*foodList, item.id); // 假设findItemById函数返回数组中的位置
printf("已为您找到该菜品!\n");
printf("商品编号 商品名称 商品价格\n");
printf("%d %s %.2f\n",
foodList->items[index].id,
foodList->items[index].name,
foodList->items[index].price);
}
else
printf("未能找到该菜品!商品编号不存在!\n");
print_food_user();
break;
case 4:
printf("请输入的商品编号进行加菜:\n");
scanf("%d", &item.id);
if (-1 != findItemById(*foodList, item.id))
{
item_.foodId = findItemById(*foodList, item.id);
strcpy(item_.foodName, foodList->items[findFoodItem(foodList, findItemById(*foodList, item.id)) - 1].name);
item_.discountPrice = foodList->items[findFoodItem(foodList, findItemById(*foodList, item.id)) - 1].price * discount;
addMenuItem(menuList, item_);
printf("已成功添加该菜品!\n");
}
else
printf("未能添加该菜品!商品编号不存在!\n");
print_food_user();
break;
case 5:
printf("请输入的商品编号进行退菜:\n");
scanf("%d", &item_.foodId);
if (findMenuItem(menuList, item_.foodId))
{
deleteMenuItem(menuList, item_.foodId);
printf("已成功删除该菜品!\n");
int index = findFoodItem(foodList, item_.foodId) - 1; // 假设findFoodItem函数返回数组中的位置
printf("商品编号 商品名称 商品价格\n");
printf("%d %s %.2f\n",
foodList->items[index].id,
foodList->items[index].name,
foodList->items[index].price);
}
else
printf("未能删除该菜品!商品编号不存在于菜品订单中!\n");
print_food_user();
break;
case 6:
printf("您已选购的订单,请过目:\n");
printf("商品编号 商品名称 商品价格\n");
printMenuItem(menuList);
printf("共计:%.2f 元\n", printMenuItem_price(menuList));
print_food_user();
break;
case 7:
printf("本次共计 %.2f 元,感谢您的惠顾!欢迎下次光临!\n", printMenuItem_price(menuList));
menuList->size = 0;
print_food_user();
break;
case 0:
break;
}
}
5. 数据存储与管理
系统通过文件读取和写入的方式存储菜单和用户信息。每次修改菜单或者用户信息后,系统都会将更新的数据保存到文件中,保证数据的持久性。
- 菜单数据存储:食物列表保存在
foodlist.txt
文件中。 - 用户数据存储:用户信息通过文件加载和保存。
1.保存食物列表到文件
void writeFoodListToFile(const FoodList* list, const char* filename) {
FILE* file = fopen(filename, "w");
if (file == NULL) {
return;
}
for (int i = 0; i < list->size; i++) {
fprintf(file, "%d,%s,%.2f\n", list->items[i].id, list->items[i].name, list->items[i].price);
}
fclose(file);
}
2.从文件加载食物列表
void readFoodListFromFile(FoodList* list, const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
return;
}
list->size = 0;
list->capacity = 10; // 初始容量,可以根据需要调整
list->items = (FoodItem*)malloc(list->capacity * sizeof(FoodItem));
char line[120];
while (fgets(line, sizeof(line), file)) {
if (list->size >= list->capacity) {
list->capacity *= 2;
list->items = (FoodItem*)realloc(list->items, list->capacity * sizeof(FoodItem));
}
FoodItem item;
sscanf(line, "%d,%99[^,],%f", &item.id, item.name, &item.price);
list->items[list->size++] = item;
}
}
6. 排序功能
用户可以选择按商品编号或价格查看菜单。为了实现这个功能,我们实现了基于冒泡排序的排序算法:
按编号排序:通过 bubbleSortById()
函数按商品编号排序。
void bubbleSortById(FoodList* foodList) {
int n = foodList->size;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (foodList->items[j].id > foodList->items[j + 1].id) {
swapFoodItems(&foodList->items[j], &foodList->items[j + 1]);
}
}
}
}
按价格排序:通过 bubbleSortByPrice()
函数按商品价格排序。
void bubbleSortByPrice(FoodList* foodList) {
int n = foodList->size;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (foodList->items[j].price > foodList->items[j + 1].price) {
swapFoodItems(&foodList->items[j], &foodList->items[j + 1]);
}
}
}
}
7. 总结
通过模块化的设计,KFC 点餐系统提供了管理员和用户两个角色的操作界面,以及一些常用的餐饮管理功能,包括菜单管理、商品折扣设置、订单处理等。此外,系统通过文件存储保证了数据的持久性,并通过简单的排序算法提升了用户的点餐体验。这种设计不仅适合餐饮行业的管理需求,也为后续系统的扩展提供了很好的基础。例如,可以通过添加更多的支付方式、配送选项,或者优化系统性能,来进一步提升用户体验。