|
|
@@ -1,6 +1,13 @@
|
|
|
import React, { useState } from 'react';
|
|
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
|
import { disabilityClientManager } from '../api/disabilityClient';
|
|
|
+import { Card, CardContent, CardHeader, CardTitle } from '@d8d/shared-ui-components/components/ui/card';
|
|
|
+import { Input } from '@d8d/shared-ui-components/components/ui/input';
|
|
|
+import { Label } from '@d8d/shared-ui-components/components/ui/label';
|
|
|
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@d8d/shared-ui-components/components/ui/select';
|
|
|
+import { Button } from '@d8d/shared-ui-components/components/ui/button';
|
|
|
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@d8d/shared-ui-components/components/ui/table';
|
|
|
+import { DataTablePagination } from '@d8d/shared-ui-components/components/admin/DataTablePagination';
|
|
|
|
|
|
// 残疾人企业查询页面组件
|
|
|
export const DisabilityPersonCompanyQuery: React.FC = () => {
|
|
|
@@ -75,115 +82,133 @@ export const DisabilityPersonCompanyQuery: React.FC = () => {
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
- <div className="p-6" data-testid="disability-person-company-query">
|
|
|
- <div className="mb-6">
|
|
|
- <h1 className="text-2xl font-bold mb-4">残疾人企业查询</h1>
|
|
|
-
|
|
|
- {/* 筛选条件表单 */}
|
|
|
- <div className="bg-white rounded-lg shadow p-4 mb-4">
|
|
|
- <div className="grid grid-cols-4 gap-4">
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">性别</label>
|
|
|
- <select
|
|
|
- data-testid="gender-filter"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
- value={filters.gender}
|
|
|
- onChange={(e) => setFilters({ ...filters, gender: e.target.value, page: 1 })}
|
|
|
+ <div className="p-6 space-y-6" data-testid="disability-person-company-query">
|
|
|
+ {/* 筛选条件卡片 */}
|
|
|
+ <Card>
|
|
|
+ <CardHeader>
|
|
|
+ <CardTitle>残疾人企业查询</CardTitle>
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
|
+ {/* 性别筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="gender-filter">性别</Label>
|
|
|
+ <Select
|
|
|
+ value={filters.gender || 'all'}
|
|
|
+ onValueChange={(value) => setFilters({ ...filters, gender: value === 'all' ? '' : value, page: 1 })}
|
|
|
>
|
|
|
- <option value="">全部</option>
|
|
|
- <option value="男">男</option>
|
|
|
- <option value="女">女</option>
|
|
|
- </select>
|
|
|
+ <SelectTrigger id="gender-filter" data-testid="gender-filter" className="w-full">
|
|
|
+ <SelectValue placeholder="全部" />
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent>
|
|
|
+ <SelectItem value="all">全部</SelectItem>
|
|
|
+ <SelectItem value="男">男</SelectItem>
|
|
|
+ <SelectItem value="女">女</SelectItem>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
</div>
|
|
|
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">残疾类别</label>
|
|
|
- <select
|
|
|
- data-testid="disability-type-filter"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
- value={filters.disabilityType}
|
|
|
- onChange={(e) => setFilters({ ...filters, disabilityType: e.target.value, page: 1 })}
|
|
|
+ {/* 残疾类别筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="disability-type-filter">残疾类别</Label>
|
|
|
+ <Select
|
|
|
+ value={filters.disabilityType || 'all'}
|
|
|
+ onValueChange={(value) => setFilters({ ...filters, disabilityType: value === 'all' ? '' : value, page: 1 })}
|
|
|
>
|
|
|
- <option value="">全部</option>
|
|
|
- <option value="视力残疾">视力残疾</option>
|
|
|
- <option value="听力残疾">听力残疾</option>
|
|
|
- <option value="言语残疾">言语残疾</option>
|
|
|
- <option value="肢体残疾">肢体残疾</option>
|
|
|
- <option value="智力残疾">智力残疾</option>
|
|
|
- <option value="精神残疾">精神残疾</option>
|
|
|
- </select>
|
|
|
+ <SelectTrigger id="disability-type-filter" data-testid="disability-type-filter" className="w-full">
|
|
|
+ <SelectValue placeholder="全部" />
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent>
|
|
|
+ <SelectItem value="all">全部</SelectItem>
|
|
|
+ <SelectItem value="视力残疾">视力残疾</SelectItem>
|
|
|
+ <SelectItem value="听力残疾">听力残疾</SelectItem>
|
|
|
+ <SelectItem value="言语残疾">言语残疾</SelectItem>
|
|
|
+ <SelectItem value="肢体残疾">肢体残疾</SelectItem>
|
|
|
+ <SelectItem value="智力残疾">智力残疾</SelectItem>
|
|
|
+ <SelectItem value="精神残疾">精神残疾</SelectItem>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
</div>
|
|
|
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">残疾等级</label>
|
|
|
- <select
|
|
|
- data-testid="disability-level-filter"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
- value={filters.disabilityLevel}
|
|
|
- onChange={(e) => setFilters({ ...filters, disabilityLevel: e.target.value, page: 1 })}
|
|
|
+ {/* 残疾等级筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="disability-level-filter">残疾等级</Label>
|
|
|
+ <Select
|
|
|
+ value={filters.disabilityLevel || 'all'}
|
|
|
+ onValueChange={(value) => setFilters({ ...filters, disabilityLevel: value === 'all' ? '' : value, page: 1 })}
|
|
|
>
|
|
|
- <option value="">全部</option>
|
|
|
- <option value="一级">一级</option>
|
|
|
- <option value="二级">二级</option>
|
|
|
- <option value="三级">三级</option>
|
|
|
- <option value="四级">四级</option>
|
|
|
- </select>
|
|
|
+ <SelectTrigger id="disability-level-filter" data-testid="disability-level-filter" className="w-full">
|
|
|
+ <SelectValue placeholder="全部" />
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent>
|
|
|
+ <SelectItem value="all">全部</SelectItem>
|
|
|
+ <SelectItem value="一级">一级</SelectItem>
|
|
|
+ <SelectItem value="二级">二级</SelectItem>
|
|
|
+ <SelectItem value="三级">三级</SelectItem>
|
|
|
+ <SelectItem value="四级">四级</SelectItem>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
</div>
|
|
|
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">最小年龄</label>
|
|
|
- <input
|
|
|
+ {/* 最小年龄筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="min-age-filter">最小年龄</Label>
|
|
|
+ <Input
|
|
|
+ id="min-age-filter"
|
|
|
data-testid="min-age-filter"
|
|
|
type="number"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
value={filters.minAge}
|
|
|
onChange={(e) => setFilters({ ...filters, minAge: e.target.value, page: 1 })}
|
|
|
placeholder="最小年龄"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">最大年龄</label>
|
|
|
- <input
|
|
|
+ {/* 最大年龄筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="max-age-filter">最大年龄</Label>
|
|
|
+ <Input
|
|
|
+ id="max-age-filter"
|
|
|
data-testid="max-age-filter"
|
|
|
type="number"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
value={filters.maxAge}
|
|
|
onChange={(e) => setFilters({ ...filters, maxAge: e.target.value, page: 1 })}
|
|
|
placeholder="最大年龄"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">市</label>
|
|
|
- <input
|
|
|
+ {/* 市筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="city-filter">市</Label>
|
|
|
+ <Input
|
|
|
+ id="city-filter"
|
|
|
data-testid="city-filter"
|
|
|
type="text"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
value={filters.city}
|
|
|
onChange={(e) => setFilters({ ...filters, city: e.target.value, page: 1 })}
|
|
|
placeholder="输入市级"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">区</label>
|
|
|
- <input
|
|
|
+ {/* 区筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="district-filter">区</Label>
|
|
|
+ <Input
|
|
|
+ id="district-filter"
|
|
|
data-testid="district-filter"
|
|
|
type="text"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
value={filters.district}
|
|
|
onChange={(e) => setFilters({ ...filters, district: e.target.value, page: 1 })}
|
|
|
placeholder="输入区级"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <div>
|
|
|
- <label className="block text-sm font-medium text-gray-700 mb-1">残疾证号</label>
|
|
|
- <input
|
|
|
+ {/* 残疾证号筛选 */}
|
|
|
+ <div className="space-y-2">
|
|
|
+ <Label htmlFor="disability-id-filter">残疾证号</Label>
|
|
|
+ <Input
|
|
|
+ id="disability-id-filter"
|
|
|
data-testid="disability-id-filter"
|
|
|
type="text"
|
|
|
- className="w-full border rounded px-3 py-2"
|
|
|
value={filters.disabilityId}
|
|
|
onChange={(e) => setFilters({ ...filters, disabilityId: e.target.value, page: 1 })}
|
|
|
placeholder="输入残疾证号"
|
|
|
@@ -193,125 +218,109 @@ export const DisabilityPersonCompanyQuery: React.FC = () => {
|
|
|
|
|
|
{/* 操作按钮 */}
|
|
|
<div className="flex gap-2 mt-4">
|
|
|
- <button
|
|
|
+ <Button
|
|
|
data-testid="reset-button"
|
|
|
onClick={handleReset}
|
|
|
- className="px-4 py-2 border rounded hover:bg-gray-50"
|
|
|
+ variant="outline"
|
|
|
>
|
|
|
重置
|
|
|
- </button>
|
|
|
- <button
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
data-testid="search-button"
|
|
|
onClick={handleSearch}
|
|
|
- className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
|
|
>
|
|
|
查询
|
|
|
- </button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- {/* 数据表格 */}
|
|
|
- <div className="bg-white rounded-lg shadow overflow-hidden">
|
|
|
- {isLoading ? (
|
|
|
- <div className="p-4 text-center" data-testid="loading-state">加载中...</div>
|
|
|
- ) : error ? (
|
|
|
- <div className="p-4 text-center text-red-600" data-testid="error-state">
|
|
|
- 加载失败: {error instanceof Error ? error.message : '未知错误'}
|
|
|
+ </Button>
|
|
|
</div>
|
|
|
- ) : (
|
|
|
- <>
|
|
|
- <table className="min-w-full divide-y divide-gray-200" data-testid="results-table">
|
|
|
- <thead className="bg-gray-50">
|
|
|
- <tr>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">姓名</th>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">残疾类别</th>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">残疾等级</th>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">公司</th>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">户籍</th>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">残疾证号</th>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">区</th>
|
|
|
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">市</th>
|
|
|
- </tr>
|
|
|
- </thead>
|
|
|
- <tbody className="bg-white divide-y divide-gray-200">
|
|
|
- {!data?.data || data.data.length === 0 ? (
|
|
|
- <tr data-testid="no-data-row">
|
|
|
- <td colSpan={8} className="px-6 py-4 text-center text-gray-500">
|
|
|
- 暂无数据
|
|
|
- </td>
|
|
|
- </tr>
|
|
|
- ) : (
|
|
|
- data.data.map((item: any) => (
|
|
|
- <tr key={`${item.personId}-${item.orderId}`}>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.name}</td>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.disabilityType}</td>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.disabilityLevel}</td>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.companyName}</td>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.city} {item.district || ''}</td>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.disabilityId}</td>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.district || '-'}</td>
|
|
|
- <td className="px-6 py-4 whitespace-nowrap">{item.city}</td>
|
|
|
- </tr>
|
|
|
- ))
|
|
|
- )}
|
|
|
- </tbody>
|
|
|
- </table>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
|
|
|
- {/* 分页 */}
|
|
|
- <div className="bg-gray-50 px-6 py-4 border-t border-gray-200 flex items-center justify-between" data-testid="pagination">
|
|
|
- <div className="text-sm text-gray-700" data-testid="total-records">
|
|
|
- 共 {data?.total || 0} 条记录
|
|
|
- </div>
|
|
|
- <div className="flex gap-2">
|
|
|
- <button
|
|
|
- data-testid="prev-page-button"
|
|
|
- onClick={() => setFilters({ ...filters, page: Math.max(1, filters.page - 1) })}
|
|
|
- disabled={filters.page === 1}
|
|
|
- className="px-4 py-2 border rounded hover:bg-gray-50 disabled:opacity-50"
|
|
|
- >
|
|
|
- 上一页
|
|
|
- </button>
|
|
|
- <span className="px-4 py-2" data-testid="current-page">
|
|
|
- 第 {filters.page} 页
|
|
|
- </span>
|
|
|
- <button
|
|
|
- data-testid="next-page-button"
|
|
|
- onClick={() => setFilters({ ...filters, page: filters.page + 1 })}
|
|
|
- disabled={!data?.data || data?.data.length < filters.limit}
|
|
|
- className="px-4 py-2 border rounded hover:bg-gray-50 disabled:opacity-50"
|
|
|
- >
|
|
|
- 下一页
|
|
|
- </button>
|
|
|
- </div>
|
|
|
+ {/* 数据表格卡片 */}
|
|
|
+ <Card>
|
|
|
+ <CardContent className="p-0">
|
|
|
+ {isLoading ? (
|
|
|
+ <div className="p-4 text-center" data-testid="loading-state">加载中...</div>
|
|
|
+ ) : error ? (
|
|
|
+ <div className="p-4 text-center text-destructive" data-testid="error-state">
|
|
|
+ 加载失败: {error instanceof Error ? error.message : '未知错误'}
|
|
|
</div>
|
|
|
- </>
|
|
|
- )}
|
|
|
- </div>
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ <Table data-testid="results-table">
|
|
|
+ <TableHeader>
|
|
|
+ <TableRow>
|
|
|
+ <TableHead>姓名</TableHead>
|
|
|
+ <TableHead>残疾类别</TableHead>
|
|
|
+ <TableHead>残疾等级</TableHead>
|
|
|
+ <TableHead>公司</TableHead>
|
|
|
+ <TableHead>户籍</TableHead>
|
|
|
+ <TableHead>残疾证号</TableHead>
|
|
|
+ <TableHead>区</TableHead>
|
|
|
+ <TableHead>市</TableHead>
|
|
|
+ </TableRow>
|
|
|
+ </TableHeader>
|
|
|
+ <TableBody>
|
|
|
+ {!data?.data || data.data.length === 0 ? (
|
|
|
+ <TableRow data-testid="no-data-row">
|
|
|
+ <TableCell colSpan={8} className="text-center text-muted-foreground">
|
|
|
+ 暂无数据
|
|
|
+ </TableCell>
|
|
|
+ </TableRow>
|
|
|
+ ) : (
|
|
|
+ data.data.map((item: any) => (
|
|
|
+ <TableRow key={`${item.personId}-${item.orderId}`}>
|
|
|
+ <TableCell>{item.name}</TableCell>
|
|
|
+ <TableCell>{item.disabilityType}</TableCell>
|
|
|
+ <TableCell>{item.disabilityLevel}</TableCell>
|
|
|
+ <TableCell>{item.companyName}</TableCell>
|
|
|
+ <TableCell>{item.city} {item.district || ''}</TableCell>
|
|
|
+ <TableCell>{item.disabilityId}</TableCell>
|
|
|
+ <TableCell>{item.district || '-'}</TableCell>
|
|
|
+ <TableCell>{item.city}</TableCell>
|
|
|
+ </TableRow>
|
|
|
+ ))
|
|
|
+ )}
|
|
|
+ </TableBody>
|
|
|
+ </Table>
|
|
|
+
|
|
|
+ {/* 分页 */}
|
|
|
+ {data.total > 0 && (
|
|
|
+ <div className="p-4">
|
|
|
+ <DataTablePagination
|
|
|
+ currentPage={filters.page}
|
|
|
+ pageSize={filters.limit}
|
|
|
+ totalCount={data.total}
|
|
|
+ onPageChange={(page, pageSize) => setFilters({ ...filters, page, limit: pageSize })}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
|
|
|
{/* 操作按钮区域 - 占位符功能,待实现 */}
|
|
|
- <div className="mt-4 flex gap-2" data-testid="action-buttons">
|
|
|
- <button
|
|
|
- className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 opacity-50 cursor-not-allowed"
|
|
|
- title="此功能待实现"
|
|
|
+ <div className="flex gap-2" data-testid="action-buttons">
|
|
|
+ <Button
|
|
|
disabled
|
|
|
+ title="此功能待实现"
|
|
|
>
|
|
|
新增
|
|
|
- </button>
|
|
|
- <button
|
|
|
- className="px-4 py-2 border rounded hover:bg-gray-50 opacity-50 cursor-not-allowed"
|
|
|
- title="此功能待实现"
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ variant="outline"
|
|
|
disabled
|
|
|
+ title="此功能待实现"
|
|
|
>
|
|
|
编辑
|
|
|
- </button>
|
|
|
- <button
|
|
|
- className="px-4 py-2 border rounded hover:bg-gray-50 opacity-50 cursor-not-allowed"
|
|
|
- title="此功能待实现"
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ variant="outline"
|
|
|
disabled
|
|
|
+ title="此功能待实现"
|
|
|
>
|
|
|
删除
|
|
|
- </button>
|
|
|
+ </Button>
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|