mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-02 19:00:49 +08:00
feat(versioning): implement UI and server version tracking with build date display in footer
This commit is contained in:
4
app.js
4
app.js
@@ -42,6 +42,9 @@ class CLIProxyManager {
|
||||
this.managementKey = '';
|
||||
this.isConnected = false;
|
||||
this.isLoggedIn = false;
|
||||
this.uiVersion = null;
|
||||
this.serverVersion = null;
|
||||
this.serverBuildDate = null;
|
||||
|
||||
// 配置缓存 - 改为分段缓存
|
||||
this.configCache = {}; // 改为对象,按配置段缓存
|
||||
@@ -129,6 +132,7 @@ class CLIProxyManager {
|
||||
}
|
||||
|
||||
init() {
|
||||
this.initUiVersion();
|
||||
this.initializeTheme();
|
||||
this.checkLoginStatus();
|
||||
this.bindEvents();
|
||||
|
||||
8
i18n.js
8
i18n.js
@@ -508,7 +508,9 @@ const i18n = {
|
||||
'sidebar.toggle_collapse': '收起侧边栏',
|
||||
|
||||
// 页脚
|
||||
'footer.version': '版本',
|
||||
'footer.api_version': 'CLI Proxy API 版本',
|
||||
'footer.build_date': '构建时间',
|
||||
'footer.version': '管理中心版本',
|
||||
'footer.author': '作者'
|
||||
},
|
||||
|
||||
@@ -1013,7 +1015,9 @@ const i18n = {
|
||||
'sidebar.toggle_collapse': 'Collapse sidebar',
|
||||
|
||||
// Footer
|
||||
'footer.version': 'Version',
|
||||
'footer.api_version': 'CLI Proxy API Version',
|
||||
'footer.build_date': 'Build Time',
|
||||
'footer.version': 'Management UI Version',
|
||||
'footer.author': 'Author'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1003,7 +1003,14 @@
|
||||
<!-- 版本信息 -->
|
||||
<footer class="version-footer">
|
||||
<div class="version-info">
|
||||
<span data-i18n="footer.version">版本</span>: __VERSION__
|
||||
<span data-i18n="footer.api_version">CLI Proxy API 版本</span>:
|
||||
<span id="api-version">-</span>
|
||||
<span class="separator">•</span>
|
||||
<span data-i18n="footer.build_date">构建时间</span>:
|
||||
<span id="api-build-date">-</span>
|
||||
<span class="separator">•</span>
|
||||
<span data-i18n="footer.version">管理中心版本</span>:
|
||||
<span id="ui-version" data-ui-version="__VERSION__">-</span>
|
||||
<span class="separator">•</span>
|
||||
<span data-i18n="footer.author">作者</span>: CLI Proxy API Team
|
||||
</div>
|
||||
|
||||
@@ -58,6 +58,95 @@ export const connectionModule = {
|
||||
this.updateLoginConnectionInfo();
|
||||
},
|
||||
|
||||
// 读取并填充管理中心版本号(可能来自构建时注入或占位符)
|
||||
initUiVersion() {
|
||||
const uiVersion = this.readUiVersionFromDom();
|
||||
this.uiVersion = uiVersion;
|
||||
this.renderVersionInfo();
|
||||
},
|
||||
|
||||
// 从 DOM 获取版本占位符,并处理空值、引号或未替换的占位符
|
||||
readUiVersionFromDom() {
|
||||
const el = document.getElementById('ui-version');
|
||||
if (!el) return null;
|
||||
|
||||
const raw = (el.dataset && el.dataset.uiVersion) ? el.dataset.uiVersion : el.textContent;
|
||||
if (typeof raw !== 'string') return null;
|
||||
|
||||
const cleaned = raw.replace(/^"+|"+$/g, '').trim();
|
||||
if (!cleaned || cleaned === '__VERSION__') {
|
||||
return null;
|
||||
}
|
||||
return cleaned;
|
||||
},
|
||||
|
||||
// 根据响应头更新版本与构建时间
|
||||
updateVersionFromHeaders(headers) {
|
||||
if (!headers || typeof headers.get !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
const version = headers.get('X-CPA-VERSION');
|
||||
const buildDate = headers.get('X-CPA-BUILD-DATE');
|
||||
let updated = false;
|
||||
|
||||
if (version && version !== this.serverVersion) {
|
||||
this.serverVersion = version;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (buildDate && buildDate !== this.serverBuildDate) {
|
||||
this.serverBuildDate = buildDate;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
this.renderVersionInfo();
|
||||
}
|
||||
},
|
||||
|
||||
// 渲染底栏的版本与构建时间
|
||||
renderVersionInfo() {
|
||||
const versionEl = document.getElementById('api-version');
|
||||
const buildDateEl = document.getElementById('api-build-date');
|
||||
const uiVersionEl = document.getElementById('ui-version');
|
||||
|
||||
if (versionEl) {
|
||||
versionEl.textContent = this.serverVersion || '-';
|
||||
}
|
||||
|
||||
if (buildDateEl) {
|
||||
buildDateEl.textContent = this.serverBuildDate
|
||||
? this.formatBuildDate(this.serverBuildDate)
|
||||
: '-';
|
||||
}
|
||||
|
||||
if (uiVersionEl) {
|
||||
const domVersion = this.readUiVersionFromDom();
|
||||
uiVersionEl.textContent = this.uiVersion || domVersion || 'v0.0.0-dev';
|
||||
}
|
||||
},
|
||||
|
||||
// 清空版本信息(例如登出时)
|
||||
resetVersionInfo() {
|
||||
this.serverVersion = null;
|
||||
this.serverBuildDate = null;
|
||||
this.renderVersionInfo();
|
||||
},
|
||||
|
||||
// 格式化构建时间,优先使用界面语言对应的本地格式
|
||||
formatBuildDate(buildDate) {
|
||||
if (!buildDate) return '-';
|
||||
|
||||
const parsed = Date.parse(buildDate);
|
||||
if (!Number.isNaN(parsed)) {
|
||||
const locale = i18n?.currentLanguage || undefined;
|
||||
return new Date(parsed).toLocaleString(locale);
|
||||
}
|
||||
|
||||
return buildDate;
|
||||
},
|
||||
|
||||
// API 请求方法
|
||||
async makeRequest(endpoint, options = {}) {
|
||||
const url = `${this.apiUrl}${endpoint}`;
|
||||
@@ -73,6 +162,8 @@ export const connectionModule = {
|
||||
headers
|
||||
});
|
||||
|
||||
this.updateVersionFromHeaders(response.headers);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.error || `HTTP ${response.status}`);
|
||||
|
||||
@@ -732,6 +732,8 @@ export const authFilesModule = {
|
||||
body: formData
|
||||
});
|
||||
|
||||
this.updateVersionFromHeaders(response.headers);
|
||||
|
||||
if (!response.ok) {
|
||||
let errorMessage = `HTTP ${response.status}`;
|
||||
try {
|
||||
@@ -891,6 +893,8 @@ export const authFilesModule = {
|
||||
}
|
||||
});
|
||||
|
||||
this.updateVersionFromHeaders(response.headers);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
@@ -1029,6 +1033,8 @@ export const authFilesModule = {
|
||||
body: formData
|
||||
});
|
||||
|
||||
this.updateVersionFromHeaders(response.headers);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.error || `HTTP ${response.status}`);
|
||||
|
||||
@@ -160,6 +160,8 @@ export const configEditorModule = {
|
||||
}
|
||||
});
|
||||
|
||||
this.updateVersionFromHeaders(response.headers);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text().catch(() => '');
|
||||
const message = errorText || `HTTP ${response.status}`;
|
||||
@@ -235,6 +237,8 @@ export const configEditorModule = {
|
||||
body: yamlText
|
||||
});
|
||||
|
||||
this.updateVersionFromHeaders(response.headers);
|
||||
|
||||
if (!response.ok) {
|
||||
const contentType = response.headers.get('content-type') || '';
|
||||
let errorText = '';
|
||||
|
||||
@@ -100,6 +100,7 @@ export const loginModule = {
|
||||
this.isConnected = false;
|
||||
this.clearCache();
|
||||
this.stopStatusUpdateTimer();
|
||||
this.resetVersionInfo();
|
||||
|
||||
localStorage.removeItem('isLoggedIn');
|
||||
secureStorage.removeItem('managementKey');
|
||||
|
||||
Reference in New Issue
Block a user