feat(electron-vue-template):重构认证与设备管理模块

- 统一token存取逻辑,封装getToken/setToken/removeToken方法
-优化设备ID获取逻辑,调整API路径
- 完善设备管理接口类型定义,增强类型安全
- 调整SSE连接逻辑,使用统一配置管理- 重构HTTP客户端,集中管理后端服务配置
- 更新认证相关API接口,完善请求/响应类型
- 优化设备列表展示逻辑,移除冗余字段
- 调整图片代理路径,统一API前缀
- 完善用户反馈列表展示功能,增强交互体验
- 移除冗余的错误处理逻辑,简化代码结构
This commit is contained in:
2025-10-16 10:37:00 +08:00
parent 6f04658265
commit 132299c4b7
37 changed files with 2193 additions and 682 deletions

View File

@@ -1,32 +1,31 @@
// 极简 HTTP 工具:封装 GET/POST按路径选择后端服务
export type HttpMethod = 'GET' | 'POST';
// HTTP 工具:统一管理后端服务配置和请求
export type HttpMethod = 'GET' | 'POST' | 'DELETE';
const BASE_CLIENT = 'http://localhost:8081'; // erp_client_sb
const BASE_RUOYI = 'http://192.168.1.89:8085';
// 集中管理所有后端服务配置
export const CONFIG = {
CLIENT_BASE: 'http://localhost:8081',
RUOYI_BASE: 'http://192.168.1.89:8085',
SSE_URL: 'http://192.168.1.89:8085/monitor/account/events'
} as const;
function resolveBase(path: string): string {
// 走 ruoyi-admin 的路径:鉴权、设备管理、版本、平台工具路由
if (path.startsWith('/monitor/account')) return BASE_RUOYI; // 账号认证相关
if (path.startsWith('/monitor/device')) return BASE_RUOYI; // 设备管理
if (path.startsWith('/system/')) return BASE_RUOYI; // 版本控制器 VersionController
if (path.startsWith('/tool/banma')) return BASE_RUOYI; // 既有规则保留
// 其他默认走客户端服务
return BASE_CLIENT;
// RuoYi 后端路径:鉴权、设备、反馈、版本、工具
if (path.startsWith('/monitor/') || path.startsWith('/system/') || path.startsWith('/tool/banma')) {
return CONFIG.RUOYI_BASE;
}
// 其他走客户端服务
return CONFIG.CLIENT_BASE;
}
// 将对象转为查询字符串
function buildQuery(params?: Record<string, unknown>): string {
if (!params) return '';
const usp = new URLSearchParams();
const query = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (value === undefined || value === null) return;
usp.append(key, String(value));
if (value != null) query.append(key, String(value));
});
const queryString = usp.toString();
return queryString ? `?${queryString}` : '';
return query.toString() ? `?${query}` : '';
}
// 统一请求入口:自动加上 BASE_URL、JSON 头与错误处理
async function request<T>(path: string, options: RequestInit): Promise<T> {
const res = await fetch(`${resolveBase(path)}${path}`, {
credentials: 'omit',
@@ -34,22 +33,27 @@ async function request<T>(path: string, options: RequestInit): Promise<T> {
...options,
headers: {
'Content-Type': 'application/json',
...(options.headers || {}),
},
...options.headers
}
});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(text || `HTTP ${res.status}`);
}
const contentType = res.headers.get('content-type') || '';
if (contentType.includes('application/json')) {
const json: any = await res.json();
// 检查业务状态码
// 业务状态码判断:支持两种格式
// - erp_client_sb (本地服务): code=0 表示成功
// - RuoYi 后端: code=200 表示成功
if (json.code !== undefined && json.code !== 0 && json.code !== 200) {
throw new Error(json.msg || json.message || '请求失败');
throw new Error(json.msg || '请求失败');
}
return json as T;
}
return (await res.text()) as unknown as T;
}
@@ -58,40 +62,38 @@ export const http = {
return request<T>(`${path}${buildQuery(params)}`, { method: 'GET' });
},
post<T>(path: string, body?: unknown) {
return request<T>(path, { method: 'POST', body: body ? JSON.stringify(body) : undefined });
return request<T>(path, {
method: 'POST',
body: body ? JSON.stringify(body) : undefined
});
},
delete<T>(path: string) {
return request<T>(path, { method: 'DELETE' });
},
// 用于无需读取响应体的 POST如删除/心跳等),从根源避免读取中断
postVoid(path: string, body?: unknown) {
return fetch(`${resolveBase(path)}${path}`, {
method: 'POST',
body: body ? JSON.stringify(body) : undefined,
credentials: 'omit',
cache: 'no-store',
headers: { 'Content-Type': 'application/json' },
}).then(res => {
if (!res.ok) return res.text().then(t => Promise.reject(new Error(t || `HTTP ${res.status}`)));
return undefined as unknown as void;
});
},
// 文件上传:透传 FormData不设置 Content-Type 让浏览器自动处理
upload<T>(path: string, form: FormData) {
const res = fetch(`${resolveBase(path)}${path}`, {
return fetch(`${resolveBase(path)}${path}`, {
method: 'POST',
body: form,
credentials: 'omit',
cache: 'no-store',
});
return res.then(async response => {
if (!response.ok) {
const text = await response.text().catch(() => '');
throw new Error(text || `HTTP ${response.status}`);
cache: 'no-store'
}).then(async res => {
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(text || `HTTP ${res.status}`);
}
return response.json() as Promise<T>;
const contentType = res.headers.get('content-type') || '';
if (contentType.includes('application/json')) {
const json: any = await res.json();
if (json.code !== undefined && json.code !== 0 && json.code !== 200) {
throw new Error(json.msg || '请求失败');
}
return json as T;
}
return (await res.text()) as unknown as T;
});
},
}
};