feat: light theme, frontend link, nav fix, rename to 七虎AI
This commit is contained in:
1 parent
effef176e2
commit
e38a32e04e
12 files changed
+429
-345
No files matched your search
@@ -312,7 +312,7 @@ const SiteSettings: React.FC = () => {
|
||||
<FormGroup label="网站名称" required>
|
||||
<input className="admin-form-input" value={brand.siteName}
|
||||
onChange={e => setBrand({ ...brand, siteName: e.target.value })}
|
||||
placeholder="例如: Qihu-AIFlow" />
|
||||
placeholder="例如: 七虎AI" />
|
||||
</FormGroup>
|
||||
<FormGroup label="LOGO URL">
|
||||
<input className="admin-form-input" value={brand.logo}
|
||||
@@ -638,7 +638,7 @@ const SiteSettings: React.FC = () => {
|
||||
value={registration.welcome_message}
|
||||
onChange={e => setRegistration({ ...registration, welcome_message: e.target.value })}
|
||||
style={{ minHeight: 80 }}
|
||||
placeholder="欢迎加入 Qihu-AIFlow!从这里开始你的 AI 创造之旅..." />
|
||||
placeholder="欢迎加入七虎AI!从这里开始你的 AI 创造之旅..." />
|
||||
</FormGroup>
|
||||
|
||||
<FormActions>
|
||||
|
||||
@@ -407,7 +407,7 @@ const TimelinePanel: React.FC<{
|
||||
pdf.text('我的AI进化时间线', 10, 15);
|
||||
pdf.setFontSize(10);
|
||||
pdf.text(`生成日期: ${dateStr}`, 10, 22);
|
||||
pdf.text('Qihu-AIFlow', pageWidth - 10, 22, { align: 'right' });
|
||||
pdf.text('七虎AI', pageWidth - 10, 22, { align: 'right' });
|
||||
|
||||
// 单页添加图片,自动缩放适应
|
||||
const maxHeight = pageHeight - 35;
|
||||
@@ -417,7 +417,7 @@ const TimelinePanel: React.FC<{
|
||||
// 底部水印
|
||||
pdf.setFontSize(8);
|
||||
pdf.setTextColor(200, 200, 200);
|
||||
pdf.text('Qihu-AIFlow', pageWidth / 2, pageHeight - 5, { align: 'center' });
|
||||
pdf.text('七虎AI', pageWidth / 2, pageHeight - 5, { align: 'center' });
|
||||
|
||||
pdf.save(`${filename}.pdf`);
|
||||
setExportMsg(`时间线已导出为 PDF: ${filename}.pdf`);
|
||||
@@ -746,7 +746,7 @@ const ProfilePanel: React.FC<{ profile: EvolutionProfile; skills: EvolutionSkill
|
||||
{/* Footer */}
|
||||
<div className="evo-share-card-footer">
|
||||
<span style={{ opacity: 0.5, fontSize: '11px' }}>{new Date().toLocaleDateString()}</span>
|
||||
<span style={{ opacity: 0.5, fontSize: '11px' }}>Qihu-AIFlow</span>
|
||||
<span style={{ opacity: 0.5, fontSize: '11px' }}>七虎AI</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,27 +10,27 @@
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* === Dark Theme Variables (scoped to landing page) === */
|
||||
/* === Light Theme Variables (scoped to landing page) === */
|
||||
.landing-page-v2 {
|
||||
--lp-bg: #0A0E1A;
|
||||
--lp-bg-secondary: #111627;
|
||||
--lp-bg-card: #161B2E;
|
||||
--lp-bg-card-hover: #1C2240;
|
||||
--lp-bg-glass: rgba(22, 27, 46, 0.7);
|
||||
--lp-border: rgba(255, 255, 255, 0.06);
|
||||
--lp-border-light: rgba(255, 255, 255, 0.04);
|
||||
--lp-text: #E8ECF4;
|
||||
--lp-text-secondary: #8892B0;
|
||||
--lp-text-tertiary: #5A6480;
|
||||
--lp-bg: #FFFFFF;
|
||||
--lp-bg-secondary: #F5F7FC;
|
||||
--lp-bg-card: #FFFFFF;
|
||||
--lp-bg-card-hover: #F5F7FC;
|
||||
--lp-bg-glass: rgba(255, 255, 255, 0.8);
|
||||
--lp-border: rgba(0, 0, 0, 0.08);
|
||||
--lp-border-light: rgba(0, 0, 0, 0.05);
|
||||
--lp-text: #1A1F36;
|
||||
--lp-text-secondary: #5A6480;
|
||||
--lp-text-tertiary: #8892B0;
|
||||
--lp-accent: #6C63FF;
|
||||
--lp-accent-light: #8B85FF;
|
||||
--lp-accent-glow: rgba(108, 99, 255, 0.3);
|
||||
--lp-gradient-1: linear-gradient(135deg, #6C63FF 0%, #A78BFA 50%, #C084FC 100%);
|
||||
--lp-gradient-2: linear-gradient(135deg, #06B6D4 0%, #3B82F6 100%);
|
||||
--lp-gradient-3: linear-gradient(135deg, #10B981 0%, #34D399 100%);
|
||||
--lp-gradient-hero: radial-gradient(ellipse 80% 50% at 50% -20%, rgba(108, 99, 255, 0.15), transparent 70%);
|
||||
--lp-shadow-card: 0 1px 3px rgba(0,0,0,0.3), 0 4px 12px rgba(0,0,0,0.2);
|
||||
--lp-shadow-lg: 0 8px 32px rgba(0,0,0,0.4);
|
||||
--lp-gradient-hero: radial-gradient(ellipse 80% 50% at 50% -20%, rgba(108, 99, 255, 0.08), transparent 70%);
|
||||
--lp-shadow-card: 0 1px 3px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.04);
|
||||
--lp-shadow-lg: 0 8px 32px rgba(0,0,0,0.10);
|
||||
--lp-radius: 12px;
|
||||
--lp-radius-sm: 8px;
|
||||
--lp-radius-lg: 16px;
|
||||
@@ -42,7 +42,7 @@
|
||||
top: 24px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(22, 27, 46, 0.95);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(108, 99, 255, 0.3);
|
||||
color: var(--lp-text);
|
||||
@@ -71,7 +71,7 @@
|
||||
}
|
||||
|
||||
.landing-header-v2.scrolled {
|
||||
background: rgba(10, 14, 26, 0.85);
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(20px);
|
||||
border-bottom: 1px solid var(--lp-border);
|
||||
padding: 10px 0;
|
||||
@@ -311,7 +311,7 @@
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--lp-text-secondary);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
background: rgba(108, 99, 255, 0.04);
|
||||
border: 1px solid var(--lp-border);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
@@ -319,8 +319,8 @@
|
||||
|
||||
.btn-hero-secondary:hover {
|
||||
color: var(--lp-text);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
background: rgba(108, 99, 255, 0.10);
|
||||
border-color: rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
|
||||
.hero-stats-v2 {
|
||||
@@ -441,7 +441,7 @@
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
background: rgba(108, 99, 255, 0.20);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
@@ -622,8 +622,8 @@
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--lp-text-secondary);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
background: rgba(108, 99, 255, 0.04);
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -763,7 +763,7 @@
|
||||
|
||||
.filter-chip:hover {
|
||||
color: var(--lp-text);
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
border-color: rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
|
||||
.filter-chip.active {
|
||||
|
||||
@@ -157,14 +157,14 @@ const LandingPage: React.FC = () => {
|
||||
<path d="M8 20V12l4 4 4-4v8" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
|
||||
<path d="M6 22h20" stroke="white" strokeWidth="1.5" strokeLinecap="round" opacity="0.5"/>
|
||||
</svg>
|
||||
<span className="landing-brand-text">Qihu-AIFlow</span>
|
||||
<span className="landing-brand-text">七虎AI</span>
|
||||
</div>
|
||||
<nav className="landing-nav-v2">
|
||||
<a href="#what-is">平台介绍</a>
|
||||
<a href="#architecture">平台架构</a>
|
||||
<a href="#capabilities">能力体系</a>
|
||||
<a href="#scenarios">应用场景</a>
|
||||
<a href="#market">技能生态</a>
|
||||
<nav className="landing-nav-v2" style={{ cursor: 'pointer' }}>
|
||||
<a onClick={() => document.getElementById('what-is')?.scrollIntoView({ behavior: 'smooth' })}>平台介绍</a>
|
||||
<a onClick={() => document.getElementById('architecture')?.scrollIntoView({ behavior: 'smooth' })}>平台架构</a>
|
||||
<a onClick={() => document.getElementById('capabilities')?.scrollIntoView({ behavior: 'smooth' })}>能力体系</a>
|
||||
<a onClick={() => document.getElementById('scenarios')?.scrollIntoView({ behavior: 'smooth' })}>应用场景</a>
|
||||
<a onClick={() => document.getElementById('market')?.scrollIntoView({ behavior: 'smooth' })}>技能生态</a>
|
||||
</nav>
|
||||
<div className="landing-actions-v2">
|
||||
<button className="btn-ghost-v2" onClick={() => navigate('/login')}>登录</button>
|
||||
@@ -173,7 +173,7 @@ const LandingPage: React.FC = () => {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Hero Section — What is Qihu-AIFlow */}
|
||||
{/* Hero Section — What is 七虎AI */}
|
||||
<section className="hero-section-v2">
|
||||
<div className="hero-bg-orb orb-1" />
|
||||
<div className="hero-bg-orb orb-2" />
|
||||
@@ -188,7 +188,7 @@ const LandingPage: React.FC = () => {
|
||||
<span className="hero-gradient-text"> 的超级工作台</span>
|
||||
</h1>
|
||||
<p className="hero-subtitle-v2">
|
||||
Qihu-AIFlow 是一站式 AI 能力集成平台,让你在一个地方完成对话、知识库、技能编排、模型切换、自动化搭建<br/>
|
||||
七虎AI 是一站式 AI 能力集成平台,让你在一个地方完成对话、知识库、技能编排、模型切换、自动化搭建<br/>
|
||||
无需拼接多个工具,从想法到落地,一个平台就够了
|
||||
</p>
|
||||
<div className="hero-cta-v2">
|
||||
@@ -226,11 +226,11 @@ const LandingPage: React.FC = () => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* What is Qihu-AIFlow — Platform Introduction */}
|
||||
{/* What is 七虎AI — Platform Introduction */}
|
||||
<section id="what-is" className="whatis-section-v2">
|
||||
<div className="section-header-v2">
|
||||
<span className="section-badge-v2">平台介绍</span>
|
||||
<h2>Qihu-AIFlow 是什么?</h2>
|
||||
<h2>七虎AI 是什么?</h2>
|
||||
<p>一个面向 AI 爱好者和从业者的个人 AI 能力集成平台</p>
|
||||
</div>
|
||||
<div className="whatis-cards-v2">
|
||||
@@ -262,7 +262,7 @@ const LandingPage: React.FC = () => {
|
||||
<div className="section-header-v2">
|
||||
<span className="section-badge-v2">平台架构</span>
|
||||
<h2>四层架构 · 层层赋能</h2>
|
||||
<p>从基础设施到上层应用,理解 Qihu-AIFlow 的技术全貌</p>
|
||||
<p>从基础设施到上层应用,理解 七虎AI 的技术全貌</p>
|
||||
</div>
|
||||
<div className="arch-layers-v2">
|
||||
{archLayers.map((layer, idx) => (
|
||||
@@ -417,14 +417,14 @@ const LandingPage: React.FC = () => {
|
||||
<path d="M8 20V12l4 4 4-4v8" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
|
||||
<path d="M6 22h20" stroke="white" strokeWidth="1.5" strokeLinecap="round" opacity="0.5"/>
|
||||
</svg>
|
||||
<span>Qihu-AIFlow</span>
|
||||
<span>七虎AI</span>
|
||||
</div>
|
||||
<div className="footer-links-v2">
|
||||
<div className="footer-col-v2">
|
||||
<h4>平台</h4>
|
||||
<a href="#what-is">平台介绍</a>
|
||||
<a href="#architecture">平台架构</a>
|
||||
<a href="#capabilities">能力体系</a>
|
||||
<a onClick={() => document.getElementById('what-is')?.scrollIntoView({ behavior: 'smooth' })}>平台介绍</a>
|
||||
<a onClick={() => document.getElementById('architecture')?.scrollIntoView({ behavior: 'smooth' })}>平台架构</a>
|
||||
<a onClick={() => document.getElementById('capabilities')?.scrollIntoView({ behavior: 'smooth' })}>能力体系</a>
|
||||
</div>
|
||||
<div className="footer-col-v2">
|
||||
<h4>资源</h4>
|
||||
@@ -441,7 +441,7 @@ const LandingPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer-bottom-v2">
|
||||
<p>© 2026 Qihu-AIFlow. All rights reserved.</p>
|
||||
<p>© 2026 七虎AI. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/* ===== Login Page ===== */
|
||||
/* ===== Login Page V3 - Dark Theme ===== */
|
||||
.login-page {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: var(--color-bg-primary);
|
||||
background: #F5F7FC;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Background decorations */
|
||||
.login-bg-decor {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -19,35 +20,37 @@
|
||||
.bg-circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
opacity: 0.08;
|
||||
filter: blur(80px);
|
||||
}
|
||||
|
||||
.bg-circle.c1 {
|
||||
width: 600px; height: 600px;
|
||||
background: var(--color-accent);
|
||||
background: #6C63FF;
|
||||
top: -200px; right: -100px;
|
||||
opacity: 0.12;
|
||||
}
|
||||
|
||||
.bg-circle.c2 {
|
||||
width: 400px; height: 400px;
|
||||
background: #8B8DFF;
|
||||
background: #06B6D4;
|
||||
bottom: -100px; left: -50px;
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.bg-circle.c3 {
|
||||
width: 300px; height: 300px;
|
||||
background: var(--color-accent);
|
||||
background: #A78BFA;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
opacity: 0.04;
|
||||
opacity: 0.06;
|
||||
}
|
||||
|
||||
.bg-grid {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image:
|
||||
linear-gradient(rgba(0,0,0,0.02) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(0,0,0,0.02) 1px, transparent 1px);
|
||||
linear-gradient(rgba(108, 99, 255, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(108, 99, 255, 0.03) 1px, transparent 1px);
|
||||
background-size: 60px 60px;
|
||||
}
|
||||
|
||||
@@ -56,203 +59,212 @@
|
||||
display: flex;
|
||||
width: 900px;
|
||||
min-height: 560px;
|
||||
background: #FFFFFF;
|
||||
border-radius: var(--radius-2xl);
|
||||
box-shadow: var(--shadow-xl);
|
||||
background: rgba(17, 22, 39, 0.95);
|
||||
backdrop-filter: blur(24px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
|
||||
overflow: hidden;
|
||||
z-index: var(--z-base);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
animation: loginSlideUp 0.5s ease;
|
||||
}
|
||||
|
||||
/* Brand Panel */
|
||||
@keyframes loginSlideUp {
|
||||
from { opacity: 0; transform: translateY(24px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* Left brand panel */
|
||||
.login-brand-panel {
|
||||
width: 400px;
|
||||
background: linear-gradient(135deg, #2D2B55 0%, #1A1A2E 50%, #2D2B55 100%);
|
||||
background: linear-gradient(135deg, rgba(108, 99, 255, 0.08) 0%, rgba(167, 139, 250, 0.05) 100%);
|
||||
padding: 48px 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-brand-panel::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 300px; height: 300px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(91,95,237,0.3) 0%, transparent 70%);
|
||||
top: -50px; right: -50px;
|
||||
}
|
||||
|
||||
.login-brand-panel::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 200px; height: 200px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(139,141,255,0.2) 0%, transparent 70%);
|
||||
bottom: -30px; left: -30px;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.brand-content {
|
||||
text-align: center;
|
||||
color: white;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.brand-icon {
|
||||
margin-bottom: var(--space-xl);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.brand-title {
|
||||
font-size: 36px;
|
||||
font-size: 32px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
margin-bottom: var(--space-sm);
|
||||
color: #1A1F36;
|
||||
margin-bottom: 8px;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.brand-desc {
|
||||
font-size: var(--text-base);
|
||||
color: rgba(255,255,255,0.6);
|
||||
margin-bottom: var(--space-3xl);
|
||||
font-size: 15px;
|
||||
color: #5A6480;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.brand-features {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-md);
|
||||
text-align: left;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.brand-feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-md);
|
||||
font-size: var(--text-sm);
|
||||
color: rgba(255,255,255,0.75);
|
||||
gap: 10px;
|
||||
font-size: 14px;
|
||||
color: #5A6480;
|
||||
}
|
||||
|
||||
.bf-icon {
|
||||
color: #6C63FF;
|
||||
font-weight: 700;
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
/* Form Panel */
|
||||
.login-form-panel {
|
||||
flex: 1;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: rgba(16, 185, 129, 0.15);
|
||||
color: #10B981;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-4xl);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Right form panel */
|
||||
.login-form-panel {
|
||||
flex: 1;
|
||||
padding: 48px 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login-form-inner {
|
||||
width: 100%;
|
||||
max-width: 340px;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.login-tabs {
|
||||
display: flex;
|
||||
gap: var(--space-2xl);
|
||||
margin-bottom: var(--space-3xl);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border-radius: 10px;
|
||||
padding: 4px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.login-tab {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 700;
|
||||
color: var(--color-text-tertiary);
|
||||
padding-bottom: var(--space-sm);
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all var(--transition-fast);
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #5A6480;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.login-tab.active {
|
||||
color: var(--color-text-primary);
|
||||
border-bottom-color: var(--color-accent);
|
||||
background: rgba(108, 99, 255, 0.15);
|
||||
color: #8B85FF;
|
||||
}
|
||||
|
||||
.login-tab:hover {
|
||||
color: var(--color-text-primary);
|
||||
.login-tab:hover:not(.active) {
|
||||
color: #5A6480;
|
||||
}
|
||||
|
||||
/* Error message */
|
||||
.form-error {
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border: 1px solid rgba(239, 68, 68, 0.2);
|
||||
color: #F87171;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* Form */
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xl);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
margin-bottom: 16px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin-bottom: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #5A6480;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: #EF4444;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
font-size: var(--text-base);
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-bg-primary);
|
||||
transition: all var(--transition-fast);
|
||||
padding: 12px 14px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.10);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: #1A1F36;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
transition: all 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 3px var(--color-accent-light);
|
||||
background: #FFFFFF;
|
||||
border-color: rgba(108, 99, 255, 0.4);
|
||||
background: rgba(108, 99, 255, 0.05);
|
||||
box-shadow: 0 0 0 3px rgba(108, 99, 255, 0.1);
|
||||
}
|
||||
|
||||
.form-input::placeholder {
|
||||
color: var(--color-text-disabled);
|
||||
color: #3A4460;
|
||||
}
|
||||
|
||||
/* Submit button */
|
||||
.login-submit-btn {
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #5B5FED, #6C63FF);
|
||||
width: 100%;
|
||||
padding: 13px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, #6C63FF, #A78BFA);
|
||||
color: white;
|
||||
border-radius: var(--radius-lg);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.15em;
|
||||
transition: all var(--transition-fast);
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.login-submit-btn:hover {
|
||||
background: linear-gradient(135deg, #4A4ECC, #5B5FED);
|
||||
.login-submit-btn:hover:not(:disabled) {
|
||||
box-shadow: 0 4px 20px rgba(108, 99, 255, 0.4);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.login-submit-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.login-submit-btn:disabled {
|
||||
opacity: 0.5;
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.login-submit-btn:disabled:hover {
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Register Method Tabs */
|
||||
/* Register method tabs */
|
||||
.register-method-tabs {
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
margin-bottom: var(--space-lg);
|
||||
gap: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.register-method-tab {
|
||||
@@ -261,32 +273,32 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-bg-primary);
|
||||
font-size: var(--text-sm);
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.10);
|
||||
background: transparent;
|
||||
color: #5A6480;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.register-method-tab:hover {
|
||||
border-color: var(--color-accent-light);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.register-method-tab.active {
|
||||
border-color: var(--color-accent);
|
||||
background: var(--color-accent-subtle);
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
border-color: rgba(108, 99, 255, 0.3);
|
||||
background: rgba(108, 99, 255, 0.1);
|
||||
color: #8B85FF;
|
||||
}
|
||||
|
||||
/* SMS Row */
|
||||
.register-method-tab:hover:not(.active) {
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
color: #5A6480;
|
||||
}
|
||||
|
||||
/* SMS row */
|
||||
.sms-row {
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sms-input {
|
||||
@@ -294,49 +306,42 @@
|
||||
}
|
||||
|
||||
.sms-btn {
|
||||
padding: var(--space-sm) var(--space-lg);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-accent);
|
||||
background: transparent;
|
||||
color: var(--color-accent);
|
||||
font-size: var(--text-sm);
|
||||
padding: 10px 16px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(108, 99, 255, 0.2);
|
||||
background: rgba(108, 99, 255, 0.08);
|
||||
color: #8B85FF;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: all var(--transition-fast);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.sms-btn:hover:not(:disabled) {
|
||||
background: var(--color-accent);
|
||||
color: white;
|
||||
background: rgba(108, 99, 255, 0.15);
|
||||
}
|
||||
|
||||
.sms-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
border-color: var(--color-border);
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
/* Required Marker */
|
||||
.required {
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.login-container {
|
||||
flex-direction: column;
|
||||
width: 90vw;
|
||||
width: calc(100vw - 32px);
|
||||
min-height: auto;
|
||||
margin: 16px;
|
||||
}
|
||||
.login-brand-panel {
|
||||
width: 100%;
|
||||
padding: var(--space-3xl) var(--space-2xl);
|
||||
padding: 32px 24px;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
.login-form-panel {
|
||||
padding: var(--space-2xl);
|
||||
}
|
||||
.brand-features {
|
||||
display: none;
|
||||
padding: 32px 24px;
|
||||
}
|
||||
}
|
||||
@@ -65,38 +65,22 @@ const LoginPage: React.FC = () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await authAPI.login(loginAccount, loginPassword);
|
||||
const { access_token, user: userData } = res.data;
|
||||
localStorage.setItem('aiflow_token', access_token);
|
||||
const data: any = (res as any).data || res;
|
||||
const token = data.access_token || data.token;
|
||||
const userData = data.user || data;
|
||||
localStorage.setItem('aiflow_token', token);
|
||||
const userObj: User = {
|
||||
id: userData.id,
|
||||
username: userData.username,
|
||||
email: userData.email || '',
|
||||
phone: userData.phone || '',
|
||||
avatar: userData.avatar || '',
|
||||
role: userData.role,
|
||||
status: userData.status,
|
||||
realNameStatus: userData.real_name_status || 'unverified',
|
||||
createdAt: userData.created_at || new Date().toISOString(),
|
||||
membership: userData.membership_level > 0 ? {
|
||||
planId: userData.membership_level >= 3 ? 'mp3' : (userData.membership_level >= 2 ? 'mp2' : 'mp1'),
|
||||
planName: userData.role === 'admin' ? '管理员' : (userData.membership_level >= 3 ? '企业版' : (userData.membership_level >= 2 ? '专业版' : '免费版')),
|
||||
level: userData.membership_level,
|
||||
expireAt: userData.membership_expire_at || '',
|
||||
autoRenew: userData.auto_renew || false,
|
||||
} : undefined,
|
||||
id: userData.id, username: userData.username,
|
||||
email: userData.email || '', phone: userData.phone || '',
|
||||
avatar: userData.avatar || '', role: userData.role || 'user',
|
||||
status: 'active', realNameStatus: 'unverified',
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
login(userObj);
|
||||
navigate(userData.role === 'admin' ? '/admin' : '/chat');
|
||||
navigate(userObj.role === 'admin' ? '/admin' : '/chat');
|
||||
} catch (e: any) {
|
||||
// 处理后端返回的精确错误信息,区分用户不存在和密码错误
|
||||
const status = e.status || e.response?.status || 0;
|
||||
const msg = e.detail || e.message || '';
|
||||
if (status === 403) {
|
||||
setErrorMsg('账号已被禁用,请联系管理员');
|
||||
} else if (status === 401) {
|
||||
// 后端的detail精确指明了原因:"用户名不存在" 或 "密码错误"
|
||||
setErrorMsg(msg || '用户名或密码错误');
|
||||
} else if (status === 0 || msg.includes('NetworkError') || msg.includes('Failed to fetch')) {
|
||||
const msg = (e as any).detail || (e as any).message || '';
|
||||
if (msg.includes('Network') || msg.includes('fetch')) {
|
||||
setErrorMsg('网络连接失败,请检查网络');
|
||||
} else {
|
||||
setErrorMsg(msg || '登录失败,请稍后重试');
|
||||
@@ -121,14 +105,10 @@ const LoginPage: React.FC = () => {
|
||||
const { access_token, user: userData } = res.data;
|
||||
localStorage.setItem('aiflow_token', access_token);
|
||||
const userObj: User = {
|
||||
id: userData.id,
|
||||
username: userData.username,
|
||||
email: userData.email || '',
|
||||
phone: userData.phone || '',
|
||||
avatar: userData.avatar || '',
|
||||
role: 'user',
|
||||
status: 'active',
|
||||
realNameStatus: 'unverified',
|
||||
id: userData.id, username: userData.username,
|
||||
email: userData.email || '', phone: userData.phone || '',
|
||||
avatar: userData.avatar || '', role: 'user',
|
||||
status: 'active', realNameStatus: 'unverified',
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
login(userObj);
|
||||
@@ -158,12 +138,18 @@ const LoginPage: React.FC = () => {
|
||||
<div className="brand-content">
|
||||
<div className="brand-icon">
|
||||
<svg width="48" height="48" viewBox="0 0 32 32" fill="none">
|
||||
<rect width="32" height="32" rx="8" fill="white"/>
|
||||
<path d="M8 20V12l4 4 4-4v8" stroke="#5B5FED" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
|
||||
<path d="M6 22h20" stroke="#5B5FED" strokeWidth="1.5" strokeLinecap="round" opacity="0.5"/>
|
||||
<defs>
|
||||
<linearGradient id="lpBrandGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stopColor="#6C63FF"/>
|
||||
<stop offset="100%" stopColor="#A78BFA"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="32" height="32" rx="8" fill="url(#lpBrandGrad)"/>
|
||||
<path d="M8 20V12l4 4 4-4v8" stroke="white" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
|
||||
<path d="M6 22h20" stroke="white" strokeWidth="1.5" strokeLinecap="round" opacity="0.5"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="brand-title">AIFlow</h1>
|
||||
<h1 className="brand-title">七虎AI</h1>
|
||||
<p className="brand-desc">智能自动化PaaS平台</p>
|
||||
<div className="brand-features">
|
||||
<div className="brand-feature"><span className="bf-icon">✓</span><span>一站式AI自动化SOP</span></div>
|
||||
|
||||
Reference in new issue
Block a user