admin_program.py 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126
  1. import abc
  2. import tkinter as tk
  3. import tkinter.ttk as ttk
  4. from tkinter.filedialog import askdirectory, askopenfilename, asksaveasfilename
  5. from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
  6. from matplotlib.axes import Axes
  7. import numpy as np
  8. from matplotlib.figure import Figure
  9. from tool.color import random_color
  10. from tool.type_ import *
  11. from tool.tk import make_font, set_tk_disable_from_list
  12. from tool.login import create_uid
  13. from conf import Config
  14. from . import admin
  15. from . import admin_event as tk_event
  16. from sql import DBBit
  17. from sql.user import find_user_by_name
  18. from core.garbage import GarbageType
  19. class AdminProgram(metaclass=abc.ABCMeta):
  20. def __init__(self, station: "admin.AdminStation", win: Union[tk.Frame, tk.Toplevel, tk.Tk], color: str, title: str):
  21. self.station = station
  22. self.win = win
  23. self.color = color
  24. self.frame = tk.Frame(self.win)
  25. self.frame['bg'] = color
  26. self.program_title = title
  27. @abc.abstractmethod
  28. def set_disable(self):
  29. ...
  30. @abc.abstractmethod
  31. def reset_disable(self):
  32. ...
  33. @abc.abstractmethod
  34. def conf_gui(self, n: int = 1):
  35. ...
  36. def to_program(self):
  37. pass
  38. def get_program_frame(self) -> Tuple[str, tk.Frame]:
  39. return self.program_title, self.frame
  40. class WelcomeProgram(AdminProgram):
  41. def __init__(self, station, win, color):
  42. super().__init__(station, win, color, "欢迎页")
  43. self.title = tk.Label(self.frame)
  44. self.info = tk.Label(self.frame)
  45. self.__conf_font()
  46. def __conf_font(self, n: int = 1):
  47. self.title_font_size = int(25 * n)
  48. self.info_font_size = int(14 * n)
  49. def conf_gui(self, n: int = 1):
  50. self.__conf_font(n)
  51. title_font = make_font(size=self.title_font_size, weight="bold")
  52. info_font = make_font(size=self.info_font_size)
  53. self.title['font'] = title_font
  54. self.title['bg'] = self.color
  55. self.title['text'] = '欢迎使用 HGSSystem 管理员系统\n[帮助]'
  56. self.info['bg'] = self.color
  57. self.info['font'] = info_font
  58. self.info['anchor'] = 'nw'
  59. self.info['justify'] = 'left'
  60. self.info['text'] = (f'''
  61. HGSSystem 管理者界面:
  62. 1) 点击菜单按钮进入子菜单或程序
  63. 2) 创建 菜单包含创建类的程序
  64. 3) 删除 菜单包含删除类的程序
  65. 4) 搜索 菜单包含数据分析类的程序
  66. 5) 更新 菜单包含数据更新类的程序
  67. 6) 当离开操作系统时请退出登录以确保安全
  68. 7) 只能使用具有管理员权限的账号登陆系统
  69. 8) 只有admin用户可以完成危险操作(例如删除所有垃圾袋数据)
  70. 程序的运行:
  71. 1) 在菜单中选中程序后,根据程序界面提示完成操作
  72. 2) 操作过程通常会显示进度条,除非任务执行迅速
  73. 3) 结果通常会被反馈, 且不会自动消失
  74. 系统登录:
  75. 1) 仅Manager用户可以登录
  76. 关于彩蛋: 存在
  77. '''.strip())
  78. self.title.place(relx=0.1, rely=0.0, relwidth=0.8, relheight=0.2)
  79. self.info.place(relx=0.05, rely=0.21, relwidth=0.90, relheight=0.75)
  80. def set_disable(self):
  81. pass
  82. def reset_disable(self):
  83. pass
  84. class AboutProgram(AdminProgram):
  85. def __init__(self, station, win, color):
  86. super().__init__(station, win, color, "关于")
  87. self.title = tk.Label(self.frame)
  88. self.info = tk.Label(self.frame)
  89. self.__conf_font()
  90. def __conf_font(self, n: int = 1):
  91. self.title_font_size = int(25 * n)
  92. self.info_font_size = int(14 * n)
  93. def conf_gui(self, n: int = 1):
  94. self.__conf_font(n)
  95. title_font = make_font(size=self.title_font_size, weight="bold")
  96. info_font = make_font(size=self.info_font_size)
  97. self.title['font'] = title_font
  98. self.title['bg'] = self.color
  99. self.title['text'] = '关于 HGSSystem 管理员系统'
  100. self.info['bg'] = self.color
  101. self.info['font'] = info_font
  102. self.info['anchor'] = 'nw'
  103. self.info['justify'] = 'left'
  104. self.info['text'] = Config.about_info
  105. self.title.place(relx=0.1, rely=0.0, relwidth=0.8, relheight=0.2)
  106. self.info.place(relx=0.05, rely=0.21, relwidth=0.90, relheight=0.75)
  107. def set_disable(self):
  108. pass
  109. def reset_disable(self):
  110. pass
  111. class CreateUserProgramBase(AdminProgram):
  112. def __init__(self, station, win, color, title: str):
  113. super().__init__(station, win, color, title)
  114. self.enter_frame = tk.Frame(self.frame)
  115. self.title: List[tk.Label] = [tk.Label(self.enter_frame) for _ in range(3)]
  116. self.enter: List[tk.Entry] = [tk.Entry(self.enter_frame) for _ in range(3)]
  117. self.var: List[tk.Variable] = [tk.StringVar() for _ in range(3)]
  118. self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(2)]
  119. self._conf("#FA8072", False) # 默认颜色
  120. self.__conf_font()
  121. def _conf(self, bg_color, is_manager: bool):
  122. self.bg_color = bg_color
  123. self.is_manager = is_manager
  124. return self
  125. def __conf_font(self, n: int = 1):
  126. self.title_font_size = int(16 * n)
  127. self.btn_font_size = int(14 * n)
  128. def conf_gui(self, n: int = 1):
  129. self.__conf_font(n)
  130. title_font = make_font(size=self.title_font_size)
  131. btn_font = make_font(size=self.btn_font_size)
  132. self.enter_frame['bg'] = self.bg_color
  133. self.enter_frame['bd'] = 5
  134. self.enter_frame['relief'] = "ridge"
  135. self.enter_frame.place(relx=0.2, rely=0.3, relwidth=0.6, relheight=0.30)
  136. height = 0.1
  137. for lb, text, enter, var in zip(self.title, ["用户名:", "用户密码:", "手机号:"], self.enter, self.var):
  138. lb['font'] = title_font
  139. lb['text'] = text
  140. lb['bg'] = self.bg_color
  141. lb['anchor'] = 'e'
  142. enter['font'] = title_font
  143. enter['textvariable'] = var
  144. lb.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.17)
  145. enter.place(relx=0.35, rely=height, relwidth=0.60, relheight=0.17)
  146. height += 0.30
  147. for btn, text, x, func in zip(self.btn,
  148. ["创建用户", "获取用户ID"],
  149. [0.2, 0.6],
  150. [lambda: self.create_by_name(), lambda: self.get_uid()]):
  151. btn['font'] = btn_font
  152. btn['text'] = text
  153. btn['bg'] = Config.tk_btn_bg
  154. btn['command'] = func
  155. btn.place(relx=x, rely=0.7, relwidth=0.2, relheight=0.08)
  156. def __get_info(self) -> Optional[Tuple[uname_t, passwd_t, str]]:
  157. name: uname_t = self.var[0].get()
  158. passwd: passwd_t = self.var[1].get()
  159. phone: str = self.var[2].get()
  160. if len(name) == 0 or len(passwd) == 0 or len(phone) != 11:
  161. self.station.show_msg("用户创建失败", "请再次尝试, 输入用户名, 用户密码和11位手机号")
  162. return None
  163. return name, passwd, phone
  164. def create_by_name(self):
  165. res = self.__get_info()
  166. if res is None:
  167. return
  168. name, passwd, phone = res
  169. event = tk_event.CreateUserEvent(self.station).start(name, passwd, phone, self.is_manager)
  170. self.station.push_event(event)
  171. def get_uid(self):
  172. res = self.__get_info()
  173. if res is None:
  174. return
  175. name, passwd, phone = res
  176. uid = create_uid(name, passwd, phone)
  177. self.station.show_msg("获取用户ID", f"用户名: {name}\n用户ID: {uid}")
  178. def set_disable(self):
  179. set_tk_disable_from_list(self.btn)
  180. set_tk_disable_from_list(self.enter)
  181. def reset_disable(self):
  182. set_tk_disable_from_list(self.btn, flat='normal')
  183. set_tk_disable_from_list(self.enter, flat='normal')
  184. class CreateNormalUserProgram(CreateUserProgramBase):
  185. def __init__(self, station, win, color):
  186. super(CreateNormalUserProgram, self).__init__(station, win, color, "创建普通用户")
  187. class CreateManagerUserProgram(CreateUserProgramBase):
  188. def __init__(self, station, win, color):
  189. super(CreateManagerUserProgram, self).__init__(station, win, color, "创建管理员")
  190. self._conf("#4b5cc4", True)
  191. class CreateAutoNormalUserProgram(AdminProgram):
  192. def __init__(self, station, win, color):
  193. super().__init__(station, win, color, "创建自动用户")
  194. self.enter_frame = tk.Frame(self.frame)
  195. self.title: tk.Label = tk.Label(self.enter_frame)
  196. self.enter: tk.Entry = tk.Entry(self.enter_frame)
  197. self.var: tk.Variable = tk.StringVar()
  198. self.btn: tk.Button = tk.Button(self.frame) # create(生成用户) try(计算uid)
  199. self.__conf_font()
  200. def __conf_font(self, n: int = 1):
  201. self.title_font_size = int(16 * n)
  202. self.btn_font_size = int(14 * n)
  203. def conf_gui(self, n: int = 1):
  204. self.__conf_font(n)
  205. title_font = make_font(size=self.title_font_size)
  206. btn_font = make_font(size=self.btn_font_size)
  207. self.enter_frame['bg'] = "#bce672"
  208. self.enter_frame['bd'] = 5
  209. self.enter_frame['relief'] = "ridge"
  210. self.enter_frame.place(relx=0.2, rely=0.3, relwidth=0.6, relheight=0.12)
  211. self.title['font'] = title_font
  212. self.title['text'] = "手机号:"
  213. self.title['bg'] = "#bce672"
  214. self.title['anchor'] = 'e'
  215. self.enter['font'] = title_font
  216. self.enter['textvariable'] = self.var
  217. self.title.place(relx=0.02, rely=0.25, relwidth=0.25, relheight=0.50)
  218. self.enter.place(relx=0.30, rely=0.25, relwidth=0.60, relheight=0.50)
  219. self.btn['font'] = btn_font
  220. self.btn['text'] = "创建用户"
  221. self.btn['bg'] = Config.tk_btn_bg
  222. self.btn['command'] = lambda: self.create_user()
  223. self.btn.place(relx=0.4, rely=0.7, relwidth=0.2, relheight=0.08)
  224. def create_user(self):
  225. phone = self.var.get()
  226. if len(phone) != 11:
  227. self.station.show_msg("UserInfoError", "Please, enter Phone(11)")
  228. event = tk_event.CreateUserEvent(self.station).start(None, None, phone, False)
  229. self.station.push_event(event)
  230. def set_disable(self):
  231. self.btn['state'] = 'disable'
  232. self.enter['state'] = 'disable'
  233. def reset_disable(self):
  234. self.btn['state'] = 'normal'
  235. self.enter['state'] = 'normal'
  236. class CreateGarbageProgram(AdminProgram):
  237. def __init__(self, station, win, color):
  238. super().__init__(station, win, color, "创建垃圾袋")
  239. self.enter_frame = tk.Frame(self.frame)
  240. self.title: List[tk.Label] = [tk.Label(self.enter_frame), tk.Label(self.enter_frame)]
  241. self.enter: List[tk.Entry] = [tk.Entry(self.enter_frame), tk.Entry(self.enter_frame)]
  242. self.var: List[tk.Variable] = [tk.StringVar(), tk.StringVar()]
  243. self.create_btn: tk.Button = tk.Button(self.frame)
  244. self.file_btn: tk.Button = tk.Button(self.frame)
  245. self.__conf_font()
  246. def __conf_font(self, n: int = 1):
  247. self.title_font_size = int(16 * n)
  248. self.btn_font_size = int(14 * n)
  249. def conf_gui(self, n: int = 1):
  250. self.__conf_font(n)
  251. title_font = make_font(size=self.title_font_size)
  252. btn_font = make_font(size=self.btn_font_size)
  253. self.enter_frame['bg'] = "#b69968"
  254. self.enter_frame['bd'] = 5
  255. self.enter_frame['relief'] = "ridge"
  256. self.enter_frame.place(relx=0.2, rely=0.3, relwidth=0.6, relheight=0.17)
  257. height = 0.1
  258. for lb, text, enter, var in zip(self.title, ["数量:", "导出位置:"], self.enter, self.var):
  259. lb['font'] = title_font
  260. lb['text'] = text
  261. lb['bg'] = "#b69968"
  262. lb['anchor'] = 'e'
  263. enter['font'] = title_font
  264. enter['textvariable'] = var
  265. lb.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.35)
  266. enter.place(relx=0.35, rely=height, relwidth=0.60, relheight=0.35)
  267. height += 0.43
  268. for btn, text, x, func in zip([self.create_btn, self.file_btn],
  269. ["创建垃圾袋", "选择目录"],
  270. [0.2, 0.6],
  271. [lambda: self.create_garbage(), lambda: self.choose_file()]):
  272. btn['font'] = btn_font
  273. btn['text'] = text
  274. btn['bg'] = Config.tk_btn_bg
  275. btn['command'] = func
  276. btn.place(relx=x, rely=0.7, relwidth=0.2, relheight=0.08)
  277. def choose_file(self):
  278. path = askdirectory(title='选择二维码导出位置')
  279. self.var[1].set(path)
  280. def create_garbage(self):
  281. try:
  282. count = int(self.var[0].get())
  283. if count <= 0:
  284. raise ValueError
  285. except (ValueError, TypeError):
  286. self.station.show_msg("类型错误", "数量必须为大于0的数字")
  287. else:
  288. path = self.var[1].get()
  289. if len(path) == 0:
  290. path = None
  291. event = tk_event.CreateGarbageEvent(self.station).start(path, count)
  292. self.station.push_event(event)
  293. def set_disable(self):
  294. self.create_btn['state'] = 'disable'
  295. self.file_btn['state'] = 'disable'
  296. set_tk_disable_from_list(self.enter)
  297. def reset_disable(self):
  298. self.create_btn['state'] = 'normal'
  299. self.file_btn['state'] = 'normal'
  300. set_tk_disable_from_list(self.enter, flat='normal')
  301. class ExportProgramBase(AdminProgram):
  302. def __init__(self, station, win, color, title: str):
  303. super().__init__(station, win, color, title)
  304. self.gid_frame = tk.Frame(self.frame)
  305. self.gid_title: List[tk.Label] = [tk.Label(self.gid_frame), tk.Label(self.gid_frame)]
  306. self.gid_enter: List[tk.Entry] = [tk.Entry(self.gid_frame), tk.Entry(self.gid_frame)]
  307. self.gid_var: List[tk.Variable] = [tk.StringVar(), tk.StringVar()]
  308. self.where_frame = tk.Frame(self.frame)
  309. self.where_title: List[tk.Label] = [tk.Label(self.where_frame), tk.Label(self.where_frame)]
  310. self.where_enter: List[tk.Entry] = [tk.Entry(self.where_frame), tk.Entry(self.where_frame)]
  311. self.where_var: List[tk.Variable] = [tk.StringVar(), tk.StringVar()]
  312. self.create_btn: List[tk.Button] = [tk.Button(self.frame), tk.Button(self.frame)]
  313. self.file_btn: List[tk.Button] = [tk.Button(self.frame), tk.Button(self.frame)]
  314. self._conf("", [], [], [])
  315. self.__conf_font()
  316. def _conf(self, bg_color: str, title_id, title_where, title_command):
  317. self.bg_color = bg_color
  318. self.title_id = title_id
  319. self.title_where = title_where
  320. self.title_command = title_command
  321. def __conf_font(self, n: int = 1):
  322. self.title_font_size = int(16 * n)
  323. self.btn_font_size = int(14 * n)
  324. def conf_gui(self, n: int = 1):
  325. self.__conf_font(n)
  326. title_font = make_font(size=self.title_font_size)
  327. btn_font = make_font(size=self.btn_font_size)
  328. self.where_frame['bg'] = self.bg_color
  329. self.where_frame['bd'] = 5
  330. self.where_frame['relief'] = "ridge"
  331. self.where_frame.place(relx=0.2, rely=0.2, relwidth=0.6, relheight=0.17)
  332. self.gid_frame['bg'] = self.bg_color
  333. self.gid_frame['bd'] = 5
  334. self.gid_frame['relief'] = "ridge"
  335. self.gid_frame.place(relx=0.2, rely=0.6, relwidth=0.6, relheight=0.17)
  336. height = 0.1
  337. for lb, text, enter, var, lb_w, text_w, enter_w, var_w in zip(
  338. self.gid_title, self.title_id, self.gid_enter, self.gid_var,
  339. self.where_title, self.title_where, self.where_enter, self.where_var):
  340. lb['font'] = title_font
  341. lb['text'] = text
  342. lb['bg'] = self.bg_color
  343. lb['anchor'] = 'e'
  344. lb_w['font'] = title_font
  345. lb_w['text'] = text_w
  346. lb_w['bg'] = self.bg_color
  347. lb_w['anchor'] = 'e'
  348. enter['textvariable'] = var
  349. enter['font'] = title_font
  350. enter_w['textvariable'] = var_w
  351. enter_w['font'] = title_font
  352. lb.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.35)
  353. enter.place(relx=0.35, rely=height, relwidth=0.60, relheight=0.35)
  354. lb_w.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.35)
  355. enter_w.place(relx=0.35, rely=height, relwidth=0.60, relheight=0.35)
  356. height += 0.43
  357. for btn, text in zip(self.create_btn + self.file_btn, self.title_command):
  358. btn['font'] = btn_font
  359. btn['text'] = text
  360. btn['bg'] = Config.tk_btn_bg
  361. self.create_btn[1]['command'] = self.export_where
  362. self.create_btn[0]['command'] = self.export_id
  363. self.create_btn[1].place(relx=0.2, rely=0.39, relwidth=0.25, relheight=0.08)
  364. self.create_btn[0].place(relx=0.2, rely=0.79, relwidth=0.25, relheight=0.08)
  365. self.file_btn[1]['command'] = self.choose_file_where
  366. self.file_btn[0]['command'] = self.choose_file_id
  367. self.file_btn[1].place(relx=0.6, rely=0.39, relwidth=0.2, relheight=0.08)
  368. self.file_btn[0].place(relx=0.6, rely=0.79, relwidth=0.2, relheight=0.08)
  369. def choose_file_id(self):
  370. path = askdirectory(title='选择二维码导出位置')
  371. self.gid_var[1].set(path)
  372. def choose_file_where(self):
  373. path = askdirectory(title='选择二维码导出位置')
  374. self.where_var[1].set(path)
  375. def export_id(self):
  376. ...
  377. def export_where(self):
  378. ...
  379. def set_disable(self):
  380. set_tk_disable_from_list(self.gid_enter)
  381. set_tk_disable_from_list(self.create_btn)
  382. set_tk_disable_from_list(self.file_btn)
  383. def reset_disable(self):
  384. set_tk_disable_from_list(self.gid_enter, flat='normal')
  385. set_tk_disable_from_list(self.create_btn, flat='normal')
  386. set_tk_disable_from_list(self.file_btn, flat='normal')
  387. class ExportGarbageProgram(ExportProgramBase):
  388. def __init__(self, station, win, color):
  389. super().__init__(station, win, color, "导出垃圾袋二维码")
  390. self._conf("#afdfe4", ["垃圾袋ID:", "导出位置:"], ["条件:", "导出位置:"],
  391. ["根据垃圾袋ID导出", "根据条件导出", "选择目录", "选择目录"])
  392. def export_id(self):
  393. gid = self.gid_var[0].get()
  394. path = self.gid_var[1].get()
  395. event = tk_event.ExportGarbageByIDEvent(self.station).start(path, gid)
  396. self.station.push_event(event)
  397. def export_where(self):
  398. where = self.where_var[0].get()
  399. path = self.where_var[1].get()
  400. event = tk_event.ExportGarbageAdvancedEvent(self.station).start(path, where)
  401. self.station.push_event(event)
  402. class ExportUserProgram(ExportProgramBase):
  403. def __init__(self, station, win, color):
  404. super().__init__(station, win, color, "导出用户二维码")
  405. self._conf("#f69c9f", ["用户ID:", "导出位置:"], ["条件:", "导出位置:"],
  406. ["根据用户ID导出", "根据条件导出", "选择目录", "选择目录"])
  407. def export_id(self):
  408. uid = self.gid_var[0].get()
  409. path = self.gid_var[1].get()
  410. event = tk_event.ExportUserByIDEvent(self.station).start(path, uid)
  411. self.station.push_event(event)
  412. def export_where(self):
  413. where = self.where_var[0].get()
  414. path = self.where_var[1].get()
  415. event = tk_event.ExportUserAdvancedEvent(self.station).start(path, where)
  416. self.station.push_event(event)
  417. class CreateUserFromCSVProgram(AdminProgram):
  418. def __init__(self, station, win, color):
  419. super().__init__(station, win, color, "从CSV导入用户")
  420. self.auto_frame = tk.Frame(self.frame)
  421. self.auto_title: tk.Label = tk.Label(self.auto_frame)
  422. self.auto_enter: tk.Entry = tk.Entry(self.auto_frame)
  423. self.auto_var: tk.Variable = tk.StringVar()
  424. self.enter_frame = tk.Frame(self.frame)
  425. self.path_title: tk.Label = tk.Label(self.enter_frame)
  426. self.path_enter: tk.Entry = tk.Entry(self.enter_frame)
  427. self.path_var: tk.Variable = tk.StringVar()
  428. self.create_btn: List[tk.Button] = [tk.Button(self.frame), tk.Button(self.frame)]
  429. self.file_btn: List[tk.Button] = [tk.Button(self.frame), tk.Button(self.frame)]
  430. self.__conf_font()
  431. def __conf_font(self, n: int = 1):
  432. self.title_font_size = int(16 * n)
  433. self.btn_font_size = int(14 * n)
  434. def conf_gui(self, n: int = 1):
  435. self.__conf_font(n)
  436. title_font = make_font(size=self.title_font_size)
  437. btn_font = make_font(size=self.btn_font_size)
  438. self.enter_frame['bg'] = "#EEE8AA"
  439. self.enter_frame['bd'] = 5
  440. self.enter_frame['relief'] = "ridge"
  441. self.enter_frame.place(relx=0.2, rely=0.2, relwidth=0.6, relheight=0.12)
  442. self.auto_frame['bg'] = "#EEE8AA"
  443. self.auto_frame['bd'] = 5
  444. self.auto_frame['relief'] = "ridge"
  445. self.auto_frame.place(relx=0.2, rely=0.6, relwidth=0.6, relheight=0.12)
  446. self.auto_title['font'] = title_font
  447. self.auto_title['text'] = "CSV文件:"
  448. self.auto_title['bg'] = "#EEE8AA"
  449. self.auto_title['anchor'] = 'e'
  450. self.path_title['font'] = title_font
  451. self.path_title['text'] = "CSV文件:"
  452. self.path_title['bg'] = "#EEE8AA"
  453. self.path_title['anchor'] = 'e'
  454. self.auto_enter['textvariable'] = self.auto_var
  455. self.auto_enter['font'] = title_font
  456. self.path_enter['textvariable'] = self.path_var
  457. self.path_enter['font'] = title_font
  458. self.auto_title.place(relx=0.01, rely=0.25, relwidth=0.30, relheight=0.50)
  459. self.auto_enter.place(relx=0.35, rely=0.25, relwidth=0.60, relheight=0.50)
  460. self.path_title.place(relx=0.01, rely=0.25, relwidth=0.30, relheight=0.50)
  461. self.path_enter.place(relx=0.35, rely=0.25, relwidth=0.60, relheight=0.50)
  462. for btn, text in zip(self.create_btn + self.file_btn,
  463. ["创建用户", "创建自动用户", "选择CSV", "选择CSV"]):
  464. btn['font'] = btn_font
  465. btn['text'] = text
  466. btn['bg'] = Config.tk_btn_bg
  467. self.create_btn[0]['command'] = self.create
  468. self.create_btn[1]['command'] = self.create_auto
  469. self.create_btn[0].place(relx=0.2, rely=0.34, relwidth=0.25, relheight=0.08)
  470. self.create_btn[1].place(relx=0.2, rely=0.74, relwidth=0.25, relheight=0.08)
  471. self.file_btn[0]['command'] = self.choose_file
  472. self.file_btn[1]['command'] = self.choose_file_auto
  473. self.file_btn[0].place(relx=0.6, rely=0.34, relwidth=0.2, relheight=0.08)
  474. self.file_btn[1].place(relx=0.6, rely=0.74, relwidth=0.2, relheight=0.08)
  475. def choose_file_auto(self):
  476. path = askopenfilename(title='选择CSV文件', filetypes=[("CSV", ".csv")])
  477. self.auto_var.set(path)
  478. def choose_file(self):
  479. path = askopenfilename(title='选择CSV文件', filetypes=[("CSV", ".csv")])
  480. self.path_var.set(path)
  481. def create_auto(self):
  482. path = self.auto_var.get()
  483. event = tk_event.CreateAutoUserFromCSVEvent(self.station).start(path)
  484. self.station.push_event(event)
  485. def create(self):
  486. path = self.path_var.get()
  487. event = tk_event.CreateUserFromCSVEvent(self.station).start(path)
  488. self.station.push_event(event)
  489. def set_disable(self):
  490. self.auto_enter['state'] = 'disable'
  491. self.path_enter['state'] = 'disable'
  492. set_tk_disable_from_list(self.create_btn)
  493. set_tk_disable_from_list(self.file_btn)
  494. def reset_disable(self):
  495. self.auto_enter['state'] = 'normal'
  496. self.path_enter['state'] = 'normal'
  497. set_tk_disable_from_list(self.create_btn, flat='normal')
  498. set_tk_disable_from_list(self.file_btn, flat='normal')
  499. class DeleteUserProgram(AdminProgram):
  500. def __init__(self, station, win, color):
  501. super().__init__(station, win, color, "删除用户")
  502. self.uid_frame = tk.Frame(self.frame)
  503. self.uid_title: tk.Label = tk.Label(self.uid_frame)
  504. self.uid_enter: tk.Entry = tk.Entry(self.uid_frame)
  505. self.uid_var: tk.Variable = tk.StringVar()
  506. self.name_frame = tk.Frame(self.frame)
  507. self.name_title: List[tk.Label] = [tk.Label(self.name_frame) for _ in range(2)]
  508. self.name_enter: List[tk.Entry] = [tk.Entry(self.name_frame) for _ in range(2)]
  509. self.name_var: List[tk.Variable] = [tk.StringVar() for _ in range(2)]
  510. self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(2)] # uid-del, name-passwd-del
  511. self.__conf_font()
  512. def __conf_font(self, n: int = 1):
  513. self.title_font_size = int(16 * n)
  514. self.btn_font_size = int(14 * n)
  515. def conf_gui(self, n: int = 1):
  516. self.__conf_font(n)
  517. title_font = make_font(size=self.title_font_size)
  518. btn_font = make_font(size=self.btn_font_size)
  519. self.uid_frame['bg'] = "#FA8072"
  520. self.uid_frame['bd'] = 5
  521. self.uid_frame['relief'] = "ridge"
  522. self.uid_frame.place(relx=0.2, rely=0.20, relwidth=0.6, relheight=0.10)
  523. self.name_frame['bg'] = "#FA8072"
  524. self.name_frame['bd'] = 5
  525. self.name_frame['relief'] = "ridge"
  526. self.name_frame.place(relx=0.2, rely=0.48, relwidth=0.6, relheight=0.25)
  527. height = 0.17
  528. for lb, text, enter, var in zip(self.name_title, ["用户名:", "密码:"], self.name_enter, self.name_var):
  529. lb['font'] = title_font
  530. lb['text'] = text
  531. lb['bg'] = "#FA8072"
  532. lb['anchor'] = 'e'
  533. enter['font'] = title_font
  534. enter['textvariable'] = var
  535. lb.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.20)
  536. enter.place(relx=0.35, rely=height, relwidth=0.60, relheight=0.20)
  537. height += 0.45
  538. self.uid_title['font'] = title_font
  539. self.uid_title['text'] = "用户ID:"
  540. self.uid_title['bg'] = "#FA8072"
  541. self.uid_title['anchor'] = 'e'
  542. self.uid_enter['font'] = title_font
  543. self.uid_enter['textvariable'] = self.uid_var
  544. self.uid_title.place(relx=0.01, rely=0.25, relwidth=0.30, relheight=0.50)
  545. self.uid_enter.place(relx=0.35, rely=0.25, relwidth=0.60, relheight=0.50)
  546. for btn, text, func in zip(self.btn,
  547. ["通过用户ID删除", "通过用户名删除"],
  548. [lambda: self.del_by_uid(), lambda: self.del_by_name()]):
  549. btn['font'] = btn_font
  550. btn['text'] = text
  551. btn['bg'] = Config.tk_btn_bg
  552. btn['command'] = func
  553. self.btn[0].place(relx=0.6, rely=0.32, relwidth=0.2, relheight=0.08)
  554. self.btn[1].place(relx=0.6, rely=0.75, relwidth=0.2, relheight=0.08)
  555. def del_by_uid(self):
  556. uid = self.uid_var.get()
  557. if len(uid) != 32:
  558. self.station.show_warning("用户ID错误", "用户ID必须为32位")
  559. return
  560. event = tk_event.DelUserEvent(self.station).start(uid)
  561. self.station.push_event(event)
  562. def del_by_name(self):
  563. name = self.name_var[0].get()
  564. passwd = self.name_var[1].get()
  565. if len(name) == 0 or len(passwd) == 0:
  566. self.station.show_warning("用户名或密码错误", "请输入用户名和密码")
  567. return
  568. uid = create_uid(name, passwd)
  569. event = tk_event.DelUserEvent(self.station).start(uid)
  570. self.station.push_event(event)
  571. def set_disable(self):
  572. set_tk_disable_from_list(self.btn)
  573. set_tk_disable_from_list(self.name_enter)
  574. self.uid_enter['state'] = 'disable'
  575. def reset_disable(self):
  576. set_tk_disable_from_list(self.btn, flat='normal')
  577. set_tk_disable_from_list(self.name_enter, flat='normal')
  578. self.uid_enter['state'] = 'normal'
  579. class DeleteUsersProgram(AdminProgram):
  580. def __init__(self, station, win, color):
  581. super().__init__(station, win, color, "删除多个用户")
  582. self.enter_frame = tk.Frame(self.frame)
  583. self.title: tk.Label = tk.Label(self.enter_frame)
  584. self.enter: tk.Entry = tk.Entry(self.enter_frame)
  585. self.var: tk.Variable = tk.StringVar()
  586. self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(2)] # del, scan
  587. self.__conf_font()
  588. def __conf_font(self, n: int = 1):
  589. self.title_font_size = int(16 * n)
  590. self.btn_font_size = int(14 * n)
  591. def conf_gui(self, n: int = 1):
  592. self.__conf_font(n)
  593. title_font = make_font(size=self.title_font_size)
  594. btn_font = make_font(size=self.btn_font_size)
  595. self.enter_frame['bg'] = "#48c0a3"
  596. self.enter_frame['bd'] = 5
  597. self.enter_frame['relief'] = "ridge"
  598. self.enter_frame.place(relx=0.2, rely=0.30, relwidth=0.6, relheight=0.10)
  599. self.title['font'] = title_font
  600. self.title['text'] = "条件:"
  601. self.title['anchor'] = 'e'
  602. self.title['bg'] = "#48c0a3"
  603. self.enter['font'] = title_font
  604. self.enter['textvariable'] = self.var
  605. self.title.place(relx=0.01, rely=0.25, relwidth=0.30, relheight=0.50)
  606. self.enter.place(relx=0.35, rely=0.25, relwidth=0.60, relheight=0.50)
  607. for btn, text, x, func in zip(self.btn,
  608. ["删除", "扫描"],
  609. [0.2, 0.6],
  610. [lambda: self.delete_user(), lambda: self.scan_user()]):
  611. btn['font'] = btn_font
  612. btn['text'] = text
  613. btn['bg'] = Config.tk_btn_bg
  614. btn['command'] = func
  615. btn.place(relx=x, rely=0.6, relwidth=0.2, relheight=0.08)
  616. def delete_user(self):
  617. where = self.var.get()
  618. if len(where) == 0:
  619. self.station.show_warning("条件错误", "条件必须为正确的SQL语句")
  620. return
  621. event = tk_event.DelUserFromWhereEvent(self.station).start(where)
  622. self.station.push_event(event)
  623. def scan_user(self):
  624. where = self.var.get()
  625. if len(where) == 0:
  626. self.station.show_warning("条件错误", "条件必须为正确的SQL语句")
  627. return
  628. event = tk_event.DelUserFromWhereScanEvent(self.station).start(where)
  629. self.station.push_event(event)
  630. def set_disable(self):
  631. set_tk_disable_from_list(self.btn)
  632. self.enter['state'] = 'disable'
  633. def reset_disable(self):
  634. set_tk_disable_from_list(self.btn, flat='normal')
  635. self.enter['state'] = 'normal'
  636. class DeleteGarbageProgramBase(AdminProgram):
  637. def __init__(self, station, win, color, title: str):
  638. super().__init__(station, win, color, title)
  639. self.enter_frame = tk.Frame(self.frame)
  640. self.title: tk.Label = tk.Label(self.enter_frame)
  641. self.enter: tk.Entry = tk.Entry(self.enter_frame)
  642. self.var: tk.Variable = tk.StringVar()
  643. self.int_var: tk.Variable = tk.IntVar()
  644. self.int_var.set(0)
  645. self.radio: List[tk.Radiobutton] = [tk.Radiobutton(self.frame) for _ in range(4)]
  646. self.btn: tk.Button = tk.Button(self.frame)
  647. self.__conf_font()
  648. self._conf()
  649. def _conf(self, title: str = "垃圾袋ID:", color: str = "#b69968", support_del_all: bool = True):
  650. self.frame_title = title
  651. self.frame_color = color
  652. self.support_del_all = support_del_all
  653. def __conf_font(self, n: int = 1):
  654. self.title_font_size = int(16 * n)
  655. self.btn_font_size = int(14 * n)
  656. def conf_gui(self, n: int = 1):
  657. self.__conf_font(n)
  658. title_font = make_font(size=self.title_font_size)
  659. btn_font = make_font(size=self.btn_font_size)
  660. self.enter_frame['bg'] = self.frame_color
  661. self.enter_frame['bd'] = 5
  662. self.enter_frame['relief'] = "ridge"
  663. self.enter_frame.place(relx=0.2, rely=0.30, relwidth=0.6, relheight=0.10)
  664. self.title['font'] = title_font
  665. self.title['text'] = self.frame_title
  666. self.title['bg'] = self.frame_color
  667. self.title['anchor'] = 'e'
  668. self.enter['font'] = title_font
  669. self.enter['textvariable'] = self.var
  670. self.title.place(relx=0.01, rely=0.25, relwidth=0.30, relheight=0.50)
  671. self.enter.place(relx=0.35, rely=0.25, relwidth=0.60, relheight=0.50)
  672. for i in range(4):
  673. radio = self.radio[i]
  674. radio['font'] = btn_font
  675. radio['text'] = ['均可', '仅未使用', '仅待检测', '仅已检测'][i]
  676. radio['bg'] = self.color
  677. radio['value'] = i
  678. radio['variable'] = self.int_var
  679. radio['anchor'] = 'w'
  680. if not self.support_del_all:
  681. self.int_var.set(1)
  682. self.radio[0]['state'] = 'disable'
  683. self.radio[0].place(relx=0.20, rely=0.43, relwidth=0.20, relheight=0.1)
  684. self.radio[1].place(relx=0.60, rely=0.43, relwidth=0.20, relheight=0.1)
  685. self.radio[2].place(relx=0.20, rely=0.55, relwidth=0.20, relheight=0.1)
  686. self.radio[3].place(relx=0.60, rely=0.55, relwidth=0.20, relheight=0.1)
  687. self.btn['font'] = btn_font
  688. self.btn['text'] = '删除'
  689. self.btn['bg'] = Config.tk_btn_bg
  690. self.btn['command'] = lambda: self.delete_garbage()
  691. self.btn.place(relx=0.4, rely=0.68, relwidth=0.2, relheight=0.08)
  692. def delete_garbage(self):
  693. ...
  694. def set_disable(self):
  695. self.enter['state'] = 'disable'
  696. self.btn['state'] = 'disable'
  697. def reset_disable(self):
  698. self.enter['state'] = 'normal'
  699. self.btn['state'] = 'normal'
  700. class DeleteGarbageProgram(DeleteGarbageProgramBase):
  701. def __init__(self, station, win, color):
  702. super(DeleteGarbageProgram, self).__init__(station, win, color, "删除垃圾袋")
  703. def delete_garbage(self):
  704. where = self.int_var.get()
  705. assert where in [0, 1, 2, 3]
  706. gid = self.var.get()
  707. if len(gid) == 0:
  708. self.station.show_warning("垃圾袋ID错误", "请输入正确的垃圾袋ID")
  709. return
  710. event = tk_event.DelGarbageEvent(self.station).start(gid, where)
  711. self.station.push_event(event)
  712. class DeleteGarbageMoreProgram(DeleteGarbageProgramBase):
  713. def __init__(self, station, win, color):
  714. super(DeleteGarbageMoreProgram, self).__init__(station, win, color, "删除多个垃圾袋")
  715. self.scan_btn = tk.Button(self.frame)
  716. self._conf("条件:", "#f58f98", False)
  717. def conf_gui(self, n: int = 1):
  718. super(DeleteGarbageMoreProgram, self).conf_gui(n)
  719. self.btn.place_forget()
  720. self.btn.place(relx=0.2, rely=0.68, relwidth=0.2, relheight=0.08)
  721. self.scan_btn['font'] = make_font(size=self.btn_font_size)
  722. self.scan_btn['text'] = '扫描'
  723. self.scan_btn['bg'] = Config.tk_btn_bg
  724. self.scan_btn['command'] = self.scan_garbage
  725. self.scan_btn.place(relx=0.6, rely=0.68, relwidth=0.2, relheight=0.08)
  726. def set_disable(self):
  727. super(DeleteGarbageMoreProgram, self).set_disable()
  728. self.scan_btn['state'] = 'disable'
  729. def reset_disable(self):
  730. super(DeleteGarbageMoreProgram, self).reset_disable()
  731. self.scan_btn['state'] = 'normal'
  732. def delete_garbage(self):
  733. where = self.int_var.get()
  734. assert where in [1, 2, 3]
  735. where_sql = self.var.get()
  736. if len(where_sql) == 0:
  737. self.station.show_warning("条件错误", "条件必须为正确的SQL语句")
  738. return
  739. event = tk_event.DelGarbageWhereEvent(self.station).start(where, where_sql)
  740. self.station.push_event(event)
  741. def scan_garbage(self):
  742. where = self.int_var.get()
  743. assert where in [1, 2, 3]
  744. where_sql = self.var.get()
  745. if len(where_sql) == 0:
  746. self.station.show_warning("条件错误", "条件必须为正确的SQL语句")
  747. return
  748. event = tk_event.DelGarbageWhereScanEvent(self.station).start(where, where_sql)
  749. self.station.push_event(event)
  750. class DeleteAllGarbageProgram(AdminProgram):
  751. def __init__(self, station, win, color):
  752. super().__init__(station, win, color, "删除所有垃圾袋")
  753. self.dangerous: tk.Label = tk.Label(self.frame)
  754. self.enter_frame = tk.Frame(self.frame)
  755. self.title: tk.Label = tk.Label(self.enter_frame)
  756. self.enter: tk.Entry = tk.Entry(self.enter_frame)
  757. self.var: tk.Variable = tk.StringVar()
  758. self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(2)] # del, scan
  759. self.__conf_font()
  760. def __conf_font(self, n: int = 1):
  761. self.danger_font_size = int(20 * n)
  762. self.title_font_size = int(16 * n)
  763. self.btn_font_size = int(14 * n)
  764. def conf_gui(self, n: int = 1):
  765. self.__conf_font(n)
  766. danger_font = make_font(size=self.danger_font_size, weight="bold", underline=1)
  767. title_font = make_font(size=self.title_font_size)
  768. btn_font = make_font(size=self.btn_font_size)
  769. danger_btn_font = make_font(size=self.btn_font_size, weight="bold", overstrike=1)
  770. self.dangerous['bg'] = self.color
  771. self.dangerous['font'] = danger_font
  772. self.dangerous['fg'] = "#f20c00"
  773. self.dangerous['text'] = ("确定要从数据库删除所有垃圾袋吗?\n"
  774. "请输入[admin]用户的密码再继续操作.\n"
  775. "只有[admin]用户具有该操作的权限.\n"
  776. "这是相当危险的操作.\n"
  777. "操作后数据库可能无法恢复原数据.\n"
  778. "SuperHuan和程序的缔造者不会对\n"
  779. "此操作负责.\n"
  780. "删库跑路可不是一件好事.\n"
  781. "请遵守当地法律法规.")
  782. self.dangerous.place(relx=0.05, rely=0.03, relwidth=0.9, relheight=0.53)
  783. self.enter_frame['bg'] = "#f20c00"
  784. self.enter_frame['bd'] = 5
  785. self.enter_frame['relief'] = "ridge"
  786. self.enter_frame.place(relx=0.2, rely=0.60, relwidth=0.6, relheight=0.10)
  787. self.title['font'] = title_font
  788. self.title['text'] = "密码:"
  789. self.title['bg'] = "#f20c00"
  790. self.title['anchor'] = 'e'
  791. self.enter['font'] = title_font
  792. self.enter['textvariable'] = self.var
  793. self.title.place(relx=0.01, rely=0.25, relwidth=0.30, relheight=0.50)
  794. self.enter.place(relx=0.35, rely=0.25, relwidth=0.60, relheight=0.50)
  795. for btn, text, x in zip(self.btn, ["删除", "扫描"], [0.2, 0.6]):
  796. btn['text'] = text
  797. btn.place(relx=x, rely=0.78, relwidth=0.2, relheight=0.08)
  798. self.btn[0]['font'] = danger_btn_font
  799. self.btn[0]['bg'] = "#f20c00"
  800. self.btn[0]['command'] = lambda: self.delete_garbage()
  801. self.btn[1]['font'] = btn_font
  802. self.btn[1]['bg'] = Config.tk_btn_bg
  803. self.btn[1]['command'] = lambda: self.scan_garbage()
  804. def scan_garbage(self):
  805. event = tk_event.DelAllGarbageScanEvent(self.station) # 不需要start
  806. self.station.push_event(event)
  807. def delete_garbage(self):
  808. passwd = self.var.get()
  809. if len(passwd) == 0:
  810. self.station.show_warning("密码错误", "请输入正确的[admin]用户密码")
  811. user = find_user_by_name('admin', passwd, self.station.get_db())
  812. if user is None or not user.is_manager():
  813. self.station.show_warning("密码错误", "请输入正确的[admin]用户密码")
  814. return
  815. event = tk_event.DelAllGarbageEvent(self.station) # 不需要start
  816. self.station.push_event(event)
  817. def set_disable(self):
  818. set_tk_disable_from_list(self.btn)
  819. self.enter['state'] = 'disable'
  820. def reset_disable(self):
  821. set_tk_disable_from_list(self.btn, flat='normal')
  822. self.enter['state'] = 'normal'
  823. class SearchProgramBase(AdminProgram, metaclass=abc.ABCMeta):
  824. def __init__(self, station, win, color, title: str):
  825. super().__init__(station, win, color, title)
  826. self.view_frame = tk.Frame(self.frame)
  827. self.view = ttk.Treeview(self.view_frame)
  828. self.y_scroll = tk.Scrollbar(self.view_frame)
  829. self.x_scroll = tk.Scrollbar(self.view_frame)
  830. def conf_view_gui(self, columns: list, relx, rely, relwidth, relheight,
  831. x_scroll=0.05, y_scroll=0.02, color: str = "#FA8072"):
  832. self.view_frame['bg'] = color
  833. self.view_frame['bd'] = 2
  834. self.view_frame['relief'] = "ridge"
  835. self.view_frame.place(relx=relx, rely=rely, relwidth=relwidth, relheight=relheight)
  836. self.view['columns'] = columns
  837. self.view['show'] = 'headings'
  838. self.view['selectmode'] = 'none'
  839. for i in columns:
  840. self.view.column(i, anchor="c")
  841. self.view.heading(i, text=i)
  842. self.y_scroll['orient'] = 'vertical'
  843. self.y_scroll['command'] = self.view.yview
  844. self.view['yscrollcommand'] = self.y_scroll.set
  845. self.x_scroll['orient'] = 'horizontal'
  846. self.x_scroll['command'] = self.view.xview
  847. self.view['xscrollcommand'] = self.x_scroll.set
  848. self.view.place(relx=0.0, rely=0.0, relwidth=1 - y_scroll, relheight=1 - x_scroll)
  849. self.y_scroll.place(relx=0.98, rely=0.0, relwidth=y_scroll, relheight=1.0)
  850. self.x_scroll.place(relx=0.0, rely=1 - x_scroll, relwidth=1 - y_scroll, relheight=x_scroll)
  851. class SearchUserProgram(SearchProgramBase):
  852. def __init__(self, station, win, color):
  853. super().__init__(station, win, color, "搜索用户")
  854. self.enter_frame = tk.Frame(self.frame)
  855. self.title: List[tk.Label] = [tk.Label(self.enter_frame) for _ in range(3)]
  856. self.enter: List[tk.Entry] = [tk.Entry(self.enter_frame) for _ in range(3)]
  857. self.var: List[tk.Variable] = [tk.StringVar() for _ in range(3)]
  858. self.check: List[Tuple[tk.Checkbutton, tk.Variable]] = [(tk.Checkbutton(self.enter_frame), tk.IntVar())
  859. for _ in range(3)]
  860. self.btn: tk.Button = tk.Button(self.frame)
  861. self._columns = ["UserID", "Name", "Phone", "Score", "Reputation", "IsManager"]
  862. self._columns_ch = ["用户ID[UserID]", "用户名[Name]", "手机号[Phone]",
  863. "积分[Score]", "垃圾分类信用[Reputation]", "是否管理员[IsManager]"]
  864. self.__conf_font()
  865. def __conf_font(self, n: int = 1):
  866. self.title_font_size = int(16 * n)
  867. self.btn_font_size = int(14 * n)
  868. def conf_gui(self, n: int = 1):
  869. self.__conf_font(n)
  870. title_font = make_font(size=self.title_font_size)
  871. btn_font = make_font(size=self.btn_font_size)
  872. self.enter_frame['bg'] = "#FA8072"
  873. self.enter_frame['bd'] = 5
  874. self.enter_frame['relief'] = "ridge"
  875. self.enter_frame.place(relx=0.2, rely=0.0, relwidth=0.6, relheight=0.30)
  876. height = 0.1
  877. for lb, text, enter, var, check in zip(self.title,
  878. ["用户ID:", "用户名:", "手机号:"],
  879. self.enter, self.var, self.check):
  880. lb['font'] = title_font
  881. lb['text'] = text
  882. lb['bg'] = "#FA8072"
  883. lb['anchor'] = 'e'
  884. enter['font'] = title_font
  885. enter['textvariable'] = var
  886. check[0]['font'] = title_font
  887. check[0]['text'] = ''
  888. check[0]['bg'] = "#FA8072"
  889. check[0]['variable'] = check[1]
  890. check[1].set(1)
  891. lb.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.17)
  892. enter.place(relx=0.35, rely=height, relwidth=0.55, relheight=0.17)
  893. check[0].place(relx=0.92, rely=height, relwidth=0.04, relheight=0.17)
  894. height += 0.30
  895. self.btn['font'] = btn_font
  896. self.btn['text'] = "搜索"
  897. self.btn['bg'] = Config.tk_btn_bg
  898. self.btn['command'] = self.search_user
  899. self.btn.place(relx=0.4, rely=0.9, relwidth=0.2, relheight=0.08)
  900. self.conf_view_gui(self._columns_ch, relx=0.05, rely=0.32, relwidth=0.9, relheight=0.55)
  901. def search_user(self):
  902. use_uid = self.check[0][1].get()
  903. use_name = self.check[1][1].get()
  904. use_phone = self.check[2][1].get()
  905. uid = None
  906. name = None
  907. phone = None
  908. if use_uid:
  909. uid = self.var[0].get()
  910. if len(uid) == 0:
  911. uid = None
  912. if use_name:
  913. name = self.var[1].get()
  914. if len(name) == 0:
  915. name = None
  916. if use_phone:
  917. phone = self.var[2].get()
  918. if len(phone) == 0:
  919. phone = None
  920. event = tk_event.SearchUserEvent(self.station).start(self._columns, uid, name, phone, self)
  921. self.station.push_event(event)
  922. def set_disable(self):
  923. self.btn['state'] = 'disable'
  924. set_tk_disable_from_list(self.enter)
  925. def reset_disable(self):
  926. self.btn['state'] = 'normal'
  927. set_tk_disable_from_list(self.enter, flat='normal')
  928. class SearchAdvancedProgramBase(SearchProgramBase, metaclass=abc.ABCMeta):
  929. def __init__(self, station, win, color, title: str):
  930. super().__init__(station, win, color, title)
  931. self.enter_frame = tk.Frame(self.frame)
  932. self.title: tk.Label = tk.Label(self.enter_frame)
  933. self.enter: tk.Entry = tk.Entry(self.enter_frame)
  934. self.var: tk.Variable = tk.StringVar()
  935. self.btn: tk.Button = tk.Button(self.frame)
  936. self._conf([], [], "#FA8072") # 默认颜色
  937. self.__conf_font()
  938. def _conf(self, columns: list, columns_ch: list, bg_color):
  939. self.bg_color = bg_color
  940. self._columns = columns
  941. self._columns_ch = columns_ch
  942. return self
  943. def __conf_font(self, n: int = 1):
  944. self.title_font_size = int(16 * n)
  945. self.btn_font_size = int(14 * n)
  946. def conf_gui(self, n: int = 1):
  947. self.__conf_font(n)
  948. title_font = make_font(size=self.title_font_size)
  949. btn_font = make_font(size=self.btn_font_size)
  950. self.enter_frame['bg'] = self.bg_color
  951. self.enter_frame['bd'] = 5
  952. self.enter_frame['relief'] = "ridge"
  953. self.enter_frame.place(relx=0.2, rely=0.00, relwidth=0.6, relheight=0.10)
  954. self.title['font'] = title_font
  955. self.title['bg'] = self.bg_color
  956. self.title['text'] = "条件:"
  957. self.title['anchor'] = 'e'
  958. self.enter['font'] = title_font
  959. self.enter['textvariable'] = self.var
  960. self.title.place(relx=0.01, rely=0.25, relwidth=0.30, relheight=0.50)
  961. self.enter.place(relx=0.35, rely=0.25, relwidth=0.60, relheight=0.50)
  962. self.btn['text'] = "搜索"
  963. self.btn['font'] = btn_font
  964. self.btn['bg'] = Config.tk_btn_bg
  965. self.btn['command'] = self.search
  966. self.btn.place(relx=0.4, rely=0.9, relwidth=0.2, relheight=0.08)
  967. self.conf_view_gui(self._columns_ch, relx=0.05, rely=0.12, relwidth=0.9, relheight=0.76)
  968. def search(self):
  969. ...
  970. def set_disable(self):
  971. self.btn['state'] = 'disable'
  972. self.enter['state'] = 'disable'
  973. def reset_disable(self):
  974. self.btn['state'] = 'normal'
  975. self.enter['state'] = 'normal'
  976. class SearchUserAdvancedProgram(SearchAdvancedProgramBase):
  977. def __init__(self, station, win, color):
  978. super(SearchUserAdvancedProgram, self).__init__(station, win, color, "高级搜索-用户")
  979. columns = ["UserID", "Name", "Phone", "Score", "Reputation", "IsManager"]
  980. columns_ch = ["用户ID[UserID]", "用户名[Name]", "手机号[Phone]",
  981. "积分[Score]", "垃圾分类信用[Reputation]", "是否管理员[IsManager]"]
  982. self._conf(columns, columns_ch, '#48c0a3')
  983. def search(self):
  984. where = self.var.get()
  985. event = tk_event.SearchUserAdvancedEvent(self.station).start(self._columns, where, self)
  986. self.station.push_event(event)
  987. class SearchGarbageProgram(SearchProgramBase):
  988. def __init__(self, station, win, color):
  989. super().__init__(station, win, color, "搜索垃圾袋")
  990. self.enter_frame = tk.Frame(self.frame)
  991. self.title: List[tk.Label] = [tk.Label(self.enter_frame) for _ in range(8)]
  992. self.enter: List[tk.Entry] = [tk.Entry(self.enter_frame) for _ in range(8)]
  993. self.var: List[tk.Variable] = [tk.StringVar() for _ in range(8)]
  994. self.check: List[Tuple[tk.Checkbutton, tk.Variable]] = [(tk.Checkbutton(self.enter_frame), tk.IntVar())
  995. for _ in range(8)]
  996. self._columns = ["GarbageID", "UserID", "CheckerID", "CreateTime", "UseTime", "Location", "GarbageType",
  997. "CheckResult"]
  998. self._columns_zh = ["垃圾袋ID[GarbageID]", "使用者ID[UserID]", "检测者ID[CheckerID]", "创建时间[CreateTime]",
  999. "使用时间[UseTime]", "使用地点[Location]", "垃圾类型[GarbageType]", "检测结果[CheckResult]"]
  1000. self.btn: tk.Button = tk.Button(self.frame)
  1001. self.__conf_font()
  1002. def __conf_font(self, n: int = 1):
  1003. self.title_font_size = int(16 * n)
  1004. self.btn_font_size = int(14 * n)
  1005. def conf_gui(self, n: int = 1):
  1006. self.__conf_font(n)
  1007. title_font = make_font(size=self.title_font_size)
  1008. btn_font = make_font(size=self.btn_font_size)
  1009. self.enter_frame['bg'] = "#7bbfea"
  1010. self.enter_frame['bd'] = 5
  1011. self.enter_frame['relief'] = "ridge"
  1012. self.enter_frame.place(relx=0.2, rely=0.0, relwidth=0.6, relheight=0.47)
  1013. height = 0.02
  1014. for lb, text, enter, var, check in zip(self.title,
  1015. ["垃圾袋ID:", "使用者ID:", "检查者ID:", "创建时间:", "使用时间:",
  1016. "使用地点:", "垃圾类型:", "检测结果:"],
  1017. self.enter, self.var, self.check):
  1018. lb['font'] = title_font
  1019. lb['text'] = text
  1020. lb['bg'] = "#7bbfea"
  1021. lb['anchor'] = 'e'
  1022. enter['font'] = title_font
  1023. enter['textvariable'] = var
  1024. check[0]['font'] = title_font
  1025. check[0]['bg'] = "#7bbfea"
  1026. check[0]['text'] = ''
  1027. check[0]['variable'] = check[1]
  1028. check[1].set(1)
  1029. lb.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.10)
  1030. enter.place(relx=0.35, rely=height, relwidth=0.55, relheight=0.10)
  1031. check[0].place(relx=0.92, rely=height, relwidth=0.04, relheight=0.10)
  1032. height += 0.121
  1033. self.btn['font'] = btn_font
  1034. self.btn['bg'] = Config.tk_btn_bg
  1035. self.btn['text'] = "Search"
  1036. self.btn['command'] = self.search_user
  1037. self.btn.place(relx=0.4, rely=0.9, relwidth=0.2, relheight=0.08)
  1038. self.conf_view_gui(self._columns_zh, relx=0.05, rely=0.49, relwidth=0.9, relheight=0.38, x_scroll=0.07)
  1039. def search_user(self):
  1040. keys = ["gid", "uid", "cuid", "create_time", "use_time", "loc", "type_", "check"]
  1041. key_values = {}
  1042. for i, key in enumerate(keys):
  1043. ck = self.check[i][1].get()
  1044. if ck:
  1045. res = self.enter[i].get()
  1046. if len(res) > 0:
  1047. key_values[key] = res
  1048. continue
  1049. key_values[key] = None
  1050. event = tk_event.SearchGarbageEvent(self.station).start(self._columns, key_values, self)
  1051. self.station.push_event(event)
  1052. def set_disable(self):
  1053. self.btn['state'] = 'disable'
  1054. set_tk_disable_from_list(self.enter)
  1055. def reset_disable(self):
  1056. self.btn['state'] = 'normal'
  1057. set_tk_disable_from_list(self.enter, flat='normal')
  1058. class SearchGarbageAdvancedProgram(SearchAdvancedProgramBase):
  1059. def __init__(self, station, win, color):
  1060. super(SearchGarbageAdvancedProgram, self).__init__(station, win, color, "高级搜索-垃圾袋")
  1061. columns = ["GarbageID", "UserID", "CheckerID", "CreateTime", "UseTime", "Location", "GarbageType",
  1062. "CheckResult"]
  1063. columns_zh = ["垃圾袋ID[GarbageID]", "使用者ID[UserID]", "检测者ID[CheckerID]", "创建时间[CreateTime]",
  1064. "使用时间[UseTime]", "使用地点[Location]", "垃圾类型[GarbageType]", "检测结果[CheckResult]"]
  1065. self._conf(columns, columns_zh, '#d1923f')
  1066. def search(self):
  1067. where = self.var.get()
  1068. event = tk_event.SearchGarbageAdvancedEvent(self.station).start(self._columns, where, self)
  1069. self.station.push_event(event)
  1070. class SearchAdvancedProgram(SearchAdvancedProgramBase):
  1071. def __init__(self, station, win, color):
  1072. super(SearchAdvancedProgram, self).__init__(station, win, color, "高级搜索")
  1073. columns = ["GarbageID", "UserID", "UserName", "UserPhone", "UserScore",
  1074. "UserReputation", "CheckerID", "CheckerName", "CheckerPhone",
  1075. "CreateTime", "UseTime", "Location", "GarbageType", "CheckResult"]
  1076. columns_zh = ["垃圾袋ID[GarbageID]", "使用者ID[UserID]", "使用者名[UserName]", "使用者手机号[UserPhone]",
  1077. "使用者积分[UserScore]", "使用者垃圾分类信用[UserReputation]", "检测者ID[CheckerID]",
  1078. "检测这名[CheckerName]", "检测者手机号[CheckerPhone]", "创建时间[CreateTime]", "使用时间[UseTime]",
  1079. "使用地点[Location]", "垃圾类型[GarbageType]", "检测结果[CheckResult]"]
  1080. self._conf(columns, columns_zh, '#426ab3')
  1081. def search(self):
  1082. where = self.var.get()
  1083. event = tk_event.SearchAdvancedEvent(self.station).start(self._columns, where, self)
  1084. self.station.push_event(event)
  1085. class UpdateUserProgramBase(AdminProgram):
  1086. def __init__(self, station, win, color, title: str):
  1087. super().__init__(station, win, color, title)
  1088. self.enter_frame = tk.Frame(self.frame)
  1089. self.title: List[tk.Label] = [tk.Label(self.enter_frame) for _ in range(2)]
  1090. self.enter: List[tk.Entry] = [tk.Entry(self.enter_frame) for _ in range(2)]
  1091. self.var: List[tk.Variable] = [tk.StringVar() for _ in range(2)]
  1092. self.where_frame = tk.Frame(self.frame)
  1093. self.where_title: List[tk.Label] = [tk.Label(self.where_frame) for _ in range(2)]
  1094. self.where_enter: List[tk.Entry] = [tk.Entry(self.where_frame) for _ in range(2)]
  1095. self.where_var: List[tk.Variable] = [tk.StringVar() for _ in range(2)]
  1096. self.btn: List[tk.Button] = [tk.Button(self.frame), tk.Button(self.frame)]
  1097. self._conf(["", ""], "#FA8072")
  1098. self.__conf_font()
  1099. def _conf(self, title: List[str], bg_color: str):
  1100. self.bg_color = bg_color
  1101. self.bg_color_where = bg_color
  1102. self.enter_title = title
  1103. def __conf_font(self, n: int = 1):
  1104. self.title_font_size = int(16 * n)
  1105. self.btn_font_size = int(14 * n)
  1106. def conf_gui(self, n: int = 1):
  1107. self.__conf_font(n)
  1108. title_font = make_font(size=self.title_font_size)
  1109. btn_font = make_font(size=self.btn_font_size)
  1110. self.where_frame['bg'] = self.bg_color_where
  1111. self.where_frame['bd'] = 5
  1112. self.where_frame['relief'] = "ridge"
  1113. self.where_frame.place(relx=0.2, rely=0.20, relwidth=0.6, relheight=0.17)
  1114. self.enter_frame['bg'] = self.bg_color
  1115. self.enter_frame['bd'] = 5
  1116. self.enter_frame['relief'] = "ridge"
  1117. self.enter_frame.place(relx=0.2, rely=0.58, relwidth=0.6, relheight=0.17)
  1118. height = 0.1
  1119. for lb, text, enter, var, lb_w, text_w, enter_w, var_w in (
  1120. zip(self.title, self.enter_title, self.enter, self.var,
  1121. self.where_title, ["条件:", self.enter_title[1]], self.where_enter, self.where_var)):
  1122. lb['font'] = title_font
  1123. lb['text'] = text
  1124. lb['bg'] = self.bg_color
  1125. lb['anchor'] = 'e'
  1126. lb_w['font'] = title_font
  1127. lb_w['text'] = text_w
  1128. lb_w['bg'] = self.bg_color_where
  1129. lb_w['anchor'] = 'e'
  1130. enter['font'] = title_font
  1131. enter['textvariable'] = var
  1132. enter_w['font'] = title_font
  1133. enter_w['textvariable'] = var_w
  1134. lb.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.35)
  1135. enter.place(relx=0.35, rely=height, relwidth=0.60, relheight=0.35)
  1136. lb_w.place(relx=0.01, rely=height, relwidth=0.30, relheight=0.35)
  1137. enter_w.place(relx=0.35, rely=height, relwidth=0.60, relheight=0.35)
  1138. height += 0.43
  1139. for btn, text, func in zip(self.btn,
  1140. ["通过条件更新", "通过用户ID更新"],
  1141. [self.update_by_where, self.update_by_uid]):
  1142. btn['font'] = btn_font
  1143. btn['text'] = text
  1144. btn['bg'] = Config.tk_btn_bg
  1145. btn['command'] = func
  1146. self.btn[0].place(relx=0.55, rely=0.40, relwidth=0.25, relheight=0.08)
  1147. self.btn[1].place(relx=0.55, rely=0.78, relwidth=0.25, relheight=0.08)
  1148. def update_by_uid(self):
  1149. ...
  1150. def update_by_where(self):
  1151. ...
  1152. def set_disable(self):
  1153. set_tk_disable_from_list(self.btn)
  1154. set_tk_disable_from_list(self.enter)
  1155. def reset_disable(self):
  1156. set_tk_disable_from_list(self.btn, flat='normal')
  1157. set_tk_disable_from_list(self.enter, flat='normal')
  1158. class UpdateUserScoreBase(UpdateUserProgramBase):
  1159. def __init__(self, station, win, color):
  1160. super(UpdateUserScoreBase, self).__init__(station, win, color, "更新用户-积分")
  1161. self._conf(["用户ID:", "积分:"], "#afdfe4")
  1162. def update_by_uid(self):
  1163. uid = self.enter[0].get()
  1164. score = int(self.enter[1].get())
  1165. event = tk_event.UpdateUserScoreEvent(self.station).start(score, f"UserID='{uid}'")
  1166. self.station.push_event(event)
  1167. def update_by_where(self):
  1168. where = self.where_enter[0].get()
  1169. score = int(self.where_enter[1].get())
  1170. event = tk_event.UpdateUserScoreEvent(self.station).start(score, where)
  1171. self.station.push_event(event)
  1172. class UpdateUserReputationBase(UpdateUserProgramBase):
  1173. def __init__(self, station, win, color):
  1174. super(UpdateUserReputationBase, self).__init__(station, win, color, "更新用户-垃圾分类信用")
  1175. self._conf(["用户ID:", "垃圾分类信用:"], "#f8aba6")
  1176. def update_by_uid(self):
  1177. uid = self.enter[0].get()
  1178. reputation = int(self.enter[1].get())
  1179. event = tk_event.UpdateUserReputationEvent(self.station).start(reputation, f"UserID='{uid}'")
  1180. self.station.push_event(event)
  1181. def update_by_where(self):
  1182. where = self.where_enter[0].get()
  1183. reputation = int(self.where_enter[1].get())
  1184. event = tk_event.UpdateUserReputationEvent(self.station).start(reputation, where)
  1185. self.station.push_event(event)
  1186. class UpdateGarbageTypeProgram(AdminProgram):
  1187. def __init__(self, station, win, color):
  1188. super().__init__(station, win, color, "更新垃圾袋-垃圾类型")
  1189. self.enter_frame = tk.Frame(self.frame)
  1190. self.title: tk.Label = tk.Label(self.enter_frame)
  1191. self.enter: tk.Entry = tk.Entry(self.enter_frame)
  1192. self.type: List[tk.Radiobutton] = [tk.Radiobutton(self.frame) for _ in range(4)]
  1193. self.var: List[tk.Variable] = [tk.StringVar, tk.IntVar()]
  1194. self.where_frame = tk.Frame(self.frame)
  1195. self.where_title: tk.Label = tk.Label(self.where_frame)
  1196. self.where_enter: tk.Entry = tk.Entry(self.where_frame)
  1197. self.where_type: List[tk.Radiobutton] = [tk.Radiobutton(self.frame) for _ in range(4)]
  1198. self.where_var: List[tk.Variable] = [tk.StringVar, tk.IntVar()]
  1199. self.btn: List[tk.Button] = [tk.Button(self.frame), tk.Button(self.frame)]
  1200. self.__conf_font()
  1201. def __conf_font(self, n: int = 1):
  1202. self.title_font_size = int(16 * n)
  1203. self.btn_font_size = int(14 * n)
  1204. def conf_gui(self, n: int = 1):
  1205. self.__conf_font(n)
  1206. title_font = make_font(size=self.title_font_size)
  1207. btn_font = make_font(size=self.btn_font_size)
  1208. self.where_frame['bg'] = "#fdb933"
  1209. self.where_frame['bd'] = 5
  1210. self.where_frame['relief'] = "ridge"
  1211. self.where_frame.place(relx=0.2, rely=0.20, relwidth=0.6, relheight=0.10)
  1212. self.enter_frame['bg'] = "#fdb933"
  1213. self.enter_frame['bd'] = 5
  1214. self.enter_frame['relief'] = "ridge"
  1215. self.enter_frame.place(relx=0.2, rely=0.60, relwidth=0.6, relheight=0.10)
  1216. for lb, enter, radios, var, y, text in zip([self.title, self.where_title],
  1217. [self.enter, self.where_enter],
  1218. [self.type, self.where_type],
  1219. [self.var, self.where_var],
  1220. [0.32, 0.72],
  1221. ["垃圾袋ID:", "条件:"]):
  1222. lb['font'] = title_font
  1223. lb['text'] = text
  1224. lb['bg'] = "#fdb933"
  1225. lb['anchor'] = 'e'
  1226. enter['font'] = title_font
  1227. enter['textvariable'] = var[0]
  1228. for i, radio in enumerate(radios):
  1229. radio['font'] = btn_font
  1230. radio['bg'] = self.color
  1231. radio['text'] = GarbageType.GarbageTypeStrList_ch[i + 1]
  1232. radio['value'] = i + 1
  1233. radio['variable'] = var[1]
  1234. radio['anchor'] = 'w'
  1235. var[1].set(1)
  1236. radios[0].place(relx=0.20, rely=y + 0.00, relwidth=0.20, relheight=0.04)
  1237. radios[1].place(relx=0.60, rely=y + 0.00, relwidth=0.20, relheight=0.04)
  1238. radios[2].place(relx=0.20, rely=y + 0.05, relwidth=0.20, relheight=0.04)
  1239. radios[3].place(relx=0.60, rely=y + 0.05, relwidth=0.20, relheight=0.04)
  1240. lb.place(relx=0.02, rely=0.2, relwidth=0.25, relheight=0.48)
  1241. enter.place(relx=0.30, rely=0.2, relwidth=0.60, relheight=0.48)
  1242. for btn, text, func in zip(self.btn,
  1243. ["通过条件更新", "通过垃圾袋ID更新"],
  1244. [self.update_by_where, self.update_by_gid]):
  1245. btn['font'] = btn_font
  1246. btn['text'] = text
  1247. btn['bg'] = Config.tk_btn_bg
  1248. btn['command'] = func
  1249. self.btn[0].place(relx=0.55, rely=0.43, relwidth=0.25, relheight=0.08)
  1250. self.btn[1].place(relx=0.55, rely=0.83, relwidth=0.25, relheight=0.08)
  1251. def update_by_gid(self):
  1252. gid = self.enter.get()
  1253. type_ = self.var[1].get()
  1254. event = tk_event.UpdateGarbageTypeEvent(self.station).start(type_, f"GarbageID={gid}")
  1255. self.station.push_event(event)
  1256. def update_by_where(self):
  1257. where = self.where_enter.get()
  1258. type_ = self.where_var[1].get()
  1259. event = tk_event.UpdateGarbageTypeEvent(self.station).start(type_, where)
  1260. self.station.push_event(event)
  1261. def set_disable(self):
  1262. set_tk_disable_from_list(self.btn)
  1263. self.enter['state'] = 'disable'
  1264. self.where_enter['state'] = 'normal'
  1265. def reset_disable(self):
  1266. set_tk_disable_from_list(self.btn, flat='normal')
  1267. self.enter['state'] = 'normal'
  1268. self.where_enter['state'] = 'normal'
  1269. class UpdateGarbageCheckResultProgram(AdminProgram):
  1270. def __init__(self, station, win, color):
  1271. super().__init__(station, win, color, "更新垃圾袋-检测结果")
  1272. self.enter_frame = tk.Frame(self.frame)
  1273. self.title: tk.Label = tk.Label(self.enter_frame)
  1274. self.enter: tk.Entry = tk.Entry(self.enter_frame)
  1275. self.type: List[tk.Radiobutton] = [tk.Radiobutton(self.frame) for _ in range(2)]
  1276. self.var: List[tk.Variable] = [tk.StringVar, tk.IntVar()]
  1277. self.where_frame = tk.Frame(self.frame)
  1278. self.where_title: tk.Label = tk.Label(self.where_frame)
  1279. self.where_enter: tk.Entry = tk.Entry(self.where_frame)
  1280. self.where_type: List[tk.Radiobutton] = [tk.Radiobutton(self.frame) for _ in range(2)]
  1281. self.where_var: List[tk.Variable] = [tk.StringVar, tk.IntVar()]
  1282. self.btn: List[tk.Button] = [tk.Button(self.frame), tk.Button(self.frame)]
  1283. self.__conf_font()
  1284. def __conf_font(self, n: int = 1):
  1285. self.title_font_size = int(16 * n)
  1286. self.btn_font_size = int(14 * n)
  1287. def conf_gui(self, n: int = 1):
  1288. self.__conf_font(n)
  1289. title_font = make_font(size=self.title_font_size)
  1290. btn_font = make_font(size=self.btn_font_size)
  1291. self.where_frame['bg'] = "#abc88b"
  1292. self.where_frame['bd'] = 5
  1293. self.where_frame['relief'] = "ridge"
  1294. self.where_frame.place(relx=0.2, rely=0.20, relwidth=0.6, relheight=0.10)
  1295. self.enter_frame['bg'] = "#abc88b"
  1296. self.enter_frame['bd'] = 5
  1297. self.enter_frame['relief'] = "ridge"
  1298. self.enter_frame.place(relx=0.2, rely=0.60, relwidth=0.6, relheight=0.10)
  1299. for lb, enter, radios, var, y, text in zip([self.title, self.where_title],
  1300. [self.enter, self.where_enter],
  1301. [self.type, self.where_type],
  1302. [self.var, self.where_var],
  1303. [0.32, 0.72],
  1304. ["垃圾袋ID:", "条件:"]):
  1305. lb['font'] = title_font
  1306. lb['text'] = text
  1307. lb['bg'] = "#abc88b"
  1308. lb['anchor'] = 'e'
  1309. enter['font'] = title_font
  1310. enter['textvariable'] = var[0]
  1311. for i, radio in enumerate(radios):
  1312. radio['font'] = btn_font
  1313. radio['bg'] = self.color
  1314. radio['text'] = ["投放错误", "投放正确"][i]
  1315. radio['value'] = i
  1316. radio['variable'] = var[1]
  1317. radio['anchor'] = 'w'
  1318. var[1].set(1)
  1319. radios[0].place(relx=0.20, rely=y + 0.00, relwidth=0.20, relheight=0.04)
  1320. radios[1].place(relx=0.60, rely=y + 0.00, relwidth=0.20, relheight=0.04)
  1321. lb.place(relx=0.02, rely=0.2, relwidth=0.25, relheight=0.48)
  1322. enter.place(relx=0.30, rely=0.2, relwidth=0.60, relheight=0.48)
  1323. for btn, text, func in zip(self.btn,
  1324. ["通过条件更新", "通过垃圾袋ID更新"],
  1325. [self.update_by_where, self.update_by_gid]):
  1326. btn['font'] = btn_font
  1327. btn['bg'] = Config.tk_btn_bg
  1328. btn['text'] = text
  1329. btn['command'] = func
  1330. self.btn[0].place(relx=0.55, rely=0.38, relwidth=0.25, relheight=0.08)
  1331. self.btn[1].place(relx=0.55, rely=0.78, relwidth=0.25, relheight=0.08)
  1332. def update_by_gid(self):
  1333. gid = self.enter.get()
  1334. check = (self.var[1].get() == 1)
  1335. event = tk_event.UpdateGarbageCheckEvent(self.station).start(check, f"GarbageID={gid}")
  1336. self.station.push_event(event)
  1337. def update_by_where(self):
  1338. where = self.where_enter.get()
  1339. check = (self.where_var[1].get() == 1)
  1340. event = tk_event.UpdateGarbageCheckEvent(self.station).start(check, where)
  1341. self.station.push_event(event)
  1342. def set_disable(self):
  1343. set_tk_disable_from_list(self.btn)
  1344. self.enter['state'] = 'disable'
  1345. self.where_enter['state'] = 'normal'
  1346. def reset_disable(self):
  1347. set_tk_disable_from_list(self.btn, flat='normal')
  1348. self.enter['state'] = 'normal'
  1349. self.where_enter['state'] = 'normal'
  1350. class StatisticsTimeBaseProgram(AdminProgram):
  1351. def __init__(self, station, win, color, title: str):
  1352. super().__init__(station, win, color, title)
  1353. self.figure_frame = tk.Frame(self.frame)
  1354. self.figure = Figure(dpi=100)
  1355. self.plt: Axes = self.figure.add_subplot(111) # 添加子图:1行1列第1个
  1356. self.canvas = FigureCanvasTkAgg(self.figure, master=self.figure_frame)
  1357. self.canvas_tk = self.canvas.get_tk_widget()
  1358. self.toolbar = NavigationToolbar2Tk(self.canvas, self.figure_frame)
  1359. self.color_frame = tk.Frame(self.frame)
  1360. self.show_list_tk = tk.Listbox(self.color_frame)
  1361. self.show_list_scroll = tk.Scrollbar(self.color_frame)
  1362. self.hide_list_tk = tk.Listbox(self.color_frame)
  1363. self.hide_list_scroll = tk.Scrollbar(self.color_frame)
  1364. self.btn_show = tk.Button(self.color_frame)
  1365. self.btn_hide = tk.Button(self.color_frame)
  1366. self.color_show_dict = {}
  1367. self.color_hide_dict = {}
  1368. self.export_lst = []
  1369. self.export_btn = tk.Button(self.frame)
  1370. self.refresh_btn = tk.Button(self.frame)
  1371. self.reset_btn = tk.Button(self.frame)
  1372. self.reverse_btn = tk.Button(self.frame)
  1373. self.legend_show = tk.Checkbutton(self.frame), tk.IntVar()
  1374. self._conf("#abc88b")
  1375. self.__conf_font()
  1376. def _conf(self, bg_color):
  1377. self.bg_color = bg_color
  1378. def __conf_font(self, n: int = 1):
  1379. self.btn_font_size = int(14 * n)
  1380. self.little_btn_font_size = int(12 * n)
  1381. def to_program(self):
  1382. self.refresh()
  1383. def update_listbox(self):
  1384. self.show_list_tk.delete(0, tk.END) # 清空列表
  1385. self.hide_list_tk.delete(0, tk.END) # 清空列表
  1386. for i in self.color_show_dict:
  1387. self.show_list_tk.insert(tk.END, i)
  1388. self.show_list_tk.itemconfig(tk.END,
  1389. selectbackground=self.color_show_dict[i],
  1390. bg=self.color_show_dict[i],
  1391. selectforeground='#FFFFFF',
  1392. fg='#000000')
  1393. for i in self.color_hide_dict:
  1394. self.hide_list_tk.insert(tk.END, i)
  1395. self.hide_list_tk.itemconfig(tk.END,
  1396. selectbackground=self.color_hide_dict[i],
  1397. bg=self.color_hide_dict[i],
  1398. selectforeground='#FFFFFF',
  1399. fg='#000000')
  1400. def check_show(self, res: str):
  1401. color = self.color_show_dict.get(res)
  1402. if color is not None:
  1403. return color
  1404. color = self.color_hide_dict.get(res)
  1405. if color is not None:
  1406. return None
  1407. color = random_color()
  1408. self.color_show_dict[res] = color
  1409. return color
  1410. def hide(self):
  1411. i = self.show_list_tk.curselection()
  1412. if len(i) == 0:
  1413. return
  1414. res = self.show_list_tk.get(i[0])
  1415. self.hide_(res)
  1416. self.update_listbox()
  1417. def show(self):
  1418. i = self.hide_list_tk.curselection()
  1419. if len(i) == 0:
  1420. return
  1421. res = self.hide_list_tk.get(i[0])
  1422. self.show_(res)
  1423. self.update_listbox()
  1424. def hide_(self, res):
  1425. color = self.color_show_dict.get(res)
  1426. if color is not None:
  1427. del self.color_show_dict[res]
  1428. self.color_hide_dict[res] = color
  1429. def show_(self, res):
  1430. color = self.color_hide_dict.get(res)
  1431. if color is not None:
  1432. del self.color_hide_dict[res]
  1433. self.color_show_dict[res] = color
  1434. def conf_gui(self, n: int = 1):
  1435. self.__conf_font(n)
  1436. btn_font = make_font(size=self.btn_font_size)
  1437. little_btn_font = make_font(size=self.little_btn_font_size)
  1438. self.color_frame['bg'] = self.bg_color
  1439. self.color_frame['bd'] = 5
  1440. self.color_frame['relief'] = "ridge"
  1441. self.show_list_tk.place(relx=0, rely=0, relwidth=0.90, relheight=0.475)
  1442. self.show_list_scroll.place(relx=0.90, rely=0, relwidth=0.10, relheight=0.475)
  1443. self.show_list_scroll['orient'] = 'vertical'
  1444. self.show_list_scroll['command'] = self.show_list_tk.yview
  1445. self.show_list_tk['yscrollcommand'] = self.show_list_scroll.set
  1446. self.show_list_tk['activestyle'] = tk.NONE
  1447. self.hide_list_tk.place(relx=0, rely=0.525, relwidth=0.90, relheight=0.475)
  1448. self.hide_list_scroll.place(relx=0.90, rely=0.525, relwidth=0.10, relheight=0.475)
  1449. self.hide_list_scroll['orient'] = 'vertical'
  1450. self.hide_list_scroll['command'] = self.hide_list_tk.yview
  1451. self.hide_list_tk['yscrollcommand'] = self.hide_list_scroll.set
  1452. self.hide_list_tk['activestyle'] = tk.NONE
  1453. for btn, text, func, x in zip([self.btn_show, self.btn_hide],
  1454. ["Show", "Hide"],
  1455. [self.show, self.hide],
  1456. [0.00, 0.50]):
  1457. btn['font'] = little_btn_font
  1458. btn['bg'] = Config.tk_btn_bg
  1459. btn['text'] = text
  1460. btn['command'] = func
  1461. btn.place(relx=x, rely=0.475, relwidth=0.50, relheight=0.05)
  1462. self.color_frame.place(relx=0.01, rely=0.02, relwidth=0.18, relheight=0.88)
  1463. self.figure_frame['bg'] = self.bg_color
  1464. self.figure_frame['bd'] = 5
  1465. self.figure_frame['relief'] = "ridge"
  1466. self.figure_frame.place(relx=0.21, rely=0.02, relwidth=0.79, relheight=0.88)
  1467. self.canvas_tk.place(relx=0, rely=0, relwidth=1.0, relheight=0.9)
  1468. self.toolbar.place(relx=0, rely=0.9, relwidth=1.0, relheight=0.1)
  1469. for btn, text, func, x in zip([self.reset_btn, self.reverse_btn, self.refresh_btn, self.export_btn],
  1470. ["复位选择", "反转选择", "刷新数据", "导出数据"],
  1471. [self.reset, self.reverse, self.refresh, self.export],
  1472. [0.37, 0.53, 0.69, 0.85]):
  1473. btn['font'] = btn_font
  1474. btn['bg'] = Config.tk_btn_bg
  1475. btn['text'] = text
  1476. btn['command'] = func
  1477. btn.place(relx=x, rely=0.91, relwidth=0.15, relheight=0.08)
  1478. self.legend_show[0]['font'] = btn_font
  1479. self.legend_show[0]['bg'] = self.color
  1480. self.legend_show[0]['text'] = "显示图例"
  1481. self.legend_show[0]['variable'] = self.legend_show[1]
  1482. self.legend_show[0].place(relx=0.21, rely=0.91, relwidth=0.15, relheight=0.08)
  1483. def export(self, title, func: Callable):
  1484. path = asksaveasfilename(title='选择CSV文件保存位置', filetypes=[("CSV", ".csv")])
  1485. if not path.endswith(".csv"):
  1486. path += ".csv"
  1487. with open(path, "w") as f:
  1488. f.write(f"Hour, Count, {title}\n")
  1489. for i in self.export_lst:
  1490. f.write(f"{i[0]}, {i[1]}, {func(i)}\n")
  1491. self.station.show_msg("保存数据", f"数据导出成功\n保存位置:\n {path}")
  1492. def refresh(self):
  1493. self.plt.cla()
  1494. def reset(self):
  1495. self.color_show_dict.update(self.color_hide_dict)
  1496. self.color_hide_dict = {}
  1497. self.update_listbox()
  1498. def reverse(self):
  1499. tmp = self.color_show_dict
  1500. self.color_show_dict = self.color_hide_dict
  1501. self.color_hide_dict = tmp
  1502. self.update_listbox()
  1503. def show_result(self, res: Dict[str, any], lst: List):
  1504. bottom = np.zeros(24)
  1505. label_num = [i for i in range(24)]
  1506. label_str = [f"{i}" for i in range(24)]
  1507. res_type_lst: List = res['res_type']
  1508. self.export_lst = lst
  1509. for res_type in res_type_lst:
  1510. res_count: Tuple[str] = res[res_type]
  1511. if len(res_count) != 0:
  1512. color = self.check_show(res_type)
  1513. if color is None:
  1514. continue
  1515. y = [0 for _ in range(24)]
  1516. for i in res_count:
  1517. y[int(i[0])] = int(i[1])
  1518. self.color_show_dict[res_type] = color
  1519. self.plt.bar(label_num, y,
  1520. color=color,
  1521. align="center",
  1522. bottom=bottom,
  1523. tick_label=label_str,
  1524. label=res_type)
  1525. bottom += np.array(y)
  1526. if self.legend_show[1].get() == 1: # 显示图例
  1527. self.plt.legend(loc="upper left")
  1528. self.plt.set_xlim(-1, 24)
  1529. self.plt.set_xticks([i for i in range(0, 24, 2)])
  1530. self.plt.set_xticklabels([f"{i}h" for i in range(0, 24, 2)])
  1531. self.plt.set_title(self.program_title)
  1532. self.canvas.draw()
  1533. self.toolbar.update()
  1534. self.update_listbox()
  1535. def set_disable(self):
  1536. self.export_btn['state'] = 'disable'
  1537. def reset_disable(self):
  1538. self.export_btn['state'] = 'normal'
  1539. class StatisticsTimeLocProgram(StatisticsTimeBaseProgram):
  1540. def __init__(self, station, win, color):
  1541. super().__init__(station, win, color, "时段分析-按投放区域")
  1542. self._conf("#abc88b")
  1543. def refresh(self):
  1544. super().refresh()
  1545. event = tk_event.CountThrowTimeEvent(self.station).start(["Location"], lambda i: i[2], self)
  1546. self.station.push_event(event)
  1547. def export(self, *_, **__):
  1548. super().export("Location", lambda i: i[2])
  1549. class StatisticsTimeTypeProgram(StatisticsTimeBaseProgram):
  1550. def __init__(self, station, win, color):
  1551. super().__init__(station, win, color, "时段分析-按投放类型")
  1552. self._conf("#abc88b")
  1553. self.color_show_dict[GarbageType.GarbageTypeStrList_ch[1]] = "#00BFFF"
  1554. self.color_show_dict[GarbageType.GarbageTypeStrList_ch[2]] = "#32CD32"
  1555. self.color_show_dict[GarbageType.GarbageTypeStrList_ch[3]] = "#DC143C"
  1556. self.color_show_dict[GarbageType.GarbageTypeStrList_ch[4]] = "#A9A9A9"
  1557. def refresh(self):
  1558. super().refresh()
  1559. event = tk_event.CountThrowTimeEvent(self.station).start(["GarbageType"], self.get_name, self)
  1560. self.station.push_event(event)
  1561. def export(self, *_, **__):
  1562. super().export("Type", self.get_name)
  1563. @staticmethod
  1564. def get_name(i: Tuple):
  1565. data: bytes = i[2]
  1566. return GarbageType.GarbageTypeStrList_ch[int(data.decode('utf-8'))]
  1567. class StatisticsTimeTypeLocProgram(StatisticsTimeBaseProgram):
  1568. def __init__(self, station, win, color):
  1569. super().__init__(station, win, color, "时段分析-按投放类型和区域")
  1570. self._conf("#abc88b")
  1571. def refresh(self):
  1572. super().refresh()
  1573. event = tk_event.CountThrowTimeEvent(self.station).start(["GarbageType", "Location"], self.get_name, self)
  1574. self.station.push_event(event)
  1575. def export(self, *_, **__):
  1576. super().export("Type-Location", self.get_name)
  1577. @staticmethod
  1578. def get_name(i: Tuple):
  1579. data: bytes = i[2]
  1580. return f"{GarbageType.GarbageTypeStrList_ch[int(data.decode('utf-8'))]}-{i[3]}"
  1581. class StatisticsTimeCheckResultProgram(StatisticsTimeBaseProgram):
  1582. def __init__(self, station, win, color):
  1583. super().__init__(station, win, color, "时段分析-按检查结果")
  1584. self._conf("#abc88b")
  1585. self.color_show_dict['Pass'] = "#00BFFF"
  1586. self.color_show_dict['Fail'] = "#DC143C"
  1587. def refresh(self):
  1588. super().refresh()
  1589. event = tk_event.CountThrowTimeEvent(self.station).start(["CheckResult"], self.get_name, self)
  1590. self.station.push_event(event)
  1591. def export(self, *_, **__):
  1592. super().export("Result", self.get_name)
  1593. @staticmethod
  1594. def get_name(i: Tuple):
  1595. data: bytes = i[2]
  1596. return 'Pass' if data == DBBit.BIT_1 else 'Fail'
  1597. class StatisticsTimeCheckResultAndTypeProgram(StatisticsTimeBaseProgram):
  1598. def __init__(self, station, win, color):
  1599. super().__init__(station, win, color, "时段分析-按检查结果和类型")
  1600. self._conf("#abc88b")
  1601. def refresh(self):
  1602. super().refresh()
  1603. event = tk_event.CountThrowTimeEvent(self.station).start(["CheckResult", "GarbageType"], self.get_name, self)
  1604. self.station.push_event(event)
  1605. def export(self, *_, **__):
  1606. super().export("Result-Location", self.get_name)
  1607. @staticmethod
  1608. def get_name(i: Tuple):
  1609. data_1: bytes = i[2]
  1610. data_2: bytes = i[3]
  1611. return ((f'Pass' if data_1 == DBBit.BIT_1 else 'Fail') +
  1612. f'-{GarbageType.GarbageTypeStrList_ch[int(data_2.decode("utf-8"))]}')
  1613. class StatisticsTimeCheckResultAndLocProgram(StatisticsTimeBaseProgram):
  1614. def __init__(self, station, win, color):
  1615. super().__init__(station, win, color, "时段分析-按检查结果和区域")
  1616. self._conf("#abc88b")
  1617. def refresh(self):
  1618. super().refresh()
  1619. event = tk_event.CountThrowTimeEvent(self.station).start(["CheckResult", "Location"], self.get_name, self)
  1620. self.station.push_event(event)
  1621. def export(self, *_, **__):
  1622. super().export("Result-Type", self.get_name)
  1623. @staticmethod
  1624. def get_name(i: Tuple):
  1625. data_1: bytes = i[2]
  1626. return (f'Pass' if data_1 == DBBit.BIT_1 else 'Fail') + f"-{i[3]}"
  1627. class StatisticsTimeDetailProgram(StatisticsTimeBaseProgram):
  1628. def __init__(self, station, win, color):
  1629. super().__init__(station, win, color, "时段分析-详细分类")
  1630. self._conf("#abc88b")
  1631. def refresh(self):
  1632. super().refresh()
  1633. event = tk_event.CountThrowTimeEvent(self.station)
  1634. event.start(["CheckResult", "GarbageType", "Location"], self.get_name, self)
  1635. self.station.push_event(event)
  1636. def export(self, *_, **__):
  1637. super().export("Detail", self.get_name)
  1638. @staticmethod
  1639. def get_name(i: Tuple):
  1640. data_1: bytes = i[2]
  1641. data_2: bytes = i[3]
  1642. return ((f'Pass' if data_1 == DBBit.BIT_1 else 'Fail') +
  1643. f'-{GarbageType.GarbageTypeStrList_ch[int(data_2.decode("utf-8"))]}' + f'-{i[4]}')
  1644. all_program = [WelcomeProgram, CreateNormalUserProgram, CreateManagerUserProgram, CreateAutoNormalUserProgram,
  1645. CreateGarbageProgram, DeleteUserProgram, DeleteUsersProgram, DeleteGarbageProgram,
  1646. DeleteGarbageMoreProgram, DeleteAllGarbageProgram, SearchUserProgram, SearchUserAdvancedProgram,
  1647. SearchGarbageProgram, SearchGarbageAdvancedProgram, SearchAdvancedProgram, UpdateUserScoreBase,
  1648. UpdateUserReputationBase, UpdateGarbageTypeProgram, UpdateGarbageCheckResultProgram,
  1649. ExportGarbageProgram, ExportUserProgram, CreateUserFromCSVProgram, AboutProgram,
  1650. StatisticsTimeLocProgram, StatisticsTimeTypeProgram, StatisticsTimeTypeLocProgram,
  1651. StatisticsTimeCheckResultProgram, StatisticsTimeCheckResultAndTypeProgram,
  1652. StatisticsTimeCheckResultAndLocProgram, StatisticsTimeDetailProgram]