admin_program.py 101 KB

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