diff --git a/apps/web/package.json b/apps/web/package.json
index 77eb2f2..1f16da9 100755
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -33,8 +33,8 @@
"@nice/client": "workspace:^",
"@nice/common": "workspace:^",
"@nice/iconer": "workspace:^",
- "@nice/ui": "workspace:^",
"@nice/theme": "workspace:^",
+ "@nice/ui": "workspace:^",
"@tanstack/query-async-storage-persister": "^5.51.9",
"@tanstack/react-query": "^5.51.21",
"@tanstack/react-query-persist-client": "^5.51.9",
@@ -70,6 +70,7 @@
"superjson": "^2.2.1",
"swiper": "^11.2.1",
"tailwind-merge": "^2.6.0",
+ "usehooks-ts": "^3.1.0",
"uuid": "^10.0.0",
"yjs": "^13.6.20",
"zod": "^3.23.8"
diff --git a/apps/web/src/app/main/letter/list/Header.tsx b/apps/web/src/app/main/letter/list/Header.tsx
index 1d7aa41..a6aad8a 100644
--- a/apps/web/src/app/main/letter/list/Header.tsx
+++ b/apps/web/src/app/main/letter/list/Header.tsx
@@ -1,20 +1,40 @@
import { SearchFilters } from "./SearchFilter";
+import { useQueryClient } from '@tanstack/react-query';
export function Header() {
- return (
-
- );
+
+ const handleSearch = (value: string) => {
+
+ };
+
+ const handleFilterChange = () => {
+
+ };
+
+ return (
+
+
+
公开信件列表
+
+
+ 服务宗旨:畅通诉求渠道 • 促进建设发展 • 提升单位战斗力
+
+
+ 实时跟踪反馈进度
+ 保障信息传递安全
+ 高效解决实际问题
+
+
+
+
+
+ );
}
diff --git a/apps/web/src/app/main/letter/list/SearchFilter.tsx b/apps/web/src/app/main/letter/list/SearchFilter.tsx
index dd697ee..f74cd28 100644
--- a/apps/web/src/app/main/letter/list/SearchFilter.tsx
+++ b/apps/web/src/app/main/letter/list/SearchFilter.tsx
@@ -1,4 +1,6 @@
-import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
+import { SearchOutlined } from '@ant-design/icons';
+import { Form, Input, Select, Spin } from 'antd';
+import { useEffect } from 'react';
interface SearchFiltersProps {
searchTerm: string;
@@ -7,8 +9,14 @@ interface SearchFiltersProps {
onCategoryChange: (value: string) => void;
filterStatus: string;
onStatusChange: (value: string) => void;
- className?: string
+ className?: string;
+ isLoading?: boolean;
}
+
+const LoadingIndicator = () => (
+
+);
+
export function SearchFilters({
searchTerm,
onSearchChange,
@@ -16,69 +24,67 @@ export function SearchFilters({
onCategoryChange,
filterStatus,
onStatusChange,
- className
+ className,
+ isLoading = false
}: SearchFiltersProps) {
+ const [form] = Form.useForm();
+
+ // 统一处理表单初始值
+ const initialValues = {
+ search: searchTerm,
+ category: filterCategory,
+ status: filterStatus
+ };
+
+ useEffect(() => {
+ form.setFieldsValue(initialValues);
+ }, [searchTerm, filterCategory, filterStatus, form]);
+
return (
-
-
-
-
-
+
+
+ }
+ placeholder="搜索关键词、发件人或单位..."
onChange={(e) => onSearchChange(e.target.value)}
+ allowClear
+ suffix={isLoading ? : null}
/>
-
+
+
+
+
+
+
+
+
+
-
-
+
);
}
-
-function FilterDropdowns({
- filterCategory,
- onCategoryChange,
- filterStatus,
- onStatusChange,
-}: Pick
) {
- const selectClassName = `min-w-[160px] h-[46px] px-4 rounded-lg
- bg-white shadow-sm transition-all duration-200
- text-[#041E42] font-medium
- focus:outline-none focus:border-[#00308F] focus:ring-2 focus:ring-[#00308F]/20
- hover:border-[#00308F]`;
- return (
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/apps/web/src/app/main/letter/progress/page.tsx b/apps/web/src/app/main/letter/progress/page.tsx
index df5b143..e8d0145 100644
--- a/apps/web/src/app/main/letter/progress/page.tsx
+++ b/apps/web/src/app/main/letter/progress/page.tsx
@@ -1,120 +1,175 @@
import { useState } from 'react'
+import { Input, Button, Card, Steps, Tag, Spin, message } from 'antd'
+import { SearchOutlined, SafetyCertificateOutlined } from '@ant-design/icons'
interface FeedbackStatus {
- status: 'pending' | 'in-progress' | 'resolved'
- ticketId: string
- submittedDate: string
- lastUpdate: string
- title: string
+ status: 'pending' | 'in-progress' | 'resolved'
+ ticketId: string
+ submittedDate: string
+ lastUpdate: string
+ title: string
}
+const { Step } = Steps
+
export default function LetterProgressPage() {
- const [feedbackId, setFeedbackId] = useState('')
- const [status, setStatus] = useState(null)
+ const [feedbackId, setFeedbackId] = useState('')
+ const [status, setStatus] = useState(null)
+ const [loading, setLoading] = useState(false)
+ const [error, setError] = useState('')
- // Mock data - In production this would come from an API
- const mockLookup = () => {
- setStatus({
- status: 'in-progress',
- ticketId: 'USAF-2025-0123',
- submittedDate: '2025-01-15',
- lastUpdate: '2025-01-21',
- title: 'Aircraft Maintenance Schedule Inquiry'
- })
+ const validateInput = () => {
+ if (!feedbackId.trim()) {
+ setError('请输入有效的问题编号')
+ return false
}
+ if (!/^USAF-\d{4}-\d{4}$/.test(feedbackId)) {
+ setError('问题编号格式不正确,应为USAF-YYYY-NNNN')
+ return false
+ }
+ setError('')
+ return true
+ }
- return (
-
- {/* Header */}
-
-
- USAF Feedback Progress Tracking
-
-
-
+ const mockLookup = () => {
+ if (!validateInput()) return
- {/* Main Content */}
-
- {/* Search Section */}
-
-
-
- setFeedbackId(e.target.value)}
- placeholder="e.g. USAF-2025-0123"
- className="flex-1 p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-[#00538B] focus:border-transparent"
- />
-
-
-
- {/* Results Section */}
- {status && (
-
-
-
-
- Feedback Details
-
-
- {status.status.toUpperCase()}
-
-
+ setLoading(true)
+ setTimeout(() => {
+ setStatus({
+ status: 'in-progress',
+ ticketId: feedbackId,
+ submittedDate: '2025-01-15',
+ lastUpdate: '2025-01-21',
+ title: 'Aircraft Maintenance Schedule Inquiry'
+ })
+ setLoading(false)
+ }, 1000)
+ }
-
-
-
Ticket ID
-
{status.ticketId}
-
-
-
Submitted Date
-
{status.submittedDate}
-
-
-
Last Update
-
{status.lastUpdate}
-
-
-
Title
-
{status.title}
-
-
+ const getStatusColor = (status: string) => {
+ switch (status) {
+ case 'pending':
+ return 'orange'
+ case 'in-progress':
+ return 'blue'
+ case 'resolved':
+ return 'green'
+ default:
+ return 'gray'
+ }
+ }
- {/* Progress Timeline */}
-
-
-
-
- {['Submitted', 'In Review', 'Resolved'].map((step, index) => (
-
-
- {index + 1}
-
-
{step}
-
- ))}
-
-
-
-
-
- )}
-
+ return (
+
+ {/* Header */}
+
+
+
+
+
USAF Feedback Tracking System
+
Enter your ticket ID to track progress
+
- )
+
+
+ {/* Main Content */}
+
+ {/* Search Section */}
+
+
+
+
+ }
+ size="large"
+ value={feedbackId}
+ onChange={(e) => setFeedbackId(e.target.value)}
+ placeholder="e.g. USAF-2025-0123"
+ status={error ? 'error' : ''}
+ className="border border-gray-300"
+ />
+ }
+ loading={loading}
+ onClick={mockLookup}
+ style={{ backgroundColor: '#003366', borderColor: '#003366' }}
+ >
+ Track
+
+
+ {error &&
{error}
}
+
+
+
+ {/* Results Section */}
+ {status && (
+
+
+ {/* Header */}
+
+
+ Ticket Details
+
+
+ {status.status}
+
+
+
+ {/* Details Grid */}
+
+
+
Ticket ID
+
{status.ticketId}
+
+
+
Submitted Date
+
{status.submittedDate}
+
+
+
Last Update
+
{status.lastUpdate}
+
+
+
Subject
+
{status.title}
+
+
+
+ {/* Progress Timeline */}
+
+
+ }
+ />
+ }
+ />
+ }
+ />
+
+
+
+
+ )}
+
+
+ )
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 669a08e..4a8df5d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -404,6 +404,9 @@ importers:
tailwind-merge:
specifier: ^2.6.0
version: 2.6.0
+ usehooks-ts:
+ specifier: ^3.1.0
+ version: 3.1.0(react@18.2.0)
uuid:
specifier: ^10.0.0
version: 10.0.0
@@ -6800,6 +6803,12 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ usehooks-ts@3.1.0:
+ resolution: {integrity: sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==}
+ engines: {node: '>=16.15.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -14251,6 +14260,11 @@ snapshots:
dependencies:
react: 18.2.0
+ usehooks-ts@3.1.0(react@18.2.0):
+ dependencies:
+ lodash.debounce: 4.0.8
+ react: 18.2.0
+
util-deprecate@1.0.2: {}
util@0.12.5: