This commit is contained in:
sjy
2026-08-13 17:57:38 +08:00
39 changed files with 2397 additions and 364 deletions
File diff suppressed because one or more lines are too long
+35 -35
View File
@@ -1,36 +1,36 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" id="favicon" />
<script>
// 立即从 localStorage 设置 favicon,避免闪烁
(function() {
try {
var cached = localStorage.getItem('siteInfo');
if (cached) {
var info = JSON.parse(cached);
if (info.siteLogo) {
var link = document.getElementById('favicon');
link.href = info.siteLogo;
link.type = 'image/png';
}
if (info.siteName) {
document.title = info.siteName;
}
}
} catch (e) {}
})();
</script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<title>民众智创</title>
<script type="module" crossorigin src="/assets/index-CGl8RZCw.js"></script>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" id="favicon" />
<script>
// 立即从 localStorage 设置 favicon,避免闪烁
(function() {
try {
var cached = localStorage.getItem('siteInfo');
if (cached) {
var info = JSON.parse(cached);
if (info.siteLogo) {
var link = document.getElementById('favicon');
link.href = info.siteLogo;
link.type = 'image/png';
}
if (info.siteName) {
document.title = info.siteName;
}
}
} catch (e) {}
})();
</script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<title>民众智创</title>
<script type="module" crossorigin src="/assets/index-8FIfOCqA.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DSYnuUvx.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
</head>
<body>
<div id="root"></div>
</body>
</html>
+1
View File
@@ -117,6 +117,7 @@ if (!res.ok) {
// 检测"被踢出"错误 — 单设备登录互斥
if (res.status === 401 && typeof parsed?.detail === 'string' && parsed.detail.includes('其他设备登录')) {
window.dispatchEvent(new CustomEvent('kicked-out', { detail: { message: parsed.detail } }));
throw new Error(parsed.detail); // 阻止后续自动跳转,由通知按钮处理
}
if (res.status === 401 && !options.skipAuthRedirect) {
clearToken();
@@ -65,7 +65,6 @@ import { getMenuConfigs, getCreditProductCatalog, getPaymentMethods, createRecha
import type { CreditProduct, CreditProductCatalog } from '../../types';
import NotificationPopup from '../NotificationPopup';
import ActivityBanner from './ActivityBanner';
import KickedOutModal from '../KickedOutModal';
import './AppLayout.css';
@@ -530,7 +529,6 @@ const AppLayout: React.FC = () => {
});
const [siteInfoLoading, setSiteInfoLoading] = useState(!localStorage.getItem('siteInfo'));
const [bannerVisible, setBannerVisible] = useState(false);
const [kickedOutVisible, setKickedOutVisible] = useState(false);
// 资源存储容量(从 getUser().resource_capacity 获取)
const [resourceCapacity, setResourceCapacity] = useState<{
@@ -546,12 +544,15 @@ const AppLayout: React.FC = () => {
const [isMobile, setIsMobile] = useState(false);
const [operationManualUrl, setOperationManualUrl] = useState('');
// 监听"被踢出"事件 — 单设备登录互斥
// 监听"被踢出"事件 — 单设备登录互斥,跳转登录页并带上标识
useEffect(() => {
const handler = () => setKickedOutVisible(true);
window.addEventListener('kicked-out', handler);
return () => window.removeEventListener('kicked-out', handler);
}, []);
const handleKickedOut = () => {
localStorage.removeItem('token');
navigate('/login?kicked_out=1');
};
window.addEventListener('kicked-out', handleKickedOut);
return () => window.removeEventListener('kicked-out', handleKickedOut);
}, [navigate]);
useEffect(() => {
getSiteInfo().then(info => {
@@ -1123,7 +1124,6 @@ const AppLayout: React.FC = () => {
overflow: 'hidden',
}}>
<ActivityBanner onVisibilityChange={(v) => setBannerVisible(v)} />
<KickedOutModal visible={kickedOutVisible} />
<div style={{ display: 'flex', position: 'relative', padding: 4, gap: 12, flex: 1, minHeight: 0, overflow: 'hidden' }}>
<div className="desktop-sidebar" style={{
width: sidebarW, position: 'sticky', top: 4, alignSelf: 'flex-start', zIndex: 100,
+11
View File
@@ -74,6 +74,17 @@ const LoginPage: React.FC = () => {
}
}, [tabParam]);
// 单设备登录互斥 — 被踢出后显示提示
useEffect(() => {
if (searchParams.get('kicked_out') === '1') {
message.warning('您的账号已在其他设备登录,请重新登录');
// 清除参数,避免刷新重复提示
const url = new URL(window.location.href);
url.searchParams.delete('kicked_out');
window.history.replaceState({}, '', url.toString());
}
}, [searchParams]);
const goToRedirect = () => {
if (redirect) {
try {