mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-03-16 16:07:07 +08:00
feat: 完善架构优化性能
- 调整音视频架构,提升 RKMPP 编码 MJPEG-->H264 性能,同时解决丢帧马赛克问题; - 删除多用户逻辑,只保留单用户,支持设置 web 单会话; - 修复删除体验不好的的回退逻辑,前端页面菜单位置微调; - 增加 OTG USB 设备动态调整功能; - 修复 mdns 问题,webrtc 视频切换更顺畅。
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
|
||||
import type {
|
||||
AppConfig,
|
||||
AuthConfig,
|
||||
AuthConfigUpdate,
|
||||
VideoConfig,
|
||||
VideoConfigUpdate,
|
||||
StreamConfigResponse,
|
||||
@@ -41,6 +43,24 @@ export const configApi = {
|
||||
getAll: () => request<AppConfig>('/config'),
|
||||
}
|
||||
|
||||
// ===== Auth 配置 API =====
|
||||
export const authConfigApi = {
|
||||
/**
|
||||
* 获取认证配置
|
||||
*/
|
||||
get: () => request<AuthConfig>('/config/auth'),
|
||||
|
||||
/**
|
||||
* 更新认证配置
|
||||
* @param config 要更新的字段
|
||||
*/
|
||||
update: (config: AuthConfigUpdate) =>
|
||||
request<AuthConfig>('/config/auth', {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(config),
|
||||
}),
|
||||
}
|
||||
|
||||
// ===== Video 配置 API =====
|
||||
export const videoConfigApi = {
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,18 @@ export const authApi = {
|
||||
|
||||
check: () =>
|
||||
request<{ authenticated: boolean; user?: string; is_admin?: boolean }>('/auth/check'),
|
||||
|
||||
changePassword: (currentPassword: string, newPassword: string) =>
|
||||
request<{ success: boolean }>('/auth/password', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ current_password: currentPassword, new_password: newPassword }),
|
||||
}),
|
||||
|
||||
changeUsername: (username: string, currentPassword: string) =>
|
||||
request<{ success: boolean }>('/auth/username', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, current_password: currentPassword }),
|
||||
}),
|
||||
}
|
||||
|
||||
// System API
|
||||
@@ -121,8 +133,6 @@ export const streamApi = {
|
||||
clients: number
|
||||
target_fps: number
|
||||
fps: number
|
||||
frames_captured: number
|
||||
frames_dropped: number
|
||||
}>('/stream/status'),
|
||||
|
||||
start: () =>
|
||||
@@ -200,7 +210,7 @@ export const webrtcApi = {
|
||||
}),
|
||||
|
||||
getIceServers: () =>
|
||||
request<{ ice_servers: IceServerConfig[] }>('/webrtc/ice-servers'),
|
||||
request<{ ice_servers: IceServerConfig[]; mdns_mode: string }>('/webrtc/ice-servers'),
|
||||
}
|
||||
|
||||
// HID API
|
||||
@@ -516,6 +526,7 @@ export const configApi = {
|
||||
|
||||
// 导出新的域分离配置 API
|
||||
export {
|
||||
authConfigApi,
|
||||
videoConfigApi,
|
||||
streamConfigApi,
|
||||
hidConfigApi,
|
||||
@@ -535,6 +546,8 @@ export {
|
||||
// 导出生成的类型
|
||||
export type {
|
||||
AppConfig,
|
||||
AuthConfig,
|
||||
AuthConfigUpdate,
|
||||
VideoConfig,
|
||||
VideoConfigUpdate,
|
||||
StreamConfig,
|
||||
@@ -588,53 +601,4 @@ export const audioApi = {
|
||||
}),
|
||||
}
|
||||
|
||||
// User Management API
|
||||
export interface User {
|
||||
id: string
|
||||
username: string
|
||||
role: 'admin' | 'user'
|
||||
created_at: string
|
||||
}
|
||||
|
||||
interface UserApiResponse {
|
||||
id: string
|
||||
username: string
|
||||
is_admin: boolean
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export const userApi = {
|
||||
list: async () => {
|
||||
const rawUsers = await request<UserApiResponse[]>('/users')
|
||||
const users: User[] = rawUsers.map(u => ({
|
||||
id: u.id,
|
||||
username: u.username,
|
||||
role: u.is_admin ? 'admin' : 'user',
|
||||
created_at: u.created_at,
|
||||
}))
|
||||
return { success: true, users }
|
||||
},
|
||||
|
||||
create: (username: string, password: string, role: 'admin' | 'user' = 'user') =>
|
||||
request<UserApiResponse>('/users', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, password, is_admin: role === 'admin' }),
|
||||
}),
|
||||
|
||||
update: (id: string, data: { username?: string; role?: 'admin' | 'user' }) =>
|
||||
request<{ success: boolean }>(`/users/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ username: data.username, is_admin: data.role === 'admin' }),
|
||||
}),
|
||||
|
||||
delete: (id: string) =>
|
||||
request<{ success: boolean }>(`/users/${id}`, { method: 'DELETE' }),
|
||||
|
||||
changePassword: (id: string, newPassword: string, currentPassword?: string) =>
|
||||
request<{ success: boolean }>(`/users/${id}/password`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ new_password: newPassword, current_password: currentPassword }),
|
||||
}),
|
||||
}
|
||||
|
||||
export { ApiError }
|
||||
|
||||
@@ -6,6 +6,7 @@ const API_BASE = '/api'
|
||||
// Toast debounce mechanism - prevent toast spam (5 seconds)
|
||||
const toastDebounceMap = new Map<string, number>()
|
||||
const TOAST_DEBOUNCE_TIME = 5000
|
||||
let sessionExpiredNotified = false
|
||||
|
||||
function shouldShowToast(key: string): boolean {
|
||||
const now = Date.now()
|
||||
@@ -81,7 +82,26 @@ export async function request<T>(
|
||||
// Handle HTTP errors (in case backend returns non-2xx)
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(data, `HTTP ${response.status}`)
|
||||
if (toastOnError && shouldShowToast(toastKey)) {
|
||||
const normalized = message.toLowerCase()
|
||||
const isNotAuthenticated = normalized.includes('not authenticated')
|
||||
if (response.status === 401 && !sessionExpiredNotified) {
|
||||
const isLoggedInElsewhere = normalized.includes('logged in elsewhere')
|
||||
const isSessionExpired = normalized.includes('session expired')
|
||||
if (isLoggedInElsewhere || isSessionExpired) {
|
||||
sessionExpiredNotified = true
|
||||
const titleKey = isLoggedInElsewhere ? 'auth.loggedInElsewhere' : 'auth.sessionExpired'
|
||||
if (toastOnError && shouldShowToast('error_session_expired')) {
|
||||
toast.error(t(titleKey), {
|
||||
description: message,
|
||||
duration: 3000,
|
||||
})
|
||||
}
|
||||
setTimeout(() => {
|
||||
window.location.reload()
|
||||
}, 1200)
|
||||
}
|
||||
}
|
||||
if (toastOnError && shouldShowToast(toastKey) && !(response.status === 401 && isNotAuthenticated)) {
|
||||
toast.error(t('api.operationFailed'), {
|
||||
description: message,
|
||||
duration: 4000,
|
||||
@@ -130,4 +150,3 @@ export async function request<T>(
|
||||
throw new ApiError(0, t('api.networkError'))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user