|
|
@@ -44,6 +44,9 @@ const SilverWisdomDetailPage: React.FC = () => {
|
|
|
const navigate = useNavigate();
|
|
|
const [isLiked, setIsLiked] = useState(false);
|
|
|
const [isBookmarked, setIsBookmarked] = useState(false);
|
|
|
+ const [pdfLoading, setPdfLoading] = useState(false);
|
|
|
+ const [pdfError, setPdfError] = useState(false);
|
|
|
+ const [showPdfPreview, setShowPdfPreview] = useState(true);
|
|
|
|
|
|
const { data, isLoading, error } = useSilverWisdomDetail(Number(id));
|
|
|
|
|
|
@@ -77,6 +80,149 @@ const SilverWisdomDetailPage: React.FC = () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ // 提前定义所有函数,避免条件渲染中的Hook调用问题
|
|
|
+ const getFileExtension = (filename: string) => {
|
|
|
+ return filename.split('.').pop()?.toLowerCase() || '';
|
|
|
+ };
|
|
|
+
|
|
|
+ const getFileIcon = (filename: string) => {
|
|
|
+ const ext = getFileExtension(filename);
|
|
|
+ switch (ext) {
|
|
|
+ case 'pdf':
|
|
|
+ return '📄';
|
|
|
+ case 'doc':
|
|
|
+ case 'docx':
|
|
|
+ return '📝';
|
|
|
+ case 'xls':
|
|
|
+ case 'xlsx':
|
|
|
+ return '📊';
|
|
|
+ case 'ppt':
|
|
|
+ case 'pptx':
|
|
|
+ return '📊';
|
|
|
+ case 'jpg':
|
|
|
+ case 'jpeg':
|
|
|
+ case 'png':
|
|
|
+ case 'gif':
|
|
|
+ return '🖼️';
|
|
|
+ default:
|
|
|
+ return '📎';
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const formatDate = (date: string) => {
|
|
|
+ return dayjs(date).format('YYYY年MM月DD日 HH:mm');
|
|
|
+ };
|
|
|
+
|
|
|
+ const getReadTime = (content: string) => {
|
|
|
+ const wordsPerMinute = 200;
|
|
|
+ const wordCount = content.length;
|
|
|
+ return Math.ceil(wordCount / wordsPerMinute);
|
|
|
+ };
|
|
|
+
|
|
|
+ const getCompatibilityMessage = () => {
|
|
|
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
|
+ const isWechat = /MicroMessenger/i.test(navigator.userAgent);
|
|
|
+ const isQQ = /QQ/i.test(navigator.userAgent);
|
|
|
+
|
|
|
+ if (isWechat || isQQ) {
|
|
|
+ return '微信/QQ内置浏览器暂不支持PDF预览,请使用系统浏览器打开';
|
|
|
+ }
|
|
|
+ if (isIOS && !checkPdfSupport()) {
|
|
|
+ return '建议使用Safari浏览器获得最佳PDF预览体验';
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 移动端PDF兼容性检测
|
|
|
+ const checkPdfSupport = () => {
|
|
|
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
|
+ const isWechat = /MicroMessenger/i.test(navigator.userAgent);
|
|
|
+ const isQQ = /QQ/i.test(navigator.userAgent);
|
|
|
+
|
|
|
+ // 禁用微信、QQ内置浏览器的PDF预览
|
|
|
+ if (isWechat || isQQ) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // iOS Safari支持较好,但部分版本有问题
|
|
|
+ if (isIOS) {
|
|
|
+ return navigator.userAgent.includes('Safari') &&
|
|
|
+ !navigator.userAgent.includes('CriOS') && // Chrome iOS
|
|
|
+ !navigator.userAgent.includes('FxiOS'); // Firefox iOS
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ const getResponsivePreviewHeight = () => {
|
|
|
+ const screenHeight = window.innerHeight;
|
|
|
+ return Math.min(320, screenHeight * 0.35); // 35%屏幕高度,最大320px
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDownload = () => {
|
|
|
+ if (data?.attachment) {
|
|
|
+ // 创建临时链接下载,避免直接打开可能的安全问题
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = data.attachment;
|
|
|
+ link.download = data.attachmentName || '附件';
|
|
|
+ link.target = '_blank';
|
|
|
+ link.rel = 'noopener noreferrer';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleShare = async () => {
|
|
|
+ if (!data) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (navigator.share) {
|
|
|
+ await navigator.share({
|
|
|
+ title: data.title,
|
|
|
+ text: data.content.substring(0, 100) + '...',
|
|
|
+ url: window.location.href,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 降级处理:复制到剪贴板
|
|
|
+ await navigator.clipboard.writeText(window.location.href);
|
|
|
+ alert('链接已复制到剪贴板');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('分享失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handlePdfPreview = () => {
|
|
|
+ if (!data?.attachment) return;
|
|
|
+
|
|
|
+ const isSupported = checkPdfSupport();
|
|
|
+ if (!isSupported) {
|
|
|
+ // 不支持的浏览器直接提供下载
|
|
|
+ setShowPdfPreview(false);
|
|
|
+ handleDownload();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ setShowPdfPreview(true);
|
|
|
+ setPdfLoading(true);
|
|
|
+ setPdfError(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 使用useEffect检查PDF支持并设置预览状态
|
|
|
+ React.useEffect(() => {
|
|
|
+ if (data?.attachment && getFileExtension(data.attachmentName || '') === 'pdf') {
|
|
|
+ const isSupported = checkPdfSupport();
|
|
|
+ setShowPdfPreview(isSupported);
|
|
|
+ // 如果支持,初始化加载状态
|
|
|
+ if (isSupported) {
|
|
|
+ setPdfLoading(true);
|
|
|
+ setPdfError(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [data?.attachment, data?.attachmentName]);
|
|
|
+
|
|
|
+ // 处理加载状态
|
|
|
if (isLoading) {
|
|
|
return (
|
|
|
<div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: COLORS.ink.light }}>
|
|
|
@@ -88,12 +234,13 @@ const SilverWisdomDetailPage: React.FC = () => {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ // 处理错误状态
|
|
|
if (error || !data) {
|
|
|
return (
|
|
|
<div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: COLORS.ink.light }}>
|
|
|
<div className="text-center">
|
|
|
<p style={{ color: COLORS.text.primary }}>获取知识详情失败</p>
|
|
|
- <button
|
|
|
+ <button
|
|
|
onClick={() => navigate('/silver-wisdom')}
|
|
|
className="mt-4 px-4 py-2 rounded-full text-white transition-colors"
|
|
|
style={{ backgroundColor: COLORS.ink.dark }}
|
|
|
@@ -105,7 +252,7 @@ const SilverWisdomDetailPage: React.FC = () => {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- const knowledge = data || {};
|
|
|
+ const knowledge = data;
|
|
|
|
|
|
// 解析标签
|
|
|
const tags = knowledge.tags ? String(knowledge.tags).split(',').map(tag => tag.trim()).filter(tag => tag) : [];
|
|
|
@@ -142,6 +289,34 @@ const SilverWisdomDetailPage: React.FC = () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ // 获取兼容性提示信息
|
|
|
+ const getCompatibilityMessage = () => {
|
|
|
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
|
+ const isWechat = /MicroMessenger/i.test(navigator.userAgent);
|
|
|
+ const isQQ = /QQ/i.test(navigator.userAgent);
|
|
|
+
|
|
|
+ if (isWechat || isQQ) {
|
|
|
+ return '微信/QQ内置浏览器暂不支持PDF预览,请使用系统浏览器打开';
|
|
|
+ }
|
|
|
+ if (isIOS && !checkPdfSupport()) {
|
|
|
+ return '建议使用Safari浏览器获得最佳PDF预览体验';
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 使用useEffect检查PDF支持并设置预览状态
|
|
|
+ React.useEffect(() => {
|
|
|
+ if (knowledge.attachment && getFileExtension(knowledge.attachmentName || '') === 'pdf') {
|
|
|
+ const isSupported = checkPdfSupport();
|
|
|
+ setShowPdfPreview(isSupported);
|
|
|
+ // 如果支持,初始化加载状态
|
|
|
+ if (isSupported) {
|
|
|
+ setPdfLoading(true);
|
|
|
+ setPdfError(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [knowledge.attachment, knowledge.attachmentName]);
|
|
|
+
|
|
|
const getFileExtension = (filename: string) => {
|
|
|
return filename.split('.').pop()?.toLowerCase() || '';
|
|
|
};
|
|
|
@@ -180,6 +355,48 @@ const SilverWisdomDetailPage: React.FC = () => {
|
|
|
return Math.ceil(wordCount / wordsPerMinute);
|
|
|
};
|
|
|
|
|
|
+ // 移动端PDF兼容性检测
|
|
|
+ const checkPdfSupport = () => {
|
|
|
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
|
+ const isWechat = /MicroMessenger/i.test(navigator.userAgent);
|
|
|
+ const isQQ = /QQ/i.test(navigator.userAgent);
|
|
|
+
|
|
|
+ // 禁用微信、QQ内置浏览器的PDF预览
|
|
|
+ if (isWechat || isQQ) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // iOS Safari支持较好,但部分版本有问题
|
|
|
+ if (isIOS) {
|
|
|
+ return navigator.userAgent.includes('Safari') &&
|
|
|
+ !navigator.userAgent.includes('CriOS') && // Chrome iOS
|
|
|
+ !navigator.userAgent.includes('FxiOS'); // Firefox iOS
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ const getResponsivePreviewHeight = () => {
|
|
|
+ const screenHeight = window.innerHeight;
|
|
|
+ return Math.min(320, screenHeight * 0.35); // 35%屏幕高度,最大320px
|
|
|
+ };
|
|
|
+
|
|
|
+ const handlePdfPreview = () => {
|
|
|
+ if (!knowledge.attachment) return;
|
|
|
+
|
|
|
+ const isSupported = checkPdfSupport();
|
|
|
+ if (!isSupported) {
|
|
|
+ // 不支持的浏览器直接提供下载
|
|
|
+ setShowPdfPreview(false);
|
|
|
+ handleDownload();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ setShowPdfPreview(true);
|
|
|
+ setPdfLoading(true);
|
|
|
+ setPdfError(false);
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<div className="min-h-screen" style={{ backgroundColor: COLORS.ink.light }}>
|
|
|
{/* 头部导航 */}
|
|
|
@@ -320,15 +537,89 @@ const SilverWisdomDetailPage: React.FC = () => {
|
|
|
{/* 文件预览 - 仅对支持的格式显示 */}
|
|
|
{getFileExtension(knowledge.attachmentName || '') === 'pdf' && (
|
|
|
<div className="mt-4 border-t pt-4" style={{ borderColor: COLORS.ink.medium }}>
|
|
|
- <p className="text-sm mb-2" style={{ color: COLORS.text.secondary }}>
|
|
|
- 文件预览:
|
|
|
- </p>
|
|
|
- <iframe
|
|
|
- src={knowledge.attachment}
|
|
|
- className="w-full h-64 rounded-lg border"
|
|
|
- style={{ borderColor: COLORS.ink.medium }}
|
|
|
- title={knowledge.attachmentName || 'PDF预览'}
|
|
|
- />
|
|
|
+ {getCompatibilityMessage() && (
|
|
|
+ <div className="p-3 rounded-lg mb-3"
|
|
|
+ style={{ backgroundColor: 'rgba(255,248,220,0.8)', borderColor: COLORS.accent.red }}
|
|
|
+ >
|
|
|
+ <p className="text-xs" style={{ color: COLORS.accent.red }}>
|
|
|
+ {getCompatibilityMessage()}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {showPdfPreview && (
|
|
|
+ <>
|
|
|
+ <div className="flex items-center justify-between mb-2">
|
|
|
+ <p className="text-sm" style={{ color: COLORS.text.secondary }}>
|
|
|
+ 文件预览:
|
|
|
+ </p>
|
|
|
+ <button
|
|
|
+ onClick={handleDownload}
|
|
|
+ className="text-xs px-2 py-1 rounded"
|
|
|
+ style={{
|
|
|
+ backgroundColor: COLORS.ink.medium,
|
|
|
+ color: COLORS.text.primary
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 下载查看
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {pdfLoading && (
|
|
|
+ <div className="w-full h-48 flex items-center justify-center rounded-lg border"
|
|
|
+ style={{ borderColor: COLORS.ink.medium, backgroundColor: 'rgba(255,255,255,0.5)' }}
|
|
|
+ >
|
|
|
+ <div className="text-center">
|
|
|
+ <div className="animate-spin rounded-full h-6 w-6 border-b-2 mx-auto"
|
|
|
+ style={{ borderColor: COLORS.ink.dark }}
|
|
|
+ ></div>
|
|
|
+ <p className="text-xs mt-2" style={{ color: COLORS.text.secondary }}>
|
|
|
+ PDF加载中...
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {pdfError && (
|
|
|
+ <div className="w-full h-48 flex items-center justify-center rounded-lg border"
|
|
|
+ style={{ borderColor: COLORS.ink.medium, backgroundColor: 'rgba(255,255,255,0.5)' }}
|
|
|
+ >
|
|
|
+ <div className="text-center">
|
|
|
+ <p className="text-sm" style={{ color: COLORS.text.primary }}>
|
|
|
+ 预览加载失败
|
|
|
+ </p>
|
|
|
+ <button
|
|
|
+ onClick={handleDownload}
|
|
|
+ className="text-xs mt-2 px-3 py-1 rounded"
|
|
|
+ style={{
|
|
|
+ backgroundColor: COLORS.ink.dark,
|
|
|
+ color: 'white'
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 下载查看
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {!pdfLoading && !pdfError && (
|
|
|
+ <iframe
|
|
|
+ src={knowledge.attachment}
|
|
|
+ className="w-full rounded-lg border"
|
|
|
+ style={{
|
|
|
+ borderColor: COLORS.ink.medium,
|
|
|
+ height: `${getResponsivePreviewHeight()}px`
|
|
|
+ }}
|
|
|
+ title={knowledge.attachmentName || 'PDF预览'}
|
|
|
+ onLoad={() => setPdfLoading(false)}
|
|
|
+ onError={() => {
|
|
|
+ setPdfLoading(false);
|
|
|
+ setPdfError(true);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ )}
|
|
|
</div>
|
|
|
)}
|
|
|
</div>
|