|
@@ -1,96 +1,322 @@
|
|
|
-# import tkinter as tk
|
|
|
-# import tkinter.font as font
|
|
|
-#
|
|
|
-# from tool.type_ import *
|
|
|
-#
|
|
|
-# from sql.db import DB
|
|
|
-# from sql.user import creat_new_user
|
|
|
-# from sql.garbage import creat_new_garbage
|
|
|
-#
|
|
|
-# from equipment.scan_user import write_uid_qr, write_all_uid_qr
|
|
|
-# from equipment.scan_garbage import write_gid_qr
|
|
|
-#
|
|
|
-# from core.user import User
|
|
|
-# from core.garbage import GarbageBag
|
|
|
-#
|
|
|
-#
|
|
|
-# class AdminStationException:
|
|
|
-# ...
|
|
|
-#
|
|
|
-#
|
|
|
-# class ControlNotLogin(AdminStationException):
|
|
|
-# ...
|
|
|
-#
|
|
|
-#
|
|
|
-# class CreatGarbageError(AdminStationException):
|
|
|
-# ...
|
|
|
-#
|
|
|
-#
|
|
|
-# class CreatUserError(AdminStationException):
|
|
|
-# ...
|
|
|
-#
|
|
|
-#
|
|
|
-# class AdminStationStatus:
|
|
|
-# def __init__(self,
|
|
|
-# win,
|
|
|
-# db: DB):
|
|
|
-# self._win = win
|
|
|
-# self._db: DB = db
|
|
|
-# self._admin: Optional[User] = None # 操作者
|
|
|
-#
|
|
|
-# def __check_manager_user(self):
|
|
|
-# if self._admin is None or not self._admin.is_manager():
|
|
|
-# raise ControlNotLogin
|
|
|
-#
|
|
|
-# def creat_garbage(self, path: str, num: int = 1) -> List[tuple[str, Optional[GarbageBag]]]:
|
|
|
-# self.__check_manager_user()
|
|
|
-#
|
|
|
-# re = []
|
|
|
-# for _ in range(num):
|
|
|
-# gar = creat_new_garbage(self._db)
|
|
|
-# if gar is None:
|
|
|
-# raise CreatGarbageError
|
|
|
-# res = write_gid_qr(gar.get_gid(), path, self._db)
|
|
|
-# re.append(res)
|
|
|
-# return re
|
|
|
-#
|
|
|
-# def creat_user(self, name: uname_t, passwd: passwd_t, phone: str, manager: bool) -> Optional[User]:
|
|
|
-# user = creat_new_user(name, passwd, phone, manager, self._db)
|
|
|
-# if user is None:
|
|
|
-# raise CreatUserError
|
|
|
-# return user
|
|
|
-#
|
|
|
-# def creat_user_from_list(self, user_list: List[Tuple[uname_t, passwd_t, str]], manager: bool) -> List[User]:
|
|
|
-# re = []
|
|
|
-# for i in user_list:
|
|
|
-# user = creat_new_user(i[0], i[1], i[2], manager, self._db)
|
|
|
-# if user is None:
|
|
|
-# raise CreatUserError
|
|
|
-# re.append(user)
|
|
|
-# return re
|
|
|
-#
|
|
|
-# def get_uid_qrcode(self, uid: uid_t, path: str) -> Tuple[str, Optional[User]]:
|
|
|
-# return write_uid_qr(uid, path, self._db)
|
|
|
-#
|
|
|
-# def get_uid_qrcode_from_list(self, uid_list: List[uid_t], path: str) -> List[Tuple[str, Optional[User]]]:
|
|
|
-# re = []
|
|
|
-# for uid in uid_list:
|
|
|
-# res = write_uid_qr(uid, path, self._db)
|
|
|
-# re.append(res)
|
|
|
-# return re
|
|
|
-#
|
|
|
-# def get_all_uid_qrcode(self, path: str, where: str = "") -> List[str]:
|
|
|
-# return write_all_uid_qr(path, self._db, where=where)
|
|
|
-#
|
|
|
-#
|
|
|
-# class AdminStation:
|
|
|
-# def __init__(self, db: DB):
|
|
|
-# self._status = AdminStationStatus(self, db)
|
|
|
-#
|
|
|
-# self._window = tk.Tk()
|
|
|
-# self._sys_height = self._window.winfo_screenheight()
|
|
|
-# self._sys_width = self._window.winfo_screenwidth()
|
|
|
-#
|
|
|
-# self._win_height = int(self._sys_height * (2 / 3))
|
|
|
-# self._win_width = int(self._sys_width * (1 / 3))
|
|
|
-# self._full_screen = False
|
|
|
+import tkinter as tk
|
|
|
+from tkinter import ttk
|
|
|
+from tkinter import messagebox as msg
|
|
|
+import tkinter.font as font
|
|
|
+import abc
|
|
|
+
|
|
|
+import conf
|
|
|
+from tool.type_ import *
|
|
|
+
|
|
|
+from sql.db import DB
|
|
|
+from sql.user import creat_new_user, del_user, find_user_by_name
|
|
|
+from sql.garbage import creat_new_garbage, del_garbage_not_use, del_garbage_not_use_many
|
|
|
+
|
|
|
+from equipment.scan_user import write_uid_qr, write_all_uid_qr
|
|
|
+from equipment.scan_garbage import write_gid_qr
|
|
|
+
|
|
|
+from core.user import User
|
|
|
+from core.garbage import GarbageBag
|
|
|
+
|
|
|
+from tk_event import TkEventBase, TkEventMain, TkThreading
|
|
|
+
|
|
|
+
|
|
|
+class AdminStationException(Exception):
|
|
|
+ ...
|
|
|
+
|
|
|
+
|
|
|
+class CreatGarbageError(AdminStationException):
|
|
|
+ ...
|
|
|
+
|
|
|
+
|
|
|
+class CreatUserError(AdminStationException):
|
|
|
+ ...
|
|
|
+
|
|
|
+
|
|
|
+class AdminEventBase(TkEventBase):
|
|
|
+ def __init__(self, station, db: DB, title: str = 'unknown'):
|
|
|
+ self.station: AdminStationBase = station
|
|
|
+ self._db: DB = db
|
|
|
+ self._title = title
|
|
|
+
|
|
|
+ def get_title(self) -> str:
|
|
|
+ return self._title
|
|
|
+
|
|
|
+ def is_end(self) -> bool:
|
|
|
+ raise AdminStationException
|
|
|
+
|
|
|
+ def done_after_event(self):
|
|
|
+ raise AdminStationException
|
|
|
+
|
|
|
+
|
|
|
+class AdminStationBase(TkEventMain, metaclass=abc.ABCMeta):
|
|
|
+ def __init__(self, db: DB):
|
|
|
+ self._admin: Optional[User] = None
|
|
|
+ self._db = db
|
|
|
+ super(AdminStationBase, self).__init__()
|
|
|
+
|
|
|
+ def creat_garbage(self, path: str, num: int = 1) -> List[tuple[str, Optional[GarbageBag]]]:
|
|
|
+ re = []
|
|
|
+ for _ in range(num):
|
|
|
+ gar = creat_new_garbage(self._db)
|
|
|
+ if gar is None:
|
|
|
+ raise CreatGarbageError
|
|
|
+ res = write_gid_qr(gar.get_gid(), path, self._db)
|
|
|
+ re.append(res)
|
|
|
+ return re
|
|
|
+
|
|
|
+ def creat_user(self, name: uname_t, passwd: passwd_t, phone: str, manager: bool) -> Optional[User]:
|
|
|
+ user = creat_new_user(name, passwd, phone, manager, self._db)
|
|
|
+ if user is None:
|
|
|
+ raise CreatUserError
|
|
|
+ return user
|
|
|
+
|
|
|
+ def creat_user_from_list(self, user_list: List[Tuple[uname_t, passwd_t, str]], manager: bool) -> List[User]:
|
|
|
+ re = []
|
|
|
+ for i in user_list:
|
|
|
+ user = creat_new_user(i[0], i[1], i[2], manager, self._db)
|
|
|
+ if user is None:
|
|
|
+ raise CreatUserError
|
|
|
+ re.append(user)
|
|
|
+ return re
|
|
|
+
|
|
|
+ def get_gid_qrcode(self, gid: gid_t, path: str) -> Tuple[str, Optional[GarbageBag]]:
|
|
|
+ return write_gid_qr(gid, path, self._db)
|
|
|
+
|
|
|
+ def get_all_gid_qrcode(self, path: str, where: str = "") -> List[str]:
|
|
|
+ return write_all_uid_qr(path, self._db, where=where)
|
|
|
+
|
|
|
+ def get_uid_qrcode(self, uid: uid_t, path: str) -> Tuple[str, Optional[User]]:
|
|
|
+ return write_uid_qr(uid, path, self._db)
|
|
|
+
|
|
|
+ def get_all_uid_qrcode(self, path: str, where: str = "") -> List[str]:
|
|
|
+ return write_all_uid_qr(path, self._db, where=where)
|
|
|
+
|
|
|
+ def del_garbage(self, gid: gid_t) -> bool:
|
|
|
+ return del_garbage_not_use(gid, self._db)
|
|
|
+
|
|
|
+ def del_garbage_many(self, from_: gid_t, to_: gid_t) -> int:
|
|
|
+ return del_garbage_not_use_many(from_, to_, self._db)
|
|
|
+
|
|
|
+ def del_user(self, uid: uid_t) -> bool:
|
|
|
+ return del_user(uid, self._db)
|
|
|
+
|
|
|
+ @abc.abstractmethod
|
|
|
+ def login_call(self):
|
|
|
+ ...
|
|
|
+
|
|
|
+ def login(self, user: User) -> bool:
|
|
|
+ if user is not None and user.is_manager():
|
|
|
+ self._admin = user
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ return False
|
|
|
+
|
|
|
+ @abc.abstractmethod
|
|
|
+ def show_loading(self, title: str):
|
|
|
+ ...
|
|
|
+
|
|
|
+ @abc.abstractmethod
|
|
|
+ def stop_loading(self):
|
|
|
+ ...
|
|
|
+
|
|
|
+ @abc.abstractmethod
|
|
|
+ def set_after_run(self, ms, func, *args):
|
|
|
+ ...
|
|
|
+
|
|
|
+
|
|
|
+class AdminStation(AdminStationBase):
|
|
|
+ def set_after_run(self, ms, func, *args): # super.__init__可能会调用
|
|
|
+ self.init_after_run_list.append((ms, func, args))
|
|
|
+
|
|
|
+ def __conf_set_after_run(self):
|
|
|
+ for ms, func, args in self.init_after_run_list:
|
|
|
+ self._window.after(ms, func, *args)
|
|
|
+
|
|
|
+ def set_after_run_now(self, ms, func, *args):
|
|
|
+ self._window.after(ms, func, *args)
|
|
|
+
|
|
|
+ def __init__(self, db: DB, refresh_delay: int = conf.tk_refresh_delay):
|
|
|
+ self.init_after_run_list: List[Tuple[int, Callable, Tuple]] = []
|
|
|
+
|
|
|
+ super().__init__(db)
|
|
|
+ self.refresh_delay = refresh_delay
|
|
|
+
|
|
|
+ self._window = tk.Tk()
|
|
|
+ self.login_window = None
|
|
|
+ self._sys_height = self._window.winfo_screenheight()
|
|
|
+ self._sys_width = self._window.winfo_screenwidth()
|
|
|
+
|
|
|
+ self._win_height = int(self._sys_height * (2 / 3))
|
|
|
+ self._win_width = int(self._sys_width * (2 / 3))
|
|
|
+
|
|
|
+ self._full_screen = False
|
|
|
+ self.__conf_windows()
|
|
|
+
|
|
|
+ self.__conf_font_size()
|
|
|
+ self.__show_login_window()
|
|
|
+ self.__conf_set_after_run()
|
|
|
+
|
|
|
+ def __conf_windows(self):
|
|
|
+ self._window.title('HGSSystem: Manage Station')
|
|
|
+ self._window.geometry(f'{self._win_width}x{self._win_height}')
|
|
|
+ self._window['bg'] = "#F0FFF0"
|
|
|
+ self._window.resizable(False, False)
|
|
|
+ self._window.protocol("WM_DELETE_WINDOW", lambda: self.main_exit())
|
|
|
+
|
|
|
+ def __conf_creak_tk(self):
|
|
|
+ self._frame_list: List[AdminMenu] = []
|
|
|
+ self._program_frame: List[AdminProgram] = []
|
|
|
+
|
|
|
+ self._msg_frame = tk.Frame(self._window)
|
|
|
+ self._msg_label = tk.Label(self._msg_frame), tk.Label(self._msg_frame), tk.StringVar(), tk.StringVar()
|
|
|
+ self._msg_hide = tk.Button(self._msg_frame)
|
|
|
+
|
|
|
+ self._loading_frame = tk.Frame(self._window)
|
|
|
+ self._loading_title: Tuple[tk.Label, tk.Variable] = tk.Label(self._loading_frame), tk.StringVar()
|
|
|
+ self._loading_pro = ttk.Progressbar(self._loading_frame)
|
|
|
+
|
|
|
+ def __conf_font_size(self, n: int = 1):
|
|
|
+ self._login_title_font_size = int(12 * n)
|
|
|
+ self._login_btn_font_size = int(11 * n)
|
|
|
+
|
|
|
+ def __show_login_window(self):
|
|
|
+ self.login_window: Optional[tk.Toplevel] = tk.Toplevel()
|
|
|
+ self.login_window.title("HGSSystem Login")
|
|
|
+
|
|
|
+ height = int(self._sys_height * (1 / 6))
|
|
|
+ width = int(height * 2)
|
|
|
+
|
|
|
+ if width > self._sys_width:
|
|
|
+ width = int(self._sys_width * (2 / 3))
|
|
|
+ height = int(width / 2)
|
|
|
+
|
|
|
+ self.login_window.geometry(f'{width}x{height}')
|
|
|
+ self.login_window['bg'] = "#d1d9e0"
|
|
|
+ self.login_window.resizable(False, False)
|
|
|
+ self.login_window.protocol("WM_DELETE_WINDOW", lambda: self.login_exit())
|
|
|
+ self._login_name = [tk.Label(self.login_window), tk.Entry(self.login_window), tk.StringVar()]
|
|
|
+ self._login_passwd = [tk.Label(self.login_window), tk.Entry(self.login_window), tk.StringVar()]
|
|
|
+ self._login_btn = [tk.Button(self.login_window), tk.Button(self.login_window)]
|
|
|
+
|
|
|
+ self.__conf_login_window()
|
|
|
+ self.hide_main()
|
|
|
+
|
|
|
+ def __conf_login_window(self):
|
|
|
+ title_font = self.__make_font(size=self._login_title_font_size, weight="bold")
|
|
|
+ btn_font = self.__make_font(size=self._login_btn_font_size, weight="bold")
|
|
|
+
|
|
|
+ for lb, text in zip([self._login_name[0], self._login_passwd[0]], ["User:", "Passwd:"]):
|
|
|
+ lb['bg'] = "#d1d9e0" # 蜜瓜绿
|
|
|
+ lb['font'] = title_font
|
|
|
+ lb['text'] = text
|
|
|
+ lb['anchor'] = 'e'
|
|
|
+
|
|
|
+ for lb, var in zip([self._login_name[1], self._login_passwd[1]], [self._login_name[2], self._login_passwd[2]]):
|
|
|
+ lb['font'] = title_font
|
|
|
+ lb['textvariable'] = var
|
|
|
+
|
|
|
+ self._login_name[0].place(relx=0.00, rely=0.20, relwidth=0.35, relheight=0.15)
|
|
|
+ self._login_passwd[0].place(relx=0.00, rely=0.40, relwidth=0.35, relheight=0.15)
|
|
|
+
|
|
|
+ self._login_name[1].place(relx=0.40, rely=0.20, relwidth=0.45, relheight=0.15)
|
|
|
+ self._login_passwd[1]['show'] = "*"
|
|
|
+ self._login_passwd[1].place(relx=0.40, rely=0.40, relwidth=0.45, relheight=0.15)
|
|
|
+
|
|
|
+ self._login_btn[0]['bg'] = "#a1afc9"
|
|
|
+ self._login_btn[0]['font'] = btn_font
|
|
|
+ self._login_btn[0]['text'] = 'Login'
|
|
|
+ self._login_btn[0]['command'] = lambda: self.login_call()
|
|
|
+ self._login_btn[0].place(relx=0.50, rely=0.70, relwidth=0.16, relheight=0.15)
|
|
|
+
|
|
|
+ self._login_btn[1]['bg'] = "#a1afc9"
|
|
|
+ self._login_btn[1]['font'] = btn_font
|
|
|
+ self._login_btn[1]['text'] = 'Exit'
|
|
|
+ self._login_btn[1]['command'] = lambda: self.login_exit()
|
|
|
+ self._login_btn[1].place(relx=0.70, rely=0.70, relwidth=0.16, relheight=0.15)
|
|
|
+
|
|
|
+ def login_call(self):
|
|
|
+ event = LoginEvent(self, self._db).start(self._login_name[2].get(),
|
|
|
+ self._login_passwd[2].get())
|
|
|
+ self.push_event(event)
|
|
|
+
|
|
|
+ def login(self, user: User):
|
|
|
+ if super(AdminStation, self).login(user):
|
|
|
+ self.login_window.destroy()
|
|
|
+ self.login_window = None
|
|
|
+ self.show_main()
|
|
|
+ else:
|
|
|
+ msg.showerror("Login error", "Please, try again")
|
|
|
+ self._login_name[2].set('')
|
|
|
+ self._login_passwd[2].set('')
|
|
|
+
|
|
|
+ def login_exit(self):
|
|
|
+ if not msg.askokcancel('Sure?', 'Exit manager system.'):
|
|
|
+ return
|
|
|
+ if self.login_window is not None:
|
|
|
+ self.login_window.destroy()
|
|
|
+ self.exit_win()
|
|
|
+
|
|
|
+ def main_exit(self):
|
|
|
+ if not msg.askokcancel('Sure?', 'Exit manager system.'):
|
|
|
+ return
|
|
|
+ self.exit_win()
|
|
|
+
|
|
|
+ def hide_main(self):
|
|
|
+ self._window.withdraw()
|
|
|
+
|
|
|
+ def show_main(self):
|
|
|
+ self._window.update()
|
|
|
+ self._window.deiconify()
|
|
|
+
|
|
|
+ def show_loading(self, title: str):
|
|
|
+ ...
|
|
|
+
|
|
|
+ def stop_loading(self):
|
|
|
+ ...
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def __make_font(family: str = 'noto', **kwargs):
|
|
|
+ return font.Font(family=conf.font_d[family], **kwargs)
|
|
|
+
|
|
|
+ def mainloop(self):
|
|
|
+ self._window.mainloop()
|
|
|
+
|
|
|
+ def exit_win(self):
|
|
|
+ self._window.destroy()
|
|
|
+
|
|
|
+
|
|
|
+class LoginEvent(AdminEventBase):
|
|
|
+ def __init__(self, station: AdminStationBase, db: DB):
|
|
|
+ super().__init__(station, db, "Ranking")
|
|
|
+ self.thread: Optional[TkThreading] = None
|
|
|
+
|
|
|
+ def login(self, name, passwd):
|
|
|
+ return find_user_by_name(name, passwd, self._db)
|
|
|
+
|
|
|
+ def start(self, name, passwd):
|
|
|
+ self.thread = TkThreading(self.login, name, passwd)
|
|
|
+ return self
|
|
|
+
|
|
|
+ def is_end(self) -> bool:
|
|
|
+ return not self.thread.is_alive()
|
|
|
+
|
|
|
+ def done_after_event(self):
|
|
|
+ self.station.login(self.thread.wait_event())
|
|
|
+
|
|
|
+
|
|
|
+class AdminMenu(metaclass=abc.ABCMeta):
|
|
|
+ @abc.abstractmethod
|
|
|
+ def get_menu_frame(self, station: AdminStation) -> tk.Frame:
|
|
|
+ ...
|
|
|
+
|
|
|
+
|
|
|
+class AdminProgram(metaclass=abc.ABCMeta):
|
|
|
+ @abc.abstractmethod
|
|
|
+ def get_admin_frame(self, station: AdminStation) -> tk.Frame:
|
|
|
+ ...
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ mysql_db = DB()
|
|
|
+ station_ = AdminStation(mysql_db)
|
|
|
+ station_.mainloop()
|