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" + /> + +
+ {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: