// aislop-ignore-file: duplicate-block -- 单元格渲染结构相似且字段不同,逻辑已通过 EditableStudentCell 共享 import React from 'react'; import { Button, Popconfirm, Space, Tag } from 'antd'; import { EyeOutlined, InboxOutlined, UndoOutlined } from '@ant-design/icons'; import PermissionButton from '../../components/PermissionButton'; import EditableCell from '../../components/EditableCell'; import { maskIdNumber, maskPhone } from '../../utils/sensitive'; export const statusMap: Record = { active: { text: '在读', color: 'green' }, graduated: { text: '已毕业', color: 'blue' }, withdrawn: { text: '已退训', color: 'red' }, archived: { text: '已归档', color: '#999' }, }; export const STUDENT_FIELDS = { name: 'name', studentNo: 'studentNo', ethnicity: 'ethnicity', emergencyContact: 'emergencyContact', supervisor: 'supervisor', status: 'status', organizationId: 'organizationId', } as const; export const SENSITIVE_LABELS = { phone: '电话', idNumber: '身份证号', emergencyPhone: '紧急联系人电话', } as const; export const STUDENT_STATUS_OPTIONS = [ { value: 'active', label: '在读' }, { value: 'graduated', label: '已毕业' }, { value: 'withdrawn', label: '已退训' }, ]; export interface StudentColumnContext { pageInfo: { current: number; pageSize: number }; organizations: Array<{ id: number; name: string; isHost?: boolean }>; canChooseOrganization: boolean; canEditStudent: boolean; canDeleteStudent: boolean; canPurgeStudent: boolean; canViewSensitive: boolean; onSaveCell: (record: any, field: string, value: unknown) => Promise | void; onViewSensitive: (recordId: number, field: string, value: string) => void; onOpenDrawer: (recordId: number) => void; onEdit: (record: any) => void; onRestore: (id: number) => Promise | unknown; onPurge: (id: number, name: string) => void; onArchive: (id: number) => Promise | unknown; } export const EditableStudentCell = ({ value, field, record, editor, min, max, required, options, onSave, children, }: { value: unknown; field: string; record: R; editor?: React.ComponentProps['editor']; min?: number; max?: number; required?: boolean; options?: Array<{ value: string | number; label: string }>; onSave: (record: R, field: string, value: unknown) => Promise | void; children?: React.ReactNode; }) => ( { await onSave(record, field, next); }} > {children ?? String(value ?? '-')} ); export const SensitiveValue: React.FC<{ value: string; masked: string; label: string; recordId: number; canViewSensitive: boolean; onViewSensitive: (recordId: number, field: string, value: string) => void; }> = ({ value, masked, label, recordId, canViewSensitive, onViewSensitive }) => { if (!value) return <>-; return ( {masked} {canViewSensitive ? ( ) : null} ); }; function buildIdentityColumns(ctx: StudentColumnContext) { const { pageInfo, canViewSensitive, onSaveCell, onViewSensitive, } = ctx; return [ { title: '序号', key: 'index', width: 70, render: (_: unknown, __: unknown, index: number) => (pageInfo.current - 1) * pageInfo.pageSize + index + 1, }, { title: '姓名', dataIndex: 'name', width: 120, render: (v: string, record: any) => ( {v} ), }, { title: '电话', dataIndex: 'phone', width: 140, render: (v: string, record: any) => ( ), }, { title: '学号', dataIndex: 'studentNo', width: 120, render: (v: string, record: any) => ( {v || '-'} ), }, { title: '身份证', dataIndex: 'idNumber', width: 180, render: (v: string, record: any) => ( ), }, ]; } function buildContactColumns(ctx: StudentColumnContext) { const { organizations, canChooseOrganization, canViewSensitive, onSaveCell, onViewSensitive } = ctx; return [ { title: '民族', dataIndex: 'ethnicity', width: 90, render: (v: string, record: any) => ( {v || '-'} ), }, { title: '紧急联系人', dataIndex: 'emergencyContact', width: 100, render: (v: string, record: any) => ( {v || '-'} ), }, { title: '紧急联系人电话', dataIndex: 'emergencyPhone', width: 150, render: (v: string, record: any) => ( ), }, { title: '所属机构', dataIndex: 'organization', width: 100, render: (organization: { name?: string } | null, record: any) => canChooseOrganization ? ( ({ value: item.id, label: item.name }))} required onSave={onSaveCell} > {organization?.name ? ( {organization.name} ) : ( '-' )} ) : organization?.name ? ( {organization.name} ) : ( '-' ), }, ]; } function buildProfileColumns(ctx: StudentColumnContext) { const { onSaveCell } = ctx; return [ { title: '负责人', dataIndex: 'supervisor', width: 100, render: (v: string, record: any) => ( {v || '-'} ), }, { title: '状态', dataIndex: 'status', width: 80, render: (s: string, record: any) => ( {statusMap[s]?.text || s} ), }, ]; } function buildActionColumn(ctx: StudentColumnContext) { const { canEditStudent, canDeleteStudent, canPurgeStudent, onOpenDrawer, onEdit, onRestore, onPurge, onArchive, } = ctx; return { title: '操作', fixed: 'right' as const, width: 180, render: (_: any, record: any) => ( {record.status === 'archived' ? ( <> {canEditStudent ? ( onRestore(record.id)} okText="恢复" cancelText="取消" > ) : null} {canPurgeStudent ? ( ) : null} ) : ( <> onOpenDrawer(record.id)} > 档案 onEdit(record)}> 编辑 {canDeleteStudent ? ( onArchive(record.id)} okText="归档" cancelText="取消" > ) : null} )} ), }; } export function buildStudentColumns(ctx: StudentColumnContext) { return [ ...buildIdentityColumns(ctx), ...buildContactColumns(ctx), ...buildProfileColumns(ctx), buildActionColumn(ctx), ]; }