Files
AHNU-Portal-Authenticator/mainwindow.cpp

327 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <QDir>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QStandardPaths>
#include <QUrlQuery>
#include <QSettings>
#include <QCloseEvent>
#include <QTimer>
#include <QNetworkProxy>
#include "ui_mainwindow.h"
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, provider({{"中国移动", "cmcc"}, {"中国电信", "telecom"}, {"中国联通", "unicom"}})
, baseUrl("http://100.64.4.10:801/eportal/portal/login")
, testUrl("http://www.baidu.com")
, logoutUrl("http://100.64.4.10:801/eportal/portal/logout")
, isOnline(false)
, trayMenu(new QMenu(this))
, trayIcon(new QSystemTrayIcon(this))
, networkChecker(new QTimer(this)) {
ui->setupUi(this);
init();
getUserInfo();
testOnline();
doAutoRun();
}
void MainWindow::init() {
setWindowTitle("AHNU上号器");
setWindowIcon(QIcon(":/images/logo.png"));
setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint & ~Qt::WindowMinimizeButtonHint);
setFixedSize(400, 178);
manager.setProxy(QNetworkProxy::NoProxy);
ui->statusbar->setSizeGripEnabled(false);
ui->logoLabel->setPixmap(QPixmap(":/images/banner.png"));
for (const auto &p: provider)
ui->providerComboBox->addItem(p.name, p.value);
ui->comboBoxMode->addItem("模式一", 1);
ui->comboBoxMode->addItem("模式二", 2);
ui->selfStartup->setChecked(isAutoRunEnabled());
trayIcon->setIcon(QIcon(":/images/logo.png"));
trayIcon->setToolTip(TrayIconMsg::Offline);
QAction *showAction = new QAction("显示窗口", this);
QAction *exitAction = new QAction("退出", this);
trayMenu->addAction(showAction);
trayMenu->addSeparator();
trayMenu->addAction(exitAction);
trayIcon->setContextMenu(trayMenu);
connect(networkChecker, &QTimer::timeout, this, &MainWindow::testOnline);
connect(showAction, &QAction::triggered, this, &MainWindow::onShowFromTray);
connect(exitAction, &QAction::triggered, this, &MainWindow::onQuitFromTray);
connect(trayIcon, &QSystemTrayIcon::activated, this, [this](QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger) // 单击托盘图标
onShowFromTray();
});
connect(ui->pushButtonQ, &QPushButton::clicked, this, [this] {
QMessageBox::information(this, "模式说明", ""
"模式一:需要购买校园卡,下行网速上限 100Mbps需要选择正确的运营商。\n\n"
"模式二:无需购买校园卡也可使用,下行网速上限 60Mbps运营商选项在此模式下无效。\n\n"
"如何选择?\n"
"如果你有校园卡且不想受限于模式二的网速上,建议选择模式一并正确选择运营商;如果你没有校园卡或者不想购买,建议选择模式二。\n\n"
"注意(仅高级用户):\n"
"模式一无法在校园内被其他设备访问,模式二则没有这个问题,如果你需要在校园内被其他设备访问(例如远程桌面),建议选择模式二。\n"
"模式二无法使用git的ssh方式如需使用建议使用https git或选择模式一。");
});
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::on_loginBtn_clicked() {
doLogin();
}
void MainWindow::online() {
ui->loginBtn->setText("登出");
ui->loginBtn->setStyleSheet("color: red;");
trayIcon->setToolTip(TrayIconMsg::Online);
setInputEnable(false);
networkChecker->start(5000);
isOnline = true;
}
void MainWindow::offline() {
ui->loginBtn->setText("登录");
ui->loginBtn->setStyleSheet("color: black;");
trayIcon->setToolTip(TrayIconMsg::Offline);
setInputEnable(true);
if (!this->isVisible())
onShowFromTray();
networkChecker->stop();
isOnline = false;
}
void MainWindow::setInputEnable(bool enable) {
ui->passwdLe->setEnabled(enable);
ui->usernameLe->setEnabled(enable);
ui->providerComboBox->setEnabled(enable);
ui->rememberMe->setEnabled(enable);
ui->comboBoxMode->setEnabled(enable);
}
void MainWindow::saveUserInfo() {
// 获取 APPDATA 路径
QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir dir(appDataPath);
if (!dir.exists())
dir.mkpath(appDataPath);
QString filePath = appDataPath + "/userinfo.json";
QFile file(filePath);
// 创建 JSON 对象
QJsonObject userInfo;
userInfo["username"] = ui->usernameLe->text();
userInfo["password"] = ui->passwdLe->text();
userInfo["provider"] = ui->providerComboBox->currentText();
userInfo["mode"] = ui->comboBoxMode->currentText();
// 写入文件
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QJsonDocument doc(userInfo);
file.write(doc.toJson(QJsonDocument::Indented));
file.close();
} else {
QMessageBox::warning(this, "注意", "无法保存账户与密码");
}
}
void MainWindow::getUserInfo() {
QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QString filePath = appDataPath + "/userinfo.json";
QFile file(filePath);
QJsonObject userInfo;
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readAll();
QJsonDocument doc = QJsonDocument::fromJson(data);
if (doc.isObject())
userInfo = doc.object();
file.close();
ui->usernameLe->setText(userInfo.take("username").toString());
ui->passwdLe->setText(userInfo.take("password").toString());
ui->providerComboBox->setEditText(userInfo.take("provider").toString());
ui->comboBoxMode->setCurrentText(userInfo.take("mode").toString());
ui->rememberMe->setChecked(true);
}
}
void MainWindow::testOnline() {
QNetworkRequest request{testUrl};
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::ManualRedirectPolicy);
QNetworkReply *reply{manager.head(request)};
connect(reply, &QNetworkReply::finished, this, [this, reply] {
if (reply->error() == QNetworkReply::NoError) {
QUrl reUrl{reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl()};
if (reUrl.host() == "rz.ahnu.edu.cn") {
ui->statusbar->showMessage(StatusBarMsg::AlreadyOffline);
offline();
} else {
ui->statusbar->showMessage(StatusBarMsg::AlreadyOnline);
online();
}
}
reply->deleteLater();
});
}
void MainWindow::setAutoRun(bool isStart) {
QString appName = QApplication::applicationName(); // 获取应用名称
QSettings settings(RegKey, QSettings::NativeFormat); // 创建QSettings对象
if (isStart) {
QString appPath = QApplication::applicationFilePath(); // 获取应用路径
appPath += " --auto-start";
settings.setValue(appName, appPath.replace("/", "\\")); // 写入注册表
} else {
settings.remove(appName); // 从注册表中删除
}
}
bool MainWindow::isAutoRunEnabled() {
QSettings settings(RegKey, QSettings::NativeFormat);
QString appPath = QDir::toNativeSeparators(QApplication::applicationFilePath());
return settings.value(QApplication::applicationName()).toString().split(" ")[0] == appPath;
}
void MainWindow::on_selfStartup_checkStateChanged() {
setAutoRun(ui->selfStartup->isChecked());
}
void MainWindow::closeEvent(QCloseEvent *event) {
hideToBackground();
event->ignore(); // 阻止真正关闭
}
void MainWindow::onShowFromTray() {
showNormal();
activateWindow(); // 把窗口带到前台
trayIcon->hide();
}
void MainWindow::onQuitFromTray() {
qApp->quit();
}
void MainWindow::showFromTray() {
onShowFromTray();
}
void MainWindow::doAutoRun() {
if (!QCoreApplication::arguments().contains("--auto-start"))
return;
if (!isOnline) {
doLogin();
}
QTimer::singleShot(500, [this] {
if (isOnline) {
hideToBackground();
trayIcon->showMessage(APPNAME, TrayIconMsg::AutoHideToBackground);
}
});
}
void MainWindow::doLogin() {
QNetworkRequest request;
if (ui->rememberMe->isChecked()) {
saveUserInfo();
}
if (isOnline) {
request.setUrl(logoutUrl);
} else {
ui->statusbar->showMessage(QString(StatusBarMsg::WaitForProvider).arg(ui->providerComboBox->currentText()));
QUrlQuery query;
int mode = ui->comboBoxMode->currentData().toInt();
QString account = mode == 1 ? ui->usernameLe->text() + "@" + ui->providerComboBox->currentData().toString(): ui->usernameLe->text();
query.addQueryItem("user_account", account);
query.addQueryItem("user_password", ui->passwdLe->text());
baseUrl.setQuery(query);
request.setUrl(baseUrl);
}
QNetworkReply *reply{manager.get(request)};
connect(reply, &QNetworkReply::finished, this, [this, reply] {
if (reply->error() == QNetworkReply::NoError) {
QByteArray d{reply->readAll()};
d.remove(0, 12); // remove jsonpReturn("
d.chop(2); // remove ")
QJsonParseError err;
QJsonDocument jd{QJsonDocument::fromJson(d, &err)};
QString msg;
if (err.error != QJsonParseError::NoError) {
QMessageBox::critical(this, "数据解析错误", err.errorString() + "\n" + d);
reply->deleteLater();
ui->statusbar->clearMessage();
return;
}
QJsonObject jo{jd.object()};
if (isOnline) {
if (jo.contains("msg"))
msg = jo.take("msg").toString();
offline();
} else {
LoginStatus result{0};
RetCode code{0};
if (jo.contains("msg"))
msg = jo.take("msg").toString();
if (jo.contains("result"))
result = static_cast<LoginStatus>(jo.take("result").toInt());
if (jo.contains("ret_code") && jo.value("ret_code").isDouble()) {
code = static_cast<RetCode>(jo.take("ret_code").toInt());
}
if (result == LoginStatus::Success
|| (result == LoginStatus::Failed && code == RetCode::AlreadyOnline)) {
online();
}
}
ui->statusbar->showMessage(QString(StatusBarMsg::MsgFromProvider).arg(msg));
} else {
ui->statusbar->showMessage(QString(StatusBarMsg::NetworkError).arg(reply->errorString()));
}
reply->deleteLater();
});
}
void MainWindow::hideToBackground() {
hide();
trayIcon->show();
}