mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 07:16:51 +00:00
页面交互与动画优化
This commit is contained in:
@@ -209,16 +209,7 @@ function AnnualReportPage() {
|
||||
return (
|
||||
<div className="annual-report-page">
|
||||
<Loader2 size={32} className="spin" style={{ color: 'var(--text-tertiary)' }} />
|
||||
<p style={{ color: 'var(--text-tertiary)', marginTop: 16 }}>正在加载年份数据(首批)...</p>
|
||||
<div className="load-telemetry compact">
|
||||
<p><span className="label">加载方式:</span>{getStrategyLabel({ loadStrategy, loadPhase, hasYearsLoadFinished, hasSwitchedStrategy, nativeTimedOut })}</p>
|
||||
<p><span className="label">状态:</span>{loadStatusText || '正在加载年份数据...'}</p>
|
||||
<p>
|
||||
<span className="label">原生耗时:</span>{formatLoadElapsed(nativeElapsedMs)}{nativeTimedOut ? '(超时)' : ''} |{' '}
|
||||
<span className="label">扫表耗时:</span>{formatLoadElapsed(scanElapsedMs)} |{' '}
|
||||
<span className="label">总耗时:</span>{formatLoadElapsed(totalElapsedMs)}
|
||||
</p>
|
||||
</div>
|
||||
<p style={{ color: 'var(--text-tertiary)', marginTop: 16 }}>正在准备年度报告...</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -264,30 +255,6 @@ function AnnualReportPage() {
|
||||
<Sparkles size={32} className="header-icon" />
|
||||
<h1 className="page-title">年度报告</h1>
|
||||
<p className="page-desc">选择年份,回顾你在微信里的点点滴滴</p>
|
||||
{loadedYearCount > 0 && (
|
||||
<p className={`page-desc load-summary ${isYearStatusComplete ? 'complete' : 'loading'}`}>
|
||||
{isYearStatusComplete ? (
|
||||
<>已显示 {loadedYearCount} 个年份,年份数据已全部加载完毕。总耗时 {formatLoadElapsed(totalElapsedMs)}</>
|
||||
) : (
|
||||
<>
|
||||
已显示 {loadedYearCount} 个年份,正在补充更多年份<span className="dot-ellipsis" aria-hidden="true">...</span>
|
||||
(已耗时 {formatLoadElapsed(totalElapsedMs)})
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
<div className={`load-telemetry ${isYearStatusComplete ? 'complete' : 'loading'}`}>
|
||||
<p><span className="label">加载方式:</span>{strategyLabel}</p>
|
||||
<p>
|
||||
<span className="label">状态:</span>
|
||||
{loadStatusText || (isYearStatusComplete ? '全部年份已加载完毕' : '正在加载年份数据...')}
|
||||
</p>
|
||||
<p>
|
||||
<span className="label">原生耗时:</span>{formatLoadElapsed(nativeElapsedMs)}{nativeTimedOut ? '(超时)' : ''} |{' '}
|
||||
<span className="label">扫表耗时:</span>{formatLoadElapsed(scanElapsedMs)} |{' '}
|
||||
<span className="label">总耗时:</span>{formatLoadElapsed(totalElapsedMs)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="report-sections">
|
||||
<section className="report-section">
|
||||
@@ -311,7 +278,6 @@ function AnnualReportPage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{renderYearLoadStatus()}
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -358,7 +324,6 @@ function AnnualReportPage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{renderYearLoadStatus()}
|
||||
</div>
|
||||
|
||||
<button
|
||||
|
||||
@@ -3854,12 +3854,6 @@ function ChatPage(props: ChatPageProps) {
|
||||
<button className="icon-btn refresh-btn" onClick={handleRefresh} disabled={isLoadingSessions || isRefreshingSessions}>
|
||||
<RefreshCw size={16} className={(isLoadingSessions || isRefreshingSessions) ? 'spin' : ''} />
|
||||
</button>
|
||||
{isSessionListSyncing && (
|
||||
<div className="session-sync-indicator">
|
||||
<Loader2 size={12} className="spin" />
|
||||
<span>同步中</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* 折叠群 header */}
|
||||
|
||||
@@ -891,28 +891,6 @@ function ContactsPage() {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="contacts-count">
|
||||
共 {filteredContacts.length} / {contacts.length} 个联系人
|
||||
{contactsUpdatedAt && (
|
||||
<span className="contacts-cache-meta">
|
||||
{contactsDataSource === 'cache' ? '缓存' : '最新'} · 更新于 {contactsUpdatedAtLabel}
|
||||
</span>
|
||||
)}
|
||||
{contacts.length > 0 && (
|
||||
<span className="contacts-cache-meta">
|
||||
头像缓存 {avatarCachedCount}/{contacts.length}
|
||||
{avatarCacheUpdatedAtLabel ? ` · 更新于 ${avatarCacheUpdatedAtLabel}` : ''}
|
||||
</span>
|
||||
)}
|
||||
{isLoading && contacts.length > 0 && (
|
||||
<span className="contacts-cache-meta syncing">后台同步中...</span>
|
||||
)}
|
||||
{avatarEnrichProgress.running && (
|
||||
<span className="avatar-enrich-progress">
|
||||
头像补全中 {avatarEnrichProgress.loaded}/{avatarEnrichProgress.total}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{exportMode && (
|
||||
<div className="selection-toolbar">
|
||||
|
||||
@@ -11,6 +11,33 @@
|
||||
padding: 28px 32px;
|
||||
background: rgba(15, 23, 42, 0.28);
|
||||
backdrop-filter: blur(10px);
|
||||
animation: settingsFadeIn 0.2s ease;
|
||||
|
||||
&.closing {
|
||||
animation: settingsFadeOut 0.2s ease forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes settingsFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
backdrop-filter: blur(0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes settingsFadeOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
backdrop-filter: blur(0);
|
||||
}
|
||||
}
|
||||
|
||||
.settings-page {
|
||||
@@ -25,6 +52,33 @@
|
||||
border-radius: 24px;
|
||||
box-shadow: 0 28px 80px rgba(15, 23, 42, 0.22);
|
||||
overflow: hidden;
|
||||
animation: settingsSlideUp 0.3s ease;
|
||||
|
||||
&.closing {
|
||||
animation: settingsSlideDown 0.2s ease forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes settingsSlideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px) scale(0.96);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes settingsSlideDown {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(20px) scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.settings-header {
|
||||
|
||||
@@ -134,6 +134,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
const [isClearingAnalyticsCache, setIsClearingAnalyticsCache] = useState(false)
|
||||
const [isClearingImageCache, setIsClearingImageCache] = useState(false)
|
||||
const [isClearingAllCache, setIsClearingAllCache] = useState(false)
|
||||
const [isClosing, setIsClosing] = useState(false)
|
||||
const saveTimersRef = useRef<Record<string, ReturnType<typeof setTimeout>>>({})
|
||||
|
||||
// 安全设置 state
|
||||
@@ -203,7 +204,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
if (!onClose) return
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
onClose()
|
||||
handleClose()
|
||||
}
|
||||
}
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
@@ -445,6 +446,14 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
setTimeout(() => setMessage(null), 3000)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
if (!onClose) return
|
||||
setIsClosing(true)
|
||||
setTimeout(() => {
|
||||
onClose()
|
||||
}, 200)
|
||||
}
|
||||
|
||||
type WxidKeys = {
|
||||
decryptKey: string
|
||||
imageXorKey: number | null
|
||||
@@ -2076,8 +2085,8 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="settings-modal-overlay" onClick={() => onClose?.()}>
|
||||
<div className="settings-page" onClick={(event) => event.stopPropagation()}>
|
||||
<div className={`settings-modal-overlay ${isClosing ? 'closing' : ''}`} onClick={handleClose}>
|
||||
<div className={`settings-page ${isClosing ? 'closing' : ''}`} onClick={(event) => event.stopPropagation()}>
|
||||
{message && <div className={`message-toast ${message.success ? 'success' : 'error'}`}>{message.text}</div>}
|
||||
|
||||
{/* 多账号选择对话框 */}
|
||||
@@ -2116,7 +2125,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
<Plug size={16} /> {isTesting ? '测试中...' : '测试连接'}
|
||||
</button>
|
||||
{onClose && (
|
||||
<button type="button" className="settings-close-btn" onClick={onClose} aria-label="关闭设置">
|
||||
<button type="button" className="settings-close-btn" onClick={handleClose} aria-label="关闭设置">
|
||||
<X size={18} />
|
||||
</button>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user