From 045bb11abfb1e7a5d9991300c78cd8b7d7cbeb61 Mon Sep 17 00:00:00 2001 From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com> Date: Fri, 5 Jun 2026 19:28:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/page-sidebar-dark.tsx | 15 +- frontend-web/src/contexts/ThemeContext.tsx | 15 + frontend-web/src/pages/StrategyRoutes.tsx | 101 +-- .../task-components/KanbanColumn.tsx | 134 +-- .../task-components/SentimentAnalyzes.tsx | 838 +++++++++++------- .../components/task-components/TaskCard.tsx | 431 ++++----- .../task-components/css/strategy-data.css | 215 ++++- 7 files changed, 1048 insertions(+), 701 deletions(-) diff --git a/frontend-web/src/components/page-sidebar-dark.tsx b/frontend-web/src/components/page-sidebar-dark.tsx index 96158764..5d54ec6a 100644 --- a/frontend-web/src/components/page-sidebar-dark.tsx +++ b/frontend-web/src/components/page-sidebar-dark.tsx @@ -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); } }; diff --git a/frontend-web/src/contexts/ThemeContext.tsx b/frontend-web/src/contexts/ThemeContext.tsx index 7a5dcc9c..5d372e9b 100644 --- a/frontend-web/src/contexts/ThemeContext.tsx +++ b/frontend-web/src/contexts/ThemeContext.tsx @@ -184,6 +184,21 @@ export const ThemeProvider: React.FC = ({ 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(); diff --git a/frontend-web/src/pages/StrategyRoutes.tsx b/frontend-web/src/pages/StrategyRoutes.tsx index e4b84c29..ce98f16b 100644 --- a/frontend-web/src/pages/StrategyRoutes.tsx +++ b/frontend-web/src/pages/StrategyRoutes.tsx @@ -1,46 +1,45 @@ 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 TagsPage from "./TagsPage"; +import AgentsPage from "./AgentsPage"; +import ChatPage from "./ChatPage"; +import ChatsPage from "./ChatsPage"; 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 ( @@ -50,14 +49,13 @@ export default function StrategyRoutes() { } /> - {/* 问答中心 */} } /> } /> @@ -69,10 +67,9 @@ export default function StrategyRoutes() { } /> - {/* 任务管理 */} + }> } /> - {/* XK任务 */} } @@ -81,7 +78,6 @@ export default function StrategyRoutes() { path="xk-task-dispatch" element={} /> - {/* pg中任务 */} } @@ -94,12 +90,11 @@ export default function StrategyRoutes() { path="effect-info-pg" element={} /> - {/* COH中任务 */} @@ -109,9 +104,9 @@ export default function StrategyRoutes() { path="plan-task/plan-task-fx" element={ } /> @@ -120,17 +115,16 @@ export default function StrategyRoutes() { element={ } /> - {/* MNTY任务 */} } /> } /> } /> - {/* 资源管理 */} + } @@ -141,16 +135,13 @@ export default function StrategyRoutes() { /> - } + element={} /> - {/* 轻应用 */} + } /> } /> } /> - {/* 对话 */} } /> - {/* 智能体管理 */} } /> } /> - {/* 技能 / 记忆 */} } /> } /> } /> - {/* 定时任务 */} } @@ -193,7 +181,6 @@ export default function StrategyRoutes() { element={} /> - {/* 设置 / 管理 — 权限与 workspace 侧一致,非 admin 重定向到 chats/new */} void; - handleStartAnalysis: (task: TaskListItem) => void + handleStartAnalysis: (task: TaskListItem) => void; } -export const KanbanColumn: React.FC = ({ title, count, color, tasks,taskType, TaskDataType = 'task' , pageIndexSearch, handleStartAnalysis }) => { +export const KanbanColumn: React.FC = ({ + 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(1); - // 每页显示数量,默认为 10 条 - const [pageSize, setPageSize] = useState(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 ( -
-
-
-
-

{title}

- {count} +
+
+
+
+
+
+

{title}

+ + {count} + +
+

+ 按时间倒序展示,支持分页切换。 +

+
- {/* */} - -
+ +
+
+ +
= ({ title, count, color, />
-
+ +
{tasks.length === 0 ? ( -
- -

暂无任务

+
+
+ +
+
暂无任务
+
+ 可以尝试调整筛选条件或切换数据模式。 +
) : ( - tasks.map(task => ) + tasks.map((task) => ( + + )) )}
); -} +}; diff --git a/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx b/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx index 7ced621f..b3f3fb56 100644 --- a/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx @@ -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 = ({ 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 = { + 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 = ({ 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('all'); const [showAnalysisModal, setShowAnalysisModal] = useState(false); const [selectedTaskForAnalysis, setSelectedTaskForAnalysis] = useState(null); - const [unanalyzedTotal, setUnanalyzedTotal] = useState(0); // 未分析 - const [runningTotal, setRunningTotal] = useState(0); // 分析中 - const [completedTotal, setCompletedTotal] = useState(0); // 已完成 - const [unanalyzedList, setUnanalyzedList] = useState([]); // 未分析 - const [runningList, setRunningList] = useState([]); // 分析中 - const [completedList, setCompletedList] = useState([]); // 已完成 - const [unanalyzedLoading, setUnanalyzedLoading] = useState(false); // 未分析 - const [runningLoading, setRunningLoading] = useState(false); // 分析中 - const [completedLoading, setCompletedLoading] = useState(false); // 已完成 - const [presets] = useState({ - 最近7天: [dayjs().subtract(6, 'day').toDate(), dayjs().toDate()], - 最近3天: [dayjs().subtract(2, 'day').toDate(), dayjs().toDate()], - 今天: [dayjs().toDate(), dayjs().toDate()], - }); - const [range, setRange] = useState([]); - const state = useRef({ - 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([]); + const [runningList, setRunningList] = useState([]); + const [completedList, setCompletedList] = useState([]); + const [unanalyzedLoading, setUnanalyzedLoading] = useState(false); + const [runningLoading, setRunningLoading] = useState(false); + const [completedLoading, setCompletedLoading] = useState(false); + const [dateRange, setDateRange] = useState([ + 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 ( -
- {/* 顶部工具栏 */} -
-
-
-
- - {category} - - / - - {subCategory} - -
-

任务中心

-
- {/* */} -
- - {/* 搜索和筛选 */} -
-
- - 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}`} - /> -
- {/* */} - {/* */} - setRangeChange(val)} enableTimePicker={true} clearable /> -
-
- - {/* 统计概览栏 */} -
- - - - -
- - {/* 看板区 */} -
- - - - - - - - - -
- - {/* 选择分析模式弹窗 */} - {showAnalysisModal && selectedTaskForAnalysis && ( -
setShowAnalysisModal(false)}> -
e.stopPropagation()} - > -
+
+
+
+
+
+
+ +
-

选择分析模式

-

为任务「{selectedTaskForAnalysis.taskName}」选择分析方式

+
+

{title}

+ {useDemoData ? ( + + 演示数据 + + ) : null} +
+

+ 面向规划任务的情绪与倾向分析看板,支持快速检索、会商启动与结果回看。 +

+
+
+
+ {category} + + {subCategory} +
+
+ +
+
+ + setDateRange(value)} + /> +
+
+ + +
+
+
+ +
+ {metrics.map(({ label, value, icon: Icon, accent }) => ( +
+
+
+

{label}

+

{value}

+
+
+ +
+
+
+ ))} +
+ +
+
+ + taskListSearch(taskType as ColumnType, pageIndex)} + handleStartAnalysis={handleStartAnalysis} + /> + +
+
+ + taskListSearch(taskType as ColumnType, pageIndex)} + handleStartAnalysis={handleStartAnalysis} + /> + +
+
+ + taskListSearch(taskType as ColumnType, pageIndex)} + handleStartAnalysis={handleStartAnalysis} + /> + +
+
+
+ + {showAnalysisModal && selectedTaskForAnalysis ? ( +
+
+
+
+

选择分析模式

+

+ 当前任务:{selectedTaskForAnalysis.taskName} +

-
- +
- - {/* 多智能体会商 */}
- )} + ) : null}
); }; diff --git a/frontend-web/src/strategy-components/components/task-components/TaskCard.tsx b/frontend-web/src/strategy-components/components/task-components/TaskCard.tsx index 32f75e0a..62edd86b 100644 --- a/frontend-web/src/strategy-components/components/task-components/TaskCard.tsx +++ b/frontend-web/src/strategy-components/components/task-components/TaskCard.tsx @@ -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 = ({ task, TaskType = 'task', handleStartAnalysis }) => { +export const TaskCard: React.FC = ({ + 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 = ({ 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 (
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' + }`} > - {/* 卡片头部:模式标签 + 状态标签 */} -
- - {LevelIcon && } - {levelConfig.label} - - - +
+
+ + {typeConfig.label} +
+ {statusConfig.label}
- {/* 任务名称 */} -

- {task.taskName} -

- - {/* 任务编号 */} -

TASK-{task.id}

- - {/* 任务摘要 */} -

{task.overview}

- - {/* 补充信息区 */} - {/*
- {task.type === 'single' && task.agent && ( -
- - 执行智能体: - {task.agent} -
- )} - {task.type === 'scene' && task.scene && ( -
- - 关联场景: - {task.scene} -
- )} - {task.type === 'consultation' && ( - <> -
- - 参与智能体: - {task.participants?.length || 0}个 -
- {task.currentRound && ( -
- - 当前轮次: - 第{task.currentRound}轮 -
- )} - - )} - {task.column === 'analyzing' && task.currentPhase && ( -
- - 当前阶段: - {task.currentPhase} -
- )} -
*/} - - {/* 时间信息 */} -
-
- - {task.taskDirection} + + +
+
+
+ + {task.owner || task.creator || '未分配'} +
+
优先级:{getLevel(task.priority)}
+
+ +
+
+ 分析进度 + {progressValue}% +
+
+
+
+
+ +
+ + 创建于 {task.createTime ? format(new Date(task.createTime), 'MM-dd HH:mm') : '--'} + + + 更新于 {task.updateTime ? format(new Date(task.updateTime), 'MM-dd HH:mm') : '--'} +
- {format(new Date(task.updateTime), 'yyyy-MM-dd HH:mm:ss')}
- {/* 操作按钮区 */} -
- {task.column === 'unanalyzed' && ( - <> - + ) : ( + - {/* */} - + + )} - {task.column === 'running' && ( - <> - - {/* */} - - )} - {task.column === 'completed' && ( - <> - - {/* */} - - )} - {/* */}
); -} +}; diff --git a/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css b/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css index 85bca3d6..7ef260bc 100644 --- a/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css +++ b/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css @@ -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);