234 lines
5.6 KiB
Python
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()
|