modify: 封装webview通用模块

This commit is contained in:
chakcy 2025-09-30 11:01:00 +08:00
parent 7abb876100
commit 01bd8e0f5e
14 changed files with 186 additions and 103 deletions

3
.gitignore vendored
View File

@ -29,3 +29,6 @@ nuitka-crash-report.xml
# plugin files
plugins/
# log files
log/

View File

@ -5,4 +5,9 @@ try:
except:
config = {}
__all__ = ["config"]
def get_info() -> dict:
return config
__all__ = ["config", "get_info"]

View File

@ -1,12 +1,8 @@
from queue_sqlite.scheduler import QueueScheduler
from .students.add_student import add_student
from .students.add_student import add_student
from .students.students_listen import students
scheduler = QueueScheduler()
scheduler = QueueScheduler(scheduler_type="async")
__all__ = [
"scheduler",
"add_student",
"students"
]
__all__ = ["scheduler", "add_student", "students"]

View File

@ -1,9 +1,8 @@
from queue_sqlite.mounter.task_mounter import TaskMounter
from queue_sqlite.mounter import task
from queue_sqlite.model import MessageItem
import time
@TaskMounter.task(meta={"task_name": "add_student"})
@task(meta={"task_name": "add_student"})
def add_student(message_item: MessageItem):
# create a new instance of the AddStudentDilalog dialog
# time.sleep(3)
@ -11,7 +10,7 @@ def add_student(message_item: MessageItem):
return {"message": "学生添加成功"}
@TaskMounter.task(meta={"task_name": "test"})
@task(meta={"task_name": "test"})
def test(message_item: MessageItem):
# print(f"测试任务: {message_item}")
return {"message": "测试成功"}

4
app/utils/__init__.py Normal file
View File

@ -0,0 +1,4 @@
from .webview_queue_sqlite_operations import WebViewQueueSqliteOperations
__all__ = ["WebViewQueueSqliteOperations"]

View File

@ -0,0 +1,8 @@
from PySide6.QtCore import QObject
class BaseWebViewBridge(QObject):
def __init__(self, webview, parent=None):
self.webview = webview
super().__init__(parent)
pass

View File

@ -0,0 +1,44 @@
from PySide6.QtCore import QObject
from .webview_queue_sqlite_operations import WebViewQueueSqliteOperations
from .base_webview_bridge import BaseWebViewBridge
from typing import List
from PySide6.QtWebChannel import QWebChannel
class WebviewController(QObject):
def __init__(
self,
web_engine_page,
webview_bridge_list: List[type[BaseWebViewBridge]],
web_webview,
scheduler,
parent=None,
):
super().__init__(parent)
self.page = web_engine_page
self.bridge_instances = {}
# 创建bridge实例并保存
for bridge_class in webview_bridge_list:
instance = bridge_class(web_webview)
bridge_name = bridge_class.__name__.lower()
setattr(self, bridge_name, instance)
self.bridge_instances[bridge_name] = instance
self.queue_sqlite_operations = WebViewQueueSqliteOperations(
web_webview, scheduler
)
self.channel = QWebChannel()
# 使用已创建的实例注册到channel
for bridge_name, instance in self.bridge_instances.items():
self.channel.registerObject(bridge_name, instance)
# 为了向前兼容,确保注册名为 "entrance" 的对象
if "webviewbridge" in self.bridge_instances:
self.channel.registerObject(
"entrance", self.bridge_instances["webviewbridge"]
)
self.channel.registerObject("queueSqlite", self.queue_sqlite_operations)
self.page.setWebChannel(self.channel)

View File

@ -0,0 +1,54 @@
import json
from PySide6.QtCore import QObject, Slot, Signal
from qframelesswindow.webengine import FramelessWebEngineView
from queue_sqlite.model import MessageItem
from queue_sqlite.scheduler import QueueScheduler
class WebViewQueueSqliteOperations(QObject):
"""
用于前端调用QueueSqlite的队列操作
"""
update_queue_state_signal = Signal(dict, str)
def __init__(
self,
webview: FramelessWebEngineView,
queue_scheduler: QueueScheduler,
parent=None,
):
super().__init__(parent)
self.webview = webview
self.page = self.webview.page()
self.update_queue_state_signal.connect(self.update_queue_state)
self.queue_scheduler = queue_scheduler
@Slot(str, str, result=str)
def send_message(self, message: str, store_key: str):
def callback(result: MessageItem):
print(f"send_message callback: {result}")
self.update_queue_state_signal.emit(result.to_dict(), store_key)
self.queue_scheduler.send_message(
MessageItem.from_dict(json.loads(message)), callback
)
def update_queue_state(self, result: dict, store_key: str):
json_str = json.dumps(result)
print(f"result: {result}")
print(f"json_str: {json_str}")
js_code = f"""
try {{
if (typeof window.queueStore.updateQueueData === 'function') {{
window.queueStore.updateQueueData('{store_key}', {json_str});
}} else {{
console.log('updateQueueData function not found');
}}
}} catch (error) {{
console.error('Error in updateQueueData:', error);
}}
"""
print(f"执行的JavaScript代码: {js_code}")
self.page.runJavaScript(js_code)

View File

@ -7,59 +7,17 @@ import base64
import tempfile
from pathlib import Path
from PySide6.QtCore import QObject, Slot, QUrl
from PySide6.QtWebChannel import QWebChannel
from PySide6.QtCore import Slot, QUrl
from PySide6.QtWebEngineCore import QWebEngineSettings
from qframelesswindow.webengine import FramelessWebEngineView
from queue_sqlite.model import MessageItem
from ...scheduler_manager import scheduler
from ...signal import global_signals
from ...utils.base_webview_bridge import BaseWebViewBridge
class WebViewQueueSqliteOperations(QObject):
"""
用于前端调用QueueSqlite的队列操作
"""
def __init__(self, webview: FramelessWebEngineView, parent=None):
super().__init__(parent)
self.webview = webview
self.page = self.webview.page()
global_signals.update_queue_state.connect(self.update_queue_state)
@Slot(str, str, result=str)
def send_message(self, message: str, store_key: str):
def callback(result: MessageItem):
print(f"send_message callback: {result}")
global_signals.update_queue_state.emit(result.to_dict(), store_key)
scheduler.send_message(MessageItem.from_dict(json.loads(message)), callback)
def update_queue_state(self, result: dict, store_key: str):
json_str = json.dumps(result)
print(f"result: {result}")
print(f"json_str: {json_str}")
js_code = f"""
try {{
if (typeof window.queueStore.updateQueueData === 'function') {{
window.queueStore.updateQueueData('{store_key}', {json_str});
}} else {{
console.log('updateQueueData function not found');
}}
}} catch (error) {{
console.error('Error in updateQueueData:', error);
}}
"""
print(f"执行的JavaScript代码: {js_code}")
self.page.runJavaScript(js_code)
class WebviewBridge(QObject):
class Entrance(BaseWebViewBridge):
"""Webview桥接类用于处理前端和Python后端之间的通信"""
def __init__(self, webview, parent=None):
super().__init__(parent)
super().__init__(webview, parent)
self.webview = webview
# 启用本地文件访问
@ -362,17 +320,3 @@ class WebviewBridge(QObject):
except Exception as e:
# 确保任何异常都返回有效的JSON
return json.dumps({"success": False, "error": str(e)})
class WebviewController(QObject):
"""Webview控制器类负责管理Webview的逻辑"""
def __init__(self, web_engine_page, web_webview, parent=None):
super().__init__(parent)
self.page = web_engine_page
self.bridge = WebviewBridge(web_webview)
self.queue_sqlite_operations = WebViewQueueSqliteOperations(web_webview)
self.channel = QWebChannel()
self.channel.registerObject("entrance", self.bridge)
self.channel.registerObject("queueSqlite", self.queue_sqlite_operations)
self.page.setWebChannel(self.channel)

View File

@ -15,8 +15,10 @@ from PySide6.QtWidgets import (
from PySide6.QtCore import QPoint, Qt, QUrl
from qframelesswindow.webengine import FramelessWebEngineView
from .entrance import WebviewController
from ...config import config
from ...utils.webview_controller import WebviewController
from .entrance import Entrance
from ...scheduler_manager import scheduler
class DevToolsWindow(FramelessWebEngineView):
@ -60,7 +62,9 @@ class WebViewInterface(QFrame):
# 创建WebviewController实例
self.page = self.webView.page()
self.controller = WebviewController(self.page, self.webView)
self.controller = WebviewController(
self.page, [Entrance], self.webView, scheduler
)
# 加载初始页面
self.load_current_page()

21
main.py
View File

@ -1,35 +1,28 @@
import sys
import os
from PySide6.QtWidgets import QApplication
from app.view import Window
from app.scheduler_manager import scheduler
def resource_path(relative_path):
"""获取资源的绝对路径。用于PyInstaller/Nuitka打包后定位资源文件。"""
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path) # type: ignore
return os.path.join(os.path.abspath("."), relative_path)
def main():
# 设置基础路径
base_dir = os.path.abspath(".")
# 启动队列调度器
scheduler.start_queue_scheduler()
scheduler.start()
# 创建Qt应用
app = QApplication(sys.argv)
window = Window()
window.show()
window.setMicaEffectEnabled(True)
# 启动事件循环
exit_code = app.exec()
# 停止队列调度器
scheduler.stop_queue_scheduler()
scheduler.stop()
sys.exit(exit_code)
if __name__ == "__main__":
main()
main()

View File

@ -9,7 +9,7 @@ dependencies = [
"opencv-python-headless>=4.12.0.88",
"pyside6>=6.9.1",
"pyside6-fluent-widgets>=1.8.6",
"queue-sqlite",
"queue-sqlite>=0.2.0",
"toml>=0.10.2",
]
# 是否是生产环境
@ -21,9 +21,6 @@ default = true
# url = "https://pypi.tuna.tsinghua.edu.cn/simple"
url = "https://mirrors.aliyun.com/pypi/simple"
[tool.uv.sources]
queue-sqlite = { path = "lib/queue_sqlite" }
[dependency-groups]
dev = [
"nuitka>=2.7.12",

View File

@ -1,5 +1,6 @@
import os
import shutil
# 需要遍历的目录
root_dir = "./"
# 遍历目录

53
uv.lock generated
View File

@ -1,5 +1,5 @@
version = 1
revision = 1
revision = 3
requires-python = ">=3.12"
[[package]]
@ -65,6 +65,27 @@ wheels = [
{ url = "https://mirrors.aliyun.com/pypi/packages/d1/5d/c059c180c84f7962db0aeae7c3b9303ed1d73d76f2bfbc32bc231c8be314/macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c" },
]
[[package]]
name = "maturin"
version = "1.9.4"
source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
sdist = { url = "https://mirrors.aliyun.com/pypi/packages/13/7c/b11b870fc4fd84de2099906314ce45488ae17be32ff5493519a6cddc518a/maturin-1.9.4.tar.gz", hash = "sha256:235163a0c99bc6f380fb8786c04fd14dcf6cd622ff295ea3de525015e6ac40cf" }
wheels = [
{ url = "https://mirrors.aliyun.com/pypi/packages/f2/90/0d99389eea1939116fca841cad0763600c8d3183a02a9478d066736c60e8/maturin-1.9.4-py3-none-linux_armv6l.whl", hash = "sha256:6ff37578e3f5fdbe685110d45f60af1f5a7dfce70a1e26dfe3810af66853ecae" },
{ url = "https://mirrors.aliyun.com/pypi/packages/f4/ed/c8ec68b383e50f084bf1fa9605e62a90cd32a3f75d9894ed3a6e5d4cc5b3/maturin-1.9.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f3837bb53611b2dafa1c090436c330f2d743ba305ef00d8801a371f4495e7e1b" },
{ url = "https://mirrors.aliyun.com/pypi/packages/84/4e/401ff5f3cfc6b123364d4b94379bf910d7baee32c9c95b72784ff2329357/maturin-1.9.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4227d627d8e3bfe45877a8d65e9d8351a9d01434549f0da75d2c06a1b570de58" },
{ url = "https://mirrors.aliyun.com/pypi/packages/51/8e/c56176dd360da9650c62b8a5ecfb85432cf011e97e46c186901e6996002e/maturin-1.9.4-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:1bb2aa0fa29032e9c5aac03ac400396ddea12cadef242f8967e9c8ef715313a1" },
{ url = "https://mirrors.aliyun.com/pypi/packages/d2/46/001fcc5c6ad509874896418d6169a61acd619df5b724f99766308c44a99f/maturin-1.9.4-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:a0868d52934c8a5d1411b42367633fdb5cd5515bec47a534192282167448ec30" },
{ url = "https://mirrors.aliyun.com/pypi/packages/b4/2e/26fa7574f01c19b7a74680fd70e5bae2e8c40fed9683d1752e765062cc2b/maturin-1.9.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:68b7b833b25741c0f553b78e8b9e095b31ae7c6611533b3c7b71f84c2cb8fc44" },
{ url = "https://mirrors.aliyun.com/pypi/packages/73/ee/ca7308832d4f5b521c1aa176d9265f6f93e0bd1ad82a90fd9cd799f6b28c/maturin-1.9.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:08dc86312afee55af778af919818632e35d8d0464ccd79cb86700d9ea560ccd7" },
{ url = "https://mirrors.aliyun.com/pypi/packages/45/e8/c623955da75e801a06942edf1fdc4e772a9e8fbc1ceebbdc85d59584dc10/maturin-1.9.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:ef20ffdd943078c4c3699c29fb2ed722bb6b4419efdade6642d1dbf248f94a70" },
{ url = "https://mirrors.aliyun.com/pypi/packages/3c/4b/19ad558fdf54e151b1b4916ed45f1952ada96684ee6db64f9cd91cabec09/maturin-1.9.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:368e958468431dfeec80f75eea9639b4356d8c42428b0128444424b083fecfb0" },
{ url = "https://mirrors.aliyun.com/pypi/packages/7e/27/153ad15eccae26921e8a01812da9f3b7f9013368f8f92c36853f2043b2a3/maturin-1.9.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:273f879214f63f79bfe851cd7d541f8150bdbfae5dfdc3c0c4d125d02d1f41b4" },
{ url = "https://mirrors.aliyun.com/pypi/packages/43/e3/f304c3bdc3fba9adebe5348d4d2dd015f1152c0a9027aaf52cae0bb182c8/maturin-1.9.4-py3-none-win32.whl", hash = "sha256:ed2e54d132ace7e61829bd49709331007dd9a2cc78937f598aa76a4f69b6804d" },
{ url = "https://mirrors.aliyun.com/pypi/packages/14/14/f86d0124bf1816b99005c058a1dbdca7cb5850d9cf4b09dcae07a1bc6201/maturin-1.9.4-py3-none-win_amd64.whl", hash = "sha256:8e450bb2c9afdf38a0059ee2e1ec2b17323f152b59c16f33eb9c74edaf1f9f79" },
{ url = "https://mirrors.aliyun.com/pypi/packages/3f/25/8320fc2591e45b750c3ae71fa596b47aefa802d07d6abaaa719034a85160/maturin-1.9.4-py3-none-win_arm64.whl", hash = "sha256:7a6f980a9b67a5c13c844c268eabd855b54a6a765df4b4bb07d15a990572a4c9" },
]
[[package]]
name = "nuitka"
version = "2.7.12"
@ -2908,7 +2929,7 @@ requires-dist = [
{ name = "opencv-python-headless", specifier = ">=4.12.0.88" },
{ name = "pyside6", specifier = ">=6.9.1" },
{ name = "pyside6-fluent-widgets", specifier = ">=1.8.6" },
{ name = "queue-sqlite", directory = "lib/queue_sqlite" },
{ name = "queue-sqlite", specifier = ">=0.2.0" },
{ name = "toml", specifier = ">=0.10.2" },
]
@ -3022,16 +3043,26 @@ wheels = [
[[package]]
name = "queue-sqlite"
version = "0.1.0"
source = { directory = "lib/queue_sqlite" }
version = "0.2.0"
source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
dependencies = [
{ name = "queue-sqlite-core" },
]
sdist = { url = "https://mirrors.aliyun.com/pypi/packages/e9/96/7ac3799d9eee19d6cc7dc58541b7a3888474eaef0314f32c6ed2bc962147/queue_sqlite-0.2.0.tar.gz", hash = "sha256:314eb16db66574679dbab61ee936e790c292cab9ec70e30bf51471955939b211" }
wheels = [
{ url = "https://mirrors.aliyun.com/pypi/packages/a8/86/0ec82affe1246ba4d677420578b2e1ef882bf99f3b2b2e9b3d04e0e40010/queue_sqlite-0.2.0-py3-none-any.whl", hash = "sha256:b7b2149c0aadd962b6d249484eb5ce133c30eb1a20fa69ce6dfdaf2fe6da89d1" },
]
[package.metadata]
[package.metadata.requires-dev]
dev = [
{ name = "maturin", specifier = ">=1.9.2" },
{ name = "psutil", specifier = ">=7.0.0" },
{ name = "pytest", specifier = ">=8.4.1" },
[[package]]
name = "queue-sqlite-core"
version = "0.2.0"
source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
dependencies = [
{ name = "maturin" },
]
wheels = [
{ url = "https://mirrors.aliyun.com/pypi/packages/75/23/3561b0da8881b0c83d2c74bb15b57a9daeb8442daaf9e1a22479d32cdde6/queue_sqlite_core-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:917efcbe7b444c33b93d405b7d7dd20517fbc0dea8803e73d8b1449dd4a281f4" },
{ url = "https://mirrors.aliyun.com/pypi/packages/21/bb/2abf6dbd3d08f0d5f7aac576168be78b957e283d9d8461bf2afcad75b86c/queue_sqlite_core-0.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a9d19840a9363bc29568b7c0e735c1ffe610b9618641c298d9647816aad8306b" },
]
[[package]]