feat: inject 3q context into rwfx chat
This commit is contained in:
1 parent
ba0c32dcee
commit
36a3851233
7 files changed
+179
-45
No files matched your search
+7
-4
@@ -31,7 +31,10 @@ import {
|
||||
type TaskPurposeResult,
|
||||
} from "@/core/auth/task-purpose";
|
||||
import { fetchTaskIdFromAction } from "@/core/auth/task-deeplink";
|
||||
import { useRwfxSqGate } from "@/strategy-components/components/task-components/rwfx-sq-gate";
|
||||
import {
|
||||
useRwfxSqGate,
|
||||
type RwfxSqGateStartContext,
|
||||
} from "@/strategy-components/components/task-components/rwfx-sq-gate";
|
||||
import { desensitize } from "@/lib/desensitize";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -164,7 +167,7 @@ export function TaskPurposePanel({
|
||||
}: {
|
||||
taskId: string;
|
||||
/** 闸门通过(无数据 / 覆盖成功),开始问答。 */
|
||||
onStart: () => void;
|
||||
onStart: (context?: RwfxSqGateStartContext) => void;
|
||||
/** rwfx:查询任务目的为空数据时,自动开始第一次问答(跳过手动点「开始问答」)。 */
|
||||
autoStartWhenEmpty?: boolean;
|
||||
}) {
|
||||
@@ -209,7 +212,7 @@ export function TaskPurposePanel({
|
||||
|
||||
const handleStart = () => {
|
||||
if (result?.hasData) setConfirmOpen(true); // 有数据 → 先确认覆盖
|
||||
else onStart(); // 无数据 → 直接开始
|
||||
else gateStart(onStart); // 无数据 → 经过 3q 门控后开始
|
||||
};
|
||||
|
||||
const handleConfirmOverwrite = async () => {
|
||||
@@ -218,7 +221,7 @@ export function TaskPurposePanel({
|
||||
const r = await deleteTaskPurpose(taskId);
|
||||
if (r.success) {
|
||||
setConfirmOpen(false);
|
||||
onStart();
|
||||
gateStart(onStart);
|
||||
} else {
|
||||
toast.error(r.message || "无法覆盖,请稍后再试");
|
||||
setConfirmOpen(false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* rwfx(任务分析)专用「3q 预检门控」。
|
||||
*
|
||||
* 进入任务分析工作区时调研判情报报告接口(``fetchSqReportStatus``)判断 3q 是否完成:
|
||||
* 进入任务分析工作区时调研判情报报告接口(``fetchSqReportCheck``)判断 3q 是否完成:
|
||||
* - ``incomplete``(3q 未完成 / 无数据)→ 弹「3q 未完成,是否前往 3qfx」框(暂不 / 前往 3qfx)。
|
||||
* - ``complete`` / ``unknown`` → 不打扰。
|
||||
*
|
||||
@@ -37,11 +37,16 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { fetchSqReportStatus } from "@/core/auth/dashboard-input";
|
||||
import { fetchSqReportCheck } from "@/core/auth/dashboard-input";
|
||||
import { readCopTaskDetail, resolveTaskDeeplinkTarget } from "@/core/auth/task-deeplink";
|
||||
|
||||
type GateStatus = "loading" | "incomplete" | "ok";
|
||||
|
||||
export interface RwfxSqGateStartContext {
|
||||
/** 已完成的 3q 研判情报报告。只随 run context 传给模型,不在页面展示。 */
|
||||
sqReport?: unknown;
|
||||
}
|
||||
|
||||
interface RwfxSqGateValue {
|
||||
/**
|
||||
* rwfx 自动开始第一次问答的门控。
|
||||
@@ -49,7 +54,7 @@ interface RwfxSqGateValue {
|
||||
* - 3q 未完成 → 挂起 ``start``,弹「前往 3qfx」框;用户点「暂不」才 ``start()``,点「前往 3qfx」跳转并丢弃。
|
||||
* 非 rwfx / 无 Provider → 直接 ``start()``(默认值)。
|
||||
*/
|
||||
gateStart: (start: () => void) => void;
|
||||
gateStart: (start: (context?: RwfxSqGateStartContext) => void) => void;
|
||||
}
|
||||
|
||||
const RwfxSqGateContext = createContext<RwfxSqGateValue>({
|
||||
@@ -72,12 +77,19 @@ export function RwfxSqGateProvider({
|
||||
const [jumping, setJumping] = useState(false);
|
||||
|
||||
const statusRef = useRef<GateStatus>(taskId ? "loading" : "ok");
|
||||
const sqReportRef = useRef<unknown | null>(null);
|
||||
// 待触发的「开始问答」回调:3q 未完成时挂起,点「暂不」/关闭弹框后触发。
|
||||
const pendingStartRef = useRef<(() => void) | null>(null);
|
||||
const pendingStartRef = useRef<((context?: RwfxSqGateStartContext) => void) | null>(null);
|
||||
|
||||
const buildStartContext = useCallback((): RwfxSqGateStartContext | undefined => {
|
||||
const sqReport = sqReportRef.current;
|
||||
return sqReport == null ? undefined : { sqReport };
|
||||
}, []);
|
||||
|
||||
// taskId 变化:重置门控状态并预检 3q。
|
||||
useEffect(() => {
|
||||
pendingStartRef.current = null;
|
||||
sqReportRef.current = null;
|
||||
setOpen(false);
|
||||
if (!taskId) {
|
||||
statusRef.current = "ok";
|
||||
@@ -85,43 +97,44 @@ export function RwfxSqGateProvider({
|
||||
}
|
||||
statusRef.current = "loading";
|
||||
let alive = true;
|
||||
void fetchSqReportStatus(taskId).then((s) => {
|
||||
void fetchSqReportCheck(taskId).then((result) => {
|
||||
if (!alive) return;
|
||||
// complete / unknown 都按「放行」(不打扰);仅明确 incomplete 才门控。
|
||||
const next: GateStatus = s === "incomplete" ? "incomplete" : "ok";
|
||||
const next: GateStatus = result.status === "incomplete" ? "incomplete" : "ok";
|
||||
statusRef.current = next;
|
||||
sqReportRef.current = result.status === "complete" ? (result.report ?? null) : null;
|
||||
if (next === "incomplete") {
|
||||
setOpen(true); // 进入即提醒(无论是否有挂起的自动发送)
|
||||
} else if (pendingStartRef.current) {
|
||||
// 加载期间已请求自动开始 → 放行后补发。
|
||||
const start = pendingStartRef.current;
|
||||
pendingStartRef.current = null;
|
||||
start();
|
||||
start(buildStartContext());
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
alive = false;
|
||||
};
|
||||
}, [taskId]);
|
||||
}, [buildStartContext, taskId]);
|
||||
|
||||
const gateStart = useCallback((start: () => void) => {
|
||||
const gateStart = useCallback((start: (context?: RwfxSqGateStartContext) => void) => {
|
||||
const status = statusRef.current;
|
||||
if (status === "ok") {
|
||||
start();
|
||||
start(buildStartContext());
|
||||
return;
|
||||
}
|
||||
// loading / incomplete:挂起。loading 解析为 ok 时补发;incomplete 时等用户「暂不」。
|
||||
pendingStartRef.current = start;
|
||||
if (status === "incomplete") setOpen(true);
|
||||
}, []);
|
||||
}, [buildStartContext]);
|
||||
|
||||
/** 暂不(不去 3q 分析)/ 关闭弹框 → 补发挂起的「开始问答」(无则无操作)。 */
|
||||
const stayAndStart = useCallback(() => {
|
||||
setOpen(false);
|
||||
const start = pendingStartRef.current;
|
||||
pendingStartRef.current = null;
|
||||
start?.();
|
||||
}, []);
|
||||
start?.(buildStartContext());
|
||||
}, [buildStartContext]);
|
||||
|
||||
const handleGo3qfx = async () => {
|
||||
const detail = readCopTaskDetail();
|
||||
|
||||
Reference in new issue
Block a user