doctor-mail/apps/web/src/components/models/post/detail/PostResources.tsx

125 lines
3.9 KiB
TypeScript
Raw Normal View History

2025-01-26 12:48:10 +08:00
import React, { useMemo } from "react";
2025-01-26 21:01:45 +08:00
import { Image, Button, Row, Col, Tooltip } from "antd";
2025-01-25 21:20:54 +08:00
import { PostDto } from "@nice/common";
2025-01-26 12:48:10 +08:00
import { env } from "@web/src/env";
import { getFileIcon } from "./utils";
2025-01-26 19:36:54 +08:00
import { formatFileSize, getCompressedImageUrl } from '@nice/utils';
2025-01-27 00:29:19 +08:00
import { useNavigate } from "react-router-dom";
2025-01-26 19:36:54 +08:00
2025-01-25 19:51:08 +08:00
export default function PostResources({ post }: { post: PostDto }) {
2025-01-26 12:48:10 +08:00
const { resources } = useMemo(() => {
if (!post?.resources) return { resources: [] };
2025-01-25 21:20:54 +08:00
2025-01-26 15:29:31 +08:00
const isImage = (url: string) =>
/\.(png|jpg|jpeg|gif|webp)$/i.test(url);
2025-01-25 19:51:08 +08:00
2025-01-26 19:36:54 +08:00
const sortedResources = post.resources.map(resource => {
const original = `http://${env.SERVER_IP}/uploads/${resource.url}`
const isImg = isImage(resource.url)
return {
2025-01-26 12:48:10 +08:00
...resource,
2025-01-26 19:36:54 +08:00
url: isImg ? getCompressedImageUrl(original) : original,
originalUrl: original,
isImage: isImg
}
}).sort((a, b) => a.isImage === b.isImage ? 0 : a.isImage ? -1 : 1)
2025-01-26 12:48:10 +08:00
return { resources: sortedResources };
2025-01-25 21:20:54 +08:00
}, [post]);
2025-01-25 19:51:08 +08:00
2025-01-26 12:48:10 +08:00
const imageResources = resources.filter((res) => res.isImage);
const fileResources = resources.filter((res) => !res.isImage);
2025-01-25 19:51:08 +08:00
return (
2025-01-26 12:48:10 +08:00
<div className="space-y-6">
{imageResources.length > 0 && (
<Row gutter={[16, 16]} className="mb-6">
<Image.PreviewGroup>
{imageResources.map((resource) => (
<Col
key={resource.url}
xs={12}
sm={8}
md={6}
lg={6}
xl={4}
2025-01-26 15:29:31 +08:00
className="relative">
2025-01-27 00:29:19 +08:00
<div className="relative aspect-square rounded-lg overflow-hidden bg-gray-100">
2025-01-26 12:48:10 +08:00
<div className="w-full h-full">
<Image
src={resource.url}
alt={resource.title}
preview={{
2025-01-26 19:36:54 +08:00
src: resource.originalUrl,
2025-01-26 12:48:10 +08:00
mask: (
<div className="flex items-center justify-center text-white">
</div>
),
}}
style={{
position: "absolute",
inset: 0,
width: "100%",
height: "100%",
objectFit: "cover",
}}
rootClassName="w-full h-full"
/>
</div>
{resource.title && (
<div className="absolute bottom-0 left-0 right-0 p-3 bg-gradient-to-t from-black/60 to-transparent text-white text-sm truncate">
{resource.title}
</div>
)}
</div>
</Col>
))}
</Image.PreviewGroup>
</Row>
)}
{fileResources.length > 0 && (
2025-01-26 21:01:45 +08:00
<div className="rounded-xl p-1 border border-gray-100 bg-white">
<div className="flex flex-nowrap overflow-x-auto scrollbar-hide gap-1.5">
{fileResources.map((resource) => {
return (
<a
key={resource.url}
className="flex-shrink-0 relative active:scale-95 transition-transform select-none "
href={resource.originalUrl}
target="_blank"
download={true}
title="点击下载文件"
>
{/* 超紧凑卡片容器 */}
<div className="w-[120px] h-[80px] p-2 flex flex-col items-center justify-between rounded-xl hover:bg-primary-50/40 cursor-pointer">
{/* 微型文件图标 */}
<div className="text-primary-600 text-base">
{getFileIcon(resource.url)}
</div>
{/* 压缩信息展示 */}
<div className="w-full text-center space-y-0.5">
<p className="text-xs font-medium text-gray-800 truncate">
{resource.title?.slice(0, 12) || "未命名"}
</p>
<div className="flex items-center justify-between text-xs text-gray-500">
<span className="bg-gray-100 px-0.5 rounded-sm">
{resource.url.split(".").pop()?.slice(0, 4).toUpperCase()}
</span>
<span>
{resource.meta.size && formatFileSize(resource.meta.size)}
</span>
</div>
2025-01-26 12:48:10 +08:00
</div>
</div>
2025-01-26 21:01:45 +08:00
</a>
);
})}
2025-01-26 12:48:10 +08:00
</div>
</div>
)}
2025-01-25 19:51:08 +08:00
</div>
);
2025-01-26 15:29:31 +08:00
}