feat: 增加网页后台管理

This commit is contained in:
2026-07-21 17:46:00 +08:00
parent 1edb87b5f2
commit ef786b1529
42 changed files with 5222 additions and 2 deletions

View File

@@ -0,0 +1,71 @@
import request from './request';
export type DeviceType = 'CONTROLLER' | 'CONTROLLED' | null;
export interface DeviceInfo {
deviceId: string;
deviceType: DeviceType;
online: boolean;
connectedAt: number | null;
}
export interface DashboardData {
serverStartTime: number;
currentTime: number;
uptimeMs: number;
totalDevices: number;
onlineDevices: number;
offlineDevices: number;
onlineControllers: number;
onlineControlled: number;
pendingConnections: number;
metrics: {
totalMessages: number;
totalOffers: number;
totalAnswers: number;
totalRejected: number;
totalRegistered: number;
peakSessions: number;
};
}
export interface PendingConnection {
fromDeviceId: string;
toDeviceId: string;
createdAt: number;
elapsedMs: number;
}
export interface ServerConfig {
dedupWindowMs: number;
requestTimeoutMs: number;
websocketEndpoint: string;
serverPort: number;
}
export function getDashboard(): Promise<DashboardData> {
return request.get('/api/admin/dashboard') as unknown as Promise<DashboardData>;
}
export function getDevices(type?: string): Promise<DeviceInfo[]> {
return request.get('/api/admin/devices', { params: type ? { type } : {} }) as unknown as Promise<
DeviceInfo[]
>;
}
export function getConnections(): Promise<PendingConnection[]> {
return request.get('/api/admin/connections') as unknown as Promise<PendingConnection[]>;
}
export function getConfig(): Promise<ServerConfig> {
return request.get('/api/admin/config') as unknown as Promise<ServerConfig>;
}
export function getHealth(): Promise<{ status: string }> {
return request.get('/api/admin/health') as unknown as Promise<{ status: string }>;
}
/** 校验令牌有效性(用于登录时验证)。 */
export function verifyToken(token: string): Promise<unknown> {
return request.get('/api/admin/health', { headers: { 'X-Admin-Token': token } });
}

View File

@@ -0,0 +1,33 @@
import axios from 'axios';
import { ElMessage } from 'element-plus';
import router from '@/router';
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE || 'http://localhost:8080',
timeout: 15000,
});
request.interceptors.request.use((config) => {
const token = localStorage.getItem('admin_token');
if (token) {
config.headers['X-Admin-Token'] = token;
}
return config;
});
request.interceptors.response.use(
(resp) => resp.data,
(error) => {
const status = error.response?.status;
if (status === 401) {
localStorage.removeItem('admin_token');
ElMessage.error('登录已失效,请重新登录');
router.replace({ name: 'Login' });
} else {
ElMessage.error(error.response?.data?.message || error.message || '请求失败');
}
return Promise.reject(error);
},
);
export default request;