pyweb/webui.py

234 lines
5.6 KiB
Python

"""
@Author: skong
@File : webui.py
@notes : Web UI with backend
"""
from typing import Optional, Any, List
from pydantic import BaseModel
import webview
import webview.menu as wm
from webview import Window
from libs.log import Logger
class Config:
"""
配置基类
"""
_version = 3.6
_base_name: str = "知识图谱"
_base_url: str = "http://localhost:8090"
_web: webview = webview
_menu_items: List = []
_default_view: Optional[Window] = None
log: Logger = Logger("webui")
__html = """
<head>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
background-color: #f2f2f2;
font-family: Arial, sans-serif;
}
.container {
text-align: center;
width: auto;
height: auto;
}
h1 {
font-size: 24px;
margin-bottom: 20px;
}
button {
padding: 10px 20px;
font-size: 18px;
background-color: #4CAF50;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<h1>服务已经运行!!!</h1>
<button onclick="pywebview.api.close_window()">关闭程序</button>
</div>
</body>
"""
Router: dict[dict] = {
"frontend": {
"title": f"{_base_name}-前端",
"url": _base_url,
},
"backend":{
"title": f"{_base_name}-后端",
"url": f"{_base_url}/docs"
},
"index":{
"title": f"{_base_name}-{_version}",
"url": "",
"html": __html,
},
}
def get_config(self, key: str, view: Optional[Window]) -> Any:
"""获取配置信息
参数:
- `key`: 需要获取的键
- `view`: 视图(不存在则获取本地配置)
示例:
```python
# 默认视图
self.get_config('window.screen.width', default_view)
# 配置信息
self.get_config('version')
```
"""
if view is not None:
return view.evaluate_js(key)
else:
...
def auto_resize(
self,
width: Optional[int]= None,
height: Optional[int]=None,
view: Optional[Window] =None,
):
"""自适应窗口大小
参数:
- `view`: 视图
- `width`: 宽度
- `height`: 高度
示例:
```python
self.auto_resize(view)
```
"""
if view is None:
view = self._default_view
if isinstance(view, Window):
if width is None and height is None:
screens = self._web.screens[0]
width = int(screens.width*0.85)
height = int(screens.height*0.85)
view.resize(width, height)
else:
self.log.error("Window is not found")
def close_window(self, window:Window):
"""
关闭窗口
"""
self._default_view.destroy()
class MenuModel(BaseModel):
"""
菜单数据模型
"""
title: Optional[str]
url: Optional[str]
html: Optional[str]
class Handler(Config):
def add_menu(self, key: str, view: list[object]):
"""
增加菜单
"""
try:
self._menu_items.insert(0, wm.Menu(key, view))
except Exception as err:
self.log.error(err)
def frontend(self):
"""
前端
"""
return self.render(MenuModel(**self.Router['frontend']))
def backend(self):
"""
后端
"""
return self.render(MenuModel(**self.Router['backend']))
def index(self):
"""
主页
"""
return self.render(MenuModel(**self.Router['index']))
def render(self, info: MenuModel):
"""渲染页面
参数:
- `info`: 数据模型或者空类型
示例:
```python
def index(self):
return self.render(info=self.Router['index'])
```
"""
self.auto_resize()
self._default_view.title = info.title
if info.html is not None:
self._default_view.load_html(info.html)
else:
self._default_view.load_url(info.url)
def start_webview(self):
"""
启动 `WebView` 程序
"""
self._default_view = self._web.create_window(
self.Router['index']['title'],
html=self.Router['index']['html'],
# confirm_close=True,
)
self._default_view.expose(self.close_window)
self._web.start(menu=self._menu_items)
if __name__ == '__main__':
app = Handler()
app.add_menu(
'服务选择',
[
wm.MenuAction('前端', app.frontend),
wm.MenuSeparator(),
wm.MenuAction("后端", app.backend),
],
)
app.add_menu(
'主页',
[
wm.MenuAction('运行状况', app.index),
wm.MenuSeparator(),
wm.MenuAction('自适应窗口', app.auto_resize),
],
)
app.start_webview()