diff --git a/hikyuu/admin/HikyuuAdmin.py b/hikyuu/admin/HikyuuAdmin.py index c25d0c46..f296c12a 100644 --- a/hikyuu/admin/HikyuuAdmin.py +++ b/hikyuu/admin/HikyuuAdmin.py @@ -46,7 +46,7 @@ from dialog import * from widget import * from data import (get_local_db, SessionModel) -import ServerApi +import service class MyMainWindow(QtWidgets.QMainWindow): @@ -293,7 +293,7 @@ class MyMainWindow(QtWidgets.QMainWindow): QtWidgets.QMessageBox.about(self, _translate("MainWindow", "info"), _translate("MainWindow", "Connected")) return - status, msg = ServerApi.getServerStatus(session) + status, msg = service.getServerStatus(session) icons = {"running": QtGui.QIcon(":/icon/circular_green.png"), "stop": QtGui.QIcon(":/icon/circular_yellow.png")} item.setText(1, msg) item.setIcon(1, icons[status]) @@ -322,7 +322,21 @@ class MyMainWindow(QtWidgets.QMainWindow): _translate("MainWindow", "The server is disconnected. Please connect first!") ) else: - tab = HkuUserManagerWidget(session, self.main_tab) + try: + data = RestDataTableModel( + ['userid', 'name', 'start_time'], [ + _translate("UserManager", "userid"), + _translate("UserManager", "name"), + _translate("UserManager", "start_time") + ], service.queryUsers(session) + ) + except Exception as e: + logging.error(e) + QtWidgets.QMessageBox.warning( + self, _translate("MainWindow", "error"), "{}: {}".format(e.__class__.__name__, e) + ) + return + tab = HkuUserManagerWidget(session, data, self.main_tab) self.main_tab.addTab(tab, title) self.tabs[title] = tab diff --git a/hikyuu/admin/ServerApi/user.py b/hikyuu/admin/ServerApi/user.py deleted file mode 100644 index 69d7c8de..00000000 --- a/hikyuu/admin/ServerApi/user.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -import requests -from .config import getServerApiUrl, defaultRequestHeader -from .restful import post - -from data import SessionModel - - -# def login(session: SessionModel): -# url = getServerApiUrl(session.host, session.port, "user", "login") -# headers = defaultRequestHeader() -# return post(url, headers=headers, json={"user": session.user, "password": session.password}) - - - - -if __name__ == "__main__": - r = login("http://127.0.0.1:9001", "1", "1") - print(r.status_code) - print(r.json()) diff --git a/hikyuu/admin/admin.pro b/hikyuu/admin/admin.pro index 610b44d0..433a610f 100644 --- a/hikyuu/admin/admin.pro +++ b/hikyuu/admin/admin.pro @@ -3,5 +3,5 @@ SOURCES = HikyuuAdmin.py UiConfig.py \ widget/HkuSessionViewWidget.py \ dialog/HkuEditSessionDialog.py \ dialog/Ui_HkuEditSessionDialog.py \ - ServerApi/assist.py + service/assist.py TRANSLATIONS = language/zh_CN.ts \ No newline at end of file diff --git a/hikyuu/admin/dialog/HkuEditSessionDialog.py b/hikyuu/admin/dialog/HkuEditSessionDialog.py index 3010ae6c..2f41d7c7 100644 --- a/hikyuu/admin/dialog/HkuEditSessionDialog.py +++ b/hikyuu/admin/dialog/HkuEditSessionDialog.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import resource -import ServerApi +import service import sqlalchemy from PyQt5 import QtWidgets, QtCore, QtGui @@ -100,7 +100,7 @@ class HkuEditSessionDialog(QtWidgets.QDialog, Ui_HkuEditSessionDialog): @QtCore.pyqtSlot() def on_test_pushButton_clicked(self): try: - ServerApi.login(self.getData()) + service.login(self.getData()) QtWidgets.QMessageBox.about( self, _translate("HkuEditSessionDialog", "success"), _translate("HkuEditSessionDialog", "Connect successfully!") diff --git a/hikyuu/admin/language/zh_CN.ts b/hikyuu/admin/language/zh_CN.ts index 66e45f55..16c3b5b9 100644 --- a/hikyuu/admin/language/zh_CN.ts +++ b/hikyuu/admin/language/zh_CN.ts @@ -262,19 +262,19 @@ - ServerApi + service - + running 运行中 - + failed! {} 失败!{} - + failed connect! 连接失败! diff --git a/hikyuu/admin/ServerApi/__init__.py b/hikyuu/admin/service/__init__.py similarity index 69% rename from hikyuu/admin/ServerApi/__init__.py rename to hikyuu/admin/service/__init__.py index b17c6c46..84ae236e 100644 --- a/hikyuu/admin/ServerApi/__init__.py +++ b/hikyuu/admin/service/__init__.py @@ -2,5 +2,5 @@ from .restful import login from .assist import getServerStatus +from .user import queryUsers -__all__ = ['login', 'getServerStatus'] diff --git a/hikyuu/admin/ServerApi/assist.py b/hikyuu/admin/service/assist.py similarity index 58% rename from hikyuu/admin/ServerApi/assist.py rename to hikyuu/admin/service/assist.py index 12c02761..322560bd 100644 --- a/hikyuu/admin/ServerApi/assist.py +++ b/hikyuu/admin/service/assist.py @@ -2,7 +2,7 @@ import logging import logging -from .restful import get, session_get +from .restful import session_get from data import SessionModel from translate import _translate @@ -12,9 +12,9 @@ def getServerStatus(session: SessionModel): try: r = session_get(session, "assist", "status") if r["result"]: - return "running", _translate("ServerApi", "running") + return "running", _translate("service", "running") else: - return "stop", _translate("ServerApi", "failed! {}").format(r["errmsg"]) + return "stop", _translate("service", "failed! {}").format(r["errmsg"]) except Exception as e: logging.info("{}: {}".format(e.__class__.__name__, e)) - return "stop", _translate("ServerApi", "failed connect!") + return "stop", _translate("service", "failed connect!") diff --git a/hikyuu/admin/ServerApi/config.py b/hikyuu/admin/service/config.py similarity index 84% rename from hikyuu/admin/ServerApi/config.py rename to hikyuu/admin/service/config.py index ca7eff51..70bd202f 100644 --- a/hikyuu/admin/ServerApi/config.py +++ b/hikyuu/admin/service/config.py @@ -9,9 +9,10 @@ server_api_config = { } -def getServerApiUrl(host_url, port, service, api): +def getserviceUrl(host_url, port, service, api): return "{}://{}:{}/{}/{}/{}/{}".format( - server_api_config["protocol"], host_url, port, server_api_config["prefix"], service, server_api_config["version"], api + server_api_config["protocol"], host_url, port, server_api_config["prefix"], service, + server_api_config["version"], api ) diff --git a/hikyuu/admin/ServerApi/restful.py b/hikyuu/admin/service/restful.py similarity index 80% rename from hikyuu/admin/ServerApi/restful.py rename to hikyuu/admin/service/restful.py index af75b250..13a7bafd 100644 --- a/hikyuu/admin/ServerApi/restful.py +++ b/hikyuu/admin/service/restful.py @@ -2,7 +2,7 @@ import requests import functools -from .config import getServerApiUrl, defaultRequestHeader +from .config import getserviceUrl, defaultRequestHeader from data import SessionModel @@ -25,6 +25,16 @@ class HttpInternalServerError(HttpStatusError): return "Http status 500: Internal Server Error" +class RestfulError: + def __init__(self, res): + super(RestfulError, self).__init__() + self.errcode = res["errcode"] + self.errmsg = res["errmsg"] + + def __str__(self): + return "errcode: {}, errmsg: {}".format(self.errcode, self.errmsg) + + def wrap_restful(func): @functools.wraps(func) def wrap_func(*args, **kwargs): @@ -75,7 +85,7 @@ class RestErrorCode: def login(session: SessionModel): - url = getServerApiUrl(session.host, session.port, "user", "login") + url = getserviceUrl(session.host, session.port, "user", "login") headers = defaultRequestHeader() res = post(url, headers=headers, json={"user": session.user, "password": session.password}) session.token = res["token"] @@ -83,15 +93,16 @@ def login(session: SessionModel): return session -def session_get(session: SessionModel, service, api, params=None, **kwargs): - def inner_get(session: SessionModel, service, api, params, **kwargs): - url = getServerApiUrl(session.host, session.port, service, api) +def session_get(session: SessionModel, service, api, params=None, **kwargs): + def inner_get(session: SessionModel, service, api, params, **kwargs): + url = getserviceUrl(session.host, session.port, service, api) headers = defaultRequestHeader() headers["hku_token"] = session.token r = get(url, headers=headers, params=params, **kwargs) if "update_token" in r: session.token = r["update_token"] return r + session.running = False if not session.token: session = login(session) @@ -101,4 +112,3 @@ def session_get(session: SessionModel, service, api, params=None, **kwargs): res = inner_get(session, service, api, params, **kwargs) session.running = True if res["result"] else False return res - diff --git a/hikyuu/admin/service/user.py b/hikyuu/admin/service/user.py new file mode 100644 index 00000000..c77e6921 --- /dev/null +++ b/hikyuu/admin/service/user.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +import logging +from .restful import session_get, RestfulError + +from data import SessionModel + + +def queryUsers(session: SessionModel): + r = session_get(session, "user", "user") + if r["result"]: + return r["data"] + else: + raise RestfulError(r) diff --git a/hikyuu/admin/widget/HkuCheckServerStatusThread.py b/hikyuu/admin/widget/HkuCheckServerStatusThread.py index a1318cbf..a341ffab 100644 --- a/hikyuu/admin/widget/HkuCheckServerStatusThread.py +++ b/hikyuu/admin/widget/HkuCheckServerStatusThread.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import resource -import ServerApi +import service from PyQt5 import QtCore, QtGui, QtWidgets @@ -33,7 +33,7 @@ class HkuCheckServerStatusThread(QtCore.QThread): items = [self.session_widget.tree.topLevelItem(i) for i in range(self.session_widget.tree.topLevelItemCount())] for item in items: session = item.data(0, QtCore.Qt.UserRole) - status, msg = ServerApi.getServerStatus(session) + status, msg = service.getServerStatus(session) item.setText(1, msg) item.setIcon(1, self.icons[status]) # 刷新 treewidget 显示界面 diff --git a/hikyuu/admin/widget/HkuUserManagerWidget.py b/hikyuu/admin/widget/HkuUserManagerWidget.py index c66cd829..fc31acd8 100644 --- a/hikyuu/admin/widget/HkuUserManagerWidget.py +++ b/hikyuu/admin/widget/HkuUserManagerWidget.py @@ -1,25 +1,32 @@ # -*- coding: utf-8 -*- from PyQt5 import QtWidgets, QtCore -from .Ui_HkuUserManagerWidget import Ui_UserManagerForm from data import SessionModel from dialog import HkuAddUserDialog +from translate import _translate + +from .Ui_HkuUserManagerWidget import Ui_UserManagerForm +from .RestDataTableModel import RestDataTableModel class HkuUserManagerWidget(QtWidgets.QWidget, Ui_UserManagerForm): def __init__( self, session: SessionModel, + data: RestDataTableModel, parent=None, ): super(HkuUserManagerWidget, self).__init__(parent) self.session = session self.setupUi(self) + self.rest_data_model = data + self.users_tableView.setModel(self.rest_data_model) + #self.users_tableView.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents) + #self.users_tableView.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.Interactive) @QtCore.pyqtSlot() def on_add_user_pushButton_clicked(self): add_dialog = HkuAddUserDialog() if add_dialog.exec() > 0: print("aaaaaaa") - diff --git a/hikyuu/admin/widget/RestDataTableModel.py b/hikyuu/admin/widget/RestDataTableModel.py new file mode 100644 index 00000000..2a89a128 --- /dev/null +++ b/hikyuu/admin/widget/RestDataTableModel.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +import typing +from PyQt5 import QtCore + + +class RestDataTableModel(QtCore.QAbstractTableModel): + def __init__(self, head: list, head_tr: list, data: list = [], parent=None): + """ Restful接口返回表数据模型 + + :param head: 表头字段名称列表(按顺序) + :param head_tr: 表头字段名称国际化翻译列表(与head对应) + :param data: restful接口返回的 data 段,一个有 dict 组成的列表 + :param parent: Qt上级对象 + """ + super(RestDataTableModel, self).__init__(parent) + self.rest_head = head + self.rest_head_tr = head_tr + self.rest_data = data + + def rowCount(self, parent: QtCore.QModelIndex): + return 0 if parent.isValid() else len(self.rest_data) + + def columnCount(self, parent: QtCore.QModelIndex): + return 0 if parent.isValid() else len(self.rest_head) + + def data(self, index: QtCore.QModelIndex, role: int): + if not index.isValid() or index.row() >= len(self.rest_data) or index.row() < 0: + return None + if role == QtCore.Qt.DisplayRole: + record = self.rest_data[index.row()] + return record[self.rest_head[index.column()]] + return None + + def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int): + if role != QtCore.Qt.DisplayRole: + return None + if orientation == QtCore.Qt.Horizontal: + return self.rest_head_tr[section] + return None + + def insertRows(self, row: int, count: int, parent: QtCore.QModelIndex) -> bool: + self.beginInsertRows(QtCore.QModelIndex(), row, row + count - 1) + for i in range(count): + self.rest_data.insert(i, dict([(k, None) for k in self.rest_head])) + self.endInsertRows() + return True + + def removeRows(self, row: int, count: int, parent: QtCore.QModelIndex = ...) -> bool: + self.beginRemoveRows(QtCore.QModelIndex(), row, row + count - 1) + for i in range(count): + self.rest_data.pop(row + count - 1 - i) + self.endRemoveRows() + return True + + def setData(self, index: QtCore.QModelIndex, value: typing.Any, role: int = ...) -> bool: + if index.isValid() and role == QtCore.Qt.EditRole: + row = index.row() + self.rest_data[row][self.rest_head[index.column()]] = value + self.dataChanged.emit(index, index, [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]) + return True + return False + + def flags(self, index: QtCore.QModelIndex) -> QtCore.Qt.ItemFlags: + if not index.isValid(): + return QtCore.Qt.ItemIsEnabled + return QtCore.Qt.ItemIsEditable + + def getAllData(self): + return self.rest_data diff --git a/hikyuu/admin/widget/Ui_HkuUserManagerWidget.py b/hikyuu/admin/widget/Ui_HkuUserManagerWidget.py index fd002f8d..eaeb81c7 100644 --- a/hikyuu/admin/widget/Ui_HkuUserManagerWidget.py +++ b/hikyuu/admin/widget/Ui_HkuUserManagerWidget.py @@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_UserManagerForm(object): def setupUi(self, UserManagerForm): UserManagerForm.setObjectName("UserManagerForm") - UserManagerForm.resize(642, 383) + UserManagerForm.resize(642, 400) self.formLayout = QtWidgets.QFormLayout(UserManagerForm) self.formLayout.setObjectName("formLayout") self.verticalLayout = QtWidgets.QVBoxLayout() @@ -40,7 +40,17 @@ class Ui_UserManagerForm(object): self.horizontalLayout.addItem(spacerItem) self.verticalLayout.addLayout(self.horizontalLayout) self.users_tableView = QtWidgets.QTableView(UserManagerForm) + self.users_tableView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.users_tableView.setAlternatingRowColors(False) + self.users_tableView.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.users_tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.users_tableView.setSortingEnabled(True) self.users_tableView.setObjectName("users_tableView") + self.users_tableView.horizontalHeader().setDefaultSectionSize(140) + self.users_tableView.horizontalHeader().setMinimumSectionSize(5) + self.users_tableView.horizontalHeader().setSortIndicatorShown(True) + self.users_tableView.horizontalHeader().setStretchLastSection(True) + self.users_tableView.verticalHeader().setVisible(False) self.verticalLayout.addWidget(self.users_tableView) self.formLayout.setLayout(0, QtWidgets.QFormLayout.SpanningRole, self.verticalLayout) diff --git a/hikyuu/admin/widget/Ui_HkuUserManagerWidget.ui b/hikyuu/admin/widget/Ui_HkuUserManagerWidget.ui index a3aff955..89fcbf7c 100644 --- a/hikyuu/admin/widget/Ui_HkuUserManagerWidget.ui +++ b/hikyuu/admin/widget/Ui_HkuUserManagerWidget.ui @@ -69,7 +69,38 @@ - + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + 5 + + + 140 + + + true + + + true + + + false + + diff --git a/hikyuu/admin/widget/__init__.py b/hikyuu/admin/widget/__init__.py index 394c0345..48293d8b 100644 --- a/hikyuu/admin/widget/__init__.py +++ b/hikyuu/admin/widget/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from .RestDataTableModel import RestDataTableModel from .HkuSessionViewWidget import HkuSessionViewWidget -from .HkuUserManagerWidget import HkuUserManagerWidget \ No newline at end of file +from .HkuUserManagerWidget import HkuUserManagerWidget