Compare commits
	
		
			5 Commits
		
	
	
		
			bb3ae1e65a
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 062b1e24e9 | |||
| ed947743fc | |||
| 943130b875 | |||
| 1c47497fc2 | |||
| c7c0d15545 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -3,4 +3,5 @@
 | 
				
			|||||||
rokae/testbench.py
 | 
					rokae/testbench.py
 | 
				
			||||||
**/__pycache__/
 | 
					**/__pycache__/
 | 
				
			||||||
NOTRACK/
 | 
					NOTRACK/
 | 
				
			||||||
gui/assets/database/
 | 
					toolbox/assets/database/
 | 
				
			||||||
 | 
					toolbox/output/
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "ip_addr": "192.168.0.160",
 | 
					    "ip_addr": "192.168.2.160",
 | 
				
			||||||
    "ssh_port": "22",
 | 
					    "ssh_port": "22",
 | 
				
			||||||
    "socket_port": 5050,
 | 
					    "socket_port": 5050,
 | 
				
			||||||
    "xService_port": 6666,
 | 
					    "xService_port": 6666,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "minimum_password_length": 8,
 | 
					    "minimum_password_length": 8,
 | 
				
			||||||
    "maximum_db_number": 10,
 | 
					    "maximum_db_number": 10,
 | 
				
			||||||
 | 
					    "log_number_per_page": 30,
 | 
				
			||||||
    "database_path": "",
 | 
					    "database_path": "",
 | 
				
			||||||
    "api_ali_pay": "",
 | 
					    "api_ali_pay": "",
 | 
				
			||||||
    "api_wechat_pay": ""
 | 
					    "api_wechat_pay": ""
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								toolbox/assets/conf/qss/home_overlay.qss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					LunarClockLabel#lb_time {
 | 
				
			||||||
 | 
					    color: rgba(255,255,255,255);
 | 
				
			||||||
 | 
					    font: 96px "Arial Black";
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LunarClockLabel#lb_date {
 | 
				
			||||||
 | 
					    color: rgba(255,255,255,255);
 | 
				
			||||||
 | 
					    font: 18px "Consolas";
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QLabel#lb_name {
 | 
				
			||||||
 | 
					    color: rgba(255,255,255,255);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QFrame#line_left,
 | 
				
			||||||
 | 
					QFrame#line_right {
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					    background-color: rgba(255, 255, 255, 40);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QLabel#lb_proverb {
 | 
				
			||||||
 | 
					    color: rgba(255,255,255,255);
 | 
				
			||||||
 | 
					    font: 20px "Consolas";
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										92
									
								
								toolbox/assets/conf/qss/list_widget.qss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					/* ------ 整体画布 ------ */
 | 
				
			||||||
 | 
					QListWidget#SListWidget {
 | 
				
			||||||
 | 
					    background: #ffffff;
 | 
				
			||||||
 | 
					    border: 1px solid #d0d7de;
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					    outline: none;
 | 
				
			||||||
 | 
					    color: #24292f;                    /* 默认文字色 */
 | 
				
			||||||
 | 
					    font-family: "Consolas";
 | 
				
			||||||
 | 
					    font-size: 18px;
 | 
				
			||||||
 | 
					    gridline-color: transparent;       /* 网格线 */
 | 
				
			||||||
 | 
					    /* 交替行颜色(需代码 setAlternatingRowColors(true)) */
 | 
				
			||||||
 | 
					    alternate-background-color: #f6f8fa;
 | 
				
			||||||
 | 
					    /* 滚动条圆角背景 */
 | 
				
			||||||
 | 
					    background-clip: padding;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 单项(行) ------ */
 | 
				
			||||||
 | 
					QListWidget#SListWidget::item {
 | 
				
			||||||
 | 
					    height: 36px;                      /* 固定行高 */
 | 
				
			||||||
 | 
					    padding-left: 12px;
 | 
				
			||||||
 | 
					    padding-right: 8px;
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					    /* 行内文字对齐方式 */
 | 
				
			||||||
 | 
					    text-align: left;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 选中态 */
 | 
				
			||||||
 | 
					QListWidget#SListWidget::item:selected {
 | 
				
			||||||
 | 
					    background: #0969da;
 | 
				
			||||||
 | 
					    color: #ffffff;
 | 
				
			||||||
 | 
					    border-left: 0px solid #0550ae;    /* 左侧高亮条 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 悬停态(未选中) */
 | 
				
			||||||
 | 
					QListWidget#SListWidget::item:hover:!selected {
 | 
				
			||||||
 | 
					    background: rgba(9, 105, 218, 12%);
 | 
				
			||||||
 | 
					    border-left: 4px solid transparent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 禁用态 */
 | 
				
			||||||
 | 
					QListWidget#SListWidget::item:disabled {
 | 
				
			||||||
 | 
					    color: #8c959f;
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 图标区域 ------ */
 | 
				
			||||||
 | 
					QListWidget#SListWidget::icon {
 | 
				
			||||||
 | 
					    padding-right: 8px;                /* 图标与文字间距 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 滚动条(仅影响 #SListWidget) ------ */
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar:vertical {
 | 
				
			||||||
 | 
					    width: 10px;
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::handle:vertical {
 | 
				
			||||||
 | 
					    background: #c0c6cc;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					    min-height: 30px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::handle:vertical:hover {
 | 
				
			||||||
 | 
					    background: #a0a6ac;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::add-line:vertical,
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::sub-line:vertical {
 | 
				
			||||||
 | 
					    height: 0;                         /* 隐藏上下箭头 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar:horizontal {
 | 
				
			||||||
 | 
					    height: 10px;
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::handle:horizontal {
 | 
				
			||||||
 | 
					    background: #c0c6cc;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					    min-width: 30px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::handle:horizontal:hover {
 | 
				
			||||||
 | 
					    background: #a0a6ac;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::add-line:horizontal,
 | 
				
			||||||
 | 
					QListWidget#SListWidget QScrollBar::sub-line:horizontal {
 | 
				
			||||||
 | 
					    width: 0;                          /* 隐藏左右箭头 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 拖拽插入指示器(可选) ------ */
 | 
				
			||||||
 | 
					QListWidget#SListWidget::drop-indicator {
 | 
				
			||||||
 | 
					    background: #0969da;
 | 
				
			||||||
 | 
					    width: 2px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								toolbox/assets/conf/qss/statusbar.qss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					QStatusBar#SStatusBar {
 | 
				
			||||||
 | 
					    background: #8B8989;   /* 背景色 */
 | 
				
			||||||
 | 
					    color: #000000;        /* 文字色 */
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					    font: 16px "Consolas";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								toolbox/assets/conf/qss/toolbar.qss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					QToolBar#SToolBar {
 | 
				
			||||||
 | 
					    background: #eef1f5;             /* 背景色 */
 | 
				
			||||||
 | 
					    border: none;                    /* 去掉默认边框 */
 | 
				
			||||||
 | 
					    border-bottom: 2px solid #d0d7de;/* 底部分隔线 */
 | 
				
			||||||
 | 
					    spacing: 2px;                    /* 图标/按钮间距 */
 | 
				
			||||||
 | 
					    padding: 2px 4px;                /* 内边距:上下/左右 */
 | 
				
			||||||
 | 
					    min-height: 20px;                /* 最小高度 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 工具栏里所有 QToolButton(图标按钮) */
 | 
				
			||||||
 | 
					QToolBar#SToolBar QToolButton {
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					    border: 1px solid transparent;
 | 
				
			||||||
 | 
					    border-radius: 8px;
 | 
				
			||||||
 | 
					    color: #24292f;
 | 
				
			||||||
 | 
					    font: 18px "Consolas";
 | 
				
			||||||
 | 
					    padding: 0px 0px;
 | 
				
			||||||
 | 
					    margin: 0px 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 悬停 */
 | 
				
			||||||
 | 
					QToolBar#SToolBar QToolButton:hover {
 | 
				
			||||||
 | 
					    background: rgba(9, 105, 218, 12%);
 | 
				
			||||||
 | 
					    border-color: #0969da;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 按下/选中 */
 | 
				
			||||||
 | 
					QToolBar#SToolBar QToolButton:pressed,
 | 
				
			||||||
 | 
					QToolBar#SToolBar QToolButton:checked {
 | 
				
			||||||
 | 
					    background: #0969da;
 | 
				
			||||||
 | 
					    color: #ffffff;
 | 
				
			||||||
 | 
					    border-color: #0550ae;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 仅工具栏里 objectName = ac_switch 的按钮 */
 | 
				
			||||||
 | 
					QToolBar#SToolBar QToolButton#ac_switch {
 | 
				
			||||||
 | 
					    background: #eef1f5;
 | 
				
			||||||
 | 
					    border: none;
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					    color: #fff;
 | 
				
			||||||
 | 
					    font: 14px "Microsoft YaHei";
 | 
				
			||||||
 | 
					    padding: 4px 6px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QToolBar#SToolBar QToolButton#ac_switch:hover {
 | 
				
			||||||
 | 
					    background: #eef1f5;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QToolBar#toolBar QToolButton#ac_switch:pressed {
 | 
				
			||||||
 | 
					    background: #0550ae;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										121
									
								
								toolbox/assets/conf/qss/w08_log.qss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					/* ------ 整体画布 ------ */
 | 
				
			||||||
 | 
					QTreeWidget#treeW {
 | 
				
			||||||
 | 
					    background: #ffffff;
 | 
				
			||||||
 | 
					    border: 1px solid #d0d7de;
 | 
				
			||||||
 | 
					    border-radius: 8px;
 | 
				
			||||||
 | 
					    outline: none;
 | 
				
			||||||
 | 
					    color: #24292f;                    /* 默认文字色 */
 | 
				
			||||||
 | 
					    font-family: "Consolas";
 | 
				
			||||||
 | 
					    font-size: 16px;
 | 
				
			||||||
 | 
					    gridline-color: #e1e4e8;       /* 网格线 */
 | 
				
			||||||
 | 
					    show-decoration-selected: 1;       /* 整行选中 */
 | 
				
			||||||
 | 
					    background-clip: padding;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 表头 ------ */
 | 
				
			||||||
 | 
					QHeaderView#header {
 | 
				
			||||||
 | 
					    background: #eef1f5;
 | 
				
			||||||
 | 
					    border-left: 1px solid #d0d7de;
 | 
				
			||||||
 | 
					    border-bottom: 1px solid #d0d7de;
 | 
				
			||||||
 | 
					    border-right: none;   /* 最右列去线 */
 | 
				
			||||||
 | 
					    font-weight: 600;
 | 
				
			||||||
 | 
					    font-size: 16px;
 | 
				
			||||||
 | 
					    color: #57606a;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QHeaderView#header:section {
 | 
				
			||||||
 | 
					    padding: 6px 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QHeaderView#header:section:hover {
 | 
				
			||||||
 | 
					    background: rgba(9, 105, 218, 12%);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 行(item) ------ */
 | 
				
			||||||
 | 
					QTreeWidget#treeW::item {
 | 
				
			||||||
 | 
					    height: 25px;                      /* 固定行高 */
 | 
				
			||||||
 | 
					    padding-left: 8px;
 | 
				
			||||||
 | 
					    /*border-right: 1px solid #e1e4e8;
 | 
				
			||||||
 | 
					    border-bottom: 1px solid #e1e4e8;*/
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QTreeWidget#treeW::item:selected {
 | 
				
			||||||
 | 
					    background: #0969da;
 | 
				
			||||||
 | 
					    color: #ffffff;
 | 
				
			||||||
 | 
					    border-left: 0px solid #0550ae;    /* 左侧高亮条 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW::item:hover:!selected {
 | 
				
			||||||
 | 
					    background: rgba(9, 105, 218, 12%);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW::item:disabled {
 | 
				
			||||||
 | 
					    color: #8c959f;
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 分支指示器(三角) ------ */
 | 
				
			||||||
 | 
					QTreeWidget#treeW::branch {
 | 
				
			||||||
 | 
					    width: 0px;
 | 
				
			||||||
 | 
					    height: 0px;
 | 
				
			||||||
 | 
					    image: none;      /* 也不画三角 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------ 滚动条(仅影响 #treeW) ------ */
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar:vertical {
 | 
				
			||||||
 | 
					    width: 10px;
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::handle:vertical {
 | 
				
			||||||
 | 
					    background: #c0c6cc;
 | 
				
			||||||
 | 
					    border-radius: 3px;
 | 
				
			||||||
 | 
					    min-height: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::handle:vertical:hover {
 | 
				
			||||||
 | 
					    background: #a0a6ac;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::add-line:vertical,
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::sub-line:vertical {
 | 
				
			||||||
 | 
					    height: 0;                         /* 隐藏箭头 */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar:horizontal {
 | 
				
			||||||
 | 
					    height: 10px;
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::handle:horizontal {
 | 
				
			||||||
 | 
					    background: #c0c6cc;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					    min-width: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::handle:horizontal:hover {
 | 
				
			||||||
 | 
					    background: #a0a6ac;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::add-line:horizontal,
 | 
				
			||||||
 | 
					QTreeWidget#treeW QScrollBar::sub-line:horizontal {
 | 
				
			||||||
 | 
					    width: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QPushButton#pb_search,
 | 
				
			||||||
 | 
					QPushButton#pb_previous,
 | 
				
			||||||
 | 
					QPushButton#pb_next {
 | 
				
			||||||
 | 
					    font-family: "Consolas";
 | 
				
			||||||
 | 
					    font-size: 18px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QLabel#lb_page {
 | 
				
			||||||
 | 
					    font-family: "Consolas";
 | 
				
			||||||
 | 
					    font-size: 18px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QCheckBox#box_info,
 | 
				
			||||||
 | 
					QCheckBox#box_warning,
 | 
				
			||||||
 | 
					QCheckBox#box_error,
 | 
				
			||||||
 | 
					QCheckBox#box_exception,
 | 
				
			||||||
 | 
					QCheckBox#box_unknown {
 | 
				
			||||||
 | 
					    font-family: "Consolas";
 | 
				
			||||||
 | 
					    font-size: 18px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QLineEdit#le_search {
 | 
				
			||||||
 | 
					    font-family: "Consolas";
 | 
				
			||||||
 | 
					    font-size: 18px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB  | 
| 
		 Before Width: | Height: | Size: 327 KiB After Width: | Height: | Size: 322 KiB  | 
| 
		 Before Width: | Height: | Size: 329 KiB  | 
| 
		 Before Width: | Height: | Size: 322 KiB  | 
| 
		 Before Width: | Height: | Size: 327 KiB  | 
| 
		 Before Width: | Height: | Size: 327 KiB  | 
| 
		 Before Width: | Height: | Size: 327 KiB  | 
| 
		 Before Width: | Height: | Size: 328 KiB  | 
| 
		 Before Width: | Height: | Size: 320 KiB  | 
| 
		 After Width: | Height: | Size: 322 KiB  | 
| 
		 Before Width: | Height: | Size: 326 KiB After Width: | Height: | Size: 326 KiB  | 
| 
		 Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 322 KiB  | 
| 
		 After Width: | Height: | Size: 326 KiB  | 
| 
		 Before Width: | Height: | Size: 324 KiB After Width: | Height: | Size: 324 KiB  | 
| 
		 After Width: | Height: | Size: 321 KiB  | 
| 
		 After Width: | Height: | Size: 324 KiB  | 
| 
		 After Width: | Height: | Size: 313 KiB  | 
| 
		 After Width: | Height: | Size: 321 KiB  | 
| 
		 After Width: | Height: | Size: 312 KiB  | 
| 
		 After Width: | Height: | Size: 313 KiB  | 
| 
		 After Width: | Height: | Size: 315 KiB  | 
| 
		 After Width: | Height: | Size: 312 KiB  | 
| 
		 After Width: | Height: | Size: 315 KiB  | 
| 
		 After Width: | Height: | Size: 314 KiB  | 
| 
		 After Width: | Height: | Size: 319 KiB  | 
| 
		 After Width: | Height: | Size: 319 KiB  | 
| 
		 After Width: | Height: | Size: 327 KiB  | 
| 
		 After Width: | Height: | Size: 321 KiB  | 
| 
		 After Width: | Height: | Size: 330 KiB  | 
| 
		 After Width: | Height: | Size: 330 KiB  | 
| 
		 After Width: | Height: | Size: 329 KiB  | 
| 
		 After Width: | Height: | Size: 325 KiB  | 
| 
		 After Width: | Height: | Size: 322 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								toolbox/assets/media/buttons/RGB.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 10 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								toolbox/assets/media/buttons/颜色库.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								toolbox/assets/media/switch_off.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								toolbox/assets/media/switch_on.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.0 KiB  | 
@@ -1,15 +1,33 @@
 | 
				
			|||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
from threading import Lock
 | 
					from threading import Lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
base_path = Path(__file__).resolve().parent.parent.parent
 | 
					
 | 
				
			||||||
lock = Lock()
 | 
					lock = Lock()
 | 
				
			||||||
account = None
 | 
					config = None
 | 
				
			||||||
code_dict = [4, 11, 4, 31, 22, 12, 19, 23, 7, 16, 7, 23, 1, 8, 7, 18, 27, 32, 28, 25, 7, 32, 9, 15, 2, 32, 0, 12, 26, 15, 14, 17]
 | 
					code_dict = [4, 11, 4, 31, 22, 12, 19, 23, 7, 16, 7, 23, 1, 8, 7, 18, 27, 32, 28, 25, 7, 32, 9, 15, 2, 32, 0, 12, 26, 15, 14, 17]
 | 
				
			||||||
username, password = "", ""
 | 
					username, password = "", ""
 | 
				
			||||||
avatar = f"{base_path}/assets/media/avatar.jpg"
 | 
					 | 
				
			||||||
proverb = "佛曰:Time will say~"
 | 
					proverb = "佛曰:Time will say~"
 | 
				
			||||||
bg = f"{base_path}/assets/media/bg.jpg"
 | 
					 | 
				
			||||||
win_width, win_height = 1100, 500
 | 
					win_width, win_height = 1100, 500
 | 
				
			||||||
 | 
					conn, cursor = None, None
 | 
				
			||||||
 | 
					listW_items = {"实用工具": "w10_practical", "效率提升": "w20_efficiency", "财务分析": "w30_financial"}
 | 
				
			||||||
 | 
					caller_frame = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					base_path = Path(__file__).resolve().parent.parent.parent
 | 
				
			||||||
 | 
					db_file = base_path / "assets/database/toolbox.db"
 | 
				
			||||||
 | 
					bg = f"{base_path}/assets/media/bg.jpg"
 | 
				
			||||||
 | 
					avatar = f"{base_path}/assets/media/avatar.jpg"
 | 
				
			||||||
 | 
					icon = f"{base_path}/assets/media/icon.ico"
 | 
				
			||||||
 | 
					logo = f"{base_path}/assets/media/logo.png"
 | 
				
			||||||
 | 
					on_icon = f"{base_path}/assets/media/switch_on.png"
 | 
				
			||||||
 | 
					off_icon = f"{base_path}/assets/media/switch_off.png"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qss_home_overlay = f"{base_path}/assets/conf/qss/home_overlay.qss"
 | 
				
			||||||
 | 
					qss_list_widget = f"{base_path}/assets/conf/qss/list_widget.qss"
 | 
				
			||||||
 | 
					qss_toolbar = f"{base_path}/assets/conf/qss/toolbar.qss"
 | 
				
			||||||
 | 
					qss_statusbar = f"{base_path}/assets/conf/qss/statusbar.qss"
 | 
				
			||||||
 | 
					qss_w08_log = f"{base_path}/assets/conf/qss/w08_log.qss"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def delete_files_in_directory(directory):
 | 
					def delete_files_in_directory(directory):
 | 
				
			||||||
    path = Path(directory)
 | 
					    path = Path(directory)
 | 
				
			||||||
    if path.exists() and path.is_dir():
 | 
					    if path.exists() and path.is_dir():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,16 @@
 | 
				
			|||||||
import sqlite3
 | 
					import sqlite3
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					from inspect import currentframe
 | 
				
			||||||
 | 
					from functools import singledispatch, wraps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from codes.common import clibs
 | 
					from codes.common import clibs
 | 
				
			||||||
from pathlib import Path
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def db_init(db_file):
 | 
					def db_init():
 | 
				
			||||||
    conn = sqlite3.connect(db_file, isolation_level=None, check_same_thread=False, cached_statements=2048, timeout=10.0)
 | 
					    if clibs.db_file.exists():
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conn = sqlite3.connect(clibs.db_file, isolation_level=None, check_same_thread=False, cached_statements=2048, timeout=10.0)
 | 
				
			||||||
    cursor = conn.cursor()
 | 
					    cursor = conn.cursor()
 | 
				
			||||||
    cursor.execute("PRAGMA journal_mode=wal")
 | 
					    cursor.execute("PRAGMA journal_mode=wal")
 | 
				
			||||||
    cursor.execute("PRAGMA wal_checkpoint=TRUNCATE")
 | 
					    cursor.execute("PRAGMA wal_checkpoint=TRUNCATE")
 | 
				
			||||||
@@ -35,14 +40,20 @@ def db_init(db_file):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    cursor.execute(f"INSERT INTO logs (level, module, content) VALUES (?, ?, ?)", ("info", "login_ui", "数据库初始化成功!"))
 | 
				
			||||||
    cursor.close()
 | 
					    cursor.close()
 | 
				
			||||||
    conn.close()
 | 
					    conn.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def db_lock(func):
 | 
					def db_lock(func):
 | 
				
			||||||
 | 
					    @wraps(func)
 | 
				
			||||||
    def wrapper(*args, **kwargs):
 | 
					    def wrapper(*args, **kwargs):
 | 
				
			||||||
 | 
					        clibs.caller_frame = currentframe().f_back
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            clibs.lock.acquire(True)
 | 
					            clibs.lock.acquire(True)
 | 
				
			||||||
            ret = func(*args, **kwargs)
 | 
					            ret = func(*args, **kwargs)
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            print(f"db operation error: {e}")
 | 
				
			||||||
 | 
					            ret = None
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            clibs.lock.release()
 | 
					            clibs.lock.release()
 | 
				
			||||||
        return ret
 | 
					        return ret
 | 
				
			||||||
@@ -50,31 +61,87 @@ def db_lock(func):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def db_backup():
 | 
					def db_backup():
 | 
				
			||||||
    t = time.strftime("%Y%m%d%H%M%S", time.localtime())
 | 
					    t = time.strftime("%Y%m%d%H%M%S", time.localtime())
 | 
				
			||||||
    db_file = clibs.base_path / "assets/database/toolbox.db"
 | 
					 | 
				
			||||||
    db_file_backup = clibs.base_path / f"assets/database/toolbox.{t}.db"
 | 
					    db_file_backup = clibs.base_path / f"assets/database/toolbox.{t}.db"
 | 
				
			||||||
    if not (db_file.exists() and db_file.is_file()):
 | 
					    db_file_backup.write_bytes(clibs.db_file.read_bytes())
 | 
				
			||||||
        db_init(db_file)
 | 
					    db_dir = clibs.base_path / "assets/database"
 | 
				
			||||||
    else:
 | 
					    db_list = [db for db in db_dir.glob("*.db")]
 | 
				
			||||||
        db_file_backup.write_bytes(db_file.read_bytes())
 | 
					    for db in sorted(db_list)[:-clibs.config["maximum_db_number"]]:
 | 
				
			||||||
        db_dir = clibs.base_path / "assets/database"
 | 
					        db.unlink()
 | 
				
			||||||
        db_list = [db for db in db_dir.glob("*.db")]
 | 
					 | 
				
			||||||
        for db in sorted(db_list)[:-clibs.account["maximum_db_number"]]:
 | 
					 | 
				
			||||||
            db.unlink()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def db_conn():
 | 
					def db_conn():
 | 
				
			||||||
    db_file = clibs.base_path / "assets/database/toolbox.db"
 | 
					    # import traceback, inspect
 | 
				
			||||||
    conn = sqlite3.connect(db_file, isolation_level=None, check_same_thread=False, cached_statements=2048, timeout=3.0)
 | 
					    # print("[Conn] 被调用", traceback.format_stack()[-2])
 | 
				
			||||||
    cursor = conn.cursor()
 | 
					    # print("[Conn] conn=", clibs.conn, "cursor=", clibs.cursor)
 | 
				
			||||||
    cursor.execute("PRAGMA journal_mode=wal")
 | 
					
 | 
				
			||||||
    cursor.execute("PRAGMA wal_checkpoint=TRUNCATE")
 | 
					    if clibs.conn is not None:
 | 
				
			||||||
    cursor.execute("PRAGMA synchronous=normal")
 | 
					        return
 | 
				
			||||||
    cursor.execute("PRAGMA temp_store=memory")
 | 
					
 | 
				
			||||||
    cursor.execute("PRAGMA mmap_size=30000000000")
 | 
					    clibs.conn = sqlite3.connect(clibs.db_file, isolation_level=None, check_same_thread=False, cached_statements=2048, timeout=3.0)
 | 
				
			||||||
    cursor.execute("PRAGMA cache_size=200000")
 | 
					    clibs.cursor = clibs.conn.cursor()
 | 
				
			||||||
    return conn, cursor
 | 
					    clibs.cursor.execute("PRAGMA journal_mode=wal")
 | 
				
			||||||
 | 
					    clibs.cursor.execute("PRAGMA wal_checkpoint=TRUNCATE")
 | 
				
			||||||
 | 
					    clibs.cursor.execute("PRAGMA synchronous=normal")
 | 
				
			||||||
 | 
					    clibs.cursor.execute("PRAGMA temp_store=memory")
 | 
				
			||||||
 | 
					    clibs.cursor.execute("PRAGMA mmap_size=30000000000")
 | 
				
			||||||
 | 
					    clibs.cursor.execute("PRAGMA cache_size=200000")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@db_lock
 | 
					@db_lock
 | 
				
			||||||
def db_close(conn, cursor):
 | 
					def db_close():
 | 
				
			||||||
    cursor.close()
 | 
					    if clibs.cursor is not None:
 | 
				
			||||||
    conn.close()
 | 
					        clibs.cursor.close()
 | 
				
			||||||
 | 
					    if clibs.conn is not None:
 | 
				
			||||||
 | 
					        clibs.conn.close()
 | 
				
			||||||
 | 
					    clibs.conn, clibs.cursor = None, None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db_lock
 | 
				
			||||||
 | 
					def db_write_logs(content, module="", level="info"):
 | 
				
			||||||
 | 
					    if module == "" and clibs.caller_frame is not None:
 | 
				
			||||||
 | 
					        module_name = clibs.caller_frame.f_globals["__name__"].split(".")[-1]  #
 | 
				
			||||||
 | 
					        func_name = clibs.caller_frame.f_code.co_name
 | 
				
			||||||
 | 
					        line_no = clibs.caller_frame.f_lineno
 | 
				
			||||||
 | 
					        module = f"{module_name}-{func_name}:{line_no}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if level.lower() not in ["info", "warning", "error", "exception"]:
 | 
				
			||||||
 | 
					        level = "unknown"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clibs.cursor.execute(f"INSERT INTO logs (level, module, content) VALUES (?, ?, ?)", (level, module, content))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@singledispatch
 | 
				
			||||||
 | 
					@db_lock
 | 
				
			||||||
 | 
					def db_query_logs(dummy: object = None):
 | 
				
			||||||
 | 
					    clibs.cursor.execute(f"SELECT * FROM logs")
 | 
				
			||||||
 | 
					    records = clibs.cursor.fetchall()
 | 
				
			||||||
 | 
					    len_records = len(records)
 | 
				
			||||||
 | 
					    return records, len_records
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db_query_logs.register
 | 
				
			||||||
 | 
					def _(levels: list):
 | 
				
			||||||
 | 
					    placeholders = ",".join("?" * len(levels))
 | 
				
			||||||
 | 
					    clibs.cursor.execute(f"SELECT * FROM logs WHERE level IN ({placeholders})", (*levels, ))
 | 
				
			||||||
 | 
					    records = clibs.cursor.fetchall()
 | 
				
			||||||
 | 
					    len_records = len(records)
 | 
				
			||||||
 | 
					    return records, len_records
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db_query_logs.register
 | 
				
			||||||
 | 
					def _(search_text: str, records: list):
 | 
				
			||||||
 | 
					    ids = [_[0] for _ in records]
 | 
				
			||||||
 | 
					    placeholder = ",".join("?" * len(ids))
 | 
				
			||||||
 | 
					    clibs.cursor.execute(f"SELECT * FROM logs WHERE id IN ({placeholder}) and content like ?", (ids + [f"%{search_text}%", ]))
 | 
				
			||||||
 | 
					    records = clibs.cursor.fetchall()
 | 
				
			||||||
 | 
					    len_records = len(records)
 | 
				
			||||||
 | 
					    return records, len_records
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db_lock
 | 
				
			||||||
 | 
					def db_write_users(username, password_encrypted, salt):
 | 
				
			||||||
 | 
					    clibs.cursor.execute("INSERT INTO users (username, password, salt) VALUES (?, ?, ?)", (username, password_encrypted, salt))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db_lock
 | 
				
			||||||
 | 
					def db_delete_users(username):
 | 
				
			||||||
 | 
					    # clibs.cursor.execute("INSERT INTO users (username, password, salt) VALUES (?, ?, ?)", (username, password_encrypted, salt))
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@db_lock
 | 
				
			||||||
 | 
					def db_query_users(username):
 | 
				
			||||||
 | 
					    clibs.cursor.execute(f""" SELECT * FROM users where username = "{username}" """)
 | 
				
			||||||
 | 
					    record = clibs.cursor.fetchall()
 | 
				
			||||||
 | 
					    return record
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								toolbox/codes/common/exception_handler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					from functools import wraps
 | 
				
			||||||
 | 
					from codes.common import db_operation
 | 
				
			||||||
 | 
					from inspect import currentframe
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def handle_exception(stop: bool = False):
 | 
				
			||||||
 | 
					    def exceptions(func):
 | 
				
			||||||
 | 
					        @wraps(func)
 | 
				
			||||||
 | 
					        def wrapper(*args, **kwargs):
 | 
				
			||||||
 | 
					            real_frame = currentframe().f_back
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                return func(*args, **kwargs)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                for frame, lineno in traceback.walk_tb(e.__traceback__):
 | 
				
			||||||
 | 
					                    if frame.f_code.co_name == func.__name__:
 | 
				
			||||||
 | 
					                        real_frame = frame
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                tb = traceback.format_exc()                          # 完整堆栈
 | 
				
			||||||
 | 
					                module_name = real_frame.f_globals["__name__"].split(".")[-1]
 | 
				
			||||||
 | 
					                func_name = real_frame.f_code.co_name
 | 
				
			||||||
 | 
					                line_no = real_frame.f_lineno
 | 
				
			||||||
 | 
					                module = f"{module_name}-{func_name}:{line_no}"
 | 
				
			||||||
 | 
					                db_operation.db_write_logs(tb, module, "exception")
 | 
				
			||||||
 | 
					                if stop:
 | 
				
			||||||
 | 
					                    raise e
 | 
				
			||||||
 | 
					        return wrapper
 | 
				
			||||||
 | 
					    return exceptions
 | 
				
			||||||
							
								
								
									
										41
									
								
								toolbox/codes/common/qss_reloader.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PySide6.QtCore import QObject, QFileSystemWatcher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QssReloader(QObject):
 | 
				
			||||||
 | 
					    instance = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __new__(cls, *args, **kwargs):
 | 
				
			||||||
 | 
					        if cls.instance is None:
 | 
				
			||||||
 | 
					            cls.instance = super().__new__(cls)
 | 
				
			||||||
 | 
					        return cls.instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        super().__init__()
 | 
				
			||||||
 | 
					        self.path2objs = {}
 | 
				
			||||||
 | 
					        self.watcher = QFileSystemWatcher(self)
 | 
				
			||||||
 | 
					        self.watcher.fileChanged.connect(self.on_file_changed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def register(self, qss_path: str, ui_obj):
 | 
				
			||||||
 | 
					        path = str(Path(qss_path).resolve())
 | 
				
			||||||
 | 
					        obj_list = self.path2objs.setdefault(path, [])
 | 
				
			||||||
 | 
					        if ui_obj not in obj_list:
 | 
				
			||||||
 | 
					            obj_list.append(ui_obj)
 | 
				
			||||||
 | 
					        if path not in self.watcher.files():
 | 
				
			||||||
 | 
					            self.watcher.addPath(path)
 | 
				
			||||||
 | 
					        self.apply_one(path, ui_obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_file_changed(self, path: str):
 | 
				
			||||||
 | 
					        for obj in self.path2objs.get(path, []):
 | 
				
			||||||
 | 
					            self.apply_one(path, obj)
 | 
				
			||||||
 | 
					        if path not in self.watcher.files():
 | 
				
			||||||
 | 
					            self.watcher.addPath(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def apply_one(path: str, obj):
 | 
				
			||||||
 | 
					        qss = Path(path).read_text(encoding="utf-8")
 | 
				
			||||||
 | 
					        obj.setStyleSheet(qss)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qss_reloader = QssReloader()
 | 
				
			||||||
							
								
								
									
										30
									
								
								toolbox/codes/common/signal_bus.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					from PySide6.QtCore import QObject, Signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SignalBus(QObject):
 | 
				
			||||||
 | 
					    instance = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __new__(cls):
 | 
				
			||||||
 | 
					        if cls.instance is None:
 | 
				
			||||||
 | 
					            cls.instance = super(SignalBus, cls).__new__(cls)
 | 
				
			||||||
 | 
					        return cls.instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        super().__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    current_stacked_page = Signal(str)         # 获取当前页面的page_id
 | 
				
			||||||
 | 
					    init_stacked_page = Signal(str)            # 设置打开侧边栏后的初始页面
 | 
				
			||||||
 | 
					    stacked_page_switch = Signal(str)          # 切换stacked widget的页面
 | 
				
			||||||
 | 
					    stacked_page_switch_setting = Signal()     # 切换stacked widget的设置页面后的触发信号
 | 
				
			||||||
 | 
					    stacked_page_switch_log = Signal()         # 切换stacked widget的日志页面后的触发信号
 | 
				
			||||||
 | 
					    stacked_page_switch_about = Signal()       # 切换stacked widget的关于页面后的触发信号
 | 
				
			||||||
 | 
					    qa_switch_change = Signal(bool)            # 切换折叠侧边栏的状态
 | 
				
			||||||
 | 
					    home_overlay_trigger = Signal()            # 触发软件锁屏
 | 
				
			||||||
 | 
					    home_overlay_auth = Signal()               # 触发密码框的显示与隐藏
 | 
				
			||||||
 | 
					    home_overlay_close = Signal()              # 退出锁屏后的收尾信号
 | 
				
			||||||
 | 
					    list_widget_click = Signal(str)            # 触发点击list widget信号
 | 
				
			||||||
 | 
					    list_widget_on_off = Signal(bool)          # 主动控制是否显示list widget组件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signal_bus = SignalBus()
 | 
				
			||||||
@@ -1,28 +0,0 @@
 | 
				
			|||||||
import subprocess
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
from codes.common import clibs
 | 
					 | 
				
			||||||
from pathlib import Path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
UIC_CMD = "pyside6-uic"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def single_uic(ui_path: str, py_path: str):
 | 
					 | 
				
			||||||
    for file in Path(ui_path).rglob("*.ui"):
 | 
					 | 
				
			||||||
        file_name = file.stem
 | 
					 | 
				
			||||||
        ui_file = file
 | 
					 | 
				
			||||||
        py_file = Path(py_path) / f"{file_name}.py"
 | 
					 | 
				
			||||||
        cmd = [UIC_CMD, "-o", py_file, ui_file]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        print(f"Processing  {ui_file} -> {py_file}")
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            subprocess.run(cmd, check=True, capture_output=True, text=True)
 | 
					 | 
				
			||||||
        except subprocess.CalledProcessError as e:
 | 
					 | 
				
			||||||
            print(f"转换失败: {ui_file}\n{e.stderr}", file=sys.stderr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def main():
 | 
					 | 
				
			||||||
    ui_path = clibs.base_path / "assets" / "ui"
 | 
					 | 
				
			||||||
    py_path = clibs.base_path / "codes" / "ui"
 | 
					 | 
				
			||||||
    single_uic(str(ui_path), str(py_path))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == "__main__":
 | 
					 | 
				
			||||||
    main()
 | 
					 | 
				
			||||||
							
								
								
									
										0
									
								
								toolbox/codes/ui/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								toolbox/codes/ui/components/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										58
									
								
								toolbox/codes/ui/components/list_widget_ui.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					from PySide6.QtGui import QFocusEvent
 | 
				
			||||||
 | 
					from PySide6.QtWidgets import QListWidget, QListWidgetItem
 | 
				
			||||||
 | 
					from PySide6.QtCore import Qt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from codes.common import clibs
 | 
				
			||||||
 | 
					from codes.common.signal_bus import signal_bus
 | 
				
			||||||
 | 
					from codes.common.qss_reloader import qss_reloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SListWidget(QListWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.pre_do()
 | 
				
			||||||
 | 
					        self.init_ui()
 | 
				
			||||||
 | 
					        self.post_do()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def pre_do(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setObjectName("SListWidget")
 | 
				
			||||||
 | 
					        self.setMinimumWidth(150)
 | 
				
			||||||
 | 
					        for item in clibs.listW_items:
 | 
				
			||||||
 | 
					            _ = QListWidgetItem(item)
 | 
				
			||||||
 | 
					            _.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
 | 
					            self.addItem(_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def post_do(self):
 | 
				
			||||||
 | 
					        qss_reloader.register(clibs.qss_list_widget, self)
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        self.itemClicked.connect(self.item_clicked)
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch_setting.connect(self.qa_hide)
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch_log.connect(self.qa_hide)
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch_about.connect(self.qa_hide)
 | 
				
			||||||
 | 
					        signal_bus.list_widget_on_off.connect(self.lw_show_hide)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def item_clicked(self, item):
 | 
				
			||||||
 | 
					        page_id = clibs.listW_items[item.text()]
 | 
				
			||||||
 | 
					        signal_bus.list_widget_click.emit(page_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def lw_show_hide(self, enabled: bool):
 | 
				
			||||||
 | 
					        if enabled:
 | 
				
			||||||
 | 
					            self.clearSelection()
 | 
				
			||||||
 | 
					            self.show()
 | 
				
			||||||
 | 
					            signal_bus.init_stacked_page.emit("w10_practical")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.hide()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def qa_hide(self):
 | 
				
			||||||
 | 
					        self.hide()
 | 
				
			||||||
 | 
					        signal_bus.qa_switch_change.emit(False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def focusOutEvent(self, event: QFocusEvent):
 | 
				
			||||||
 | 
					        self.clearSelection()
 | 
				
			||||||
 | 
					        super().focusOutEvent(event)
 | 
				
			||||||
							
								
								
									
										41
									
								
								toolbox/codes/ui/components/stacked_widget_ui.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QStackedWidget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from codes.common.signal_bus import signal_bus
 | 
				
			||||||
 | 
					from codes.ui.stacked_pages.w01_setting import W01Setting
 | 
				
			||||||
 | 
					from codes.ui.stacked_pages.w08_log import W08Log
 | 
				
			||||||
 | 
					from codes.ui.stacked_pages.w09_about import W09About
 | 
				
			||||||
 | 
					from codes.ui.stacked_pages.w10_practical import W10Practical
 | 
				
			||||||
 | 
					from codes.ui.stacked_pages.w20_efficiency import W20Efficiency
 | 
				
			||||||
 | 
					from codes.ui.stacked_pages.w30_financial import W30Financial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SStackedWidget(QStackedWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.predos()
 | 
				
			||||||
 | 
					        self.init_ui()
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def predos(self):
 | 
				
			||||||
 | 
					        self.page_list = {"w01_setting": W01Setting(), "w08_log": W08Log(), "w09_about": W09About(), "w10_practical": W10Practical(), "w20_efficiency": W20Efficiency(), "w30_financial": W30Financial()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setObjectName("SStackedWidget")
 | 
				
			||||||
 | 
					        # stacked widget  1x: 10为一级按钮页,其余为二级按钮页,2-9同理 | 0x. 日志/设置/关于等页面
 | 
				
			||||||
 | 
					        for page_id, widget in self.page_list.items():
 | 
				
			||||||
 | 
					            widget.setObjectName(page_id)
 | 
				
			||||||
 | 
					            self.addWidget(widget)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        w = self.page_list.get("w01_setting")
 | 
				
			||||||
 | 
					        self.setCurrentWidget(w)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        signal_bus.init_stacked_page.connect(self.set_current_page)
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch.connect(self.set_current_page)
 | 
				
			||||||
 | 
					        signal_bus.list_widget_click.connect(self.set_current_page)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_current_page(self, page_id: str):
 | 
				
			||||||
 | 
					        w = self.page_list.get(page_id)
 | 
				
			||||||
 | 
					        self.setCurrentWidget(w)
 | 
				
			||||||
 | 
					        signal_bus.current_stacked_page.emit(page_id)
 | 
				
			||||||
							
								
								
									
										25
									
								
								toolbox/codes/ui/components/statusbar_ui.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QStatusBar
 | 
				
			||||||
 | 
					from PySide6.QtGui import QAction, QIcon
 | 
				
			||||||
 | 
					from PySide6.QtCore import QSize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from codes.common import clibs
 | 
				
			||||||
 | 
					from codes.common.signal_bus import signal_bus
 | 
				
			||||||
 | 
					from codes.common.qss_reloader import qss_reloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SStatusBar(QStatusBar):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.pre_do()
 | 
				
			||||||
 | 
					        self.init_ui()
 | 
				
			||||||
 | 
					        self.post_do()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def pre_do(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setObjectName("SStatusBar")
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def post_do(self):
 | 
				
			||||||
 | 
					        qss_reloader.register(clibs.qss_statusbar, self)
 | 
				
			||||||
							
								
								
									
										102
									
								
								toolbox/codes/ui/components/toolbar_ui.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QToolBar
 | 
				
			||||||
 | 
					from PySide6.QtGui import QAction, QIcon
 | 
				
			||||||
 | 
					from PySide6.QtCore import QSize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from codes.common import clibs
 | 
				
			||||||
 | 
					from codes.common.signal_bus import signal_bus
 | 
				
			||||||
 | 
					from codes.common.qss_reloader import qss_reloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SToolBar(QToolBar):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.pre_do()
 | 
				
			||||||
 | 
					        self.init_ui()
 | 
				
			||||||
 | 
					        self.post_do()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def pre_do(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setObjectName("SToolBar")
 | 
				
			||||||
 | 
					        # switch
 | 
				
			||||||
 | 
					        self.on_icon  = QIcon(clibs.on_icon)   # 开状态图标
 | 
				
			||||||
 | 
					        self.off_icon = QIcon(clibs.off_icon)  # 关状态图标
 | 
				
			||||||
 | 
					        self.ac_switch = QAction(self.on_icon, "", self)
 | 
				
			||||||
 | 
					        self.ac_switch.setMenuRole(QAction.MenuRole.NoRole)
 | 
				
			||||||
 | 
					        self.ac_switch.setStatusTip("Switch side bar")
 | 
				
			||||||
 | 
					        self.ac_switch.setToolTip("Ctrl+Alt+T")
 | 
				
			||||||
 | 
					        self.ac_switch.setCheckable(True)
 | 
				
			||||||
 | 
					        self.ac_switch.setChecked(True)
 | 
				
			||||||
 | 
					        self.setIconSize(QSize(30, 30))
 | 
				
			||||||
 | 
					        self.addAction(self.ac_switch)
 | 
				
			||||||
 | 
					        btn = self.widgetForAction(self.ac_switch)  # 取出实际 QToolButton
 | 
				
			||||||
 | 
					        btn.setObjectName("ac_switch")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # homepage
 | 
				
			||||||
 | 
					        self.ac_homepage = QAction()
 | 
				
			||||||
 | 
					        self.ac_homepage.setMenuRole(QAction.MenuRole.NoRole)
 | 
				
			||||||
 | 
					        self.ac_homepage.setStatusTip("Go to home page")
 | 
				
			||||||
 | 
					        self.ac_homepage.setToolTip("Ctrl+Alt+H")
 | 
				
			||||||
 | 
					        self.ac_homepage.setText("主页")
 | 
				
			||||||
 | 
					        self.addAction(self.ac_homepage)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # setting
 | 
				
			||||||
 | 
					        self.ac_setting = QAction()
 | 
				
			||||||
 | 
					        self.ac_setting.setMenuRole(QAction.MenuRole.NoRole)
 | 
				
			||||||
 | 
					        self.ac_setting.setStatusTip("Go to setting page")
 | 
				
			||||||
 | 
					        self.ac_setting.setToolTip("Ctrl+Alt+S")
 | 
				
			||||||
 | 
					        self.ac_setting.setText("设置")
 | 
				
			||||||
 | 
					        self.addAction(self.ac_setting)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # log
 | 
				
			||||||
 | 
					        self.ac_log = QAction()
 | 
				
			||||||
 | 
					        self.ac_log.setMenuRole(QAction.MenuRole.NoRole)
 | 
				
			||||||
 | 
					        self.ac_log.setStatusTip("Go to log page")
 | 
				
			||||||
 | 
					        self.ac_log.setToolTip("Ctrl+Alt+L")
 | 
				
			||||||
 | 
					        self.ac_log.setText("日志")
 | 
				
			||||||
 | 
					        self.addAction(self.ac_log)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # about
 | 
				
			||||||
 | 
					        self.ac_about = QAction()
 | 
				
			||||||
 | 
					        self.ac_about.setMenuRole(QAction.MenuRole.NoRole)
 | 
				
			||||||
 | 
					        self.ac_about.setStatusTip("Go to about page")
 | 
				
			||||||
 | 
					        self.ac_about.setToolTip("Ctrl+Alt+A")
 | 
				
			||||||
 | 
					        self.ac_about.setText("关于")
 | 
				
			||||||
 | 
					        self.addAction(self.ac_about)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def post_do(self):
 | 
				
			||||||
 | 
					        qss_reloader.register(clibs.qss_toolbar, self)
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        self.ac_switch.toggled.connect(self.ac_sw)
 | 
				
			||||||
 | 
					        self.ac_homepage.triggered.connect(self.ac_hp)
 | 
				
			||||||
 | 
					        self.ac_setting.triggered.connect(self.ac_sp)
 | 
				
			||||||
 | 
					        self.ac_log.triggered.connect(self.ac_lp)
 | 
				
			||||||
 | 
					        self.ac_about.triggered.connect(self.ac_ap)
 | 
				
			||||||
 | 
					        signal_bus.qa_switch_change.connect(self.change2hide)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ac_sw(self, checked: bool):
 | 
				
			||||||
 | 
					        self.ac_switch.setIcon(self.on_icon if checked else self.off_icon)
 | 
				
			||||||
 | 
					        signal_bus.list_widget_on_off.emit(checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ac_hp(self):
 | 
				
			||||||
 | 
					        signal_bus.home_overlay_trigger.emit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ac_sp(self):
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch.emit("w01_setting")
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch_setting.emit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ac_lp(self):
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch.emit("w08_log")
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch_log.emit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ac_ap(self):
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch.emit("w09_about")
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch_about.emit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def change2hide(self):
 | 
				
			||||||
 | 
					        self.ac_switch.setChecked(False)
 | 
				
			||||||
 | 
					        self.ac_switch.setIcon(self.off_icon)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,64 +1,80 @@
 | 
				
			|||||||
import sys
 | 
					import sys
 | 
				
			||||||
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QListWidget, QStackedWidget, QCheckBox, QSpinBox, QToolBox, QLineEdit, QTableWidget, QTreeWidget, QCalendarWidget, QMessageBox, QToolBar, QSizePolicy
 | 
					from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QLineEdit, QMessageBox, QSizePolicy
 | 
				
			||||||
from PySide6.QtCore import Qt, QTime, QSize, QRect,QEvent, QThread
 | 
					from PySide6.QtCore import Qt, QSize
 | 
				
			||||||
from PySide6.QtGui import QCursor, QFont, QIcon, QImage, QPixmap, QShortcut
 | 
					from PySide6.QtGui import QFont, QIcon, QPixmap, QShortcut
 | 
				
			||||||
from codes.common import clibs, db_operation
 | 
					from codes.common import clibs, db_operation
 | 
				
			||||||
from codes.common.secure_encrypt import PassCipher
 | 
					from codes.common.secure_encrypt import PassCipher
 | 
				
			||||||
from codes.ui import main_ui
 | 
					from codes.ui import main_ui
 | 
				
			||||||
 | 
					from codes.common.exception_handler import handle_exception
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LoginWindow(QWidget):
 | 
					class LoginWindow(QWidget):
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        super().__init__()
 | 
					        super().__init__()
 | 
				
			||||||
 | 
					        self.pre_do()
 | 
				
			||||||
        self.init_ui()
 | 
					        self.init_ui()
 | 
				
			||||||
        self.setup_slot()
 | 
					        self.post_do()
 | 
				
			||||||
        self.predos()
 | 
					
 | 
				
			||||||
        self.le_username.setFocus()
 | 
					    def pre_do(self):
 | 
				
			||||||
 | 
					        db_operation.db_init()
 | 
				
			||||||
 | 
					        db_operation.db_conn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init_ui(self):
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setObjectName("LoginWindow")
 | 
				
			||||||
        self.setMinimumSize(420, 200)
 | 
					        self.setMinimumSize(420, 200)
 | 
				
			||||||
        self.setMaximumSize(500, 240)
 | 
					        self.setMaximumSize(500, 240)
 | 
				
			||||||
        self.resize(480, 200)
 | 
					        self.resize(480, 200)
 | 
				
			||||||
        self.setWindowTitle("登录")
 | 
					        self.setWindowTitle("登录")
 | 
				
			||||||
        self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
 | 
					        self.setWindowIcon(QIcon(clibs.icon))
 | 
				
			||||||
        self.setFont(QFont("Consolas", 14))
 | 
					        self.setFont(QFont("Consolas", 14))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.layout_outter = QHBoxLayout()
 | 
					        self.layout_outer = QHBoxLayout()
 | 
				
			||||||
        self.lb_logo = QLabel()
 | 
					        self.lb_logo = QLabel()
 | 
				
			||||||
 | 
					        self.lb_logo.setObjectName("lb_logo")
 | 
				
			||||||
        self.lb_logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.lb_logo.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
 | 
					        self.lb_logo.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
 | 
				
			||||||
        self.lb_logo.setPixmap(QPixmap(f"{clibs.base_path}/assets/media/logo.png"))
 | 
					        self.lb_logo.setPixmap(QPixmap(clibs.logo))
 | 
				
			||||||
        self.lb_logo.setFixedSize(QSize(120, 120))
 | 
					        self.lb_logo.setFixedSize(QSize(120, 120))
 | 
				
			||||||
        self.lb_logo.setScaledContents(True)
 | 
					        self.lb_logo.setScaledContents(True)
 | 
				
			||||||
        self.layout_outter.addWidget(self.lb_logo)
 | 
					        self.layout_outer.addWidget(self.lb_logo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.tabW_login = QTabWidget()
 | 
					        self.tabW_login = QTabWidget()
 | 
				
			||||||
 | 
					        self.tabW_login.setObjectName("tabW_login")
 | 
				
			||||||
        self.tab_login = QWidget()
 | 
					        self.tab_login = QWidget()
 | 
				
			||||||
 | 
					        self.tab_login.setObjectName("tab_login")
 | 
				
			||||||
        self.tabW_login.addTab(self.tab_login, "登录")
 | 
					        self.tabW_login.addTab(self.tab_login, "登录")
 | 
				
			||||||
        self.tab_register = QWidget()
 | 
					        self.tab_register = QWidget()
 | 
				
			||||||
 | 
					        self.tab_register.setObjectName("tab_register")
 | 
				
			||||||
        self.tabW_login.addTab(self.tab_register, "注册")
 | 
					        self.tabW_login.addTab(self.tab_register, "注册")
 | 
				
			||||||
        self.layout_outter.addWidget(self.tabW_login)
 | 
					        self.layout_outer.addWidget(self.tabW_login)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # 登陆页面
 | 
					        # 登陆页面
 | 
				
			||||||
        self.layout_H_username = QHBoxLayout()
 | 
					        self.layout_H_username = QHBoxLayout()
 | 
				
			||||||
        self.lb_username = QLabel("账号")
 | 
					        self.lb_username = QLabel("账号")
 | 
				
			||||||
 | 
					        self.lb_username.setObjectName("lb_username")
 | 
				
			||||||
        self.lb_username.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_username.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.layout_H_username.addWidget(self.lb_username)
 | 
					        self.layout_H_username.addWidget(self.lb_username)
 | 
				
			||||||
        self.le_username = QLineEdit()
 | 
					        self.le_username = QLineEdit()
 | 
				
			||||||
 | 
					        self.le_username.setObjectName("le_username")
 | 
				
			||||||
        self.le_username.setFocus()
 | 
					        self.le_username.setFocus()
 | 
				
			||||||
        self.layout_H_username.addWidget(self.le_username)
 | 
					        self.layout_H_username.addWidget(self.le_username)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.layout_H_password = QHBoxLayout()
 | 
					        self.layout_H_password = QHBoxLayout()
 | 
				
			||||||
        self.lb_password = QLabel("密码")
 | 
					        self.lb_password = QLabel("密码")
 | 
				
			||||||
 | 
					        self.lb_password.setObjectName("lb_password")
 | 
				
			||||||
        self.lb_password.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_password.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.layout_H_password.addWidget(self.lb_password)
 | 
					        self.layout_H_password.addWidget(self.lb_password)
 | 
				
			||||||
        self.le_password = QLineEdit()
 | 
					        self.le_password = QLineEdit()
 | 
				
			||||||
 | 
					        self.le_password.setObjectName("le_password")
 | 
				
			||||||
        self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
 | 
					        self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
 | 
				
			||||||
        self.layout_H_password.addWidget(self.le_password)
 | 
					        self.layout_H_password.addWidget(self.le_password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.layout_H_button = QHBoxLayout()
 | 
					        self.layout_H_button = QHBoxLayout()
 | 
				
			||||||
        self.btn_login = QPushButton("登录")
 | 
					        self.btn_login = QPushButton("登录")
 | 
				
			||||||
 | 
					        self.btn_login.setObjectName("btn_login")
 | 
				
			||||||
        self.btn_login.setAutoDefault(True)
 | 
					        self.btn_login.setAutoDefault(True)
 | 
				
			||||||
        self.btn_cancel = QPushButton("取消")
 | 
					        self.btn_cancel = QPushButton("取消")
 | 
				
			||||||
 | 
					        self.btn_cancel.setObjectName("btn_cancel")
 | 
				
			||||||
        self.btn_cancel.setAutoDefault(True)
 | 
					        self.btn_cancel.setAutoDefault(True)
 | 
				
			||||||
        self.layout_H_button.addWidget(self.btn_login)
 | 
					        self.layout_H_button.addWidget(self.btn_login)
 | 
				
			||||||
        self.layout_H_button.addWidget(self.btn_cancel)
 | 
					        self.layout_H_button.addWidget(self.btn_cancel)
 | 
				
			||||||
@@ -72,32 +88,40 @@ class LoginWindow(QWidget):
 | 
				
			|||||||
        # 注册页面
 | 
					        # 注册页面
 | 
				
			||||||
        self.layout_H_username_reg = QHBoxLayout()
 | 
					        self.layout_H_username_reg = QHBoxLayout()
 | 
				
			||||||
        self.lb_username_reg = QLabel("账号设定")
 | 
					        self.lb_username_reg = QLabel("账号设定")
 | 
				
			||||||
 | 
					        self.lb_username_reg.setObjectName("lb_username_reg")
 | 
				
			||||||
        self.lb_username_reg.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_username_reg.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.layout_H_username_reg.addWidget(self.lb_username_reg)
 | 
					        self.layout_H_username_reg.addWidget(self.lb_username_reg)
 | 
				
			||||||
        self.le_username_reg = QLineEdit()
 | 
					        self.le_username_reg = QLineEdit()
 | 
				
			||||||
 | 
					        self.le_username_reg.setObjectName("le_username_reg")
 | 
				
			||||||
        self.le_username_reg.setFocus()
 | 
					        self.le_username_reg.setFocus()
 | 
				
			||||||
        self.layout_H_username_reg.addWidget(self.le_username_reg)
 | 
					        self.layout_H_username_reg.addWidget(self.le_username_reg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.layout_H_password_reg = QHBoxLayout()
 | 
					        self.layout_H_password_reg = QHBoxLayout()
 | 
				
			||||||
        self.lb_password_reg = QLabel("密码设定")
 | 
					        self.lb_password_reg = QLabel("密码设定")
 | 
				
			||||||
 | 
					        self.lb_password_reg.setObjectName("lb_password_reg")
 | 
				
			||||||
        self.lb_password_reg.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_password_reg.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.layout_H_password_reg.addWidget(self.lb_password_reg)
 | 
					        self.layout_H_password_reg.addWidget(self.lb_password_reg)
 | 
				
			||||||
        self.le_password_reg = QLineEdit()
 | 
					        self.le_password_reg = QLineEdit()
 | 
				
			||||||
 | 
					        self.le_password_reg.setObjectName("le_password_reg")
 | 
				
			||||||
        self.le_password_reg.setEchoMode(QLineEdit.EchoMode.Password)
 | 
					        self.le_password_reg.setEchoMode(QLineEdit.EchoMode.Password)
 | 
				
			||||||
        self.layout_H_password_reg.addWidget(self.le_password_reg)
 | 
					        self.layout_H_password_reg.addWidget(self.le_password_reg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.layout_H_password_reg_confirm = QHBoxLayout()
 | 
					        self.layout_H_password_reg_confirm = QHBoxLayout()
 | 
				
			||||||
        self.lb_password_reg_confirm = QLabel("密码确认")
 | 
					        self.lb_password_reg_confirm = QLabel("密码确认")
 | 
				
			||||||
 | 
					        self.lb_password_reg_confirm.setObjectName("lb_password_reg_confirm")
 | 
				
			||||||
        self.lb_password_reg_confirm.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_password_reg_confirm.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.layout_H_password_reg_confirm.addWidget(self.lb_password_reg_confirm)
 | 
					        self.layout_H_password_reg_confirm.addWidget(self.lb_password_reg_confirm)
 | 
				
			||||||
        self.le_password_reg_confirm = QLineEdit()
 | 
					        self.le_password_reg_confirm = QLineEdit()
 | 
				
			||||||
 | 
					        self.le_password_reg.setObjectName("le_password_reg")
 | 
				
			||||||
        self.le_password_reg_confirm.setEchoMode(QLineEdit.EchoMode.Password)
 | 
					        self.le_password_reg_confirm.setEchoMode(QLineEdit.EchoMode.Password)
 | 
				
			||||||
        self.layout_H_password_reg_confirm.addWidget(self.le_password_reg_confirm)
 | 
					        self.layout_H_password_reg_confirm.addWidget(self.le_password_reg_confirm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.layout_H_button_reg = QHBoxLayout()
 | 
					        self.layout_H_button_reg = QHBoxLayout()
 | 
				
			||||||
        self.btn_login_reg = QPushButton("确认")
 | 
					        self.btn_login_reg = QPushButton("确认")
 | 
				
			||||||
 | 
					        self.btn_login_reg.setObjectName("btn_login_reg")
 | 
				
			||||||
        self.btn_login_reg.setAutoDefault(True)
 | 
					        self.btn_login_reg.setAutoDefault(True)
 | 
				
			||||||
        self.btn_cancel_reg = QPushButton("取消")
 | 
					        self.btn_cancel_reg = QPushButton("取消")
 | 
				
			||||||
 | 
					        self.btn_cancel_reg.setObjectName("btn_cancel_reg")
 | 
				
			||||||
        self.btn_cancel_reg.setAutoDefault(True)
 | 
					        self.btn_cancel_reg.setAutoDefault(True)
 | 
				
			||||||
        self.layout_H_button_reg.addWidget(self.btn_login_reg)
 | 
					        self.layout_H_button_reg.addWidget(self.btn_login_reg)
 | 
				
			||||||
        self.layout_H_button_reg.addWidget(self.btn_cancel_reg)
 | 
					        self.layout_H_button_reg.addWidget(self.btn_cancel_reg)
 | 
				
			||||||
@@ -109,7 +133,11 @@ class LoginWindow(QWidget):
 | 
				
			|||||||
        self.layout_V_user_pass_reg.addLayout(self.layout_H_button_reg)
 | 
					        self.layout_V_user_pass_reg.addLayout(self.layout_H_button_reg)
 | 
				
			||||||
        self.tab_register.setLayout(self.layout_V_user_pass_reg)
 | 
					        self.tab_register.setLayout(self.layout_V_user_pass_reg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.setLayout(self.layout_outter)
 | 
					        self.setLayout(self.layout_outer)
 | 
				
			||||||
 | 
					        self.le_username.setFocus()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def post_do(self):
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup_slot(self):
 | 
					    def setup_slot(self):
 | 
				
			||||||
        self.tabW_login.currentChanged.connect(self.onChange_tabW)
 | 
					        self.tabW_login.currentChanged.connect(self.onChange_tabW)
 | 
				
			||||||
@@ -117,14 +145,11 @@ class LoginWindow(QWidget):
 | 
				
			|||||||
        self.btn_cancel.clicked.connect(self.close)
 | 
					        self.btn_cancel.clicked.connect(self.close)
 | 
				
			||||||
        self.btn_login_reg.clicked.connect(self.register_check)
 | 
					        self.btn_login_reg.clicked.connect(self.register_check)
 | 
				
			||||||
        self.btn_cancel_reg.clicked.connect(self.close)
 | 
					        self.btn_cancel_reg.clicked.connect(self.close)
 | 
				
			||||||
        QShortcut("Esc", self).activated.connect(self.close)
 | 
					 | 
				
			||||||
        self.le_password.returnPressed.connect(self.login_check)
 | 
					        self.le_password.returnPressed.connect(self.login_check)
 | 
				
			||||||
        self.le_password_reg_confirm.returnPressed.connect(self.register_check)
 | 
					        self.le_password_reg_confirm.returnPressed.connect(self.register_check)
 | 
				
			||||||
 | 
					        QShortcut("Esc", self).activated.connect(self.close)
 | 
				
			||||||
    def predos(self):
 | 
					        QShortcut("Alt+1", self).activated.connect(lambda: self.tabW_login.setCurrentIndex(0))
 | 
				
			||||||
        db_file = clibs.base_path / "assets/database/toolbox.db"
 | 
					        QShortcut("Alt+2", self).activated.connect(lambda: self.tabW_login.setCurrentIndex(1))
 | 
				
			||||||
        if not db_file.exists():
 | 
					 | 
				
			||||||
            db_operation.db_init(db_file)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def onChange_tabW(self):
 | 
					    def onChange_tabW(self):
 | 
				
			||||||
        text = self.tabW_login.tabText(self.tabW_login.currentIndex())
 | 
					        text = self.tabW_login.tabText(self.tabW_login.currentIndex())
 | 
				
			||||||
@@ -137,98 +162,93 @@ class LoginWindow(QWidget):
 | 
				
			|||||||
            self.le_password_reg.clear()
 | 
					            self.le_password_reg.clear()
 | 
				
			||||||
            self.le_password_reg_confirm.clear()
 | 
					            self.le_password_reg_confirm.clear()
 | 
				
			||||||
            self.le_username_reg.setFocus()
 | 
					            self.le_username_reg.setFocus()
 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            raise Exception(f"Unknown TabWidget Name: {text}")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @handle_exception()
 | 
				
			||||||
    def login_check(self):
 | 
					    def login_check(self):
 | 
				
			||||||
        def login_failed():
 | 
					        def login_failed(flag: int = 0):
 | 
				
			||||||
 | 
					            reason = {-1: "用户名或密码为空", 0: "用户名未注册", 1: "解密成功,密码错误", 2: "解密失败,密码错误", 3: "数据库中有重复的用户名"}
 | 
				
			||||||
            self.le_username.clear()
 | 
					            self.le_username.clear()
 | 
				
			||||||
            self.le_password.clear()
 | 
					            self.le_password.clear()
 | 
				
			||||||
            self.le_username.setFocus()
 | 
					            self.le_username.setFocus()
 | 
				
			||||||
            QMessageBox.critical(self, "错误", "账号或密码错误,请重新输入!")
 | 
					            QMessageBox.critical(self, "错误", "账号或密码错误,请重新输入!")
 | 
				
			||||||
 | 
					            raise Exception(f"username:{username} login failed, reason: {reason[flag]}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def validate_login():
 | 
					        def validate_login():
 | 
				
			||||||
            nonlocal username, password
 | 
					            nonlocal username, password
 | 
				
			||||||
            conn, cursor = db_operation.db_conn()
 | 
					            record = db_operation.db_query_users(username)
 | 
				
			||||||
            cursor.execute(f""" SELECT * FROM users where username = "{username}" """)
 | 
					            if username == "" or password == "":
 | 
				
			||||||
            record = cursor.fetchall()
 | 
					                login_failed(flag=-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if len(record) == 0:
 | 
					            if len(record) == 0:
 | 
				
			||||||
                login_failed()
 | 
					                login_failed(flag=0)
 | 
				
			||||||
            elif len(record) == 1:
 | 
					            elif len(record) == 1:
 | 
				
			||||||
                keys = ["id", "timestamp", "username", "password", "salt"]
 | 
					                keys = ["id", "timestamp", "username", "password", "salt"]
 | 
				
			||||||
                login_info = dict(zip(keys, record[0]))
 | 
					                login_info = dict(zip(keys, record[0]))
 | 
				
			||||||
                salt = PassCipher.gen_salt("@".join([username, password]))
 | 
					                salt = PassCipher.gen_salt("@".join([username, password]))
 | 
				
			||||||
                cipher = PassCipher(salt)
 | 
					                cipher = PassCipher(salt)
 | 
				
			||||||
                # password_encrypt = cipher.encrypt("@".join([username, password]))
 | 
					 | 
				
			||||||
                # print(f"password_encrypt = {password_encrypt}")
 | 
					 | 
				
			||||||
                # exit()
 | 
					 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    decrypt_password = cipher.decrypt(login_info["password"])
 | 
					                    decrypt_password = cipher.decrypt(login_info["password"])
 | 
				
			||||||
                    if password != decrypt_password:
 | 
					                    if password != decrypt_password:
 | 
				
			||||||
                        login_failed()
 | 
					                        login_failed(flag=1)
 | 
				
			||||||
                        return False
 | 
					 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        self.mainWindow = main_ui.MainWindow()
 | 
					                        self.mainWindow = main_ui.MainWindow()
 | 
				
			||||||
                        self.mainWindow.show()
 | 
					                        self.mainWindow.show()
 | 
				
			||||||
                        db_operation.db_close(conn, cursor)
 | 
					 | 
				
			||||||
                        clibs.username = username
 | 
					                        clibs.username = username
 | 
				
			||||||
                        clibs.password = password
 | 
					                        clibs.password = password
 | 
				
			||||||
                        self.close()
 | 
					                        db_operation.db_write_logs(f"username:{username} 登录成功!")
 | 
				
			||||||
                        return True
 | 
					                        self.deleteLater()
 | 
				
			||||||
                except ValueError:
 | 
					                except ValueError:
 | 
				
			||||||
                    login_failed()
 | 
					                    login_failed(flag=2)
 | 
				
			||||||
                    return False
 | 
					 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                raise Exception(f"username duplicated: {username}")
 | 
					                login_failed(flag=3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        username = self.le_username.text()
 | 
					        username = self.le_username.text()
 | 
				
			||||||
        password = self.le_password.text()
 | 
					        password = self.le_password.text()
 | 
				
			||||||
 | 
					 | 
				
			||||||
        validate_login()
 | 
					        validate_login()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @handle_exception()
 | 
				
			||||||
    def register_check(self):
 | 
					    def register_check(self):
 | 
				
			||||||
        def register_failed(flag: int = 0):
 | 
					        def register_failed(flag: int = 0):
 | 
				
			||||||
 | 
					            reason = {-1: "用户名或密码为空", 0: "两次密码不一致", 1: "密码长度不合规", 2: "用户名已存在", 3: "数据库中有重复的用户名"}
 | 
				
			||||||
            self.le_username_reg.clear()
 | 
					            self.le_username_reg.clear()
 | 
				
			||||||
            self.le_password_reg.clear()
 | 
					            self.le_password_reg.clear()
 | 
				
			||||||
            self.le_password_reg_confirm.clear()
 | 
					            self.le_password_reg_confirm.clear()
 | 
				
			||||||
            self.le_username_reg.setFocus()
 | 
					            self.le_username_reg.setFocus()
 | 
				
			||||||
            if flag == 0:
 | 
					            QMessageBox.critical(self, "错误", "账号错误,密码长度(>8)不合规,或两次输入密码不一致,请确认后重新输入!")
 | 
				
			||||||
                QMessageBox.critical(self, "错误", "账号已存在,或两次输入密码不一致,请重新输入!")
 | 
					            raise Exception(f"register failed, reason: {reason[flag]}")
 | 
				
			||||||
            elif flag == 1:
 | 
					 | 
				
			||||||
                QMessageBox.critical(self, "错误", "密码长度不符合要求,请重新输入!")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def validate_register():
 | 
					        def validate_register():
 | 
				
			||||||
            nonlocal username, password, password_confirm, record, conn, cursor
 | 
					            nonlocal username, password, password_confirm
 | 
				
			||||||
            if password != password_confirm:
 | 
					            record = db_operation.db_query_users(username)
 | 
				
			||||||
                register_failed()
 | 
					            if username == "" or password == "" or password_confirm == "":
 | 
				
			||||||
                return False
 | 
					                register_failed(flag=-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if len(password) < clibs.account["minimum_password_length"]:
 | 
					            if password != password_confirm:
 | 
				
			||||||
 | 
					                register_failed(flag=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if len(password) < clibs.config["minimum_password_length"]:
 | 
				
			||||||
                register_failed(flag=1)
 | 
					                register_failed(flag=1)
 | 
				
			||||||
                return False
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if len(record) == 0:
 | 
					            if len(record) == 0:
 | 
				
			||||||
                salt = PassCipher.gen_salt("@".join([username, password]))
 | 
					                salt = PassCipher.gen_salt("@".join([username, password]))
 | 
				
			||||||
                cipher = PassCipher(salt)
 | 
					                cipher = PassCipher(salt)
 | 
				
			||||||
                password_encrypted = cipher.encrypt(password)
 | 
					                password_encrypted = cipher.encrypt(password)
 | 
				
			||||||
                cursor.execute("INSERT INTO users (username, password, salt) VALUES (?, ?, ?)", (username, password_encrypted, salt))
 | 
					                db_operation.db_write_users(username, password_encrypted, salt)
 | 
				
			||||||
                QMessageBox.information(self, "成功", "注册成功,切换至登录窗口进行登录!")
 | 
					                QMessageBox.information(self, "成功", "注册成功,切换至登录窗口进行登录!")
 | 
				
			||||||
                self.tabW_login.setCurrentIndex(self.tabW_login.indexOf(self.tab_login))
 | 
					                self.tabW_login.setCurrentIndex(self.tabW_login.indexOf(self.tab_login))
 | 
				
			||||||
                return True
 | 
					 | 
				
			||||||
            elif len(record) == 1:
 | 
					            elif len(record) == 1:
 | 
				
			||||||
                register_failed()
 | 
					                register_failed(flag=2)
 | 
				
			||||||
                return False
 | 
					 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                raise Exception(f"username duplicated: {username}")
 | 
					                register_failed(flag=3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        username = self.le_username_reg.text()
 | 
					        username = self.le_username_reg.text()
 | 
				
			||||||
        password = self.le_password_reg.text()
 | 
					        password = self.le_password_reg.text()
 | 
				
			||||||
        password_confirm = self.le_password_reg_confirm.text()
 | 
					        password_confirm = self.le_password_reg_confirm.text()
 | 
				
			||||||
        conn, cursor = db_operation.db_conn()
 | 
					 | 
				
			||||||
        cursor.execute(f""" SELECT * FROM users where username = "{username}" """)
 | 
					 | 
				
			||||||
        record = cursor.fetchall()
 | 
					 | 
				
			||||||
        validate_register()
 | 
					        validate_register()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def closeEvent(self, event):
 | 
				
			||||||
 | 
					        event.accept()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    app = QApplication(sys.argv)
 | 
					    app = QApplication(sys.argv)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,64 +1,116 @@
 | 
				
			|||||||
import json
 | 
					 | 
				
			||||||
from math import lgamma
 | 
					 | 
				
			||||||
from shutil import copy
 | 
					 | 
				
			||||||
from random import choice
 | 
					 | 
				
			||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
import sys
 | 
					from random import choice
 | 
				
			||||||
 | 
					from shutil import copy
 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QListWidget, QStackedWidget, QCheckBox, QSpinBox, QToolBox, QLineEdit, QTableWidget, QTreeWidget, QCalendarWidget, QMessageBox, QToolBar, QSizePolicy, QMainWindow, QStatusBar
 | 
					import json
 | 
				
			||||||
from PySide6.QtCore import Qt, QTime, QSize, QRect,QEvent, QThread
 | 
					import sys
 | 
				
			||||||
from PySide6.QtGui import QCursor, QFont, QIcon, QImage, QPixmap, QShortcut, QAction, QKeySequence, QResizeEvent
 | 
					
 | 
				
			||||||
 | 
					from PySide6.QtWidgets import QApplication, QWidget, QHBoxLayout, QMessageBox, QMainWindow, QStatusBar
 | 
				
			||||||
 | 
					from PySide6.QtGui import QIcon, QResizeEvent, QShortcut, QKeySequence, QAction
 | 
				
			||||||
 | 
					from PySide6.QtCore import Qt, QFileSystemWatcher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from codes.common import clibs, db_operation
 | 
					from codes.common import clibs, db_operation
 | 
				
			||||||
from codes.ui.widget_bg_ui import WidgetWithBg
 | 
					from codes.ui.components.toolbar_ui import SToolBar
 | 
				
			||||||
 | 
					from codes.ui.components.list_widget_ui import SListWidget
 | 
				
			||||||
 | 
					from codes.ui.components.stacked_widget_ui import SStackedWidget
 | 
				
			||||||
 | 
					from codes.ui.components.statusbar_ui import SStatusBar
 | 
				
			||||||
 | 
					from codes.common.signal_bus import signal_bus
 | 
				
			||||||
from codes.common.worker import Worker
 | 
					from codes.common.worker import Worker
 | 
				
			||||||
from typing import Callable, Any
 | 
					from codes.common.exception_handler import handle_exception
 | 
				
			||||||
 | 
					from codes.ui.overlay_page.overlay_ui import WidgetWithBg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainWindow(QMainWindow):
 | 
					class MainWindow(QMainWindow):
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        super().__init__()
 | 
					        super().__init__()
 | 
				
			||||||
 | 
					        self.pre_do()
 | 
				
			||||||
        self.init_ui()
 | 
					        self.init_ui()
 | 
				
			||||||
        self.setup_slot()
 | 
					        self.post_do()
 | 
				
			||||||
        self.predos()
 | 
					
 | 
				
			||||||
 | 
					    def pre_do(self):
 | 
				
			||||||
 | 
					        self.m = Path(__file__).stem
 | 
				
			||||||
 | 
					        self.home_overlay = None
 | 
				
			||||||
 | 
					        db_operation.db_backup()
 | 
				
			||||||
 | 
					        db_operation.db_conn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init_ui(self):
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setObjectName("MainWindow")
 | 
				
			||||||
        self.setMinimumSize(clibs.win_width, clibs.win_height)
 | 
					        self.setMinimumSize(clibs.win_width, clibs.win_height)
 | 
				
			||||||
        self.resize(clibs.win_width, clibs.win_height)
 | 
					        self.resize(clibs.win_width, clibs.win_height)
 | 
				
			||||||
        self.setWindowTitle("Toolbox")
 | 
					        self.setWindowTitle("Toolbox")
 | 
				
			||||||
        self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
 | 
					        self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
 | 
				
			||||||
        self.setFont(QFont("Consolas", 14))
 | 
					 | 
				
			||||||
        # 任务栏/主窗口/状态栏
 | 
					        # 任务栏/主窗口/状态栏
 | 
				
			||||||
        self.toolBar = QToolBar()
 | 
					        self.toolBar = SToolBar()
 | 
				
			||||||
        self.addToolBar(self.toolBar)
 | 
					        self.addToolBar(self.toolBar)
 | 
				
			||||||
        self.toolBar.setMovable(False)
 | 
					        self.toolBar.setMovable(False)
 | 
				
			||||||
        self.centralW = QWidget()
 | 
					        self.centralW = QWidget()
 | 
				
			||||||
        self.setCentralWidget(self.centralW)
 | 
					        self.setCentralWidget(self.centralW)
 | 
				
			||||||
        self.statusBar = QStatusBar()
 | 
					        self.statusBar = SStatusBar()
 | 
				
			||||||
        self.setStatusBar(self.statusBar)
 | 
					        self.setStatusBar(self.statusBar)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # toolbar
 | 
					        layout_h = QHBoxLayout()
 | 
				
			||||||
        self.ac_homepage = QAction()
 | 
					        # list widget
 | 
				
			||||||
        self.ac_homepage.setMenuRole(QAction.MenuRole.NoRole)
 | 
					        self.listW = SListWidget()
 | 
				
			||||||
        self.ac_homepage.setStatusTip("Go to homepage")
 | 
					        layout_h.addWidget(self.listW, stretch=1)
 | 
				
			||||||
        self.ac_homepage.setToolTip("Ctrl+Alt+H")
 | 
					        self.stackedW =SStackedWidget()
 | 
				
			||||||
        self.ac_homepage.setText("主页")
 | 
					        layout_h.addWidget(self.stackedW, stretch=5)
 | 
				
			||||||
        self.ac_homepage.setShortcut(QKeySequence("Ctrl+Alt+H"))
 | 
					        self.centralW.setLayout(layout_h)
 | 
				
			||||||
        self.toolBar.addAction(self.ac_homepage)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup_slot(self):
 | 
					    def setup_slot(self):
 | 
				
			||||||
        self.ac_homepage.triggered.connect(self.ac_hp)
 | 
					        signal_bus.home_overlay_trigger.connect(self.ac_hp)
 | 
				
			||||||
        # QShortcut("Esc", self).activated.connect(self.close)
 | 
					        signal_bus.home_overlay_close.connect(self.exit_overlay)
 | 
				
			||||||
 | 
					        self.install_sc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def predos(self):
 | 
					    def post_do(self):
 | 
				
			||||||
        self.home_overlay = None
 | 
					        self.setup_slot()
 | 
				
			||||||
        db_operation.db_backup()
 | 
					        self.setup_sc()
 | 
				
			||||||
        self.conn, self.cursor = db_operation.db_conn()
 | 
					
 | 
				
			||||||
 | 
					    def setup_sc(self, enable: bool = True):
 | 
				
			||||||
 | 
					        for sc_id, obj in self.sc_pool.items():
 | 
				
			||||||
 | 
					            if isinstance(obj, QAction):
 | 
				
			||||||
 | 
					                obj.setEnabled(enable)
 | 
				
			||||||
 | 
					            elif isinstance(obj, QShortcut):
 | 
				
			||||||
 | 
					                obj.setEnabled(enable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if enable == False and (sc_id == "esc" or sc_id == "ctrl_alt_m") and self.home_overlay:
 | 
				
			||||||
 | 
					                obj.setEnabled(True)
 | 
				
			||||||
 | 
					            if (sc_id == "esc" or sc_id == "ctrl_alt_m") and self.home_overlay is None:
 | 
				
			||||||
 | 
					                obj.setEnabled(False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def install_sc(self):
 | 
				
			||||||
 | 
					        self.sc_pool = {}
 | 
				
			||||||
 | 
					        # QAction
 | 
				
			||||||
 | 
					        self.toolBar.ac_switch.setShortcut(QKeySequence("Ctrl+Alt+T"))
 | 
				
			||||||
 | 
					        self.sc_pool["ctrl_alt_t"] = self.toolBar.ac_switch
 | 
				
			||||||
 | 
					        self.toolBar.ac_homepage.setShortcut(QKeySequence("Ctrl+Alt+H"))
 | 
				
			||||||
 | 
					        self.sc_pool["ctrl_alt_h"] = self.toolBar.ac_homepage
 | 
				
			||||||
 | 
					        self.toolBar.ac_setting.setShortcut(QKeySequence("Ctrl+Alt+S"))
 | 
				
			||||||
 | 
					        self.sc_pool["ctrl_alt_s"] = self.toolBar.ac_setting
 | 
				
			||||||
 | 
					        self.toolBar.ac_log.setShortcut(QKeySequence("Ctrl+Alt+L"))
 | 
				
			||||||
 | 
					        self.sc_pool["ctrl_alt_l"] = self.toolBar.ac_log
 | 
				
			||||||
 | 
					        self.toolBar.ac_about.setShortcut(QKeySequence("Ctrl+Alt+A"))
 | 
				
			||||||
 | 
					        self.sc_pool["ctrl_alt_a"] = self.toolBar.ac_about
 | 
				
			||||||
 | 
					        # QShortcut
 | 
				
			||||||
 | 
					        self.sc_f11 = QShortcut(QKeySequence("F11"), self)
 | 
				
			||||||
 | 
					        self.sc_f11.activated.connect(self.shortcut_f11)
 | 
				
			||||||
 | 
					        self.sc_pool["f11"] = self.sc_f11
 | 
				
			||||||
 | 
					        # Subpage
 | 
				
			||||||
 | 
					        self.sc_Esc = QShortcut(QKeySequence("Esc"), self)
 | 
				
			||||||
 | 
					        self.sc_Esc.activated.connect(signal_bus.home_overlay_auth.emit)
 | 
				
			||||||
 | 
					        self.sc_pool["esc"] = self.sc_Esc
 | 
				
			||||||
 | 
					        self.sc_caM = QShortcut(QKeySequence("Ctrl+Alt+M"), self)
 | 
				
			||||||
 | 
					        self.sc_caM.activated.connect(self.toggle_full_screen)
 | 
				
			||||||
 | 
					        self.sc_pool["ctrl_alt_m"] = self.sc_caM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def ac_hp(self):
 | 
					    def ac_hp(self):
 | 
				
			||||||
        def get_files(dir_path):
 | 
					        def get_files(dir_path):
 | 
				
			||||||
            folder = Path(dir_path)
 | 
					            folder = Path(dir_path)
 | 
				
			||||||
            files = [p for p in folder.rglob("*") if p.is_file()]
 | 
					            files = [p for p in folder.rglob("*") if p.is_file()]
 | 
				
			||||||
            return choice(files), files
 | 
					            if files:
 | 
				
			||||||
 | 
					                rand_choice = choice(files)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                rand_choice = ""
 | 
				
			||||||
 | 
					            return rand_choice, files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def del_repeat_proverb(proverbs: list):
 | 
					        def del_repeat_proverb(proverbs: list):
 | 
				
			||||||
            _proverbs = []
 | 
					            _proverbs = []
 | 
				
			||||||
@@ -67,6 +119,7 @@ class MainWindow(QMainWindow):
 | 
				
			|||||||
                    _proverbs.append(proverb)
 | 
					                    _proverbs.append(proverb)
 | 
				
			||||||
            return _proverbs
 | 
					            return _proverbs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @handle_exception()
 | 
				
			||||||
        def get_resources():
 | 
					        def get_resources():
 | 
				
			||||||
            # background image
 | 
					            # background image
 | 
				
			||||||
            bing = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=8"
 | 
					            bing = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=8"
 | 
				
			||||||
@@ -77,33 +130,46 @@ class MainWindow(QMainWindow):
 | 
				
			|||||||
            for file in files:
 | 
					            for file in files:
 | 
				
			||||||
                image_names.append(file.name.removesuffix(".jpg"))
 | 
					                image_names.append(file.name.removesuffix(".jpg"))
 | 
				
			||||||
            for image in res["images"]:
 | 
					            for image in res["images"]:
 | 
				
			||||||
                startdate = image["startdate"]
 | 
					                image_name = "-".join([image["startdate"], image["hsh"]])
 | 
				
			||||||
                if startdate in image_names:
 | 
					                if image_name in image_names:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    image_url = f"""https://www.bing.com{image["url"]}"""
 | 
					                    image_url = f"""https://www.bing.com{image["url"]}"""
 | 
				
			||||||
                    file = Path(f"{clibs.base_path}/assets/media/bg/{startdate}.jpg")
 | 
					                    file = Path(f"{clibs.base_path}/assets/media/bg/{image_name}.jpg")
 | 
				
			||||||
                    try:
 | 
					                    req = requests.get(image_url, stream=True, timeout=10)
 | 
				
			||||||
                        req = requests.get(image_url, stream=True, timeout=10)
 | 
					                    with open(file, "wb") as f:
 | 
				
			||||||
                        with open(file, "wb") as f:
 | 
					                        for chunk in req.iter_content(chunk_size=8192):
 | 
				
			||||||
                            for chunk in req.iter_content(chunk_size=8192):
 | 
					                            f.write(chunk)
 | 
				
			||||||
                                f.write(chunk)
 | 
					 | 
				
			||||||
                    except Exception as e:
 | 
					 | 
				
			||||||
                        pass
 | 
					 | 
				
			||||||
            # proverbs
 | 
					            # proverbs
 | 
				
			||||||
            hitokoto = "https://v1.hitokoto.cn/"
 | 
					            hitokoto = "https://v1.hitokoto.cn/"
 | 
				
			||||||
            proverbs = []
 | 
					            proverbs = []
 | 
				
			||||||
            try:
 | 
					            proverb_file = Path(f"{clibs.base_path}/assets/media/hitokoto.json")
 | 
				
			||||||
                req = requests.get(hitokoto)
 | 
					            req = requests.get(hitokoto)
 | 
				
			||||||
                with open(f"{clibs.base_path}/assets/media/hitokoto.json", mode="rt", encoding="utf-8") as f:
 | 
					            if not proverb_file.exists():
 | 
				
			||||||
                    proverbs = json.load(f)
 | 
					                proverb_file.touch()
 | 
				
			||||||
                    proverbs.append(eval(req.text))
 | 
					                proverb_file.write_text("[]")
 | 
				
			||||||
                    proverbs = del_repeat_proverb(proverbs)
 | 
					                with open(proverb_file, "w") as f:
 | 
				
			||||||
                with open(f"{clibs.base_path}/assets/media/hitokoto.json", mode="wt", encoding="utf-8") as f:
 | 
					                    f.write("[]")
 | 
				
			||||||
                    json.dump(proverbs, f, ensure_ascii=False)
 | 
					 | 
				
			||||||
            except Exception as e:
 | 
					 | 
				
			||||||
                pass
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            with open(proverb_file, mode="rt", encoding="utf-8") as f:
 | 
				
			||||||
 | 
					                proverbs = json.load(f)
 | 
				
			||||||
 | 
					                proverb = json.loads(req.text)
 | 
				
			||||||
 | 
					                if None in proverb.values():
 | 
				
			||||||
 | 
					                    for k, v in proverb.items():
 | 
				
			||||||
 | 
					                        if v is None:
 | 
				
			||||||
 | 
					                            if v == "from_who":
 | 
				
			||||||
 | 
					                                proverb.update({k: "佚名"})
 | 
				
			||||||
 | 
					                            elif v == "from":
 | 
				
			||||||
 | 
					                                proverb.update({k: "不知道"})
 | 
				
			||||||
 | 
					                            else:
 | 
				
			||||||
 | 
					                                proverb.update({k: "-"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                proverbs.append(proverb)
 | 
				
			||||||
 | 
					                proverbs = del_repeat_proverb(proverbs)
 | 
				
			||||||
 | 
					            with open(proverb_file, mode="wt", encoding="utf-8") as f:
 | 
				
			||||||
 | 
					                json.dump(proverbs, f, ensure_ascii=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @handle_exception()
 | 
				
			||||||
        def change_resources():
 | 
					        def change_resources():
 | 
				
			||||||
            # avatar
 | 
					            # avatar
 | 
				
			||||||
            src, _ = get_files(f"{clibs.base_path}/assets/media/avatar")
 | 
					            src, _ = get_files(f"{clibs.base_path}/assets/media/avatar")
 | 
				
			||||||
@@ -123,11 +189,9 @@ class MainWindow(QMainWindow):
 | 
				
			|||||||
            copy(src, dst)
 | 
					            copy(src, dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def gen_page():
 | 
					        def gen_page():
 | 
				
			||||||
            self.set_shortcuts(False)
 | 
					 | 
				
			||||||
            self.home_overlay = WidgetWithBg(parent=self)
 | 
					            self.home_overlay = WidgetWithBg(parent=self)
 | 
				
			||||||
            self.home_overlay.on_closed.connect(self.exit_overlay)
 | 
					 | 
				
			||||||
            self.home_overlay.on_full_screen.connect(self.full_screen)
 | 
					 | 
				
			||||||
            self.home_overlay.show()
 | 
					            self.home_overlay.show()
 | 
				
			||||||
 | 
					            self.setup_sc(False)
 | 
				
			||||||
            width, height = self.width(), self.height()
 | 
					            width, height = self.width(), self.height()
 | 
				
			||||||
            if width > clibs.win_width:
 | 
					            if width > clibs.win_width:
 | 
				
			||||||
                self.resize(self.width()-1, self.height()-1)
 | 
					                self.resize(self.width()-1, self.height()-1)
 | 
				
			||||||
@@ -138,44 +202,7 @@ class MainWindow(QMainWindow):
 | 
				
			|||||||
        self.launch_get_resources(get_resources)
 | 
					        self.launch_get_resources(get_resources)
 | 
				
			||||||
        gen_page()
 | 
					        gen_page()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def full_screen(self, flag: bool):
 | 
					    def launch_get_resources(self, func, on_anything=None, *args, **kwargs):
 | 
				
			||||||
        if flag == 0:
 | 
					 | 
				
			||||||
            if self.isFullScreen():
 | 
					 | 
				
			||||||
                self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
 | 
					 | 
				
			||||||
                self.show()
 | 
					 | 
				
			||||||
                self.showMaximized()
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
 | 
					 | 
				
			||||||
                self.showFullScreen()
 | 
					 | 
				
			||||||
        elif flag == 1:
 | 
					 | 
				
			||||||
            self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
 | 
					 | 
				
			||||||
            self.show()
 | 
					 | 
				
			||||||
            self.showMaximized()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def exit_overlay(self):
 | 
					 | 
				
			||||||
        self.set_shortcuts(True)
 | 
					 | 
				
			||||||
        if self.isFullScreen():
 | 
					 | 
				
			||||||
            self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
 | 
					 | 
				
			||||||
            self.show()
 | 
					 | 
				
			||||||
            self.showMaximized()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def set_shortcuts(self, stat: bool = True):
 | 
					 | 
				
			||||||
        if stat:
 | 
					 | 
				
			||||||
            self.ac_homepage.setShortcut(QKeySequence("Ctrl+Alt+H"))
 | 
					 | 
				
			||||||
            # self.ac_settings.setShortcut(QKeySequence("Ctrl+Alt+S"))
 | 
					 | 
				
			||||||
            # self.ac_logs.setShortcut(QKeySequence("Ctrl+Alt+L"))
 | 
					 | 
				
			||||||
            # self.ac_about.setShortcut(QKeySequence("Ctrl+Alt+A"))
 | 
					 | 
				
			||||||
            # self.ac_caging.setShortcut(QKeySequence("Ctrl+Alt+C"))
 | 
					 | 
				
			||||||
            # self.ac_quit.setShortcut(QKeySequence("Ctrl+Alt+Q"))
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.ac_homepage.setShortcut(QKeySequence())
 | 
					 | 
				
			||||||
            # self.ac_settings.setShortcut(QKeySequence())
 | 
					 | 
				
			||||||
            # self.ac_logs.setShortcut(QKeySequence())
 | 
					 | 
				
			||||||
            # self.ac_about.setShortcut(QKeySequence())
 | 
					 | 
				
			||||||
            # self.ac_caging.setShortcut(QKeySequence())
 | 
					 | 
				
			||||||
            # self.ac_quit.setShortcut(QKeySequence())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def launch_get_resources(self, func, on_anything: Callable[..., Any] = None, *args, **kwargs):
 | 
					 | 
				
			||||||
        self.td_get_resources = Worker(func, *args, **kwargs)
 | 
					        self.td_get_resources = Worker(func, *args, **kwargs)
 | 
				
			||||||
        self.td_get_resources.started.connect(lambda: None)
 | 
					        self.td_get_resources.started.connect(lambda: None)
 | 
				
			||||||
        self.td_get_resources.result.connect(lambda: None)
 | 
					        self.td_get_resources.result.connect(lambda: None)
 | 
				
			||||||
@@ -183,6 +210,28 @@ class MainWindow(QMainWindow):
 | 
				
			|||||||
        self.td_get_resources.finished.connect(lambda: None)
 | 
					        self.td_get_resources.finished.connect(lambda: None)
 | 
				
			||||||
        self.td_get_resources.start()
 | 
					        self.td_get_resources.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toggle_full_screen(self):
 | 
				
			||||||
 | 
					        if self.isFullScreen():
 | 
				
			||||||
 | 
					            self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
 | 
				
			||||||
 | 
					            self.show()
 | 
				
			||||||
 | 
					            self.showMaximized()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
 | 
				
			||||||
 | 
					            self.showFullScreen()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exit_overlay(self):
 | 
				
			||||||
 | 
					        self.home_overlay = None
 | 
				
			||||||
 | 
					        self.setup_sc()
 | 
				
			||||||
 | 
					        if self.isFullScreen():
 | 
				
			||||||
 | 
					            self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
 | 
				
			||||||
 | 
					            self.show()
 | 
				
			||||||
 | 
					            self.showMaximized()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def shortcut_f11(self):
 | 
				
			||||||
 | 
					        if not self.home_overlay:
 | 
				
			||||||
 | 
					            self.ac_hp()
 | 
				
			||||||
 | 
					            self.toggle_full_screen()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def resizeEvent(self, event: QResizeEvent):
 | 
					    def resizeEvent(self, event: QResizeEvent):
 | 
				
			||||||
        super().resizeEvent(event)
 | 
					        super().resizeEvent(event)
 | 
				
			||||||
        if self.home_overlay:
 | 
					        if self.home_overlay:
 | 
				
			||||||
@@ -195,7 +244,7 @@ class MainWindow(QMainWindow):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        reply = QMessageBox.question(self, "退出", "\n程序可能在运行,确定要退出吗?")
 | 
					        reply = QMessageBox.question(self, "退出", "\n程序可能在运行,确定要退出吗?")
 | 
				
			||||||
        if reply == QMessageBox.StandardButton.Yes:
 | 
					        if reply == QMessageBox.StandardButton.Yes:
 | 
				
			||||||
            db_operation.db_close(self.conn, self.cursor)
 | 
					            db_operation.db_close()
 | 
				
			||||||
            event.accept()
 | 
					            event.accept()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            event.ignore()
 | 
					            event.ignore()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										0
									
								
								toolbox/codes/ui/overlay_page/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -1,26 +1,42 @@
 | 
				
			|||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from PySide6.QtWidgets import QWidget, QApplication, QSizePolicy, QVBoxLayout, QLabel, QFrame, QHBoxLayout, QLineEdit, QMessageBox
 | 
					from PySide6.QtWidgets import QWidget, QApplication, QSizePolicy, QVBoxLayout, QLabel, QFrame, QHBoxLayout, QLineEdit, QMessageBox
 | 
				
			||||||
from PySide6.QtGui import QPixmap, QPainter, QFontDatabase, QFont, QBrush, QShortcut, QKeySequence, QColor
 | 
					from PySide6.QtGui import QPixmap, QPainter, QFontDatabase, QFont, QBrush, QColor
 | 
				
			||||||
from PySide6.QtCore import Qt, QPoint, QDateTime, Signal, QTimer
 | 
					from PySide6.QtCore import Qt, QPoint, QDateTime, Signal, QTimer
 | 
				
			||||||
from zhdate import ZhDate
 | 
					from zhdate import ZhDate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from codes.common import clibs
 | 
					from codes.common import clibs
 | 
				
			||||||
 | 
					from codes.common.signal_bus import signal_bus
 | 
				
			||||||
 | 
					from codes.common.qss_reloader import qss_reloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LunarClockLabel(QLabel):
 | 
					class LunarClockLabel(QLabel):
 | 
				
			||||||
    def __init__(self, parent=None):
 | 
					    def __init__(self, parent=None, flag=0):
 | 
				
			||||||
        super().__init__(parent)
 | 
					        super().__init__(parent)
 | 
				
			||||||
        self.setMinimumWidth(350)
 | 
					        self.setMinimumWidth(350)
 | 
				
			||||||
        timer = QTimer(self)
 | 
					        timer = QTimer(self)
 | 
				
			||||||
        timer.timeout.connect(self.update_time)
 | 
					 | 
				
			||||||
        timer.start(1000)
 | 
					        timer.start(1000)
 | 
				
			||||||
        self.update_time()
 | 
					        if flag == 0:
 | 
				
			||||||
 | 
					            self.update_date()
 | 
				
			||||||
 | 
					            timer.timeout.connect(self.update_date)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.update_time()
 | 
				
			||||||
 | 
					            timer.timeout.connect(self.update_time)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_date(self):
 | 
				
			||||||
 | 
					        dt = QDateTime.currentDateTime()
 | 
				
			||||||
 | 
					        g = dt.date()
 | 
				
			||||||
 | 
					        z = ZhDate.today()
 | 
				
			||||||
 | 
					        week = "一二三四五六日"[g.dayOfWeek() - 1]
 | 
				
			||||||
 | 
					        text = f"{g.year()}年{g.month()}月{g.day()}日 {z.chinese()[5:]} 星期{week}"
 | 
				
			||||||
 | 
					        self.setText(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def update_time(self):
 | 
					    def update_time(self):
 | 
				
			||||||
        dt = QDateTime.currentDateTime()
 | 
					        dt = QDateTime.currentDateTime()
 | 
				
			||||||
        g = dt.date()
 | 
					        g = dt.date()
 | 
				
			||||||
        z = ZhDate.today()
 | 
					        z = ZhDate.today()
 | 
				
			||||||
        week = "一二三四五六日"[g.dayOfWeek() - 1]
 | 
					        week = "一二三四五六日"[g.dayOfWeek() - 1]
 | 
				
			||||||
        text = f"{g.year()}年{g.month()}月{g.day()}日 {z.chinese()[5:]} 星期{week} {dt.toString('hh:mm:ss')}"
 | 
					        text = f"{dt.toString('hh:mm')}"
 | 
				
			||||||
        self.setText(text)
 | 
					        self.setText(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,100 +49,97 @@ class DoubleClickLabel(QLabel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WidgetWithBg(QWidget):
 | 
					class WidgetWithBg(QWidget):
 | 
				
			||||||
    on_closed = Signal()
 | 
					 | 
				
			||||||
    on_full_screen = Signal(int)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, parent=None):
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
        super().__init__(parent)
 | 
					        super().__init__(parent)
 | 
				
			||||||
        self.predos()
 | 
					        self.pre_do()
 | 
				
			||||||
        self.init_ui()
 | 
					        self.init_ui()
 | 
				
			||||||
        self.setup_slot()
 | 
					        self.post_do()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def predos(self):
 | 
					    def pre_do(self):
 | 
				
			||||||
        font_id = QFontDatabase.addApplicationFont(f"{clibs.base_path}/assets/media/font/OldEnglishTextMT/OldEnglishTextMT.ttf")
 | 
					        font_id = QFontDatabase.addApplicationFont(f"{clibs.base_path}/assets/media/font/OldEnglishTextMT/OldEnglishTextMT.ttf")
 | 
				
			||||||
        family = QFontDatabase.applicationFontFamilies(font_id)[0]
 | 
					        family = QFontDatabase.applicationFontFamilies(font_id)[0]
 | 
				
			||||||
        self.lb_font = QFont(family, 28, QFont.Weight.Medium)
 | 
					        self.lb_font = QFont(family, 32, QFont.Weight.Medium)
 | 
				
			||||||
        self.background_pixmap = QPixmap(clibs.bg)
 | 
					        self.background_pixmap = QPixmap(clibs.bg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init_ui(self):
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setObjectName("WidgetWithBg")
 | 
				
			||||||
        layout_v = QVBoxLayout()
 | 
					        layout_v = QVBoxLayout()
 | 
				
			||||||
        # 最上层的空白区
 | 
					        # 最上层的空白区
 | 
				
			||||||
        self.lb_empty_up = QLabel(self)
 | 
					        self.lb_empty_up = QLabel(self)
 | 
				
			||||||
 | 
					        self.lb_empty_up.setObjectName("lb_empty_up")
 | 
				
			||||||
        layout_v.addWidget(self.lb_empty_up)
 | 
					        layout_v.addWidget(self.lb_empty_up)
 | 
				
			||||||
        # 头像区
 | 
					        # 头像区
 | 
				
			||||||
 | 
					        layout_h_1 = QHBoxLayout()
 | 
				
			||||||
 | 
					        layout_h_1.addStretch(1)
 | 
				
			||||||
        self.lb_avatar = DoubleClickLabel(self)
 | 
					        self.lb_avatar = DoubleClickLabel(self)
 | 
				
			||||||
 | 
					        self.lb_avatar.setObjectName("lb_avatar")
 | 
				
			||||||
        self.lb_avatar.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_avatar.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        avatar = QPixmap(clibs.avatar)
 | 
					        avatar = QPixmap(clibs.avatar)
 | 
				
			||||||
        avatar = self.circle_pixmap(avatar, 200)
 | 
					        avatar = self.circle_pixmap(avatar, 200)
 | 
				
			||||||
        self.lb_avatar.setPixmap(avatar)
 | 
					        self.lb_avatar.setPixmap(avatar)
 | 
				
			||||||
        self.lb_avatar.setScaledContents(True)
 | 
					        self.lb_avatar.setScaledContents(True)
 | 
				
			||||||
        self.lb_avatar.setFixedSize(144, 144)
 | 
					        self.lb_avatar.setFixedSize(144, 144)
 | 
				
			||||||
        layout_v.addWidget(self.lb_avatar, alignment=Qt.AlignmentFlag.AlignCenter)
 | 
					        layout_h_1.addWidget(self.lb_avatar)
 | 
				
			||||||
 | 
					        self.lb_time = LunarClockLabel(self, flag=1)
 | 
				
			||||||
 | 
					        self.lb_time.setObjectName("lb_time")
 | 
				
			||||||
 | 
					        self.lb_time.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
 | 
					        layout_h_1.addWidget(self.lb_time)
 | 
				
			||||||
 | 
					        layout_h_1.addStretch(1)
 | 
				
			||||||
 | 
					        layout_v.addLayout(layout_h_1)
 | 
				
			||||||
        # 艺术字区
 | 
					        # 艺术字区
 | 
				
			||||||
        self.lb_name = QLabel(self)
 | 
					        self.lb_name = QLabel(self)
 | 
				
			||||||
 | 
					        self.lb_name.setObjectName("lb_name")
 | 
				
			||||||
        self.lb_name.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_name.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.lb_name.setText("Manford Fan · Code Create Life")
 | 
					        self.lb_name.setText("Manford Fan · Code Create Life")
 | 
				
			||||||
        self.lb_name.setStyleSheet("color: rgba(255,255,255,255);")
 | 
					 | 
				
			||||||
        self.lb_name.setFont(self.lb_font)
 | 
					        self.lb_name.setFont(self.lb_font)
 | 
				
			||||||
        layout_v.addWidget(self.lb_name)
 | 
					        layout_v.addWidget(self.lb_name)
 | 
				
			||||||
        # 时间区-左横线
 | 
					        # 时间区-左横线
 | 
				
			||||||
        layout_h = QHBoxLayout()
 | 
					        layout_h = QHBoxLayout()
 | 
				
			||||||
        self.line_left = QFrame(self)
 | 
					        self.line_left = QFrame(self)
 | 
				
			||||||
 | 
					        self.line_left.setObjectName("line_left")
 | 
				
			||||||
        self.line_left.setFrameShape(QFrame.Shape.HLine)
 | 
					        self.line_left.setFrameShape(QFrame.Shape.HLine)
 | 
				
			||||||
        self.line_left.setFrameShadow(QFrame.Shadow.Plain)
 | 
					        self.line_left.setFrameShadow(QFrame.Shadow.Plain)
 | 
				
			||||||
        self.line_left.setStyleSheet("""
 | 
					 | 
				
			||||||
            QFrame {
 | 
					 | 
				
			||||||
                border: none;
 | 
					 | 
				
			||||||
                background-color: rgba(255, 255, 255, 40);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        """)
 | 
					 | 
				
			||||||
        policy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
 | 
					        policy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
 | 
				
			||||||
        self.line_left.setSizePolicy(policy)
 | 
					        self.line_left.setSizePolicy(policy)
 | 
				
			||||||
        self.line_left.setLineWidth(1)
 | 
					        self.line_left.setLineWidth(1)
 | 
				
			||||||
        self.line_left.setFixedWidth(100)
 | 
					        self.line_left.setFixedWidth(100)
 | 
				
			||||||
        # 时间区-右横线
 | 
					        # 时间区-右横线
 | 
				
			||||||
        self.line_right = QFrame(self)
 | 
					        self.line_right = QFrame(self)
 | 
				
			||||||
 | 
					        self.line_right.setObjectName("line_right")
 | 
				
			||||||
        self.line_right.setFrameShape(QFrame.Shape.HLine)
 | 
					        self.line_right.setFrameShape(QFrame.Shape.HLine)
 | 
				
			||||||
        self.line_right.setFrameShadow(QFrame.Shadow.Plain)
 | 
					        self.line_right.setFrameShadow(QFrame.Shadow.Plain)
 | 
				
			||||||
        self.line_right.setStyleSheet("""
 | 
					 | 
				
			||||||
            QFrame {
 | 
					 | 
				
			||||||
                border: none;
 | 
					 | 
				
			||||||
                background-color: rgba(255, 255, 255, 40);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        """)
 | 
					 | 
				
			||||||
        policy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
 | 
					        policy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
 | 
				
			||||||
        self.line_right.setSizePolicy(policy)
 | 
					        self.line_right.setSizePolicy(policy)
 | 
				
			||||||
        self.line_right.setLineWidth(1)
 | 
					        self.line_right.setLineWidth(1)
 | 
				
			||||||
        self.line_right.setFixedWidth(100)
 | 
					        self.line_right.setFixedWidth(100)
 | 
				
			||||||
        # 时间区-时间
 | 
					        # 时间区-时间
 | 
				
			||||||
        self.lb_time = LunarClockLabel(self)
 | 
					        self.lb_date = LunarClockLabel(self)
 | 
				
			||||||
        self.lb_time.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_date.setObjectName("lb_date")
 | 
				
			||||||
        self.lb_time.setStyleSheet("color: rgba(255,255,255,255);")
 | 
					        self.lb_date.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.lb_time.setFont(QFont("Consolas", 12, QFont.Weight.Bold))
 | 
					 | 
				
			||||||
        layout_h.addStretch(1)
 | 
					        layout_h.addStretch(1)
 | 
				
			||||||
        layout_h.addWidget(self.line_left)
 | 
					        layout_h.addWidget(self.line_left)
 | 
				
			||||||
        layout_h.addWidget(self.lb_time)
 | 
					        layout_h.addWidget(self.lb_date)
 | 
				
			||||||
        layout_h.addWidget(self.line_right)
 | 
					        layout_h.addWidget(self.line_right)
 | 
				
			||||||
        layout_h.addStretch(1)
 | 
					        layout_h.addStretch(1)
 | 
				
			||||||
        layout_v.addLayout(layout_h)
 | 
					        layout_v.addLayout(layout_h)
 | 
				
			||||||
        # layout_v.addWidget(self.line, alignment=Qt.AlignmentFlag.AlignCenter)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.lb_proverb = QLabel(self)
 | 
					        self.lb_proverb = QLabel(self)
 | 
				
			||||||
 | 
					        self.lb_proverb.setObjectName("lb_proverb")
 | 
				
			||||||
        self.lb_proverb.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
					        self.lb_proverb.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
        self.lb_proverb.setText(clibs.proverb)
 | 
					        self.lb_proverb.setText(clibs.proverb)
 | 
				
			||||||
        self.lb_proverb.setStyleSheet("color: rgba(255,255,255,255);")
 | 
					 | 
				
			||||||
        self.lb_proverb.setFont(QFont("Consolas", 14, QFont.Weight.Bold))
 | 
					 | 
				
			||||||
        layout_v.addWidget(self.lb_proverb)
 | 
					        layout_v.addWidget(self.lb_proverb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.le_password = QLineEdit(self)
 | 
					        self.le_password = QLineEdit(self)
 | 
				
			||||||
 | 
					        self.le_password.setObjectName("le_password")
 | 
				
			||||||
        self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
 | 
					        self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
 | 
				
			||||||
        self.le_password.setFont(QFont("Consolas", 12, QFont.Weight.Normal))
 | 
					        # self.le_password.setFont(QFont("Consolas", 12, QFont.Weight.Normal))
 | 
				
			||||||
        self.le_password.setMinimumWidth(300)
 | 
					        self.le_password.setMinimumWidth(300)
 | 
				
			||||||
        self.le_password.setFixedHeight(30)
 | 
					        self.le_password.setFixedHeight(30)
 | 
				
			||||||
        self.hide_le_password()
 | 
					 | 
				
			||||||
        layout_v.addWidget(self.le_password, alignment=Qt.AlignmentFlag.AlignCenter)
 | 
					        layout_v.addWidget(self.le_password, alignment=Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
 | 
					        self.hide_le_password()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.lb_empty_down = QLabel(self)
 | 
					        self.lb_empty_down = QLabel(self)
 | 
				
			||||||
 | 
					        self.lb_empty_down.setObjectName("lb_empty_down")
 | 
				
			||||||
        layout_v.addWidget(self.lb_empty_down)
 | 
					        layout_v.addWidget(self.lb_empty_down)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        layout_v.setStretch(0, 2)  # empty up
 | 
					        layout_v.setStretch(0, 2)  # empty up
 | 
				
			||||||
@@ -138,29 +151,31 @@ class WidgetWithBg(QWidget):
 | 
				
			|||||||
        layout_v.setStretch(6, 2)  # empty down
 | 
					        layout_v.setStretch(6, 2)  # empty down
 | 
				
			||||||
        self.setLayout(layout_v)
 | 
					        self.setLayout(layout_v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup_slot(self):
 | 
					    def post_do(self):
 | 
				
			||||||
        self.lb_avatar.doubleClicked.connect(self.auth_show)
 | 
					        qss_reloader.register(clibs.qss_home_overlay, self)
 | 
				
			||||||
        self.le_password.returnPressed.connect(self.validate_password)
 | 
					        self.setup_slot()
 | 
				
			||||||
        QShortcut(QKeySequence("Ctrl+Alt+L"), self, self.auth_show)
 | 
					 | 
				
			||||||
        QShortcut(QKeySequence("Ctrl+Alt+S"), self, lambda: self.on_full_screen.emit(0))
 | 
					 | 
				
			||||||
        # QShortcut(QKeySequence("Esc"), self).activated.connect(lambda: self.on_full_screen.emit(1))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def auth_show(self):
 | 
					    def setup_slot(self):
 | 
				
			||||||
        if self.input_hide:
 | 
					        self.lb_avatar.doubleClicked.connect(self.toggle_auth_show)
 | 
				
			||||||
            self.show_le_password()
 | 
					        self.le_password.returnPressed.connect(self.validate_password)
 | 
				
			||||||
        else:
 | 
					        signal_bus.home_overlay_auth.connect(self.toggle_auth_show)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toggle_auth_show(self):
 | 
				
			||||||
 | 
					        if self.le_is_visible:
 | 
				
			||||||
            self.hide_le_password()
 | 
					            self.hide_le_password()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.show_le_password()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def show_le_password(self):
 | 
					    def show_le_password(self):
 | 
				
			||||||
        self.input_hide = False
 | 
					        self.le_is_visible = True
 | 
				
			||||||
        self.le_password.clear()
 | 
					        self.le_password.clear()
 | 
				
			||||||
        self.le_password.setPlaceholderText("Password")
 | 
					        self.le_password.setPlaceholderText("Password")
 | 
				
			||||||
        self.le_password.setStyleSheet("")
 | 
					        self.le_password.setStyleSheet("border:none; border-radius: 5px;")
 | 
				
			||||||
        self.le_password.setDisabled(False)
 | 
					        self.le_password.setDisabled(False)
 | 
				
			||||||
        self.le_password.setFocus()
 | 
					        self.le_password.setFocus()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def hide_le_password(self):
 | 
					    def hide_le_password(self):
 | 
				
			||||||
        self.input_hide = True
 | 
					        self.le_is_visible = False
 | 
				
			||||||
        self.le_password.clear()
 | 
					        self.le_password.clear()
 | 
				
			||||||
        self.le_password.setDisabled(True)
 | 
					        self.le_password.setDisabled(True)
 | 
				
			||||||
        self.le_password.setPlaceholderText("")
 | 
					        self.le_password.setPlaceholderText("")
 | 
				
			||||||
@@ -169,14 +184,17 @@ class WidgetWithBg(QWidget):
 | 
				
			|||||||
    def validate_password(self):
 | 
					    def validate_password(self):
 | 
				
			||||||
        password = self.le_password.text()
 | 
					        password = self.le_password.text()
 | 
				
			||||||
        if password == clibs.password:
 | 
					        if password == clibs.password:
 | 
				
			||||||
            self.on_closed.emit()
 | 
					            self.hide_le_password()
 | 
				
			||||||
            self.close()
 | 
					            signal_bus.home_overlay_close.emit()
 | 
				
			||||||
 | 
					            self.deleteLater()
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
        elif password == "":
 | 
					        elif password == "":
 | 
				
			||||||
            self.hide_le_password()
 | 
					            self.hide_le_password()
 | 
				
			||||||
            return
 | 
					            return False
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            QMessageBox.critical(self, "错误", "密码不正确,请确认后重新输入!")
 | 
					            # QMessageBox.critical(self, "错误", "密码不正确,请确认后重新输入!")
 | 
				
			||||||
            self.show_le_password()
 | 
					            self.show_le_password()
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def circle_pixmap(src: QPixmap, diameter: int) -> QPixmap:
 | 
					    def circle_pixmap(src: QPixmap, diameter: int) -> QPixmap:
 | 
				
			||||||
							
								
								
									
										0
									
								
								toolbox/codes/ui/stacked_pages/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										27
									
								
								toolbox/codes/ui/stacked_pages/w01_setting.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QWidget, QLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from codes.common import clibs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class W01Setting(QWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.predos()
 | 
				
			||||||
 | 
					        self.ui_init()
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					        self.setup_sc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def predos(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ui_init(self):
 | 
				
			||||||
 | 
					        self.lb_test = QLabel(f"testing text on widget: \n{__file__}", parent=self)
 | 
				
			||||||
 | 
					        self.lb_test.setObjectName("lb_test")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_sc(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										286
									
								
								toolbox/codes/ui/stacked_pages/w08_log.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,286 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QWidget, QLabel, QMessageBox, QVBoxLayout, QTreeWidget, QHeaderView, QHBoxLayout, QPushButton, QFrame, QLineEdit, QCheckBox, QTreeWidgetItem, QDialog, QPlainTextEdit, QApplication
 | 
				
			||||||
 | 
					from PySide6.QtCore import Qt, Signal, QSize
 | 
				
			||||||
 | 
					from PySide6.QtGui import QColor, QIcon, QKeySequence, QIntValidator, QShortcut
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from codes.common.signal_bus import signal_bus
 | 
				
			||||||
 | 
					from codes.common import db_operation
 | 
				
			||||||
 | 
					from codes.common import clibs
 | 
				
			||||||
 | 
					from codes.common.qss_reloader import qss_reloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LogDialog(QDialog):
 | 
				
			||||||
 | 
					    def __init__(self, content, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.setWindowTitle("日志详情")
 | 
				
			||||||
 | 
					        self.setGeometry(100, 100, 700, 300)
 | 
				
			||||||
 | 
					        self.center_on_screen()
 | 
				
			||||||
 | 
					        layout = QVBoxLayout(self)
 | 
				
			||||||
 | 
					        self.plain_text_edit = QPlainTextEdit()
 | 
				
			||||||
 | 
					        self.plain_text_edit.setReadOnly(True)
 | 
				
			||||||
 | 
					        self.plain_text_edit.setPlainText(content)
 | 
				
			||||||
 | 
					        layout.addWidget(self.plain_text_edit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def center_on_screen(self):
 | 
				
			||||||
 | 
					        screen_geometry = QApplication.primaryScreen().geometry()
 | 
				
			||||||
 | 
					        screen_width = screen_geometry.width()
 | 
				
			||||||
 | 
					        screen_height = screen_geometry.height()
 | 
				
			||||||
 | 
					        dialog_width = self.width()
 | 
				
			||||||
 | 
					        dialog_height = self.height()
 | 
				
			||||||
 | 
					        x = (screen_width - dialog_width) // 2
 | 
				
			||||||
 | 
					        y = (screen_height - dialog_height) // 2
 | 
				
			||||||
 | 
					        self.move(x, y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PageNumberInput(QDialog):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.init_ui()
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        QShortcut(QKeySequence("Esc"), self).activated.connect(self.reject)
 | 
				
			||||||
 | 
					        self.le_page_number.returnPressed.connect(self.accept)
 | 
				
			||||||
 | 
					        self.le_page_number.returnPressed.connect(self.get_page_number)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def init_ui(self):
 | 
				
			||||||
 | 
					        self.setMinimumSize(300,100)
 | 
				
			||||||
 | 
					        self.setMaximumSize(400,120)
 | 
				
			||||||
 | 
					        self.resize(300, 100)
 | 
				
			||||||
 | 
					        self.setWindowIcon(QIcon(clibs.icon))
 | 
				
			||||||
 | 
					        self.setWindowTitle("输入页码")
 | 
				
			||||||
 | 
					        layout_h = QHBoxLayout()
 | 
				
			||||||
 | 
					        layout_h.addStretch(1)
 | 
				
			||||||
 | 
					        self.le_page_number = QLineEdit(self)
 | 
				
			||||||
 | 
					        self.le_page_number.setText("1")
 | 
				
			||||||
 | 
					        self.le_page_number.selectAll()
 | 
				
			||||||
 | 
					        self.le_page_number.setValidator(QIntValidator(0, 9999999, self))
 | 
				
			||||||
 | 
					        layout_h.addWidget(self.le_page_number, stretch=4)
 | 
				
			||||||
 | 
					        layout_h.addStretch(1)
 | 
				
			||||||
 | 
					        self.setLayout(layout_h)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_page_number(self):
 | 
				
			||||||
 | 
					        text = self.le_page_number.text()
 | 
				
			||||||
 | 
					        return 1 if text == 0 else int(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClickableLabel(QLabel):
 | 
				
			||||||
 | 
					    clicked = Signal()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def mousePressEvent(self, event):
 | 
				
			||||||
 | 
					        if event.button() == Qt.MouseButton.LeftButton:
 | 
				
			||||||
 | 
					            self.clicked.emit()
 | 
				
			||||||
 | 
					        super().mousePressEvent(event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class W08Log(QWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.pre_do()
 | 
				
			||||||
 | 
					        self.ui_init()
 | 
				
			||||||
 | 
					        self.post_do()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def pre_do(self):
 | 
				
			||||||
 | 
					        self.records, self.len_records = "", ""
 | 
				
			||||||
 | 
					        self.is_searching = False
 | 
				
			||||||
 | 
					        self.max_item_number = clibs.config["log_number_per_page"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ui_init(self):
 | 
				
			||||||
 | 
					        self.setObjectName("W08Log")
 | 
				
			||||||
 | 
					        layout_v = QVBoxLayout(self)
 | 
				
			||||||
 | 
					        self.treeW = QTreeWidget()
 | 
				
			||||||
 | 
					        self.treeW.setObjectName("treeW")
 | 
				
			||||||
 | 
					        self.treeW.setHeaderLabels(["ID", "时间戳", "告警级别", "模块信息", "告警内容"])
 | 
				
			||||||
 | 
					        self.treeW.headerItem().setTextAlignment(0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
 | 
				
			||||||
 | 
					        self.header = self.treeW.header()
 | 
				
			||||||
 | 
					        self.header.setObjectName("header")
 | 
				
			||||||
 | 
					        for i in range(self.treeW.columnCount()):
 | 
				
			||||||
 | 
					            self.header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents)
 | 
				
			||||||
 | 
					        layout_v.addWidget(self.treeW, stretch=9)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        layout_h = QHBoxLayout()
 | 
				
			||||||
 | 
					        self.pb_previous = QPushButton("上一页")
 | 
				
			||||||
 | 
					        self.pb_previous.setObjectName("pb_previous")
 | 
				
			||||||
 | 
					        layout_h.addWidget(self.pb_previous, stretch=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.lb_page = ClickableLabel("999999/999999")
 | 
				
			||||||
 | 
					        self.lb_page.setObjectName("lb_page")
 | 
				
			||||||
 | 
					        self.lb_page.setAlignment(Qt.AlignmentFlag.AlignCenter)
 | 
				
			||||||
 | 
					        self.lb_page.setMinimumWidth(144)
 | 
				
			||||||
 | 
					        layout_h.addWidget(self.lb_page, stretch=2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.pb_next = QPushButton("下一页")
 | 
				
			||||||
 | 
					        self.pb_next.setObjectName("pb_next")
 | 
				
			||||||
 | 
					        layout_h.addWidget(self.pb_next, stretch=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        layout_h.addStretch(9)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.frame_checkbox = QFrame()
 | 
				
			||||||
 | 
					        self.frame_checkbox.setObjectName("frame_checkbox")
 | 
				
			||||||
 | 
					        layout_h_checkbox = QHBoxLayout()
 | 
				
			||||||
 | 
					        self.box_info = QCheckBox("通知", parent=self.frame_checkbox)
 | 
				
			||||||
 | 
					        self.box_info.setObjectName("box_info")
 | 
				
			||||||
 | 
					        self.box_info.setChecked(True)
 | 
				
			||||||
 | 
					        layout_h_checkbox.addWidget(self.box_info, stretch=1)
 | 
				
			||||||
 | 
					        self.box_warning = QCheckBox("告警", parent=self.frame_checkbox)
 | 
				
			||||||
 | 
					        self.box_warning.setObjectName("box_warning")
 | 
				
			||||||
 | 
					        self.box_warning.setChecked(True)
 | 
				
			||||||
 | 
					        layout_h_checkbox.addWidget(self.box_warning, stretch=1)
 | 
				
			||||||
 | 
					        self.box_error = QCheckBox("错误", parent=self.frame_checkbox)
 | 
				
			||||||
 | 
					        self.box_error.setObjectName("box_error")
 | 
				
			||||||
 | 
					        self.box_error.setChecked(True)
 | 
				
			||||||
 | 
					        layout_h_checkbox.addWidget(self.box_error, stretch=1)
 | 
				
			||||||
 | 
					        self.box_exception = QCheckBox("异常", parent=self.frame_checkbox)
 | 
				
			||||||
 | 
					        self.box_exception.setObjectName("box_exception")
 | 
				
			||||||
 | 
					        self.box_exception.setChecked(True)
 | 
				
			||||||
 | 
					        layout_h_checkbox.addWidget(self.box_exception, stretch=1)
 | 
				
			||||||
 | 
					        self.box_unknown = QCheckBox("未知", parent=self.frame_checkbox)
 | 
				
			||||||
 | 
					        self.box_unknown.setObjectName("box_unknown")
 | 
				
			||||||
 | 
					        self.box_unknown.setChecked(True)
 | 
				
			||||||
 | 
					        layout_h_checkbox.addWidget(self.box_unknown, stretch=1)
 | 
				
			||||||
 | 
					        layout_h.addLayout(layout_h_checkbox, stretch=4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.le_search = QLineEdit()
 | 
				
			||||||
 | 
					        self.le_search.setObjectName("le_search")
 | 
				
			||||||
 | 
					        self.le_search.setPlaceholderText("告警内容")
 | 
				
			||||||
 | 
					        self.le_search.setMinimumWidth(300)
 | 
				
			||||||
 | 
					        layout_h.addWidget(self.le_search, stretch=5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.pb_search = QPushButton("查找")
 | 
				
			||||||
 | 
					        self.pb_search.setObjectName("pb_search")
 | 
				
			||||||
 | 
					        layout_h.addWidget(self.pb_search, stretch=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        layout_v.addLayout(layout_h, stretch=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.setLayout(layout_v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def post_do(self):
 | 
				
			||||||
 | 
					        qss_reloader.register(clibs.qss_w08_log, self)
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					        self.setup_sc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        self.treeW.itemDoubleClicked.connect(self.show_single_log)
 | 
				
			||||||
 | 
					        self.pb_previous.clicked.connect(self.previous_page)
 | 
				
			||||||
 | 
					        self.pb_next.clicked.connect(self.next_page)
 | 
				
			||||||
 | 
					        self.pb_search.clicked.connect(self.search_page)
 | 
				
			||||||
 | 
					        self.le_search.returnPressed.connect(self.search_page)
 | 
				
			||||||
 | 
					        self.lb_page.clicked.connect(self.goto_page)
 | 
				
			||||||
 | 
					        signal_bus.stacked_page_switch_log.connect(self.show_latest_page)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_sc(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def previous_page(self):
 | 
				
			||||||
 | 
					        if not self.is_searching:
 | 
				
			||||||
 | 
					            self.records, self.len_records = db_operation.db_query_logs(None)
 | 
				
			||||||
 | 
					        current, total = self.lb_page.text().split("/")
 | 
				
			||||||
 | 
					        page_number = int(current) - 1
 | 
				
			||||||
 | 
					        self.show_page(self.records, self.len_records, page_number=page_number)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next_page(self):
 | 
				
			||||||
 | 
					        if not self.is_searching:
 | 
				
			||||||
 | 
					            self.records, self.len_records = db_operation.db_query_logs(None)
 | 
				
			||||||
 | 
					        current, total = self.lb_page.text().split("/")
 | 
				
			||||||
 | 
					        page_number = int(current) + 1
 | 
				
			||||||
 | 
					        self.show_page(self.records, self.len_records, page_number=page_number)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_page(self):
 | 
				
			||||||
 | 
					        filters = {"info": self.box_info.isChecked(), "warning": self.box_warning.isChecked(), "error": self.box_error.isChecked(), "exception": self.box_exception.isChecked(), "unknown": self.box_unknown.isChecked()}
 | 
				
			||||||
 | 
					        search_text = self.le_search.text().strip()
 | 
				
			||||||
 | 
					        flag, levels = False, []
 | 
				
			||||||
 | 
					        for level, enable in filters.items():
 | 
				
			||||||
 | 
					            if not enable:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            flag = True
 | 
				
			||||||
 | 
					            levels.append(level)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not flag:
 | 
				
			||||||
 | 
					            QMessageBox().warning(None, "警告", "至少选择一个过滤器!")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.records, self.len_records = db_operation.db_query_logs(levels)
 | 
				
			||||||
 | 
					        if search_text:
 | 
				
			||||||
 | 
					            self.records, self.len_records = db_operation.db_query_logs(search_text, self.records)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_searching = True
 | 
				
			||||||
 | 
					        self.show_page(self.records, self.len_records, page_number=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def goto_page(self):
 | 
				
			||||||
 | 
					        dlg = PageNumberInput()
 | 
				
			||||||
 | 
					        if dlg.exec() != 1:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        page_number = dlg.get_page_number()
 | 
				
			||||||
 | 
					        if not self.is_searching:
 | 
				
			||||||
 | 
					            self.records, self.len_records = db_operation.db_query_logs(None)
 | 
				
			||||||
 | 
					        self.show_page(self.records, self.len_records, page_number=page_number)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_latest_page(self):
 | 
				
			||||||
 | 
					        self.records, self.len_records = db_operation.db_query_logs(None)
 | 
				
			||||||
 | 
					        self.is_searching = False
 | 
				
			||||||
 | 
					        self.box_info.setChecked(True)
 | 
				
			||||||
 | 
					        self.box_warning.setChecked(True)
 | 
				
			||||||
 | 
					        self.box_error.setChecked(True)
 | 
				
			||||||
 | 
					        self.box_exception.setChecked(True)
 | 
				
			||||||
 | 
					        self.box_unknown.setChecked(True)
 | 
				
			||||||
 | 
					        self.le_search.clear()
 | 
				
			||||||
 | 
					        self.show_page(self.records, self.len_records, page_number=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_page(self, records, len_records, page_number: int | None):
 | 
				
			||||||
 | 
					        if len_records == 0:
 | 
				
			||||||
 | 
					            self.treeW.clear()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        remainder = len_records % self.max_item_number
 | 
				
			||||||
 | 
					        total = len_records // self.max_item_number + 1 if remainder else len_records // self.max_item_number
 | 
				
			||||||
 | 
					        if page_number is None:
 | 
				
			||||||
 | 
					            current = total
 | 
				
			||||||
 | 
					        elif page_number <= 0:
 | 
				
			||||||
 | 
					            current = 1
 | 
				
			||||||
 | 
					        elif page_number < total:
 | 
				
			||||||
 | 
					            current = page_number
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            current = total
 | 
				
			||||||
 | 
					        self.lb_page.setText(f"{current}/{total}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if current == 1:
 | 
				
			||||||
 | 
					            idx_start = 0
 | 
				
			||||||
 | 
					            idx_end = self.max_item_number if len_records >= self.max_item_number else len_records
 | 
				
			||||||
 | 
					        elif current == total:
 | 
				
			||||||
 | 
					            remainder = len_records % self.max_item_number
 | 
				
			||||||
 | 
					            idx_start = len_records - remainder if remainder else len_records - self.max_item_number
 | 
				
			||||||
 | 
					            idx_end = len_records
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            idx_start = self.max_item_number * (current-1)
 | 
				
			||||||
 | 
					            idx_end = self.max_item_number * current
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.treeW.clear()
 | 
				
			||||||
 | 
					        self.treeW.setUniformRowHeights(True)
 | 
				
			||||||
 | 
					        for record in records[idx_start:idx_end]:
 | 
				
			||||||
 | 
					            record = [str(_) for _ in record]
 | 
				
			||||||
 | 
					            item = QTreeWidgetItem(self.treeW, record)
 | 
				
			||||||
 | 
					            colors = {
 | 
				
			||||||
 | 
					                "info": QColor(255, 255, 255),  # 白色
 | 
				
			||||||
 | 
					                "warning": QColor(244, 164, 96),  # 棕橙色
 | 
				
			||||||
 | 
					                "error": QColor(205, 92, 92),  # 印度红
 | 
				
			||||||
 | 
					                "exception": QColor(70, 130, 180),  # 钢蓝色
 | 
				
			||||||
 | 
					                "unknown": QColor(190, 190, 190)  # 灰色
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            # colors = {"info": "#FFFFFF", "warning": "#F4A460", "error": "#CD5C5C", "exception": "#4682B4", "unknown": "#BEBEBE"}
 | 
				
			||||||
 | 
					            level = record[2]
 | 
				
			||||||
 | 
					            color = colors.get(level, QColor(255, 255, 255))
 | 
				
			||||||
 | 
					            for col in range(self.treeW.columnCount()):
 | 
				
			||||||
 | 
					                item.setBackground(col, color)
 | 
				
			||||||
 | 
					            self.treeW.addTopLevelItem(item)
 | 
				
			||||||
 | 
					        self.treeW.scrollToBottom()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_single_log(self, item, column):
 | 
				
			||||||
 | 
					        log_id = f"id = {item.text(0)}"
 | 
				
			||||||
 | 
					        log_ts = f"ts = {item.text(1)}"
 | 
				
			||||||
 | 
					        log_level = f"level = {item.text(2)}"
 | 
				
			||||||
 | 
					        log_module = f"module = {item.text(3)}\n"
 | 
				
			||||||
 | 
					        deco_line = "=" * 40
 | 
				
			||||||
 | 
					        log_msg = item.text(4)
 | 
				
			||||||
 | 
					        content = "\n".join([log_id, log_ts, log_level, log_module, deco_line, log_msg])
 | 
				
			||||||
 | 
					        dialog = LogDialog(content, self)
 | 
				
			||||||
 | 
					        dialog.exec()
 | 
				
			||||||
							
								
								
									
										25
									
								
								toolbox/codes/ui/stacked_pages/w09_about.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QWidget, QLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class W09About(QWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.predos()
 | 
				
			||||||
 | 
					        self.ui_init()
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					        self.setup_sc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def predos(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ui_init(self):
 | 
				
			||||||
 | 
					        self.lb_test = QLabel(f"testing text on widget: \n{__file__}", parent=self)
 | 
				
			||||||
 | 
					        self.lb_test.setObjectName("lb_test")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_sc(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								toolbox/codes/ui/stacked_pages/w10_practical.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QWidget, QLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class W10Practical(QWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.predos()
 | 
				
			||||||
 | 
					        self.ui_init()
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					        self.setup_sc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def predos(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ui_init(self):
 | 
				
			||||||
 | 
					        self.lb_test = QLabel(f"testing text on widget: \n{__file__}", parent=self)
 | 
				
			||||||
 | 
					        self.lb_test.setObjectName("lb_test")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_sc(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								toolbox/codes/ui/stacked_pages/w20_efficiency.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QWidget, QLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class W20Efficiency(QWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.predos()
 | 
				
			||||||
 | 
					        self.ui_init()
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					        self.setup_sc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def predos(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ui_init(self):
 | 
				
			||||||
 | 
					        self.lb_test = QLabel(f"testing text on widget: \n{__file__}", parent=self)
 | 
				
			||||||
 | 
					        self.lb_test.setObjectName("lb_test")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_sc(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								toolbox/codes/ui/stacked_pages/w30_financial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					from PySide6.QtWidgets import QWidget, QLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class W30Financial(QWidget):
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.predos()
 | 
				
			||||||
 | 
					        self.ui_init()
 | 
				
			||||||
 | 
					        self.setup_slot()
 | 
				
			||||||
 | 
					        self.setup_sc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def predos(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ui_init(self):
 | 
				
			||||||
 | 
					        self.lb_test = QLabel(f"testing text on widget: \n{__file__}", parent=self)
 | 
				
			||||||
 | 
					        self.lb_test.setObjectName("lb_test")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_slot(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_sc(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,145 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<ui version="4.0">
 | 
					 | 
				
			||||||
 <class>Form</class>
 | 
					 | 
				
			||||||
 <widget class="QWidget" name="Form">
 | 
					 | 
				
			||||||
  <property name="geometry">
 | 
					 | 
				
			||||||
   <rect>
 | 
					 | 
				
			||||||
    <x>0</x>
 | 
					 | 
				
			||||||
    <y>0</y>
 | 
					 | 
				
			||||||
    <width>602</width>
 | 
					 | 
				
			||||||
    <height>376</height>
 | 
					 | 
				
			||||||
   </rect>
 | 
					 | 
				
			||||||
  </property>
 | 
					 | 
				
			||||||
  <property name="windowTitle">
 | 
					 | 
				
			||||||
   <string>Form</string>
 | 
					 | 
				
			||||||
  </property>
 | 
					 | 
				
			||||||
  <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
					 | 
				
			||||||
   <item>
 | 
					 | 
				
			||||||
    <layout class="QVBoxLayout" name="verticalLayout">
 | 
					 | 
				
			||||||
     <item>
 | 
					 | 
				
			||||||
      <widget class="QLabel" name="label">
 | 
					 | 
				
			||||||
       <property name="text">
 | 
					 | 
				
			||||||
        <string>TextLabel</string>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
      </widget>
 | 
					 | 
				
			||||||
     </item>
 | 
					 | 
				
			||||||
     <item>
 | 
					 | 
				
			||||||
      <widget class="QLabel" name="label_2">
 | 
					 | 
				
			||||||
       <property name="minimumSize">
 | 
					 | 
				
			||||||
        <size>
 | 
					 | 
				
			||||||
         <width>125</width>
 | 
					 | 
				
			||||||
         <height>125</height>
 | 
					 | 
				
			||||||
        </size>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="maximumSize">
 | 
					 | 
				
			||||||
        <size>
 | 
					 | 
				
			||||||
         <width>125</width>
 | 
					 | 
				
			||||||
         <height>125</height>
 | 
					 | 
				
			||||||
        </size>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="text">
 | 
					 | 
				
			||||||
        <string/>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="pixmap">
 | 
					 | 
				
			||||||
        <pixmap>../../assets/media/avatar.png</pixmap>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="scaledContents">
 | 
					 | 
				
			||||||
        <bool>true</bool>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="alignment">
 | 
					 | 
				
			||||||
        <set>Qt::AlignmentFlag::AlignCenter</set>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
      </widget>
 | 
					 | 
				
			||||||
     </item>
 | 
					 | 
				
			||||||
     <item>
 | 
					 | 
				
			||||||
      <widget class="QLabel" name="label_3">
 | 
					 | 
				
			||||||
       <property name="text">
 | 
					 | 
				
			||||||
        <string>Manford Fan · Code Create Life</string>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="alignment">
 | 
					 | 
				
			||||||
        <set>Qt::AlignmentFlag::AlignCenter</set>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
      </widget>
 | 
					 | 
				
			||||||
     </item>
 | 
					 | 
				
			||||||
     <item>
 | 
					 | 
				
			||||||
      <widget class="Line" name="line">
 | 
					 | 
				
			||||||
       <property name="minimumSize">
 | 
					 | 
				
			||||||
        <size>
 | 
					 | 
				
			||||||
         <width>400</width>
 | 
					 | 
				
			||||||
         <height>0</height>
 | 
					 | 
				
			||||||
        </size>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="maximumSize">
 | 
					 | 
				
			||||||
        <size>
 | 
					 | 
				
			||||||
         <width>400</width>
 | 
					 | 
				
			||||||
         <height>16777215</height>
 | 
					 | 
				
			||||||
        </size>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="layoutDirection">
 | 
					 | 
				
			||||||
        <enum>Qt::LayoutDirection::LeftToRight</enum>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="autoFillBackground">
 | 
					 | 
				
			||||||
        <bool>false</bool>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="frameShadow">
 | 
					 | 
				
			||||||
        <enum>QFrame::Shadow::Sunken</enum>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="midLineWidth">
 | 
					 | 
				
			||||||
        <number>0</number>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="orientation">
 | 
					 | 
				
			||||||
        <enum>Qt::Orientation::Horizontal</enum>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
      </widget>
 | 
					 | 
				
			||||||
     </item>
 | 
					 | 
				
			||||||
     <item>
 | 
					 | 
				
			||||||
      <widget class="QLabel" name="label_4">
 | 
					 | 
				
			||||||
       <property name="frameShadow">
 | 
					 | 
				
			||||||
        <enum>QFrame::Shadow::Sunken</enum>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="text">
 | 
					 | 
				
			||||||
        <string>memo</string>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
       <property name="alignment">
 | 
					 | 
				
			||||||
        <set>Qt::AlignmentFlag::AlignCenter</set>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
      </widget>
 | 
					 | 
				
			||||||
     </item>
 | 
					 | 
				
			||||||
     <item>
 | 
					 | 
				
			||||||
      <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,9">
 | 
					 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <widget class="QLabel" name="label_6">
 | 
					 | 
				
			||||||
         <property name="text">
 | 
					 | 
				
			||||||
          <string>TextLabel</string>
 | 
					 | 
				
			||||||
         </property>
 | 
					 | 
				
			||||||
         <property name="alignment">
 | 
					 | 
				
			||||||
          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
 | 
					 | 
				
			||||||
         </property>
 | 
					 | 
				
			||||||
        </widget>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
       <item>
 | 
					 | 
				
			||||||
        <widget class="QLineEdit" name="lineEdit">
 | 
					 | 
				
			||||||
         <property name="maximumSize">
 | 
					 | 
				
			||||||
          <size>
 | 
					 | 
				
			||||||
           <width>200</width>
 | 
					 | 
				
			||||||
           <height>16777215</height>
 | 
					 | 
				
			||||||
          </size>
 | 
					 | 
				
			||||||
         </property>
 | 
					 | 
				
			||||||
        </widget>
 | 
					 | 
				
			||||||
       </item>
 | 
					 | 
				
			||||||
      </layout>
 | 
					 | 
				
			||||||
     </item>
 | 
					 | 
				
			||||||
     <item>
 | 
					 | 
				
			||||||
      <widget class="QLabel" name="label_5">
 | 
					 | 
				
			||||||
       <property name="text">
 | 
					 | 
				
			||||||
        <string>TextLabel</string>
 | 
					 | 
				
			||||||
       </property>
 | 
					 | 
				
			||||||
      </widget>
 | 
					 | 
				
			||||||
     </item>
 | 
					 | 
				
			||||||
    </layout>
 | 
					 | 
				
			||||||
   </item>
 | 
					 | 
				
			||||||
  </layout>
 | 
					 | 
				
			||||||
 </widget>
 | 
					 | 
				
			||||||
 <resources/>
 | 
					 | 
				
			||||||
 <connections/>
 | 
					 | 
				
			||||||
</ui>
 | 
					 | 
				
			||||||
@@ -1,26 +1,18 @@
 | 
				
			|||||||
import sys
 | 
					import sys
 | 
				
			||||||
import json
 | 
					from pathlib import Path
 | 
				
			||||||
from PySide6.QtWidgets import QMainWindow, QApplication
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from codes.ui import login_ui, main_ui
 | 
					from PySide6.QtWidgets import QApplication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from codes.ui.main_ui import MainWindow
 | 
				
			||||||
 | 
					from codes.ui.login_ui import LoginWindow
 | 
				
			||||||
from codes.common import clibs
 | 
					from codes.common import clibs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LoginWindow(login_ui.LoginWindow):
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        super().__init__()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class MainWindow(main_ui.MainWindow):
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        super().__init__()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    with open(f"{clibs.base_path}/assets/conf/config.json", mode="rt", encoding="utf-8") as f:
 | 
					    clibs.config = eval(Path(f"{clibs.base_path}/assets/conf/config.json").read_text(encoding="utf-8"))
 | 
				
			||||||
        clibs.account = json.load(f)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    app = QApplication(sys.argv)
 | 
					    app = QApplication(sys.argv)
 | 
				
			||||||
    window = LoginWindow()
 | 
					    # window = LoginWindow()
 | 
				
			||||||
    # window = MainWindow()
 | 
					    window = MainWindow()
 | 
				
			||||||
    window.show()
 | 
					    window.show()
 | 
				
			||||||
    sys.exit(app.exec())
 | 
					    sys.exit(app.exec())
 | 
				
			||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					# 工具箱
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 功能
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 计算器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 颜色板
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 时间转换
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### ASCII码速查
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 账本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 待办提醒
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 密码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## TODOs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 自定义快捷键
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 修改密码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 自定义图标
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```commandline
 | 
				
			||||||
 | 
					pyinstaller --noconfirm --onedir --windowed --icon "D:\Syncthing\company\S-Program\Projects\toolbox\assets\media\icon.ico" --name "toolbox" --contents-directory "resource" --clean --log-level "WARN" --optimize "2" --add-data "D:\Syncthing\company\S-Program\Projects\toolbox\assets;assets/"  "D:\Syncthing\company\S-Program\Projects\toolbox\main.py"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||