,
+ hover: "hover:from-orange-100 hover:to-orange-200",
+ },
+ suggestion: {
+ bg: "bg-gradient-to-r from-blue-50 to-blue-100",
+ text: "text-blue-800",
+ border: "border-blue-200",
+ icon:
,
+ hover: "hover:from-blue-100 hover:to-blue-200",
+ },
+ request: {
+ bg: "bg-gradient-to-r from-purple-50 to-purple-100",
+ text: "text-purple-800",
+ border: "border-purple-200",
+ icon:
,
+ hover: "hover:from-purple-100 hover:to-purple-200",
+ },
+ feedback: {
+ bg: "bg-gradient-to-r from-teal-50 to-teal-100",
+ text: "text-teal-800",
+ border: "border-teal-200",
+ icon:
,
+ hover: "hover:from-teal-100 hover:to-teal-200",
+ },
+ },
+ state: {
+ [PostState.PENDING]: {
+ bg: "bg-gradient-to-r from-yellow-50 to-yellow-100",
+ text: "text-yellow-800",
+ border: "border-yellow-200",
+ icon:
,
+ hover: "hover:from-yellow-100 hover:to-yellow-200",
+ },
+ [PostState.PROCESSING]: {
+ bg: "bg-gradient-to-r from-blue-50 to-blue-100",
+ text: "text-blue-800",
+ border: "border-blue-200",
+ icon:
,
+ hover: "hover:from-blue-100 hover:to-blue-200",
+ },
+ [PostState.RESOLVED]: {
+ bg: "bg-gradient-to-r from-green-50 to-green-100",
+ text: "text-green-800",
+ border: "border-green-200",
+ icon:
,
+ hover: "hover:from-green-100 hover:to-green-200",
+ },
+ },
+ tag: {
+ default: {
+ bg: "bg-gradient-to-r from-gray-50 to-gray-100",
+ text: "text-gray-800",
+ border: "border-gray-200",
+ icon:
,
+ hover: "hover:from-gray-100 hover:to-gray-200",
+ }
+ },
+} as const;
+
+export const getBadgeStyle = (
+ type: keyof typeof BADGE_STYLES,
+ value: string
+) => {
+ const style = type === 'tag'
+ ? BADGE_STYLES.tag.default
+ : BADGE_STYLES[type][value as keyof (typeof BADGE_STYLES)[typeof type]] || {
+ bg: "bg-gradient-to-r from-gray-50 to-gray-100",
+ text: "text-gray-800",
+ border: "border-gray-200",
+ icon:
,
+ hover: "hover:from-gray-100 hover:to-gray-200",
+ };
+
+ return style;
+};
+
+export function LetterBadge({
+ type,
+ value,
+ className = "",
+}: {
+ type: "category" | "state" | "tag";
+ value: string;
+ className?: string;
+}) {
+ if (!value) return null;
+
+ const style = getBadgeStyle(type, value);
+
+ return (
+
+ {style.icon}
+
+ {type === 'state' ? PostStateLabels[value] : value}
+
+
+ );
+}
diff --git a/apps/web/src/components/models/post/LetterCard.tsx b/apps/web/src/components/models/post/LetterCard.tsx
index 009b577..de28fad 100644
--- a/apps/web/src/components/models/post/LetterCard.tsx
+++ b/apps/web/src/components/models/post/LetterCard.tsx
@@ -9,12 +9,10 @@ import {
SendOutlined,
} from "@ant-design/icons";
import { Button, Typography, Space, Tooltip } from "antd";
-import toast from "react-hot-toast";
-import { useState } from "react";
-import { getBadgeStyle } from "@web/src/app/main/letter/list/utils";
-import { PostDto } from "@nice/common";
+import { PostDto, PostStateLabels } from "@nice/common";
import dayjs from "dayjs";
import PostLikeButton from "./detail/PostHeader/PostLikeButton";
+import { LetterBadge } from "./LetterBadge";
const { Title, Paragraph, Text } = Typography;
interface LetterCardProps {
@@ -22,78 +20,104 @@ interface LetterCardProps {
}
export function LetterCard({ letter }: LetterCardProps) {
-
-
return (
-
-
- {/* Title & Priority */}
+
{
+ window.open(`/${letter.id}/detail`)
+ }}
+ className=" cursor-pointer w-full p-6 bg-white rounded-xl group relative overflow-hidden duration-300 hover:-translate-y-1 transition-all ease-in-out "
+ >
+
-
{/* Meta Info */}
-
-
-
-
-
+
+
+
+
+
{letter.author?.showname || '匿名用户'}
-
-
-
- {letter.receivers.map(item => item.department?.name).toString()}
-
-
-
-
- {letter.receivers.map(item => item.showname).toString()}
-
-
-
-
-
-
+
+
+ {letter.receivers.some(item => item.department?.name) && (
+
+
+ item.department?.name).filter(Boolean).join(', ')}>
+
+ {letter.receivers
+ .map(item => item.department?.name)
+ .filter(Boolean)
+ .slice(0, 2)
+ .join('、')}
+ {letter.receivers.filter(item => item.department?.name).length > 2 && ' 等'}
+
+
+
+ )}
+
+ {letter.receivers.some(item => item.showname) && (
+
+
+ item.showname).filter(Boolean).join(', ')}>
+
+ {letter.receivers
+ .map(item => item.showname)
+ .filter(Boolean)
+ .slice(0, 2)
+ .join('、')}
+ {letter.receivers.filter(item => item.showname).length > 2 && ' 等'}
+
+
+
+ )}
+
+
+
+
{dayjs(letter.createdAt).format("YYYY-MM-DD")}
-
+
{/* Content Preview */}
{letter.content && (
-
-
-
- {letter.content}
-
-
+
+ {letter.content}
+
)}
-
+
+
+ {letter.meta.tags.map(tag => (
+
+ ))}
+
{/* Badges & Interactions */}
-
-
-
-
-
+
+
+ {letter.terms.map(term => (
+
+ ))}
+
-
-
- {letter.views}
-
+
}
+ >
+ {letter.views}
+
@@ -101,27 +125,3 @@ export function LetterCard({ letter }: LetterCardProps) {
);
}
-
-export function Badge({
- type,
- value,
- className = "",
-}: {
- type: "priority" | "category" | "status";
- value: string;
- className?: string;
-}) {
- return (
- value && (
-
- {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 db34df0..e2113b0 100644
--- a/apps/web/src/components/models/post/detail/PostHeader/PostLikeButton.tsx
+++ b/apps/web/src/components/models/post/detail/PostHeader/PostLikeButton.tsx
@@ -1,7 +1,5 @@
import { PostDto, VisitType } from "@nice/common";
import { useVisitor } from "@nice/client";
-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";
@@ -37,17 +35,14 @@ export default function PostLikeButton({ post }: { post: PostDto }) {
: }
- onClick={likeThisPost}
- className={`
- flex items-center gap-1 px-3 transform transition-all duration-300
- hover:scale-105 hover:shadow-md
- ${post?.liked ? "bg-blue-500 hover:bg-blue-600" : "hover:border-blue-500 hover:text-blue-500"}
- `}>
-
- {post?.likes}
-
+ onClick={(e) => {
+ e.stopPropagation()
+ likeThisPost()
+ }}
+ >
+ {post?.likes}
);
diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts
index b1d8fa8..c1f8795 100755
--- a/packages/common/src/types.ts
+++ b/packages/common/src/types.ts
@@ -135,7 +135,7 @@ export type PostDto = Post & {
liked: boolean;
readedCount: number;
commentsCount: number;
- term: TermDto;
+ terms: TermDto[];
author: StaffDto | undefined;
receivers: StaffDto[];
resources: Resource[];