feat(webrtc): 完善前端会话恢复、设备绑定与开发代理配置

- 控制端新增页面刷新后自动恢复登录会话,并展示恢复中状态
- 支持被控端配对码绑定、设备在线状态标记及离线设备禁用连接
- 优化登录流程,支持双因子验证码输入
- 修复 API 客户端令牌刷新逻辑,增加认证失败统一回调
- 信令地址支持环境变量推导,ICE 服务器支持自定义配置
- 管理后台强制开发态走 Vite 代理,避免跨域和 IP 不可达问题
- 修复 tsconfig.node.json 产物干扰 vite 配置加载的构建问题
- 添加 .env.example 作为环境变量配置模板
This commit is contained in:
TongTongStudio
2026-08-03 02:44:52 +08:00
parent e689b999e6
commit e6ed7c8e3e
16 changed files with 465 additions and 116 deletions

View File

@@ -1,5 +1,15 @@
# 管理后台连接的后端信令服务器地址Spring Boot 端口)
# VITE_API_BASE=http://175.178.213.60:8088
# ============================================================
# 管理后台前端配置
# ============================================================
# 【代理目标】Vite dev server 把 /api/** 转发到这里(仅开发态生效,浏览器不直接访问)。
# 后端 Spring Boot 地址,按需改成本机或远程信令服务器。
VITE_API_TARGET=http://localhost:8080
# 【请求基地址】留空表示走相对路径 /api同源经上面的代理转发——推荐保持留空。
# 仅在需要浏览器直连后端、绕过代理时才填绝对地址,例如:
# VITE_API_BASE=http://192.168.5.224:8080
# 注意:填了绝对地址就会产生跨域,且用非该 IP 的地址打开页面时可能连不上。
VITE_API_BASE=http://192.168.5.224:8080
# 默认管理令牌,需与服务器 application.yml 中 admin.token 一致

View File

@@ -2,7 +2,20 @@ import axios from 'axios';
import { ElMessage } from 'element-plus';
import router from '@/router';
const BASE_URL = import.meta.env.VITE_API_BASE || 'http://localhost:8080';
/**
* 请求基地址。
*
* 开发态vite dev强制使用相对路径 '',即请求 /api/**
* 由 Vite dev server 代理转发到后端(见 vite.config.ts 的 server.proxy
* 目标取自 VITE_API_TARGET。这样浏览器侧始终同源从根本上避免
* - 跨域被拦截;
* - .env 里写死的后端 IP如 192.168.5.224)在当前网络/主机下不可达,
* 或用 localhost 打开页面时该 IP 解析不到,浏览器直接抛 "Failed to fetch"。
*
* 生产构建下才使用 VITE_API_BASE若未配置则同样走相对路径
* 由部署侧Nginx 等)反向代理 /api。
*/
const BASE_URL = import.meta.env.DEV ? '' : import.meta.env.VITE_API_BASE || '';
const request = axios.create({
baseURL: BASE_URL,

View File

@@ -7,7 +7,12 @@ declare module '*.vue' {
}
interface ImportMetaEnv {
/** 请求基地址,留空表示走相对路径 /api由 Vite 代理或部署侧反代转发)。 */
readonly VITE_API_BASE: string;
/** Vite dev server 的 /api 代理目标,仅构建工具侧读取。 */
readonly VITE_API_TARGET: string;
/** 默认管理令牌,需与服务端 application.yml 的 admin.token 一致。 */
readonly VITE_ADMIN_TOKEN: string;
}
interface ImportMeta {

View File

@@ -5,7 +5,14 @@
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
"strict": true,
// composite 隐含 declaration会把 vite.config.ts 编译出 vite.config.js / .d.ts。
// 而 Vite 加载配置时 .js 优先级高于 .ts那份陈旧产物会顶掉真正的 vite.config.ts
// (曾导致 server.proxy 失效、接口请求 404 / Failed to fetch
// 这里只做类型检查不产出任何文件tsBuildInfo 也移出源码目录。
"noEmit": true,
"emitDeclarationOnly": false,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
},
"include": ["vite.config.ts"]
}

View File

@@ -1,2 +0,0 @@
declare const _default: import("vite").UserConfig;
export default _default;

View File

@@ -1,15 +0,0 @@
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { fileURLToPath, URL } from 'node:url';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
server: {
host: true,
port: 5180,
},
});

View File

@@ -1,16 +1,35 @@
import { defineConfig } from 'vite';
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import { fileURLToPath, URL } from 'node:url';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
// 开发态一律走 Vite 同源代理:前端只请求相对路径 /api/**
// 由 dev server 转发到 VITE_API_TARGET 指向的后端。
// 这样浏览器侧不存在跨域,也不会因为「访问 dev server 用的主机名/协议」
// 与「后端绝对地址」不一致而出现 Failed to fetch。
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
// 代理目标:优先 VITE_API_TARGET兼容旧的 VITE_API_BASE默认本机后端。
const target = env.VITE_API_TARGET || env.VITE_API_BASE || 'http://localhost:8080';
// 启动时打印,便于确认请求究竟被转发到哪台后端。
console.log(`[vite] /api -> ${target}`);
return {
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
},
server: {
host: true,
port: 5180,
},
server: {
host: true,
port: 5180,
proxy: {
'/api': {
target,
changeOrigin: true,
secure: false,
},
},
},
};
});