Merge branch 'ji' into master (操作日志 Y-Log 上报)

# Conflicts:
#	CLAUDE.md
This commit is contained in:
Administrator committed 2026-06-23 19:22:53 +08:00
commit 053d3e300e
35 files changed
+1182 -125

No files matched your search

@@ -16,6 +16,7 @@ import {
import { apiFetch } from "@/core/api/fetch-client";
import { getBackendBaseURL } from "@/core/config";
import { OptType, writeYLog } from "@/core/log/y-log";
import { parseThemeMap, stringifyThemeMap } from "@/strategy-components/lib/light-app";
export type LightAppType = "window_open" | "iframe";
@@ -156,7 +157,15 @@ export async function listLightApps(params: ListLightAppsParams = {}): Promise<L
const query = qs.toString();
const res = await apiFetch(`${BASE()}${query ? `?${query}` : ""}`, { method: "GET" });
const data = await readJson<{ apps: ServerApp[] }>(res, "list light apps");
return (data.apps ?? []).map(toApp);
const apps = (data.apps ?? []).map(toApp);
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-轻应用-列表",
url: `${BASE()}${query ? `?${query}` : ""}`,
reqParam: params,
returnParam: apps,
});
return apps;
}
export async function getLightApp(appId: string): Promise<LightApp> {
@@ -170,7 +179,15 @@ export async function createLightApp(input: LightAppInput): Promise<LightApp> {
headers: { "Content-Type": "application/json" },
body: JSON.stringify(toBody(input)),
});
return toApp(await readJson<ServerApp>(res, "create light app"));
const app = toApp(await readJson<ServerApp>(res, "create light app"));
writeYLog({
optType: OptType.create,
optDetail: "B1-CM助手-轻应用-注册",
url: BASE(),
reqParam: input,
returnParam: app,
});
return app;
}
export async function updateLightApp(
@@ -182,12 +199,26 @@ export async function updateLightApp(
headers: { "Content-Type": "application/json" },
body: JSON.stringify(toBody(patch)),
});
return toApp(await readJson<ServerApp>(res, "update light app"));
const app = toApp(await readJson<ServerApp>(res, "update light app"));
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-轻应用-修改",
url: `${BASE()}/${encodeURIComponent(appId)}`,
reqParam: { appId, patch },
returnParam: app,
});
return app;
}
export async function deleteLightApp(appId: string): Promise<void> {
const res = await apiFetch(`${BASE()}/${encodeURIComponent(appId)}`, { method: "DELETE" });
await readJson<{ success: boolean }>(res, "delete light app");
writeYLog({
optType: OptType.delete,
optDetail: "B1-CM助手-轻应用-删除",
url: `${BASE()}/${encodeURIComponent(appId)}`,
reqParam: { appId },
});
}
// ── React Query hooks(管理页 / 列表页 / 侧边栏共用缓存) ───────────────────
@@ -10,6 +10,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiFetch } from "@/core/api/fetch-client";
import { getBackendBaseURL } from "@/core/config";
import { OptType, writeYLog } from "@/core/log/y-log";
import type { MenuOverride } from "@/core/page-layout/menu-overrides";
const BASE = () => `${getBackendBaseURL()}/api/menu-overrides`;
@@ -67,7 +68,15 @@ export async function replaceMenuOverrides(overrides: MenuOverride[]): Promise<M
body: JSON.stringify({ overrides: overrides.map(toBody) }),
});
const data = await readJson<{ overrides: ServerOverride[] }>(res, "save menu overrides");
return (data.overrides ?? []).map(toOverride);
const saved = (data.overrides ?? []).map(toOverride);
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-菜单管理-保存",
url: "/api/menu-overrides",
reqParam: { overrides },
returnParam: saved,
});
return saved;
}
// ── React Query hooks(侧边栏 + 管理页共用缓存) ────────────────────────────
@@ -10,6 +10,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiFetch } from "@/core/api/fetch-client";
import { getBackendBaseURL } from "@/core/config";
import { OptType, writeYLog } from "@/core/log/y-log";
const BASE = () => `${getBackendBaseURL()}/api/sensitive-words`;
@@ -71,7 +72,14 @@ async function readJson<T>(res: Response, ctx: string): Promise<T> {
export async function listSensitiveWords(): Promise<SensitiveWord[]> {
const res = await apiFetch(BASE(), { method: "GET" });
const data = await readJson<{ words: ServerWord[] }>(res, "list sensitive words");
return (data.words ?? []).map(toWord);
const words = (data.words ?? []).map(toWord);
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-敏感词管理-列表",
url: "/api/sensitive-words",
returnParam: words,
});
return words;
}
export async function replaceSensitiveWords(words: SensitiveWord[]): Promise<SensitiveWord[]> {
@@ -81,7 +89,15 @@ export async function replaceSensitiveWords(words: SensitiveWord[]): Promise<Sen
body: JSON.stringify({ words: words.map(toBody) }),
});
const data = await readJson<{ words: ServerWord[] }>(res, "save sensitive words");
return (data.words ?? []).map(toWord);
const saved = (data.words ?? []).map(toWord);
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-敏感词管理-保存",
url: "/api/sensitive-words",
reqParam: { words },
returnParam: saved,
});
return saved;
}
/** 把「启用」的词条折叠成运行时脱敏所需的 `原始词 → 替换词` 映射。 */
@@ -11,6 +11,7 @@ import { useQuery } from "@tanstack/react-query";
import { apiFetch } from "@/core/api/fetch-client";
import { getBackendBaseURL } from "@/core/config";
import { OptType, writeYLog } from "@/core/log/y-log";
const BASE = () => `${getBackendBaseURL()}/api/skill-addresses`;
@@ -197,7 +198,15 @@ export async function scanAddresses(kinds?: AddressKind[], skill?: string): Prom
if (skill) params.set("skill", skill);
const qs = params.toString();
const res = await apiFetch(`${BASE()}/scan${qs ? `?${qs}` : ""}`, { method: "GET" });
return toScanResult(await readJson<any>(res, "扫描"));
const result = toScanResult(await readJson<any>(res, "扫描"));
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-技能地址管理-扫描",
url: `${BASE()}/scan${qs ? `?${qs}` : ""}`,
reqParam: { kinds, skill },
returnParam: result,
});
return result;
}
/** 流式扫描:逐技能上报进度,返回最终聚合结果。 */
@@ -216,6 +225,13 @@ export async function scanAddressesStream(
else if (ev.type === "result") result = toScanResult(ev);
});
if (!result) throw new Error("扫描未返回结果");
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-技能地址管理-扫描",
url: `${BASE()}/scan/stream${qs ? `?${qs}` : ""}`,
reqParam: { kinds: opts.kinds, skill: opts.skill },
returnParam: result,
});
return result;
}
@@ -251,6 +267,13 @@ export async function applyReplacementsStream(
else if (ev.type === "result") result = toApplyResult(ev);
});
if (!result) throw new Error("应用未返回结果");
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-技能地址管理-应用替换",
url: `${BASE()}/apply/stream`,
reqParam: body,
returnParam: result,
});
return result;
}
@@ -269,7 +292,15 @@ export async function listBackups(): Promise<BackupEntry[]> {
export async function rollbackBackup(backupId: string): Promise<{ restored: number }> {
const res = await apiFetch(`${BASE()}/rollback/${encodeURIComponent(backupId)}`, { method: "POST" });
const data = await readJson<{ restored_files: string[] }>(res, "撤销");
return { restored: (data.restored_files ?? []).length };
const result = { restored: (data.restored_files ?? []).length };
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-技能地址管理-回退",
url: `${BASE()}/rollback/${encodeURIComponent(backupId)}`,
reqParam: { backupId },
returnParam: result,
});
return result;
}
// ── React Query ────────────────────────────────────────────────────────────
@@ -10,6 +10,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiFetch } from "@/core/api/fetch-client";
import { getBackendBaseURL } from "@/core/config";
import { OptType, writeYLog } from "@/core/log/y-log";
import type {
TaskBusiness,
TaskButton,
@@ -91,7 +92,15 @@ export async function replaceTaskButtons(buttons: TaskButton[]): Promise<TaskBut
body: JSON.stringify({ buttons: buttons.map(toBody) }),
});
const data = await readJson<{ buttons: ServerButton[] }>(res, "save task buttons");
return (data.buttons ?? []).map(toButton);
const saved = (data.buttons ?? []).map(toButton);
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-按钮管理-保存",
url: "/api/task-buttons",
reqParam: { buttons },
returnParam: saved,
});
return saved;
}
// ── React Query hooks(工作区 + 管理页共用缓存) ────────────────────────────