|
@@ -1,5 +1,5 @@
|
|
|
import PIL.Image
|
|
|
-
|
|
|
+import time
|
|
|
import conf
|
|
|
import cv2
|
|
|
import tkinter as tk
|
|
@@ -7,12 +7,102 @@ import tkinter.font as font
|
|
|
from tool.type_ import *
|
|
|
import datetime
|
|
|
from PIL import Image, ImageTk
|
|
|
-from control import Control, global_control, ControlScanType, ControlNotLogin
|
|
|
+from control import Control, global_control, ControlScanType, ControlNotLogin, ThrowGarbageError, CheckGarbageError
|
|
|
+from core.user import User, UserNotSupportError
|
|
|
+from core.garbage import GarbageBag, GarbageType, GarbageBagNotUse
|
|
|
+import tkinter.messagebox as msg
|
|
|
+
|
|
|
+
|
|
|
+class GarbageStationException(Exception):
|
|
|
+ ...
|
|
|
+
|
|
|
+
|
|
|
+class GarbageStationStatus:
|
|
|
+ status_normal = 1
|
|
|
+ status_get_garbage_type = 2
|
|
|
+ status_get_garbage_check = 3
|
|
|
+
|
|
|
+ def __init__(self, win, ctrl: Control = global_control):
|
|
|
+ self._win: GarbageStation = win
|
|
|
+ self._ctrl = ctrl
|
|
|
+ self._garbage: Optional[GarbageBag] = None
|
|
|
+ self._flat = GarbageStationStatus.status_normal
|
|
|
+
|
|
|
+ def to_get_garbage_type(self, garbage: GarbageBag):
|
|
|
+ self._flat = GarbageStationStatus.status_get_garbage_type
|
|
|
+ self.set_garbage(garbage)
|
|
|
+
|
|
|
+ def to_get_garbage_check(self, garbage: GarbageBag):
|
|
|
+ self._flat = GarbageStationStatus.status_get_garbage_check
|
|
|
+ self.set_garbage(garbage)
|
|
|
+
|
|
|
+ def set_garbage(self, garbage: GarbageBag):
|
|
|
+ self._garbage = garbage
|
|
|
+
|
|
|
+ def get_garbage(self) -> Optional[GarbageBag]:
|
|
|
+ if not self._ctrl.check_user():
|
|
|
+ self._garbage = None
|
|
|
+ return self._garbage
|
|
|
+
|
|
|
+ def get_user_info_no_update(self):
|
|
|
+ return self._ctrl.get_user_info_no_update()
|
|
|
+
|
|
|
+ def scan(self):
|
|
|
+ return self._ctrl.scan()
|
|
|
+
|
|
|
+ def get_cap_img(self):
|
|
|
+ return self._ctrl.get_cap_img()
|
|
|
+
|
|
|
+ def switch_user(self, user: User):
|
|
|
+ return self._ctrl.switch_user(user)
|
|
|
+
|
|
|
+ def throw_garbage(self, garbage_type: enum):
|
|
|
+ if self._flat != GarbageStationStatus.status_get_garbage_type or self._garbage is None:
|
|
|
+ msg.showwarning("Operation Fail", "You should login first and scan the QR code of the trash bag")
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ self._ctrl.throw_garbage(self._garbage, garbage_type)
|
|
|
+ except (ThrowGarbageError, UserNotSupportError, ControlNotLogin):
|
|
|
+ msg.showwarning("Operation Fail", "The garbage bags have been used.")
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ self._flat = GarbageStationStatus.status_normal
|
|
|
+ self._garbage = None
|
|
|
+
|
|
|
+ def check_garbage(self, check: bool):
|
|
|
+ if self._flat != GarbageStationStatus.status_get_garbage_check or self._garbage is None:
|
|
|
+ msg.showwarning("Operation Fail", "You should login first and scan the QR code of the trash bag")
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ self._ctrl.check_garbage(self._garbage, check)
|
|
|
+ except (ThrowGarbageError, UserNotSupportError, CheckGarbageError, GarbageBagNotUse):
|
|
|
+ msg.showwarning("Operation Fail", "The garbage bag has been checked")
|
|
|
+ finally:
|
|
|
+ self._flat = GarbageStationStatus.status_normal
|
|
|
+ self._garbage = None
|
|
|
+
|
|
|
+ def show_garbage_info(self):
|
|
|
+ if self._flat != GarbageStationStatus.status_get_garbage_check or self._garbage is None:
|
|
|
+ msg.showwarning("Operation Fail", "You should login first and scan the QR code of the trash bag")
|
|
|
+ return
|
|
|
+
|
|
|
+ if not self._garbage.is_use():
|
|
|
+ msg.showwarning("Operation Fail", "The garbage bag has not been used")
|
|
|
+ return
|
|
|
+
|
|
|
+ info = self._garbage.get_info()
|
|
|
+ garbage_type = GarbageType.GarbageTypeStrList[int(info['type'])]
|
|
|
+ time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(float(info['use_time'])))
|
|
|
+ msg.showwarning("Garbage Info", f"type = {garbage_type}\n"
|
|
|
+ f"location = {info['loc']}\n"
|
|
|
+ f"use-time = {time_str}")
|
|
|
|
|
|
|
|
|
class GarbageStation:
|
|
|
def __init__(self, ctrl: Control = global_control):
|
|
|
- self._ctrl = ctrl
|
|
|
+ self._status = GarbageStationStatus(self, ctrl)
|
|
|
self._window = tk.Tk()
|
|
|
self._sys_height = self._window.winfo_screenheight()
|
|
|
self._sys_width = self._window.winfo_screenwidth()
|
|
@@ -75,6 +165,7 @@ class GarbageStation:
|
|
|
tk.Button(self._user_btn_frame)]
|
|
|
self.__conf_user_btn()
|
|
|
self.__conf_after()
|
|
|
+ self.all_user_disable()
|
|
|
|
|
|
def __conf_windows(self):
|
|
|
self._window.title('HGSSystem: Garbage Station')
|
|
@@ -180,6 +271,11 @@ class GarbageStation:
|
|
|
btn['bg'] = info[1]
|
|
|
btn['text'] = info[0]
|
|
|
|
|
|
+ self._throw_ctrl_btn[0]['command'] = lambda: self._status.throw_garbage(GarbageType.recyclable)
|
|
|
+ self._throw_ctrl_btn[1]['command'] = lambda: self._status.throw_garbage(GarbageType.other)
|
|
|
+ self._throw_ctrl_btn[2]['command'] = lambda: self._status.throw_garbage(GarbageType.hazardous)
|
|
|
+ self._throw_ctrl_btn[3]['command'] = lambda: self._status.throw_garbage(GarbageType.kitchen)
|
|
|
+
|
|
|
self._throw_ctrl_btn[0].place(relx=0.000, rely=0.000, relwidth=0.495, relheight=0.495)
|
|
|
self._throw_ctrl_btn[1].place(relx=0.505, rely=0.000, relwidth=0.495, relheight=0.495)
|
|
|
self._throw_ctrl_btn[2].place(relx=0.000, rely=0.505, relwidth=0.495, relheight=0.495)
|
|
@@ -196,7 +292,9 @@ class GarbageStation:
|
|
|
btn['font'] = btn_font
|
|
|
btn['text'] = info[0]
|
|
|
btn['bg'] = info[1]
|
|
|
- btn['state'] = 'disabled'
|
|
|
+
|
|
|
+ self._check_ctrl_btn[0]['command'] = lambda: self._status.check_garbage(False)
|
|
|
+ self._check_ctrl_btn[1]['command'] = lambda: self._status.check_garbage(True)
|
|
|
|
|
|
self._check_ctrl_btn[0].place(relx=0.000, rely=0.000, relwidth=0.495, relheight=1)
|
|
|
self._check_ctrl_btn[1].place(relx=0.505, rely=0.000, relwidth=0.495, relheight=1)
|
|
@@ -282,19 +380,26 @@ class GarbageStation:
|
|
|
rubbish: tk.Variable = self._user_rubbish[2]
|
|
|
eval_: tk.Variable = self._user_eval[2]
|
|
|
|
|
|
- user_info: Dict[str, str] = self._ctrl.get_user_info_no_update()
|
|
|
+ user_info: Dict[str, str] = self._status.get_user_info_no_update()
|
|
|
if user_info.get('uid') is None:
|
|
|
name.set('Not-Login')
|
|
|
uid.set('Not-Login')
|
|
|
eval_.set('---')
|
|
|
rubbish.set('---')
|
|
|
score.set('---')
|
|
|
- elif user_info.get('manager', False):
|
|
|
+ self.all_user_disable()
|
|
|
+ elif user_info.get('manager', '0') == '1':
|
|
|
name.set(user_info.get('name'))
|
|
|
- uid.set(user_info.get('uid'))
|
|
|
+ uid_get = user_info.get('uid', None)
|
|
|
+ if uid_get is None or len(uid_get) < 32:
|
|
|
+ uid.set('error')
|
|
|
+ else:
|
|
|
+ uid.set(uid_get[0:21])
|
|
|
eval_.set('Manager-User')
|
|
|
rubbish.set('Manager-User')
|
|
|
score.set('Manager-User')
|
|
|
+ self.manager_user_able()
|
|
|
+ self.manager_user_disable()
|
|
|
else:
|
|
|
name.set(user_info.get('name'))
|
|
|
uid_get = user_info.get('uid', None)
|
|
@@ -305,6 +410,17 @@ class GarbageStation:
|
|
|
eval_.set(user_info.get('reputation'))
|
|
|
rubbish.set(user_info.get('rubbish'))
|
|
|
score.set(user_info.get('score'))
|
|
|
+ self.normal_user_able()
|
|
|
+ self.normal_user_disable()
|
|
|
+
|
|
|
+ garbage = self._status.get_garbage()
|
|
|
+ if garbage is None:
|
|
|
+ self._garbage_id[2].set('---')
|
|
|
+ else:
|
|
|
+ gid = garbage.get_gid()
|
|
|
+ if len(gid) > 20:
|
|
|
+ gid = gid[-20:]
|
|
|
+ self._garbage_id[2].set(gid)
|
|
|
|
|
|
if update:
|
|
|
self.__define_after(10, self.update_control)
|
|
@@ -312,22 +428,50 @@ class GarbageStation:
|
|
|
def update_scan(self):
|
|
|
res: Tuple[enum, any] = ControlScanType.no_to_done, None
|
|
|
try:
|
|
|
- res = self._ctrl.scan()
|
|
|
+ res = self._status.scan()
|
|
|
except ControlNotLogin:
|
|
|
- ...
|
|
|
+ msg.showwarning("Scan Fail", "You should login first.")
|
|
|
|
|
|
# 需要存储一些数据 谨防被gc释放
|
|
|
- _cap_img_info = (Image.fromarray(cv2.cvtColor(self._ctrl.get_cap_img(), cv2.COLOR_BGR2RGB)).
|
|
|
+ _cap_img_info = (Image.fromarray(cv2.cvtColor(self._status.get_cap_img(), cv2.COLOR_BGR2RGB)).
|
|
|
transpose(Image.FLIP_LEFT_RIGHT))
|
|
|
self._cap_img = ImageTk.PhotoImage(image=_cap_img_info)
|
|
|
self._cap_label['image'] = self._cap_img
|
|
|
|
|
|
if res[0] == ControlScanType.switch_user:
|
|
|
- self._ctrl.switch_user(res[1])
|
|
|
+ self._status.switch_user(res[1])
|
|
|
+ self.update_control(False)
|
|
|
+ elif res[0] == ControlScanType.throw_garbage:
|
|
|
+ self._status.to_get_garbage_type(res[1])
|
|
|
+ self.update_control(False)
|
|
|
+ elif res[0] == ControlScanType.check_garbage:
|
|
|
+ self._status.to_get_garbage_check(res[1])
|
|
|
self.update_control(False)
|
|
|
|
|
|
self.__define_after(10, self.update_scan)
|
|
|
|
|
|
+ def normal_user_disable(self):
|
|
|
+ for btn in self._check_ctrl_btn:
|
|
|
+ btn['state'] = 'disabled'
|
|
|
+ self._user_btn[0]['command'] = lambda: None
|
|
|
+
|
|
|
+ def manager_user_disable(self):
|
|
|
+ for btn in self._throw_ctrl_btn:
|
|
|
+ btn['state'] = 'disabled'
|
|
|
+ self._user_btn[0]['command'] = lambda: self._status.show_garbage_info()
|
|
|
+
|
|
|
+ def all_user_disable(self):
|
|
|
+ self.manager_user_disable()
|
|
|
+ self.normal_user_disable()
|
|
|
+
|
|
|
+ def normal_user_able(self):
|
|
|
+ for btn in self._throw_ctrl_btn:
|
|
|
+ btn['state'] = 'normal'
|
|
|
+
|
|
|
+ def manager_user_able(self):
|
|
|
+ for btn in self._check_ctrl_btn:
|
|
|
+ btn['state'] = 'normal'
|
|
|
+
|
|
|
@staticmethod
|
|
|
def __make_font(family: str = 'noto', **kwargs):
|
|
|
return font.Font(family=conf.font_d[family], **kwargs)
|