diff --git a/apps/web/src/components/models/post/LetterCard.tsx b/apps/web/src/components/models/post/LetterCard.tsx index 0c9e6a9..dd517cc 100644 --- a/apps/web/src/components/models/post/LetterCard.tsx +++ b/apps/web/src/components/models/post/LetterCard.tsx @@ -1,11 +1,12 @@ import { - EyeOutlined, - LikeOutlined, - LikeFilled, - UserOutlined, - BankOutlined, - CalendarOutlined, - FileTextOutlined, + EyeOutlined, + LikeOutlined, + LikeFilled, + UserOutlined, + BankOutlined, + CalendarOutlined, + FileTextOutlined, + SendOutlined, } from "@ant-design/icons"; import { Button, Typography, Space, Tooltip } from "antd"; import toast from "react-hot-toast"; @@ -13,146 +14,115 @@ import { useState } from "react"; import { getBadgeStyle } from "@web/src/app/main/letter/list/utils"; import { PostDto } from "@nice/common"; import dayjs from "dayjs"; +import PostLikeButton from "./detail/PostHeader/PostLikeButton"; const { Title, Paragraph, Text } = Typography; interface LetterCardProps { - letter: PostDto; + letter: PostDto; } export function LetterCard({ letter }: LetterCardProps) { - const [likes, setLikes] = useState(0); - const [liked, setLiked] = useState(false); - const [views] = useState(Math.floor(Math.random() * 100)); // 模拟浏览量数据 - const handleLike = () => { - if (!liked) { - setLikes((prev) => prev + 1); - setLiked(true); - toast.success("已点赞!", { - icon: , - className: "custom-message", - }); - } else { - setLikes((prev) => prev - 1); - setLiked(false); - toast("已取消点赞", { - className: "custom-message", - }); - } - }; - return ( -
-
- {/* Title & Priority */} -
- - <a - href={`/letters/${letter.id}`} - target="_blank" - className="text-primary transition-all duration-300 relative + + return ( + <div className="w-full border-2 p-4 bg-white rounded-xl transition-all duration-300 ease-in-out group"> + <div className="flex flex-col gap-3"> + {/* Title & Priority */} + <div className="flex justify-between items-start"> + <Title level={4} className="!mb-0 flex-1"> + <a + href={`/letters/${letter.id}`} + target="_blank" + className="text-primary transition-all duration-300 relative before:absolute before:bottom-0 before:left-0 before:w-0 before:h-[2px] before:bg-primary-600 group-hover:before:w-full before:transition-all before:duration-300 group-hover:text-primary-600 group-hover:scale-105 group-hover:drop-shadow-md"> - {letter.title} - </a> - -
+ {letter.title} + + +
- {/* Meta Info */} -
- - - - - {letter.author?.showname || - letter?.author?.username} - - - | - - - {letter.author?.department?.name} - - - - - - {dayjs(letter.createdAt).format("YYYY-MM-DD")} - - -
+ {/* Meta Info */} +
+ + + + + {letter.author?.showname || '匿名用户'} + + + + + {letter.receivers.map(item => item.department?.name).toString()} + + + + + {letter.receivers.map(item => item.showname).toString()} + + + + + + + {dayjs(letter.createdAt).format("YYYY-MM-DD")} + + +
- {/* Content Preview */} - {letter.content && ( -
- - - {letter.content} - -
- )} + {/* Content Preview */} + {letter.content && ( +
+ + + {letter.content} + +
+ )} - {/* Badges & Interactions */} -
- - - - + {/* Badges & Interactions */} +
+ + + + -
-
- - {views} -
- - - -
-
-
-
- ); +
+
+ + {letter.views} +
+ +
+ + + + ); } export function Badge({ - type, - value, - className = "", + type, + value, + className = "", }: { - type: "priority" | "category" | "status"; - value: string; - className?: string; + type: "priority" | "category" | "status"; + value: string; + className?: string; }) { - return ( - value && ( - - {value?.toUpperCase()} - - ) - ); + {value?.toUpperCase()} + + ) + ); } diff --git a/apps/web/src/components/models/post/detail/PostHeader/PostLikeButton.tsx b/apps/web/src/components/models/post/detail/PostHeader/PostLikeButton.tsx index 419d7be..db34df0 100644 --- a/apps/web/src/components/models/post/detail/PostHeader/PostLikeButton.tsx +++ b/apps/web/src/components/models/post/detail/PostHeader/PostLikeButton.tsx @@ -4,11 +4,11 @@ import { useContext } from "react"; import { PostDetailContext } from "../context/PostDetailContext"; import { Button, Tooltip } from "antd"; import { LikeFilled, LikeOutlined } from "@ant-design/icons"; +import { useAuth } from "@web/src/providers/auth-provider"; export default function PostLikeButton({ post }: { post: PostDto }) { - const { user } = useContext(PostDetailContext); + const { user } = useAuth(); const { like, unLike } = useVisitor(); - function likeThisPost() { if (!post?.liked) { post.likes += 1; diff --git a/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx b/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx index c5e83b3..b1ad590 100644 --- a/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx +++ b/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx @@ -4,6 +4,7 @@ import { api, usePost } from "@nice/client"; import toast from "react-hot-toast"; import { useNavigate } from "react-router-dom"; import { PostState, PostType } from "@nice/common"; +import dayjs from "dayjs"; export interface LetterFormData { title: string; @@ -70,18 +71,34 @@ export function LetterFormProvider({ isPublic: data?.isPublic, resources: data.resources?.length ? { - connect: ( - data.resources?.filter(Boolean) || [] - ).map((fileId) => ({ - fileId, - })), - } + connect: ( + data.resources?.filter(Boolean) || [] + ).map((fileId) => ({ + fileId, + })), + } : undefined, }, }); - // console.log(123); + const formattedDateTime = dayjs().format('YYYY-MM-DD HH:mm:ss') + // 创建包含信件编号和提交时间的文本 + const fileContent = `信件编号: ${result.id}\n投递时间: ${formattedDateTime}`; + // 创建包含信件编号和提交时间的Blob对象 + const blob = new Blob([fileContent], { type: 'text/plain' }); + // 创建下载链接 + const downloadUrl = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = downloadUrl; + link.download = `信件编号-${result.id}.txt`; // 设置下载文件名 + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(downloadUrl); + + toast.success(`信件投递成功!信件编号已保存到本地,请妥善保管用于进度查询`, { + duration: 5000 // 10秒 + }); navigate(`/${result.id}/detail`, { replace: true }); - toast.success("发送成功!"); form.resetFields(); } catch (error) { console.error("Error submitting form:", error); diff --git a/apps/web/src/components/models/post/list/LetterList.tsx b/apps/web/src/components/models/post/list/LetterList.tsx index 0adfe6f..205e038 100644 --- a/apps/web/src/components/models/post/list/LetterList.tsx +++ b/apps/web/src/components/models/post/list/LetterList.tsx @@ -5,6 +5,7 @@ import { LetterCard } from "../LetterCard"; import { NonVoid } from "@nice/utils"; import { SearchOutlined } from '@ant-design/icons'; import debounce from 'lodash/debounce'; +import { postDetailSelect } from '@nice/common'; export default function LetterList({ params }: { params: NonVoid }) { const [searchText, setSearchText] = useState(''); const [currentPage, setCurrentPage] = useState(1); @@ -20,9 +21,14 @@ export default function LetterList({ params }: { params: NonVoid { + console.log(data) + }, [data]) // Debounced search function const debouncedSearch = useMemo( () => @@ -73,7 +79,7 @@ export default function LetterList({ params }: { params: NonVoid ) : data?.items.length ? ( <> -
+
{data.items.map((letter: any) => ( ))} diff --git a/packages/common/prisma/schema.prisma b/packages/common/prisma/schema.prisma index fe37e9e..ba34981 100644 --- a/packages/common/prisma/schema.prisma +++ b/packages/common/prisma/schema.prisma @@ -192,11 +192,7 @@ model Post { state String? // 状态 : 未读、处理中、已回答 title String? // 帖子标题,可为空 content String? // 帖子内容,可为空 - domainId String? @map("domain_id") - // term Term? @relation(fields: [termId], references: [id]) - // termId String? @map("term_id") - // 添加多对多关系 terms Term[] @relation("post_term") // 日期时间类型字段 createdAt DateTime @default(now()) @map("created_at") @@ -208,7 +204,6 @@ model Post { visits Visit[] // 访问记录,关联 Visit 模型 views Int @default(0) likes Int @default(0) - receivers Staff[] @relation("post_receiver") parentId String? @map("parent_id") parent Post? @relation("PostChildren", fields: [parentId], references: [id]) // 父级帖子,关联 Post 模型 diff --git a/packages/common/src/select.ts b/packages/common/src/select.ts index 668bd06..0e9e0c6 100644 --- a/packages/common/src/select.ts +++ b/packages/common/src/select.ts @@ -12,11 +12,9 @@ export const postDetailSelect: Prisma.PostSelect = { resources: true, createdAt: true, updatedAt: true, - + terms: { - include: { - - }, + select: { id: true, name: true }, }, authorId: true, author: {