fix: 处理声明问题,优化赛事用户列表

This commit is contained in:
ZhuRui
2026-08-06 15:17:48 +08:00
parent 9d615c8500
commit d85333d058
5 changed files with 60 additions and 75 deletions
+12 -2
View File
@@ -12,7 +12,7 @@ import pageStyles from '@/assets/styles/pageLayout.module.less';
* 架构分层:
* - 数据层:services.tsAPI 调用)
* - 逻辑层:useUserModel.ts(状态 + 业务逻辑 + 交互处理)
* - 视图层:useUserColumns.ts(表格列配置)+ 本组件(纯 UI 渲染)
* - 视图层:useUserColumns.tsx(表格列配置)+ 本组件(纯 UI 渲染)
*/
export default defineComponent({
name: 'EventUsers',
@@ -46,7 +46,7 @@ export default defineComponent({
loading={togglingId.value === record.id}
onClick={() => handleToggleStatus(record)}
>
{isActive ? '用' : '启用'}
{isActive ? '用' : '启用'}
</Button>
);
};
@@ -79,6 +79,16 @@ export default defineComponent({
onPressEnter={handleSearch}
/>
</Form.Item>
<Form.Item label="手机号" name="phone">
<Input
value={filterForm.phone}
placeholder="请输入手机号"
style={{ width: '180px' }}
allowClear
onUpdate:value={(val: any) => (filterForm.phone = val.target?.value ?? val ?? '')}
onPressEnter={handleSearch}
/>
</Form.Item>
<Form.Item label="状态" name="status">
<Select
value={filterForm.status}
+8 -16
View File
@@ -3,12 +3,14 @@
* 集中管理筛选默认值、字段映射、选项配置
*/
import type { StatusTagTone } from '@/components';
// ============================================================
// 筛选默认值
// ============================================================
export const FILTER_DEFAULTS = {
text: '',
roleId: '',
nickname: '',
phone: '',
status: '',
} as const;
@@ -19,8 +21,8 @@ export const FILTER_DEFAULTS = {
type FieldMapping = [keyof typeof FILTER_DEFAULTS, string, ((v: any) => any)?];
export const FIELD_MAPPINGS: FieldMapping[] = [
['text', 'text', (v) => v?.trim?.() ?? v],
['roleId', 'roleId'],
['nickname', 'nickname', (v) => v?.trim?.() ?? v],
['phone', 'phone'],
['status', 'status'],
];
@@ -29,25 +31,15 @@ export const FIELD_MAPPINGS: FieldMapping[] = [
// ============================================================
export const USER_STATUS_OPTIONS = [
{ value: '', label: '全部' },
{ value: '0', label: '用' },
{ value: '0', label: '用' },
{ value: '1', label: '正常' },
] as const;
/** 角色选项(TODO: 对接角色 API) */
export const ROLE_OPTIONS = [
{ value: '', label: '全部' },
{ value: '1', label: '超级管理员' },
{ value: '2', label: '赛事管理员' },
{ value: '3', label: '裁判' },
{ value: '4', label: '财务' },
] as const;
// ============================================================
// 状态映射(用于 StatusTag 渲染)
// ============================================================
import type { StatusTagTone } from '@/components';
export const STATUS_MAP: Record<string, { label: string; tone: StatusTagTone }> = {
'1': { label: '正常', tone: 'success' },
'0': { label: '用', tone: 'danger' },
'0': { label: '用', tone: 'danger' },
};
+3 -2
View File
@@ -18,14 +18,15 @@ import type {
/** 赛事用户列表项 */
export interface EventUserVO {
id: number;
id: string;
nickname: string;
phone: string;
realName: string;
idCard: string;
idCardImg: string;
idCardImgList: string[];
status: number;
gender: string;
status: string;
createTime: string;
}
@@ -1,6 +1,4 @@
import { h, type VNodeChild } from 'vue';
import { Image, Space } from 'ant-design-vue';
import type { ImageProps } from 'ant-design-vue/es/image';
import { StatusTag } from '@/components';
import { STATUS_MAP } from './config';
@@ -10,6 +8,9 @@ const GENDER_MAP: Record<string, string> = {
'2': '女',
};
/** 空值占位 */
const E = (v: string | undefined | null) => v || '--';
/**
* -
*
@@ -24,6 +25,7 @@ export function useUserColumns() {
key: 'nickname',
width: 140,
align: 'center' as const,
customRender: ({ text }: { text: string }) => E(text),
},
{
title: '用户姓名',
@@ -31,6 +33,7 @@ export function useUserColumns() {
key: 'realName',
width: 110,
align: 'center' as const,
customRender: ({ text }: { text: string }) => E(text),
},
{
title: '手机号',
@@ -38,6 +41,7 @@ export function useUserColumns() {
key: 'phone',
width: 140,
align: 'center' as const,
customRender: ({ text }: { text: string }) => E(text),
},
{
title: '性别',
@@ -45,7 +49,7 @@ export function useUserColumns() {
key: 'gender',
width: 80,
align: 'center' as const,
customRender: ({ text }: { text: string }) => GENDER_MAP[text] || '',
customRender: ({ text }: { text: string }) => GENDER_MAP[text] || '--',
},
{
title: '证件号',
@@ -53,6 +57,7 @@ export function useUserColumns() {
key: 'idCard',
width: 120,
align: 'center' as const,
customRender: ({ text }: { text: string }) => E(text),
},
{
title: '证件图片',
@@ -60,26 +65,21 @@ export function useUserColumns() {
key: 'idCardImgList',
width: 120,
align: 'center' as const,
customRender: ({ text }: { text: string[] }): VNodeChild => {
customRender: ({ text }: { text: string[] }) => {
const imgList = Array.isArray(text) ? text : [];
if (imgList.length === 0) return '--';
return h(
Space,
{ size: 4 },
{
default: () =>
imgList.map((url, index) =>
h<ImageProps>(Image, {
key: index,
src: url,
alt: `证件图${index + 1}`,
width: 40,
height: 40,
style: { objectFit: 'cover', borderRadius: '4px', cursor: 'pointer' },
preview: true,
}),
),
},
if (imgList.length === 0) return <span>--</span>;
return (
<Space size={4}>
{imgList.map((url, index) => (
<Image
key={index}
src={url}
width={40}
height={40}
style={{ objectFit: 'cover', borderRadius: '4px', cursor: 'pointer' }}
/>
))}
</Space>
);
},
},
@@ -89,6 +89,7 @@ export function useUserColumns() {
key: 'createTime',
width: 170,
align: 'center' as const,
customRender: ({ text }: { text: string }) => E(text),
},
{
title: '状态',
@@ -97,8 +98,8 @@ export function useUserColumns() {
width: 90,
align: 'center' as const,
customRender: ({ text }: { text: string }) => {
const info = STATUS_MAP[text] || { label: text, tone: 'default' as const };
return h(StatusTag, { label: info.label, tone: info.tone });
const info = STATUS_MAP[text] || { label: text || '--', tone: 'default' as const };
return <StatusTag label={info.label} tone={info.tone} />;
},
},
];
+12 -31
View File
@@ -1,13 +1,9 @@
import { computed, reactive, toRef, Ref, type UnwrapRef } from 'vue';
import { computed, reactive } from 'vue';
import { Modal, message } from 'ant-design-vue';
import { useState, useDebounce } from '@/hooks';
import { useState } from '@/hooks';
import { useRequest } from '@/hooks/useRequest';
import { useEffect } from '@/hooks/useEffect';
import {
usePagination,
syncPaginationTotal,
type UsePaginationReturn,
} from '@/hooks/usePagination';
import { usePagination, syncPaginationTotal } from '@/hooks/usePagination';
import { hasValue, isEmptyValue, safeTransform } from '@/utils';
import {
getUserList,
@@ -17,19 +13,9 @@ import {
type PageData,
type ApiResult,
} from './services';
import {
FILTER_DEFAULTS,
FIELD_MAPPINGS,
USER_STATUS_OPTIONS,
ROLE_OPTIONS,
STATUS_MAP,
} from './config';
import { FILTER_DEFAULTS, FIELD_MAPPINGS, USER_STATUS_OPTIONS, STATUS_MAP } from './config';
export { USER_STATUS_OPTIONS, ROLE_OPTIONS, STATUS_MAP };
// 提取 Pagination Ref 类型
type PaginationRef = UnwrapRef<UsePaginationReturn>;
type PageSizeRef = PaginationRef['pageSize'];
export { USER_STATUS_OPTIONS, STATUS_MAP };
/**
* 用户列表页数据模型
@@ -38,7 +24,7 @@ type PageSizeRef = PaginationRef['pageSize'];
* 架构分层:
* - 数据层:services.tsAPI 调用)
* - 逻辑层:本文件(状态 + 业务逻辑)
* - 视图层:useUserColumns.ts + index.tsx(纯 UI 渲染)
* - 视图层:useUserColumns.tsx + index.tsx(纯 UI 渲染)
*/
export function useUserModel() {
// ===== 筛选表单状态 =====
@@ -50,11 +36,6 @@ export function useUserModel() {
// ===== 分页管理 =====
const pagination = usePagination({ defaultCurrent: 1, defaultPageSize: 10 });
// ===== 防抖处理 =====
const { debouncedValue: debouncedText } = useDebounce(toRef(filterForm, 'text') as Ref<string>, {
delay: 300,
});
// ===== 构建查询参数 =====
const buildQueryParams = (): UserListQueryParams => {
const { page, pageSize } = pagination.params.value;
@@ -104,15 +85,15 @@ export function useUserModel() {
// ===== 计算属性 =====
const hasFilter = computed(() => {
const f = filterForm;
return !!debouncedText.value?.trim() || !!f.roleId || !!f.status;
return !!f.nickname?.trim() || !!f.phone?.trim() || !!f.status;
});
// ===== 事件处理 =====
const handleSearch = () => fetchList();
const handleReset = async () => {
filterForm.text = '';
filterForm.roleId = '';
filterForm.nickname = '';
filterForm.phone = '';
filterForm.status = '';
pagination.reset();
await fetchList();
@@ -120,16 +101,16 @@ export function useUserModel() {
const handlePageChange = (page: number, pageSize: number) => {
pagination.setCurrent(page);
if (pageSize !== (pagination.pageSize as PageSizeRef)) {
if (pageSize !== pagination.pageSize) {
pagination.setPageSize(pageSize);
}
fetchList();
};
// ===== 启用/用用户 =====
// ===== 启用/用用户 =====
const handleToggleStatus = async (record: TournamentAdminUserVO) => {
const isActive = record.status === '1';
const actionText = isActive ? '用' : '启用';
const actionText = isActive ? '用' : '启用';
Modal.confirm({
title: `${actionText}确认`,