173 lines
5.2 KiB
C++
173 lines
5.2 KiB
C++
#include "ApiClient.h"
|
||
#include <QJsonDocument>
|
||
#include <QDebug>
|
||
|
||
|
||
static QString joinUrl(const QString &base, const QString &path)
|
||
{
|
||
if (path.startsWith("http://") || path.startsWith("https://")) return path;
|
||
QString b = base;
|
||
QString p = path;
|
||
if (b.endsWith('/')) b.chop(1);
|
||
if (p.startsWith('/')) p.remove(0, 1);
|
||
if (b.isEmpty()) return p;
|
||
return b + '/' + p;
|
||
}
|
||
|
||
ApiClient* ApiClient::m_instance = nullptr;
|
||
ApiClient::ApiClient(QObject *parent)
|
||
: QObject(parent)
|
||
, m_httpClient(new AeaQt::HttpClient(this))
|
||
{
|
||
}
|
||
|
||
ApiClient::~ApiClient()
|
||
{
|
||
}
|
||
|
||
ApiClient* ApiClient::getInstance()
|
||
{
|
||
if (m_instance == nullptr)
|
||
{
|
||
if (m_instance == nullptr)
|
||
{
|
||
m_instance = new ApiClient();
|
||
}
|
||
}
|
||
return m_instance;
|
||
}
|
||
|
||
AeaQt::HttpClient* ApiClient::httpClient() const { return m_httpClient; }
|
||
|
||
void ApiClient::setBaseUrl(const QString &baseUrl) { m_baseUrl = baseUrl; }
|
||
QString ApiClient::baseUrl() const { return m_baseUrl; }
|
||
|
||
void ApiClient::setToken(const QString &token)
|
||
{
|
||
// 保存时确保前缀存在:如果调用方传入原始 token(不带 Bearer)也能工作
|
||
if (token.startsWith("Bearer ")) m_token = token;
|
||
else if (token.isEmpty()) m_token.clear();
|
||
else m_token = "Bearer " + token;
|
||
}
|
||
|
||
QString ApiClient::token() const { return m_token; }
|
||
|
||
void ApiClient::handleResponse(const QJsonObject &resp, SuccessCB onSuccess, FailedCB onFailed)
|
||
{
|
||
// 统一处理服务端返回格式:{ code, message, data }
|
||
int code = resp.value("code").toInt(-1);
|
||
QString message = resp.value("message").toString();
|
||
if (code != 0) {
|
||
if (onFailed) onFailed(message);
|
||
return;
|
||
}
|
||
// 成功,优先返回 data 字段(如果存在且为 object),否则返回整个 resp
|
||
if (resp.contains("data") && resp.value("data").isObject()) {
|
||
if (onSuccess) onSuccess(resp.value("data").toObject());
|
||
return;
|
||
}
|
||
if (onSuccess) onSuccess(resp);
|
||
}
|
||
|
||
void ApiClient::login(const QString &username, const QString &password, SuccessCB onSuccess, FailedCB onFailed)
|
||
{
|
||
QJsonObject body;
|
||
|
||
body["login_mode"] = "local";
|
||
body["login_type"] = "username";
|
||
body["identifier"] = username;
|
||
body["password"] = password;
|
||
|
||
QString url = joinUrl(m_baseUrl, "/auth/api/v1/auth/login");
|
||
|
||
m_httpClient->post(url)
|
||
.bodyWithJson(body)
|
||
.onSuccess([this, onSuccess, onFailed](const QJsonObject &resp) {
|
||
// 先统一处理返回结构
|
||
this->handleResponse(resp,
|
||
// onSuccess -> 特殊处理 login 的 token 保存
|
||
[this, onSuccess](const QJsonObject &data) {
|
||
QString rawToken = data.value("token").toString();
|
||
if (!rawToken.isEmpty()) {
|
||
this->setToken(rawToken);
|
||
}
|
||
if (onSuccess) onSuccess(data);
|
||
},
|
||
// onFailed
|
||
[onFailed](const QString &err) {
|
||
if (onFailed) onFailed(err);
|
||
}
|
||
);
|
||
})
|
||
.onFailed([onFailed](const QString &err) {
|
||
if (onFailed) onFailed(err);
|
||
})
|
||
.exec();
|
||
}
|
||
|
||
void ApiClient::get(const QString &path, SuccessCB onSuccess, FailedCB onFailed)
|
||
{
|
||
qDebug() << "ApiClient::get " << path;
|
||
QString url = joinUrl(m_baseUrl, path);
|
||
|
||
auto req = m_httpClient->get(url);
|
||
if (!m_token.isEmpty()) req.header("Authorization", m_token);
|
||
|
||
req.onSuccess([this, onSuccess, onFailed](const QJsonObject &resp) {
|
||
this->handleResponse(resp, onSuccess, onFailed);
|
||
})
|
||
.onFailed([onFailed](const QString &err) {
|
||
if (onFailed) onFailed(err);
|
||
})
|
||
.exec();
|
||
}
|
||
|
||
void ApiClient::post(const QString &path, const QJsonObject &body, SuccessCB onSuccess, FailedCB onFailed)
|
||
{
|
||
qDebug() << "ApiClient::post " << path;
|
||
QString url = joinUrl(m_baseUrl, path);
|
||
|
||
auto req = m_httpClient->post(url).bodyWithJson(body);
|
||
if (!m_token.isEmpty()) req.header("Authorization", m_token);
|
||
|
||
req.onSuccess([this, onSuccess, onFailed](const QJsonObject &resp) {
|
||
this->handleResponse(resp, onSuccess, onFailed);
|
||
})
|
||
.onFailed([onFailed](const QString &err) {
|
||
if (onFailed) onFailed(err);
|
||
})
|
||
.exec();
|
||
}
|
||
|
||
void ApiClient::put(const QString &path, const QJsonObject &body, SuccessCB onSuccess, FailedCB onFailed)
|
||
{
|
||
QString url = joinUrl(m_baseUrl, path);
|
||
|
||
auto req = m_httpClient->put(url).bodyWithJson(body);
|
||
if (!m_token.isEmpty()) req.header("Authorization", m_token);
|
||
|
||
req.onSuccess([this, onSuccess, onFailed](const QJsonObject &resp) {
|
||
this->handleResponse(resp, onSuccess, onFailed);
|
||
})
|
||
.onFailed([onFailed](const QString &err) {
|
||
if (onFailed) onFailed(err);
|
||
})
|
||
.exec();
|
||
}
|
||
|
||
void ApiClient::del(const QString &path, SuccessCB onSuccess, FailedCB onFailed)
|
||
{
|
||
QString url = joinUrl(m_baseUrl, path);
|
||
|
||
auto req = m_httpClient->del(url);
|
||
if (!m_token.isEmpty()) req.header("Authorization", m_token);
|
||
|
||
req.onSuccess([this, onSuccess, onFailed](const QJsonObject &resp) {
|
||
this->handleResponse(resp, onSuccess, onFailed);
|
||
})
|
||
.onFailed([onFailed](const QString &err) {
|
||
if (onFailed) onFailed(err);
|
||
})
|
||
.exec();
|
||
}
|