From 7acedfd3853e9c444c88d30072ac1c1299111553 Mon Sep 17 00:00:00 2001 From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com> Date: Tue, 9 Jun 2026 19:41:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task-components/ActionAnalyzes.tsx | 65 +++----- .../task-components/SentimentAnalyzes.tsx | 95 +++++++---- .../task-components/TaskAnalyzes.tsx | 95 ++++++++--- .../components/task-components/actionMock.ts | 130 --------------- .../components/task-components/kanbanMock.ts | 148 ------------------ 5 files changed, 157 insertions(+), 376 deletions(-) delete mode 100644 frontend-web/src/strategy-components/components/task-components/actionMock.ts delete mode 100644 frontend-web/src/strategy-components/components/task-components/kanbanMock.ts diff --git a/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx b/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx index bccf13fb..25d61dad 100644 --- a/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx @@ -8,7 +8,6 @@ import { Col, Loading, Pagination, Progress, Row } from 'tdesign-react'; import { requestCrudService } from '@/service/request-axios-service'; import { ActionColumn } from './ActionColumn'; import { resolveStatusIcon } from './icons'; -import { mockActionColumns, mockTaskList } from './actionMock'; interface ActionAnalyzesProps { TaskType?: string; @@ -70,14 +69,6 @@ export const ActionAnalyzes: React.FC = ({ title, category, await taskListSearch(); } - // 接口不可用 / 返回为空时回落到本地预览数据,方便联调看效果。 - const fallbackToMock = () => { - setTaskList(mockTaskList); - setTotal(mockTaskList.length); - setActionColumnList(mockActionColumns); - if (mockTaskList[0]) setTaskId(mockTaskList[0].id); - }; - // 任务查询 const taskListSearch = async () => { const param = { @@ -86,27 +77,19 @@ export const ActionAnalyzes: React.FC = ({ title, category, pageSize: state.current.pageSize } setTaskLoading(true); - try { - const res = await service.post(`${zncmUrl}/action/cop-action-tasks`, param); - const result: TaskListItem[] = Array.isArray(res?.data) ? res.data : []; - if (result.length === 0) { - fallbackToMock(); - return; - } - result.forEach((item: TaskListItem) => { - item.progress = item.endCount / item.sumAll || 0; // 获取已完成和未完成的占比 - item.taskStatusData = taskStatusList[item.taskStatus] // 根据任务状态码获取相关信息 - }) - setTaskList(result); // 设置任务列表页 - const totalRes = await service.post(`${zncmUrl}/action/cop-action-tasks-count`, param); // 查询任务总数 - setTotal(totalRes?.data || result.length); // 设置总数 + const res = await service.post(`${zncmUrl}/action/cop-action-tasks`, param); + setTaskLoading(false); + const result = res.data; + result.forEach((item: TaskListItem) => { + item.progress = item.endCount / item.sumAll || 0; // 获取已完成和未完成的占比 + item.taskStatusData = taskStatusList[item.taskStatus] // 根据任务状态码获取相关信息 + }) + setTaskList(result || []); // 设置任务列表页 + const totalRes = await service.post(`${zncmUrl}/action/cop-action-tasks-count`, param); // 查询任务总数 + setTotal(totalRes.data || 0); // 设置总数 + if (result.length > 0) { setTaskId(result[0].id); await actionListSearch(result[0].id); - } catch (err) { - console.warn('任务搜索失败,使用本地预览数据', err); - fallbackToMock(); - } finally { - setTaskLoading(false); } } @@ -116,23 +99,15 @@ export const ActionAnalyzes: React.FC = ({ title, category, taskId: taskId, } setActionLoading(true); - try { - const res = await service.get(`${zncmUrl}/action/cop-task-actions`, param); - const result = res?.data ?? {}; - const columns = [ - { columnName: '待分析', icon: '待CEH.svg', actionList: result.collect || [] }, - { columnName: 'CEH中', icon: '进行中.svg', actionList: result.collect1 || [] }, - { columnName: 'CEH完成', icon: '完成.svg', actionList: result.collect2 || [] }, - { columnName: '已终止', icon: '已终止.svg', actionList: result.endDate || [] }, - ]; - const hasAny = columns.some((c) => c.actionList.length > 0); - setActionColumnList(hasAny ? columns : mockActionColumns); - } catch (err) { - console.warn('行动查询失败,使用本地预览数据', err); - setActionColumnList(mockActionColumns); - } finally { - setActionLoading(false); - } + const res = await service.get(`${zncmUrl}/action/cop-task-actions`, param); + setActionLoading(false); + const result = res.data; + setActionColumnList([ + { columnName: '待分析', icon: '待CEH.svg', actionList: result.collect || [] }, + { columnName: 'CEH中', icon: '进行中.svg', actionList: result.collect1 || [] }, + { columnName: 'CEH完成', icon: '完成.svg', actionList: result.collect2 || [] }, + { columnName: '已终止', icon: '已终止.svg', actionList: result.endDate || [] }, + ]); } const taskDataChange = async (taskId: number) => { 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 41c56ceb..d7aa1d58 100644 --- a/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx @@ -1,13 +1,14 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { ArrowRight, Layers, Plus, Search, Users, X } from 'lucide-react'; +import { ArrowRight, Bot, Layers, Plus, Search, Users, X } from 'lucide-react'; import dayjs from 'dayjs'; import { DateRangePicker, DateRangePickerProps, DateRangeValue, Loading } from 'tdesign-react'; import { useNavigate } from 'react-router-dom'; import { useTheme } from '@/contexts/ThemeContext'; import { requestCrudService } from '@/service/request-axios-service'; +import { toast } from 'sonner'; import { KanbanColumn } from './KanbanColumn'; import { TaskListItem } from './TaskManagement'; -import { sentimentAnalyzeMock } from './kanbanMock'; +import { listBusinessMappings } from '@/strategy-components/api/business-mapping'; interface TaskListPageProps { title: string; @@ -25,6 +26,8 @@ type ColumnType = 'unanalyzed' | 'running' | 'completed'; const service = requestCrudService; const zncmUrl = import.meta.env.VITE_API_BASE_URL || ''; +/** 本页对应的业务码(3QFX = 3Q);用于查业务映射拿到要自动选用的业务链 / 单智能体。 */ +const BUSINESS_CODE = '3Q'; const SentimentAnalyzes: React.FC = ({ title, category, subCategory }) => { const { theme } = useTheme(); @@ -79,19 +82,6 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa await taskDataChange(); }; - const applyColumnData = (taskType: ColumnType, list: TaskListItem[], total: number) => { - if (taskType === 'unanalyzed') { - setUnanalyzedTotal(total); - setUnanalyzedList(list); - } else if (taskType === 'running') { - setRunningTotal(total); - setRunningList(list); - } else { - setCompletedTotal(total); - setCompletedList(list); - } - }; - const taskListSearch = async ( taskType: ColumnType, pageNum = 1, @@ -119,19 +109,18 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa column: taskType, taskLevel: item.taskLevel || 1, })); + const total = Number(result.total ?? normalized.length); - if (normalized.length === 0) { - // 接口无数据时回落到本地预览数据,方便联调看效果 - const mock = sentimentAnalyzeMock[taskType]; - applyColumnData(taskType, mock, mock.length); - return; + if (taskType === 'unanalyzed') { + setUnanalyzedTotal(total); + setUnanalyzedList(normalized); + } else if (taskType === 'running') { + setRunningTotal(total); + setRunningList(normalized); + } else { + setCompletedTotal(total); + setCompletedList(normalized); } - - applyColumnData(taskType, normalized, Number(result.total ?? normalized.length)); - } catch (err) { - console.warn('三情任务查询失败,使用本地预览数据', err); - const mock = sentimentAnalyzeMock[taskType]; - applyColumnData(taskType, mock, mock.length); } finally { if (taskType === 'unanalyzed') setUnanalyzedLoading(false); if (taskType === 'running') setRunningLoading(false); @@ -173,7 +162,7 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa roundtablePrefill: { taskTitle: task.taskName, taskGoal: task.overview, - businessCode: '3Q', + businessCode: BUSINESS_CODE, autoStart: true, }, }, @@ -181,6 +170,41 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa setShowAnalysisModal(false); }; + // 单智能体分析:用「业务链条管理」里为本业务配置的智能体,跳转到其问答页(新会话), + // 把任务名称/简介作为开场消息暂存,由 AgentChatPage 读取 sessionStorage.pendingAgentMessage + // 自动发出并开始问答。未配置智能体则提示去配置。 + const handleSingleAgentAnalysis = async () => { + const task = stateRef.current.task; + if (!task) return; + let agentId: string | null = null; + try { + const mappings = await listBusinessMappings(); + agentId = mappings.find((m) => m.businessCode === BUSINESS_CODE)?.agentId ?? null; + } catch { + /* ignore → 下面按未配置处理 */ + } + if (!agentId) { + toast.error('该业务尚未在「业务链条管理」中配置单智能体'); + return; + } + const text = [ + task.taskName ? `任务名称:${task.taskName}` : '', + task.overview ? `任务简介:${task.overview}` : '', + ] + .filter(Boolean) + .join('\n'); + try { + sessionStorage.setItem( + 'pendingAgentMessage', + JSON.stringify({ agentId, text }), + ); + } catch { + /* noop */ + } + navigate(`/page/strategy/agents/${agentId}/chats/new`); + setShowAnalysisModal(false); + }; + const handleKeyDown = async (event: React.KeyboardEvent) => { if ((event.metaKey || event.ctrlKey || event.shiftKey) && event.key === 'Enter') { event.preventDefault(); @@ -399,6 +423,23 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa + + diff --git a/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx b/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx index 36eb93a8..5b689846 100644 --- a/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx @@ -5,9 +5,10 @@ import dayjs from 'dayjs'; import { useNavigate } from 'react-router-dom'; import { useTheme } from '@/contexts/ThemeContext'; import { requestCrudService } from '@/service/request-axios-service'; +import { toast } from 'sonner'; import { KanbanColumn } from './KanbanColumn'; import { TaskListItem } from './TaskManagement'; -import { taskAnalyzeMock } from './kanbanMock'; +import { listBusinessMappings } from '@/strategy-components/api/business-mapping'; interface TaskListPageProps { title: string; @@ -25,6 +26,8 @@ type ColumnType = 'unanalyzed' | 'running' | 'completed'; const service = requestCrudService; const zncmUrl = import.meta.env.VITE_API_BASE_URL || ''; +/** 本页对应的业务码(任务FX = 6BF);用于查业务映射拿到要自动选用的业务链 / 单智能体。 */ +const BUSINESS_CODE = '6BF'; const TaskAnalyzes: React.FC = ({ title, category, subCategory }) => { const { theme } = useTheme(); @@ -79,19 +82,6 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor await taskDataChange(); }; - const applyColumnData = (taskType: ColumnType, list: TaskListItem[], total: number) => { - if (taskType === 'unanalyzed') { - setUnanalyzedTotal(total); - setUnanalyzedList(list); - } else if (taskType === 'running') { - setRunningTotal(total); - setRunningList(list); - } else { - setCompletedTotal(total); - setCompletedList(list); - } - }; - const taskListSearch = async ( taskType: ColumnType, pageNum = 1, @@ -119,19 +109,18 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor column: taskType, taskLevel: item.taskLevel || 1, })); + const total = Number(result.total ?? normalized.length); - if (normalized.length === 0) { - // 接口无数据时回落到本地预览数据,方便联调看效果 - const mock = taskAnalyzeMock[taskType]; - applyColumnData(taskType, mock, mock.length); - return; + if (taskType === 'unanalyzed') { + setUnanalyzedTotal(total); + setUnanalyzedList(normalized); + } else if (taskType === 'running') { + setRunningTotal(total); + setRunningList(normalized); + } else { + setCompletedTotal(total); + setCompletedList(normalized); } - - applyColumnData(taskType, normalized, Number(result.total ?? normalized.length)); - } catch (err) { - console.warn('任务查询失败,使用本地预览数据', err); - const mock = taskAnalyzeMock[taskType]; - applyColumnData(taskType, mock, mock.length); } finally { if (taskType === 'unanalyzed') setUnanalyzedLoading(false); if (taskType === 'running') setRunningLoading(false); @@ -173,7 +162,7 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor roundtablePrefill: { taskTitle: task.taskName, taskGoal: task.overview, - businessCode: '6BF', + businessCode: BUSINESS_CODE, autoStart: true, }, }, @@ -181,6 +170,41 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor setShowAnalysisModal(false); }; + // 单智能体分析:用「业务链条管理」里为本业务配置的智能体,跳转到其问答页(新会话), + // 把任务名称/简介作为开场消息暂存,由 AgentChatPage 读取 sessionStorage.pendingAgentMessage + // 自动发出并开始问答。未配置智能体则提示去配置。 + const handleSingleAgentAnalysis = async () => { + const task = stateRef.current.task; + if (!task) return; + let agentId: string | null = null; + try { + const mappings = await listBusinessMappings(); + agentId = mappings.find((m) => m.businessCode === BUSINESS_CODE)?.agentId ?? null; + } catch { + /* ignore → 下面按未配置处理 */ + } + if (!agentId) { + toast.error('该业务尚未在「业务链条管理」中配置单智能体'); + return; + } + const text = [ + task.taskName ? `任务名称:${task.taskName}` : '', + task.overview ? `任务简介:${task.overview}` : '', + ] + .filter(Boolean) + .join('\n'); + try { + sessionStorage.setItem( + 'pendingAgentMessage', + JSON.stringify({ agentId, text }), + ); + } catch { + /* noop */ + } + navigate(`/page/strategy/agents/${agentId}/chats/new`); + setShowAnalysisModal(false); + }; + const handleKeyDown = async (event: React.KeyboardEvent) => { if ((event.metaKey || event.ctrlKey || event.shiftKey) && event.key === 'Enter') { event.preventDefault(); @@ -419,6 +443,25 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor + + diff --git a/frontend-web/src/strategy-components/components/task-components/actionMock.ts b/frontend-web/src/strategy-components/components/task-components/actionMock.ts deleted file mode 100644 index a75f4055..00000000 --- a/frontend-web/src/strategy-components/components/task-components/actionMock.ts +++ /dev/null @@ -1,130 +0,0 @@ -/** - * 行动 CE 看板的本地预览数据。 - * - * 仅在接口不可用 / 返回为空时回落使用(见 ActionAnalyzes 的 catch 分支), - * 后端正常返回数据时不会用到。纯前端联调 / 演示效果用。 - */ -import { - actionColumnItem, - ActionListItem, - TaskListItem, - taskStatusList, -} from "./TaskManagement"; - -const statusMap = taskStatusList as Record; - -/** 左侧任务列表 —— 覆盖「待分析 / 分析中 / 审核通过(完成) / 审核未通过」四种状态图标。 */ -export const mockTaskList: TaskListItem[] = ( - [ - { - id: 9001, - taskName: "京津冀区域舆情联动处置专项", - taskStartDate: "2026-06-08 09:12:00", - taskStatus: 20, - endCount: 3, - sumAll: 8, - }, - { - id: 9002, - taskName: "重点人群引导策略分析", - taskStartDate: "2026-06-07 14:30:00", - taskStatus: 10, - endCount: 0, - sumAll: 5, - }, - { - id: 9003, - taskName: "阶段性成效复盘与归档", - taskStartDate: "2026-06-05 16:45:00", - taskStatus: 110, - endCount: 6, - sumAll: 6, - }, - { - id: 9004, - taskName: "审核未通过任务回溯", - taskStartDate: "2026-06-04 11:10:00", - taskStatus: 50, - endCount: 2, - sumAll: 7, - }, - ] as Array> -).map((t) => ({ - ...t, - progress: t.sumAll ? (t.endCount as number) / (t.sumAll as number) : 0, - taskStatusData: statusMap[String(t.taskStatus)], -})) as unknown as TaskListItem[]; - -function action(partial: Partial): ActionListItem { - return partial as unknown as ActionListItem; -} - -/** 右侧四栏行动 —— 列与 ActionAnalyzes 里真实构建的四栏一一对应。 */ -export const mockActionColumns: actionColumnItem[] = [ - { - columnName: "待分析", - icon: "待CEH.svg", - actionList: [ - action({ - id: 1101, - actionName: "梳理重点平台舆情数据,输出待分析清单", - level: 1, - deptName: "情报研判处", - actionStatus: 0, - }), - action({ - id: 1102, - actionName: "采集竞品动向与受众反馈样本", - level: 2, - deptName: "数据采集组", - actionStatus: 0, - }), - ], - }, - { - columnName: "CEH中", - icon: "进行中.svg", - actionList: [ - action({ - id: 1201, - actionName: "开展多智能体会商,形成初步处置共识", - level: 1, - deptName: "策略策划处", - actionStatus: 1, - }), - ], - }, - { - columnName: "CEH完成", - icon: "完成.svg", - actionList: [ - action({ - id: 1301, - actionName: "完成作战方案撰写并通过审核", - level: 1, - deptName: "指挥协调中心", - actionStatus: 1, - }), - action({ - id: 1302, - actionName: "归档阶段性成效报告并同步相关单位", - level: 2, - deptName: "综合保障组", - actionStatus: 1, - }), - ], - }, - { - columnName: "已终止", - icon: "已终止.svg", - actionList: [ - action({ - id: 1401, - actionName: "因优先级调整终止的预备行动", - level: 2, - deptName: "综合保障组", - actionStatus: 1, - }), - ], - }, -]; diff --git a/frontend-web/src/strategy-components/components/task-components/kanbanMock.ts b/frontend-web/src/strategy-components/components/task-components/kanbanMock.ts deleted file mode 100644 index 2dec3776..00000000 --- a/frontend-web/src/strategy-components/components/task-components/kanbanMock.ts +++ /dev/null @@ -1,148 +0,0 @@ -/** - * 看板(任务分析 / 三情分析)的本地预览数据。 - * - * 仅在接口不可用 / 返回为空时回落使用(见各页 taskListSearch 的空数据 / catch 分支), - * 后端正常返回数据时不会用到。纯前端联调 / 演示效果用。 - */ -import { TaskListItem } from "./TaskManagement"; - -export type KanbanColumnType = "unanalyzed" | "running" | "completed"; - -interface Seed { - taskName: string; - overview: string; - taskDirection: string; - taskType?: number; // 1单任务 2场景 3会商 4多智能体 5检索 - taskLevel?: number; // 1一般 2紧急 3加急 - createTime?: string; - updateTime?: string; -} - -function buildTask(seed: Seed, column: KanbanColumnType, id: number): TaskListItem { - return { - id, - column, - taskName: seed.taskName, - overview: seed.overview, - taskDirection: seed.taskDirection, - taskType: seed.taskType ?? 1, - taskLevel: seed.taskLevel ?? 1, - createTime: seed.createTime ?? "2026-06-08 09:30:00", - updateTime: seed.updateTime ?? "2026-06-09 10:15:00", - scene: "", - } as unknown as TaskListItem; -} - -function makeMock( - baseId: number, - seeds: Record, -): Record { - let id = baseId; - const build = (col: KanbanColumnType) => seeds[col].map((s) => buildTask(s, col, (id += 1))); - return { - unanalyzed: build("unanalyzed"), - running: build("running"), - completed: build("completed"), - }; -} - -/** 任务分析(plan-task-fx)预览数据。 */ -export const taskAnalyzeMock = makeMock(7100, { - unanalyzed: [ - { - taskName: "区域目标人群拆解专项", - overview: "对重点区域目标人群进行分层拆解,明确触达优先级与切入口。", - taskDirection: "策略策划处", - taskType: 4, - taskLevel: 2, - createTime: "2026-06-09 08:20:00", - updateTime: "2026-06-09 08:20:00", - }, - { - taskName: "竞品动向监测立项", - overview: "梳理同类项目近期动向,输出可对照的策略阻力清单。", - taskDirection: "情报研判处", - taskType: 5, - taskLevel: 1, - createTime: "2026-06-08 16:45:00", - updateTime: "2026-06-08 17:02:00", - }, - ], - running: [ - { - taskName: "阶段目标可行性会商", - overview: "多智能体围绕阶段目标的可达性与风险点开展讨论并形成初步结论。", - taskDirection: "指挥协调中心", - taskType: 3, - taskLevel: 3, - createTime: "2026-06-07 10:10:00", - updateTime: "2026-06-09 09:40:00", - }, - ], - completed: [ - { - taskName: "重点议题策略路径分析", - overview: "完成重点议题的策略路径推演,已形成可执行的行动建议。", - taskDirection: "策略策划处", - taskType: 2, - taskLevel: 1, - createTime: "2026-06-04 14:00:00", - updateTime: "2026-06-06 11:25:00", - }, - { - taskName: "受众态度归因复盘", - overview: "对上一阶段受众态度变化进行归因复盘,沉淀经验供后续复用。", - taskDirection: "综合保障组", - taskType: 1, - taskLevel: 2, - createTime: "2026-06-03 09:15:00", - updateTime: "2026-06-05 18:30:00", - }, - ], -}); - -/** 三情分析(plan-task-sentiment)预览数据。 */ -export const sentimentAnalyzeMock = makeMock(7200, { - unanalyzed: [ - { - taskName: "重点平台情绪监测专项", - overview: "采集重点平台舆论样本,识别情绪倾向与潜在风险信号。", - taskDirection: "情报研判处", - taskType: 5, - taskLevel: 2, - createTime: "2026-06-09 07:50:00", - updateTime: "2026-06-09 07:50:00", - }, - { - taskName: "舆情走势预研立项", - overview: "围绕热点事件开展舆情走势预研,输出三情研判初判结论。", - taskDirection: "策略策划处", - taskType: 1, - taskLevel: 1, - createTime: "2026-06-08 13:20:00", - updateTime: "2026-06-08 13:48:00", - }, - ], - running: [ - { - taskName: "群体情绪共识会商", - overview: "多智能体从社情、舆情、敌情多视角讨论群体情绪态势并形成共识。", - taskDirection: "指挥协调中心", - taskType: 3, - taskLevel: 3, - createTime: "2026-06-07 11:30:00", - updateTime: "2026-06-09 10:05:00", - }, - ], - completed: [ - { - taskName: "阶段性情绪研判归档", - overview: "完成阶段性三情研判,结论已通过审核并归档同步相关单位。", - taskDirection: "综合保障组", - taskType: 2, - taskLevel: 1, - createTime: "2026-06-02 15:10:00", - updateTime: "2026-06-05 16:40:00", - }, - ], -});