ui(assets): move AI assistant to the bottom feedback position
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
shishengliang
2026-09-23 16:02:50 +08:00
parent 7e9760f5db
commit d20bc71efe
3 changed files with 15 additions and 13 deletions
+1 -1
View File
@@ -165,7 +165,7 @@ export function Shell({ modules }: { modules: ModuleConfig[] }) {
<Suspense fallback={<div className="p-3 md:p-6"><LoadingState label="正在加载业务模块" /></div>}> <Suspense fallback={<div className="p-3 md:p-6"><LoadingState label="正在加载业务模块" /></div>}>
{ActiveComponent && <ActiveComponent />} {ActiveComponent && <ActiveComponent />}
</Suspense> </Suspense>
<FeedbackFab module={activeModule} /> {activeModule !== 'assets' && <FeedbackFab module={activeModule} />}
</main> </main>
{/* 移动端底部导航 (md 以下) */} {/* 移动端底部导航 (md 以下) */}
+13 -2
View File
@@ -1,6 +1,7 @@
import React, { lazy, Suspense, useState, useEffect, useCallback, useMemo, useRef } from 'react'; import React, { lazy, Suspense, useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { import {
Truck, Truck,
Sparkles,
ChevronDown, ChevronDown,
ChevronRight, ChevronRight,
Loader2, Loader2,
@@ -483,8 +484,6 @@ export default function AssetsModule() {
return ( return (
<div className="min-h-screen bg-[var(--app-bg)] text-gray-800 font-sans p-3 md:p-6 relative"> <div className="min-h-screen bg-[var(--app-bg)] text-gray-800 font-sans p-3 md:p-6 relative">
<AssetsHeader <AssetsHeader
assistantTrigger={assistantTrigger}
onOpenAssistant={() => setAssistantOpen(true)}
activeTab={activeTab} activeTab={activeTab}
setActiveTab={setActiveTab} setActiveTab={setActiveTab}
theme={theme} theme={theme}
@@ -1708,6 +1707,18 @@ export default function AssetsModule() {
</div> </div>
<RotatingFooterHint className="pb-4" /> <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>} {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> </div>
); );
+1 -10
View File
@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { ChevronDown, Filter, Loader2, Search, Sparkles } from 'lucide-react'; import { ChevronDown, Filter, Loader2, Search } from 'lucide-react';
import { motion } from 'motion/react'; import { motion } from 'motion/react';
import type { SubjectOption } from '../api'; import type { SubjectOption } from '../api';
@@ -7,8 +7,6 @@ export type AssetsTab = 'overview' | 'department' | 'region' | 'customer';
export type AssetsTheme = 'soft' | 'minimal' | 'vibrant'; export type AssetsTheme = 'soft' | 'minimal' | 'vibrant';
interface AssetsHeaderProps { interface AssetsHeaderProps {
onOpenAssistant: () => void;
assistantTrigger: React.RefObject<HTMLButtonElement | null>;
activeTab: AssetsTab; activeTab: AssetsTab;
setActiveTab: React.Dispatch<React.SetStateAction<AssetsTab>>; setActiveTab: React.Dispatch<React.SetStateAction<AssetsTab>>;
theme: AssetsTheme; theme: AssetsTheme;
@@ -33,8 +31,6 @@ const TABS = [
]; ];
export function AssetsHeader({ export function AssetsHeader({
onOpenAssistant,
assistantTrigger,
activeTab, activeTab,
setActiveTab, setActiveTab,
theme, theme,
@@ -81,11 +77,6 @@ export function AssetsHeader({
</div> </div>
</div> </div>
</div> </div>
<div className="flex justify-end px-4 pb-1">
<button ref={assistantTrigger} type="button" onClick={onOpenAssistant} className="inline-flex min-h-8 items-center gap-1.5 rounded-lg border border-blue-100 bg-blue-50 px-3 text-xs font-semibold text-blue-600 hover:bg-blue-100">
<Sparkles size={14} aria-hidden="true" />AI 问数
</button>
</div>
{/* 归属公司作用域筛选 (Scope Chip) */} {/* 归属公司作用域筛选 (Scope Chip) */}
<div className="flex items-center justify-center px-4 pt-1"> <div className="flex items-center justify-center px-4 pt-1">
<div className="relative" ref={subjectDropdownRef}> <div className="relative" ref={subjectDropdownRef}>