116 lines
4.5 KiB
TypeScript
116 lines
4.5 KiB
TypeScript
import React, { useEffect, useState, useCallback } from 'react';
|
|
import CategoryTabs from '../components/schemes/CategoryTabs';
|
|
import SchemeList from '../components/schemes/SchemeList';
|
|
import type { SchemeData } from '../components/schemes/SchemeCard';
|
|
import { getSchemes, getCategory, useScheme } from '../services/schemes.api';
|
|
import { addFavorite, removeFavorite, checkFavorite } from '../services/favorites.api';
|
|
import { useAuthStore } from '../stores/authStore';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useToast } from '../components/ui/Toast';
|
|
|
|
const DEFAULT_CATEGORIES = [
|
|
{ code: 'AR', name: '突击步枪' }, { code: 'SMG', name: '冲锋枪' },
|
|
{ code: 'SR', name: '狙击枪' }, { code: 'LMG', name: '轻机枪' },
|
|
{ code: 'SG', name: '霰弹枪' }, { code: 'Pistol', name: '手枪' },
|
|
{ code: 'Launcher', name: '发射器' },
|
|
];
|
|
|
|
export default function WeaponSchemes() {
|
|
const navigate = useNavigate();
|
|
const toast = useToast();
|
|
const isLoggedIn = useAuthStore(s => s.isLoggedIn);
|
|
|
|
const [categories, setCategories] = useState<Array<{ code: string; name: string }>>(DEFAULT_CATEGORIES);
|
|
const [activeCode, setActiveCode] = useState('AR');
|
|
const [schemes, setSchemes] = useState<SchemeData[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [page, setPage] = useState(1);
|
|
const [totalPages, setTotalPages] = useState(1);
|
|
const [favoritedIds, setFavoritedIds] = useState<Set<string>>(new Set());
|
|
const [sort, setSort] = useState<'hot' | 'new'>('hot');
|
|
|
|
useEffect(() => {
|
|
getCategory('AR').then(r => {
|
|
if (r.success && Array.isArray(r.data) && r.data.length > 0) {
|
|
setCategories(r.data);
|
|
}
|
|
}).catch(() => {});
|
|
}, []);
|
|
|
|
const loadSchemes = useCallback(async (code: string, p: number, s: string) => {
|
|
setLoading(true);
|
|
try {
|
|
const res = await getSchemes({ sort: s, page: p, limit: 12, source: code, weaponCategory: code });
|
|
if (res.success && Array.isArray(res.data)) {
|
|
setSchemes(res.data || []);
|
|
setTotalPages(Math.ceil((res as any).total || res.data.length / 12));
|
|
} else { setSchemes([]); }
|
|
} catch { setSchemes([]); }
|
|
finally { setLoading(false); }
|
|
}, []);
|
|
|
|
useEffect(() => { loadSchemes(activeCode, page, sort); }, [activeCode, page, sort, loadSchemes]);
|
|
|
|
const handleCategoryChange = (code: string) => { setActiveCode(code); setPage(1); };
|
|
|
|
const handleFavorite = async (id: string) => {
|
|
if (!isLoggedIn) { toast('warning', '请先登录'); navigate('/login'); return; }
|
|
try {
|
|
if (favoritedIds.has(id)) {
|
|
await removeFavorite(id);
|
|
setFavoritedIds(prev => { const n = new Set(prev); n.delete(id); return n; });
|
|
toast('success', '已取消收藏');
|
|
} else {
|
|
await addFavorite({ targetId: id, targetType: 'Scheme' });
|
|
setFavoritedIds(prev => new Set(prev).add(id));
|
|
toast('success', '已收藏');
|
|
}
|
|
} catch { toast('error', '操作失败'); }
|
|
};
|
|
|
|
const handleUse = async (id: string) => {
|
|
if (!isLoggedIn) { toast('warning', '请先登录'); navigate('/login'); return; }
|
|
try {
|
|
await useScheme(id, activeCode);
|
|
toast('success', '方案使用记录已保存');
|
|
} catch { toast('error', '操作失败'); }
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col gap-4 p-4 flex-1">
|
|
{/* 标题 */}
|
|
<div className="flex items-center justify-between border-b border-[#333] pb-2">
|
|
<h1 className="text-[34px] font-bold tracking-[0.15em] uppercase">改枪方案</h1>
|
|
<div className="flex gap-1">
|
|
{(['hot', 'new'] as const).map(s => (
|
|
<button
|
|
key={s}
|
|
onClick={() => { setSort(s); setPage(1); }}
|
|
className={`px-2 py-1 text-[15px] font-semibold tracking-[0.08em] uppercase border transition-colors duration-75
|
|
${sort === s ? 'border-[#ff4500] text-[#ff4500] bg-[#ff4500]/10' : 'border-[#333] text-[#555] hover:border-[#555]'}`}
|
|
>
|
|
{s === 'hot' ? '🔥 热门' : '🕐 最新'}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 分类标签 */}
|
|
<CategoryTabs categories={categories} activeCode={activeCode} onSelect={handleCategoryChange} />
|
|
|
|
{/* 方案列表 */}
|
|
<SchemeList
|
|
schemes={schemes}
|
|
loading={loading}
|
|
favoritedIds={favoritedIds}
|
|
page={page}
|
|
totalPages={totalPages}
|
|
onPageChange={setPage}
|
|
onFavorite={handleFavorite}
|
|
onUse={handleUse}
|
|
onClick={(id) => navigate(`/scheme-detail/${id}`)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|