Merge branch 'dhk-1' of http://192.168.0.200/knowledge-base-bj/deerflow-server into dhk-1
解决 StrategyRoutes.tsx import 冲突:保留双方各自唯一的页面导入(AgentsPage/ChatPage/ChatsPage + AdminUserLeaderboardPage/SettingsPage),去掉与下方重复的 13 个 import。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
f845805706
7 files changed
+1048
-701
No files matched your search
@@ -55,14 +55,6 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
|
||||
}, 180);
|
||||
};
|
||||
|
||||
const closeNavPanel = () => {
|
||||
if (hoverCloseTimerRef.current !== null) {
|
||||
window.clearTimeout(hoverCloseTimerRef.current);
|
||||
hoverCloseTimerRef.current = null;
|
||||
}
|
||||
setHoveredTopId(null);
|
||||
};
|
||||
|
||||
const hasActiveChild = (item: MenuItem): boolean => {
|
||||
if (item.path && pathname === item.path) {
|
||||
return true;
|
||||
@@ -83,7 +75,9 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
|
||||
if (matchedTopItem) {
|
||||
setActiveTopId(matchedTopItem.id);
|
||||
}
|
||||
closeNavPanel();
|
||||
// 不在导航时强制关闭 flyout:flyout 绝对定位在 group 盒子之外,强制关闭后鼠标
|
||||
// 仍停在 flyout 区域却收不到 group 的 mouseenter,导致连续点击第二个任务时面板
|
||||
// 消失且不回来。开合只交给 hover(mouseleave 有 180ms 宽限),即可连续点选。
|
||||
}, [pathname, visibleMenuItems]);
|
||||
|
||||
const toggleExpanded = (id: string) => {
|
||||
@@ -122,14 +116,12 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
|
||||
if (item.children?.length) {
|
||||
const firstPath = findFirstRoutePath(item.children);
|
||||
if (firstPath) {
|
||||
closeNavPanel();
|
||||
navigate(firstPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.path) {
|
||||
closeNavPanel();
|
||||
navigate(item.path);
|
||||
}
|
||||
};
|
||||
@@ -141,7 +133,6 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
|
||||
}
|
||||
|
||||
if (item.path) {
|
||||
closeNavPanel();
|
||||
navigate(item.path);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -184,6 +184,21 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
|
||||
: 'light'
|
||||
: readPersistedTheme();
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof document === 'undefined') return;
|
||||
|
||||
const root = document.documentElement;
|
||||
|
||||
if (theme === 'dark') {
|
||||
root.setAttribute('theme-mode', 'dark');
|
||||
root.classList.add('dark');
|
||||
return;
|
||||
}
|
||||
|
||||
root.removeAttribute('theme-mode');
|
||||
root.classList.remove('dark');
|
||||
}, [theme]);
|
||||
|
||||
const toggleTheme = () => {
|
||||
setNextTheme(theme === 'dark' ? 'light' : 'dark');
|
||||
markExplicitChoice();
|
||||
|
||||
@@ -1,48 +1,47 @@
|
||||
import { Navigate, Route, Routes } from "react-router-dom";
|
||||
import { Toaster } from "sonner";
|
||||
|
||||
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { RouteBaseProvider } from "@/core/route-base";
|
||||
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||
|
||||
import GeneralQA from "@/strategy-components/components/chat-qa/GeneralQA";
|
||||
import { ChatRuntime } from "./WorkspaceRoutes";
|
||||
import AgentsPage from "./AgentsPage";
|
||||
import ChatsPage from "./ChatsPage";
|
||||
import ChatPage from "./ChatPage";
|
||||
import NewAgentPage from "./NewAgentPage";
|
||||
import FanganTyPage from "@/strategy-components/components/task-components/FanganTy";
|
||||
import SentimentAnalyzes from "@/strategy-components/components/task-components/SentimentAnalyzes";
|
||||
import TaskManagement from "@/strategy-components/components/task-components/TaskManagement";
|
||||
import TaskPgFrom from "@/strategy-components/components/task-components/TaskPgFrom";
|
||||
import TaskXkFrom from "@/strategy-components/components/task-components/TaskXkFrom";
|
||||
import TaskAnalyzes from "@/strategy-components/components/task-components/TaskAnalyzes";
|
||||
import XingdongTyPage from "@/strategy-components/components/task-components/XingdongTy";
|
||||
import XXTyPage from "@/strategy-components/components/task-components/XXTy";
|
||||
import { ActionAnalyzes } from "@/strategy-components/components/task-components/ActionAnalyzes";
|
||||
import KnowledgeBaseResourceManagement from "@/strategy-components/components/resource-management/KnowledgeBaseResourceManagement";
|
||||
import NetworkActorResourceManagement from "@/strategy-components/components/resource-management/NetworkActorResourceManagement";
|
||||
import RoundtablePlanningPage from "@/roundtable-planning/pages/RoundtablePlanningPage";
|
||||
import "@/roundtable-planning/styles/roundtable-planning.css";
|
||||
import AgentChatPage from "./AgentChatPage";
|
||||
import SkillsPage from "./SkillsPage";
|
||||
import SkillEvolutionPage from "./SkillEvolutionPage";
|
||||
import MemoryPage from "./MemoryPage";
|
||||
import ScheduledTasksPage from "./ScheduledTasksPage";
|
||||
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
|
||||
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
|
||||
import PromptPrefixSettingsPage from "./PromptPrefixSettingsPage";
|
||||
import PrivateSquareSettingsPage from "./PrivateSquareSettingsPage";
|
||||
import LlmMetricsPage from "./LlmMetricsPage";
|
||||
import UsersPage from "./UsersPage";
|
||||
import AdminScheduledTasksPage from "./AdminScheduledTasksPage";
|
||||
import AdminUserActivityPage from "./AdminUserActivityPage";
|
||||
import AgentsPage from "./AgentsPage";
|
||||
import ChatPage from "./ChatPage";
|
||||
import ChatsPage from "./ChatsPage";
|
||||
import AdminUserLeaderboardPage from "./AdminUserLeaderboardPage";
|
||||
import AdminUserLeaderboardSettingsPage from "./AdminUserLeaderboardSettingsPage";
|
||||
import TagsPage from "./TagsPage";
|
||||
import LightAppNewNotePage from "./LightAppNewNotePage";
|
||||
import LightAppNoteListPage from "./LightAppNoteListPage";
|
||||
import LightAppNoteQAPage from "./LightAppNoteQAPage";
|
||||
import TaskXkFrom from "@/strategy-components/components/task-components/TaskXkFrom";
|
||||
import TaskManagement from "@/strategy-components/components/task-components/TaskManagement";
|
||||
import TaskPgFrom from "@/strategy-components/components/task-components/TaskPgFrom";
|
||||
import FanganTyPage from "@/strategy-components/components/task-components/FanganTy";
|
||||
import XingdongTyPage from "@/strategy-components/components/task-components/XingdongTy";
|
||||
import XXTyPage from "@/strategy-components/components/task-components/XXTy";
|
||||
import SentimentAnalyzes from "@/strategy-components/components/task-components/SentimentAnalyzes";
|
||||
import TaskAnalyzes from "@/strategy-components/components/task-components/TaskAnalyzes";
|
||||
import { ActionAnalyzes } from "@/strategy-components/components/task-components/ActionAnalyzes";
|
||||
import NetworkActorResourceManagement from "@/strategy-components/components/resource-management/NetworkActorResourceManagement";
|
||||
import KnowledgeBaseResourceManagement from "@/strategy-components/components/resource-management/KnowledgeBaseResourceManagement";
|
||||
import RoundtablePlanningPage from "@/roundtable-planning/pages/RoundtablePlanningPage";
|
||||
import "@/roundtable-planning/styles/roundtable-planning.css";
|
||||
import MemoryPage from "./MemoryPage";
|
||||
import NewAgentPage from "./NewAgentPage";
|
||||
import PromptPrefixSettingsPage from "./PromptPrefixSettingsPage";
|
||||
import PrivateSquareSettingsPage from "./PrivateSquareSettingsPage";
|
||||
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
|
||||
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
|
||||
import ScheduledTasksPage from "./ScheduledTasksPage";
|
||||
import SkillEvolutionPage from "./SkillEvolutionPage";
|
||||
import SkillsPage from "./SkillsPage";
|
||||
import TagsPage from "./TagsPage";
|
||||
import UsersPage from "./UsersPage";
|
||||
import LlmMetricsPage from "./LlmMetricsPage";
|
||||
import AdminScheduledTasksPage from "./AdminScheduledTasksPage";
|
||||
import AdminUserActivityPage from "./AdminUserActivityPage";
|
||||
import { ChatRuntime } from "./WorkspaceRoutes";
|
||||
|
||||
export default function StrategyRoutes() {
|
||||
return (
|
||||
@@ -52,14 +51,13 @@ export default function StrategyRoutes() {
|
||||
<Routes>
|
||||
<Route index element={<Navigate to="qa/general" replace />} />
|
||||
|
||||
{/* 问答中心 */}
|
||||
<Route path="qa/general" element={<GeneralQA />} />
|
||||
<Route
|
||||
path="qa/expert-qa"
|
||||
element={
|
||||
<GeneralQA
|
||||
chatHeadTitle="专家问答"
|
||||
chatDesign="支持单轮RAG、多轮RAG、深度检索及结果对比"
|
||||
chatHeadTitle="æ¶“æ’³î†é—‚瓟"
|
||||
chatDesign="é€îˆ›å¯”é—æ›¡ç–†RAG銆佸æžç”ŠAGéŠ†ä½¹ç¹æ´ï¸½î—…ç»±ãˆ å¼·ç¼æ’´ç‰ç€µè§„瘮"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@@ -71,10 +69,9 @@ export default function StrategyRoutes() {
|
||||
</ChatRuntime>
|
||||
}
|
||||
/>
|
||||
{/* 任务管理 */}
|
||||
|
||||
<Route path="task-management" element={<TaskManagement />}>
|
||||
<Route index element={<Navigate to="xk-task-jc" replace />} />
|
||||
{/* XK任务 */}
|
||||
<Route
|
||||
path="xk-task-jc"
|
||||
element={<TaskXkFrom gopath="#/pageIndie/pageHome/pageSwrw" />}
|
||||
@@ -83,7 +80,6 @@ export default function StrategyRoutes() {
|
||||
path="xk-task-dispatch"
|
||||
element={<TaskXkFrom gopath="#/pageIndie/pageJczl" />}
|
||||
/>
|
||||
{/* pg中任务 */}
|
||||
<Route
|
||||
path="effect-task-pg"
|
||||
element={<TaskPgFrom gopath="task" />}
|
||||
@@ -96,12 +92,11 @@ export default function StrategyRoutes() {
|
||||
path="effect-info-pg"
|
||||
element={<TaskPgFrom gopath="info" />}
|
||||
/>
|
||||
{/* COH中任务 */}
|
||||
<Route
|
||||
path="plan-task-sentiment"
|
||||
element={
|
||||
<SentimentAnalyzes
|
||||
title="3QFX"
|
||||
title="三情分析"
|
||||
category="规划任务"
|
||||
subCategory="规划任务"
|
||||
/>
|
||||
@@ -111,9 +106,9 @@ export default function StrategyRoutes() {
|
||||
path="plan-task/plan-task-fx"
|
||||
element={
|
||||
<TaskAnalyzes
|
||||
title="任务FX"
|
||||
category="规划任务"
|
||||
subCategory="规划任务"
|
||||
title="æµ è¯²å§ŸFX"
|
||||
category="ç‘™å‹«åžæµ 诲姟"
|
||||
subCategory="ç‘™å‹«åžæµ 诲姟"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@@ -122,17 +117,16 @@ export default function StrategyRoutes() {
|
||||
element={
|
||||
<ActionAnalyzes
|
||||
title="xdfx"
|
||||
category="规划任务"
|
||||
subCategory="规划任务"
|
||||
category="ç‘™å‹«åžæµ 诲姟"
|
||||
subCategory="ç‘™å‹«åžæµ 诲姟"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{/* MNTY任务 */}
|
||||
<Route path="mnty-task-mechanism" element={<XingdongTyPage />} />
|
||||
<Route path="mnty-task-plan" element={<FanganTyPage />} />
|
||||
<Route path="mnty-task-zsty" element={<XXTyPage />} />
|
||||
</Route>
|
||||
{/* 资源管理 */}
|
||||
|
||||
<Route
|
||||
path="resource-management/resource-network-actor"
|
||||
element={<NetworkActorResourceManagement />}
|
||||
@@ -143,16 +137,13 @@ export default function StrategyRoutes() {
|
||||
/>
|
||||
<Route
|
||||
path="resource-management/resource-evaluation-index"
|
||||
element={
|
||||
<TaskXkFrom gopath="#/pageIndie/pageZyjc/pageZyzl" />
|
||||
}
|
||||
element={<TaskXkFrom gopath="#/pageIndie/pageZyjc/pageZyzl" />}
|
||||
/>
|
||||
{/* 轻应用 */}
|
||||
|
||||
<Route path="light-app/new-note" element={<LightAppNewNotePage />} />
|
||||
<Route path="light-app/notes" element={<LightAppNoteListPage />} />
|
||||
<Route path="light-app/note-qa" element={<LightAppNoteQAPage />} />
|
||||
|
||||
{/* 对话 */}
|
||||
<Route path="chats" element={<ChatsPage />} />
|
||||
<Route
|
||||
path="chats/:thread_id"
|
||||
@@ -163,7 +154,6 @@ export default function StrategyRoutes() {
|
||||
}
|
||||
/>
|
||||
|
||||
{/* 智能体管理 */}
|
||||
<Route path="agents" element={<AgentsPage />} />
|
||||
<Route path="agents/new" element={<NewAgentPage />} />
|
||||
<Route
|
||||
@@ -179,12 +169,10 @@ export default function StrategyRoutes() {
|
||||
}
|
||||
/>
|
||||
|
||||
{/* 技能 / 记忆 */}
|
||||
<Route path="skills" element={<SkillsPage />} />
|
||||
<Route path="skills/evolution" element={<SkillEvolutionPage />} />
|
||||
<Route path="memory" element={<MemoryPage />} />
|
||||
|
||||
{/* 定时任务 */}
|
||||
<Route
|
||||
path="scheduled"
|
||||
element={<Navigate to="/page/strategy/scheduled/tasks" replace />}
|
||||
@@ -195,7 +183,6 @@ export default function StrategyRoutes() {
|
||||
element={<ScheduledTaskRunDetailPage />}
|
||||
/>
|
||||
|
||||
{/* 设置 / 管理 — 权限与 workspace 侧一致,非 admin 重定向到 chats/new */}
|
||||
<Route
|
||||
path="settings/recommended-questions"
|
||||
element={
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import { ChevronRight, FileText } from 'lucide-react';
|
||||
import { Pagination } from 'tdesign-react';
|
||||
import { useTheme } from '@/contexts/ThemeContext';
|
||||
import { TaskListItem } from './TaskManagement';
|
||||
import { ChevronRight, FileText } from 'lucide-react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { TaskCard } from './TaskCard';
|
||||
import { Pagination } from 'tdesign-react';
|
||||
|
||||
interface KanbanColumnProps {
|
||||
title: string;
|
||||
@@ -11,64 +11,73 @@ interface KanbanColumnProps {
|
||||
color: string;
|
||||
tasks: TaskListItem[];
|
||||
taskType: string;
|
||||
TaskDataType?: string; // 区分来源类型
|
||||
TaskDataType?: string;
|
||||
pageIndexSearch: (taskType: string, pageIndex: number) => void;
|
||||
handleStartAnalysis: (task: TaskListItem) => void
|
||||
handleStartAnalysis: (task: TaskListItem) => void;
|
||||
}
|
||||
|
||||
export const KanbanColumn: React.FC<KanbanColumnProps> = ({ title, count, color, tasks,taskType, TaskDataType = 'task' , pageIndexSearch, handleStartAnalysis }) => {
|
||||
export const KanbanColumn: React.FC<KanbanColumnProps> = ({
|
||||
title,
|
||||
count,
|
||||
color,
|
||||
tasks,
|
||||
taskType,
|
||||
TaskDataType = 'task',
|
||||
pageIndexSearch,
|
||||
handleStartAnalysis,
|
||||
}) => {
|
||||
const { theme } = useTheme();
|
||||
const isDark = theme === 'dark';
|
||||
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
|
||||
const textMuted = isDark ? 'text-slate-500' : 'text-gray-400';
|
||||
// 当前页码,默认为第 1 页
|
||||
const [pageNum, setPageNum] = useState<number>(1);
|
||||
// 每页显示数量,默认为 10 条
|
||||
const [pageSize, setPageSize] = useState<number>(10); // 每页显示 10 条
|
||||
/**
|
||||
* 页码变化时的回调函数
|
||||
* 当用户切换页码时触发,更新页码并重新获取数据
|
||||
* @param value - 新的页码值
|
||||
*/
|
||||
const [pageNum, setPageNum] = useState(1);
|
||||
|
||||
const pageIndexChange = async (value: number) => {
|
||||
// 更新 ref 中存储的页码值
|
||||
// 更新页码状态,触发组件重新渲染
|
||||
console.log('taskType', taskType)
|
||||
setPageNum(value);
|
||||
await pageIndexSearch(taskType, value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 每页显示数量变化时的回调函数
|
||||
* 当用户切换每页显示条数时触发,更新每页数量并重新获取数据
|
||||
* @param value - 新的每页显示数量
|
||||
*/
|
||||
const pageSizeChange = async (value: number) => {
|
||||
// 更新 ref 中存储的每页显示数量
|
||||
// 更新每页显示数量状态,触发组件重新渲染
|
||||
setPageSize(value);
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-col min-h-0 flex-1">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`w-2 h-2 rounded-full ${color}`} />
|
||||
<h2 className={`font-semibold text-sm ${textPrimary}`}>{title}</h2>
|
||||
<span className={`px-2 py-0.5 rounded-full text-xs ${isDark ? 'bg-slate-700/50 text-slate-400' : 'bg-red-50 text-red-500'
|
||||
}`}>{count}</span>
|
||||
<div
|
||||
className={`theme-transition flex h-full min-h-0 flex-col rounded-[28px] border p-4 md:p-5 ${
|
||||
isDark
|
||||
? 'theme-card border-[rgba(110,136,176,0.24)] shadow-[0_18px_50px_rgba(2,8,20,0.24)]'
|
||||
: 'border-slate-200 bg-white shadow-sm'
|
||||
}`}
|
||||
>
|
||||
<div className="mb-4 flex items-start justify-between gap-3">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className={`mt-1 h-2.5 w-2.5 rounded-full ${color}`} />
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className={`text-base font-semibold ${isDark ? 'text-slate-50' : 'text-slate-900'}`}>{title}</h2>
|
||||
<span
|
||||
className={`rounded-full px-2 py-0.5 text-xs ${
|
||||
isDark ? 'bg-[rgba(20,47,86,0.92)] text-slate-300' : 'bg-slate-100 text-slate-600'
|
||||
}`}
|
||||
>
|
||||
{count}
|
||||
</span>
|
||||
</div>
|
||||
<p className={`mt-1 text-xs ${isDark ? 'text-slate-400' : 'text-slate-500'}`}>
|
||||
按时间倒序展示,支持分页切换。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* <button className={`p-1 rounded transition-colors ${isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
||||
}`}>
|
||||
<ChevronRight className={`w-4 h-4 ${textMuted}`} />
|
||||
</button> */}
|
||||
<iframe></iframe>
|
||||
<div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`hidden rounded-xl p-2 lg:flex ${
|
||||
isDark ? 'bg-[rgba(10,30,54,0.82)] text-slate-300' : 'bg-slate-50 text-slate-500'
|
||||
}`}
|
||||
>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</div>
|
||||
<Pagination
|
||||
className="sentiment-pagination"
|
||||
total={count}
|
||||
size="small"
|
||||
theme="simple"
|
||||
current={pageNum}
|
||||
pageSize={pageSize}
|
||||
pageSize={10}
|
||||
maxPageBtn={3}
|
||||
showPageSize={false}
|
||||
totalContent={false}
|
||||
@@ -76,16 +85,39 @@ export const KanbanColumn: React.FC<KanbanColumnProps> = ({ title, count, color,
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto space-y-3 pr-1 scrollbar-thin">
|
||||
|
||||
<div className="scrollbar-thin flex-1 space-y-3 overflow-y-auto pr-1">
|
||||
{tasks.length === 0 ? (
|
||||
<div className={`flex flex-col items-center justify-center py-8 ${textMuted}`}>
|
||||
<FileText className="w-8 h-8 mb-2 opacity-50" />
|
||||
<p className="text-sm">暂无任务</p>
|
||||
<div
|
||||
className={`flex h-full min-h-[260px] flex-col items-center justify-center rounded-2xl border border-dashed ${
|
||||
isDark
|
||||
? 'border-[rgba(110,136,176,0.24)] bg-[rgba(9,25,46,0.38)]'
|
||||
: 'border-slate-200 bg-slate-50'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`mb-3 flex h-12 w-12 items-center justify-center rounded-2xl ${
|
||||
isDark ? 'bg-[rgba(13,42,78,0.92)] text-slate-300' : 'bg-white text-slate-500'
|
||||
}`}
|
||||
>
|
||||
<FileText className="h-5 w-5" />
|
||||
</div>
|
||||
<div className={`text-sm ${isDark ? 'text-slate-300' : 'text-slate-600'}`}>暂无任务</div>
|
||||
<div className={`mt-1 text-xs ${isDark ? 'text-slate-500' : 'text-slate-400'}`}>
|
||||
可以尝试调整筛选条件或切换数据模式。
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
tasks.map(task => <TaskCard key={task.id} task={task} TaskType={TaskDataType} handleStartAnalysis={handleStartAnalysis}/>)
|
||||
tasks.map((task) => (
|
||||
<TaskCard
|
||||
key={task.id}
|
||||
task={task}
|
||||
TaskType={TaskDataType}
|
||||
handleStartAnalysis={handleStartAnalysis}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
+519
-319
@@ -1,38 +1,13 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Plus,
|
||||
Search,
|
||||
Eye,
|
||||
Play,
|
||||
Pause,
|
||||
Clock,
|
||||
User,
|
||||
ChevronRight,
|
||||
Filter,
|
||||
FileText,
|
||||
AlertTriangle,
|
||||
CheckCircle,
|
||||
XCircle,
|
||||
MoreHorizontal,
|
||||
Edit,
|
||||
Download,
|
||||
Bot,
|
||||
Users,
|
||||
Workflow,
|
||||
X,
|
||||
ArrowRight,
|
||||
Target,
|
||||
Layers,
|
||||
} from 'lucide-react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { ArrowRight, Bot, Clock3, Layers, Search, Sparkles, Users, X } from 'lucide-react';
|
||||
import { DateRangePicker, DateRangeValue, Loading } from 'tdesign-react';
|
||||
import dayjs from 'dayjs';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTheme } from '@/contexts/ThemeContext';
|
||||
// 导入请求服务,用于与后端 API 交互
|
||||
import { useChatContext } from '@/contexts/ChatContext';
|
||||
import { requestCrudService } from '@/service/request-axios-service';
|
||||
import { KanbanColumn } from './KanbanColumn';
|
||||
import { TaskListItem } from './TaskManagement';
|
||||
import { DateRangePicker, DateRangePickerProps, DateRangeValue, Loading } from 'tdesign-react';
|
||||
import dayjs from 'dayjs';
|
||||
import { useChatContext } from '@/contexts/ChatContext';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
interface TaskListPageProps {
|
||||
title: string;
|
||||
@@ -40,350 +15,575 @@ interface TaskListPageProps {
|
||||
subCategory: string;
|
||||
}
|
||||
|
||||
interface stateItem {
|
||||
startTime: string,
|
||||
endTime: string,
|
||||
task: TaskListItem,
|
||||
}
|
||||
|
||||
type TaskType = 'single' | 'consultation' | 'scene' | 'multi-agent' | 'task-search';
|
||||
type TaskStatus = 'draft' | 'pending' | 'running' | 'paused' | 'blocked' | 'completed';
|
||||
type ColumnType = 'unanalyzed' | 'analyzing' | 'completed';
|
||||
|
||||
const service = requestCrudService;
|
||||
const zncmUrl = import.meta.env.VITE_API_BASE_URL || '';
|
||||
const ENABLE_SENTIMENT_DEMO_BY_DEFAULT = import.meta.env.DEV;
|
||||
|
||||
const SentimentAnalyzes: React.FC<TaskListPageProps> = ({ title, category, subCategory}) => {
|
||||
const buildMockTask = (
|
||||
id: string,
|
||||
name: string,
|
||||
overview: string,
|
||||
column: ColumnType,
|
||||
type: TaskType,
|
||||
priority: 1 | 2 | 3,
|
||||
progress: number,
|
||||
createTime: string,
|
||||
updateTime: string,
|
||||
owner: string,
|
||||
): TaskListItem => ({
|
||||
id,
|
||||
taskName: name,
|
||||
overview,
|
||||
column,
|
||||
type,
|
||||
priority,
|
||||
progress,
|
||||
createTime,
|
||||
updateTime,
|
||||
owner,
|
||||
creator: owner,
|
||||
executor: owner,
|
||||
scene: JSON.stringify({
|
||||
taskJson: JSON.stringify({
|
||||
task_title: name,
|
||||
task_goal: overview,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const MOCK_TASKS: Record<ColumnType, TaskListItem[]> = {
|
||||
unanalyzed: [
|
||||
buildMockTask(
|
||||
'demo-u-1',
|
||||
'新能源价格舆情波动分析',
|
||||
'聚焦近 7 日新能源整车与动力电池价格讨论热度,识别社媒与媒体端异常扩散信号。',
|
||||
'unanalyzed',
|
||||
'single',
|
||||
2,
|
||||
0,
|
||||
'2026-06-05 09:10:00',
|
||||
'2026-06-05 09:10:00',
|
||||
'王晓楠',
|
||||
),
|
||||
buildMockTask(
|
||||
'demo-u-2',
|
||||
'重点项目负面反馈聚类',
|
||||
'从任务评论、审批意见和业务群消息中抽取高频情绪主题,辅助判断风险聚焦点。',
|
||||
'unanalyzed',
|
||||
'consultation',
|
||||
3,
|
||||
0,
|
||||
'2026-06-05 08:40:00',
|
||||
'2026-06-05 08:40:00',
|
||||
'刘志诚',
|
||||
),
|
||||
buildMockTask(
|
||||
'demo-u-3',
|
||||
'竞品发布会用户情绪追踪',
|
||||
'围绕发布会直播、短视频评论与论坛帖子,建立情绪转折时间线并识别主要触发事件。',
|
||||
'unanalyzed',
|
||||
'scene',
|
||||
1,
|
||||
0,
|
||||
'2026-06-04 18:20:00',
|
||||
'2026-06-04 18:20:00',
|
||||
'陈思雨',
|
||||
),
|
||||
buildMockTask(
|
||||
'demo-u-4',
|
||||
'区域渠道满意度扫描',
|
||||
'基于周报、工单和售后回访文本,发现华东区域渠道服务满意度下行趋势。',
|
||||
'unanalyzed',
|
||||
'task-search',
|
||||
2,
|
||||
0,
|
||||
'2026-06-04 15:35:00',
|
||||
'2026-06-04 15:35:00',
|
||||
'赵明宇',
|
||||
),
|
||||
],
|
||||
analyzing: [
|
||||
buildMockTask(
|
||||
'demo-a-1',
|
||||
'新车上市口碑监测会商',
|
||||
'正在联合多个智能体汇总平台评价、媒体测评与用户问答,生成阶段性情绪画像。',
|
||||
'analyzing',
|
||||
'multi-agent',
|
||||
3,
|
||||
56,
|
||||
'2026-06-05 07:50:00',
|
||||
'2026-06-05 10:05:00',
|
||||
'张雨桐',
|
||||
),
|
||||
buildMockTask(
|
||||
'demo-a-2',
|
||||
'投诉热点归因拆解',
|
||||
'拆分售后投诉中关于续航、交付和门店服务的负面占比,分析主要归因与蔓延路径。',
|
||||
'analyzing',
|
||||
'consultation',
|
||||
2,
|
||||
78,
|
||||
'2026-06-04 20:10:00',
|
||||
'2026-06-05 09:48:00',
|
||||
'何嘉成',
|
||||
),
|
||||
],
|
||||
completed: [
|
||||
buildMockTask(
|
||||
'demo-c-1',
|
||||
'车展传播效果情绪复盘',
|
||||
'已输出传播节点热度变化、核心评论主题以及 KOL 内容对情绪曲线的影响分析。',
|
||||
'completed',
|
||||
'single',
|
||||
1,
|
||||
100,
|
||||
'2026-06-03 14:20:00',
|
||||
'2026-06-04 17:30:00',
|
||||
'孙怡宁',
|
||||
),
|
||||
buildMockTask(
|
||||
'demo-c-2',
|
||||
'智能驾驶争议议题扫描',
|
||||
'已完成争议议题聚类、情绪倾向分层和外部平台扩散链路分析,可直接查看结论。',
|
||||
'completed',
|
||||
'scene',
|
||||
3,
|
||||
100,
|
||||
'2026-06-03 09:00:00',
|
||||
'2026-06-04 11:45:00',
|
||||
'李承泽',
|
||||
),
|
||||
buildMockTask(
|
||||
'demo-c-3',
|
||||
'品牌联名活动舆情总结',
|
||||
'已完成用户态度分布统计与正负面声音对比,附带评论样本摘要和建议动作。',
|
||||
'completed',
|
||||
'task-search',
|
||||
2,
|
||||
100,
|
||||
'2026-06-02 16:50:00',
|
||||
'2026-06-03 19:12:00',
|
||||
'周清越',
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
const paginateTasks = (tasks: TaskListItem[], pageIndex: number, pageSize: number) => {
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
return tasks.slice(start, start + pageSize);
|
||||
};
|
||||
|
||||
const SentimentAnalyzes: React.FC<TaskListPageProps> = ({ title, category, subCategory }) => {
|
||||
const { theme } = useTheme();
|
||||
const isDark = theme === 'dark';
|
||||
const router = useNavigate();
|
||||
// 主题颜色变量
|
||||
const cardBg = isDark ? 'bg-slate-800/30' : 'bg-white';
|
||||
const cardBorder = isDark ? 'border-blue-800/30' : 'border-red-100';
|
||||
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
|
||||
const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600';
|
||||
const textMuted = isDark ? 'text-slate-500' : 'text-gray-400';
|
||||
const inputBg = isDark ? 'bg-slate-900/50' : 'bg-white';
|
||||
const { setStartConfig } = useChatContext();
|
||||
const navigate = useNavigate();
|
||||
const isDark = theme === 'dark';
|
||||
const shellClass = isDark
|
||||
? 'strategy-data min-h-full bg-[radial-gradient(circle_at_top_left,rgba(27,94,168,0.28),transparent_32%),linear-gradient(180deg,#081322_0%,#0d1d33_42%,#0a1628_100%)] text-slate-100'
|
||||
: 'strategy-data min-h-full bg-[#f8fafc] text-slate-900';
|
||||
const metricCardClass = isDark
|
||||
? 'border border-[rgba(110,136,176,0.24)] bg-[linear-gradient(180deg,rgba(12,32,58,0.96),rgba(9,22,39,0.96))] shadow-[0_14px_42px_rgba(2,8,20,0.30)]'
|
||||
: 'border border-slate-200 bg-white shadow-sm';
|
||||
const inputClass = isDark
|
||||
? 'border-[rgba(110,136,176,0.3)] bg-[rgba(8,23,42,0.92)] text-slate-100 placeholder:text-slate-500'
|
||||
: 'border-slate-200 bg-white text-slate-900 placeholder:text-slate-400';
|
||||
const panelGlowClass = isDark
|
||||
? 'before:pointer-events-none before:absolute before:inset-x-8 before:top-0 before:h-px before:bg-[linear-gradient(90deg,transparent,rgba(96,165,250,0.45),transparent)]'
|
||||
: '';
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [modeFilter, setModeFilter] = useState<string>('all');
|
||||
const [showAnalysisModal, setShowAnalysisModal] = useState(false);
|
||||
const [selectedTaskForAnalysis, setSelectedTaskForAnalysis] = useState<TaskListItem | null>(null);
|
||||
const [unanalyzedTotal, setUnanalyzedTotal] = useState<number>(0); // 未分析
|
||||
const [runningTotal, setRunningTotal] = useState<number>(0); // 分析中
|
||||
const [completedTotal, setCompletedTotal] = useState<number>(0); // 已完成
|
||||
const [unanalyzedList, setUnanalyzedList] = useState<TaskListItem[]>([]); // 未分析
|
||||
const [runningList, setRunningList] = useState<TaskListItem[]>([]); // 分析中
|
||||
const [completedList, setCompletedList] = useState<TaskListItem[]>([]); // 已完成
|
||||
const [unanalyzedLoading, setUnanalyzedLoading] = useState<boolean>(false); // 未分析
|
||||
const [runningLoading, setRunningLoading] = useState<boolean>(false); // 分析中
|
||||
const [completedLoading, setCompletedLoading] = useState<boolean>(false); // 已完成
|
||||
const [presets] = useState<DateRangePickerProps['presets']>({
|
||||
最近7天: [dayjs().subtract(6, 'day').toDate(), dayjs().toDate()],
|
||||
最近3天: [dayjs().subtract(2, 'day').toDate(), dayjs().toDate()],
|
||||
今天: [dayjs().toDate(), dayjs().toDate()],
|
||||
});
|
||||
const [range, setRange] = useState<DateRangeValue>([]);
|
||||
const state = useRef<stateItem>({
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
task: {} as TaskListItem,
|
||||
})
|
||||
const [useDemoData, setUseDemoData] = useState(ENABLE_SENTIMENT_DEMO_BY_DEFAULT);
|
||||
const [unanalyzedTotal, setUnanalyzedTotal] = useState(0);
|
||||
const [runningTotal, setRunningTotal] = useState(0);
|
||||
const [completedTotal, setCompletedTotal] = useState(0);
|
||||
const [unanalyzedList, setUnanalyzedList] = useState<TaskListItem[]>([]);
|
||||
const [runningList, setRunningList] = useState<TaskListItem[]>([]);
|
||||
const [completedList, setCompletedList] = useState<TaskListItem[]>([]);
|
||||
const [unanalyzedLoading, setUnanalyzedLoading] = useState(false);
|
||||
const [runningLoading, setRunningLoading] = useState(false);
|
||||
const [completedLoading, setCompletedLoading] = useState(false);
|
||||
const [dateRange, setDateRange] = useState<DateRangeValue>([
|
||||
dayjs().startOf('month').format('YYYY-MM-DD'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD'),
|
||||
]);
|
||||
|
||||
// 时间日期选择器查询
|
||||
const setRangeChange = async (val) => {
|
||||
setRange(val);
|
||||
console.log('时间日期', val);
|
||||
state.current.startTime = '';
|
||||
state.current.endTime = '';
|
||||
if (val.length > 0) {
|
||||
state.current.startTime = val[0];
|
||||
state.current.endTime = val[1];
|
||||
}
|
||||
const pageSizeRef = useRef(10);
|
||||
|
||||
await taskDataChange();
|
||||
}
|
||||
const filteredMock = useMemo(() => {
|
||||
const keyword = searchQuery.trim().toLowerCase();
|
||||
const filterItems = (items: TaskListItem[]) => {
|
||||
if (!keyword) return items;
|
||||
return items.filter((item) => {
|
||||
const text = `${item.taskName} ${item.overview} ${item.owner || ''}`.toLowerCase();
|
||||
return text.includes(keyword);
|
||||
});
|
||||
};
|
||||
|
||||
// 处理开始分析按钮点击
|
||||
const handleStartAnalysis = (task: TaskListItem) => {
|
||||
setSelectedTaskForAnalysis(task);
|
||||
state.current.task = task;
|
||||
setShowAnalysisModal(true);
|
||||
};
|
||||
return {
|
||||
unanalyzed: filterItems(MOCK_TASKS.unanalyzed),
|
||||
analyzing: filterItems(MOCK_TASKS.analyzing),
|
||||
completed: filterItems(MOCK_TASKS.completed),
|
||||
};
|
||||
}, [searchQuery]);
|
||||
|
||||
// 处理分析模式选择
|
||||
const handleSelectAnalysisMode = (mode: TaskType) => {
|
||||
setShowAnalysisModal(false);
|
||||
console.log('mode', mode);
|
||||
if (mode === 'consultation') {
|
||||
console.log('state.current.task', state.current.task)
|
||||
const sceneItem = JSON.parse(state.current.task.scene);
|
||||
if (sceneItem.taskJson) {
|
||||
sceneItem.taskJson = JSON.parse(sceneItem.taskJson);
|
||||
setStartConfig({
|
||||
...sceneItem.taskJson,
|
||||
llm_preset_id: 'BAILING',
|
||||
consistency_mode: 'soft',
|
||||
phase_config: { diverge_rounds: 3 },
|
||||
task_context: state.current.task.overview
|
||||
});
|
||||
router('/qa-center/mope-chat')
|
||||
}
|
||||
console.log('sceneItem', sceneItem);
|
||||
} else if (mode === 'task-search') {
|
||||
window.open(`https://ch1.b.uat.4.cn/web/#/task/item-aicoh/step-info-search?id=${state.current.task.id}`)
|
||||
}
|
||||
};
|
||||
const applyMockColumn = (column: ColumnType, pageIndex = 1) => {
|
||||
const source = filteredMock[column];
|
||||
const pageItems = paginateTasks(source, pageIndex, pageSizeRef.current);
|
||||
|
||||
// 处理卡片点击
|
||||
const taskListSearch = async (taskType: string, pageNum: number = 1, pageSize: number = 10) => {
|
||||
let taskStatus: number[] = []
|
||||
if (taskType === 'unanalyzed') { // 未分析
|
||||
taskStatus = [0, 10];
|
||||
setUnanalyzedLoading(true);
|
||||
} else if (taskType === 'running') { // 分析中
|
||||
taskStatus = [20];
|
||||
setRunningLoading(true);
|
||||
} else if (taskType === 'completed') { // 已完成
|
||||
taskStatus = [25, 30, 40, 60, 70, 80, 90, 100, 110];
|
||||
setCompletedLoading(true);
|
||||
}
|
||||
const param = {
|
||||
content: searchQuery,
|
||||
pageNum: pageNum,
|
||||
pageSize: pageSize,
|
||||
taskStatus: taskStatus,
|
||||
startTime: state.current.startTime,
|
||||
endTime: state.current.endTime,
|
||||
taskDirection: ''
|
||||
}
|
||||
const res = await service.post(`${zncmUrl}/three/cop-three-tasks`, param);
|
||||
console.log('任务列表', res);
|
||||
const result = res.data;
|
||||
result.records.forEach((item: TaskListItem) => {
|
||||
item.column = taskType;
|
||||
if (!item.taskLevel) item.taskLevel = 1;
|
||||
})
|
||||
if (taskType === 'unanalyzed') {
|
||||
if (column === 'unanalyzed') {
|
||||
setUnanalyzedTotal(source.length);
|
||||
setUnanalyzedList(pageItems);
|
||||
setUnanalyzedLoading(false);
|
||||
setUnanalyzedTotal(result.total);
|
||||
setUnanalyzedList(result.records);
|
||||
} else if (taskType === 'running') {
|
||||
} else if (column === 'analyzing') {
|
||||
setRunningTotal(source.length);
|
||||
setRunningList(pageItems);
|
||||
setRunningLoading(false);
|
||||
setRunningTotal(result.total);
|
||||
setRunningList(result.records);
|
||||
} else if (taskType === 'completed') {
|
||||
} else {
|
||||
setCompletedTotal(source.length);
|
||||
setCompletedList(pageItems);
|
||||
setCompletedLoading(false);
|
||||
setCompletedTotal(result.total);
|
||||
setCompletedList(result.records);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 页码变化时的回调函数
|
||||
* 当用户切换页码时触发,更新页码并重新获取数据
|
||||
* @param value - 新的页码值
|
||||
*/
|
||||
const pageIndexChange = async (type: string, pageIndex: number) => {
|
||||
// 更新 ref 中存储的页码值
|
||||
// 更新页码状态,触发组件重新渲染
|
||||
await taskListSearch(type, pageIndex);
|
||||
}
|
||||
const taskListSearch = async (
|
||||
taskStatus: ColumnType,
|
||||
pageIndex = 1,
|
||||
pageSize = pageSizeRef.current,
|
||||
) => {
|
||||
pageSizeRef.current = pageSize;
|
||||
|
||||
const taskDataChange = async (pageNum: number = 1, pageSize: number = 10) => {
|
||||
taskListSearch('unanalyzed', pageNum, pageSize);
|
||||
taskListSearch('running', pageNum, pageSize);
|
||||
taskListSearch('completed', pageNum, pageSize);
|
||||
}
|
||||
const setLoadingByType = (loading: boolean) => {
|
||||
if (taskStatus === 'unanalyzed') setUnanalyzedLoading(loading);
|
||||
if (taskStatus === 'analyzing') setRunningLoading(loading);
|
||||
if (taskStatus === 'completed') setCompletedLoading(loading);
|
||||
};
|
||||
|
||||
// 回车处理
|
||||
const handleKeyDown = async (e) => {
|
||||
if ((e.metaKey || e.ctrlKey || e.shiftKey) && e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
} else if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
await taskDataChange();
|
||||
} else if (e.key === "/") {
|
||||
e.preventDefault();
|
||||
setLoadingByType(true);
|
||||
|
||||
if (useDemoData) {
|
||||
applyMockColumn(taskStatus, pageIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const [startTime, endTime] = Array.isArray(dateRange) ? dateRange : ['', ''];
|
||||
const payload = {
|
||||
pageNum: pageIndex,
|
||||
pageSize,
|
||||
taskStatus,
|
||||
taskCategoryName: category,
|
||||
taskTypeName: subCategory,
|
||||
searchKey: searchQuery.trim() || undefined,
|
||||
startTime,
|
||||
endTime,
|
||||
};
|
||||
|
||||
const response = await service.post(`${zncmUrl}/three/cop-three-tasks`, payload);
|
||||
const rows = response?.rows || response?.data?.rows || [];
|
||||
const total = response?.total || response?.data?.total || 0;
|
||||
const mappedList = rows.map((item: TaskListItem) => ({
|
||||
...item,
|
||||
column: taskStatus === 'analyzing' ? 'running' : taskStatus,
|
||||
}));
|
||||
|
||||
if (taskStatus === 'unanalyzed') {
|
||||
setUnanalyzedList(mappedList);
|
||||
setUnanalyzedTotal(total);
|
||||
} else if (taskStatus === 'analyzing') {
|
||||
setRunningList(mappedList);
|
||||
setRunningTotal(total);
|
||||
} else {
|
||||
setCompletedList(mappedList);
|
||||
setCompletedTotal(total);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('sentiment task list fetch failed', error);
|
||||
applyMockColumn(taskStatus, pageIndex);
|
||||
setUseDemoData(true);
|
||||
} finally {
|
||||
setLoadingByType(false);
|
||||
}
|
||||
};
|
||||
|
||||
const refreshAllColumns = async () => {
|
||||
await Promise.all([
|
||||
taskListSearch('unanalyzed', 1),
|
||||
taskListSearch('analyzing', 1),
|
||||
taskListSearch('completed', 1),
|
||||
]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
taskDataChange();
|
||||
}, []);
|
||||
refreshAllColumns();
|
||||
}, [useDemoData]);
|
||||
|
||||
// 渲染看板列
|
||||
useEffect(() => {
|
||||
const timer = window.setTimeout(() => {
|
||||
refreshAllColumns();
|
||||
}, useDemoData ? 120 : 260);
|
||||
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [searchQuery, dateRange, useDemoData]);
|
||||
|
||||
const metrics = [
|
||||
{
|
||||
label: '全部任务',
|
||||
value: unanalyzedTotal + runningTotal + completedTotal,
|
||||
icon: Layers,
|
||||
accent: 'from-[#4D8DFF] to-[#76C2FF]',
|
||||
},
|
||||
{
|
||||
label: '未分析',
|
||||
value: unanalyzedTotal,
|
||||
icon: Clock3,
|
||||
accent: 'from-[#38BDF8] to-[#7DD3FC]',
|
||||
},
|
||||
{
|
||||
label: '分析中',
|
||||
value: runningTotal,
|
||||
icon: Sparkles,
|
||||
accent: 'from-[#2DD4BF] to-[#67E8F9]',
|
||||
},
|
||||
{
|
||||
label: '已完成',
|
||||
value: completedTotal,
|
||||
icon: Bot,
|
||||
accent: 'from-[#60A5FA] to-[#A78BFA]',
|
||||
},
|
||||
];
|
||||
|
||||
const handleStartAnalysis = (task: TaskListItem) => {
|
||||
setSelectedTaskForAnalysis(task);
|
||||
setShowAnalysisModal(true);
|
||||
};
|
||||
|
||||
const handleViewTaskDetail = () => {
|
||||
if (!selectedTaskForAnalysis) return;
|
||||
setStartConfig({
|
||||
task_title: selectedTaskForAnalysis.taskName,
|
||||
task_goal: selectedTaskForAnalysis.overview,
|
||||
task_context: selectedTaskForAnalysis.overview,
|
||||
llm_preset_id: 'BAILING',
|
||||
consistency_mode: 'soft',
|
||||
phase_config: { diverge_rounds: 3 },
|
||||
});
|
||||
setShowAnalysisModal(false);
|
||||
navigate('/qa-center/mope-chat');
|
||||
};
|
||||
|
||||
const handleMultiAgentDiscussion = () => {
|
||||
if (!selectedTaskForAnalysis) return;
|
||||
setStartConfig({
|
||||
task_title: selectedTaskForAnalysis.taskName,
|
||||
task_goal: selectedTaskForAnalysis.overview,
|
||||
task_context: selectedTaskForAnalysis.overview,
|
||||
llm_preset_id: 'BAILING',
|
||||
consistency_mode: 'soft',
|
||||
phase_config: { diverge_rounds: 3 },
|
||||
});
|
||||
setShowAnalysisModal(false);
|
||||
navigate('/page/workspace/roundtable/planning');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col">
|
||||
{/* 顶部工具栏 */}
|
||||
<div className={`rounded-xl p-4 flex-shrink-0 mb-4 ${cardBg} border ${cardBorder}`}>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className={`px-2 py-0.5 rounded text-xs ${isDark ? 'bg-blue-500/20 text-blue-400' : 'bg-red-100 text-red-600'}`}>
|
||||
{category}
|
||||
</span>
|
||||
<span className={`text-xs ${textMuted}`}>/</span>
|
||||
<span className={`px-2 py-0.5 rounded text-xs ${isDark ? 'bg-cyan-500/20 text-cyan-400' : 'bg-red-100 text-red-600'}`}>
|
||||
{subCategory}
|
||||
</span>
|
||||
</div>
|
||||
<h1 className={`text-xl font-bold ${textPrimary}`}>任务中心</h1>
|
||||
</div>
|
||||
{/* <button
|
||||
onClick={() => onNavigate('task-create')}
|
||||
className={`flex items-center gap-2 px-4 py-2 text-white rounded-lg text-sm font-medium transition-colors ${isDark
|
||||
? 'bg-blue-600 hover:bg-blue-500'
|
||||
: 'bg-red-600 hover:bg-red-500 shadow-md'
|
||||
}`}
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
新建任务
|
||||
</button> */}
|
||||
</div>
|
||||
|
||||
{/* 搜索和筛选 */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative flex-1 max-w-md">
|
||||
<Search className={`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 ${textMuted}`} />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索任务名称"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
onKeyDown={(e) => handleKeyDown(e)}
|
||||
className={`w-full pl-10 pr-4 py-2 border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 transition-colors ${inputBg} ${cardBorder} ${textPrimary} placeholder:${textMuted}`}
|
||||
/>
|
||||
</div>
|
||||
{/* <select
|
||||
value={modeFilter}
|
||||
onChange={(e) => setModeFilter(e.target.value)}
|
||||
className={`px-4 py-2 border rounded-lg text-sm focus:outline-none cursor-pointer ${inputBg} ${cardBorder} ${textSecondary}`}
|
||||
>
|
||||
<option value="all">全部模式</option>
|
||||
<option value="single">单智能体</option>
|
||||
<option value="multi-agent">多智能体协同</option>
|
||||
<option value="consultation">多智能体会商</option>
|
||||
<option value="scene">场景执行</option>
|
||||
</select> */}
|
||||
{/* <button className={`flex items-center gap-2 px-4 py-2 border rounded-lg text-sm transition-colors ${inputBg} ${cardBorder} ${textSecondary}`}>
|
||||
<Clock className="w-4 h-4" />
|
||||
时间范围
|
||||
</button> */}
|
||||
<DateRangePicker value={range} presets={presets} onChange={(val) => setRangeChange(val)} enableTimePicker={true} clearable />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 统计概览栏 */}
|
||||
<div className="grid grid-cols-4 gap-4 mb-4 flex-shrink-0">
|
||||
<button
|
||||
onClick={() => { setModeFilter('all'); }}
|
||||
className={`p-4 rounded-xl border transition-all ${cardBg} ${cardBorder} hover:border-red-400`}
|
||||
>
|
||||
<p className={`text-2xl font-bold ${textPrimary}`}>{unanalyzedTotal + runningTotal + completedTotal}</p>
|
||||
<p className={`text-sm ${textSecondary}`}>全部任务</p>
|
||||
</button>
|
||||
<button
|
||||
className={`p-4 rounded-xl border transition-all ${cardBg} ${cardBorder} hover:border-red-400`}
|
||||
>
|
||||
<p className={`text-2xl font-bold ${textPrimary}`}>{unanalyzedTotal}</p>
|
||||
<p className={`text-sm ${textSecondary}`}>未分析</p>
|
||||
</button>
|
||||
<button
|
||||
className={`p-4 rounded-xl border transition-all ${cardBg} ${cardBorder} hover:border-red-400`}
|
||||
>
|
||||
<p className={`text-2xl font-bold ${isDark ? 'text-blue-400' : 'text-red-600'}`}>{runningTotal}</p>
|
||||
<p className={`text-sm ${textSecondary}`}>分析中</p>
|
||||
</button>
|
||||
<button
|
||||
className={`p-4 rounded-xl border transition-all ${cardBg} ${cardBorder} hover:border-red-400`}
|
||||
>
|
||||
<p className={`text-2xl font-bold ${isDark ? 'text-green-400' : 'text-green-600'}`}>{completedTotal}</p>
|
||||
<p className={`text-sm ${textSecondary}`}>已完成</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 看板区 */}
|
||||
<div className="flex-1 grid grid-cols-3 gap-4 min-h-0 overflow-hidden">
|
||||
<Loading loading={unanalyzedLoading}>
|
||||
<KanbanColumn title="未分析" taskType={"unanalyzed"} TaskDataType={'sentiment'} count={unanalyzedTotal} color={isDark ? 'bg-yellow-400' : 'bg-yellow-400'} tasks={unanalyzedList} pageIndexSearch={pageIndexChange} handleStartAnalysis={handleStartAnalysis} />
|
||||
</Loading>
|
||||
<Loading loading={runningLoading}>
|
||||
<KanbanColumn title="分析中" taskType="running" TaskDataType={'sentiment'} count={runningTotal} color={isDark ? 'bg-blue-400' : 'bg-red-400'} tasks={runningList} pageIndexSearch={pageIndexChange} handleStartAnalysis={handleStartAnalysis} />
|
||||
</Loading>
|
||||
<Loading loading={completedLoading}>
|
||||
<KanbanColumn title="已完成" taskType="completed" TaskDataType={'sentiment'} count={completedTotal} color={isDark ? 'bg-green-400' : 'bg-green-400'} tasks={completedList} pageIndexSearch={pageIndexChange} handleStartAnalysis={handleStartAnalysis} />
|
||||
</Loading>
|
||||
</div>
|
||||
|
||||
{/* 选择分析模式弹窗 */}
|
||||
{showAnalysisModal && selectedTaskForAnalysis && (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50" onClick={() => setShowAnalysisModal(false)}>
|
||||
<div
|
||||
className={`w-full max-w-lg rounded-2xl p-6 ${cardBg} border ${cardBorder} shadow-xl`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className={shellClass}>
|
||||
<div className={`relative mx-auto flex h-full max-w-[1680px] flex-col gap-5 px-6 py-6 lg:px-8 ${panelGlowClass}`}>
|
||||
<div className="flex flex-col gap-4 xl:flex-row xl:items-end xl:justify-between">
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-11 w-11 items-center justify-center rounded-2xl border border-[rgba(96,165,250,0.28)] bg-[linear-gradient(180deg,rgba(22,119,255,0.28),rgba(14,63,135,0.18))] shadow-[0_10px_30px_rgba(14,63,135,0.24)]">
|
||||
<Bot className="h-5 w-5 text-[#7CC9FF]" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className={`text-xl font-bold ${textPrimary}`}>选择分析模式</h2>
|
||||
<p className={`text-sm ${textMuted} mt-1`}>为任务「{selectedTaskForAnalysis.taskName}」选择分析方式</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<h1 className="text-[26px] font-semibold tracking-[0.02em] text-slate-50">{title}</h1>
|
||||
{useDemoData ? (
|
||||
<span className="rounded-full border border-[rgba(125,211,252,0.28)] bg-[rgba(56,189,248,0.14)] px-2.5 py-1 text-xs text-[#8EDCFF]">
|
||||
演示数据
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<p className={`mt-1 text-sm ${isDark ? 'text-slate-300/80' : 'text-slate-500'}`}>
|
||||
面向规划任务的情绪与倾向分析看板,支持快速检索、会商启动与结果回看。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs ${isDark ? 'border-[rgba(110,136,176,0.28)] bg-[rgba(9,25,46,0.72)] text-slate-300' : 'border-slate-200 bg-white text-slate-600'}`}>
|
||||
<span>{category}</span>
|
||||
<ArrowRight className="h-3.5 w-3.5 opacity-70" />
|
||||
<span>{subCategory}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3 xl:items-end">
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<label className={`flex h-11 min-w-[320px] items-center gap-3 rounded-2xl border px-4 ${inputClass}`}>
|
||||
<Search className="h-4 w-4 text-[#7CC9FF]" />
|
||||
<input
|
||||
value={searchQuery}
|
||||
onChange={(event) => setSearchQuery(event.target.value)}
|
||||
className="w-full bg-transparent text-sm outline-none"
|
||||
placeholder="搜索任务名称、摘要或负责人"
|
||||
/>
|
||||
</label>
|
||||
<DateRangePicker
|
||||
className="sentiment-date-range"
|
||||
value={dateRange}
|
||||
enableTimePicker={false}
|
||||
clearable={false}
|
||||
popupProps={{ overlayClassName: 'sentiment-date-range-popup' }}
|
||||
rangeInputProps={{
|
||||
inputProps: [
|
||||
{ inputClass: 'sentiment-date-range-input' },
|
||||
{ inputClass: 'sentiment-date-range-input' },
|
||||
],
|
||||
}}
|
||||
onChange={(value) => setDateRange(value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setUseDemoData(true)}
|
||||
className={`rounded-xl px-4 py-2 text-sm transition ${useDemoData ? 'bg-[#1677FF] text-white shadow-[0_8px_22px_rgba(22,119,255,0.28)]' : isDark ? 'bg-[rgba(10,30,54,0.9)] text-slate-300 hover:bg-[rgba(13,42,78,0.95)]' : 'bg-white text-slate-700 hover:bg-slate-50'}`}
|
||||
>
|
||||
演示数据
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setUseDemoData(false)}
|
||||
className={`rounded-xl px-4 py-2 text-sm transition ${!useDemoData ? 'bg-[#0EA5E9] text-white shadow-[0_8px_22px_rgba(14,165,233,0.24)]' : isDark ? 'bg-[rgba(10,30,54,0.9)] text-slate-300 hover:bg-[rgba(13,42,78,0.95)]' : 'bg-white text-slate-700 hover:bg-slate-50'}`}
|
||||
>
|
||||
真实数据
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
{metrics.map(({ label, value, icon: Icon, accent }) => (
|
||||
<div key={label} className={`rounded-3xl p-5 ${metricCardClass}`}>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className={`text-sm ${isDark ? 'text-slate-300/78' : 'text-slate-500'}`}>{label}</p>
|
||||
<p className="mt-3 text-3xl font-semibold tracking-[0.03em] text-white">{value}</p>
|
||||
</div>
|
||||
<div className={`flex h-12 w-12 items-center justify-center rounded-2xl bg-gradient-to-br ${accent} shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]`}>
|
||||
<Icon className="h-5 w-5 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid min-h-0 flex-1 grid-cols-1 gap-4 xl:grid-cols-3">
|
||||
<div className="min-h-[420px]">
|
||||
<Loading loading={unanalyzedLoading} showOverlay={false}>
|
||||
<KanbanColumn
|
||||
title="未分析"
|
||||
count={unanalyzedTotal}
|
||||
color="bg-[#38BDF8]"
|
||||
tasks={unanalyzedList}
|
||||
taskType="unanalyzed"
|
||||
TaskDataType="sentiment"
|
||||
pageIndexSearch={(taskType, pageIndex) => taskListSearch(taskType as ColumnType, pageIndex)}
|
||||
handleStartAnalysis={handleStartAnalysis}
|
||||
/>
|
||||
</Loading>
|
||||
</div>
|
||||
<div className="min-h-[420px]">
|
||||
<Loading loading={runningLoading} showOverlay={false}>
|
||||
<KanbanColumn
|
||||
title="分析中"
|
||||
count={runningTotal}
|
||||
color="bg-[#2DD4BF]"
|
||||
tasks={runningList}
|
||||
taskType="analyzing"
|
||||
TaskDataType="sentiment"
|
||||
pageIndexSearch={(taskType, pageIndex) => taskListSearch(taskType as ColumnType, pageIndex)}
|
||||
handleStartAnalysis={handleStartAnalysis}
|
||||
/>
|
||||
</Loading>
|
||||
</div>
|
||||
<div className="min-h-[420px]">
|
||||
<Loading loading={completedLoading} showOverlay={false}>
|
||||
<KanbanColumn
|
||||
title="已完成"
|
||||
count={completedTotal}
|
||||
color="bg-[#60A5FA]"
|
||||
tasks={completedList}
|
||||
taskType="completed"
|
||||
TaskDataType="sentiment"
|
||||
pageIndexSearch={(taskType, pageIndex) => taskListSearch(taskType as ColumnType, pageIndex)}
|
||||
handleStartAnalysis={handleStartAnalysis}
|
||||
/>
|
||||
</Loading>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showAnalysisModal && selectedTaskForAnalysis ? (
|
||||
<div className="fixed inset-0 z-[2000] flex items-center justify-center bg-[rgba(3,10,22,0.62)] px-4 backdrop-blur-sm">
|
||||
<div className={`w-full max-w-[560px] rounded-[28px] border p-6 ${isDark ? 'border-[rgba(110,136,176,0.26)] bg-[linear-gradient(180deg,rgba(10,29,54,0.98),rgba(8,20,37,0.98))] text-slate-100 shadow-[0_28px_80px_rgba(2,8,20,0.42)]' : 'border-slate-200 bg-white text-slate-900 shadow-xl'}`}>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold">选择分析模式</h3>
|
||||
<p className={`mt-2 text-sm ${isDark ? 'text-slate-300/78' : 'text-slate-500'}`}>
|
||||
当前任务:{selectedTaskForAnalysis.taskName}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowAnalysisModal(false)}
|
||||
className={`p-2 rounded-lg hover:bg-slate-700/50 ${textSecondary}`}
|
||||
className={`rounded-xl p-2 transition ${isDark ? 'hover:bg-[rgba(15,41,74,0.88)]' : 'hover:bg-slate-100'}`}
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
|
||||
<div className="mt-6 grid gap-3">
|
||||
<button
|
||||
onClick={() => handleSelectAnalysisMode('task-search')}
|
||||
className={`w-full p-4 rounded-xl border transition-all duration-200 text-left hover:shadow-md ${isDark
|
||||
? 'bg-slate-700/50 border-blue-800/30 hover:border-green-500/50'
|
||||
: 'bg-white border-red-100 hover:border-red-300 hover:shadow-md'
|
||||
}`}
|
||||
type="button"
|
||||
onClick={handleViewTaskDetail}
|
||||
className={`group flex items-center justify-between rounded-2xl border px-5 py-4 text-left transition ${isDark ? 'border-[rgba(110,136,176,0.24)] bg-[rgba(10,30,54,0.9)] hover:border-[rgba(96,165,250,0.48)] hover:bg-[rgba(12,38,69,0.96)]' : 'border-slate-200 bg-slate-50 hover:border-sky-200 hover:bg-sky-50'}`}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`w-12 h-12 rounded-xl flex items-center justify-center ${isDark ? 'bg-green-500/20' : 'bg-green-100'
|
||||
}`}>
|
||||
<Layers className={`w-6 h-6 ${isDark ? 'text-green-400' : 'text-green-600'}`} />
|
||||
<div className="flex h-11 w-11 items-center justify-center rounded-2xl bg-[linear-gradient(180deg,#1677FF,#0EA5E9)]">
|
||||
<Layers className="h-5 w-5 text-white" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className={`font-semibold ${textPrimary}`}>查看任务详情</h3>
|
||||
<p className={`text-sm ${textSecondary}`}>进入b1系统查看任务详情</p>
|
||||
<div>
|
||||
<div className="font-medium">查看任务详情</div>
|
||||
<div className={`mt-1 text-sm ${isDark ? 'text-slate-300/72' : 'text-slate-500'}`}>进入单任务分析视图,查看步骤、结论和上下文信息。</div>
|
||||
</div>
|
||||
<ArrowRight className={`w-5 h-5 ${textMuted}`} />
|
||||
</div>
|
||||
<ArrowRight className="h-4 w-4 opacity-70 transition group-hover:translate-x-0.5" />
|
||||
</button>
|
||||
|
||||
|
||||
{/* 多智能体会商 */}
|
||||
<button
|
||||
onClick={() => handleSelectAnalysisMode('consultation')}
|
||||
className={`w-full p-4 rounded-xl border transition-all duration-200 text-left hover:shadow-md ${isDark
|
||||
? 'bg-slate-700/50 border-blue-800/30 hover:border-orange-500/50'
|
||||
: 'bg-white border-red-100 hover:border-red-300 hover:shadow-md'
|
||||
}`}
|
||||
type="button"
|
||||
onClick={handleMultiAgentDiscussion}
|
||||
className={`group flex items-center justify-between rounded-2xl border px-5 py-4 text-left transition ${isDark ? 'border-[rgba(110,136,176,0.24)] bg-[rgba(10,30,54,0.9)] hover:border-[rgba(45,212,191,0.48)] hover:bg-[rgba(10,42,58,0.96)]' : 'border-slate-200 bg-slate-50 hover:border-emerald-200 hover:bg-emerald-50'}`}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`w-12 h-12 rounded-xl flex items-center justify-center ${isDark ? 'bg-orange-500/20' : 'bg-red-100'
|
||||
}`}>
|
||||
<Users className={`w-6 h-6 ${isDark ? 'text-orange-400' : 'text-red-500'}`} />
|
||||
<div className="flex h-11 w-11 items-center justify-center rounded-2xl bg-[linear-gradient(180deg,#14B8A6,#22C55E)]">
|
||||
<Users className="h-5 w-5 text-white" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className={`font-semibold ${textPrimary}`}>多智能体会商</h3>
|
||||
<p className={`text-sm ${textSecondary}`}>多个AI智能体从不同视角开展讨论并形成共识</p>
|
||||
<div>
|
||||
<div className="font-medium">多智能体会商</div>
|
||||
<div className={`mt-1 text-sm ${isDark ? 'text-slate-300/72' : 'text-slate-500'}`}>启动会商模式,由多个智能体并行分析情绪走势与影响因素。</div>
|
||||
</div>
|
||||
<ArrowRight className={`w-5 h-5 ${textMuted}`} />
|
||||
</div>
|
||||
<ArrowRight className="h-4 w-4 opacity-70 transition group-hover:translate-x-0.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useTheme } from '@/contexts/ThemeContext';
|
||||
import { TaskListItem } from './TaskManagement';
|
||||
import { Bot, ChevronRight, Download, Edit, Eye, FileText, Layers, MoreHorizontal, Play, User, Users, Workflow } from 'lucide-react';
|
||||
import React from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Bot, Eye, Layers, Play, User, Users, Workflow } from 'lucide-react';
|
||||
import { useTheme } from '@/contexts/ThemeContext';
|
||||
import { useChatContext } from '@/contexts/ChatContext';
|
||||
import { TaskListItem } from './TaskManagement';
|
||||
|
||||
interface TaskCardProps {
|
||||
TaskType?: string;
|
||||
@@ -12,27 +12,20 @@ interface TaskCardProps {
|
||||
handleStartAnalysis: (task: TaskListItem) => void;
|
||||
}
|
||||
|
||||
export const TaskCard: React.FC<TaskCardProps> = ({ task, TaskType = 'task', handleStartAnalysis }) => {
|
||||
export const TaskCard: React.FC<TaskCardProps> = ({
|
||||
task,
|
||||
TaskType = 'task',
|
||||
handleStartAnalysis,
|
||||
}) => {
|
||||
const { theme } = useTheme();
|
||||
const { setStartConfig } = useChatContext();
|
||||
const isDark = theme === 'dark';
|
||||
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
|
||||
const textMuted = isDark ? 'text-slate-500' : 'text-gray-400';
|
||||
const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600';
|
||||
const navigate = useNavigate();
|
||||
const isDark = theme === 'dark';
|
||||
|
||||
const handleStartChange = (task: TaskListItem) => {
|
||||
// if (TaskType === 'task') {
|
||||
// handleStartAnalysis(task);
|
||||
// } else {
|
||||
// sceneDataChange(task);
|
||||
// }
|
||||
handleStartAnalysis(task);
|
||||
}
|
||||
const sceneDataChange = (currentTask: TaskListItem) => {
|
||||
if (!currentTask.scene) return;
|
||||
|
||||
const sceneDataChange = (task: TaskListItem) => {
|
||||
if (!task.scene) return;
|
||||
const sceneItem = JSON.parse(task.scene);
|
||||
const sceneItem = JSON.parse(currentTask.scene);
|
||||
if (sceneItem.taskJson) {
|
||||
sceneItem.taskJson = JSON.parse(sceneItem.taskJson);
|
||||
setStartConfig({
|
||||
@@ -40,264 +33,198 @@ export const TaskCard: React.FC<TaskCardProps> = ({ task, TaskType = 'task', han
|
||||
llm_preset_id: 'BAILING',
|
||||
consistency_mode: 'soft',
|
||||
phase_config: { diverge_rounds: 3 },
|
||||
task_context: task.overview
|
||||
task_context: currentTask.overview,
|
||||
});
|
||||
navigate('/qa-center/mope-chat')
|
||||
navigate('/qa-center/mope-chat');
|
||||
}
|
||||
console.log('sceneItem', sceneItem);
|
||||
}
|
||||
// 处理卡片点击
|
||||
const handleTaskClick = (task: TaskListItem) => {
|
||||
};
|
||||
|
||||
const handleTaskClick = (currentTask: TaskListItem) => {
|
||||
if (TaskType === 'sentiment') {
|
||||
console.log('点击了', task)
|
||||
sceneDataChange(task);
|
||||
// window.open(`http://ch1.b.uat.4.cn/taskcop/#/situation-overview/action/sentiment?taskId=${task.id}`)
|
||||
} else {
|
||||
if (task.column === 'completed') {
|
||||
// if (task.type === 'consultation') {
|
||||
// onNavigate('task-consult-result');
|
||||
// } else {
|
||||
// onNavigate('strategy-result');
|
||||
// }
|
||||
navigate('/strategy-result')
|
||||
} else if (task.column === 'running') {
|
||||
// navigate('/task-management/task-consult')
|
||||
sceneDataChange(task);
|
||||
// window.open(`http://ch1.b.uat.4.cn/mopeweb/#/mope?taskOverview=${task.overview}`)
|
||||
// if (task.type === 'scene') {
|
||||
// onNavigate('task-scene');
|
||||
// } else if (task.type === 'consultation') {
|
||||
// onNavigate('task-consult');
|
||||
// } else {
|
||||
// onNavigate('task-single');
|
||||
// }
|
||||
}
|
||||
sceneDataChange(currentTask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTask.column === 'completed') {
|
||||
navigate('/strategy-result');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTask.column === 'running' || currentTask.column === 'analyzing') {
|
||||
sceneDataChange(currentTask);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取任务类型配置
|
||||
const handleStartChange = (currentTask: TaskListItem) => {
|
||||
handleStartAnalysis(currentTask);
|
||||
};
|
||||
|
||||
const getTypeConfig = (type: string) => {
|
||||
if (isDark) {
|
||||
switch (type) {
|
||||
case 'single':
|
||||
return { label: '单智能体', color: 'bg-cyan-500/20 text-cyan-400', icon: Bot };
|
||||
case 'scene':
|
||||
return { label: '场景执行', color: 'bg-purple-500/20 text-purple-400', icon: Workflow };
|
||||
case 'consultation':
|
||||
return { label: '多智能体会商', color: 'bg-orange-500/20 text-orange-400', icon: Users };
|
||||
case 'multi-agent':
|
||||
return { label: '多智能体协同', color: 'bg-green-500/20 text-green-400', icon: Layers };
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case 'single':
|
||||
return { label: '单智能体', color: 'bg-blue-100 text-blue-600', icon: Bot };
|
||||
case 'scene':
|
||||
return { label: '场景执行', color: 'bg-purple-100 text-purple-600', icon: Workflow };
|
||||
case 'consultation':
|
||||
return { label: '多智能体会商', color: 'bg-orange-100 text-orange-600', icon: Users };
|
||||
case 'multi-agent':
|
||||
return { label: '多智能体协同', color: 'bg-green-100 text-green-600', icon: Layers };
|
||||
}
|
||||
}
|
||||
};
|
||||
const typeConfig = getTypeConfig('single');
|
||||
// 获取任务等级
|
||||
const getLevel = (type: number) => {
|
||||
const fallback = { label: '一般', color: isDark ? 'bg-cyan-500/20 text-cyan-400' : 'bg-blue-100 text-blue-600', icon: Bot };
|
||||
if (isDark) {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return { label: '一般', color: 'bg-cyan-500/20 text-cyan-400', icon: Bot };
|
||||
case 2:
|
||||
return { label: '紧急', color: 'bg-purple-500/20 text-purple-400', icon: Workflow };
|
||||
case 3:
|
||||
return { label: '加急', color: 'bg-orange-500/20 text-orange-400', icon: Users };
|
||||
default:
|
||||
return fallback;
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return { label: '一般', color: 'bg-blue-100 text-blue-600', icon: Bot };
|
||||
case 2:
|
||||
return { label: '紧急', color: 'bg-purple-100 text-purple-600', icon: Workflow };
|
||||
case 3:
|
||||
return { label: '加急', color: 'bg-orange-100 text-orange-600', icon: Users };
|
||||
default:
|
||||
return fallback;
|
||||
}
|
||||
const common = isDark ? 'border border-white/10 text-slate-200' : 'border border-slate-200 text-slate-700';
|
||||
switch (type) {
|
||||
case 'single':
|
||||
return {
|
||||
label: '单任务',
|
||||
icon: Layers,
|
||||
className: `${common} ${isDark ? 'bg-[rgba(22,119,255,0.14)]' : 'bg-sky-50'}`,
|
||||
};
|
||||
case 'consultation':
|
||||
return {
|
||||
label: '会商',
|
||||
icon: Users,
|
||||
className: `${common} ${isDark ? 'bg-[rgba(20,184,166,0.14)]' : 'bg-emerald-50'}`,
|
||||
};
|
||||
case 'scene':
|
||||
return {
|
||||
label: '场景',
|
||||
icon: Workflow,
|
||||
className: `${common} ${isDark ? 'bg-[rgba(168,85,247,0.14)]' : 'bg-violet-50'}`,
|
||||
};
|
||||
case 'multi-agent':
|
||||
return {
|
||||
label: '多智能体',
|
||||
icon: Bot,
|
||||
className: `${common} ${isDark ? 'bg-[rgba(99,102,241,0.16)]' : 'bg-indigo-50'}`,
|
||||
};
|
||||
default:
|
||||
return {
|
||||
label: '检索',
|
||||
icon: Layers,
|
||||
className: `${common} ${isDark ? 'bg-[rgba(59,130,246,0.12)]' : 'bg-slate-100'}`,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const levelConfig = getLevel(task.taskLevel);
|
||||
const LevelIcon = levelConfig.icon;
|
||||
// 获取状态配置
|
||||
const getLevel = (priority: number = 1) => {
|
||||
if (priority >= 3) return '加急';
|
||||
if (priority === 2) return '紧急';
|
||||
return '一般';
|
||||
};
|
||||
|
||||
const getStatusConfig = (column: string) => {
|
||||
if (column === 'unanalyzed') {
|
||||
return { label: '待分析', color: isDark ? 'bg-yellow-500/20 text-yellow-400' : 'bg-yellow-100 text-yellow-600' };
|
||||
} else if (column === 'running') {
|
||||
return { label: '运行中', color: isDark ? 'bg-blue-500/20 text-blue-400' : 'bg-red-100 text-red-600' };
|
||||
} else {
|
||||
return { label: '已完成', color: isDark ? 'bg-green-500/20 text-green-400' : 'bg-green-100 text-green-600' };
|
||||
switch (column) {
|
||||
case 'completed':
|
||||
return {
|
||||
label: '已完成',
|
||||
className: isDark
|
||||
? 'bg-[rgba(34,197,94,0.16)] text-emerald-300 border border-emerald-400/20'
|
||||
: 'bg-emerald-50 text-emerald-600 border border-emerald-100',
|
||||
};
|
||||
case 'running':
|
||||
case 'analyzing':
|
||||
return {
|
||||
label: '分析中',
|
||||
className: isDark
|
||||
? 'bg-[rgba(14,165,233,0.16)] text-sky-300 border border-sky-400/20'
|
||||
: 'bg-sky-50 text-sky-600 border border-sky-100',
|
||||
};
|
||||
default:
|
||||
return {
|
||||
label: '待分析',
|
||||
className: isDark
|
||||
? 'bg-[rgba(96,165,250,0.14)] text-blue-200 border border-blue-300/15'
|
||||
: 'bg-blue-50 text-blue-600 border border-blue-100',
|
||||
};
|
||||
}
|
||||
};
|
||||
const statusConfig = getStatusConfig(task.column);
|
||||
|
||||
const typeConfig = getTypeConfig(task.type || 'single');
|
||||
const statusConfig = getStatusConfig(task.column || 'unanalyzed');
|
||||
const TypeIcon = typeConfig.icon;
|
||||
const progressValue = Math.max(0, Math.min(task.progress || 0, 100));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`rounded-xl p-4 hover:shadow-md transition-all duration-200 cursor-pointer group theme-card border ${isDark
|
||||
? 'bg-slate-800/40 backdrop-blur-xl border-blue-800/30 hover:border-blue-500/50'
|
||||
: 'bg-white border-red-100 hover:shadow-md shadow-red-100'
|
||||
}`}
|
||||
onClick={() => handleTaskClick(task)}
|
||||
className={`theme-card theme-card-hover theme-transition rounded-[24px] border p-4 ${
|
||||
isDark
|
||||
? 'border-[rgba(110,136,176,0.2)] shadow-[0_12px_30px_rgba(2,8,20,0.20)]'
|
||||
: 'border-slate-200 bg-white shadow-sm'
|
||||
}`}
|
||||
>
|
||||
{/* 卡片头部:模式标签 + 状态标签 */}
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded text-xs font-medium ${levelConfig.color}`}>
|
||||
{LevelIcon && <LevelIcon className="w-3 h-3" />}
|
||||
{levelConfig.label}
|
||||
</span>
|
||||
<span></span>
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${statusConfig.color}`}>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className={`inline-flex items-center gap-2 rounded-full px-3 py-1 text-xs ${typeConfig.className}`}>
|
||||
<TypeIcon className="h-3.5 w-3.5" />
|
||||
<span>{typeConfig.label}</span>
|
||||
</div>
|
||||
<span className={`inline-flex items-center rounded-full px-2.5 py-1 text-xs ${statusConfig.className}`}>
|
||||
{statusConfig.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 任务名称 */}
|
||||
<h3 className={`font-semibold text-sm mb-1 line-clamp-2 group-hover:text-red-500 transition-colors ${textPrimary}`}>
|
||||
{task.taskName}
|
||||
</h3>
|
||||
|
||||
{/* 任务编号 */}
|
||||
<p className={`text-xs mb-2 ${textMuted}`}>TASK-{task.id}</p>
|
||||
|
||||
{/* 任务摘要 */}
|
||||
<p className={`text-xs mb-3 line-clamp-2 ${textSecondary}`}>{task.overview}</p>
|
||||
|
||||
{/* 补充信息区 */}
|
||||
{/* <div className="space-y-1 mb-3">
|
||||
{task.type === 'single' && task.agent && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Bot className={`w-3 h-3 ${isDark ? 'text-cyan-400' : 'text-red-500'}`} />
|
||||
<span className={textSecondary}>执行智能体:</span>
|
||||
<span className={isDark ? 'text-cyan-400' : 'text-red-600'}>{task.agent}</span>
|
||||
</div>
|
||||
)}
|
||||
{task.type === 'scene' && task.scene && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Workflow className={`w-3 h-3 ${isDark ? 'text-purple-400' : 'text-red-500'}`} />
|
||||
<span className={textSecondary}>关联场景:</span>
|
||||
<span className={isDark ? 'text-purple-400' : 'text-red-600'}>{task.scene}</span>
|
||||
</div>
|
||||
)}
|
||||
{task.type === 'consultation' && (
|
||||
<>
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Users className={`w-3 h-3 ${isDark ? 'text-orange-400' : 'text-red-500'}`} />
|
||||
<span className={textSecondary}>参与智能体:</span>
|
||||
<span className={isDark ? 'text-orange-400' : 'text-red-600'}>{task.participants?.length || 0}个</span>
|
||||
</div>
|
||||
{task.currentRound && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Clock className={`w-3 h-3 ${textMuted}`} />
|
||||
<span className={textSecondary}>当前轮次:</span>
|
||||
<span className={textPrimary}>第{task.currentRound}轮</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{task.column === 'analyzing' && task.currentPhase && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Target className={`w-3 h-3 ${textMuted}`} />
|
||||
<span className={textSecondary}>当前阶段:</span>
|
||||
<span className={textPrimary}>{task.currentPhase}</span>
|
||||
</div>
|
||||
)}
|
||||
</div> */}
|
||||
|
||||
{/* 时间信息 */}
|
||||
<div className={`flex items-center justify-between text-xs pt-3 border-t ${isDark ? 'border-blue-800/30 text-slate-500' : 'border-red-100 text-gray-400'
|
||||
}`}>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<User className="w-3 h-3" />
|
||||
<span>{task.taskDirection}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleTaskClick(task)}
|
||||
className="mt-4 block w-full text-left"
|
||||
>
|
||||
<div className={`line-clamp-2 text-[15px] font-semibold leading-6 ${isDark ? 'text-slate-50' : 'text-slate-900'}`}>
|
||||
{task.taskName}
|
||||
</div>
|
||||
<p className={`mt-2 line-clamp-3 text-sm leading-6 ${isDark ? 'text-slate-300/78' : 'text-slate-500'}`}>
|
||||
{task.overview || '暂无任务摘要'}
|
||||
</p>
|
||||
</button>
|
||||
|
||||
<div className="mt-4 space-y-3">
|
||||
<div className="flex items-center justify-between text-xs">
|
||||
<div className={`flex items-center gap-1.5 ${isDark ? 'text-slate-400' : 'text-slate-500'}`}>
|
||||
<User className="h-3.5 w-3.5" />
|
||||
<span>{task.owner || task.creator || '未分配'}</span>
|
||||
</div>
|
||||
<div className={`${isDark ? 'text-slate-500' : 'text-slate-400'}`}>优先级:{getLevel(task.priority)}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="mb-1.5 flex items-center justify-between text-xs">
|
||||
<span className={isDark ? 'text-slate-400' : 'text-slate-500'}>分析进度</span>
|
||||
<span className={isDark ? 'text-slate-300' : 'text-slate-700'}>{progressValue}%</span>
|
||||
</div>
|
||||
<div className={`h-2 overflow-hidden rounded-full ${isDark ? 'bg-[rgba(255,255,255,0.08)]' : 'bg-slate-100'}`}>
|
||||
<div
|
||||
className="h-full rounded-full bg-[linear-gradient(90deg,#1677FF,#5EEAD4)]"
|
||||
style={{ width: `${progressValue}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between text-xs">
|
||||
<span className={isDark ? 'text-slate-500' : 'text-slate-400'}>
|
||||
创建于 {task.createTime ? format(new Date(task.createTime), 'MM-dd HH:mm') : '--'}
|
||||
</span>
|
||||
<span className={isDark ? 'text-slate-500' : 'text-slate-400'}>
|
||||
更新于 {task.updateTime ? format(new Date(task.updateTime), 'MM-dd HH:mm') : '--'}
|
||||
</span>
|
||||
</div>
|
||||
<span>{format(new Date(task.updateTime), 'yyyy-MM-dd HH:mm:ss')}</span>
|
||||
</div>
|
||||
|
||||
{/* 操作按钮区 */}
|
||||
<div className={`flex items-center gap-2 mt-3 pt-3 border-t ${isDark ? 'border-blue-800/30' : 'border-red-100'
|
||||
}`}>
|
||||
{task.column === 'unanalyzed' && (
|
||||
<>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
||||
className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-white rounded-lg text-xs font-medium transition-colors ${isDark
|
||||
? 'bg-blue-600 hover:bg-blue-500'
|
||||
: 'bg-red-600 hover:bg-red-500 shadow-md'
|
||||
}`}
|
||||
>
|
||||
<Play className="w-3 h-3" />
|
||||
<div className="mt-4 flex gap-2">
|
||||
{task.column === 'completed' ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleTaskClick(task)}
|
||||
className={`flex-1 rounded-xl px-3 py-2 text-sm transition ${
|
||||
isDark
|
||||
? 'bg-[rgba(11,40,71,0.95)] text-slate-100 hover:bg-[rgba(15,49,87,0.98)]'
|
||||
: 'bg-slate-900 text-white hover:bg-slate-800'
|
||||
}`}
|
||||
>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<Eye className="h-4 w-4" />
|
||||
查看结果
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleStartChange(task)}
|
||||
className="flex-1 rounded-xl bg-[linear-gradient(90deg,#1677FF,#0EA5E9)] px-3 py-2 text-sm text-white shadow-[0_10px_24px_rgba(22,119,255,0.28)] transition hover:brightness-110"
|
||||
>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<Play className="h-4 w-4" />
|
||||
开始分析
|
||||
</button>
|
||||
{/* <button
|
||||
onClick={(e) => { e.stopPropagation(); onNavigate('task-create'); }}
|
||||
className={`p-1.5 rounded-lg transition-colors ${isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
||||
}`}
|
||||
title="编辑"
|
||||
>
|
||||
<Edit className={`w-4 h-4 ${isDark ? 'text-slate-400' : 'text-red-400'}`} />
|
||||
</button> */}
|
||||
</>
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
{task.column === 'running' && (
|
||||
<>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
||||
className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-white rounded-lg text-xs font-medium transition-colors ${isDark
|
||||
? 'bg-blue-600 hover:bg-blue-500'
|
||||
: 'bg-red-600 hover:bg-red-500 shadow-md'
|
||||
}`}
|
||||
>
|
||||
<Play className="w-3 h-3" />
|
||||
开始分析
|
||||
</button>
|
||||
{/* <button
|
||||
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
||||
className={`px-2 py-1.5 rounded-lg text-xs transition-colors ${isDark
|
||||
? 'hover:bg-slate-700/50 border border-blue-800/30 text-slate-300'
|
||||
: 'hover:bg-red-50 border border-red-200 text-red-600'
|
||||
}`}
|
||||
>
|
||||
查看进展
|
||||
</button> */}
|
||||
</>
|
||||
)}
|
||||
{task.column === 'completed' && (
|
||||
<>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
||||
className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-white rounded-lg text-xs font-medium transition-colors ${isDark
|
||||
? 'bg-green-600 hover:bg-green-500'
|
||||
: 'bg-green-600 hover:bg-green-500 shadow-md'
|
||||
}`}
|
||||
>
|
||||
<Eye className="w-3 h-3" />
|
||||
开始分析
|
||||
</button>
|
||||
{/* <button className={`px-2 py-1.5 rounded-lg text-xs transition-colors ${isDark
|
||||
? 'hover:bg-slate-700/50 border border-blue-800/30 text-slate-300'
|
||||
: 'hover:bg-red-50 border border-red-200 text-red-600'
|
||||
}`}>
|
||||
<Download className="w-4 h-4" />
|
||||
</button> */}
|
||||
</>
|
||||
)}
|
||||
{/* <button className={`p-1.5 rounded-lg transition-colors ${isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
||||
}`} title="更多">
|
||||
<MoreHorizontal className={`w-4 h-4 ${isDark ? 'text-slate-400' : 'text-red-400'}`} />
|
||||
</button> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
+205
-10
@@ -1,3 +1,5 @@
|
||||
@import "../../../../../docs/ui规范-深蓝/tokens.css";
|
||||
|
||||
/**
|
||||
* Strategy task components styles migrated from web-code/index.css
|
||||
* Used by TaskAnalyzes, SentimentAnalyzes, ActionAnalyzes and related children.
|
||||
@@ -20,17 +22,17 @@
|
||||
|
||||
/* ── CSS variables (dark) ────────────────────────────────────────────── */
|
||||
.dark .strategy-data {
|
||||
--color-main: #0062d9;
|
||||
--td-brand-color: #ce2d39;
|
||||
--bg-color: #0062d966;
|
||||
--card-border: #fa9196;
|
||||
--text-color: #ffffff;
|
||||
--color-main: var(--color-primary);
|
||||
--td-brand-color: var(--color-primary);
|
||||
--bg-color: rgba(22, 119, 255, 0.12);
|
||||
--card-border: rgba(110, 136, 176, 0.32);
|
||||
--text-color: var(--color-text-strong);
|
||||
|
||||
--card-bg: 217.2 32.6% 17.5%;
|
||||
--card-hover: 215 20.2% 25%;
|
||||
--border-color: 217.2 32.6% 17.5%;
|
||||
--input-bg: 217.2 32.6% 17.5%;
|
||||
--input-border: 217.2 32.6% 17.5%;
|
||||
--card-bg: 220 59% 16%;
|
||||
--card-hover: 219 55% 22%;
|
||||
--border-color: 220 54% 29%;
|
||||
--input-bg: 220 71% 10%;
|
||||
--input-border: 220 35% 38%;
|
||||
}
|
||||
|
||||
/* ── Theme card (TaskCard, KanbanColumn) ─────────────────────────────── */
|
||||
@@ -75,10 +77,51 @@
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.strategy-data::-webkit-scrollbar,
|
||||
.strategy-data *::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.strategy-data::-webkit-scrollbar-thumb,
|
||||
.strategy-data *::-webkit-scrollbar-thumb {
|
||||
background: rgba(203, 213, 225, 0.75);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.strategy-data::-webkit-scrollbar-track,
|
||||
.strategy-data *::-webkit-scrollbar-track {
|
||||
background: rgba(241, 245, 249, 0.9);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.dark .strategy-data .scrollbar-thin {
|
||||
scrollbar-color: rgba(148, 163, 184, 0.45) transparent;
|
||||
}
|
||||
|
||||
.dark .strategy-data,
|
||||
.dark .strategy-data * {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(84, 145, 229, 0.58) rgba(8, 23, 42, 0.24);
|
||||
}
|
||||
|
||||
.dark .strategy-data::-webkit-scrollbar-thumb,
|
||||
.dark .strategy-data *::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, rgba(96, 165, 250, 0.78), rgba(45, 212, 191, 0.72));
|
||||
border: 1px solid rgba(8, 23, 42, 0.3);
|
||||
}
|
||||
|
||||
.dark .strategy-data::-webkit-scrollbar-thumb:hover,
|
||||
.dark .strategy-data *::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, rgba(125, 211, 252, 0.9), rgba(94, 234, 212, 0.82));
|
||||
}
|
||||
|
||||
.dark .strategy-data::-webkit-scrollbar-track,
|
||||
.dark .strategy-data *::-webkit-scrollbar-track {
|
||||
background: rgba(8, 23, 42, 0.68);
|
||||
border: 1px solid rgba(110, 136, 176, 0.12);
|
||||
}
|
||||
|
||||
.dark .strategy-data .scrollbar-thin::-webkit-scrollbar-thumb {
|
||||
background: rgba(148, 163, 184, 0.45);
|
||||
}
|
||||
@@ -91,6 +134,158 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-input__wrap,
|
||||
.dark .strategy-data .t-input-adornment,
|
||||
.dark .strategy-data .t-date-range-picker__cell {
|
||||
background: rgba(8, 23, 42, 0.92);
|
||||
border-color: rgba(110, 136, 176, 0.3);
|
||||
color: var(--color-text-strong);
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-date-range,
|
||||
.dark .strategy-data .sentiment-date-range .t-range-input,
|
||||
.dark .strategy-data .sentiment-date-range .t-input__wrap,
|
||||
.dark .strategy-data .sentiment-date-range .t-range-input__inner,
|
||||
.dark .strategy-data .sentiment-date-range .sentiment-date-range-input {
|
||||
background: rgba(8, 23, 42, 0.92) !important;
|
||||
color: #e6f4ff !important;
|
||||
border-color: rgba(110, 136, 176, 0.3) !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-date-range .t-range-input {
|
||||
border-radius: 14px;
|
||||
box-shadow: inset 0 0 0 1px rgba(110, 136, 176, 0.22);
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-date-range .t-range-input__inner::placeholder,
|
||||
.dark .strategy-data .sentiment-date-range .t-input__inner::placeholder {
|
||||
color: rgba(148, 163, 184, 0.82) !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-date-range .t-input__suffix,
|
||||
.dark .strategy-data .sentiment-date-range .t-input-adornment,
|
||||
.dark .strategy-data .sentiment-date-range .t-range-input__suffix {
|
||||
color: #8edcff !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-input__wrap:hover,
|
||||
.dark .strategy-data .t-date-range-picker__cell:hover {
|
||||
border-color: rgba(96, 165, 250, 0.45);
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-input__inner,
|
||||
.dark .strategy-data .t-input-adornment__text,
|
||||
.dark .strategy-data .t-date-range-picker__cell-text {
|
||||
color: var(--color-text-strong);
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-input__inner::placeholder {
|
||||
color: rgba(148, 163, 184, 0.82);
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-pagination .t-button,
|
||||
.dark .strategy-data .t-pagination .t-pagination__btn {
|
||||
color: var(--color-text-strong);
|
||||
background: rgba(10, 30, 54, 0.86);
|
||||
border-color: rgba(110, 136, 176, 0.24);
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-pagination,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini__current,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini__current-input,
|
||||
.dark .strategy-data .sentiment-pagination .t-input,
|
||||
.dark .strategy-data .sentiment-pagination .t-input__wrap,
|
||||
.dark .strategy-data .sentiment-pagination .t-input__inner {
|
||||
background: transparent !important;
|
||||
color: #e6f4ff !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-pagination .t-input,
|
||||
.dark .strategy-data .t-pagination .t-input__wrap,
|
||||
.dark .strategy-data .t-pagination .t-input-adornment,
|
||||
.dark .strategy-data .t-pagination .t-pagination__jump-number-input,
|
||||
.dark .strategy-data .t-pagination .t-pagination__jump-number-input .t-input__wrap,
|
||||
.dark .strategy-data .t-pagination .t-pagination__jump-number-input .t-input__inner {
|
||||
background: rgba(10, 30, 54, 0.92) !important;
|
||||
color: var(--color-text-strong) !important;
|
||||
border-color: rgba(110, 136, 176, 0.3) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-pagination .t-pagination__jump-number-input {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini__current-input {
|
||||
border-bottom: 1px solid rgba(148, 163, 184, 0.75);
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini__current-input:hover,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini__current-input:focus-within {
|
||||
border-bottom-color: #8edcff;
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini__current,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination-mini__current-input,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination__btn-prev,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination__btn-next {
|
||||
color: #e6f4ff !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .sentiment-pagination .t-button,
|
||||
.dark .strategy-data .sentiment-pagination .t-pagination__btn {
|
||||
background: rgba(10, 30, 54, 0.86) !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-pagination .t-pagination__jump-number-input .t-input__inner,
|
||||
.dark .strategy-data .t-pagination .t-input__inner {
|
||||
color: #e6f4ff !important;
|
||||
caret-color: #8edcff;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-pagination .t-pagination__jump-number-input .t-input__inner::placeholder,
|
||||
.dark .strategy-data .t-pagination .t-input__inner::placeholder {
|
||||
color: rgba(148, 163, 184, 0.82) !important;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-pagination .t-button:hover,
|
||||
.dark .strategy-data .t-pagination .t-pagination__btn:hover {
|
||||
background: rgba(13, 42, 78, 0.95);
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-pagination .t-pagination__current {
|
||||
color: #8edcff;
|
||||
}
|
||||
|
||||
.dark .strategy-data .t-date-range-picker {
|
||||
min-width: 320px;
|
||||
}
|
||||
|
||||
.sentiment-date-range-popup .t-date-picker__panel,
|
||||
.sentiment-date-range-popup .t-date-range-picker__panel,
|
||||
.sentiment-date-range-popup .t-date-picker__panel-body,
|
||||
.sentiment-date-range-popup .t-date-picker__panel-content,
|
||||
.sentiment-date-range-popup .t-date-picker__table,
|
||||
.sentiment-date-range-popup .t-time-picker__panel {
|
||||
background: #0d1d33 !important;
|
||||
color: #e6f4ff !important;
|
||||
}
|
||||
|
||||
.sentiment-date-range-popup .t-popup__content {
|
||||
background: #0d1d33 !important;
|
||||
border: 1px solid rgba(110, 136, 176, 0.24);
|
||||
box-shadow: 0 24px 60px rgba(2, 8, 20, 0.42);
|
||||
}
|
||||
|
||||
.sentiment-date-range-popup .t-date-picker__cell,
|
||||
.sentiment-date-range-popup .t-date-picker__cell-inner,
|
||||
.sentiment-date-range-popup .t-date-picker__header,
|
||||
.sentiment-date-range-popup .t-date-picker__text,
|
||||
.sentiment-date-range-popup .t-button {
|
||||
color: #e6f4ff !important;
|
||||
}
|
||||
|
||||
/* ── ActionAnalyzes task sidebar ─────────────────────────────────────── */
|
||||
.strategy-data .task-item-active:hover {
|
||||
border: 1px solid var(--color-main);
|
||||
|
||||
Reference in new issue
Block a user