diff --git a/frontend-web/src/components/page-sdebar.css b/frontend-web/src/components/page-sdebar.css index 6aff6410..205eb9a1 100644 --- a/frontend-web/src/components/page-sdebar.css +++ b/frontend-web/src/components/page-sdebar.css @@ -119,7 +119,8 @@ border: 1px solid; border-color: rgba(43, 143, 254, 0.6); border-radius: 4px; - backdrop-filter: blur(2px); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); position: absolute; left: 108px; top: 0; diff --git a/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx b/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx index 7b0b81c4..7ffe0069 100644 --- a/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx +++ b/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx @@ -211,6 +211,13 @@ export const HighFidelityReport: React.FC = ({ [artifactsBySeat], ); + // 只保留「有产出文件」的席位;加载中 / 出错的席位仍保留以展示其状态。 + // 全部席位都没有文件(且都已加载完成、无错误)时,整块「生成的报告文件」隐藏。 + const seatsWithFiles = useMemo( + () => artifactsBySeat.filter((s) => s.loading || s.error || s.files.length > 0), + [artifactsBySeat], + ); + const toggleSeat = useCallback((key: string) => { setExpandedSeats((prev) => { const next = new Set(prev); @@ -424,21 +431,20 @@ export const HighFidelityReport: React.FC = ({ )} - {/* Section 3: Generated files per seat —— 点击「查看」进入沙箱分栏预览 */} -
-

- - 生成的报告文件 - - {totalFileCount} - -

+ {/* Section 3: Generated files per seat —— 点击「查看」进入沙箱分栏预览。 + 仅当存在「有产出文件 / 加载中 / 出错」的席位时才渲染;全部席位无文件则整块隐藏。 */} + {seatsWithFiles.length > 0 && ( +
+

+ + 生成的报告文件 + + {totalFileCount} + +

- {artifactsBySeat.length === 0 ? ( -

尚未初始化席位线程,无法列出文件。

- ) : (
- {artifactsBySeat.map((seat) => ( + {seatsWithFiles.map((seat) => (
{seat.displayName} @@ -501,8 +507,8 @@ export const HighFidelityReport: React.FC = ({
))}
- )} -
+
+ )} {/* Footer */}
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 d35e6690..bccf13fb 100644 --- a/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx @@ -4,9 +4,11 @@ import { Bot, ChevronRight, Download, Edit, Eye, FileText, Layers, MoreHorizonta import React, { useEffect, useRef, useState } from 'react'; import { format } from 'date-fns'; import { useNavigate } from 'react-router-dom'; -import { Col, Empty, Loading, Pagination, Progress, Row } from 'tdesign-react'; +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; @@ -68,6 +70,14 @@ 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 = { @@ -76,21 +86,27 @@ export const ActionAnalyzes: React.FC = ({ title, category, pageSize: state.current.pageSize } setTaskLoading(true); - const res = await service.post(`${zncmUrl}/action/cop-action-tasks`, param); - setTaskLoading(false); - console.log('任务搜索', res); - 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); // 查询任务总数 - console.log('totalRes', totalRes) - setTotal(totalRes.data || 0); // 设置总数 - if (result.length > 0) { + 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); // 设置总数 setTaskId(result[0].id); await actionListSearch(result[0].id); + } catch (err) { + console.warn('任务搜索失败,使用本地预览数据', err); + fallbackToMock(); + } finally { + setTaskLoading(false); } } @@ -100,16 +116,23 @@ export const ActionAnalyzes: React.FC = ({ title, category, taskId: taskId, } setActionLoading(true); - const res = await service.get(`${zncmUrl}/action/cop-task-actions`, param); - console.log('行动查询', res); - 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 || [] }, - ]); + 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 taskDataChange = async (taskId: number) => { @@ -151,7 +174,7 @@ export const ActionAnalyzes: React.FC = ({ title, category,
{item.taskName}
{format(new Date(item.taskStartDate), 'yyyy-MM-dd HH:mm:ss')}
- + {item?.taskStatusData?.label}
@@ -195,7 +218,11 @@ export const ActionAnalyzes: React.FC = ({ title, category, )) } { - actionColumnList.length === 0 && + actionColumnList.length === 0 && ( +
+ 暂无数据 +
+ ) }
diff --git a/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx b/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx index f890c9ef..9bcfc62f 100644 --- a/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx +++ b/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx @@ -4,8 +4,9 @@ import { Bot, ChevronRight, Download, Edit, Eye, FileText, Layers, MoreHorizonta import React, { useEffect, useRef, useState } from 'react'; import { format } from 'date-fns'; import { useNavigate } from 'react-router-dom'; -import { Col, Empty, Pagination, Progress, Row } from 'tdesign-react'; +import { Col, Pagination, Progress, Row } from 'tdesign-react'; import { requestCrudService } from '@/service/request-axios-service'; +import { resolveStatusIcon } from './icons'; interface ActionColumnProps { TaskType?: string; @@ -66,7 +67,7 @@ export const ActionColumn: React.FC = ({ title, category, sub
- + {columnName} {actionCount}
@@ -99,13 +100,11 @@ export const ActionColumn: React.FC = ({ title, category, sub )) } { - actionList.length === 0 && - } /> + actionList.length === 0 && ( +
+ 暂无数据 +
+ ) }
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 c4297e29..b220f695 100644 --- a/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx @@ -236,9 +236,6 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor
-
- -

{title} diff --git a/frontend-web/src/strategy-components/components/task-components/actionMock.ts b/frontend-web/src/strategy-components/components/task-components/actionMock.ts new file mode 100644 index 00000000..a75f4055 --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/actionMock.ts @@ -0,0 +1,130 @@ +/** + * 行动 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/icons/index.ts b/frontend-web/src/strategy-components/components/task-components/icons/index.ts new file mode 100644 index 00000000..a1adb766 --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/icons/index.ts @@ -0,0 +1,30 @@ +/** + * 行动 / 任务状态图标。 + * + * 用 `import` 引入 SVG,让 Vite 把它们打进产物并生成带 hash 的最终 URL, + * 这样无论部署到子路径(base)还是带指纹的静态资源服务都能正确访问 —— + * 不能再用 `/icon/xxx.svg` 这种运行时绝对路径(部署后会 404)。 + * + * key 沿用后端 / taskStatusList 里给的中文文件名,方便按名取用。 + */ +import daiQianShou from "./待签收.svg"; +import daiCEH from "./待CEH.svg"; +import jinXingZhong from "./进行中.svg"; +import wanCheng from "./完成.svg"; +import weiTongGuo from "./未通过.svg"; +import yiZhongZhi from "./已终止.svg"; + +export const statusIconMap: Record = { + "待签收.svg": daiQianShou, + "待CEH.svg": daiCEH, + "进行中.svg": jinXingZhong, + "完成.svg": wanCheng, + "未通过.svg": weiTongGuo, + "已终止.svg": yiZhongZhi, +}; + +/** 按文件名取打包后的图标 URL;取不到返回 undefined( 不渲染 broken icon)。 */ +export function resolveStatusIcon(name?: string | null): string | undefined { + if (!name) return undefined; + return statusIconMap[name]; +} diff --git a/frontend-web/src/strategy-components/components/task-components/icons/完成.svg b/frontend-web/src/strategy-components/components/task-components/icons/完成.svg new file mode 100644 index 00000000..a05e3a40 --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/icons/完成.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend-web/src/strategy-components/components/task-components/icons/已终止.svg b/frontend-web/src/strategy-components/components/task-components/icons/已终止.svg new file mode 100644 index 00000000..6324baa5 --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/icons/已终止.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend-web/src/strategy-components/components/task-components/icons/待CEH.svg b/frontend-web/src/strategy-components/components/task-components/icons/待CEH.svg new file mode 100644 index 00000000..d832a6cc --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/icons/待CEH.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend-web/src/strategy-components/components/task-components/icons/待签收.svg b/frontend-web/src/strategy-components/components/task-components/icons/待签收.svg new file mode 100644 index 00000000..ce2b1dc6 --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/icons/待签收.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend-web/src/strategy-components/components/task-components/icons/未通过.svg b/frontend-web/src/strategy-components/components/task-components/icons/未通过.svg new file mode 100644 index 00000000..0310b3a2 --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/icons/未通过.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend-web/src/strategy-components/components/task-components/icons/进行中.svg b/frontend-web/src/strategy-components/components/task-components/icons/进行中.svg new file mode 100644 index 00000000..fdecefde --- /dev/null +++ b/frontend-web/src/strategy-components/components/task-components/icons/进行中.svg @@ -0,0 +1,4 @@ + + + + diff --git a/offline-backend-20260512/backend/config.yaml b/offline-backend-20260512/backend/config.yaml index 152ebfb2..d95031b0 100644 --- a/offline-backend-20260512/backend/config.yaml +++ b/offline-backend-20260512/backend/config.yaml @@ -14,7 +14,7 @@ models: display_name: DeepSeek Chat use: langchain_openai:ChatOpenAI model: deepseek-chat - api_key: sk-e1c22b7931dc446f8b67e57878edd105 + api_key: sk-3fee562f834a4c08bb0d471ef44cb445 base_url: https://api.deepseek.com request_timeout: 600.0 max_retries: 2 @@ -27,7 +27,7 @@ models: display_name: DeepSeek V4 Flash use: langchain_openai:ChatOpenAI model: deepseek-v4-flash - api_key: sk-e1c22b7931dc446f8b67e57878edd105 + api_key: sk-3fee562f834a4c08bb0d471ef44cb445 base_url: https://api.deepseek.com request_timeout: 600.0 max_retries: 2