* 主组件
()
| 71 | * 主组件 |
| 72 | */ |
| 73 | function ScriptList() { |
| 74 | const { t } = useTranslation(); |
| 75 | const [usp] = useSearchParams(); |
| 76 | const { guideMode } = useAppContext(); |
| 77 | |
| 78 | // 1. 基础 UI 状态 |
| 79 | const [sidebarOpen, setSidebarOpen] = useState(() => localStorage.getItem("script-list-sidebar") === "1"); |
| 80 | const [viewMode, setViewMode] = useState<"table" | "card">(() => { |
| 81 | const saved = localStorage.getItem("script-list-view-mode"); |
| 82 | if (saved === "table" || saved === "card") return saved; |
| 83 | return window.screen.width < 1280 ? "card" : "table"; |
| 84 | }); |
| 85 | const [selectedFilters, setSelectedFilters] = useState<TSelectFilter>({ |
| 86 | status: null, |
| 87 | type: null, |
| 88 | tags: null, |
| 89 | source: null, |
| 90 | }); |
| 91 | const [searchRequest, setSearchRequest] = useState<SearchFilterRequest>({ keyword: "", type: "auto" }); |
| 92 | |
| 93 | // 2. 弹窗状态 (独立状态,不会引起 MainContent 重绘) |
| 94 | const [userConfig, setUserConfig] = useState<{ |
| 95 | script: Script; |
| 96 | userConfig: UserConfig; |
| 97 | values: Record<string, any>; |
| 98 | }>(); |
| 99 | const [cloudScript, setCloudScript] = useState<Script>(); |
| 100 | |
| 101 | // 3. 数据与统计 Hook |
| 102 | const { scriptList, setScriptList, loadingList } = useScriptDataManagement(); |
| 103 | const { stats, filterItems } = useScriptFilters(scriptList, selectedFilters, searchRequest, t); |
| 104 | const [filterScriptList, setFilterScriptList] = useState<ScriptLoading[]>([]); |
| 105 | |
| 106 | // 4. 更新函数 (useCallback 保证引用稳定) |
| 107 | const updateScripts = useCallback( |
| 108 | (uuids: string[], data: Partial<ScriptLoading>) => { |
| 109 | const set = new Set(uuids); |
| 110 | setScriptList((list) => { |
| 111 | let changed = false; |
| 112 | const newList = list.map((s) => { |
| 113 | if (set.has(s.uuid)) { |
| 114 | let hasDiff = false; |
| 115 | const next = { ...s }; |
| 116 | for (const [k, v] of Object.entries(data)) { |
| 117 | if ((s as any)[k] !== v) { |
| 118 | hasDiff = true; |
| 119 | (next as any)[k] = v; |
| 120 | } |
| 121 | } |
| 122 | if (hasDiff) { |
| 123 | changed = true; |
| 124 | return next; |
| 125 | } |
| 126 | } |
| 127 | return s; |
| 128 | }); |
| 129 | return changed ? newList : list; |
| 130 | }); |
nothing calls this directly
no test coverage detected