Merge branch 'main' of http://113.45.157.195:3003/insiinc/leader-mail
This commit is contained in:
commit
fe4a7cfae3
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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">
|
||||
点击预览
|
||||
|
|
|
@ -9,3 +9,4 @@ export * from "./useTaxonomy"
|
|||
export * from "./useVisitor"
|
||||
export * from "./useMessage"
|
||||
export * from "./usePost"
|
||||
export * from "./useEntity"
|
|
@ -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 模型
|
||||
|
|
|
@ -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"
|
Loading…
Reference in New Issue