瀏覽代碼

feat: 支持7日分析

SongZihuan 3 年之前
父節點
當前提交
07e985ff47
共有 4 個文件被更改,包括 447 次插入31 次删除
  1. 29 0
      setup.sql
  2. 50 2
      tk_ui/admin_event.py
  3. 105 5
      tk_ui/admin_menu.py
  4. 263 24
      tk_ui/admin_program.py

+ 29 - 0
setup.sql

@@ -118,6 +118,35 @@ SELECT garbage_user.GarbageID       AS GarbageID,
 FROM garbage_user
          LEFT JOIN garbage_checker on garbage_user.GarbageID = garbage_checker.GarbageID;
 
+DROP VIEW IF EXISTS garbage_7d;
+CREATE VIEW garbage_7d AS
+SELECT (TO_DAYS(NOW()) - TO_DAYS(UseTime)) AS days,
+       GarbageID,
+       CreateTime,
+       Flat,
+       UserID,
+       UseTime,
+       GarbageType,
+       Location,
+       CheckResult,
+       CheckerID
+FROM garbage
+WHERE TO_DAYS(NOW()) - TO_DAYS(UseTime) < 7;
+
+DROP VIEW IF EXISTS garbage_30d;
+CREATE VIEW garbage_30d AS
+SELECT (TO_DAYS(NOW()) - TO_DAYS(UseTime)) AS days,
+       GarbageID,
+       CreateTime,
+       Flat,
+       UserID,
+       UseTime,
+       GarbageType,
+       Location,
+       CheckResult,
+       CheckerID
+FROM garbage
+WHERE TO_DAYS(NOW()) - TO_DAYS(UseTime) < 30;
 
 -- 创建函数
 CREATE FUNCTION get_avg(num1 int, num2 int)

+ 50 - 2
tk_ui/admin_event.py

@@ -585,7 +585,7 @@ class UpdateGarbageCheckEvent(AdminEventBase):
             self.station.show_msg("更新成功", f"成功更新{res}个垃圾袋-检测结果")
 
 
-class CountThrowTimeEvent(AdminEventBase):
+class CountTimeEvent(AdminEventBase):
     """
     任务: 按时段统计数据
     """
@@ -615,7 +615,7 @@ class CountThrowTimeEvent(AdminEventBase):
     def __init__(self, gb_station):
         super().__init__(gb_station)
         self.thread = None
-        self._program: Optional[admin_program.StatisticsTimeBaseProgram] = None
+        self._program: Optional[admin_program.StatisticsTimeProgramBase] = None
 
     def start(self, column: List, get_name: Callable, program):
         self.thread = TkThreading(self.func, column, get_name)
@@ -797,3 +797,51 @@ class PassingRateEvent(AdminEventBase):
             self.station.show_warning("数据分析", "数据获取时发生错误")
         else:
             self._program.show_result(res)
+
+
+class CountDateEvent(AdminEventBase):
+    """
+    任务: 按日期统计数据
+    """
+
+    def func(self, days: int, column: List, get_name: Callable):
+        res = {}
+        cur = self._db.search(columns=["days", "count(GarbageID) AS count", *column],
+                              table=f"garbage_{days}d",
+                              group_by=["days", *column],
+                              order_by=[(c, "DESC") for c in column] + [("days", "ASC")],
+                              where="UseTime IS NOT NULL")
+        if cur is None:
+            return None
+        loc_list = cur.fetchall()
+        loc_type = []
+        for i in loc_list:
+            name = get_name(i)
+            if name not in loc_type:
+                loc_type.append(name)
+            lst: List = res.get(name, list())
+            lst.append(i)
+            res[name] = lst
+        res['res_type'] = loc_type
+
+        return res, loc_list
+
+    def __init__(self, gb_station):
+        super().__init__(gb_station)
+        self.thread = None
+        self._program: Optional[admin_program.StatisticsTimeProgramBase] = None
+
+    def start(self, days, column: List, get_name: Callable, program):
+        self.thread = TkThreading(self.func, days, column, get_name)
+        self._program = program
+        return self
+
+    def is_end(self) -> bool:
+        return not self.thread.is_alive()
+
+    def done_after_event(self):
+        res: Optional[Tuple[Dict[str, str], List]] = self.thread.wait_event()
+        if res is None:
+            self.station.show_warning("数据分析", "数据获取时发生错误")
+        else:
+            self._program.show_result(res[0], res[1])

+ 105 - 5
tk_ui/admin_menu.py

@@ -210,18 +210,22 @@ class UpdateMenu(AdminMenu):
 class StatisticsMenu(AdminMenu):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "数据分析")
-        self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(3)]
-        self.btn_name = ["时段分析", "积分信用分析", "通过率"]
+        self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(4)]
+        self.btn_name = ["时段分析", "日期分析", "积分信用分析", "通过率"]
 
     def conf_gui(self, color: str, n: int = 1):
         super().conf_gui(color, n)
         self.btn[0]['command'] = self.statistics_time_command
-        self.btn[1]['command'] = self.statistics_user_command
-        self.btn[2]['command'] = self.statistics_pass_command
+        self.btn[1]['command'] = self.statistics_date_command
+        self.btn[2]['command'] = self.statistics_user_command
+        self.btn[3]['command'] = self.statistics_pass_command
 
     def statistics_time_command(self):
         self.station.to_menu("时段分析")
 
+    def statistics_date_command(self):
+        self.station.to_menu("日期分析")
+
     def statistics_user_command(self):
         self.station.to_menu("积分信用分析")
 
@@ -268,6 +272,102 @@ class StatisticsTimeMenu(AdminMenu):
         self.station.to_program("时段分析-详细分类")
 
 
+class StatisticsDateMenu(AdminMenu):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "日期分析")
+        self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(2)]
+        self.btn_name = ["最近7日", "最近30日"]
+
+    def conf_gui(self, color: str, n: int = 1):
+        super().conf_gui(color, n)
+        self.btn[0]['command'] = self.by_7
+        self.btn[1]['command'] = self.by_30
+
+    def by_7(self):
+        self.station.to_menu("日期分析-最近7日")
+
+    def by_30(self):
+        self.station.to_menu("日期分析-最近30日")
+
+
+class StatisticsDate7Menu(AdminMenu):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "日期分析-最近7日")
+        self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(7)]
+        self.btn_name = ["按投放区域", "按投放类型", "投放类型和区域", "按检查结果", "按检查结果和类型", "按检查结果和区域",
+                         "详细分类"]
+
+    def conf_gui(self, color: str, n: int = 1):
+        super().conf_gui(color, n)
+        self.btn[0]['command'] = self.by_loc
+        self.btn[1]['command'] = self.by_type
+        self.btn[2]['command'] = self.by_type_and_type
+        self.btn[3]['command'] = self.by_result
+        self.btn[4]['command'] = self.by_result_and_type
+        self.btn[5]['command'] = self.by_result_and_loc
+        self.btn[6]['command'] = self.by_detail
+
+    def by_loc(self):
+        self.station.to_program("最近7日-按投放区域")
+
+    def by_type(self):
+        self.station.to_program("最近7日-按投放类型")
+
+    def by_type_and_type(self):
+        self.station.to_program("最近7日-按投放类型和区域")
+
+    def by_result(self):
+        self.station.to_program("最近7日-按检查结果")
+
+    def by_result_and_type(self):
+        self.station.to_program("最近7日-按检查结果和类型")
+
+    def by_result_and_loc(self):
+        self.station.to_program("最近7日-按检查结果和区域")
+
+    def by_detail(self):
+        self.station.to_program("最近7日-详细分类")
+
+
+class StatisticsDate30Menu(AdminMenu):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "日期分析-最近30日")
+        self.btn: List[tk.Button] = [tk.Button(self.frame) for _ in range(7)]
+        self.btn_name = ["按投放区域", "按投放类型", "投放类型和区域", "按检查结果", "按检查结果和类型", "按检查结果和区域",
+                         "详细分类"]
+
+    def conf_gui(self, color: str, n: int = 1):
+        super().conf_gui(color, n)
+        self.btn[0]['command'] = self.by_loc
+        self.btn[1]['command'] = self.by_type
+        self.btn[2]['command'] = self.by_type_and_type
+        self.btn[3]['command'] = self.by_result
+        self.btn[4]['command'] = self.by_result_and_type
+        self.btn[5]['command'] = self.by_result_and_loc
+        self.btn[6]['command'] = self.by_detail
+
+    def by_loc(self):
+        self.station.to_program("最近30日-按投放区域")
+
+    def by_type(self):
+        self.station.to_program("最近30日-按投放类型")
+
+    def by_type_and_type(self):
+        self.station.to_program("最近30日-按投放类型和区域")
+
+    def by_result(self):
+        self.station.to_program("最近30日-按检查结果")
+
+    def by_result_and_type(self):
+        self.station.to_program("最近30日-按检查结果和类型")
+
+    def by_result_and_loc(self):
+        self.station.to_program("最近30日-按检查结果和区域")
+
+    def by_detail(self):
+        self.station.to_program("最近30日-详细分类")
+
+
 class StatisticsUserMenu(AdminMenu):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "积分信用分析")
@@ -321,4 +421,4 @@ class StatisticsPassMenu(AdminMenu):
 
 
 all_menu = [MainMenu, CreateMenu, DeleteMenu, SearchMenu, UpdateMenu, StatisticsMenu, StatisticsTimeMenu,
-            StatisticsUserMenu, StatisticsPassMenu]
+            StatisticsUserMenu, StatisticsPassMenu, StatisticsDateMenu, StatisticsDate7Menu, StatisticsDate30Menu]

+ 263 - 24
tk_ui/admin_program.py

@@ -2,7 +2,7 @@ import abc
 import tkinter as tk
 import tkinter.ttk as ttk
 from tkinter.filedialog import askdirectory, askopenfilename, asksaveasfilename
-import random
+from math import ceil
 
 import matplotlib.pyplot
 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
@@ -1509,9 +1509,9 @@ class UpdateUserProgramBase(AdminProgram):
         set_tk_disable_from_list(self.enter, flat='normal')
 
 
-class UpdateUserScoreBase(UpdateUserProgramBase):
+class UpdateUserScore(UpdateUserProgramBase):
     def __init__(self, station, win, color):
-        super(UpdateUserScoreBase, self).__init__(station, win, color, "更新用户-积分")
+        super(UpdateUserScore, self).__init__(station, win, color, "更新用户-积分")
         self._conf(["用户ID:", "积分:"], "#afdfe4")
 
     def update_by_uid(self):
@@ -1527,9 +1527,9 @@ class UpdateUserScoreBase(UpdateUserProgramBase):
         self.station.push_event(event)
 
 
-class UpdateUserReputationBase(UpdateUserProgramBase):
+class UpdateUserReputation(UpdateUserProgramBase):
     def __init__(self, station, win, color):
-        super(UpdateUserReputationBase, self).__init__(station, win, color, "更新用户-垃圾分类信用")
+        super(UpdateUserReputation, self).__init__(station, win, color, "更新用户-垃圾分类信用")
         self._conf(["用户ID:", "垃圾分类信用:"], "#f8aba6")
 
     def update_by_uid(self):
@@ -1751,7 +1751,7 @@ class UpdateGarbageCheckResultProgram(AdminProgram):
         self.where_enter['state'] = 'normal'
 
 
-class StatisticsTimeBaseProgram(AdminProgram):
+class StatisticsTimeProgramBase(AdminProgram):
     def __init__(self, station, win, color, title: str):
         super().__init__(station, win, color, title)
 
@@ -1956,7 +1956,7 @@ class StatisticsTimeBaseProgram(AdminProgram):
 
                 y = [0 for _ in range(24)]
                 for i in res_count:
-                    y[int(i[0])] = int(i[1])
+                    y[int(i[0])] += int(i[1])
 
                 self.color_show_dict[res_type] = color
                 self.plt_1.bar(label_num, y,
@@ -2005,21 +2005,21 @@ class StatisticsTimeBaseProgram(AdminProgram):
         self.btn_hide['state'] = 'normal'
 
 
-class StatisticsTimeLocProgram(StatisticsTimeBaseProgram):
+class StatisticsTimeLocProgram(StatisticsTimeProgramBase):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "时段分析-按投放区域")
         self._conf("#abc88b")
 
     def refresh(self):
         super().refresh()
-        event = tk_event.CountThrowTimeEvent(self.station).start(["Location"], lambda i: i[2], self)
+        event = tk_event.CountTimeEvent(self.station).start(["Location"], lambda i: i[2], self)
         self.station.push_event(event)
 
     def export(self, *_, **__):
         super().export("Location", lambda i: i[2])
 
 
-class StatisticsTimeTypeProgram(StatisticsTimeBaseProgram):
+class StatisticsTimeTypeProgram(StatisticsTimeProgramBase):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "时段分析-按投放类型")
         self._conf("#abc88b")
@@ -2030,7 +2030,7 @@ class StatisticsTimeTypeProgram(StatisticsTimeBaseProgram):
 
     def refresh(self):
         super().refresh()
-        event = tk_event.CountThrowTimeEvent(self.station).start(["GarbageType"], self.get_name, self)
+        event = tk_event.CountTimeEvent(self.station).start(["GarbageType"], self.get_name, self)
         self.station.push_event(event)
 
     def export(self, *_, **__):
@@ -2042,14 +2042,14 @@ class StatisticsTimeTypeProgram(StatisticsTimeBaseProgram):
         return GarbageType.GarbageTypeStrList_ch[int(data.decode('utf-8'))]
 
 
-class StatisticsTimeTypeLocProgram(StatisticsTimeBaseProgram):
+class StatisticsTimeTypeLocProgram(StatisticsTimeProgramBase):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "时段分析-按投放类型和区域")
         self._conf("#abc88b")
 
     def refresh(self):
         super().refresh()
-        event = tk_event.CountThrowTimeEvent(self.station).start(["GarbageType", "Location"], self.get_name, self)
+        event = tk_event.CountTimeEvent(self.station).start(["GarbageType", "Location"], self.get_name, self)
         self.station.push_event(event)
 
     def export(self, *_, **__):
@@ -2061,7 +2061,7 @@ class StatisticsTimeTypeLocProgram(StatisticsTimeBaseProgram):
         return f"{GarbageType.GarbageTypeStrList_ch[int(data.decode('utf-8'))]}-{i[3]}"
 
 
-class StatisticsTimeCheckResultProgram(StatisticsTimeBaseProgram):
+class StatisticsTimeCheckResultProgram(StatisticsTimeProgramBase):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "时段分析-按检查结果")
         self._conf("#abc88b")
@@ -2070,7 +2070,7 @@ class StatisticsTimeCheckResultProgram(StatisticsTimeBaseProgram):
 
     def refresh(self):
         super().refresh()
-        event = tk_event.CountThrowTimeEvent(self.station).start(["CheckResult"], self.get_name, self)
+        event = tk_event.CountTimeEvent(self.station).start(["CheckResult"], self.get_name, self)
         self.station.push_event(event)
 
     def export(self, *_, **__):
@@ -2082,14 +2082,14 @@ class StatisticsTimeCheckResultProgram(StatisticsTimeBaseProgram):
         return 'Pass' if data == DBBit.BIT_1 else 'Fail'
 
 
-class StatisticsTimeCheckResultAndTypeProgram(StatisticsTimeBaseProgram):
+class StatisticsTimeCheckResultAndTypeProgram(StatisticsTimeProgramBase):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "时段分析-按检查结果和类型")
         self._conf("#abc88b")
 
     def refresh(self):
         super().refresh()
-        event = tk_event.CountThrowTimeEvent(self.station).start(["CheckResult", "GarbageType"], self.get_name, self)
+        event = tk_event.CountTimeEvent(self.station).start(["CheckResult", "GarbageType"], self.get_name, self)
         self.station.push_event(event)
 
     def export(self, *_, **__):
@@ -2103,14 +2103,14 @@ class StatisticsTimeCheckResultAndTypeProgram(StatisticsTimeBaseProgram):
                 f'-{GarbageType.GarbageTypeStrList_ch[int(data_2.decode("utf-8"))]}')
 
 
-class StatisticsTimeCheckResultAndLocProgram(StatisticsTimeBaseProgram):
+class StatisticsTimeCheckResultAndLocProgram(StatisticsTimeProgramBase):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "时段分析-按检查结果和区域")
         self._conf("#abc88b")
 
     def refresh(self):
         super().refresh()
-        event = tk_event.CountThrowTimeEvent(self.station).start(["CheckResult", "Location"], self.get_name, self)
+        event = tk_event.CountTimeEvent(self.station).start(["CheckResult", "Location"], self.get_name, self)
         self.station.push_event(event)
 
     def export(self, *_, **__):
@@ -2122,14 +2122,14 @@ class StatisticsTimeCheckResultAndLocProgram(StatisticsTimeBaseProgram):
         return (f'Pass' if data_1 == DBBit.BIT_1 else 'Fail') + f"-{i[3]}"
 
 
-class StatisticsTimeDetailProgram(StatisticsTimeBaseProgram):
+class StatisticsTimeDetailProgram(StatisticsTimeProgramBase):
     def __init__(self, station, win, color):
         super().__init__(station, win, color, "时段分析-详细分类")
         self._conf("#abc88b")
 
     def refresh(self):
         super().refresh()
-        event = tk_event.CountThrowTimeEvent(self.station)
+        event = tk_event.CountTimeEvent(self.station)
         event.start(["CheckResult", "GarbageType", "Location"], self.get_name, self)
         self.station.push_event(event)
 
@@ -2612,15 +2612,254 @@ class StatisticsPassRateTypeAndLocProgram(StatisticsUserBaseProgram):
         self.station.push_event(event)
 
 
+class StatisticsDateProgramBase(StatisticsTimeProgramBase):
+    def _conf(self, bg_color, days: int = 7, days_sep: int = 1):
+        super(StatisticsDateProgramBase, self)._conf(bg_color)
+        self._days = days
+        self._days_sep = days_sep
+
+    def export(self, title, func: Callable):
+        path = asksaveasfilename(title='选择CSV文件保存位置', filetypes=[("CSV", ".csv")])
+        if not path.endswith(".csv"):
+            path += ".csv"
+        with open(path, "w") as f:
+            f.write(f"Days, Count, {title}\n")
+            for i in self.export_lst:
+                f.write(f"{i[0]}, {i[1]}, {func(i)}\n")
+        self.station.show_msg("保存数据", f"数据导出成功\n保存位置:\n  {path}")
+
+    def show_result(self, res: Dict[str, any], lst: List):
+        bottom = np.zeros(self._days)
+        label_num = [i for i in range(self._days)]
+        label_str = [f"{i}" for i in range(self._days)]
+
+        res_type_lst: List = res['res_type']
+        self.export_lst = lst
+        max_y_plot = 1  # max_y的最大值
+        max_y_bar = 1  # max_y的最大值
+        for res_type in res_type_lst:
+            res_count: Tuple[str] = res[res_type]
+            if len(res_count) != 0:
+                color = self.check_show(res_type)
+                if color is None:
+                    continue
+
+                y = [0 for _ in range(self._days)]
+                for i in range(0, len(res_count)):  # 反向迭代列表
+                    index = self._days - res_count[i - 1][0] - 1  # 反向排序
+                    y[index] += int(res_count[i - 1][1])
+
+                max_y_plot = max(max(y), max_y_plot)
+                self.color_show_dict[res_type] = color
+                self.plt_1.plot(label_num, y,
+                                color=color,
+                                label=res_type)
+                self.plt_2.bar(label_num, y,
+                               color=color,
+                               align="center",
+                               bottom=bottom,
+                               tick_label=label_str,
+                               label=res_type)
+                bottom += np.array(y)
+
+        if self.legend_show[1].get() == 1:  # 显示图例
+            self.plt_1.legend(loc="upper left")
+            self.plt_2.legend(loc="upper left")
+
+        self.plt_1.set_xlim(-1, self._days)
+        self.plt_1.set_xticks([i for i in range(0, self._days, self._days_sep)])
+        self.plt_1.set_xticklabels([f"{i}d" for i in range(self._days - 1, -1, -self._days_sep)])  # 倒序
+
+        self.plt_1.set_ylim(0, max_y_plot + max_y_plot * 0.1)
+        step = ceil(max_y_plot / 4)  # 向上取整
+        if step > 0:
+            y_ticks = [i for i in range(0, max_y_plot, step)]
+            y_ticklabels = [f'{i}' for i in range(0, max_y_plot, step)]
+        else:
+            y_ticks = []
+            y_ticklabels = []
+        y_ticks.append(max_y_plot)
+        y_ticklabels.append(f"{max_y_plot}")
+        self.plt_1.set_yticks(y_ticks)
+        self.plt_1.set_yticklabels(y_ticklabels)  # 倒序
+
+        self.plt_1.set_title(f"{self.program_title}折现图")
+
+        self.plt_2.set_xlim(-1, self._days)
+        self.plt_2.set_xticks([i for i in range(0, self._days, self._days_sep)])
+        self.plt_2.set_xticklabels([f"{i}d" for i in range(self._days - 1, -1, -self._days_sep)])
+
+        max_y_bar = int(max(bottom.max(), max_y_bar))
+        self.plt_2.set_ylim(0, max_y_bar + max_y_bar * 0.1)
+        step = ceil(max_y_bar / 4)  # 向上取整
+        if step > 0:
+            y_ticks = [i for i in range(0, max_y_bar, step)]
+            y_ticklabels = [f'{i}' for i in range(0, max_y_bar, step)]
+        else:
+            y_ticks = []
+            y_ticklabels = []
+        y_ticks.append(max_y_bar)
+        y_ticklabels.append(f"{max_y_bar}")
+        self.plt_2.set_yticks(y_ticks)
+        self.plt_2.set_yticklabels(y_ticklabels)  # 倒序
+
+        self.plt_2.set_title(f"{self.program_title}柱状图")
+
+        self.canvas.draw()
+        self.toolbar.update()
+        self.update_listbox()
+
+
+class StatisticsDateTypeProgram(StatisticsDateProgramBase):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "最近7日-按投放类型")
+        self._conf("#abc88b", 7, 1)
+        self.color_show_dict[GarbageType.GarbageTypeStrList_ch[1]] = "#00BFFF"
+        self.color_show_dict[GarbageType.GarbageTypeStrList_ch[2]] = "#32CD32"
+        self.color_show_dict[GarbageType.GarbageTypeStrList_ch[3]] = "#DC143C"
+        self.color_show_dict[GarbageType.GarbageTypeStrList_ch[4]] = "#A9A9A9"
+
+    def refresh(self):
+        super().refresh()
+        event = tk_event.CountDateEvent(self.station).start(7, ["GarbageType"], self.get_name, self)
+        self.station.push_event(event)
+
+    def export(self, *_, **__):
+        super().export("Type", self.get_name)
+
+    @staticmethod
+    def get_name(i: Tuple):
+        data: bytes = i[2]
+        return GarbageType.GarbageTypeStrList_ch[int(data.decode('utf-8'))]
+
+
+class StatisticsDateLocProgram(StatisticsDateProgramBase):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "最近7日-按投放区域")
+        self._conf("#abc88b", 7, 1)
+
+    def refresh(self):
+        super().refresh()
+        event = tk_event.CountDateEvent(self.station).start(7, ["Location"], lambda i: i[2], self)
+        self.station.push_event(event)
+
+    def export(self, *_, **__):
+        super().export("Location", lambda i: i[2])
+
+
+class StatisticsDateTypeLocProgram(StatisticsDateProgramBase):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "最近7日-按投放类型和区域")
+        self._conf("#abc88b", 7, 1)
+
+    def refresh(self):
+        super().refresh()
+        event = tk_event.CountDateEvent(self.station).start(7, ["GarbageType", "Location"], self.get_name, self)
+        self.station.push_event(event)
+
+    def export(self, *_, **__):
+        super().export("Type-Location", self.get_name)
+
+    @staticmethod
+    def get_name(i: Tuple):
+        data: bytes = i[2]
+        return f"{GarbageType.GarbageTypeStrList_ch[int(data.decode('utf-8'))]}-{i[3]}"
+
+
+class StatisticsDateCheckResultProgram(StatisticsDateProgramBase):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "最近7日-按检查结果")
+        self._conf("#abc88b", 7, 1)
+        self.color_show_dict['Pass'] = "#00BFFF"
+        self.color_show_dict['Fail'] = "#DC143C"
+
+    def refresh(self):
+        super().refresh()
+        event = tk_event.CountDateEvent(self.station).start(7, ["CheckResult"], self.get_name, self)
+        self.station.push_event(event)
+
+    def export(self, *_, **__):
+        super().export("Result", self.get_name)
+
+    @staticmethod
+    def get_name(i: Tuple):
+        data: int = i[2]  # 返回garbage表时, BIT类型都是按bytes回传的, 但garbage_7和garbage_30会以int的方式回传
+        return 'Pass' if data == 1 else 'Fail'
+
+
+class StatisticsDateCheckResultAndTypeProgram(StatisticsDateProgramBase):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "最近7日-按检查结果和类型")
+        self._conf("#abc88b", 7, 1)
+
+    def refresh(self):
+        super().refresh()
+        event = tk_event.CountDateEvent(self.station).start(7, ["CheckResult", "GarbageType"], self.get_name, self)
+        self.station.push_event(event)
+
+    def export(self, *_, **__):
+        super().export("Result-Location", self.get_name)
+
+    @staticmethod
+    def get_name(i: Tuple):
+        data_1: int = i[2]
+        data_2: bytes = i[3]
+        return ((f'Pass' if data_1 == 1 else 'Fail') +
+                f'-{GarbageType.GarbageTypeStrList_ch[int(data_2.decode("utf-8"))]}')
+
+
+class StatisticsDateCheckResultAndLocProgram(StatisticsDateProgramBase):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "最近7日-按检查结果和区域")
+        self._conf("#abc88b", 7, 1)
+
+    def refresh(self):
+        super().refresh()
+        event = tk_event.CountDateEvent(self.station).start(7, ["CheckResult", "Location"], self.get_name, self)
+        self.station.push_event(event)
+
+    def export(self, *_, **__):
+        super().export("Result-Type", self.get_name)
+
+    @staticmethod
+    def get_name(i: Tuple):
+        data_1: int = i[2]
+        return (f'Pass' if data_1 == 1 else 'Fail') + f"-{i[3]}"
+
+
+class StatisticsDateDetailProgram(StatisticsDateProgramBase):
+    def __init__(self, station, win, color):
+        super().__init__(station, win, color, "最近7日-详细分类")
+        self._conf("#abc88b", 7, 1)
+
+    def refresh(self):
+        super().refresh()
+        event = tk_event.CountDateEvent(self.station)
+        event.start(7, ["CheckResult", "GarbageType", "Location"], self.get_name, self)
+        self.station.push_event(event)
+
+    def export(self, *_, **__):
+        super().export("Detail", self.get_name)
+
+    @staticmethod
+    def get_name(i: Tuple):
+        data_1: int = i[2]
+        data_2: bytes = i[3]
+        return ((f'Pass' if data_1 == 1 else 'Fail') +
+                f'-{GarbageType.GarbageTypeStrList_ch[int(data_2.decode("utf-8"))]}' + f'-{i[4]}')
+
+
 all_program = [WelcomeProgram, CreateNormalUserProgram, CreateManagerUserProgram, CreateAutoNormalUserProgram,
                CreateGarbageProgram, DeleteUserProgram, DeleteUsersProgram, DeleteGarbageProgram,
                DeleteGarbageMoreProgram, DeleteAllGarbageProgram, SearchUserProgram, SearchUserAdvancedProgram,
-               SearchGarbageProgram, SearchGarbageAdvancedProgram, SearchAdvancedProgram, UpdateUserScoreBase,
-               UpdateUserReputationBase, UpdateGarbageTypeProgram, UpdateGarbageCheckResultProgram,
+               SearchGarbageProgram, SearchGarbageAdvancedProgram, SearchAdvancedProgram, UpdateUserScore,
+               UpdateUserReputation, UpdateGarbageTypeProgram, UpdateGarbageCheckResultProgram,
                ExportGarbageProgram, ExportUserProgram, CreateUserFromCSVProgram, AboutProgram,
                StatisticsTimeLocProgram, StatisticsTimeTypeProgram, StatisticsTimeTypeLocProgram,
                StatisticsTimeCheckResultProgram, StatisticsTimeCheckResultAndTypeProgram,
                StatisticsTimeCheckResultAndLocProgram, StatisticsTimeDetailProgram, StatisticsUserTinyProgram,
                StatisticsUserLargeProgram, StatisticsScoreDistributedProgram, StatisticsReputationDistributedProgram,
                StatisticsPassRateGlobalProgram, StatisticsPassRateTypeProgram, StatisticsPassRateLocProgram,
-               StatisticsPassRateTypeAndLocProgram]
+               StatisticsPassRateTypeAndLocProgram, StatisticsDateTypeProgram, StatisticsDateLocProgram,
+               StatisticsDateTypeLocProgram, StatisticsDateCheckResultProgram, StatisticsDateCheckResultAndTypeProgram,
+               StatisticsDateCheckResultAndLocProgram, StatisticsDateDetailProgram]