feat(admin-web): 用户管理高级筛选增加"已认种/未认种"过滤

在用户管理页面的"用户状态"下拉框中新增"已认种"和"未认种"两个筛选选项。

实现方式:
- 复用后端已有的 minAdoptions/maxAdoptions 查询参数
- "已认种"映射为 minAdoptions=1(personalAdoptionCount >= 1)
- "未认种"映射为 maxAdoptions=0(personalAdoptionCount = 0)
- 与原有"正常/冻结"状态筛选互斥(同一下拉框)
- 切换筛选时自动重置分页到第 1 页

后端无改动:admin-service 的 ListUsersDto 和 UserQueryRepository
已支持 minAdoptions/maxAdoptions 参数及对应的 WHERE 条件。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-03 07:58:24 -08:00
parent 126169c631
commit 50dc18a224
1 changed files with 34 additions and 3 deletions

View File

@ -49,11 +49,32 @@ export default function UsersPage() {
const [keyword, setKeyword] = useState('');
const [showFilters, setShowFilters] = useState(false);
const [selectedRows, setSelectedRows] = useState<string[]>([]);
// 用户状态/认种状态筛选
// 可选值: '' (全部) | 'ACTIVE' (正常) | 'FROZEN' (冻结) | 'adopted' (已认种) | 'not_adopted' (未认种)
const [statusFilter, setStatusFilter] = useState('');
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
});
// 根据 statusFilter 映射为 API 查询参数
// 'ACTIVE'/'FROZEN' → status 参数(后端 DTO 校验要求大写)
// 'adopted' → minAdoptions: 1personalAdoptionCount >= 1
// 'not_adopted' → maxAdoptions: 0personalAdoptionCount = 0
const filterParams = (() => {
switch (statusFilter) {
case 'ACTIVE':
case 'FROZEN':
return { status: statusFilter };
case 'adopted':
return { minAdoptions: 1 };
case 'not_adopted':
return { maxAdoptions: 0 };
default:
return {};
}
})();
// 使用 React Query hooks 获取用户列表
const {
data: usersData,
@ -62,6 +83,7 @@ export default function UsersPage() {
refetch,
} = useUsers({
keyword: keyword || undefined,
...filterParams,
page: pagination.current,
pageSize: pagination.pageSize,
sortBy: 'registeredAt',
@ -290,10 +312,19 @@ export default function UsersPage() {
<option value="shenzhen"></option>
<option value="guangzhou">广</option>
</select>
<select className={styles.users__paginationSelect}>
<select
className={styles.users__paginationSelect}
value={statusFilter}
onChange={(e) => {
setStatusFilter(e.target.value);
setPagination((prev) => ({ ...prev, current: 1 }));
}}
>
<option value=""></option>
<option value="active"></option>
<option value="frozen"></option>
<option value="ACTIVE"></option>
<option value="FROZEN"></option>
<option value="adopted"></option>
<option value="not_adopted"></option>
</select>
</div>
)}