feat: 统一页面调度体系 — 全局互斥 + 动态尺寸 + 账户信息页
PageDispatcher 重构: - singleton + floatingPanels[] 双状态 → 单一 activePanel 状态 - 全局互斥:已打开面板时禁止打开新面板(保留拖拽/图片拖放等互操作) - 占位组件预计算为模块级 Map,消除 ESLint static-components 误报 - PAGE_MAP 支持 width/height 配置,动态函数计算(视口比例自适应) - 容器默认尺寸改为动态:Modal=min(w*0.55,720) Drawer=min(w*0.38,520) - 修复 FloatingPanel 未接收 width/height 配置的问题 Test2 账户信息页: - AuthAPI.getUserInfo() → 三卡片布局(积分/套餐/今日统计) - 加载态 Skeleton / 错误态 Result+重试 - centToYuan 积分转换、formatDate 日期格式化 目录调整:wechat-work/ → headers/ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
98
src/pages/headers/WechatWorkPage.tsx
Normal file
98
src/pages/headers/WechatWorkPage.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
// ============================================================
|
||||
// WechatWorkPage — 企业微信二维码 Modal 内容
|
||||
//
|
||||
// 点击导航栏"企业微信"后以 Modal 形式展示二维码。
|
||||
// 数据来源:GET /api/v1/creatives(Banner API)
|
||||
//
|
||||
// 识别逻辑:Banner 中 category === 'promotion' 的条目,
|
||||
// 其 image_url 为企业微信二维码图片
|
||||
// ============================================================
|
||||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { Spin, Empty } from 'antd';
|
||||
import { WechatOutlined } from '@ant-design/icons';
|
||||
import { fetchBanners, type Banner } from '@/services/modules/banner';
|
||||
|
||||
export function WechatWorkPage() {
|
||||
const [banner, setBanner] = useState<Banner | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const list = await fetchBanners();
|
||||
// category === 'promotion' → 企业微信二维码
|
||||
const promotion = list.find(
|
||||
(item) => item.is_active && item.category === 'promotion',
|
||||
);
|
||||
setBanner(promotion ?? null);
|
||||
} catch (err) {
|
||||
setError((err as Error).message || '加载失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
void load();
|
||||
}, [load]);
|
||||
|
||||
// 加载态
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', padding: 48 }}>
|
||||
<Spin description="加载中..." />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 无数据 / 错误
|
||||
if (error || !banner || !banner.image_url) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', padding: 48 }}>
|
||||
<Empty
|
||||
image={<WechatOutlined style={{ fontSize: 48, color: '#9CA3AF' }} />}
|
||||
description={error || '暂未获取到企业微信二维码,请联系管理员'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, padding: 8 }}>
|
||||
{/* 二维码图片 */}
|
||||
<div
|
||||
style={{
|
||||
width: 240,
|
||||
height: 240,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 8,
|
||||
background: '#fff',
|
||||
border: '1px solid #E5E7EB',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={banner.image_url}
|
||||
alt="企业微信二维码"
|
||||
style={{ width: '100%', height: '100%', objectFit: 'contain' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 标题(如果 Banner 有标题则显示) */}
|
||||
{banner.title && (
|
||||
<p style={{ margin: 0, fontSize: 14, fontWeight: 500, color: 'inherit' }}>
|
||||
{banner.title}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* 提示文字 */}
|
||||
<p style={{ margin: 0, fontSize: 13, color: 'inherit', opacity: 0.5 }}>
|
||||
请使用微信扫描二维码添加企业微信
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user