Merge asset statistics and contextual AI assistant into main
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
shishengliang
2026-09-23 16:09:14 +08:00
43 changed files with 5872 additions and 1337 deletions
+25 -10
View File
@@ -1,6 +1,7 @@
import React, { lazy, Suspense, useState, useEffect, useCallback, useMemo, useRef } from 'react';
import {
Truck,
Sparkles,
ChevronDown,
ChevronRight,
Loader2,
@@ -315,17 +316,21 @@ export default function AssetsModule() {
};
const toggleInventoryRegion = (region: string) => {
const newSet = new Set(expandedInventoryRegions);
if (newSet.has(region)) newSet.delete(region);
else newSet.add(region);
setExpandedInventoryRegions(newSet);
setExpandedInventoryRegions(current => {
const next = new Set(current);
if (next.has(region)) next.delete(region);
else next.add(region);
return next;
});
};
const toggleInventoryType = (type: string) => {
const newSet = new Set(expandedInventoryTypes);
if (newSet.has(type)) newSet.delete(type);
else newSet.add(type);
setExpandedInventoryTypes(newSet);
setExpandedInventoryTypes(current => {
const next = new Set(current);
if (next.has(type)) next.delete(type);
else next.add(type);
return next;
});
};
const inventoryTypeFilter = isInventoryFilterOpen
@@ -476,8 +481,6 @@ export default function AssetsModule() {
return (
<div className="min-h-screen bg-[var(--app-bg)] text-gray-800 font-sans p-3 md:p-6 relative">
<AssetsHeader
assistantTrigger={assistantTrigger}
onOpenAssistant={() => setAssistantOpen(true)}
activeTab={activeTab}
setActiveTab={setActiveTab}
theme={theme}
@@ -1701,6 +1704,18 @@ export default function AssetsModule() {
</div>
<RotatingFooterHint className="pb-4" />
<button
ref={assistantTrigger}
type="button"
onClick={() => setAssistantOpen(true)}
aria-label="打开 AI 问数"
aria-haspopup="dialog"
aria-expanded={assistantOpen}
className="fixed bottom-[calc(5rem+env(safe-area-inset-bottom))] right-4 z-[60] inline-flex min-h-12 items-center gap-2 rounded-full bg-gradient-to-br from-blue-600 to-cyan-500 px-4 text-sm font-semibold text-white shadow-lg shadow-blue-200 transition hover:from-blue-700 hover:to-cyan-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 md:bottom-6 md:right-6"
>
<Sparkles size={20} aria-hidden="true" />
AI 问数
</button>
{assistantOpen && <Suspense fallback={<div role="status" className="fixed bottom-20 right-6 z-50 rounded-xl bg-white p-4 text-slate-900 shadow-lg">正在打开 AI 问数…</div>}><AssetAssistant key={selectedSubject || 'all'} subject={selectedSubject} appearance="light" close={() => { setAssistantOpen(false); requestAnimationFrame(() => assistantTrigger.current?.focus()); }} /></Suspense>}
</div>
);