mirror of
https://github.com/Aurora1949/AHNU-Portal-Authenticator.git
synced 2026-03-04 09:33:08 +08:00
327 lines
11 KiB
C++
327 lines
11 KiB
C++
#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();
|
||
}
|