admin.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. import abc
  2. import tkinter as tk
  3. from tkinter import messagebox as msg
  4. from tkinter import ttk
  5. from _tkinter import TclError
  6. from conf import Config
  7. from core.garbage import GarbageBag
  8. from core.user import User
  9. from equipment.scan_garbage import write_gid_qr, write_all_gid_qr
  10. from equipment.scan_user import write_uid_qr, write_all_uid_qr
  11. from .event import TkEventMain
  12. from sql.db import DB, search_from_garbage_checker_user
  13. from sql.garbage import (create_new_garbage, search_garbage_by_fields, search_from_garbage_view,
  14. del_garbage, del_garbage_not_use, del_garbage_wait_check, del_garbage_has_check,
  15. del_garbage_where_scan_not_use, del_garbage_where_scan_wait_check,
  16. del_garbage_where_scan_has_check,
  17. del_garbage_where_not_use, del_garbage_where_wait_check, del_garbage_where_has_check,
  18. del_all_garbage, del_all_garbage_scan,
  19. update_garbage_check, update_garbage_type)
  20. from sql.user import (create_new_user, del_user, del_user_from_where, del_user_from_where_scan,
  21. search_user_by_fields, search_from_user_view,
  22. update_user_score, update_user_reputation,
  23. creat_user_from_csv, creat_auto_user_from_csv)
  24. from tool.tk import make_font
  25. from tool.typing import *
  26. class AdminStationBase(TkEventMain, metaclass=abc.ABCMeta):
  27. """
  28. AdminStation基类
  29. 封装管理员的相关操作
  30. 主要是柯里化 sql相关函数
  31. """
  32. def __init__(self, db: DB):
  33. self._admin: Optional[User] = None
  34. self._db = db
  35. super(AdminStationBase, self).__init__()
  36. def get_db(self):
  37. return self._db
  38. def create_garbage(self, path: Optional[str], num: int = 1) -> "List[tuple[str, Optional[GarbageBag]]]":
  39. re = []
  40. for _ in range(num):
  41. gar = create_new_garbage(self._db)
  42. assert gar
  43. if path is not None:
  44. res = write_gid_qr(gar.get_gid(), path, self._db)
  45. re.append(res)
  46. else:
  47. re.append(("", gar))
  48. return re
  49. def export_garbage_by_gid(self, path: Optional[str], gid: gid_t) -> Tuple[str, Optional[GarbageBag]]:
  50. return write_gid_qr(gid, path, self._db)
  51. def export_garbage(self, path: Optional[str], where: str) -> List[Tuple[str]]:
  52. return write_all_gid_qr(path, self._db, where=where)
  53. def create_user(self, name: uname_t, passwd: passwd_t, phone: str, manager: bool) -> Optional[User]:
  54. return create_new_user(name, passwd, phone, manager, self._db)
  55. def create_user_from_csv(self, path) -> List[User]:
  56. return creat_user_from_csv(path, self._db)
  57. def create_auto_user_from_csv(self, path) -> List[User]:
  58. return creat_auto_user_from_csv(path, self._db)
  59. def export_user_by_uid(self, path: str, uid: uid_t) -> Tuple[str, Optional[User]]:
  60. return write_uid_qr(uid, path, self._db)
  61. def export_user(self, path: str, where) -> List[str]:
  62. return write_all_uid_qr(path, self._db, where=where)
  63. def del_garbage_not_use(self, gid: gid_t) -> bool:
  64. return del_garbage_not_use(gid, self._db)
  65. def del_garbage_wait_check(self, gid: gid_t) -> bool:
  66. return del_garbage_wait_check(gid, self._db)
  67. def del_garbage_has_check(self, gid: gid_t) -> bool:
  68. return del_garbage_has_check(gid, self._db)
  69. def del_garbage(self, gid: gid_t) -> bool:
  70. return del_garbage(gid, self._db)
  71. def del_garbage_where_not_use(self, where) -> int:
  72. return del_garbage_where_not_use(where, self._db)
  73. def del_garbage_where_wait_check(self, where) -> int:
  74. return del_garbage_where_wait_check(where, self._db)
  75. def del_garbage_where_has_check(self, where) -> int:
  76. return del_garbage_where_has_check(where, self._db)
  77. def del_garbage_where_scan_not_use(self, where) -> int:
  78. return del_garbage_where_scan_not_use(where, self._db)
  79. def del_garbage_where_scan_wait_check(self, where) -> int:
  80. return del_garbage_where_scan_wait_check(where, self._db)
  81. def del_garbage_where_scan_has_check(self, where) -> int:
  82. return del_garbage_where_scan_has_check(where, self._db)
  83. def del_all_garbage_scan(self) -> int:
  84. return del_all_garbage_scan(self._db)
  85. def del_all_garbage(self) -> int:
  86. return del_all_garbage(self._db)
  87. def del_user(self, uid: uid_t) -> bool:
  88. return del_user(uid, self._db)
  89. def del_user_from_where_scan(self, where: str) -> int:
  90. return del_user_from_where_scan(where, self._db)
  91. def del_user_from_where(self, where: str) -> int:
  92. return del_user_from_where(where, self._db)
  93. def search_user(self, columns, uid, name, phone):
  94. return search_user_by_fields(columns, uid, name, phone, self._db)
  95. def search_user_advanced(self, columns, sql):
  96. return search_from_user_view(columns, sql, self._db)
  97. def search_garbage(self, columns, key_values: dict):
  98. return search_garbage_by_fields(columns, **key_values, db=self._db)
  99. def search_garbage_advanced(self, columns, sql):
  100. return search_from_garbage_view(columns, sql, self._db)
  101. def search_advanced(self, columns, sql):
  102. return search_from_garbage_checker_user(columns, sql, self._db)
  103. def update_user_score(self, score: score_t, where: str) -> int:
  104. return update_user_score(where, score, self._db)
  105. def update_user_reputation(self, reputation: score_t, where: str) -> int:
  106. return update_user_reputation(where, reputation, self._db)
  107. def update_garbage_type(self, type_: int, where: str):
  108. return update_garbage_type(where, type_, self._db)
  109. def update_garbage_check(self, check_: str, where: str):
  110. if check_ == 'pass':
  111. check = True
  112. elif check_ == 'fail':
  113. check = False
  114. else:
  115. return -1
  116. return update_garbage_check(where, check, self._db)
  117. @abc.abstractmethod
  118. def login_call(self):
  119. ...
  120. def login(self, user: User) -> bool:
  121. if user is not None and user.is_manager():
  122. self._admin = user
  123. return True
  124. else:
  125. return False
  126. def logout(self):
  127. if self._admin is not None:
  128. self._admin.destruct()
  129. self._admin = None
  130. def exit_(self):
  131. if self._admin is not None:
  132. self._admin.destruct()
  133. self._admin = None
  134. @abc.abstractmethod
  135. def show_loading(self, title: str):
  136. ...
  137. @abc.abstractmethod
  138. def stop_loading(self):
  139. ...
  140. @abc.abstractmethod
  141. def set_after_run(self, ms, func, *args):
  142. ...
  143. @abc.abstractmethod
  144. def to_menu(self, name: str = "主页"):
  145. ...
  146. @abc.abstractmethod
  147. def to_program(self, name: str = "欢迎页"):
  148. ...
  149. @abc.abstractmethod
  150. def show_msg(self, title, info, msg_type='提示'):
  151. ...
  152. @abc.abstractmethod
  153. def show_warning(self, title, info):
  154. ...
  155. @abc.abstractmethod
  156. def hide_msg(self):
  157. ...
  158. from . import admin_program as tk_program
  159. from . import admin_menu as tk_menu
  160. from . import admin_event as tk_event
  161. class AdminStation(AdminStationBase):
  162. """
  163. AdminStation 管理员系统
  164. 使用tkinter作为GUI
  165. 构造与GarbageStation类似
  166. """
  167. def set_after_run(self, ms, func, *args): # super.__init__可能会调用
  168. self.init_after_run_list.append((ms, func, args))
  169. def __conf_set_after_run(self):
  170. for ms, func, args in self.init_after_run_list:
  171. self._window.after(ms, func, *args)
  172. def set_after_run_now(self, ms, func, *args):
  173. self._window.after(ms, func, *args)
  174. def __init__(self, db: DB, refresh_delay: int = Config.tk_refresh_delay):
  175. self.init_after_run_list: List[Tuple[int, Callable, Tuple]] = []
  176. super().__init__(db)
  177. self.refresh_delay = refresh_delay
  178. self._window = tk.Tk()
  179. self.login_window = None
  180. self._sys_height = self._window.winfo_screenheight()
  181. self._sys_width = self._window.winfo_screenwidth()
  182. self._win_height = int(self._sys_height * (2 / 3))
  183. self._win_width = int(self._sys_width * (2 / 3))
  184. self.__conf_windows(before_load=True)
  185. self._full_screen = False
  186. self._is_loading = False
  187. self._disable_all_btn = False
  188. self._menu_now: Optional[Tuple[str, tk.Frame, tk_menu.AdminMenu]] = None
  189. self._program_now: Optional[Tuple[str, tk.Frame, tk_program.AdminProgram]] = None
  190. self.__conf_font_size()
  191. self.__conf_create_tk()
  192. self.__conf_create_menu()
  193. self.__conf_create_program()
  194. self.__conf_windows(before_load=False)
  195. self.__conf_tk() # 在所有的Creat完成后才conf_tk
  196. self.__show_login_window() # 显示登录窗口, Debug期间暂时注释该代码
  197. self.__conf_set_after_run()
  198. def __conf_windows(self, before_load: bool = True):
  199. if before_load:
  200. self._window.title('HGSSystem: Manage Station')
  201. self._window.geometry(f'{self._win_width}x{self._win_height}')
  202. self._window['bg'] = Config.tk_win_bg
  203. self._window.resizable(False, False)
  204. self._window.protocol("WM_DELETE_WINDOW", lambda: self.main_exit())
  205. self._window.title('HGSSystem: Manage Station 加载中')
  206. try:
  207. self._window.iconbitmap(Config.picture_d["logo-ico"])
  208. except TclError:
  209. pass
  210. else:
  211. self._window.title('HGSSystem: Manage Station')
  212. def __conf_create_tk(self):
  213. self._menu_back = tk.Frame(self._window)
  214. self._menu_line = tk.Label(self._menu_back) # 下划线
  215. self._menu_title: Tuple[tk.Label, tk.Variable] = (tk.Label(self._menu_back), tk.StringVar())
  216. self._menu_dict: Dict[str, tk_menu.AdminMenu] = {}
  217. self._menu_list: List[str] = [] # 菜单回溯
  218. self._program_back = tk.Frame(self._window)
  219. self._program_title: Tuple[tk.Label, tk.Variable] = (tk.Label(self._program_back), tk.StringVar())
  220. self._program_dict: Dict[str, tk_program.AdminProgram] = {}
  221. self._win_ctrl_button: List[tk.Button, tk.Button, tk.Button] = [tk.Button(self._menu_back),
  222. tk.Button(self._menu_back),
  223. tk.Button(self._window),
  224. tk.Button(self._window),
  225. tk.Button(self._window)]
  226. self._msg_frame = tk.Frame(self._window)
  227. self._msg_line = tk.Label(self._msg_frame)
  228. self._msg_label = tk.Label(self._msg_frame), tk.Label(self._msg_frame), tk.StringVar(), tk.StringVar()
  229. self._msg_hide = tk.Button(self._msg_frame)
  230. self._loading_pro = ttk.Progressbar(self._window)
  231. def __conf_font_size(self, n: int = 1):
  232. self._login_title_font_size = int(12 * n)
  233. self._login_btn_font_size = int(12 * n)
  234. self._win_ctrl_font_size = int(15 * n)
  235. self._menu_title_font_size = int(17 * n)
  236. self._program_title_font_size = int(14 * n)
  237. self._msg_font_size = int(20 * n)
  238. def __conf_tk(self, n: int = 1):
  239. self.__conf_win_ctrl_button()
  240. self.__conf_menu_title()
  241. self.__conf_menu(n)
  242. self.__conf_program_title()
  243. self.__conf_program(n)
  244. self.__conf_loading()
  245. self.__conf_msg()
  246. self.to_menu() # 显示主页面
  247. self.to_program()
  248. def __conf_win_ctrl_button(self):
  249. title_font = make_font(size=self._win_ctrl_font_size)
  250. title_font_bold = make_font(size=self._win_ctrl_font_size, weight="bold")
  251. for bt in self._win_ctrl_button:
  252. bt: tk.Button
  253. bt['bg'] = Config.tk_btn_bg
  254. bt['font'] = title_font
  255. bt_main: tk.Button = self._win_ctrl_button[1]
  256. bt_main['text'] = '主页'
  257. bt_main['font'] = title_font_bold
  258. bt_main['command'] = lambda: self.__to_main_menu()
  259. bt_main.place(relx=0.02, rely=0.86, relwidth=0.96, relheight=0.06)
  260. bt_back: tk.Button = self._win_ctrl_button[0]
  261. bt_back['text'] = '后退'
  262. bt_back['font'] = title_font_bold
  263. bt_back['state'] = 'disable'
  264. bt_back['command'] = lambda: self.__to_back_menu()
  265. bt_back.place(relx=0.02, rely=0.93, relwidth=0.96, relheight=0.06)
  266. rely = 0.02
  267. bt_help: tk.Button = self._win_ctrl_button[2]
  268. bt_help['text'] = '帮助'
  269. bt_help['command'] = lambda: self.to_program()
  270. bt_help.place(relx=0.81, rely=rely, relwidth=0.05, relheight=0.05)
  271. bt_about: tk.Button = self._win_ctrl_button[3]
  272. bt_about['text'] = '关于'
  273. bt_about['command'] = lambda: self.to_program("关于")
  274. bt_about.place(relx=0.87, rely=rely, relwidth=0.05, relheight=0.05)
  275. bt_exit: tk.Button = self._win_ctrl_button[4]
  276. bt_exit['text'] = '退出'
  277. bt_exit['command'] = lambda: self.main_exit()
  278. bt_exit.place(relx=0.93, rely=rely, relwidth=0.05, relheight=0.05)
  279. def set_ctrl_back_button(self):
  280. if len(self._menu_list) <= 1:
  281. self._win_ctrl_button[0]['state'] = 'disable'
  282. else:
  283. self._win_ctrl_button[0]['state'] = 'normal'
  284. def __to_main_menu(self):
  285. self._menu_list = []
  286. self.to_menu()
  287. def __to_back_menu(self):
  288. assert len(self._menu_list) > 1
  289. self._menu_list.pop() # 弹出最后一个元素
  290. self.to_menu(self._menu_list.pop()) # 再弹出一个元素
  291. def __conf_create_menu(self):
  292. frame_list = []
  293. for i in tk_menu.all_menu:
  294. self._window.update()
  295. frame_list.append(i(self, self._menu_back, Config.tk_second_win_bg))
  296. for i in frame_list:
  297. name = i.get_menu_title()
  298. self._menu_dict[name] = i
  299. def __conf_menu(self, n: int = 1):
  300. for i in self._menu_dict:
  301. menu = self._menu_dict[i]
  302. menu.conf_gui(Config.tk_btn_bg, n)
  303. def __conf_menu_title(self):
  304. self._menu_back['bg'] = Config.tk_second_win_bg
  305. self._menu_back['bd'] = 5
  306. self._menu_back['relief'] = "ridge"
  307. title_font = make_font(size=self._menu_title_font_size, weight="bold")
  308. self._menu_title[0]['bg'] = Config.tk_second_win_bg
  309. self._menu_title[0]['font'] = title_font
  310. self._menu_title[0]['textvariable'] = self._menu_title[1]
  311. self._menu_line['bg'] = '#000000'
  312. # 不立即显示
  313. def to_menu(self, name: str = "主页"):
  314. if self._menu_now is not None:
  315. self._menu_now[1].place_forget()
  316. menu = self._menu_dict.get(name)
  317. if menu is None:
  318. self._menu_title[1].set(f'菜单错误')
  319. self.show_msg("菜单错误", f"系统无法找到菜单:\n {name}")
  320. return
  321. name, frame = menu.get_menu_frame()
  322. self._menu_title[1].set(name)
  323. self._menu_back.place(relx=0.02, rely=0.02, relwidth=0.20, relheight=0.96)
  324. self._menu_line.place(relx=0.06, rely=0.065, relwidth=0.88, height=1) # 一个像素的高度即可
  325. self._menu_title[0].place(relx=0.02, rely=0.02, relwidth=0.96, relheight=0.03)
  326. frame.place(relx=0.02, rely=0.07, relwidth=0.96, relheight=0.79)
  327. self._menu_list.append(name)
  328. self._menu_now = name, frame, menu
  329. self.set_ctrl_back_button()
  330. def __conf_program_title(self):
  331. self._program_back['bg'] = Config.tk_second_win_bg
  332. self._program_back['relief'] = "ridge"
  333. self._program_back['bd'] = 5
  334. title_font = make_font(size=self._program_title_font_size, weight="bold")
  335. self._program_title[0]['bg'] = '#2468a2'
  336. self._program_title[0]['fg'] = "#F0F8FF"
  337. self._program_title[0]['font'] = title_font
  338. self._program_title[0]['anchor'] = 'w'
  339. self._program_title[0]['textvariable'] = self._program_title[1]
  340. # 不立即显示
  341. def __conf_create_program(self):
  342. program_list = []
  343. for i in tk_program.all_program:
  344. self._window.update()
  345. program_list.append(i(self, self._program_back, Config.tk_second_win_bg))
  346. for i in program_list:
  347. name = i.get_title()
  348. self._program_dict[name] = i
  349. def __conf_program(self, n: int = 1):
  350. for i in self._program_dict:
  351. program = self._program_dict[i]
  352. program.conf_gui(n)
  353. def to_program(self, name: str = "欢迎页"):
  354. if self._program_now is not None:
  355. self._program_now[2].leave_program()
  356. self._program_now[1].place_forget()
  357. program = self._program_dict.get(name)
  358. if program is None:
  359. self._program_title[1].set(f' 程序加载错误')
  360. self.show_msg("程序错误", f"系统无法找到程序:\n {name}")
  361. return
  362. program.to_program()
  363. name, frame = program.get_program_frame()
  364. self.__show_program()
  365. self._program_title[1].set(f' {name}')
  366. self._program_title[0].place(relx=0.00, rely=0.00, relwidth=1, relheight=0.05)
  367. frame.place(relx=0.02, rely=0.06, relwidth=0.96, relheight=0.92)
  368. self._program_now = name, frame, program
  369. def __show_program(self):
  370. self._program_back.place(relx=0.26, rely=0.1, relwidth=0.68, relheight=0.84)
  371. def __hide_program(self):
  372. self._program_back.place_forget()
  373. def __conf_loading(self):
  374. self._loading_pro['mode'] = 'indeterminate'
  375. self._loading_pro['orient'] = 'horizontal'
  376. self._loading_pro['maximum'] = 50
  377. def show_loading(self, _):
  378. self._is_loading = True
  379. self.set_all_btn_disable()
  380. self._loading_pro['value'] = 0
  381. self._loading_pro.place(relx=0.30, rely=0.035, relwidth=0.48, relheight=0.03)
  382. self._loading_pro.start(50)
  383. def stop_loading(self):
  384. self._is_loading = False
  385. self._loading_pro.place_forget()
  386. self._loading_pro.stop()
  387. self.set_reset_all_btn()
  388. def __conf_msg(self):
  389. title_font = make_font(size=self._msg_font_size + 1, weight="bold")
  390. info_font = make_font(size=self._msg_font_size - 1)
  391. self._msg_frame['bg'] = Config.tk_second_win_bg
  392. self._msg_frame['bd'] = 5
  393. self._msg_frame['relief'] = "ridge"
  394. # frame 不会立即显示
  395. self._msg_label[0]['font'] = title_font
  396. self._msg_label[0]['bg'] = Config.tk_second_win_bg
  397. self._msg_label[0]['anchor'] = 'w'
  398. self._msg_label[0]['textvariable'] = self._msg_label[2]
  399. self._msg_line['bg'] = '#000000'
  400. self._msg_label[1]['font'] = info_font
  401. self._msg_label[1]['bg'] = Config.tk_second_win_bg
  402. self._msg_label[1]['anchor'] = 'nw'
  403. self._msg_label[1]['textvariable'] = self._msg_label[3]
  404. self._msg_label[1]['justify'] = 'left'
  405. self._msg_label[0].place(relx=0.05, rely=0.05, relwidth=0.9, relheight=0.1)
  406. self._msg_line.place(relx=0.05, rely=0.15, relwidth=0.9, height=1) # 一个像素的高度即可
  407. self._msg_label[1].place(relx=0.075, rely=0.2, relwidth=0.85, relheight=0.58)
  408. self._msg_hide['font'] = info_font
  409. self._msg_hide['text'] = '关闭'
  410. self._msg_hide['bg'] = Config.tk_btn_bg
  411. self._msg_hide['command'] = lambda: self.hide_msg()
  412. self._msg_hide.place(relx=0.375, rely=0.80, relwidth=0.25, relheight=0.10)
  413. def show_msg(self, title, info, msg_type='提示'):
  414. assert not self._is_loading # loading 时不显示msg
  415. self.set_all_btn_disable()
  416. self._msg_label[2].set(f'{msg_type}: {title}')
  417. self._msg_label[3].set(f'{info}')
  418. frame_width = self._win_width * 0.50
  419. self._msg_label[1]['wraplength'] = frame_width * 0.85 - 5 # 设定自动换行的像素
  420. self._msg_frame.place(relx=0.30, rely=0.25, relwidth=0.55, relheight=0.50)
  421. # 不隐藏元素, 隐藏后界面会显得单调
  422. def show_warning(self, title, info):
  423. self.show_msg(title, info, "警告")
  424. def hide_msg(self):
  425. self.set_reset_all_btn()
  426. self._msg_frame.place_forget()
  427. def set_all_btn_disable(self):
  428. for btn in self._win_ctrl_button[:-1]: # Exit 不设置disable
  429. btn['state'] = 'disable'
  430. if self._menu_list != 0:
  431. menu = self._menu_dict.get(self._menu_list[-1], None)
  432. assert menu is not None
  433. menu.set_disable()
  434. if self._program_now is not None:
  435. self._program_now[2].set_disable()
  436. def set_reset_all_btn(self):
  437. for btn in self._win_ctrl_button[:-1]:
  438. btn['state'] = 'normal'
  439. self.set_ctrl_back_button()
  440. if self._menu_list != 0:
  441. menu = self._menu_dict.get(self._menu_list[-1], None)
  442. assert menu is not None
  443. menu.reset_disable()
  444. if self._program_now is not None:
  445. self._program_now[2].reset_disable()
  446. def __show_login_window(self):
  447. self.login_window: Optional[tk.Toplevel] = tk.Toplevel()
  448. self.login_window.title("HGSSystem Login")
  449. try:
  450. self.login_window.iconbitmap(Config.picture_d["logo-ico"])
  451. except TclError:
  452. pass
  453. height = int(self._sys_height * (1 / 5))
  454. width = int(height * 2)
  455. if width > self._sys_width:
  456. width = int(self._sys_width * (2 / 3))
  457. height = int(width / 2)
  458. self.login_window.geometry(f'{width}x{height}')
  459. self.login_window['bg'] = Config.tk_win_bg
  460. self.login_window.resizable(False, False)
  461. self.login_window.protocol("WM_DELETE_WINDOW", lambda: self.login_exit())
  462. self._login_frame = tk.Frame(self.login_window)
  463. self._login_name = [tk.Label(self._login_frame), tk.Entry(self._login_frame), tk.StringVar()]
  464. self._login_passwd = [tk.Label(self._login_frame), tk.Entry(self._login_frame), tk.StringVar()]
  465. self._login_btn = [tk.Button(self.login_window), tk.Button(self.login_window)]
  466. self.__conf_login_window()
  467. self.hide_main()
  468. self.login_window.deiconify()
  469. def __conf_login_window(self):
  470. title_font = make_font(size=self._login_title_font_size)
  471. btn_font = make_font(size=self._login_btn_font_size, weight="bold")
  472. self._login_frame['bg'] = "#EEE8AA"
  473. self._login_frame['bd'] = 5
  474. self._login_frame['relief'] = "ridge"
  475. self._login_frame.place(relx=0.1, rely=0.2, relwidth=0.8, relheight=0.45)
  476. for lb, text in zip([self._login_name[0], self._login_passwd[0]], ["账户:", "密码:"]):
  477. lb['bg'] = "#EEE8AA"
  478. lb['font'] = title_font
  479. lb['text'] = text
  480. lb['anchor'] = 'e'
  481. for lb, var in zip([self._login_name[1], self._login_passwd[1]], [self._login_name[2], self._login_passwd[2]]):
  482. lb['font'] = title_font
  483. lb['textvariable'] = var
  484. self._login_name[0].place(relx=0.00, rely=0.13, relwidth=0.25, relheight=0.30)
  485. self._login_passwd[0].place(relx=0.00, rely=0.53, relwidth=0.25, relheight=0.30)
  486. self._login_name[1].place(relx=0.26, rely=0.13, relwidth=0.64, relheight=0.30)
  487. self._login_passwd[1]['show'] = "*"
  488. self._login_passwd[1].place(relx=0.26, rely=0.53, relwidth=0.64, relheight=0.30)
  489. self._login_btn[0]['bg'] = Config.tk_btn_bg
  490. self._login_btn[0]['font'] = btn_font
  491. self._login_btn[0]['text'] = '登录'
  492. self._login_btn[0]['command'] = lambda: self.login_call()
  493. self._login_btn[0].place(relx=0.54, rely=0.70, relwidth=0.16, relheight=0.15)
  494. self._login_btn[1]['bg'] = Config.tk_btn_bg
  495. self._login_btn[1]['font'] = btn_font
  496. self._login_btn[1]['text'] = '退出'
  497. self._login_btn[1]['command'] = lambda: self.login_exit()
  498. self._login_btn[1].place(relx=0.74, rely=0.70, relwidth=0.16, relheight=0.15)
  499. def login_call(self):
  500. event = tk_event.LoginEvent(self).start(self._login_name[2].get(), self._login_passwd[2].get())
  501. self.push_event(event)
  502. def login(self, user: User):
  503. if super(AdminStation, self).login(user):
  504. self.login_window.destroy()
  505. self.login_window = None
  506. self.show_main()
  507. else:
  508. msg.showerror("登录失败", "请重新尝试")
  509. self._login_name[2].set('')
  510. self._login_passwd[2].set('')
  511. def logout(self):
  512. super(AdminStation, self).logout()
  513. self.__show_login_window()
  514. def login_exit(self):
  515. if not msg.askokcancel('退出', '确定退出管理员系统吗?'):
  516. return
  517. if self.login_window is not None:
  518. self.login_window.destroy()
  519. self.exit_win()
  520. def main_exit(self):
  521. if not msg.askokcancel('退出', '确定退出管理员系统吗?'):
  522. return
  523. self.exit_win()
  524. def hide_main(self):
  525. self._window.withdraw()
  526. def show_main(self):
  527. self._window.update()
  528. self._window.deiconify()
  529. def mainloop(self):
  530. self._window.mainloop()
  531. def exit_win(self):
  532. self.exit_()
  533. self._window.destroy()