feat(controlled, controller): 新增配对码生成与兑换功能

被控端:新增生成一次性配对码并弹窗展示,支持倒计时与复制;控制端:新增输入配对码兑换绑定,刷新设备列表,并在设备列表中显示在线状态和点击连接。同时添加统一 401 拦截器,令牌失效时触发重新激活。
This commit is contained in:
TongTongStudio
2026-08-03 01:57:42 +08:00
parent ded6fe5ab7
commit e689b999e6
29 changed files with 1096 additions and 86 deletions

View File

@@ -2,8 +2,10 @@ 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';
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE || 'http://localhost:8080',
baseURL: BASE_URL,
timeout: 15000,
});
@@ -15,12 +17,34 @@ request.interceptors.request.use((config) => {
return config;
});
/**
* 统一响应拦截:除 401 外所有异常都给出错误提示。
* 401 表示令牌失效/未登录,清除本地令牌并跳转登录页。
*/
request.interceptors.response.use(
(resp) => resp.data,
(error) => {
const status = error.response?.status;
if (status === 401) {
localStorage.removeItem('admin_token');
ElMessage.error('登录已失效,请重新登录');
if (router.currentRoute.value.name !== 'Login') {
router.replace({ name: 'Login' });
}
} else {
ElMessage.error(error.response?.data?.message || error.message || '请求失败');
}
return Promise.reject(error);
},
);
/**
* 不携带任何鉴权头的请求实例,专用于登录等公开接口,
* 避免把本地可能过期/失效的令牌误带上去造成 401 / 鉴权混乱。
* 公开接口的 401 表示账号或密码错误,直接提示,不跳转(已在登录页)。
*/
export const publicRequest = axios.create({
baseURL: import.meta.env.VITE_API_BASE || 'http://localhost:8080',
baseURL: BASE_URL,
timeout: 15000,
});
@@ -29,7 +53,6 @@ publicRequest.interceptors.response.use(
(error) => {
const status = error.response?.status;
if (status === 401) {
localStorage.removeItem('admin_token');
ElMessage.error('登录失败,请检查账号或密码');
} else {
ElMessage.error(error.response?.data?.message || error.message || '请求失败');
@@ -40,19 +63,3 @@ publicRequest.interceptors.response.use(
export default request;
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);
},
);