This commit is contained in:
ditiqi 2025-01-26 19:43:27 +08:00
commit fe4a7cfae3
6 changed files with 33 additions and 23 deletions

View File

@ -3,7 +3,7 @@ import { motion } from "framer-motion";
import { Button, Input, Tabs } from "antd";
import QuillEditor from "@web/src/components/common/editor/quill/QuillEditor";
import { PostDetailContext } from "./context/PostDetailContext";
import { usePost } from "@nice/client";
import { useEntity } from "@nice/client";
import { PostType } from "@nice/common";
import toast from "react-hot-toast";
import { isContentEmpty } from "./utils";
@ -18,8 +18,7 @@ export default function PostCommentEditor() {
const [content, setContent] = useState("");
const [signature, setSignature] = useState<string | undefined>(undefined);
const [fileIds, setFileIds] = useState<string[]>([]);
const { create } = usePost();
const { create } = useEntity("post")
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (isContentEmpty(content)) {

View File

@ -1,7 +1,6 @@
import { useContext } from "react";
import { useState, useRef, useEffect } from "react";
import { PostDetailContext } from "../context/PostDetailContext";
import { motion } from "framer-motion";
import { StatsSection } from "./StatsSection";
import PostResources from "../PostResources";
@ -10,7 +9,7 @@ export default function Content() {
const [isExpanded, setIsExpanded] = useState(false);
const contentWrapperRef = useRef(null);
const [shouldCollapse, setShouldCollapse] = useState(false);
const maxHeight = 125;
useEffect(() => {
if (contentWrapperRef.current) {
const shouldCollapse = contentWrapperRef.current.scrollHeight > 150;

View File

@ -4,7 +4,9 @@ import { DownloadOutlined } from "@ant-design/icons";
import { PostDto } from "@nice/common";
import { env } from "@web/src/env";
import { getFileIcon } from "./utils";
import { formatFileSize } from "@nice/utils";
import { formatFileSize, getCompressedImageUrl } from '@nice/utils';
export default function PostResources({ post }: { post: PostDto }) {
const { resources } = useMemo(() => {
if (!post?.resources) return { resources: [] };
@ -12,13 +14,16 @@ export default function PostResources({ post }: { post: PostDto }) {
const isImage = (url: string) =>
/\.(png|jpg|jpeg|gif|webp)$/i.test(url);
const sortedResources = post.resources
.map((resource) => ({
const sortedResources = post.resources.map(resource => {
const original = `http://${env.SERVER_IP}/uploads/${resource.url}`
const isImg = isImage(resource.url)
return {
...resource,
url: `http://${env.SERVER_IP}/uploads/${resource.url}`,
isImage: isImage(resource.url),
}))
.sort((a, b) => (a.isImage === b.isImage ? 0 : a.isImage ? -1 : 1));
url: isImg ? getCompressedImageUrl(original) : original,
originalUrl: original,
isImage: isImg
}
}).sort((a, b) => a.isImage === b.isImage ? 0 : a.isImage ? -1 : 1)
return { resources: sortedResources };
}, [post]);
@ -46,6 +51,7 @@ export default function PostResources({ post }: { post: PostDto }) {
src={resource.url}
alt={resource.title}
preview={{
src: resource.originalUrl,
mask: (
<div className="flex items-center justify-center text-white">

View File

@ -9,3 +9,4 @@ export * from "./useTaxonomy"
export * from "./useVisitor"
export * from "./useMessage"
export * from "./usePost"
export * from "./useEntity"

View File

@ -70,11 +70,11 @@ model TermAncestry {
}
model Staff {
id String @id @default(cuid())
showname String? @map("showname")
username String @unique @map("username")
avatar String? @map("avatar")
password String? @map("password")
id String @id @default(cuid())
showname String? @map("showname")
username String @unique @map("username")
avatar String? @map("avatar")
password String? @map("password")
phoneNumber String? @unique @map("phone_number")
@ -196,16 +196,16 @@ model Post {
domainId String? @map("domain_id")
terms Term[] @relation("post_term")
// 日期时间类型字段
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @map("updated_at")
createdAt DateTime? @default(now()) @map("created_at")
updatedAt DateTime? @map("updated_at")
deletedAt DateTime? @map("deleted_at") // 删除时间,可为空
// 关系类型字段
authorId String? @map("author_id")
author Staff? @relation("post_author", fields: [authorId], references: [id]) // 帖子作者,关联 Staff 模型
visits Visit[] // 访问记录,关联 Visit 模型
views Int @default(0)
likes Int @default(0)
hates Int @default(0)
views Int? @default(0)
likes Int? @default(0)
hates Int? @default(0)
receivers Staff[] @relation("post_receiver")
parentId String? @map("parent_id")
parent Post? @relation("PostChildren", fields: [parentId], references: [id]) // 父级帖子,关联 Post 模型

View File

@ -27,5 +27,10 @@ export const formatFileSize = (bytes: number) => {
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
};
// 压缩图片路径生成函数
export const getCompressedImageUrl = (originalUrl: string): string => {
const cleanUrl = originalUrl.split(/[?#]/)[0] // 移除查询参数和哈希
const lastSlashIndex = cleanUrl.lastIndexOf('/')
return `${cleanUrl.slice(0, lastSlashIndex)}/compressed/${cleanUrl.slice(lastSlashIndex + 1).replace(/\.[^.]+$/, '.webp')}`
}
export * from "./types"