fix: 修复前端构建问题 - 清理死代码和 Next.js 残留 #56
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// This file is auto-used by Next.js TypeScript projects.
|
||||
@@ -1,6 +0,0 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
@@ -1,140 +0,0 @@
|
||||
/* V21 App Root Styles */
|
||||
|
||||
.xx-app-root {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #eef2ff 100%);
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.xx-app-container {
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Hero Section */
|
||||
.xx-hero-section {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.xx-logo {
|
||||
font-size: 72px;
|
||||
margin-bottom: 24px;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
|
||||
.xx-hero-section h1 {
|
||||
font-size: 36px;
|
||||
font-weight: 850;
|
||||
color: #0f172a;
|
||||
margin: 0 0 12px;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
.xx-hero-section p {
|
||||
font-size: 18px;
|
||||
color: #64748b;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.xx-status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 20px;
|
||||
padding: 8px 16px;
|
||||
background: #eef2ff;
|
||||
color: #4f46e5;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.xx-status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: #4f46e5;
|
||||
border-radius: 50%;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.5; transform: scale(1.2); }
|
||||
}
|
||||
|
||||
/* Card */
|
||||
.xx-card {
|
||||
background: rgba(255,255,255,0.94);
|
||||
border: 1px solid rgba(226,232,240,0.95);
|
||||
border-radius: 22px;
|
||||
box-shadow: 0 24px 70px rgba(15,23,42,0.09);
|
||||
padding: 28px;
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.xx-card:hover {
|
||||
box-shadow: 0 26px 64px rgba(15,23,42,0.14);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.xx-card h3 {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin: 0 0 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Quick Links */
|
||||
.xx-link-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.xx-link-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 24px 16px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 16px;
|
||||
text-decoration: none;
|
||||
color: #0f172a;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.xx-link-item:hover {
|
||||
background: #eef2ff;
|
||||
border-color: #4f46e5;
|
||||
color: #4f46e5;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 24px rgba(79,70,229,0.15);
|
||||
}
|
||||
|
||||
.xx-link-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 480px) {
|
||||
.xx-hero-section h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.xx-link-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* App Root Component - V21 UI
|
||||
* 注意:此组件已被路由系统接管,仅作为默认展示
|
||||
*/
|
||||
import { Link } from 'react-router-dom';
|
||||
import './App.css';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="xx-app-root">
|
||||
<div className="xx-app-container">
|
||||
<div className="xx-hero-section">
|
||||
<div className="xx-logo">🎬</div>
|
||||
<h1>小虾 SaaS</h1>
|
||||
<p>自动化视频剪辑平台</p>
|
||||
<div className="xx-status-badge">
|
||||
<span className="xx-status-dot"></span>
|
||||
前端开发中
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="xx-card xx-quick-links">
|
||||
<h3>快速链接</h3>
|
||||
<div className="xx-link-grid">
|
||||
<span>Projects (Coming Soon)</span>
|
||||
<Link to="/projects" className="xx-link-item">
|
||||
<span className="xx-link-icon">📋</span>
|
||||
<span>我的项目</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* 配额使用展示组件 - V21 UI
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Card, Progress, Row, Col, Tag, Space } from 'antd';
|
||||
import { ProjectOutlined, CloudOutlined, WarningOutlined } from '@ant-design/icons';
|
||||
import './business.css';
|
||||
|
||||
interface QuotaStatus {
|
||||
projects: {
|
||||
used: number;
|
||||
limit: number;
|
||||
status: string;
|
||||
};
|
||||
storage: {
|
||||
used_gb: number;
|
||||
limit_gb: number;
|
||||
status: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface QuotaDisplayProps {
|
||||
quota: QuotaStatus;
|
||||
}
|
||||
|
||||
const QuotaDisplay: React.FC<QuotaDisplayProps> = ({ quota }) => {
|
||||
const getStatusTag = (status: string) => {
|
||||
const config: Record<string, { color: string; text: string; className: string }> = {
|
||||
normal: { color: 'success', text: '正常', className: 'xx-tag-success' },
|
||||
warning: { color: 'warning', text: '接近上限', className: 'xx-tag-warning' },
|
||||
critical: { color: 'error', text: '即将超限', className: 'xx-tag-error' },
|
||||
exceeded: { color: 'error', text: '已超限', className: 'xx-tag-error' },
|
||||
};
|
||||
const item = config[status] || config.normal;
|
||||
return (
|
||||
<Tag color={item.color} icon={<WarningOutlined />} className={`xx-tag ${item.className}`}>
|
||||
{item.text}
|
||||
</Tag>
|
||||
);
|
||||
};
|
||||
|
||||
const getProgressColor = (status: string) => {
|
||||
const colorMap: Record<string, string> = {
|
||||
normal: '#16a34a',
|
||||
warning: '#d97706',
|
||||
critical: '#dc2626',
|
||||
exceeded: '#dc2626',
|
||||
};
|
||||
return colorMap[status] || '#4f46e5';
|
||||
};
|
||||
|
||||
return (
|
||||
<Card title="配额使用情况" className="xx-card">
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="large">
|
||||
<div className="xx-quota-item">
|
||||
<Row justify="space-between" align="middle" style={{ marginBottom: 12 }}>
|
||||
<Col>
|
||||
<Space>
|
||||
<ProjectOutlined style={{ fontSize: 18, color: '#4f46e5' }} />
|
||||
<span style={{ fontWeight: 600, color: '#0f172a', fontSize: 15 }}>项目数量</span>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col>{getStatusTag(quota.projects.status)}</Col>
|
||||
</Row>
|
||||
<div style={{ marginBottom: 8, color: '#64748b', fontSize: 14 }}>
|
||||
{quota.projects.used} / {quota.projects.limit} 个项目
|
||||
</div>
|
||||
<Progress
|
||||
percent={Math.round((quota.projects.used / quota.projects.limit) * 100)}
|
||||
strokeColor={getProgressColor(quota.projects.status)}
|
||||
trailColor="#f1f5f9"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="xx-quota-item">
|
||||
<Row justify="space-between" align="middle" style={{ marginBottom: 12 }}>
|
||||
<Col>
|
||||
<Space>
|
||||
<CloudOutlined style={{ fontSize: 18, color: '#4f46e5' }} />
|
||||
<span style={{ fontWeight: 600, color: '#0f172a', fontSize: 15 }}>存储空间</span>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col>{getStatusTag(quota.storage.status)}</Col>
|
||||
</Row>
|
||||
<div style={{ marginBottom: 8, color: '#64748b', fontSize: 14 }}>
|
||||
{quota.storage.used_gb.toFixed(2)} / {quota.storage.limit_gb} GB
|
||||
</div>
|
||||
<Progress
|
||||
percent={Math.round((quota.storage.used_gb / quota.storage.limit_gb) * 100)}
|
||||
strokeColor={getProgressColor(quota.storage.status)}
|
||||
trailColor="#f1f5f9"
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuotaDisplay;
|
||||
@@ -5,6 +5,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/store/authStore';
|
||||
import { useLogout } from '@/hooks/useAuth';
|
||||
import type { MenuProps } from 'antd';
|
||||
import './Header.css';
|
||||
|
||||
const extractProjectId = (pathname: string) => {
|
||||
const match = pathname.match(/^\/projects\/([^/]+)/);
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* 工作空间状态管理
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import { Workspace } from '@/api/workspace';
|
||||
|
||||
interface WorkspaceState {
|
||||
currentWorkspace: Workspace | null;
|
||||
workspaces: Workspace[];
|
||||
|
||||
// Actions
|
||||
setCurrentWorkspace: (workspace: Workspace | null) => void;
|
||||
setWorkspaces: (workspaces: Workspace[]) => void;
|
||||
addWorkspace: (workspace: Workspace) => void;
|
||||
removeWorkspace: (workspaceId: string) => void;
|
||||
}
|
||||
|
||||
export const useWorkspaceStore = create<WorkspaceState>((set) => ({
|
||||
currentWorkspace: null,
|
||||
workspaces: [],
|
||||
|
||||
setCurrentWorkspace: (workspace) => {
|
||||
set({ currentWorkspace: workspace });
|
||||
},
|
||||
|
||||
setWorkspaces: (workspaces) => {
|
||||
set({ workspaces });
|
||||
},
|
||||
|
||||
addWorkspace: (workspace) => {
|
||||
set((state) => ({
|
||||
workspaces: [...state.workspaces, workspace],
|
||||
}));
|
||||
},
|
||||
|
||||
removeWorkspace: (workspaceId) => {
|
||||
set((state) => ({
|
||||
workspaces: state.workspaces.filter((w) => w.id !== workspaceId),
|
||||
currentWorkspace:
|
||||
state.currentWorkspace?.id === workspaceId ? null : state.currentWorkspace,
|
||||
}));
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user