Kaynağa Gözat

✨ feat(policy-news): 优化政策资讯图片展示逻辑

- 图片来源优先使用关联文件,兼容旧的images字段
- 详情页图片布局优化:单图时大图展示,多图时分网格布局
- 仅展示图片类型文件,过滤非图片格式
- 修复图片加载错误处理逻辑
- 优化图片网格布局,3张图片时首图占2列宽

✨ feat(types): 添加政策资讯文件类型定义

- 为PolicyNewsItem添加files字段类型定义
- 定义文件对象结构,包含id、name、type、fullUrl等属性
yourname 7 ay önce
ebeveyn
işleme
dc7a88bcc1

+ 23 - 8
src/client/mobile/components/PolicyNewsCard.tsx

@@ -43,13 +43,22 @@ const PolicyNewsCard: React.FC<PolicyNewsCardProps> = ({ news, onClick }) => {
   };
 
   const getFirstImage = () => {
-    if (imageError || !news.images) {
+    if (imageError) {
       return PLACEHOLDER_IMAGE;
     }
     
-    // 处理 images 字符串,可能是单个URL或逗号分隔的多个URL
-    const images = news.images.split(',');
-    return images[0]?.trim() || PLACEHOLDER_IMAGE;
+    // 优先使用关联的文件
+    if (news.files && news.files.length > 0) {
+      return news.files[0].fullUrl;
+    }
+    
+    // 兼容旧的 images 字段
+    if (news.images) {
+      const images = news.images.split(',');
+      return images[0]?.trim() || PLACEHOLDER_IMAGE;
+    }
+    
+    return PLACEHOLDER_IMAGE;
   };
 
   const formatDate = (date: string | Date) => {
@@ -181,12 +190,18 @@ export const PolicyNewsCardSimple: React.FC<PolicyNewsCardProps> = ({ news, onCl
   };
 
   const getThumbnailImage = () => {
-    if (!news.images) {
-      return PLACEHOLDER_IMAGE;
+    // 优先使用关联的文件
+    if (news.files && news.files.length > 0) {
+      return news.files[0].fullUrl;
+    }
+    
+    // 兼容旧的 images 字段
+    if (news.images) {
+      const images = news.images.split(',');
+      return images[0]?.trim() || PLACEHOLDER_IMAGE;
     }
     
-    const images = news.images.split(',');
-    return images[0]?.trim() || PLACEHOLDER_IMAGE;
+    return PLACEHOLDER_IMAGE;
   };
 
   return (

+ 9 - 0
src/client/mobile/hooks/usePolicyNewsData.ts

@@ -17,6 +17,15 @@ interface PolicyNewsItem {
   isDeleted: number;
   createdAt: string | Date;
   updatedAt: string | Date;
+  files?: Array<{
+    id: number;
+    name: string;
+    type: string | null;
+    size: number | null;
+    path: string;
+    fullUrl: string;
+    description: string | null;
+  }>;
 }
 
 interface PolicyNewsResponse {

+ 47 - 11
src/client/mobile/pages/PolicyNewsDetailPage.tsx

@@ -119,16 +119,39 @@ const PolicyNewsDetailPage: React.FC = () => {
     });
   };
 
-  const images = news.images ? [news.images] : [];
+  // 获取政策资讯的图片列表
+  const getImages = () => {
+    const images: string[] = [];
+    
+    // 优先使用关联的文件
+    if (news.files && news.files.length > 0) {
+      news.files.forEach(file => {
+        // 只添加图片类型的文件
+        if (file.type && file.type.startsWith('image/')) {
+          images.push(file.fullUrl);
+        }
+      });
+    }
+    
+    // 如果没有关联的图片文件,使用旧的 images 字段
+    if (images.length === 0 && news.images) {
+      const legacyImages = news.images.split(',').map(img => img.trim()).filter(img => img);
+      images.push(...legacyImages);
+    }
+    
+    return images;
+  };
+
+  const images = getImages();
 
   return (
     <div className="min-h-screen pb-16" style={{ backgroundColor: COLORS.ink.light }}>
       {/* 头部导航 */}
-      <header 
+      <header
         className="sticky top-0 z-10 shadow-sm border-b border-opacity-20"
-        style={{ 
+        style={{
           backgroundColor: COLORS.ink.light,
-          borderColor: COLORS.ink.medium 
+          borderColor: COLORS.ink.medium
         }}
       >
         <div className="px-4 py-4 flex items-center justify-between">
@@ -190,7 +213,7 @@ const PolicyNewsDetailPage: React.FC = () => {
                 <span>{news.viewCount} 阅读</span>
               </div>
             </div>
-            <span 
+            <span
               className="px-3 py-1 rounded-full text-xs"
               style={{
                 backgroundColor: COLORS.accent.blue,
@@ -204,18 +227,31 @@ const PolicyNewsDetailPage: React.FC = () => {
 
         {/* 图片展示 */}
         {images.length > 0 && (
-          <div className="grid grid-cols-1 gap-4">
-            {images.map((image, index) => (
+          <div className="space-y-4">
+            {images.length === 1 ? (
               <img
-                key={index}
-                src={image.trim()}
-                alt={`政策资讯图片 ${index + 1}`}
+                src={images[0]}
+                alt={`政策资讯图片`}
                 className="w-full h-64 object-cover rounded-xl"
                 onError={(e) => {
                   (e.target as HTMLImageElement).src = '/images/placeholder-banner.jpg';
                 }}
               />
-            ))}
+            ) : (
+              <div className="grid grid-cols-2 gap-3">
+                {images.slice(0, 4).map((image, index) => (
+                  <img
+                    key={index}
+                    src={image}
+                    alt={`政策资讯图片 ${index + 1}`}
+                    className={`w-full object-cover rounded-lg ${images.length === 3 && index === 0 ? 'col-span-2 h-48' : 'h-32'}`}
+                    onError={(e) => {
+                      (e.target as HTMLImageElement).src = '/images/placeholder-banner.jpg';
+                    }}
+                  />
+                ))}
+              </div>
+            )}
           </div>
         )}