// ModCodes.tsx import { useEffect, useState, useCallback, useMemo } from "react"; import { Card, Col, Pagination, Row, Tag, Typography, Button, Popconfirm, Space, Select, App } from "antd"; import { Link } from "react-router-dom"; import { ModificationApi, TagApi } from "@/api"; import { Modification } from "@/types"; import ModificationCreateModal from "@/components/modification-create-modal"; import ModificationEditModal from "@/components/modification-edit-modal"; import { useAppSelector } from "@/hooks/store"; const pageSize = 10; // 常量,不需要 useState interface ModCodesProps { firearmId: string; // 从父组件传入 } export default function ModCodes({ firearmId }: ModCodesProps) { const { message } = App.useApp(); const user = useAppSelector((state) => state.auth.user); // ✅ 所有 useState 必须放在组件函数内部 const [createModalOpen, setCreateModalOpen] = useState(false); const [editingModification, setEditingModification] = useState(null); const [loading, setLoading] = useState(false); const [modifications, setModifications] = useState([]); const [tagOptions, setTagOptions] = useState([]); const [selectedTags, setSelectedTags] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [deletingId, setDeletingId] = useState(null); // 获取标签选项 useEffect(() => { const _firearmId = firearmId ? Number(firearmId) : undefined; if (_firearmId) { TagApi.getTags(_firearmId).then(setTagOptions); } }, [firearmId]); // 加载改枪码列表 const loadModifications = useCallback(async () => { const numericId = firearmId if (!numericId) return; setLoading(true); try { const pagedData = await ModificationApi.getModifications({ page: page - 1, size: pageSize, sortBy: "id", direction: "ASC", firearmId: numericId, // 使用数字类型 tags: selectedTags, }); setModifications(pagedData.items); setTotal(pagedData.totalElements); } finally { setLoading(false); } }, [firearmId, page, selectedTags]); useEffect(() => { loadModifications(); }, [loadModifications]); const handleDelete = async (modification: Modification) => { setDeletingId(modification.id); try { await ModificationApi.removeModification(modification.id); message.success("删除成功"); if (modifications.length === 1 && page > 1) { setPage(page - 1); } else { await loadModifications(); } } catch { message.error("删除失败"); } finally { setDeletingId(null); } }; // 当 firearmId 或标签改变时重置分页 useEffect(() => { setPage(1); }, [firearmId, selectedTags]); const parsedFirearmId = useMemo(() => { const value = Number(firearmId); return isNaN(value) ? undefined : value; }, [firearmId]); if (!parsedFirearmId) { return 无效的武器 ID; } const tagColors = [ '#e28010', // 青绿 '#0EA5E9', // 天蓝 '#8B5CF6', // 紫色 '#F59E0B', // 琥珀 '#EF4444', // 红色 '#EC4899', // 粉红 ]; return (
标签: mode="multiple" allowClear placeholder="请选择标签" className="w-64" value={selectedTags} options={tagOptions.map((tag) => ({ value: tag, label: tag }))} onChange={(values) => { setSelectedTags(values); }} /> {firearmId && 武器 ID: {firearmId}} {(firearmId || selectedTags.length > 0) && ( )} {user && ( )}
{modifications.map((modification) => ( handleDelete(modification)} >
) : null } variant="outlined" styles={{ root: { background: '#35333385' }, header: { minHeight: 56 }, }} >
{/* 改枪码行 */}
改枪码: {modification.code}
{/* 作者 */}
作者: {modification.author || "未知"}
{/* 标签列表 */} {(modification.tags?.length || 0) > 0 && (
{(modification.tags || []).map((tag,idx) => ( {tag} ))}
)} {/* 配件配置区域 */}
配件配置:
{(modification.accessories?.length || 0) > 0 ? (
{(modification.accessories || []).map((accessory, accessoryIndex) => (
{accessory.slotName || "未填写槽位"} {accessory.accessoryName || "未填写配件"}
{(accessory.tunings?.length || 0) > 0 ? (
{accessory.tunings.map((tuning, tuningIndex) => ( {tuning.tuningName || "未命名"}: {tuning.tuningValue ?? "-"} ))}
) : null}
))}
) : ( 暂无配件信息 )}
{/* 备注 */}
{modification.note || "暂无备注"}
{/* 视频链接 */}
{modification.videoUrl && ( )}
))} {modifications.length === 0 && ( 暂无改枪码数据 )}
{ setPage(nextPage); }} showSizeChanger={false} />
setCreateModalOpen(false)} onSuccess={() => { setCreateModalOpen(false); void loadModifications(); }} /> setEditingModification(null)} onSuccess={() => { setEditingModification(null); void loadModifications(); }} /> ); }