From 0681ca8b3422a29ed3df8469d448b8cb8a0a57b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B4=E5=9E=9A=20=E8=8C=83?= <2664438031@qq.com> Date: Mon, 25 May 2026 14:04:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=AD=A6=E5=99=A8=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...{OIP-removebg-preview.png => footer-2.png} | Bin src/components/mod-codes/index.tsx | 357 +++++++++++++ src/index.css | 146 +++++- src/layout/hero-layout/index.tsx | 18 +- src/page/firearms/index.tsx | 487 +++++++++++++----- src/page/mod-codes/index.tsx | 2 +- 6 files changed, 864 insertions(+), 146 deletions(-) rename public/{OIP-removebg-preview.png => footer-2.png} (100%) create mode 100644 src/components/mod-codes/index.tsx diff --git a/public/OIP-removebg-preview.png b/public/footer-2.png similarity index 100% rename from public/OIP-removebg-preview.png rename to public/footer-2.png diff --git a/src/components/mod-codes/index.tsx b/src/components/mod-codes/index.tsx new file mode 100644 index 0000000..f935f2b --- /dev/null +++ b/src/components/mod-codes/index.tsx @@ -0,0 +1,357 @@ +// 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 "@/store/hooks"; + +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(); + }} + /> + + ); +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index 63db6f0..d465b22 100644 --- a/src/index.css +++ b/src/index.css @@ -2,7 +2,8 @@ @import 'tailwindcss'; -html, body { +html, +body { margin: 0; padding: 0; width: 100%; @@ -38,6 +39,7 @@ html, body { .nav-item { position: relative; overflow: hidden; + z-index: 1; } .nav-item::after { @@ -51,15 +53,151 @@ html, body { transition: height 0.2s ease-in-out; opacity: 0.35; pointer-events: none; - + z-index: -1; + } -.nav-item:hover::after, +.nav-item:hover::after { + height: 30%; +} + +/* 激活状态效果 */ .nav-item.active::after { - height: 80%; /* 向上打光的高度,可以调整 */ + height: 30%; +} + +/* 可选:激活+悬停效果 */ +.nav-item.active:hover::after { + opacity: 0.35; +} + +.custom-btn-outlined { + --ant-color-solid: #10E28C; + /* 边框和文字颜色 */ + --ant-color-solid-hover: #2ee59d; + --ant-color-solid-active: #0cb878; +} + + +.hex-bg { + background-color: #1E1E1E; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' opacity='0.3' viewBox='0 0 100 100'%3E%3Cdefs%3E%3ClinearGradient id='fadeDown' x1='0%25' y1='0%25' x2='0%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%2339ff14' stop-opacity='1' /%3E%3Cstop offset='100%25' stop-color='%2339ff14' stop-opacity='0' /%3E%3C/linearGradient%3E%3C/defs%3E%3Cg fill='none' stroke='url(%23fadeDown)' stroke-width='0.5'%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546041,-0.85081805,0.85081805,0.52546041,-203.01888079,130.22116071)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-190.65208214,130.43446239)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-197.04868859,141.09544261)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-184.68192833,141.30866893)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-178.2853524,130.6476887)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-172.3151986,141.52187999)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-190.86530846,152.18286021)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-178.49857872,152.39608653)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-203.44526451,151.88976939)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-165.94457787,152.72932323)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-197.30770653,163.1089619)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-184.99694603,163.40205272)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-172.3930642,163.69517406)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-165.94457787,130.86648448)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-178.84158104,174.24726756)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-166.23769921,174.68691905)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-160.08231896,163.69518931)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-159.78921288,141.71168407)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-160.37542504,185.6786793)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-172.68620079,185.53211864)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-209.32536095,140.83235057)'/%3E%3Cpath d='M225 131.704L230.452 134.852 230.452 141.148 225 144.296 219.548 141.148 219.548 134.852Z' transform='matrix(0.52546006,-0.85081827,0.85081827,0.52546006,-215.48072594,129.98715098)'/%3E%3C/g%3E%3C/svg%3E"); + background-size: 350px 350px; + background-position: right -90px top -40px; + background-repeat: no-repeat; + margin: 0; + } .nav-item:hover, .nav-item.active { color: white; +} + + +/* LeftMiddleRightBox.css */ +.lmr-container { + display: flex; + width: 100%; + /* 可根据需要调整 */ + overflow: hidden; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); + background: '#555555'; + color: 'white'; + padding: '4px 12px'; + border-radius: '4px'; + font-size: '14px'; + font-weight: '500'; + letter-spacing: '0.5px'; +} + +/* 公共列样式:平均分配宽度,带有视觉区分 */ +.lmr-left, +.lmr-middle, +.lmr-right { + padding: 20px; + transition: all 0.2s ease; + height: 100%; +} + +/* 为左右中区域添加微妙的背景色差异,便于区分 */ +.lmr-left { + flex: 1; + background-color: '#555555'; + color: 'white'; + padding: '4px 12px'; + border-radius: '4px'; + font-size: '14px'; + font-weight: '500'; + letter-spacing: '0.5px'; + margin: auto; +} + +.lmr-middle { + flex: 3; + background-color: '#555555'; + color: 'white'; + padding: '4px 12px'; + border-radius: '4px'; + font-size: '14px'; + font-weight: '500'; + letter-spacing: '0.5px'; +} + +.lmr-right { + flex: 2; + background-color: '#555555'; + color: 'white'; + padding: '4px 12px'; + border-radius: '4px'; + font-size: '14px'; + font-weight: '500'; + letter-spacing: '0.5px'; +} + +.content-placeholder { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + justify-content: center; + height: 100%; + border-radius: 12px; + padding: 16px; +} + + +/* 响应式:小屏幕下自动转为垂直排列 */ +@media (max-width: 768px) { + .lmr-container { + flex-direction: column; + min-height: auto; + } + + .lmr-left, + .lmr-middle, + .lmr-right { + border-right: none; + + } + + .lmr-right { + border-bottom: none; + } + + .content-placeholder { + min-height: 100px; + } +} + +.css-var-_r_1_.ant-collapse{ + --ant-collapse-header-bg:#1e1e1e; + width: 90%; + border: 0; + margin-left: auto; + margin-right: auto; +} + +.ant-collapse-body{ + background: #1e1e1e; } \ No newline at end of file diff --git a/src/layout/hero-layout/index.tsx b/src/layout/hero-layout/index.tsx index e6722ad..34d6d76 100644 --- a/src/layout/hero-layout/index.tsx +++ b/src/layout/hero-layout/index.tsx @@ -26,7 +26,7 @@ export default function HeroLayout() { } return ( -
+
{/* Navigation Header */}
@@ -34,25 +34,25 @@ export default function HeroLayout() {

三角洲行动改枪码库

-
+ + + ))} + {firearms.length === 0 && ( + + + 暂无武器数据 + + + )} + +
+
+ { + setPage(nextPage) + }} + showSizeChanger={false} + /> +
+ setCreateModalOpen(false)} + onSuccess={() => { + setCreateModalOpen(false) + void loadFirearms() }} - showSizeChanger={false} /> -
- setCreateModalOpen(false)} - onSuccess={() => { - setCreateModalOpen(false) - void loadFirearms() - }} - /> + setEditingFirearm(null)} + onSuccess={() => { + setEditingFirearm(null) + void loadFirearms() + }} - setEditingFirearm(null)} - onSuccess={() => { - setEditingFirearm(null) - void loadFirearms() - }} - /> + /> + + ) } diff --git a/src/page/mod-codes/index.tsx b/src/page/mod-codes/index.tsx index e3afcd1..5b35be0 100644 --- a/src/page/mod-codes/index.tsx +++ b/src/page/mod-codes/index.tsx @@ -192,7 +192,7 @@ export default function ModCodesPage() { 复制 - + 作者: {modification.author || "未知"}