代码提交
This commit is contained in:
1 parent
27e6b0b23e
commit
d7ad0624b7
36 files changed
+2194
-287
No files matched your search
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 按任务保存的研判情报报告详情。
|
||||
*
|
||||
* 后端 `/api/task-reports/by-task/{taskId}` 返回的外壳和原 Consumer
|
||||
* `selectSqReport` 完全一致:`{ state, msg, data }`。其中 `contentJson`
|
||||
* 保持为 JSON 字符串,由使用方按 `categoryType` 反序列化。
|
||||
*/
|
||||
|
||||
import { apiFetch } from "@/core/api/fetch-client";
|
||||
import { getBackendBaseURL } from "@/core/config";
|
||||
|
||||
export type TaskReportTaskId = string | number;
|
||||
|
||||
export interface TaskReportRecord {
|
||||
id: string;
|
||||
taskId: TaskReportTaskId;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
sessionId: string;
|
||||
contentJson: string;
|
||||
categoryType: string;
|
||||
}
|
||||
|
||||
export interface TaskReportResponse {
|
||||
state: string;
|
||||
msg: string;
|
||||
data: TaskReportRecord[];
|
||||
}
|
||||
|
||||
/** 保存/修改时可省略由后端生成或维护的 id、创建/更新时间。 */
|
||||
export type TaskReportRecordDraft = Omit<
|
||||
TaskReportRecord,
|
||||
"id" | "taskId" | "createTime" | "updateTime"
|
||||
> &
|
||||
Partial<Pick<TaskReportRecord, "id" | "taskId" | "createTime" | "updateTime">>;
|
||||
|
||||
const BASE = () => `${getBackendBaseURL()}/api/task-reports/by-task`;
|
||||
|
||||
function endpoint(taskId: TaskReportTaskId) {
|
||||
return `${BASE()}/${encodeURIComponent(String(taskId))}`;
|
||||
}
|
||||
|
||||
async function readResponse(res: Response, context: string): Promise<TaskReportResponse> {
|
||||
const body = (await res.json().catch(() => null)) as TaskReportResponse | { detail?: unknown } | null;
|
||||
if (!res.ok) {
|
||||
const detail = body && typeof body === "object" && "detail" in body ? String(body.detail) : "";
|
||||
throw new Error(detail || `${context} failed (${res.status})`);
|
||||
}
|
||||
if (!body || !Array.isArray((body as TaskReportResponse).data)) {
|
||||
throw new Error(`${context} returned an invalid report payload`);
|
||||
}
|
||||
return body as TaskReportResponse;
|
||||
}
|
||||
|
||||
/** 查询任务详情;尚未保存时后端返回 `{ state: "200", data: [] }`。 */
|
||||
export async function getTaskReport(taskId: TaskReportTaskId): Promise<TaskReportResponse> {
|
||||
const res = await apiFetch(endpoint(taskId), { method: "GET" });
|
||||
return readResponse(res, "get task report");
|
||||
}
|
||||
|
||||
/** 首次保存一个任务的完整 `data` 数组。任务已有详情时会返回 409。 */
|
||||
export async function saveTaskReport(
|
||||
taskId: TaskReportTaskId,
|
||||
data: TaskReportRecordDraft[],
|
||||
): Promise<TaskReportResponse> {
|
||||
const res = await apiFetch(endpoint(taskId), {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ data }),
|
||||
});
|
||||
return readResponse(res, "save task report");
|
||||
}
|
||||
|
||||
/** 修改一个任务的完整 `data` 数组。保留同 id 项的原始 createTime。 */
|
||||
export async function updateTaskReport(
|
||||
taskId: TaskReportTaskId,
|
||||
data: TaskReportRecordDraft[],
|
||||
): Promise<TaskReportResponse> {
|
||||
const res = await apiFetch(endpoint(taskId), {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ data }),
|
||||
});
|
||||
return readResponse(res, "update task report");
|
||||
}
|
||||
+48
-44
@@ -1,63 +1,67 @@
|
||||
import sqReportMock from './sq-report-mock.json';
|
||||
import sqReportMock from "./sq-report-mock.json";
|
||||
|
||||
/**
|
||||
* 「研判情报报告」接口 `/cop/selectSqReport` 的假数据 —— 给「大屏绘制智能体」独立页面
|
||||
* (深链 `?taskId=` 模式)在真实接口未就绪时本地预览。
|
||||
* 研判情报报告的契约样例。
|
||||
*
|
||||
* 真实接口(GET `{VITE_AIPI_CONSUMER_URL}/cop/selectSqReport?taskId=`)返回结构:
|
||||
* `{ state, msg, data: [{ id, taskId, createTime, updateTime, sessionId, contentJson, categoryType }] }`
|
||||
* 其中 `contentJson` 是**被转义的 JSON 字符串**,`categoryType` 形如「敌情关键事件 JSON」。
|
||||
* 假数据 `sq-report-mock.json` 即后端给出的样例响应(taskId=3332),原样保留 contentJson 字符串。
|
||||
*
|
||||
* 启停由环境变量 `VITE_MOCK_SQ_REPORT` 控制(见 `utils/request.ts` 请求拦截器):
|
||||
* - `VITE_MOCK_SQ_REPORT=true`(默认,.env.development) → 走本地假数据;
|
||||
* - `VITE_MOCK_SQ_REPORT=false`(.env.production / .env.network / .env.sit) → 走真实接口。
|
||||
* 与 `VITE_MOCK_COP_TASK_DETAIL`(cop-task-detail)独立,机制完全一致。
|
||||
* ⚠️ 真实接口联调通过后删除本 mock 及其引用。
|
||||
* `sq-report-mock.json` 是外部系统提供的真实字段格式,保留在仓库中供接口联调、
|
||||
* 手工保存测试和解析器测试使用。运行时不再将它注入请求;大屏与 rwfx 检查统一通过
|
||||
* `/api/task-reports/by-task/{taskId}` 读取数据库保存的数据。
|
||||
*/
|
||||
|
||||
/** 命中本 mock 的接口路径。 */
|
||||
export const SQ_REPORT_ROUTE = '/cop/selectSqReport';
|
||||
export interface SqReportMockItem {
|
||||
id: string;
|
||||
taskId: string | number;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
sessionId: string;
|
||||
contentJson: string;
|
||||
categoryType: string;
|
||||
}
|
||||
|
||||
/** 判断某请求 url 是否是 selectSqReport。 */
|
||||
export const SQ_REPORT_MOCK_RESPONSE = sqReportMock as {
|
||||
state: string;
|
||||
msg: string;
|
||||
data: SqReportMockItem[];
|
||||
};
|
||||
|
||||
/** 大屏 mock 命中的真实接口路径。 */
|
||||
export const SQ_REPORT_ROUTE = "/cop/selectSqReport";
|
||||
|
||||
/** 供 axios 请求拦截器判断是否需要注入大屏样例数据。 */
|
||||
export function matchSqReportMock(url?: string): boolean {
|
||||
return !!url && url.includes(SQ_REPORT_ROUTE);
|
||||
return Boolean(url?.includes(SQ_REPORT_ROUTE));
|
||||
}
|
||||
|
||||
/** 从 axios config 取 taskId(优先 params,其次 url query)。 */
|
||||
function readTaskIdFromConfig(config: { url?: string; params?: Record<string, unknown> }): string {
|
||||
function readTaskId(config: { url?: string; params?: Record<string, unknown> }): string {
|
||||
const fromParams = config.params?.taskId;
|
||||
if (fromParams != null && fromParams !== '') return String(fromParams);
|
||||
if (config.url) {
|
||||
const m = config.url.match(/[?&]taskId=([^&]+)/);
|
||||
if (m) return decodeURIComponent(m[1]);
|
||||
}
|
||||
return '';
|
||||
if (fromParams != null && fromParams !== "") return String(fromParams);
|
||||
const matched = config.url?.match(/[?&]taskId=([^&]+)/);
|
||||
return matched ? decodeURIComponent(matched[1]) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟 selectSqReport 的 body:返回后端给的样例响应,并把 data 里每条的 taskId 改成
|
||||
* 当前请求的 taskId(让任意 taskId 进来都能看到这份演示报告)。
|
||||
* 以真实 selectSqReport 的响应结构返回样例数据;请求 taskId 会写回每条记录,
|
||||
* 让任意深链(例如 demo1)都能加载同一套可解析的大屏数据。
|
||||
*/
|
||||
function buildSqReportBody(taskId: string) {
|
||||
const tid = taskId || String((sqReportMock as { data?: Array<{ taskId?: unknown }> }).data?.[0]?.taskId ?? '');
|
||||
const src = sqReportMock as { state: string; msg: string; data: Array<Record<string, unknown>> };
|
||||
return {
|
||||
state: src.state,
|
||||
msg: src.msg,
|
||||
data: (src.data ?? []).map((item) => ({ ...item, taskId: tid })),
|
||||
};
|
||||
}
|
||||
|
||||
/** 临时假数据 axios adapter:命中 selectSqReport 时直接返回 mock body,不发真实请求。 */
|
||||
export function sqReportMockAdapter(config: {
|
||||
url?: string;
|
||||
params?: Record<string, unknown>;
|
||||
}): Promise<{ data: unknown; status: number; statusText: string; headers: Record<string, unknown>; config: unknown }> {
|
||||
const body = buildSqReportBody(readTaskIdFromConfig(config));
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({ data: body, status: 200, statusText: 'OK', headers: {}, config });
|
||||
}, 220);
|
||||
}): Promise<{
|
||||
data: typeof SQ_REPORT_MOCK_RESPONSE;
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers: Record<string, unknown>;
|
||||
config: unknown;
|
||||
}> {
|
||||
const taskId = readTaskId(config);
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
...SQ_REPORT_MOCK_RESPONSE,
|
||||
data: SQ_REPORT_MOCK_RESPONSE.data.map((item) => ({ ...item, taskId: taskId || item.taskId })),
|
||||
},
|
||||
status: 200,
|
||||
statusText: "OK",
|
||||
headers: {},
|
||||
config,
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user