parent
fa542e57f1
commit
65007987f2
|
@ -8,8 +8,8 @@ pyweb是一个基于Pywebview构建的开箱即用的模板,旨在帮助快速
|
|||
|
||||
- [x] 界面展示
|
||||
- [x] 数据处理
|
||||
- [x] 用户认证
|
||||
- [x] 数据库集成
|
||||
- [ ] 用户认证
|
||||
- [ ] 数据库集成
|
||||
- [ ] 数据可视化
|
||||
- [ ] 文件上传和下载
|
||||
|
||||
|
@ -27,7 +27,7 @@ python run main.py
|
|||
|
||||
## 📷 截屏
|
||||
|
||||
<!-- ![截屏](screenshot.png) -->
|
||||
![截屏](./res/screenshot.png)
|
||||
|
||||
## 🤝 贡献
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
"""
|
||||
提供 logger 对象。
|
||||
> 其他任何 "libs" 模块都应使用此模块的 "logger" 来打印日志。
|
||||
|
||||
Tip:
|
||||
移除 `logging` 改用 `loguru.logger`
|
||||
"""
|
||||
import wrapt
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class Logger:
|
||||
def __init__(self, name):
|
||||
self.__log = logger.bind(name=name)
|
||||
self.__log.add(
|
||||
sink=f"{name}.log",
|
||||
format="{time} | {level} | {message}",
|
||||
rotation="1 week",
|
||||
)
|
||||
|
||||
def __call__(self, func):
|
||||
@wrapt.decorator
|
||||
def wrapper(wrapped, instance, args, kwargs):
|
||||
resp = wrapped(*args, **kwargs)
|
||||
self.info(f"{wrapped.__name__}|=> {resp}")
|
||||
return resp
|
||||
return wrapper(func)
|
||||
|
||||
@property
|
||||
def info(self):
|
||||
return self.__log.info
|
||||
|
||||
@property
|
||||
def warn(self):
|
||||
return self.__log.warn
|
||||
|
||||
@property
|
||||
def error(self):
|
||||
return self.__log.error
|
||||
|
||||
@property
|
||||
def debug(self):
|
||||
return self.__log.debug
|
||||
|
||||
|
||||
__all__ = [
|
||||
'Logger',
|
||||
]
|
|
@ -0,0 +1,7 @@
|
|||
pywebview
|
||||
fastapi[all]
|
||||
httpx
|
||||
requests
|
||||
pymysql
|
||||
aiomysql
|
||||
aiofiles
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,233 @@
|
|||
"""
|
||||
@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()
|
Loading…
Reference in New Issue