admin.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import tkinter as tk
  2. from tkinter import ttk
  3. from tkinter import messagebox as msg
  4. import tkinter.font as font
  5. import abc
  6. import conf
  7. from tool.type_ import *
  8. from sql.db import DB
  9. from sql.user import creat_new_user, del_user, find_user_by_name
  10. from sql.garbage import creat_new_garbage, del_garbage_not_use, del_garbage_not_use_many
  11. from equipment.scan_user import write_uid_qr, write_all_uid_qr
  12. from equipment.scan_garbage import write_gid_qr
  13. from core.user import User
  14. from core.garbage import GarbageBag
  15. from tk_event import TkEventBase, TkEventMain, TkThreading
  16. class AdminStationException(Exception):
  17. ...
  18. class CreatGarbageError(AdminStationException):
  19. ...
  20. class CreatUserError(AdminStationException):
  21. ...
  22. class AdminEventBase(TkEventBase):
  23. def __init__(self, station, db: DB, title: str = 'unknown'):
  24. self.station: AdminStationBase = station
  25. self._db: DB = db
  26. self._title = title
  27. def get_title(self) -> str:
  28. return self._title
  29. def is_end(self) -> bool:
  30. raise AdminStationException
  31. def done_after_event(self):
  32. raise AdminStationException
  33. class AdminStationBase(TkEventMain, metaclass=abc.ABCMeta):
  34. def __init__(self, db: DB):
  35. self._admin: Optional[User] = None
  36. self._db = db
  37. super(AdminStationBase, self).__init__()
  38. def creat_garbage(self, path: str, num: int = 1) -> List[tuple[str, Optional[GarbageBag]]]:
  39. re = []
  40. for _ in range(num):
  41. gar = creat_new_garbage(self._db)
  42. if gar is None:
  43. raise CreatGarbageError
  44. res = write_gid_qr(gar.get_gid(), path, self._db)
  45. re.append(res)
  46. return re
  47. def creat_user(self, name: uname_t, passwd: passwd_t, phone: str, manager: bool) -> Optional[User]:
  48. user = creat_new_user(name, passwd, phone, manager, self._db)
  49. if user is None:
  50. raise CreatUserError
  51. return user
  52. def creat_user_from_list(self, user_list: List[Tuple[uname_t, passwd_t, str]], manager: bool) -> List[User]:
  53. re = []
  54. for i in user_list:
  55. user = creat_new_user(i[0], i[1], i[2], manager, self._db)
  56. if user is None:
  57. raise CreatUserError
  58. re.append(user)
  59. return re
  60. def get_gid_qrcode(self, gid: gid_t, path: str) -> Tuple[str, Optional[GarbageBag]]:
  61. return write_gid_qr(gid, path, self._db)
  62. def get_all_gid_qrcode(self, path: str, where: str = "") -> List[str]:
  63. return write_all_uid_qr(path, self._db, where=where)
  64. def get_uid_qrcode(self, uid: uid_t, path: str) -> Tuple[str, Optional[User]]:
  65. return write_uid_qr(uid, path, self._db)
  66. def get_all_uid_qrcode(self, path: str, where: str = "") -> List[str]:
  67. return write_all_uid_qr(path, self._db, where=where)
  68. def del_garbage(self, gid: gid_t) -> bool:
  69. return del_garbage_not_use(gid, self._db)
  70. def del_garbage_many(self, from_: gid_t, to_: gid_t) -> int:
  71. return del_garbage_not_use_many(from_, to_, self._db)
  72. def del_user(self, uid: uid_t) -> bool:
  73. return del_user(uid, self._db)
  74. @abc.abstractmethod
  75. def login_call(self):
  76. ...
  77. def login(self, user: User) -> bool:
  78. if user is not None and user.is_manager():
  79. self._admin = user
  80. return True
  81. else:
  82. return False
  83. @abc.abstractmethod
  84. def show_loading(self, title: str):
  85. ...
  86. @abc.abstractmethod
  87. def stop_loading(self):
  88. ...
  89. @abc.abstractmethod
  90. def set_after_run(self, ms, func, *args):
  91. ...
  92. class AdminStation(AdminStationBase):
  93. def set_after_run(self, ms, func, *args): # super.__init__可能会调用
  94. self.init_after_run_list.append((ms, func, args))
  95. def __conf_set_after_run(self):
  96. for ms, func, args in self.init_after_run_list:
  97. self._window.after(ms, func, *args)
  98. def set_after_run_now(self, ms, func, *args):
  99. self._window.after(ms, func, *args)
  100. def __init__(self, db: DB, refresh_delay: int = conf.tk_refresh_delay):
  101. self.init_after_run_list: List[Tuple[int, Callable, Tuple]] = []
  102. super().__init__(db)
  103. self.refresh_delay = refresh_delay
  104. self._window = tk.Tk()
  105. self.login_window = None
  106. self._sys_height = self._window.winfo_screenheight()
  107. self._sys_width = self._window.winfo_screenwidth()
  108. self._win_height = int(self._sys_height * (2 / 3))
  109. self._win_width = int(self._sys_width * (2 / 3))
  110. self._full_screen = False
  111. self.__conf_windows()
  112. self.__conf_font_size()
  113. self.__show_login_window()
  114. self.__conf_set_after_run()
  115. def __conf_windows(self):
  116. self._window.title('HGSSystem: Manage Station')
  117. self._window.geometry(f'{self._win_width}x{self._win_height}')
  118. self._window['bg'] = "#F0FFF0"
  119. self._window.resizable(False, False)
  120. self._window.protocol("WM_DELETE_WINDOW", lambda: self.main_exit())
  121. def __conf_creak_tk(self):
  122. self._frame_list: List[AdminMenu] = []
  123. self._program_frame: List[AdminProgram] = []
  124. self._msg_frame = tk.Frame(self._window)
  125. self._msg_label = tk.Label(self._msg_frame), tk.Label(self._msg_frame), tk.StringVar(), tk.StringVar()
  126. self._msg_hide = tk.Button(self._msg_frame)
  127. self._loading_frame = tk.Frame(self._window)
  128. self._loading_title: Tuple[tk.Label, tk.Variable] = tk.Label(self._loading_frame), tk.StringVar()
  129. self._loading_pro = ttk.Progressbar(self._loading_frame)
  130. def __conf_font_size(self, n: int = 1):
  131. self._login_title_font_size = int(12 * n)
  132. self._login_btn_font_size = int(11 * n)
  133. def __show_login_window(self):
  134. self.login_window: Optional[tk.Toplevel] = tk.Toplevel()
  135. self.login_window.title("HGSSystem Login")
  136. height = int(self._sys_height * (1 / 6))
  137. width = int(height * 2)
  138. if width > self._sys_width:
  139. width = int(self._sys_width * (2 / 3))
  140. height = int(width / 2)
  141. self.login_window.geometry(f'{width}x{height}')
  142. self.login_window['bg'] = "#d1d9e0"
  143. self.login_window.resizable(False, False)
  144. self.login_window.protocol("WM_DELETE_WINDOW", lambda: self.login_exit())
  145. self._login_name = [tk.Label(self.login_window), tk.Entry(self.login_window), tk.StringVar()]
  146. self._login_passwd = [tk.Label(self.login_window), tk.Entry(self.login_window), tk.StringVar()]
  147. self._login_btn = [tk.Button(self.login_window), tk.Button(self.login_window)]
  148. self.__conf_login_window()
  149. self.hide_main()
  150. def __conf_login_window(self):
  151. title_font = self.__make_font(size=self._login_title_font_size, weight="bold")
  152. btn_font = self.__make_font(size=self._login_btn_font_size, weight="bold")
  153. for lb, text in zip([self._login_name[0], self._login_passwd[0]], ["User:", "Passwd:"]):
  154. lb['bg'] = "#d1d9e0" # 蜜瓜绿
  155. lb['font'] = title_font
  156. lb['text'] = text
  157. lb['anchor'] = 'e'
  158. for lb, var in zip([self._login_name[1], self._login_passwd[1]], [self._login_name[2], self._login_passwd[2]]):
  159. lb['font'] = title_font
  160. lb['textvariable'] = var
  161. self._login_name[0].place(relx=0.00, rely=0.20, relwidth=0.35, relheight=0.15)
  162. self._login_passwd[0].place(relx=0.00, rely=0.40, relwidth=0.35, relheight=0.15)
  163. self._login_name[1].place(relx=0.40, rely=0.20, relwidth=0.45, relheight=0.15)
  164. self._login_passwd[1]['show'] = "*"
  165. self._login_passwd[1].place(relx=0.40, rely=0.40, relwidth=0.45, relheight=0.15)
  166. self._login_btn[0]['bg'] = "#a1afc9"
  167. self._login_btn[0]['font'] = btn_font
  168. self._login_btn[0]['text'] = 'Login'
  169. self._login_btn[0]['command'] = lambda: self.login_call()
  170. self._login_btn[0].place(relx=0.50, rely=0.70, relwidth=0.16, relheight=0.15)
  171. self._login_btn[1]['bg'] = "#a1afc9"
  172. self._login_btn[1]['font'] = btn_font
  173. self._login_btn[1]['text'] = 'Exit'
  174. self._login_btn[1]['command'] = lambda: self.login_exit()
  175. self._login_btn[1].place(relx=0.70, rely=0.70, relwidth=0.16, relheight=0.15)
  176. def login_call(self):
  177. event = LoginEvent(self, self._db).start(self._login_name[2].get(),
  178. self._login_passwd[2].get())
  179. self.push_event(event)
  180. def login(self, user: User):
  181. if super(AdminStation, self).login(user):
  182. self.login_window.destroy()
  183. self.login_window = None
  184. self.show_main()
  185. else:
  186. msg.showerror("Login error", "Please, try again")
  187. self._login_name[2].set('')
  188. self._login_passwd[2].set('')
  189. def login_exit(self):
  190. if not msg.askokcancel('Sure?', 'Exit manager system.'):
  191. return
  192. if self.login_window is not None:
  193. self.login_window.destroy()
  194. self.exit_win()
  195. def main_exit(self):
  196. if not msg.askokcancel('Sure?', 'Exit manager system.'):
  197. return
  198. self.exit_win()
  199. def hide_main(self):
  200. self._window.withdraw()
  201. def show_main(self):
  202. self._window.update()
  203. self._window.deiconify()
  204. def show_loading(self, title: str):
  205. ...
  206. def stop_loading(self):
  207. ...
  208. @staticmethod
  209. def __make_font(family: str = 'noto', **kwargs):
  210. return font.Font(family=conf.font_d[family], **kwargs)
  211. def mainloop(self):
  212. self._window.mainloop()
  213. def exit_win(self):
  214. self._window.destroy()
  215. class LoginEvent(AdminEventBase):
  216. def __init__(self, station: AdminStationBase, db: DB):
  217. super().__init__(station, db, "Ranking")
  218. self.thread: Optional[TkThreading] = None
  219. def login(self, name, passwd):
  220. return find_user_by_name(name, passwd, self._db)
  221. def start(self, name, passwd):
  222. self.thread = TkThreading(self.login, name, passwd)
  223. return self
  224. def is_end(self) -> bool:
  225. return not self.thread.is_alive()
  226. def done_after_event(self):
  227. self.station.login(self.thread.wait_event())
  228. class AdminMenu(metaclass=abc.ABCMeta):
  229. @abc.abstractmethod
  230. def get_menu_frame(self, station: AdminStation) -> tk.Frame:
  231. ...
  232. class AdminProgram(metaclass=abc.ABCMeta):
  233. @abc.abstractmethod
  234. def get_admin_frame(self, station: AdminStation) -> tk.Frame:
  235. ...
  236. if __name__ == '__main__':
  237. mysql_db = DB()
  238. station_ = AdminStation(mysql_db)
  239. station_.mainloop()