chore: initial commit - maqt-desktop v0.2

- Phase 1-5: UI framework, auth, weapon schemes, color filters, system optimization
- Industrial/tech design style with Chinese localization
- Points to gch3n.online/delta backend API
- Hardware monitor, filter editor, and all module pages
This commit is contained in:
Chen Gu
2026-05-09 00:31:09 +08:00
commit 5bd314deb2
80 changed files with 12217 additions and 0 deletions

115
src/pages/WeaponSchemes.tsx Normal file
View File

@@ -0,0 +1,115 @@
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-3 p-3 flex-1">
{/* 标题 */}
<div className="flex items-center justify-between border-b border-[#333] pb-2">
<h1 className="text-[11px] 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-[8px] 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>
);
}