diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx
index 165217b..80552a9 100644
--- a/frontend/src/app/dashboard/page.tsx
+++ b/frontend/src/app/dashboard/page.tsx
@@ -3,20 +3,41 @@
import { useEffect, Suspense } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useAuthStore } from '@/lib/auth-store';
-import { getUserInfo } from '@/lib/api';
import Layout from '@/components/layout';
+import { Activity, BadgeCheck, Boxes, ShieldCheck } from 'lucide-react';
+
+const cards = [
+ {
+ title: '欢迎回来',
+ value: 'IMTIM Portal',
+ description: '您已成功登录企业门户',
+ icon: ShieldCheck,
+ },
+ {
+ title: '账户状态',
+ value: '已激活',
+ description: '当前账号可正常访问系统',
+ icon: BadgeCheck,
+ },
+ {
+ title: '系统版本',
+ value: '1.0.0',
+ description: '基础登录门户服务',
+ icon: Boxes,
+ },
+];
function DashboardContent() {
- const { login, initialize } = useAuthStore();
+ const { user, isAuthenticated, isInitialized, login, initialize } = useAuthStore();
const router = useRouter();
const searchParams = useSearchParams();
+ const token = searchParams.get('token');
useEffect(() => {
initialize();
}, [initialize]);
useEffect(() => {
- const token = searchParams.get('token');
if (token) {
const fetchUser = async () => {
try {
@@ -39,25 +60,74 @@ function DashboardContent() {
};
fetchUser();
}
- }, [searchParams, login, router]);
+ }, [token, login, router]);
+
+ useEffect(() => {
+ if (isInitialized && !isAuthenticated && !token) {
+ router.replace('/login');
+ }
+ }, [isInitialized, isAuthenticated, token, router]);
+
+ if (token || !isInitialized || !isAuthenticated) {
+ return (
+
+ );
+ }
return (
-
-
仪表板
-
-
-
欢迎
-
- 您已成功登录 IMTIM Portal
+
+
+
+
控制台
+
仪表板
+
+ {user?.username ? `${user.username},查看登录状态、账户可用性和基础系统信息。` : '查看登录状态、账户可用性和基础系统信息。'}
-
-
账户状态
-
已激活
+
-
+
+
+ {cards.map((card) => {
+ const Icon = card.icon;
+ return (
+
+
+
+
+
+ {card.title === '账户状态' ? (
+
+ Active
+
+ ) : null}
+
+
{card.title}
+
{card.value}
+
{card.description}
+
+ );
+ })}
+
+
+
+
+
+
认证流程
+
+ OAuth 回调、用户信息获取和本地会话写入均已就绪。
+
+
+
+ Ready
+
@@ -67,7 +137,13 @@ function DashboardContent() {
export default function DashboardPage() {
return (
- 加载中...}>
+
+ 加载中...
+
+ }
+ >
diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css
index f1ee6bc..96e9cfe 100644
--- a/frontend/src/app/globals.css
+++ b/frontend/src/app/globals.css
@@ -1,34 +1,66 @@
@import "tailwindcss";
:root {
- --background: oklch(1 0 0);
- --foreground: oklch(0.145 0 0);
+ --background: oklch(0.985 0.006 247.858);
+ --foreground: oklch(0.21 0.034 264.665);
--card: oklch(1 0 0);
- --card-foreground: oklch(0.145 0 0);
+ --card-foreground: oklch(0.21 0.034 264.665);
--popover: oklch(1 0 0);
- --popover-foreground: oklch(0.145 0 0);
- --primary: oklch(0.205 0 0);
+ --popover-foreground: oklch(0.21 0.034 264.665);
+ --primary: oklch(0.52 0.19 253.3);
--primary-foreground: oklch(0.985 0 0);
- --secondary: oklch(0.97 0 0);
- --secondary-foreground: oklch(0.205 0 0);
- --muted: oklch(0.97 0 0);
- --muted-foreground: oklch(0.556 0 0);
- --accent: oklch(0.97 0 0);
- --accent-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.96 0.013 247.858);
+ --secondary-foreground: oklch(0.279 0.041 260.031);
+ --muted: oklch(0.96 0.013 247.858);
+ --muted-foreground: oklch(0.446 0.043 257.281);
+ --accent: oklch(0.94 0.025 255.585);
+ --accent-foreground: oklch(0.279 0.041 260.031);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
- --border: oklch(0.922 0 0);
- --input: oklch(0.922 0 0);
- --ring: oklch(0.708 0 0);
+ --border: oklch(0.9 0.022 252.894);
+ --input: oklch(0.9 0.022 252.894);
+ --ring: oklch(0.52 0.19 253.3);
--radius: 0.5rem;
}
+@theme inline {
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-destructive-foreground: var(--destructive-foreground);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+}
+
* {
border-color: var(--border);
}
+html {
+ min-width: 320px;
+ scroll-behavior: smooth;
+}
+
body {
background-color: var(--background);
color: var(--foreground);
font-family: system-ui, -apple-system, sans-serif;
}
+
+button,
+a {
+ -webkit-tap-highlight-color: transparent;
+}
diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx
index 60fe13a..2c0a99b 100644
--- a/frontend/src/app/login/page.tsx
+++ b/frontend/src/app/login/page.tsx
@@ -4,18 +4,22 @@ import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useAuthStore } from '@/lib/auth-store';
import { getLoginUrl } from '@/lib/api';
-import { LogIn } from 'lucide-react';
+import { BadgeCheck, KeyRound, LogIn } from 'lucide-react';
import Layout from '@/components/layout';
export default function LoginPage() {
- const { isAuthenticated } = useAuthStore();
+ const { isAuthenticated, isInitialized, initialize } = useAuthStore();
const router = useRouter();
useEffect(() => {
- if (isAuthenticated) {
- router.push('/dashboard');
+ initialize();
+ }, [initialize]);
+
+ useEffect(() => {
+ if (isInitialized && isAuthenticated) {
+ router.replace('/dashboard');
}
- }, [isAuthenticated, router]);
+ }, [isInitialized, isAuthenticated, router]);
const handleLogin = async () => {
try {
@@ -28,25 +32,66 @@ export default function LoginPage() {
return (
-
-
-
-
-
登录
-
+
+
+ 统一身份认证
+
+ 通过 Casdoor 安全接入 IMTIM Portal
+
+
+
+
+
+
+
+
+
单点登录入口
+
+ 使用统一账号完成认证,减少重复登录和权限分散。
+
+
+
+
+
+
+
+
+
+
+
认证状态同步
+
+ 登录成功后自动写入会话并跳转到控制台。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
登录
+
使用 Casdoor 账号登录 IMTIM Portal
+
+ 登录即表示将跳转到 Casdoor 完成身份验证
+
-
+
);
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 9f87232..c2bdac6 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -3,71 +3,121 @@
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useAuthStore } from '@/lib/auth-store';
-import { ArrowRight, Shield, Zap, Users } from 'lucide-react';
+import { ArrowRight, CheckCircle2, Shield, Users, Zap } from 'lucide-react';
import Layout from '@/components/layout';
+const features = [
+ {
+ title: '安全可靠',
+ description: '基于 OAuth 2.0 的企业级认证,支持统一身份入口和多因素认证。',
+ icon: Shield,
+ },
+ {
+ title: '快速部署',
+ description: '面向容器化交付,适合快速接入现有服务并降低运维成本。',
+ icon: Zap,
+ },
+ {
+ title: '易于扩展',
+ description: '模块化架构设计,便于扩展自定义业务逻辑和第三方集成。',
+ icon: Users,
+ },
+];
+
+const metrics = [
+ ['OAuth 2.0', '认证协议'],
+ ['Docker', '部署方式'],
+ ['SSO', '统一登录'],
+];
+
export default function Home() {
- const { isAuthenticated, initialize } = useAuthStore();
+ const { initialize } = useAuthStore();
const router = useRouter();
useEffect(() => {
initialize();
}, [initialize]);
- useEffect(() => {
- if (isAuthenticated) {
- router.push('/dashboard');
- }
- }, [isAuthenticated, router]);
-
return (
-
- {/* Hero Section */}
-
-
-
- IMTIM Portal
-
-
+
+
+
+
+
+
+ 企业登录基座
+
+
+ IMTIM Portal
+
+
企业级门户登录基座应用,安全、高效、易于扩展
-
-
+
+
+
+
+
+
+
+
+
+
+
+ {metrics.map(([value, label]) => (
+
+ ))}
+
+
+
- {/* Features Section */}
-
-
-
核心特性
-
-
-
-
安全可靠
-
- 基于 OAuth 2.0 的企业级认证,支持多因素认证
-
-
-
-
-
快速部署
-
- Docker 一键部署,开箱即用,降低运维成本
-
-
-
-
-
易于扩展
-
- 模块化架构设计,支持自定义业务逻辑和第三方集成
-
-
+
+
+
+
核心特性
+
+ 围绕认证、部署和扩展体验整理基础能力,适合作为内部系统统一入口。
+
+
+
+ {features.map((feature) => {
+ const Icon = feature.icon;
+ return (
+
+
+
+
+
{feature.title}
+
+ {feature.description}
+
+
+ );
+ })}
diff --git a/frontend/src/components/header.tsx b/frontend/src/components/header.tsx
index 68260af..1138706 100644
--- a/frontend/src/components/header.tsx
+++ b/frontend/src/components/header.tsx
@@ -1,7 +1,7 @@
import Link from 'next/link';
import { useAuthStore } from '@/lib/auth-store';
import { getLoginUrl } from '@/lib/api';
-import { LogOut, User } from 'lucide-react';
+import { LogIn, LogOut, User } from 'lucide-react';
import * as Avatar from '@radix-ui/react-avatar';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
@@ -23,18 +23,23 @@ export default function Header() {
};
return (
-
-
-
- IMTIM Portal
+
+
+
+
+ IM
+
+
+ IMTIM Portal
+
-