diff --git a/apps/web/src/app/main/letter/write/mock.ts b/apps/web/src/app/main/letter/write/mock.ts
deleted file mode 100644
index 1a7ff1d..0000000
--- a/apps/web/src/app/main/letter/write/mock.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { Leader } from "./types";
-
-export const leaders: Leader[] = [
- {
- id: "1",
- name: "John Mitchell",
- rank: "General",
- division: "Air Combat Command",
- imageUrl:
- "https://th.bing.com/th/id/OIP.ea0spF2OAgI4I1KzgZFtTgHaHX?rs=1&pid=ImgDetMain",
- email: "j.mitchell@af.mil",
- phone: "(555) 123-4567",
- office: "Pentagon, Wing A-123",
- },
- {
- id: "2",
- name: "Sarah Williams",
- rank: "Colonel",
- division: "Air Force Space Command",
- imageUrl:
- "https://th.bing.com/th/id/OIP.ea0spF2OAgI4I1KzgZFtTgHaHX?rs=1&pid=ImgDetMain",
- },
- {
- id: "3",
- name: "Michael Roberts",
- rank: "Major General",
- division: "Air Mobility Command",
- imageUrl:
- "https://th.bing.com/th/id/OIP.ea0spF2OAgI4I1KzgZFtTgHaHX?rs=1&pid=ImgDetMain",
- },
-];
diff --git a/apps/web/src/app/main/letter/write/page.tsx b/apps/web/src/app/main/letter/write/page.tsx
index 1ed0640..f4d8c8a 100644
--- a/apps/web/src/app/main/letter/write/page.tsx
+++ b/apps/web/src/app/main/letter/write/page.tsx
@@ -1,14 +1,18 @@
-import { useState, useMemo, useCallback, useEffect } from 'react';
+import { useState, useCallback, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
-import Header from './header';
+import { useSearchParams } from 'react-router-dom';
+
import { SendCard } from './SendCard';
-import { Spin, Empty, Input, Alert, message, Pagination } from 'antd';
+import { Spin, Empty, Input, Alert, Pagination } from 'antd';
import { api } from '@nice/client';
import DepartmentSelect from '@web/src/components/models/department/department-select';
import debounce from 'lodash/debounce';
import { SearchOutlined } from '@ant-design/icons';
+import WriteHeader from './WriteHeader';
export default function WriteLetterPage() {
+ const [searchParams] = useSearchParams();
+ const termId = searchParams.get('termId');
const [searchQuery, setSearchQuery] = useState('');
const [selectedDept, setSelectedDept] = useState
();
const [currentPage, setCurrentPage] = useState(1);
@@ -30,19 +34,19 @@ export default function WriteLetterPage() {
}]
}
});
- useEffect(() => {
- console.log(selectedDept)
- console.log(data)
- console.log(searchQuery)
- }, [selectedDept, data, searchQuery])
- // Reset to first page when search query or department changes
- useCallback(() => {
+
+ const resetPage = useCallback(() => {
setCurrentPage(1);
- }, [searchQuery, selectedDept]);
+ }, []);
+
+ // Reset page when search or department changes
+ useEffect(() => {
+ resetPage();
+ }, [searchQuery, selectedDept, resetPage]);
return (
-
-
+
+
{/* Search and Filter Section */}
@@ -86,10 +90,11 @@ export default function WriteLetterPage() {
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
- {data?.items.map((item) => (
+ {data?.items.map((item: any) => (
))}
diff --git a/apps/web/src/app/main/letter/write/types.ts b/apps/web/src/app/main/letter/write/types.ts
deleted file mode 100644
index 4d0af62..0000000
--- a/apps/web/src/app/main/letter/write/types.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export interface Leader {
- id: string;
- name: string;
- rank: string;
- division: string;
- imageUrl: string;
- email: string; // Added
- phone: string; // Added
- office: string; // Added
-}
-
-
diff --git a/apps/web/src/components/layout/main/useNavItem.ts b/apps/web/src/components/layout/main/useNavItem.ts
index d90d947..665c034 100644
--- a/apps/web/src/components/layout/main/useNavItem.ts
+++ b/apps/web/src/components/layout/main/useNavItem.ts
@@ -23,7 +23,7 @@ export function useNavItem() {
// 构建分类导航项
const categoryItems = data.map(term => ({
- to: `/write-letter?category=${term.id}`,
+ to: `/write-letter?termId=${term.id}`,
label: term.name
}));
diff --git a/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx b/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx
index f5327b7..dadb265 100644
--- a/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx
+++ b/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx
@@ -1,164 +1,106 @@
import { Form, Input, Button, Checkbox, Select } from "antd";
-import { useState } from "react";
import { useLetterEditor } from "../context/LetterEditorContext";
-import { api } from "@nice/client";
-import {
- UserOutlined,
- FolderOutlined,
- TagOutlined,
- FileTextOutlined,
-} from "@ant-design/icons";
-
+import { SendOutlined } from "@ant-design/icons";
import QuillEditor from "@web/src/components/common/editor/quill/QuillEditor";
-import { PostBadge } from "../../detail/badge/PostBadge";
+import StaffSelect from "../../../staff/staff-select";
+import TermSelect from "../../../term/term-select";
export function LetterBasicForm() {
const { onSubmit, receiverId, termId, form } = useLetterEditor();
- const { data: receiver } = api.staff.findFirst.useQuery(
- {
- where: {
- id: receiverId,
- },
- },
- {
- enabled: !!receiverId,
- }
- );
- const { data: term } = api.term.findFirst.useQuery(
- {
- where: { id: termId },
- },
- { enabled: !!termId }
- );
-
const handleFinish = async (values: any) => {
await onSubmit(values);
};
-
return (
-
+
+
+
form.setFieldValue("content", content)}
- {/* 标签输入 */}
-
-
-
- 标签
-
- }
- name={["meta", "tags"]}
- labelCol={{ span: 24 }}
- wrapperCol={{ span: 24 }}>
-
-
+
+
- {/* 内容输入框 */}
-
-
-
- 内容
-
- (必选)
-
-
- }
- name="content"
- rules={[{ required: true, message: "请输入内容" }]}
- required={false} //不显示星号
- labelCol={{ span: 24 }}
- wrapperCol={{ span: 24 }}>
-
-
- form.setFieldValue("content", content)
- }
- />
-
-
-
-
-
-
-
+ {/* Footer Actions */}
+
- 是否公开
-
+ initialValue={true}
+ >
+
+ 是否公开
+
+
diff --git a/apps/web/src/components/models/post/editor/layout/LetterEditorLayout.tsx b/apps/web/src/components/models/post/editor/layout/LetterEditorLayout.tsx
deleted file mode 100644
index 9f083b6..0000000
--- a/apps/web/src/components/models/post/editor/layout/LetterEditorLayout.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { useLocation, useParams } from "react-router-dom";
-import { motion } from "framer-motion";
-import { PaperAirplaneIcon } from "@heroicons/react/24/outline";
-import { LetterFormProvider } from "../context/LetterEditorContext";
-import { LetterBasicForm } from "../form/LetterBasicForm";
-import { useTheme } from "@nice/theme";
-
-export default function LetterEditorLayout() {
- const location = useLocation();
- const params = new URLSearchParams(location.search);
- // const {} = useTheme();
- const receiverId = params.get("receiverId");
- const termId = params.get("termId");
-
- return (
-
-
-
-
- {/* */}
- 撰写信件
-
-
- {/* 隐私保护说明 */}
-
-
- {/* 隐私承诺 */}
-
-
- 我们承诺:您的个人信息将被严格保密,不向任何第三方透露。您可以选择匿名反映问题,平台会自动过滤可能暴露身份的信息。
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/apps/web/src/components/models/post/list/LetterList.tsx b/apps/web/src/components/models/post/list/LetterList.tsx
index 36b47c6..0adfe6f 100644
--- a/apps/web/src/components/models/post/list/LetterList.tsx
+++ b/apps/web/src/components/models/post/list/LetterList.tsx
@@ -1,18 +1,111 @@
+import { useState, useEffect, useMemo } from 'react';
+import { Input, Pagination, Empty } from 'antd';
import { api, RouterInputs } from "@nice/client";
-import { Prisma } from "packages/common/dist";
import { LetterCard } from "../LetterCard";
-
-export default function LetterList({ params }: { params: RouterInputs["post"]["findManyWithPagination"] }) {
+import { NonVoid } from "@nice/utils";
+import { SearchOutlined } from '@ant-design/icons';
+import debounce from 'lodash/debounce';
+export default function LetterList({ params }: { params: NonVoid
}) {
+ const [searchText, setSearchText] = useState('');
+ const [currentPage, setCurrentPage] = useState(1);
const { data, isLoading } = api.post.findManyWithPagination.useQuery({
- page: 1,
- pageSize: 1,
- where: {},
- select: {}
- })
- return
- {data?.items.map((letter: any) => (
-
- ))}
-
-}
\ No newline at end of file
+ page: currentPage,
+ pageSize: params.pageSize,
+ where: {
+ OR: [{
+ title: {
+ contains: searchText
+ }
+ }],
+ ...params?.where
+ },
+ select: params.select
+ });
+
+ // Debounced search function
+ const debouncedSearch = useMemo(
+ () =>
+ debounce((value: string) => {
+ setSearchText(value);
+ setCurrentPage(1);
+ }, 300),
+ []
+ );
+ // Cleanup debounce on unmount
+ useEffect(() => {
+ return () => {
+ debouncedSearch.cancel();
+ };
+ }, [debouncedSearch]);
+ const handleSearch = (value: string) => {
+ debouncedSearch(value);
+ };
+
+ const handlePageChange = (page: number) => {
+ setCurrentPage(page);
+ // Scroll to top when page changes
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ };
+
+ return (
+
+ {/* Search Bar */}
+
+
+ handleSearch(e.target.value)}
+ prefix={}
+ />
+
+
+
+ {/* Content Area */}
+
+ {isLoading ? (
+
+ {[...Array(6)].map((_, index) => (
+
+ ))}
+
+ ) : data?.items.length ? (
+ <>
+
+ {data.items.map((letter: any) => (
+
+ ))}
+
+
+ >
+ ) : (
+
+
+ {searchText ? "未找到相关信件" : "暂无信件"}
+
+ }
+
+ className="flex flex-col items-center"
+ />
+
+ )}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/models/staff/staff-select.tsx b/apps/web/src/components/models/staff/staff-select.tsx
index d6721b1..5fa44d6 100644
--- a/apps/web/src/components/models/staff/staff-select.tsx
+++ b/apps/web/src/components/models/staff/staff-select.tsx
@@ -3,6 +3,7 @@ import { Button, Select, Spin } from "antd";
import type { SelectProps } from "antd";
import { api } from "@nice/client";
import React from "react";
+import { SizeType } from "antd/es/config-provider/SizeContext";
interface StaffSelectProps {
value?: string | string[];
onChange?: (value: string | string[]) => void;
@@ -10,6 +11,7 @@ interface StaffSelectProps {
multiple?: boolean;
domainId?: string;
placeholder?: string;
+ size?: SizeType
}
export default function StaffSelect({
@@ -19,6 +21,7 @@ export default function StaffSelect({
style,
multiple,
domainId,
+ size
}: StaffSelectProps) {
const [keyword, setQuery] = useState("");
@@ -67,6 +70,7 @@ export default function StaffSelect({
return (
<>