diff --git a/Car.py b/Car.py index a309d38..b892b3f 100644 --- a/Car.py +++ b/Car.py @@ -1,534 +1,19 @@ -from enum import Enum -import time -import re -import os -import logging +class Car: + def __init__(self, license_plate, model, color): -Model = Enum('Model', ("小汽车", "小卡", "中卡", "大卡")) -Color = Enum('Color', ("白色", "黑色", "灰色", "蓝色", "红色", "黄色")) -unit_price = 5 # 每小时单价为5元 - - -class Car(object): # ParkManage - def __init__(self, parknum, carnum, model, color, intime=None): - # super(Car, self).__init__() - self.parknum = parknum - self.carnum = carnum + self.license_plate = license_plate self.model = model self.color = color - self.intime = intime - - def __setitem__(self, key, value): - self.__dict__[key] = value - - def __getitem__(self, key): - return self.__dict__[key] def __str__(self): - return "%4s %-8s %-6s %-s %s" % \ - (self.parknum, self.carnum, self.model.name, self.color.name, self.intime) - - -class ParkManage(object): - def __init__(self, max_car=150): - self.max_car = max_car - self.carlist = [] - # self.carnum = len(self.carlist) - - def check_empty(self, model=1): - """ - 查找空闲车位,model=1默认按小汽车查找 - :return:{list}空闲车位号列表 - """ - if model == 1: - # t_num = [parkedCar["parknum"] for parkedCar in self.carlist] - """ - t_list = [] - for i in range(self.max_car): - if i not in t_num: - t_list.append(i) - return t_list - """ - # return [i for i in range(self.max_car) if i not in t_num] - return [i for i in range(self.max_car) if i not in - [parkedCar["parknum"] for parkedCar in self.carlist]] - - def inquire_empty(self): - """ - 查询空闲车位,调用即可进行输出。 - :return: None - """ - t_i = 0 - for t_empty in self.check_empty(): - print("%3s " % t_empty, end='') - t_i += 1 - if len(self.check_empty()) > 15 and t_i % 15 == 0: # 每15个一行 - print('') - - def check_car_num(self, carnum): - """ - 基于正则表达式判断车牌号是否合法,合法为True - :return:{bool}True/False - """ - # return True # TODO DEBUG - car_license = re.compile(u"^[\u4e00-\u9fa5][A-Z][A-Z0-9]{5}$") # e.g.: 苏BCD123 - if car_license.match(carnum): - return True - else: - return False - - def park(self, isAdmin): - """ - 输入车辆信息,停车。管理员isAdmin==1时询问是否继续停车。 - :return:None - """ - if len(self.carlist) >= self.max_car: - print("对不起,当前车库已满!") - return None - while True: - print('当前空闲车位如下:') - self.inquire_empty() - print('') - - # 变量初始化 - flag_right_input = False - flag_error = 0 # 清除错误flag - temp_parknum = None - temp_carnum = None - temp_color = None - temp_model = None - try: - temp_parknum = int(input('请输入所停车位:')) - temp_carnum = input('请输入车牌号:') - temp_model = int(input('请输入车型序号(1小汽车, 2小卡, 3中卡, 4大卡):')) - temp_color = int(input('请输入车辆颜色序号(1白色, 2黑色, 3灰色, 4蓝色, 5红色, 6黄色):')) - - # 以下为输入信息是否有效的判断 - if 0 <= temp_parknum <= self.max_car: # 判断车位是否在合理范围内 - if 1 <= temp_model <= 4: - temp_model = Model(temp_model) # 转化为Model枚举类型 - if 1 <= temp_color <= 6: - temp_color = Color(temp_color) # 转化Color枚举类型 - if self.check_car_num(temp_carnum): # 判断车牌号是否有效 - for parkedCar in self.carlist: - if parkedCar.parknum == temp_parknum: # 判断车位是否已被占用 - flag_error = 1 - break - elif parkedCar.carnum == temp_carnum: # 判断车牌是否已重复 - flag_error = 2 - break - else: - flag_right_input = True # 以上判断均通过 - """ - else: - error_input = 3 - else: - error_input = 4 - else: - error_input = 5 - """ - - except Exception as e: - # logging.exception(e) # for debug - flag_right_input = False # 输入类型错误 - # error_input = 6 - finally: - # if error_input != 0: - if not flag_right_input: - if flag_error == 1: - print('当前车位已被占用!') - elif flag_error == 2: - print('车牌号重复!') - else: - print("输入错误!") - retry_choice = input('按键返回主菜单,按其他任意键重试') - if retry_choice == 'F' or retry_choice == 'f': - return None # 返回主菜单 - else: - os.system('cls') # 清屏 - else: - # 通过各项判断,下面新增车辆 - temp_car = Car(temp_parknum, temp_carnum, temp_model, temp_color) - temp_car["intime"] = time.ctime() # 调用当前时间 - self.carlist.append(temp_car) - print("%s 停车入库成功!" % temp_carnum) - - if not isAdmin: # 用户返回主菜单 - print('按任意键返回主菜单......') - os.system("pause") - return None - if isAdmin: # 管理员询问是否继续新增车辆 - while True: - continue_choice = input("是(Y)否(N)继续新增车辆?") - if continue_choice == 'Y' or continue_choice == 'y': - os.system('cls') # 清屏 - break - elif continue_choice == 'N' or continue_choice == 'n': - return None - else: - print('输入错误,请重试!') - - """ - def add_car(self, car): - # 从car新增车辆到carlist中 - # if self.check_car(car) is not None: - # print("车辆已存在,请重试!") - # else: - car["intime"] = time.ctime() # 调用当前时间 - self.carlist.append(car) - print("%s 停车入库成功!" % car.carnum) - """ - - def display(self, carlist=None): - """ - 显示车辆信息 - :param:{list}carlist, 默认为self.carlist - :return:None - """ - if carlist is None: - carlist = self.carlist - if len(self.carlist) == 0: - print("停车场内暂无车辆。") - return None - - print("车位 车牌号 车型 颜色 入场时间 ") - i = 0 - for parkedCar in carlist: - print(parkedCar) - i += 1 - if len(carlist) > 10 and i % 10 == 0: # 超过10辆车则每10辆一页 - print("按任意键查看下一页......") - os.system("pause") - print("车位 车牌号 车型 颜色 入场时间 ") - # os.system('pause') - - def check_car(self, keyword, sort=1): - """ - 用于查找车辆。默认sort=1,按照车位查找,若存在则返回满足条件的车辆信息。 - :param:keyword关键词,sort查找方式 - :return:{class Car}/{list} - """ - if sort == 1: # 按车位 - for parkedCar in self.carlist: - if parkedCar.parknum == keyword: - return parkedCar - elif sort == 2: # 按车牌 - for parkedCar in self.carlist: - if parkedCar.carnum == keyword: - return parkedCar - elif 3 <= sort <= 4: - if sort == 3: # 按车型 - key = "model" - elif sort == 4: # 按颜色 - key = "color" - else: - return None - t_list = [] - for parkedCar in self.carlist: - if parkedCar[key] == keyword: - t_list.append(parkedCar) - return t_list - elif sort == 5: # TODO 按入场时间 - # (developing) - pass - else: - return None - - def inquire(self, choice=-1): - """ - 查询信息 - 复用于取车的查找,修改信息的查找。 - Developing:按照入场时间查询(多少时间内)。 - :param choice:查询方式选择,默认为-1. - :return:None/{class Car}parkedCar - """ - # choice = -1 # DEBUG - while choice < 0 or choice > 6: - print(""" - 1)空闲车位查询 - --车辆信息查询-- - 2)按车位查询车辆 - 3)按车牌查询车辆 - 4)按车型查询车辆 - 5)按颜色查询车辆 - 6)按入场时间查询(developing) - --------------------------- - 0)返回主菜单 - """) - try: - choice = int(input("请输入操作码:")) - except Exception: - print("错误操作码,请重试!") - continue - if choice < 0 or choice > 6: - print("错误操作码,请重试!") - - if choice == 0: - return None # 返回主菜单 - # 空闲车位查询: - elif choice == 1: - if len(self.carlist) >= self.max_car: - print("对不起,当前车库已满!") - return None - else: - print('空闲车位如下:') - self.inquire_empty() - print('') # 多空一行 - else: - if len(self.carlist) == 0: - print("停车场内暂无车辆。") - return None - try: - # 按车位查询车辆: - if choice == 2: - keyword = int(input("请输入车位号:")) - t_result = self.check_car(keyword, sort=1) - if t_result: - print("车位 车牌号 车型 颜色 入场时间 ") - print(t_result) - return t_result - else: - print("停车场中无此车辆。") - - # 按车牌查询车辆: - elif choice == 3: - keyword = input("请输入车牌号:") - t_result = self.check_car(keyword, sort=2) - if t_result: - print("车位 车牌号 车型 颜色 入场时间 ") - print(t_result) - return t_result - else: - print("停车场中无此车辆。") - - # 按车型查询车辆: - elif choice == 4: - keyword = Model(int(input("请输入车辆的车型(1小汽车, 2小卡, 3中卡, 4大卡):"))) - t_result = self.check_car(keyword, sort=3) - if t_result: - self.display(t_result) - else: - print("停车场中无此车型车辆。") - - # 按颜色查询车辆: - elif choice == 5: - keyword = Color(int(input("请输入车辆的颜色(1白色, 2黑色, 3灰色, 4蓝色, 5红色, 6黄色):"))) - t_result = self.check_car(keyword, sort=4) - if t_result: - self.display(t_result) - else: - print("停车场中无此颜色车辆。") - - # 按入场时间查询: - elif choice == 6: - # TODO (developing) 按入场时间查询 - pass - """ - keyword = input("请输入入场时间:") - t_result = self.check_car(keyword, sort=5) - if t_result: - print(t_result) - else: - print("停车场中无此车辆。") - """ - else: - pass - except Exception as e: # 输入异常处理 - # logging.exception(e) # DEBUG - print("输入错误,按任意键返回......") - return None - - def pickup(self): - """ - 取车 - :return:None - """ - if len(self.carlist) == 0: - print("停车场内暂无车辆。") - return None - # 变量初始化 - exit_car = None - inquire_choice = -1 - while inquire_choice < 0 or inquire_choice > 2: - try: - print("-----------取车-----------") - inquire_choice = int(input("1)按车位查找\n2)按车牌号查找\n0)返回主菜单\n\n请输入操作码:")) - except: - continue - if inquire_choice == 0: # 返回主菜单 - return None - elif inquire_choice == 1: # 按车位 - exit_car = self.inquire(choice=2) - elif inquire_choice == 2: # 按车牌号 - exit_car = self.inquire(choice=3) - if exit_car is None: - return None - exit_choice = input("确定请输入“Y”,其他任意输入返回主菜单:") - if exit_choice == 'Y' or exit_choice == 'y': - exit_time = time.ctime() - park_time = time.mktime(time.strptime(exit_time)) - time.mktime(time.strptime(exit_car.intime)) - m, s = divmod(park_time, 60) - h, m = divmod(m, 60) - str_time = "%02d:%02d:%02d" % (h, m, s) # 得到时分秒字符串 - global unit_price - price = h * unit_price - print("车牌号:%s \n停车时长:%s\n请交费%3d元 " % (exit_car.carnum, str_time, price)) - self.carlist.remove(exit_car) - os.system("pause") # 预留之后完善计费功能 - print("结算成功,欢迎您再次光临!") - else: - return None - - def edit(self): - """ - 编辑车辆信息 - :return:None - """ - if len(self.carlist) == 0: - print("停车场内暂无车辆。") - return None - - # 变量初始化 - edit_car = None - inquire_choice = -1 - while inquire_choice < 0 or inquire_choice > 2: - try: - print("-----车辆信息编辑-----") - inquire_choice = int(input("1)按车位查找\n2)按车牌号查找\n0)返回主菜单\n\n请输入操作码:")) - except: - continue - if inquire_choice == 0: # 返回主菜单 - return None - elif inquire_choice == 1: # 按车位 - edit_car = self.inquire(choice=2) - elif inquire_choice == 2: # 按车牌号 - edit_car = self.inquire(choice=3) - if edit_car is None: - return None - edit_choice = input("确定请输入“Y”,其他任意输入返回主菜单:") - if edit_choice == 'Y' or edit_choice == 'y': - index = self.carlist.index(edit_car) # 获取索引 - while True: - try: - flag_right = False # right flag - change_choice = input( - "\n1)车位号\n2)车牌号\n3)车型\n4)车颜色\n5)入场时间\n0)不修改返回主菜单\n\n请输入您要修改的信息序号:") - if change_choice == '0': - return None - elif change_choice == '1': - new_info = int(input("请输入新的车位号:")) - if 0 <= new_info <= self.max_car: # 在范围内 - for parkedCar in self.carlist: - if parkedCar.parknum == new_info: # 判断车位是否已被占用 - print(" %d号车位已被占用!" % new_info) - break - else: - self.carlist[index]["parknum"] = new_info - flag_right = True - print("车位号修改成功!") - # break - elif change_choice == '2': - new_info = input("请输入新的车牌号:") - if self.check_car_num(new_info): # 判断车牌号是否有效 - for parkedCar in self.carlist: - if parkedCar.carnum == new_info: # 判断车牌是否已重复 - print("车牌号重复!") - break - else: - self.carlist[index]["carnum"] = new_info - flag_right = True - print("车牌号修改成功!") - # break - elif change_choice == '3': - new_info = int(input("请输入新的车型(1小汽车, 2小卡, 3中卡, 4大卡):")) - if 1 <= new_info <= 4: - new_info = Model(new_info) # 转化为Model枚举类型 - self.carlist[index]["model"] = new_info - flag_right = True - print("车型修改成功!") - elif change_choice == '4': - new_info = int(input("请输入新的车颜色(1白色, 2黑色, 3灰色, 4蓝色, 5红色, 6黄色):")) - if 1 <= new_info <= 6: - new_info = Color(new_info) # 转化Color枚举类型 - self.carlist[index]["color"] = new_info - flag_right = True - print("颜色修改成功!") - elif change_choice == '5': - new_info = input("请输入新的入场时间:(参考格式:2019.3.4 12:00:00)") - print("DEVELOPING...") - # TODO 修改入场时间 - pass - break - else: - pass - except: - print("输入错误,请重试!") - continue - - if flag_right: - break - else: - print("请重试!") - continue - else: - return None - - def statistics(self): - """ - 统计车辆信息 - :return:None - """ - print(""" - 本停车场总车位数:{total:3d} - 当前已驶入车辆数:{exist:3d} 空闲车位数:{empty:3d} - ----------------------------------------------- - """.format(total=self.max_car, exist=len(self.carlist), empty=self.max_car - len(self.carlist)), - end='') - - # 按车型、颜色统计车辆信息 - cnt_model = [0, 0, 0, 0] - cnt_color = [0, 0, 0, 0, 0, 0] - if len(self.carlist) != 0: - for parkedCar in self.carlist: - cnt_model[parkedCar.model.value - 1] += 1 - cnt_color[parkedCar.color.value - 1] += 1 - print(""" - * 按车型统计: - 小汽车 {:3d}, 小卡 {:3d}, 中卡 {:3d}, 大卡 {:3d} - - * 按颜色统计: - 白色 {:3d}, 黑色 {:3d}, 灰色 {:3d} - 蓝色 {:3d}, 红色 {:3d}, 黄色 {:3d} - """.format(cnt_model[0], cnt_model[1], cnt_model[2], cnt_model[3], - cnt_color[0], cnt_color[1], cnt_color[2], - cnt_color[3], cnt_color[4], cnt_color[5], ), end='') - - if len(self.carlist) == 0: - print(""" - ----------------------------------------------- - """) - else: - # TODO 按入场时间统计 - print(""" - * 按入场时间统计: - (正在开发中 Developing...) - - -----------------------------------------------""") + """返回车辆的字符串表示""" + return f"车牌号: {self.license_plate}, 车型: {self.model}, 颜色: {self.color}" - # TODO 车辆信息按顺序输出 + def update_info(self, license_plate=None, model=None, color=None): - # choice = input(""" - # 1)按车位排序 2)按入场时间排序 - # 请输入操作码(其他任意输入返回主菜单):""") - # if choice == '1': - # pass - # temp_carlist = [] - # for parkedCar in self.carlist: - # pass - # - # self.display(temp_carlist) - # elif choice == '2': - # pass - # else: - # return None - # \ No newline at end of file + if license_plate is not None: + self.license_plate = license_plate + if model is not None: + self.model = model + if color is not None: + self.color = color \ No newline at end of file diff --git a/GUI.py b/GUI.py deleted file mode 100644 index 395c303..0000000 --- a/GUI.py +++ /dev/null @@ -1,2 +0,0 @@ -import tkinter as tk -import tkinter.messagebox \ No newline at end of file diff --git a/IO.py b/IO.py deleted file mode 100644 index c80c4f2..0000000 --- a/IO.py +++ /dev/null @@ -1,78 +0,0 @@ -import multiprocessing as mp -from Car import Car, Model, Color - - -def load_from_file(park, filename=r"cars.csv"): - """ - 从文件中读取车辆信息。 - :param park:停车场实例 - :param filename:文件名 - :return: {class ParkManage}park, {int}cnt:导入成功计数 - """ - cnt = 0 # counter - try: - with open(filename, 'r+') as fp: - - while True: - temp_car = fp.readline() - if temp_car == '': - break - else: - items = list(temp_car.strip().split(',')) - car = Car(int(items[0]), items[1], Model(int(items[2])), Color(int(items[3])), items[4]) - park.carlist.append(car) - cnt += 1 - except Exception: - print('File loaded error!') - return park, cnt - - -def load_new_file(park): - """ - 从新文件中加载记录,成功返回加载后的park,否则返回原来的park - 注意:此处暂未考虑重复记录及记录的有效性! - :param park:停车场实例 - :return: {class ParkManage}park - """ - filename = input('请输入导入的文件名(请勿重复导入):') - if filename == '': - print('文件名不能为空!') - return park - elif filename == 'cars.csv': - print('请勿导入重复文件!') - return park - else: - temp_park, cnt_success = load_from_file(park=park, filename=filename) - if cnt_success > 0: - print('成功导入 %d 条记录。' % cnt_success) - return temp_park - else: - print('导入失败!') - return park - - -def write_to_file(park, filename=r"cars.csv"): - """ - 将车辆信息写入文件。 - :param park:停车场实例 - :param filename:文件名 - :return: None - """ - try: - with open(filename, 'w+') as file: - if len(park.carlist) == 0: - pass - for parkedCar in park.carlist: - file.write('{},{},{},{},{}\n'.format(parkedCar.parknum, parkedCar.carnum, parkedCar.model.value, - parkedCar.color.value, parkedCar.intime)) - except Exception: - print('File wrote error!') - - -def realtimeIO(): - """ - TODO 实时读写文件 - 思路:子进程每隔一段时间检查一次self.carlist,发现改动则更新文件。 - :return: None - """ - pass \ No newline at end of file diff --git a/Member.py b/Member.py deleted file mode 100644 index b3025ed..0000000 --- a/Member.py +++ /dev/null @@ -1,21 +0,0 @@ -class Member: - def __init__(self, member_id, name, license_plate, points): - self.member_id = member_id - self.name = name - self.license_plate = license_plate - self.points = points - - def add_points(self, points): - self.points += points - # 更新数据库中的会员积分 - # ... - - def redeem_points(self, points_to_redeem): - if points_to_redeem <= self.points: - self.points -= points_to_redeem - # 更新数据库中的会员积分 - # ... - return True - else: - print("Insufficient points.") - return False \ No newline at end of file diff --git a/ParkManage.py b/ParkManage.py new file mode 100644 index 0000000..7410dd3 --- /dev/null +++ b/ParkManage.py @@ -0,0 +1,201 @@ +import mysql.connector +from mysql.connector import Error +from tkinter import messagebox +from Car import Car + +class ParkManage: + def __init__(self, host="localhost", user="root", password="root", database="sys", user_gui=None): + """初始化数据库连接""" + self.conn = mysql.connector.connect( + host="localhost", + user="root", + password="root", + database="sys" + ) + self.cursor = self.conn.cursor() + self.create_tables() + self.user_gui = user_gui # 添加一个可选参数用于Tkinter根窗口 + + def create_tables(self): + """创建必要的数据库表""" + try: + self.cursor.execute(""" + CREATE TABLE IF NOT EXISTS parked_cars ( + id INT AUTO_INCREMENT PRIMARY KEY, + license_plate VARCHAR(255) NOT NULL UNIQUE, + parked_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + picked_up_time TIMESTAMP NULL + ); + """) + self.conn.commit() + except Error as e: + messagebox.showerror("数据库错误", f"创建表失败: {e}") + + def park(self, license_plate): + """处理停车逻辑并存储到数据库""" + try: + query = "INSERT INTO parked_cars (license_plate) VALUES (%s)" + values = (license_plate,) + self.cursor.execute(query, values) + self.conn.commit() + return True + except mysql.connector.IntegrityError: # 车牌号已存在 + return False + except Error as e: + messagebox.showerror("数据库错误", f"停车操作时发生错误: {e}") + return False + + def pickup(self, license_plate): + """处理取车逻辑,更新数据库记录""" + try: + # 更新取车时间 + query = "UPDATE parked_cars SET picked_up_time = CURRENT_TIMESTAMP WHERE license_plate = %s AND picked_up_time IS NULL" + values = (license_plate,) + self.cursor.execute(query, values) + if self.cursor.rowcount > 0: + self.conn.commit() + return True + else: + messagebox.showinfo("取车失败", f"车牌号{license_plate}的车辆未找到或已取走。") + return False + except Error as e: + messagebox.showerror("数据库错误", f"取车操作时发生错误: {e}") + return False + + # 其他方法如查询、编辑、统计等可以根据需要类似地实现 + def query_car_info(self, license_plate): + """根据车牌号查询车辆停放信息""" + try: + query = """ + SELECT + license_plate, + parked_time, + picked_up_time + FROM + parked_cars + WHERE + license_plate = %s + """ + values = (license_plate,) + self.cursor.execute(query, values) + car_info = self.cursor.fetchone() + + if car_info: + # 格式化输出信息 + parked_time_str = car_info[1].strftime('%Y-%m-%d %H:%M:%S') + picked_up_time_str = "尚未取车" if car_info[2] is None else car_info[2].strftime('%Y-%m-%d %H:%M:%S') + message = f"车牌号: {car_info[0]}\n停放时间: {parked_time_str}\n取车时间: {picked_up_time_str}" + messagebox.showinfo("车辆信息", message) + else: + messagebox.showinfo("查询结果", "未找到该车牌号的车辆信息。") + except Error as e: + messagebox.showerror("查询错误", f"查询车辆信息时发生错误: {e}") + + def display_all_cars_info(self): + """显示所有车辆的停放信息""" + try: + query = """ + SELECT + license_plate, + parked_time, + picked_up_time + FROM + parked_cars + """ + self.cursor.execute(query) + all_cars_info = self.cursor.fetchall() + + if all_cars_info: + # 遍历所有车辆信息并格式化输出 + all_cars_message = "\n\n".join([ + f"车牌号: {car[0]}\n" + f"停放时间: {car[1].strftime('%Y-%m-%d %H:%M:%S')}\n" + f"取车时间: {'未取车' if car[2] is None else car[2].strftime('%Y-%m-%d %H:%M:%S')}" + for car in all_cars_info + ]) + messagebox.showinfo("所有车辆信息", all_cars_message) + else: + messagebox.showinfo("信息提示", "当前停车场内没有车辆信息。") + except Error as e: + messagebox.showerror("显示错误", f"显示所有车辆信息时发生错误: {e}") + + def edit_car_pickup_time(self, license_plate): + """编辑车辆的取车时间""" + try: + # 查询指定车牌号的车辆是否存在 + check_query = """ + SELECT COUNT(*) + FROM parked_cars + WHERE license_plate = %s + """ + self.cursor.execute(check_query, (license_plate,)) + car_exists = self.cursor.fetchone()[0] + + if car_exists: + # 弹出对话框让用户输入新的取车时间 + new_picked_up_time_str = simpledialog.askstring("编辑取车时间", + "请输入新的取车时间(YYYY-MM-DD HH:MM:SS):", + initialvalue="2023-04-01 14:00:00") + if new_picked_up_time_str: + try: + # 尝试将输入的字符串转换为datetime对象 + from datetime import datetime + new_picked_up_time = datetime.strptime(new_picked_up_time_str, '%Y-%m-%d %H:%M:%S') + except ValueError: + messagebox.showerror("输入错误", "请输入正确的日期时间格式!") + return + + # 更新数据库中的取车时间 + update_query = """ + UPDATE parked_cars + SET picked_up_time = %s + WHERE license_plate = %s + """ + self.cursor.execute(update_query, (new_picked_up_time, license_plate)) + self.connection.commit() # 提交事务 + + messagebox.showinfo("更新成功", f"车牌号为{license_plate}的车辆取车时间已更新。") + else: + messagebox.showinfo("取消操作", "未输入取车时间,操作已取消。") + else: + messagebox.showinfo("查询结果", "未找到该车牌号的车辆信息。") + except Error as e: + messagebox.showerror("编辑错误", f"编辑车辆取车时间时发生错误: {e}") + + def count_parked_cars(self): + """统计当前停在停车场的车辆总数""" + query = "SELECT COUNT(*) FROM parked_cars" + self.cursor.execute(query) + parked_count = self.cursor.fetchone()[0] + return parked_count + + def count_empty_slots(self, total_slots): + """计算空闲车位数""" + parked_count = self.count_parked_cars() + empty_slots = total_slots - parked_count + return empty_slots + + def most_frequent_parking_time(self): + """ + 分析并返回最频繁的停车时段。 + 这里简化处理,实际应用中可能需要更复杂的SQL查询来统计时段。 + """ + query = """ + SELECT + HOUR(parked_time) AS hour, + COUNT(*) AS frequency + FROM parked_cars + GROUP BY hour + ORDER BY frequency DESC + LIMIT 1 + """ + self.cursor.execute(query) + most_frequent_hour, _ = self.cursor.fetchone() + return f"最频繁的停车时段是第{most_frequent_hour}小时" + + + def close_connection(self): + """关闭数据库连接""" + if self.conn.is_connected(): + self.cursor.close() + self.conn.close() \ No newline at end of file diff --git a/ParkingLotManager.py b/ParkingLotManager.py deleted file mode 100644 index 78a8f4f..0000000 --- a/ParkingLotManager.py +++ /dev/null @@ -1,229 +0,0 @@ -import tkinter as tk -from tkinter import messagebox, simpledialog -from datetime import datetime -import mysql.connector - -conn = mysql.connector.connect( - host="localhost", - user="root", - password="root", - database="sys" -) - - - -class ParkingLotManager: - def __init__(self): - self.conn = mysql.connector.connect( - host="localhost", - user="root", - password="root", - database="sys" - ) - self.cursor = self.conn.cursor() - - # 初始化时从数据库加载定价规则 - self.load_pricing_rules_from_db() - self.parked_vehicles = {} # 本地缓存,用于快速查询 - - def load_parked_vehicles_from_db(self): - """从数据库加载已停车辆""" - self.cursor.execute("SELECT license_plate, vehicle_type, entry_time FROM parked_vehicles") - parked_data = self.cursor.fetchall() - for plate, vehicle_type, entry_time in parked_data: - self.parked_vehicles[plate] = { - 'vehicle': Vehicle(plate, vehicle_type), - 'entry_time': datetime.strptime(entry_time, "%Y-%m-%d %H:%M:%S") - } - - # 添加一个新方法用于初始化App时加载数据 - def initialize_data_on_login(self): - self.load_parked_vehicles_from_db() - # 在ParkingSystemApp的__init__方法中调用加载数据的方法 - - def open_main_system(parking_manager): - main_system_window = tk.Toplevel(login_window) - main_system_window.title("停车场管理系统 - 主功能") - - # 在创建ParkingSystemApp实例前,先初始化数据 - parking_manager.initialize_data_on_login() - - app = ParkingSystemApp(main_system_window, parking_manager) - - main_system_window.protocol("WM_DELETE_WINDOW", lambda: [main_system_window.destroy(), login_window.destroy()]) - def __init__(self, master, parking_manager): - # ...其他初始化代码... - parking_manager.load_parked_vehicles_from_db() - self.update_ui_vehicles() - - def park_vehicle(self, vehicle): - # 除了现有逻辑,还需要在数据库中记录入场时间 - sql = "INSERT INTO parked_vehicles (license_plate, vehicle_type, entry_time) VALUES (%s, %s, %s)" - val = (vehicle.get_license_plate(), vehicle.get_vehicle_type(), datetime.now()) - self.cursor.execute(sql, val) - self.conn.commit() - self.parked_vehicles[vehicle.get_license_plate()] = {'vehicle': vehicle, 'entry_time': datetime.now()} - - def unpark_vehicle(self, license_plate): - # 除了现有逻辑,更新数据库中的出场时间和费用 - vehicle_info = self.parked_vehicles.get(license_plate) - if vehicle_info: - exit_time = datetime.now() - hours_parked = (exit_time - vehicle_info['entry_time']).total_seconds() / 3600 - vehicle_type = vehicle_info['vehicle'].get_vehicle_type() - fee = self.pricing_rules[vehicle_type].calculate_fee(hours_parked) - - sql_update = "UPDATE parked_vehicles SET exit_time=%s, total_fee=%s WHERE license_plate=%s" - val = (exit_time, fee, license_plate) - self.cursor.execute(sql_update, val) - self.conn.commit() - - del self.parked_vehicles[license_plate] - return fee - else: - raise ValueError("Vehicle not found in the system.") - - - - - -class PricingRule: - def __init__(self, vehicle_type, hourly_rate, max_daily_rate=None): - self.vehicle_type = vehicle_type - self.hourly_rate = hourly_rate - self.max_daily_rate = max_daily_rate or float('inf') - - def calculate_fee(self, hours_parked): - fee = hours_parked * self.hourly_rate - if self.max_daily_rate and fee > self.max_daily_rate: - return self.max_daily_rate - return fee - -class Vehicle: - def __init__(self, license_plate, vehicle_type): - self.license_plate = license_plate - self.vehicle_type = vehicle_type - - def get_license_plate(self): - return self.license_plate - - def get_vehicle_type(self): - return self.vehicle_type - -class ParkingLotManager: - def __init__(self): - self.pricing_rules = {} - self.parked_vehicles = {} - - def add_pricing_rule(self, vehicle_type, hourly_rate, max_daily_rate=None): - self.pricing_rules[vehicle_type] = PricingRule(vehicle_type, hourly_rate, max_daily_rate) - - def park_vehicle(self, vehicle): - self.parked_vehicles[vehicle.get_license_plate()] = {'vehicle': vehicle, 'entry_time': datetime.now()} - - def unpark_vehicle(self, license_plate): - entry_time = self.parked_vehicles[license_plate]['entry_time'] - parked_hours = (datetime.now() - entry_time).total_seconds() / 3600 - vehicle_type = self.parked_vehicles[license_plate]['vehicle'].get_vehicle_type() - - if vehicle_type in self.pricing_rules: - fee = self.pricing_rules[vehicle_type].calculate_fee(parked_hours) - del self.parked_vehicles[license_plate] - return fee - else: - raise ValueError("No pricing rule for this vehicle type.") - -class ParkingSystemApp: - def __init__(self, master, parking_manager): - self.master = master - self.parking_manager = parking_manager - master.title("停车场管理系统") - - self.vehicle_listbox = tk.Listbox(master, width=50) - self.vehicle_listbox.pack(pady=10) - - self.search_entry = tk.Entry(master) - self.search_entry.pack(pady=5) - - tk.Button(master, text="查询车辆", command=self.search_vehicle).pack(side=tk.LEFT, padx=5) - tk.Button(master, text="录入入场", command=self.add_vehicle).pack(side=tk.LEFT, padx=5) - tk.Button(master, text="删除出场", command=self.remove_vehicle).pack(side=tk.LEFT, padx=5) - tk.Button(master, text="退出系统", command=self.quit_app).pack(side=tk.RIGHT, padx=5) - - # 示例数据,实际应用中应从数据库读取 - self.vehicles = ["ABC123", "XYZ789", "CDE456"] - self.update_ui_vehicles() - - def update_ui_vehicles(self): - self.vehicle_listbox.delete(0, tk.END) - for plate in self.parking_manager.parked_vehicles.keys(): - self.vehicle_listbox.insert(tk.END, plate) - - def search_vehicle(self): - query = self.search_entry.get().strip() - if query: - self.vehicle_listbox.delete(0, tk.END) - for plate in self.parking_manager.parked_vehicles.keys(): - if query.lower() in plate.lower(): - self.vehicle_listbox.insert(tk.END, plate) - - def add_vehicle(self): - new_vehicle = simpledialog.askstring("录入车辆", "请输入车牌号:") - if new_vehicle and new_vehicle not in self.vehicles: - car = Vehicle(new_vehicle, "car") - parking_manager.park_vehicle(car) # 假设park_vehicle方法已更新数据库 - self.update_ui_vehicles() # 添加车辆后立即刷新UI - - def remove_vehicle(self): - selected = self.vehicle_listbox.curselection() - if selected: - plate = self.vehicle_listbox.get(selected[0]) - fee = parking_manager.unpark_vehicle(plate) - messagebox.showinfo("停车费用", f"车辆 {plate} 的停车费用为:{fee}元") - self.update_ui_vehicles() # 移除车辆后刷新UI - - def quit_app(self): - self.master.destroy() - -def login_success(username_entry, password_entry, parking_manager): - expected_username = "1" - expected_password = "1" # 这里设置具体的密码 - - entered_username = username_entry.get().strip() - entered_password = password_entry.get().strip() - - if entered_username == expected_username and entered_password == expected_password: - login_window.withdraw() - open_main_system(parking_manager) - else: - messagebox.showerror("登录失败", "用户名或密码错误,请重试。") - -def open_main_system(parking_manager): - main_system_window = tk.Toplevel(login_window) - main_system_window.title("停车场管理系统 - 主功能") - app = ParkingSystemApp(main_system_window, parking_manager) - - main_system_window.protocol("WM_DELETE_WINDOW", lambda: [main_system_window.destroy(), login_window.destroy()]) - -# 初始化停车场管理器 -parking_manager = ParkingLotManager() -parking_manager.add_pricing_rule("car", 2, 20) # 小型车每小时2元,每日最高20元 - -# 登录界面 -login_window = tk.Tk() -login_window.title("停车场管理系统 - 登录") - -label_username = tk.Label(login_window, text="用户名:") -label_username.pack() -entry_username = tk.Entry(login_window) -entry_username.pack() - -label_password = tk.Label(login_window, text="密码:") -label_password.pack() -entry_password = tk.Entry(login_window, show="*") -entry_password.pack() - -button_login = tk.Button(login_window, text="登录", command=lambda: login_success(entry_username, entry_password, parking_manager)) -button_login.pack(pady=10) - -login_window.mainloop() diff --git a/User.py b/User.py index 27e47c4..e4dacba 100644 --- a/User.py +++ b/User.py @@ -1,32 +1,30 @@ -import time - +class User: + def __init__(self, username, password, role='user'): + """ + 初始化用户对象 + :param username: 用户名 + :param password: 密码(注意:在实际应用中不应明文存储,此处仅为示例) + :param role: 用户角色,如'user'(默认)、'admin'等 + """ + self.username = username + self.password = password # 实际应用中应加密存储 + self.role = role -class User(object): - def __init__(self): - self.Username = [] - self.Userpwd = [] - self.Adminname = "xyh" - self.Adminpwd = "xyh" + def __str__(self): + """返回用户的字符串表示""" + return f"用户名: {self.username}, 角色: {self.role}" - def login(self): + def change_password(self, new_password): """ - 用户登录 - :return:{bool}True(登录成功进入管理员模式)/False(登录失败返回用户模式) + 更改用户密码 + :param new_password: 新密码 """ - cnt = 1 # counter for trial - while 1 <= cnt <= 5: - name = input('请输入用户名:') - pwd = input('请输入密码:') - if name == '' or pwd == '': - print('用户名或密码不能为空!') - continue - elif name == self.Adminname and pwd == self.Adminpwd: - return True - else: - if cnt <= 4: - print('用户名或密码错误,您还有%d次机会,请重试!' % (5-cnt)) - cnt += 1 - else: - print('机会已用尽,即将返回用户模式......') - time.sleep(2) - return False \ No newline at end of file + self.password = new_password # 实际应用中应处理密码加密逻辑 + + def promote_to_admin(self): + """提升用户为管理员角色""" + self.role = 'admin' + + def demote_to_user(self): + """降级用户为普通用户角色""" + self.role = 'user' \ No newline at end of file diff --git a/main.py b/main.py deleted file mode 100644 index 24f9e87..0000000 --- a/main.py +++ /dev/null @@ -1,202 +0,0 @@ -import os -import logging -import re # 正则表达式 -import time - -# Sub module -from Car import Car, ParkManage, Model, Color -from User import User -from IO import * - - -# from GUI import * # TODO - -def menu_select(isAdmin, park): - """显示菜单,返回str型操作码""" - if isAdmin == True: - # 管理员模式 - while True: - os.system("cls") - print(""" - ***欢迎使用停车场管理系统*** - ## 管理员模式 ## - - ---北京第三区交通委提醒您--- - | 道路千万条,安全第一条 | - | 行车不规范,亲人两行泪 | - --------------------------- - 本停车场总车位数:%3d 当前空闲车位数:%3d - - 1)停车 - 2)取车 - 3)显示车辆信息 - 4)查询车辆信息 - 5)编辑车辆信息 - 6)统计车辆信息 - 7)从文件加载车辆 - - 8)切换至用户模式 - 9)关于 - 0)退出系统 - """ % (park.max_car, park.max_car - len(park.carlist))) - c = input("请输入操作码(0~9):") - if re.match(r'(^\d$)', c): - if 0 <= int(c) <= 9: # c >= 0 and c <= 9 - return c - else: - print("输入错误,请重试!") - else: - print("输入错误,请重试!") - ''' - try: - c = int(input("请输入操作码(0~8):")) - except Exception as e: - logging.exception(e) - c = -1 - continue - ''' - - - elif isAdmin == False: - # 用户模式 - while True: - os.system("cls") - print(""" - ***欢迎使用停车场管理系统*** - ## 用户模式 ## - - ---北京第三区交通委提醒您--- - | 道路千万条,安全第一条 | - | 行车不规范,亲人两行泪 | - --------------------------- - 本停车场总车位数:%3d 当前空闲车位数:%3d - - 1)停车 - 2)取车 - 3)查询车辆信息 - - 4)切换至管理员模式 - 5)关于 - 0)退出系统 - """ % (park.max_car, park.max_car - len(park.carlist))) - c = input("请输入操作码(0~5):") - if re.match(r'(^\d$)', c): - if 0 <= int(c) <= 5: # c >= 0 and c <= 5 - return c - else: - print("输入错误,请重试!") - else: - print("输入错误,请重试!") - - ''' - try: - c = int(input("请输入操作码(0~5):")) - except Exception as e: - print('请输入正确的操作码!') - logging.exception(e) - c = -1 - continue - ''' - - -def main(): - park = ParkManage() # 建立并初始化车库 - user = User() # 初始化用户 - park = load_from_file(park, filename="cars.csv")[0] # 从文件初始化车辆信息 - - # user.login() - # isAdmin = True # TODO DEBUG 测试用 - isAdmin = False # 程序启动时直接进入用户模式 - - while True: - choice = menu_select(isAdmin, park=park) - if not isAdmin: - # 用户 - if choice == '0': - os.system("cls") # 清屏 - write_to_file(park, filename="cars.csv") # 将车辆信息写入文件 - print("Goodbye.\nHave a nice day!\n期待与您下一次的相遇! \n\n系统3秒后自动关闭...") - time.sleep(3) - exit(0) - elif choice == '1': # 停车 - os.system("cls") # 清屏 - park.park(isAdmin) - elif choice == '2': # 取车 - os.system("cls") - park.pickup() - os.system("pause") - elif choice == '3': # 查车 - os.system("cls") - park.inquire() - os.system("pause") - elif choice == '4': # 切换到管理员模式 - # isAdmin = True # DEBUG - os.system("cls") - isAdmin = user.login() # 管理员登录 - continue - elif choice == '5': # 关于 - os.system("cls") # 清屏 - print(""" - 停车场管理系统 - Version:0.6.0 - Copyright by Hzj. - All rights reserved. - - """) - os.system("pause") - else: - pass - - elif isAdmin: - # 管理员 - if choice == '0': # 退出 - os.system("cls") # 清屏 - write_to_file(park, filename="cars.csv") # 将车辆信息写入文件 - print("Goodbye.\nHave a nice day!\n期待与您下一次的相遇! \n\n系统3秒后自动关闭...") - time.sleep(3) - exit(0) - elif choice == '1': # 停车 - os.system("cls") # 清屏 - park.park(isAdmin) - elif choice == '2': # 取车 - os.system("cls") # 清屏 - park.pickup() - os.system("pause") - elif choice == '3': # 显示车辆信息 - os.system("cls") # 清屏 - park.display() - os.system("pause") - elif choice == '4': # 查询车辆信息 - os.system("cls") - park.inquire() - os.system("pause") - elif choice == '5': # 编辑车辆信息 - os.system("cls") # 清屏 - park.edit() - os.system("pause") - elif choice == '6': # 统计车辆信息 - os.system("cls") # 清屏 - park.statistics() - os.system("pause") - elif choice == '7': # 从文件加载车辆 - os.system("cls") # 清屏 - park = load_new_file(park=park) - os.system("pause") - elif choice == '8': # 切换到用户模式 - isAdmin = False - elif choice == '9': # 关于 - os.system("cls") # 清屏 - print(""" - 停车场管理系统 - Version:0.6.0 - Copyright by Hzj. - All rights reserved. - - """) - os.system("pause") - else: - pass - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/main1.py b/main1.py new file mode 100644 index 0000000..23836f2 --- /dev/null +++ b/main1.py @@ -0,0 +1,205 @@ +import tkinter as tk +from tkinter import messagebox +from tkinter import simpledialog +from Car import Car +from ParkManage import ParkManage # 确保你的模块路径正确 +from User import User + + +# 初始化停车场管理 +park_manage_instance = ParkManage() +park = ParkManage() +# 创建一个用户实例 +user1 = User('Alice', 'P@ssw0rd') + +# 打印用户信息 +print(user1) + +# 修改用户密码 +user1.change_password('NewP@ssw0rd') + +# 提升用户为管理员 +user1.promote_to_admin() + +# 再次打印用户信息,查看角色是否变化 +print(user1) + +# 降级用户为普通用户 +user1.demote_to_user() + +# 最后一次打印用户信息 +print(user1) +isAdmin = False + + +def on_park_click(): + """处理停车操作的回调函数""" + # 弹出对话框让用户输入车牌号 + license_plate = simpledialog.askstring("停车", "请输入车牌号:") + if license_plate: + # 调用park对象的park方法,传入用户输入的车牌号 + success = park.park(license_plate) + if success: + messagebox.showinfo("停车成功", f"车牌号{license_plate}的车辆已成功停放。") + else: + messagebox.showerror("停车失败", "停车过程中出现问题,请重试。") + else: + messagebox.showwarning("警告", "车牌号不能为空,请重新输入。") + + +def on_pickup_click(): + """处理取车操作的回调函数""" + # 弹出对话框让用户输入车牌号 + license_plate = simpledialog.askstring("取车", "请输入车牌号:") + if license_plate: + # 调用park对象的pickup方法,传入用户输入的车牌号尝试取车 + success = park.pickup(license_plate) + if success: + messagebox.showinfo("取车成功", f"车牌号为{license_plate}的车辆已成功取走。") + else: + messagebox.showerror("取车失败", f"车牌号为{license_plate}的车辆取车失败。请检查车牌号是否正确或车辆是否已取走。") + else: + messagebox.showwarning("警告", "车牌号不能为空,请重新输入。") + +def on_inquire_click(): + """处理查询车辆信息操作的回调函数""" + # 弹出对话框让用户输入车牌号 + license_plate = simpledialog.askstring("查询车辆信息", "请输入车牌号:") + if license_plate: + try: + # 调用park对象的query_car_info方法,传入用户输入的车牌号查询车辆信息 + car_info = park.query_car_info(license_plate) + if car_info: + # 假设query_car_info返回车辆信息的字典,展示相关信息 + message = ( + f"车牌号: {car_info['license_plate']}\n" + f"车型: {car_info['model']}\n" + f"颜色: {car_info['color']}\n" + f"停放时间: {car_info['parked_time'].strftime('%Y-%m-%d %H:%M:%S')}\n" + f"取车时间: {car_info['picked_up_time'].strftime('%Y-%m-%d %H:%M:%S') if car_info['picked_up_time'] else '未取车'}" + ) + messagebox.showinfo("车辆信息", message) + else: + messagebox.showerror("查询结果", "未找到该车牌号的车辆信息。") + except Exception as e: + messagebox.showerror("查询错误", f"查询过程中发生错误: {e}") + else: + messagebox.showwarning("警告", "车牌号不能为空,请重新输入。") +def on_display_info_click(): + + try: + # 调用ParkManage类中的方法来获取所有车辆信息 + car_info = park.display_all_cars_info() + + if cars_info: + # 假设cars_info是一个包含车辆信息的列表,每个元素是车辆的字典表示 + info_text = "\n".join( + [f"车牌号: {car['license_plate']}, 停放时间: {car['parked_time'].strftime('%Y-%m-%d %H:%M:%S')}" + f"{', 取车时间: ' + car['picked_up_time'].strftime('%Y-%m-%d %H:%M:%S') if car['picked_up_time'] else ''}" + for car in cars_info]) + messagebox.showinfo("车辆信息", info_text) + else: + messagebox.showinfo("信息提示", "当前没有车辆信息可显示。") + except Exception as e: + messagebox.showerror("错误", f"显示车辆信息时发生错误: {e}") + + +def on_edit_info_click(): + + # 从界面获取车牌号、车型和颜色 + license_plate = license_plate_entry.get().strip() + new_model = model_entry.get().strip() + new_color = color_entry.get().strip() + + if not license_plate: + messagebox.showerror("错误", "请输入车牌号进行编辑!") + return + + try: + # 假设ParkManage类有一个edit_car_info方法用于更新车辆信息 + success = park_manage_instance.edit_car_info(license_plate, new_model=new_model, new_color=new_color) + + if success: + messagebox.showinfo("成功", "车辆信息已成功更新。") + else: + messagebox.showinfo("失败", "未能找到或更新车辆信息,请检查车牌号是否正确。") + except Exception as e: + messagebox.showerror("错误", f"编辑车辆信息时发生错误: {e}") + + +def on_statistics_click(): + + try: + # 假设ParkManage类中包含以下统计方法 + parked_cars_count = park_manage_instance.count_parked_cars() + empty_slots = park_manage_instance.count_empty_slots(total_slots=100) # 假设总车位数为100,根据实际情况调整 + most_frequent_time = park_manage_instance.most_frequent_parking_time() + + # 构建统计信息字符串 + stats_message = ( + f"当前停车数量: {parked_cars_count}\n" + f"空闲车位数: {empty_slots}\n" + f"最频繁的停车时段: {most_frequent_time}\n" + + ) + + messagebox.showinfo("统计信息", stats_message) + except Exception as e: + messagebox.showerror("错误", f"统计车辆信息时发生错误: {e}") + + + +def on_switch_mode(): + """处理模式切换的回调函数""" + global isAdmin + isAdmin = not isAdmin + refresh_ui() + + +def on_exit_click(): + """处理退出操作的回调函数""" + if messagebox.askyesno("退出", "确定要退出吗?"): + window.destroy() # 关闭窗口 + + +def refresh_ui(): + """根据当前模式刷新界面""" + for widget in window.winfo_children(): + widget.destroy() + + tk.Label(window, text=f"欢迎使用停车场管理系统 - {'管理员' if isAdmin else '用户'}模式").pack() + + buttons = [ + ("停车", on_park_click), + ("取车", on_pickup_click), + ("查询车辆信息", on_inquire_click), + ] + + if isAdmin: + additional_buttons = [ + ("显示车辆信息", on_display_info_click), + ("编辑车辆信息", on_edit_info_click), + ("统计信息", on_statistics_click), + ("切换至用户模式", on_switch_mode), + ] + buttons.extend(additional_buttons) + else: + buttons.append(("切换至管理员模式", on_switch_mode)) + + buttons.append(("退出", on_exit_click)) + + for idx, (text, cmd) in enumerate(buttons): + tk.Button(window, text=text, command=cmd).pack(fill=tk.X, pady=5) + + +def main_gui(): + global window + window = tk.Tk() + window.title("停车场管理系统") + + refresh_ui() # 初始化界面 + window.mainloop() + + +if __name__ == "__main__": + main_gui() \ No newline at end of file