feat:首页调整

dev_na
puz 2026-06-30 15:25:51 +08:00
parent d36beec479
commit 1ab6e37fe1
2 changed files with 180 additions and 145 deletions

View File

@ -3,15 +3,41 @@
@home-text-gray: #475569; // ui-ux-pro-max slate-600 @home-text-gray: #475569; // ui-ux-pro-max slate-600
@home-bg: #f8fafc; // ui-ux-pro-max slate-50 @home-bg: #f8fafc; // ui-ux-pro-max slate-50
.home-page {
padding: 8px;
min-width: 0;
background: #f5f6fa;
}
.home-page > .page-container__body {
padding: 0;
overflow: hidden;
border: none;
border-radius: 0;
background: transparent;
}
.home-shell-card .section-card__content {
padding: 8px;
}
.home-data-panel .data-list-panel__table-area,
.home-data-panel .app-page__table-wrap {
height: 100%;
min-height: 0;
}
.home-container { .home-container {
position: relative; position: relative;
flex: 1; flex: 1;
min-height: 100%; // Changed from height: 100% to avoid height conflicts height: 100%;
padding: clamp(40px, 8vh, 80px) clamp(24px, 5vw, 60px) 0; // Top shift down, ZERO bottom padding min-height: 100%;
padding: clamp(40px, 8vh, 80px) clamp(24px, 5vw, 60px) 0;
border-radius: 4px;
background: linear-gradient(135deg, #ffffff 0%, #f1f5f9 100%); background: linear-gradient(135deg, #ffffff 0%, #f1f5f9 100%);
color: @home-text-main; color: @home-text-main;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
overflow-x: hidden; overflow: hidden auto;
z-index: 1; z-index: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -9,6 +9,9 @@ import { useNavigate } from "react-router-dom";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { getRecentTasks } from "@/api/business/dashboard"; import { getRecentTasks } from "@/api/business/dashboard";
import { getMeetingCreateConfig, type MeetingCreateConfig, type MeetingVO } from "@/api/business/meeting"; import { getMeetingCreateConfig, type MeetingCreateConfig, type MeetingVO } from "@/api/business/meeting";
import DataListPanel from "@/components/shared/DataListPanel";
import PageContainer from "@/components/shared/PageContainer";
import SectionCard from "@/components/shared/SectionCard";
import "./index.less"; import "./index.less";
import RightVisual from "./RightVisual"; import RightVisual from "./RightVisual";
import { MeetingCreateDrawer, MeetingCreateType } from "@/components/business/MeetingCreateDrawer"; import { MeetingCreateDrawer, MeetingCreateType } from "@/components/business/MeetingCreateDrawer";
@ -193,156 +196,162 @@ export default function HomePage() {
}; };
return ( return (
<main className="home-container"> <PageContainer title={null} className="home-page">
{/* Massive Abstract Background Sphere matching the design/img.png */} <SectionCard className="home-shell-card">
<div className="home-bg-visual" aria-hidden="true"> <DataListPanel className="home-data-panel">
<div className="home-bg-sphere" /> <main className="home-container">
<RightVisual /> {/* Massive Abstract Background Sphere matching the design/img.png */}
</div> <div className="home-bg-visual" aria-hidden="true">
<div className="home-bg-sphere" />
<RightVisual />
</div>
<div className="home-content-wrapper"> <div className="home-content-wrapper">
<header className="home-hero"> <header className="home-hero">
<Title level={1} className="home-title"> <Title level={1} className="home-title">
<span className="home-title-accent-wrapper"> <span className="home-title-accent-wrapper">
<span <span
className="home-title-accent-scroller" className="home-title-accent-scroller"
style={{ transform: `translateY(-${wordIndex * 1.2}em)` }} style={{ transform: `translateY(-${wordIndex * 1.2}em)` }}
> >
{ROTATING_WORDS.map((word) => ( {ROTATING_WORDS.map((word) => (
<span key={word} className="home-title-accent"> <span key={word} className="home-title-accent">
{word} {word}
</span>
))}
</span>
</span> </span>
))} </Title>
</span>
</span> <div className="home-quick-actions">
</Title> {configLoaded ? (
visibleQuickEntries.length > 0 ? visibleQuickEntries.map((entry) => (
<div className="home-quick-actions"> <div
{configLoaded ? ( className={`home-action-item home-action-item--${entry.accent}`}
visibleQuickEntries.length > 0 ? visibleQuickEntries.map((entry) => ( onClick={entry.onClick}
<div key={entry.title}
className={`home-action-item home-action-item--${entry.accent}`} >
onClick={entry.onClick} <div className="home-action-badge">{entry.badge}</div>
key={entry.title} <div className="home-action-icon-wrapper">
> <div className="home-action-icon">{entry.icon}</div>
<div className="home-action-badge">{entry.badge}</div> <div className="home-action-icon-glow" />
<div className="home-action-icon-wrapper"> <div className="home-action-icon-circle" />
<div className="home-action-icon">{entry.icon}</div> </div>
<div className="home-action-icon-glow" /> <Title level={3} className="home-action-title">{entry.title}</Title>
<div className="home-action-icon-circle" /> <div className="home-action-desc">
</div> {entry.description.map((line) => (
<Title level={3} className="home-action-title">{entry.title}</Title> <Text key={line} className="home-action-line">
<div className="home-action-desc"> {line}
{entry.description.map((line) => ( </Text>
<Text key={line} className="home-action-line"> ))}
{line} </div>
</Text> </div>
)) : (
<div className="home-action-item home-action-item--cyan" style={{ cursor: "default", opacity: 0.7 }}>
<div className="home-action-badge"></div>
<div className="home-action-icon-wrapper">
<div className="home-action-icon"><AudioOutlined /></div>
<div className="home-action-icon-glow" />
<div className="home-action-icon-circle" />
</div>
<Title level={3} className="home-action-title"></Title>
<div className="home-action-desc">
<Text className="home-action-line">线</Text>
</div>
</div>
)
) : (
// Loading state for quick actions to prevent jump
[...Array(2)].map((_, i) => (
<div key={i} className="home-action-item home-action-item--loading" style={{ background: 'rgba(255,255,255,0.4)', border: '1px dashed rgba(0,0,0,0.05)' }}>
<Skeleton active avatar paragraph={{ rows: 2 }} />
</div>
))
)}
</div>
</header>
<section className="home-recent-section">
<div className="home-section-header">
<Title level={3}></Title>
<Button type="link" onClick={() => navigate("/meetings")} className="home-view-all">
&gt;
</Button>
</div>
{loading ? (
<div className="home-recent-grid">
{[...Array(4)].map((_, i) => (
<div key={i} className="home-recent-skeleton">
<Skeleton active paragraph={{ rows: 2 }} title={{ width: "60%" }} />
</div>
))} ))}
</div> </div>
</div> ) : recentCards.length ? (
)) : ( <div className="home-recent-grid">
<div className="home-action-item home-action-item--cyan" style={{ cursor: "default", opacity: 0.7 }}> {recentCards.slice(0, 4).map((card) => (
<div className="home-action-badge"></div> <article
<div className="home-action-icon-wrapper"> key={card.id}
<div className="home-action-icon"><AudioOutlined /></div> className="home-recent-card"
<div className="home-action-icon-glow" /> onClick={() => handleRecentCardClick(card)}
<div className="home-action-icon-circle" /> onKeyDown={(event) => {
</div> if (event.key === "Enter" || event.key === " ") {
<Title level={3} className="home-action-title"></Title> event.preventDefault();
<div className="home-action-desc"> handleRecentCardClick(card);
<Text className="home-action-line">线</Text> }
</div> }}
</div> role="button"
) tabIndex={0}
) : ( >
// Loading state for quick actions to prevent jump {/* {!readCardIds.includes(String(card.id)) && <span className="home-recent-card-dot" />} */}
[...Array(2)].map((_, i) => ( <div className="home-recent-card-head">
<div key={i} className="home-action-item home-action-item--loading" style={{ background: 'rgba(255,255,255,0.4)', border: '1px dashed rgba(0,0,0,0.05)' }}> <Title level={4} className="home-recent-card-title">{card.title}</Title>
<Skeleton active avatar paragraph={{ rows: 2 }} /> <div className="home-recent-card-icon">
</div> <VideoCameraOutlined className="home-recent-card-play-icon" />
)) </div>
)} </div>
</div> <div className="home-recent-card-tags">
</header> {recentTaskMap.get(String(card.id))?.meetingSource && (
<Tag key={`${card.id}-source`} className="home-recent-card-tag" bordered={false}>
<section className="home-recent-section"> {recentTaskMap.get(String(card.id))?.meetingSource === "ANDROID" ? "安卓端" : "Web端"}
<div className="home-section-header"> </Tag>
<Title level={3}></Title> )}
<Button type="link" onClick={() => navigate("/meetings")} className="home-view-all"> {card.tags.slice(0, 4).map((tag) => (
&gt; <Tag key={`${card.id}-${tag}`} className="home-recent-card-tag" bordered={false}>
</Button> {tag}
</div> </Tag>
))}
{loading ? ( </div>
<div className="home-recent-grid"> <div className="home-recent-card-footer">
{[...Array(4)].map((_, i) => ( <span className="home-recent-card-duration">{card.duration}</span>
<div key={i} className="home-recent-skeleton"> <span className="home-recent-card-time">{card.time}</span>
<Skeleton active paragraph={{ rows: 2 }} title={{ width: "60%" }} /> </div>
</div> </article>
))}
</div>
) : recentCards.length ? (
<div className="home-recent-grid">
{recentCards.slice(0, 4).map((card) => (
<article
key={card.id}
className="home-recent-card"
onClick={() => handleRecentCardClick(card)}
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
handleRecentCardClick(card);
}
}}
role="button"
tabIndex={0}
>
{/* {!readCardIds.includes(String(card.id)) && <span className="home-recent-card-dot" />} */}
<div className="home-recent-card-head">
<Title level={4} className="home-recent-card-title">{card.title}</Title>
<div className="home-recent-card-icon">
<VideoCameraOutlined className="home-recent-card-play-icon" />
</div>
</div>
<div className="home-recent-card-tags">
{recentTaskMap.get(String(card.id))?.meetingSource && (
<Tag key={`${card.id}-source`} className="home-recent-card-tag" bordered={false}>
{recentTaskMap.get(String(card.id))?.meetingSource === "ANDROID" ? "安卓端" : "Web端"}
</Tag>
)}
{card.tags.slice(0, 4).map((tag) => (
<Tag key={`${card.id}-${tag}`} className="home-recent-card-tag" bordered={false}>
{tag}
</Tag>
))} ))}
</div> </div>
<div className="home-recent-card-footer"> ) : (
<span className="home-recent-card-duration">{card.duration}</span> <div className="home-empty-state">
<span className="home-recent-card-time">{card.time}</span> <Empty description="暂无最近记录" />
</div> </div>
</article> )}
))} </section>
</div> </div>
) : (
<div className="home-empty-state">
<Empty description="暂无最近记录" />
</div>
)}
</section>
</div>
<MeetingCreateDrawer <MeetingCreateDrawer
open={drawerOpen} open={drawerOpen}
initialType={drawerType} initialType={drawerType}
onCancel={() => setDrawerOpen(false)} onCancel={() => setDrawerOpen(false)}
onSuccess={() => { onSuccess={() => {
setDrawerOpen(false); setDrawerOpen(false);
// onSuccess doesn't return meeting id in MeetingCreateDrawerProps right now // onSuccess doesn't return meeting id in MeetingCreateDrawerProps right now
// the Drawer handles its own navigation or we can just redirect to meetings list // the Drawer handles its own navigation or we can just redirect to meetings list
navigate('/meetings'); navigate('/meetings');
}} }}
/> />
</main> </main>
</DataListPanel>
</SectionCard>
</PageContainer>
); );
} }