1
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
@import "https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap";:root{--font-sans:"Outfit", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--nav-bg:#08080c;--nav-surface:#ffffff0a;--nav-border:#ffffff0f;--nav-text:#e8e8ec;--nav-text-muted:#8b8fa3;--nav-hover:#ffffff14;--nav-active:#ffffff1f}*,:before,:after{box-sizing:border-box}html,body{font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#1a1a2e;letter-spacing:-.01em;background:#f8f9fc;margin:0;padding:0}#root{min-height:100vh}
|
||||||
Vendored
+103
-103
File diff suppressed because one or more lines are too long
Vendored
+6
-2
@@ -4,8 +4,12 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>VideoGen.AI 管理后台</title>
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<script type="module" crossorigin src="/assets/index-C93H_elA.js"></script>
|
<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-ECGzn5Wr.js"></script>
|
||||||
|
<link rel="stylesheet" crossorigin href="/assets/index-D7ShJUt4.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -8,6 +8,26 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<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" />
|
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
|
||||||
<title>后台管理</title>
|
<title>后台管理</title>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var cached = localStorage.getItem('siteInfo');
|
||||||
|
if (cached) {
|
||||||
|
try {
|
||||||
|
var info = JSON.parse(cached);
|
||||||
|
if (info.siteName) {
|
||||||
|
document.title = info.siteName + ' - 管理后台';
|
||||||
|
}
|
||||||
|
if (info.siteLogo) {
|
||||||
|
var link = document.querySelector('link[rel="icon"]');
|
||||||
|
if (link) {
|
||||||
|
link.href = info.siteLogo;
|
||||||
|
link.type = 'image/png';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -315,6 +315,10 @@ export async function adminChangePassword(oldPwd: string, newPwd: string): Promi
|
|||||||
await api.post('/admin/change-password', { old_password: oldPwd, new_password: newPwd });
|
await api.post('/admin/change-password', { old_password: oldPwd, new_password: newPwd });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getSiteInfo(): Promise<{ siteName: string; siteLogo: string; userAgreementUrl: string; privacyPolicyUrl: string }> {
|
||||||
|
return api.get('/auth/site-info', false);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Recharge Packages ───────────────────────────────────
|
// ── Recharge Packages ───────────────────────────────────
|
||||||
|
|
||||||
export async function getRechargePackages(): Promise<any[]> {
|
export async function getRechargePackages(): Promise<any[]> {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Outlet, useNavigate, useLocation, Navigate } from 'react-router-dom';
|
import { Outlet, useNavigate, useLocation, Navigate } from 'react-router-dom';
|
||||||
import { useAdminStore } from '../store';
|
import { useAdminStore } from '../store';
|
||||||
import { getMenuConfigs, adminChangePassword } from '../api';
|
import { getMenuConfigs, adminChangePassword, getSiteInfo } from '../api';
|
||||||
|
|
||||||
const { Sider, Content } = Layout;
|
const { Sider, Content } = Layout;
|
||||||
|
|
||||||
@@ -53,6 +53,35 @@ const AdminLayout: React.FC = () => {
|
|||||||
const [menuItems, setMenuItems] = useState<any[]>([]);
|
const [menuItems, setMenuItems] = useState<any[]>([]);
|
||||||
const [pwdModal, setPwdModal] = useState(false);
|
const [pwdModal, setPwdModal] = useState(false);
|
||||||
const [pwdForm] = Form.useForm();
|
const [pwdForm] = Form.useForm();
|
||||||
|
const [siteName, setSiteName] = useState(() => {
|
||||||
|
const cached = localStorage.getItem('siteInfo');
|
||||||
|
return cached ? JSON.parse(cached).siteName || '管理后台' : '管理后台';
|
||||||
|
});
|
||||||
|
const [siteLogo, setSiteLogo] = useState(() => {
|
||||||
|
const cached = localStorage.getItem('siteInfo');
|
||||||
|
return cached ? JSON.parse(cached).siteLogo || '' : '';
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getSiteInfo().then(info => {
|
||||||
|
const name = info.siteName || '管理后台';
|
||||||
|
const logo = info.siteLogo || '';
|
||||||
|
setSiteName(name);
|
||||||
|
setSiteLogo(logo);
|
||||||
|
document.title = name;
|
||||||
|
localStorage.setItem('siteInfo', JSON.stringify({ siteName: name, siteLogo: logo }));
|
||||||
|
if (logo) {
|
||||||
|
let faviconLink = document.querySelector('link[rel="icon"]') as HTMLLinkElement;
|
||||||
|
if (!faviconLink) {
|
||||||
|
faviconLink = document.createElement('link');
|
||||||
|
faviconLink.rel = 'icon';
|
||||||
|
document.head.appendChild(faviconLink);
|
||||||
|
}
|
||||||
|
faviconLink.href = logo;
|
||||||
|
faviconLink.type = 'image/png';
|
||||||
|
}
|
||||||
|
}).catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getMenuConfigs().then(data => {
|
getMenuConfigs().then(data => {
|
||||||
@@ -198,12 +227,17 @@ const AdminLayout: React.FC = () => {
|
|||||||
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
|
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
|
||||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||||
boxShadow: '0 2px 8px rgba(99,102,241,0.3)',
|
boxShadow: '0 2px 8px rgba(99,102,241,0.3)',
|
||||||
|
overflow: 'hidden',
|
||||||
}}>
|
}}>
|
||||||
<ThunderboltOutlined style={{ fontSize: 16, color: '#fff' }} />
|
{siteLogo ? (
|
||||||
|
<img src={siteLogo} alt="logo" style={{ width: 24, height: 24, objectFit: 'contain' }} />
|
||||||
|
) : (
|
||||||
|
<ThunderboltOutlined style={{ fontSize: 16, color: '#fff' }} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
<span style={{ color: '#1f2937', fontSize: 15, fontWeight: 600, letterSpacing: -0.02 }}>
|
<span style={{ color: '#1f2937', fontSize: 15, fontWeight: 600, letterSpacing: -0.02 }}>
|
||||||
管理后台
|
{siteName}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -218,12 +252,12 @@ const AdminLayout: React.FC = () => {
|
|||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
paddingTop: 8,
|
paddingTop: 8,
|
||||||
|
marginTop: 8,
|
||||||
}}
|
}}
|
||||||
onClick={({ key }) => {
|
onClick={({ key }) => {
|
||||||
if (key.startsWith('group-')) return;
|
if (key.startsWith('group-')) return;
|
||||||
navigate(key);
|
navigate(key);
|
||||||
}}
|
}}
|
||||||
style={{ background: 'transparent', borderRight: 0, marginTop: 8 }}
|
|
||||||
theme="light"
|
theme="light"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
@@ -8,6 +8,26 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<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" />
|
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
|
||||||
<title>民众智创</title>
|
<title>民众智创</title>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var cached = localStorage.getItem('siteInfo');
|
||||||
|
if (cached) {
|
||||||
|
try {
|
||||||
|
var info = JSON.parse(cached);
|
||||||
|
if (info.siteName) {
|
||||||
|
document.title = info.siteName;
|
||||||
|
}
|
||||||
|
if (info.siteLogo) {
|
||||||
|
var link = document.querySelector('link[rel="icon"]');
|
||||||
|
if (link) {
|
||||||
|
link.href = info.siteLogo;
|
||||||
|
link.type = 'image/png';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -141,11 +141,24 @@ const AppLayout: React.FC = () => {
|
|||||||
const [unreadCount, setUnreadCount] = useState(0);
|
const [unreadCount, setUnreadCount] = useState(0);
|
||||||
const [siteName, setSiteName] = useState(() => {
|
const [siteName, setSiteName] = useState(() => {
|
||||||
const cached = localStorage.getItem('siteInfo');
|
const cached = localStorage.getItem('siteInfo');
|
||||||
return cached ? JSON.parse(cached).siteName || '' : '';
|
const name = cached ? JSON.parse(cached).siteName || '' : '';
|
||||||
|
if (name) document.title = name;
|
||||||
|
return name;
|
||||||
});
|
});
|
||||||
const [siteLogo, setSiteLogo] = useState(() => {
|
const [siteLogo, setSiteLogo] = useState(() => {
|
||||||
const cached = localStorage.getItem('siteInfo');
|
const cached = localStorage.getItem('siteInfo');
|
||||||
return cached ? JSON.parse(cached).siteLogo || '' : '';
|
const logo = cached ? JSON.parse(cached).siteLogo || '' : '';
|
||||||
|
if (logo) {
|
||||||
|
let faviconLink = document.querySelector('link[rel="icon"]') as HTMLLinkElement;
|
||||||
|
if (!faviconLink) {
|
||||||
|
faviconLink = document.createElement('link');
|
||||||
|
faviconLink.rel = 'icon';
|
||||||
|
document.head.appendChild(faviconLink);
|
||||||
|
}
|
||||||
|
faviconLink.href = logo;
|
||||||
|
faviconLink.type = 'image/png';
|
||||||
|
}
|
||||||
|
return logo;
|
||||||
});
|
});
|
||||||
const [siteInfoLoading, setSiteInfoLoading] = useState(!localStorage.getItem('siteInfo'));
|
const [siteInfoLoading, setSiteInfoLoading] = useState(!localStorage.getItem('siteInfo'));
|
||||||
const [qrCodeModalOpen, setQrCodeModalOpen] = useState(false);
|
const [qrCodeModalOpen, setQrCodeModalOpen] = useState(false);
|
||||||
@@ -171,29 +184,29 @@ const AppLayout: React.FC = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const cached = localStorage.getItem('siteInfo');
|
|
||||||
if (!cached) {
|
|
||||||
setSiteName('民众智创');
|
|
||||||
setSiteLogo('');
|
|
||||||
document.title = '民众智创';
|
|
||||||
}
|
|
||||||
|
|
||||||
getSiteInfo().then(info => {
|
getSiteInfo().then(info => {
|
||||||
const siteName = info.siteName || '民众智创';
|
const name = info.siteName || '民众智创';
|
||||||
const siteLogo = info.siteLogo || '';
|
const logo = info.siteLogo || '';
|
||||||
setSiteName(siteName);
|
|
||||||
setSiteLogo(siteLogo);
|
if (name !== siteName) {
|
||||||
document.title = siteName;
|
setSiteName(name);
|
||||||
localStorage.setItem('siteInfo', JSON.stringify({ siteName, siteLogo }));
|
document.title = name;
|
||||||
}).catch(() => {
|
|
||||||
// 如果没有缓存且请求失败,使用默认值
|
|
||||||
if (!cached) {
|
|
||||||
setSiteName('民众智创');
|
|
||||||
document.title = '民众智创';
|
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
|
||||||
setSiteInfoLoading(false);
|
if (logo && logo !== siteLogo) {
|
||||||
});
|
setSiteLogo(logo);
|
||||||
|
let faviconLink = document.querySelector('link[rel="icon"]') as HTMLLinkElement;
|
||||||
|
if (!faviconLink) {
|
||||||
|
faviconLink = document.createElement('link');
|
||||||
|
faviconLink.rel = 'icon';
|
||||||
|
document.head.appendChild(faviconLink);
|
||||||
|
}
|
||||||
|
faviconLink.href = logo;
|
||||||
|
faviconLink.type = 'image/png';
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem('siteInfo', JSON.stringify({ siteName: name, siteLogo: logo }));
|
||||||
|
}).catch(() => {});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadUnreadCount = () => {
|
const loadUnreadCount = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user