|
|
|
|
@@ -59,6 +59,9 @@ const appState = {
|
|
|
|
|
userCurrentPlatformPolicy: null,
|
|
|
|
|
adminSystemMainPolicy: null,
|
|
|
|
|
adminSystemPlatformPolicies: [],
|
|
|
|
|
adminGovernanceDirectory: null,
|
|
|
|
|
adminOverrideTarget: null,
|
|
|
|
|
adminOverridePolicy: null,
|
|
|
|
|
tenantQuota: null,
|
|
|
|
|
tenantUsage: null,
|
|
|
|
|
adminOpsOverview: null,
|
|
|
|
|
@@ -1261,6 +1264,9 @@ async function logoutSession() {
|
|
|
|
|
appState.userCurrentPlatformPolicy = null;
|
|
|
|
|
appState.adminSystemMainPolicy = null;
|
|
|
|
|
appState.adminSystemPlatformPolicies = [];
|
|
|
|
|
appState.adminGovernanceDirectory = null;
|
|
|
|
|
appState.adminOverrideTarget = null;
|
|
|
|
|
appState.adminOverridePolicy = null;
|
|
|
|
|
appState.tenantQuota = null;
|
|
|
|
|
appState.tenantUsage = null;
|
|
|
|
|
appState.adminOpsOverview = null;
|
|
|
|
|
@@ -1312,12 +1318,14 @@ async function loadAgentControlSurfaces(projectId = "") {
|
|
|
|
|
const supportsUserPlatformPolicy = backendSupports("/v2/oneliner/governance/user/platforms/{platform}");
|
|
|
|
|
const supportsAdminSystemMainPolicy = backendSupports("/v2/admin/oneliner/governance/system/main-agent");
|
|
|
|
|
const supportsAdminSystemPlatformPolicy = backendSupports("/v2/admin/oneliner/governance/system/platforms/{platform}");
|
|
|
|
|
const supportsAdminGovernanceDirectory = backendSupports("/v2/admin/oneliner/governance/directory");
|
|
|
|
|
const supportsAdminOverridePolicy = backendSupports("/v2/admin/oneliner/governance/overrides");
|
|
|
|
|
const supportsAdminOps = backendSupports("/v2/admin/ops/overview");
|
|
|
|
|
const supportsAdminFixRuns = backendSupports("/v2/admin/ops/fix-runs");
|
|
|
|
|
const supportsTenantQuota = backendSupports("/v2/tenant/quota");
|
|
|
|
|
const supportsTenantUsage = backendSupports("/v2/tenant/usage");
|
|
|
|
|
|
|
|
|
|
const [profile, sessionsPayload, actionRegistryPayload, platformAgentsPayload, governanceEffective, userGlobalPolicy, userCurrentPlatformPolicy, adminSystemMainPolicy, adminSystemPlatformPolicies, tenantQuota, tenantUsage, adminOpsOverview, adminFixRunsPayload] = await Promise.all([
|
|
|
|
|
const [profile, sessionsPayload, actionRegistryPayload, platformAgentsPayload, governanceEffective, userGlobalPolicy, userCurrentPlatformPolicy, adminSystemMainPolicy, adminSystemPlatformPolicies, adminGovernanceDirectory, tenantQuota, tenantUsage, adminOpsOverview, adminFixRunsPayload] = await Promise.all([
|
|
|
|
|
supportsOneLinerProfile
|
|
|
|
|
? storyforgeFetch(`/v2/oneliner/profile?project_id=${encodeURIComponent(normalizedProjectId)}`).catch(() => null)
|
|
|
|
|
: Promise.resolve(null),
|
|
|
|
|
@@ -1347,6 +1355,9 @@ async function loadAgentControlSurfaces(projectId = "") {
|
|
|
|
|
storyforgeFetch(`/v2/admin/oneliner/governance/system/platforms/${encodeURIComponent(item.value)}`).catch(() => null)
|
|
|
|
|
))
|
|
|
|
|
: Promise.resolve([]),
|
|
|
|
|
supportsAdminGovernanceDirectory && isSuperAdmin()
|
|
|
|
|
? storyforgeFetch("/v2/admin/oneliner/governance/directory").catch(() => ({ items: [] }))
|
|
|
|
|
: Promise.resolve({ items: [] }),
|
|
|
|
|
supportsTenantQuota
|
|
|
|
|
? storyforgeFetch(`/v2/tenant/quota?project_id=${encodeURIComponent(normalizedProjectId)}`).catch(() => null)
|
|
|
|
|
: Promise.resolve(null),
|
|
|
|
|
@@ -1373,6 +1384,24 @@ async function loadAgentControlSurfaces(projectId = "") {
|
|
|
|
|
appState.userCurrentPlatformPolicy = userCurrentPlatformPolicy;
|
|
|
|
|
appState.adminSystemMainPolicy = adminSystemMainPolicy;
|
|
|
|
|
appState.adminSystemPlatformPolicies = safeArray(adminSystemPlatformPolicies);
|
|
|
|
|
appState.adminGovernanceDirectory = safeArray(adminGovernanceDirectory?.items || adminGovernanceDirectory);
|
|
|
|
|
if (isSuperAdmin() && supportsAdminOverridePolicy && appState.adminGovernanceDirectory.length) {
|
|
|
|
|
const existingTarget = appState.adminOverrideTarget || {};
|
|
|
|
|
const targetUserId = String(existingTarget.targetUserId || existingTarget.target_user_id || appState.adminGovernanceDirectory[0]?.id || "");
|
|
|
|
|
const targetUser = appState.adminGovernanceDirectory.find((item) => item.id === targetUserId) || appState.adminGovernanceDirectory[0] || null;
|
|
|
|
|
const targetProjects = safeArray(targetUser?.projects);
|
|
|
|
|
const targetProjectId = String(existingTarget.targetProjectId || existingTarget.target_project_id || targetProjects[0]?.id || "");
|
|
|
|
|
const targetPlatform = normalizePlatformValue(existingTarget.platform || governancePlatform, "douyin");
|
|
|
|
|
appState.adminOverrideTarget = {
|
|
|
|
|
targetUserId,
|
|
|
|
|
targetProjectId,
|
|
|
|
|
platform: targetPlatform
|
|
|
|
|
};
|
|
|
|
|
appState.adminOverridePolicy = await storyforgeFetch(`/v2/admin/oneliner/governance/overrides?target_user_id=${encodeURIComponent(targetUserId)}&target_project_id=${encodeURIComponent(targetProjectId)}&platform=${encodeURIComponent(targetPlatform)}`).catch(() => null);
|
|
|
|
|
} else {
|
|
|
|
|
appState.adminOverrideTarget = null;
|
|
|
|
|
appState.adminOverridePolicy = null;
|
|
|
|
|
}
|
|
|
|
|
appState.tenantQuota = tenantQuota;
|
|
|
|
|
appState.tenantUsage = tenantUsage;
|
|
|
|
|
appState.adminOpsOverview = adminOpsOverview;
|
|
|
|
|
@@ -3203,9 +3232,86 @@ function summarizePolicyHighlights(policy = {}, platform = "") {
|
|
|
|
|
return items.slice(0, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderGovernanceSummaryCard({ title, subtitle, effective, primaryAction = "", primaryLabel = "编辑策略", secondaryAction = "", secondaryLabel = "", secondaryPlatform = "" }) {
|
|
|
|
|
function getGovernanceDirectoryItems() {
|
|
|
|
|
return safeArray(appState.adminGovernanceDirectory?.items || appState.adminGovernanceDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parseAdminOverrideScopeValue(value) {
|
|
|
|
|
const normalized = String(value || "").trim();
|
|
|
|
|
if (!normalized) return { targetUserId: "", targetProjectId: "" };
|
|
|
|
|
if (normalized.startsWith("project:")) {
|
|
|
|
|
const parts = normalized.slice("project:".length).split("|");
|
|
|
|
|
return { targetUserId: parts[0] || "", targetProjectId: parts[1] || "" };
|
|
|
|
|
}
|
|
|
|
|
if (normalized.startsWith("user:")) {
|
|
|
|
|
return { targetUserId: normalized.slice("user:".length), targetProjectId: "" };
|
|
|
|
|
}
|
|
|
|
|
return { targetUserId: normalized, targetProjectId: "" };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAdminOverrideTargetOptions(directoryItems = getGovernanceDirectoryItems()) {
|
|
|
|
|
return safeArray(directoryItems).flatMap((account) => {
|
|
|
|
|
const accountLabel = account.display_name || account.username || account.id;
|
|
|
|
|
const projects = safeArray(account.projects);
|
|
|
|
|
return [
|
|
|
|
|
{ value: `user:${account.id}`, label: `${accountLabel} · 全部项目` },
|
|
|
|
|
...projects.map((project) => ({
|
|
|
|
|
value: `project:${account.id}|${project.id}`,
|
|
|
|
|
label: `${accountLabel} / ${project.name || project.id}`
|
|
|
|
|
}))
|
|
|
|
|
];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeAdminOverrideTarget(target, directoryItems = getGovernanceDirectoryItems(), fallbackPlatform = "") {
|
|
|
|
|
const items = safeArray(directoryItems);
|
|
|
|
|
if (!items.length) {
|
|
|
|
|
return { targetUserId: "", targetProjectId: "", platform: normalizePlatformValue(fallbackPlatform, "douyin") };
|
|
|
|
|
}
|
|
|
|
|
const preferred = target && target.targetUserId
|
|
|
|
|
? items.find((item) => item.id === target.targetUserId)
|
|
|
|
|
: items.find((item) => item.role !== "super_admin") || items[0];
|
|
|
|
|
const preferredProjects = safeArray(preferred?.projects);
|
|
|
|
|
const project =
|
|
|
|
|
target?.targetProjectId
|
|
|
|
|
? preferredProjects.find((item) => item.id === target.targetProjectId)
|
|
|
|
|
: preferredProjects[0] || null;
|
|
|
|
|
return {
|
|
|
|
|
targetUserId: preferred?.id || "",
|
|
|
|
|
targetProjectId: project?.id || "",
|
|
|
|
|
platform: target?.platform === "" ? "" : normalizePlatformValue(target?.platform || fallbackPlatform, "douyin")
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findGovernanceDirectoryAccount(userId) {
|
|
|
|
|
return getGovernanceDirectoryItems().find((item) => item.id === userId) || null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findGovernanceDirectoryProject(userId, projectId) {
|
|
|
|
|
const account = findGovernanceDirectoryAccount(userId);
|
|
|
|
|
return safeArray(account?.projects).find((item) => item.id === projectId) || null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAdminOverrideTargetSummary(target = appState.adminOverrideTarget) {
|
|
|
|
|
const normalized = target || {};
|
|
|
|
|
const account = findGovernanceDirectoryAccount(normalized.targetUserId || "");
|
|
|
|
|
const project = normalized.targetProjectId ? findGovernanceDirectoryProject(normalized.targetUserId || "", normalized.targetProjectId) : null;
|
|
|
|
|
return {
|
|
|
|
|
account,
|
|
|
|
|
project,
|
|
|
|
|
accountLabel: account?.display_name || account?.username || normalized.targetUserId || "未选择用户",
|
|
|
|
|
projectLabel: project?.name || (normalized.targetProjectId ? normalized.targetProjectId : "全部项目"),
|
|
|
|
|
platformLabel: normalized.platform ? platformLabel(normalized.platform) : "全部平台"
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderGovernanceSummaryCard({ title, subtitle, effective, primaryAction = "", primaryLabel = "编辑策略", secondaryAction = "", secondaryLabel = "", secondaryPlatform = "", actions = null }) {
|
|
|
|
|
const layers = safeArray(effective?.layers);
|
|
|
|
|
const highlights = summarizePolicyHighlights(effective?.effective_policy || {}, effective?.platform || secondaryPlatform || "");
|
|
|
|
|
const resolvedActions = safeArray(actions?.length ? actions : [
|
|
|
|
|
primaryAction ? { action: primaryAction, label: primaryLabel } : null,
|
|
|
|
|
secondaryAction ? { action: secondaryAction, label: secondaryLabel, platform: secondaryPlatform } : null
|
|
|
|
|
].filter(Boolean));
|
|
|
|
|
return `
|
|
|
|
|
<div class="task-item compact">
|
|
|
|
|
<h4>${escapeHtml(title)}</h4>
|
|
|
|
|
@@ -3214,10 +3320,13 @@ function renderGovernanceSummaryCard({ title, subtitle, effective, primaryAction
|
|
|
|
|
${layers.map((layer) => `<span class="tag ${layer.scope_kind === "admin_override" ? "orange" : "blue"}">${escapeHtml(policyScopeTagLabel(layer.scope_kind, layer.scope?.platform || effective?.platform || ""))}</span>`).join("") || `<span class="tag">尚未发布</span>`}
|
|
|
|
|
${highlights.map((item) => `<span class="tag green">${escapeHtml(item)}</span>`).join("")}
|
|
|
|
|
</div>
|
|
|
|
|
${(primaryAction || secondaryAction) ? `
|
|
|
|
|
${resolvedActions.length ? `
|
|
|
|
|
<div class="task-meta" style="margin-top:10px;">
|
|
|
|
|
${primaryAction ? `<span class="tag clickable-tag" data-action="${escapeHtml(primaryAction)}">${escapeHtml(primaryLabel)}</span>` : ""}
|
|
|
|
|
${secondaryAction ? `<span class="tag clickable-tag" data-action="${escapeHtml(secondaryAction)}" ${secondaryPlatform ? `data-platform="${escapeHtml(secondaryPlatform)}"` : ""}>${escapeHtml(secondaryLabel)}</span>` : ""}
|
|
|
|
|
${resolvedActions.map((item) => `
|
|
|
|
|
<span class="tag clickable-tag" data-action="${escapeHtml(item.action || "")}" ${item.platform ? `data-platform="${escapeHtml(item.platform)}"` : ""}>
|
|
|
|
|
${escapeHtml(item.label || "查看")}
|
|
|
|
|
</span>
|
|
|
|
|
`).join("")}
|
|
|
|
|
</div>
|
|
|
|
|
` : ""}
|
|
|
|
|
</div>
|
|
|
|
|
@@ -3228,6 +3337,8 @@ function renderAdminGovernanceSummaryPanel() {
|
|
|
|
|
const systemMain = appState.adminSystemMainPolicy;
|
|
|
|
|
const systemPlatforms = safeArray(appState.adminSystemPlatformPolicies);
|
|
|
|
|
const configuredPlatforms = systemPlatforms.filter((item) => item?.current_version);
|
|
|
|
|
const targetSummary = getAdminOverrideTargetSummary();
|
|
|
|
|
const overrideBundle = appState.adminOverridePolicy;
|
|
|
|
|
return `
|
|
|
|
|
<div class="panel pad" style="box-shadow:none; margin-bottom:18px;">
|
|
|
|
|
<div class="panel-head">
|
|
|
|
|
@@ -3248,6 +3359,20 @@ function renderAdminGovernanceSummaryPanel() {
|
|
|
|
|
<div class="entity-meta">
|
|
|
|
|
<span class="tag ${systemMain?.current_version ? "green" : "orange"}">${escapeHtml(systemMain?.current_version ? `版本 ${formatNumber(systemMain.current_version.version_no)}` : "未发布")}</span>
|
|
|
|
|
<span class="tag">历史 ${escapeHtml(formatNumber(systemMain?.versions?.count || 0))}</span>
|
|
|
|
|
<span class="tag clickable-tag" data-action="open-system-main-policy-history">历史与回滚</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="entity-card pad">
|
|
|
|
|
<div class="cell-title">管理员覆盖</div>
|
|
|
|
|
<div class="cell-desc">${escapeHtml(overrideBundle?.current_version?.summary || `${targetSummary.accountLabel} / ${targetSummary.projectLabel} / ${targetSummary.platformLabel}`)}</div>
|
|
|
|
|
<div class="entity-meta">
|
|
|
|
|
<span class="tag blue">${escapeHtml(targetSummary.accountLabel)}</span>
|
|
|
|
|
<span class="tag">${escapeHtml(targetSummary.projectLabel)}</span>
|
|
|
|
|
<span class="tag">${escapeHtml(targetSummary.platformLabel)}</span>
|
|
|
|
|
<span class="tag ${overrideBundle?.current_version ? "orange" : "blue"}">${escapeHtml(overrideBundle?.current_version ? `版本 ${formatNumber(overrideBundle.current_version.version_no)}` : "未发布")}</span>
|
|
|
|
|
<span class="tag clickable-tag" data-action="open-admin-override-target">切换目标</span>
|
|
|
|
|
<span class="tag clickable-tag" data-action="open-admin-override-policy">编辑覆盖</span>
|
|
|
|
|
<span class="tag clickable-tag" data-action="open-admin-override-history">历史与回滚</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
${ACTIVE_PLATFORMS.map((platformItem) => {
|
|
|
|
|
@@ -3260,6 +3385,7 @@ function renderAdminGovernanceSummaryPanel() {
|
|
|
|
|
<span class="tag ${item?.current_version ? "green" : "blue"}">${escapeHtml(item?.current_version ? `版本 ${formatNumber(item.current_version.version_no)}` : "沿用系统默认")}</span>
|
|
|
|
|
<span class="tag">历史 ${escapeHtml(formatNumber(item?.versions?.count || 0))}</span>
|
|
|
|
|
<span class="tag clickable-tag" data-action="open-system-platform-policy" data-platform="${escapeHtml(platformItem.value)}">编辑</span>
|
|
|
|
|
<span class="tag clickable-tag" data-action="open-system-platform-policy-history" data-platform="${escapeHtml(platformItem.value)}">历史与回滚</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
@@ -4755,11 +4881,26 @@ function renderPlaybookScreen() {
|
|
|
|
|
title: "我的策略与历史",
|
|
|
|
|
subtitle: appState.userGlobalPolicy?.current_version?.summary || "你和主 Agent 的策略对话,会先沉淀成用户全局策略,再按需要下放到单平台。",
|
|
|
|
|
effective: appState.onelinerGovernanceEffective,
|
|
|
|
|
primaryAction: "open-user-global-policy",
|
|
|
|
|
primaryLabel: `编辑全局策略 · 历史 ${formatNumber(appState.userGlobalPolicy?.versions?.count || 0)}`,
|
|
|
|
|
secondaryAction: "open-user-platform-policy",
|
|
|
|
|
secondaryLabel: `编辑当前平台策略 · 历史 ${formatNumber(appState.userCurrentPlatformPolicy?.versions?.count || 0)}`,
|
|
|
|
|
secondaryPlatform: appState.onelinerGovernanceEffective?.platform || appState.onelinerProfile?.default_platform || getPreferredPlatform()
|
|
|
|
|
actions: [
|
|
|
|
|
{
|
|
|
|
|
action: "open-user-global-policy",
|
|
|
|
|
label: `编辑全局策略 · 历史 ${formatNumber(appState.userGlobalPolicy?.versions?.count || 0)}`
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
action: "open-user-global-policy-history",
|
|
|
|
|
label: "查看全局历史"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
action: "open-user-platform-policy",
|
|
|
|
|
label: `编辑当前平台策略 · 历史 ${formatNumber(appState.userCurrentPlatformPolicy?.versions?.count || 0)}`,
|
|
|
|
|
platform: appState.onelinerGovernanceEffective?.platform || appState.onelinerProfile?.default_platform || getPreferredPlatform()
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
action: "open-user-platform-policy-history",
|
|
|
|
|
label: "查看当前平台历史",
|
|
|
|
|
platform: appState.onelinerGovernanceEffective?.platform || appState.onelinerProfile?.default_platform || getPreferredPlatform()
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="panel pad" style="box-shadow:none; margin-top:18px;">
|
|
|
|
|
@@ -6409,6 +6550,82 @@ function renderPolicyVersionSummary(bundle, emptyText) {
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAdminGovernanceDirectoryItems() {
|
|
|
|
|
return safeArray(appState.adminGovernanceDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findAdminGovernanceDirectoryItem(targetUserId) {
|
|
|
|
|
return getAdminGovernanceDirectoryItems().find((item) => item.id === targetUserId) || null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAdminOverrideTargetState() {
|
|
|
|
|
const directoryItems = getAdminGovernanceDirectoryItems();
|
|
|
|
|
const existing = appState.adminOverrideTarget || {};
|
|
|
|
|
const targetUserId = String(existing.targetUserId || existing.target_user_id || directoryItems[0]?.id || "");
|
|
|
|
|
const targetUser = findAdminGovernanceDirectoryItem(targetUserId) || directoryItems[0] || null;
|
|
|
|
|
const targetProjects = safeArray(targetUser?.projects);
|
|
|
|
|
const targetProjectId = String(existing.targetProjectId || existing.target_project_id || targetProjects[0]?.id || "");
|
|
|
|
|
return {
|
|
|
|
|
targetUserId,
|
|
|
|
|
targetProjectId,
|
|
|
|
|
platform: normalizePlatformValue(existing.platform || getPreferredPlatform(), "douyin")
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatAdminGovernanceTargetLabel(target) {
|
|
|
|
|
const directoryItem = findAdminGovernanceDirectoryItem(target?.targetUserId || target?.target_user_id || "");
|
|
|
|
|
const project = safeArray(directoryItem?.projects).find((item) => item.id === (target?.targetProjectId || target?.target_project_id || ""));
|
|
|
|
|
const userLabel = directoryItem ? `${directoryItem.display_name || directoryItem.username || directoryItem.id}${directoryItem.role ? ` · ${directoryItem.role}` : ""}` : "未选择目标";
|
|
|
|
|
const projectLabel = project ? project.name || project.id : "默认用户全局";
|
|
|
|
|
return `${userLabel} / ${projectLabel}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAdminGovernanceDirectoryUserOptions() {
|
|
|
|
|
return getAdminGovernanceDirectoryItems().map((item) => ({
|
|
|
|
|
value: item.id,
|
|
|
|
|
label: `${item.display_name || item.username || item.id}${item.project_count ? ` · ${formatNumber(item.project_count)} 项目` : ""}`
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAdminGovernanceDirectoryProjectOptions(targetUserId) {
|
|
|
|
|
const directoryItem = findAdminGovernanceDirectoryItem(targetUserId);
|
|
|
|
|
return safeArray(directoryItem?.projects).map((item) => ({
|
|
|
|
|
value: item.id,
|
|
|
|
|
label: item.name || item.id
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderPolicyVersionsHtml(items, emptyText = "暂无历史版本。") {
|
|
|
|
|
const versions = safeArray(items);
|
|
|
|
|
if (!versions.length) {
|
|
|
|
|
return `<div class="task-item compact"><h4>还没有历史版本</h4><p>${escapeHtml(emptyText)}</p></div>`;
|
|
|
|
|
}
|
|
|
|
|
return versions.slice(0, 8).map((version) => `
|
|
|
|
|
<div class="task-item compact">
|
|
|
|
|
<h4>${escapeHtml(version.title || `版本 ${formatNumber(version.version_no || 0)}`)}</h4>
|
|
|
|
|
<p>${escapeHtml(version.summary || "没有补充摘要。")}</p>
|
|
|
|
|
<div class="task-meta">
|
|
|
|
|
<span class="tag blue">版本 ${escapeHtml(formatNumber(version.version_no || 0))}</span>
|
|
|
|
|
${version.created_at ? `<span class="tag">${escapeHtml(formatDateTime(version.created_at))}</span>` : ""}
|
|
|
|
|
${version.rollback_from_version_id ? `<span class="tag orange">回滚生成</span>` : ""}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`).join("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function loadPolicyVersions(url) {
|
|
|
|
|
const payload = await storyforgeFetch(url).catch(() => ({ items: [] }));
|
|
|
|
|
const items = safeArray(payload?.items || payload);
|
|
|
|
|
return { items, count: Number(payload?.count || items.length) };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildPolicyVersionOptions(history) {
|
|
|
|
|
return safeArray(history?.items).map((item) => ({
|
|
|
|
|
value: item.id,
|
|
|
|
|
label: `v${formatNumber(item.version_no || 0)} · ${item.title || brief(item.summary || item.id, 24)}`
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openUserGlobalPolicyAction() {
|
|
|
|
|
const project = requireSelectedProject();
|
|
|
|
|
const bundle = appState.userGlobalPolicy || {};
|
|
|
|
|
@@ -6478,6 +6695,77 @@ function openUserPlatformPolicyAction(platform) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function openUserGlobalPolicyHistoryAction() {
|
|
|
|
|
const project = requireSelectedProject();
|
|
|
|
|
const history = await loadPolicyVersions(`/v2/oneliner/governance/user/global/versions?project_id=${encodeURIComponent(project.id)}`);
|
|
|
|
|
const selectedVersionId = history.items[0]?.id || "";
|
|
|
|
|
const versionOptions = buildPolicyVersionOptions(history);
|
|
|
|
|
openActionModal({
|
|
|
|
|
title: "我的全局策略历史",
|
|
|
|
|
description: "查看你自己的全局策略版本,并从历史里选择一个版本回滚。回滚不会改旧记录,而是会生成一个新的生效版本。",
|
|
|
|
|
submitLabel: "回滚到所选版本",
|
|
|
|
|
hideSubmit: !selectedVersionId,
|
|
|
|
|
fields: [
|
|
|
|
|
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(appState.userGlobalPolicy || {}, "你还没有发布自己的全局策略。") },
|
|
|
|
|
{ type: "html", label: "历史版本", html: renderPolicyVersionsHtml(history.items, "你的全局策略还没有历史版本。") },
|
|
|
|
|
...(selectedVersionId ? [
|
|
|
|
|
{ name: "versionId", label: "回滚版本", type: "select", value: selectedVersionId, options: versionOptions },
|
|
|
|
|
{ name: "reason", label: "回滚原因", type: "textarea", rows: 3, value: "", placeholder: "例如:恢复到更稳妥的首页动作和语气策略" }
|
|
|
|
|
] : [])
|
|
|
|
|
],
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
|
const saved = await storyforgeFetch("/v2/oneliner/governance/user/global/rollback", {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: {
|
|
|
|
|
project_id: project.id,
|
|
|
|
|
version_id: values.versionId || selectedVersionId,
|
|
|
|
|
reason: values.reason || ""
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
appState.userGlobalPolicy = saved;
|
|
|
|
|
await loadAgentControlSurfaces(project.id);
|
|
|
|
|
rememberAction("我的全局策略已回滚", `已生成回滚版本 ${saved.current_version?.version_no || "所选版本"}。`, "green", saved);
|
|
|
|
|
renderAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function openUserPlatformPolicyHistoryAction(platform) {
|
|
|
|
|
const normalizedPlatform = normalizePlatformValue(platform || getPreferredPlatform(), "douyin");
|
|
|
|
|
const project = requireSelectedProject();
|
|
|
|
|
const history = await loadPolicyVersions(`/v2/oneliner/governance/user/platforms/${encodeURIComponent(normalizedPlatform)}/versions?project_id=${encodeURIComponent(project.id)}`);
|
|
|
|
|
const selectedVersionId = history.items[0]?.id || "";
|
|
|
|
|
const versionOptions = buildPolicyVersionOptions(history);
|
|
|
|
|
openActionModal({
|
|
|
|
|
title: `${platformLabel(normalizedPlatform)} 平台策略历史`,
|
|
|
|
|
description: "查看该平台的个人策略版本,并从历史里选择一个版本回滚。回滚只影响当前平台,不会改动其他平台。",
|
|
|
|
|
submitLabel: "回滚到所选版本",
|
|
|
|
|
hideSubmit: !selectedVersionId,
|
|
|
|
|
fields: [
|
|
|
|
|
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(appState.userCurrentPlatformPolicy || {}, `你还没有发布 ${platformLabel(normalizedPlatform)} 平台策略。`) },
|
|
|
|
|
{ type: "html", label: "历史版本", html: renderPolicyVersionsHtml(history.items, `${platformLabel(normalizedPlatform)} 还没有历史版本。`) },
|
|
|
|
|
...(selectedVersionId ? [
|
|
|
|
|
{ name: "versionId", label: "回滚版本", type: "select", value: selectedVersionId, options: versionOptions },
|
|
|
|
|
{ name: "reason", label: "回滚原因", type: "textarea", rows: 3, value: "", placeholder: "例如:恢复到更适合这个平台的拆解方式" }
|
|
|
|
|
] : [])
|
|
|
|
|
],
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
|
const saved = await storyforgeFetch(`/v2/oneliner/governance/user/platforms/${encodeURIComponent(normalizedPlatform)}/rollback`, {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: {
|
|
|
|
|
project_id: project.id,
|
|
|
|
|
version_id: values.versionId || selectedVersionId,
|
|
|
|
|
reason: values.reason || ""
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
appState.userCurrentPlatformPolicy = saved;
|
|
|
|
|
await loadAgentControlSurfaces(project.id);
|
|
|
|
|
rememberAction(`${platformLabel(normalizedPlatform)} 平台策略已回滚`, `已生成回滚版本 ${saved.current_version?.version_no || "所选版本"}。`, "green", saved);
|
|
|
|
|
renderAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openSystemMainPolicyAction() {
|
|
|
|
|
const projectId = getOneLinerProjectId();
|
|
|
|
|
const bundle = appState.adminSystemMainPolicy || {};
|
|
|
|
|
@@ -6548,6 +6836,165 @@ function openSystemPlatformPolicyAction(platform) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function openAdminOverrideTargetAction() {
|
|
|
|
|
const current = getAdminOverrideTargetState();
|
|
|
|
|
const directoryItems = getAdminGovernanceDirectoryItems();
|
|
|
|
|
openActionModal({
|
|
|
|
|
title: "选择管理员覆盖目标",
|
|
|
|
|
description: "先选中要覆盖的用户、项目和平台,再去编辑覆盖策略或查看历史。",
|
|
|
|
|
submitLabel: "保存目标",
|
|
|
|
|
fields: [
|
|
|
|
|
{ type: "html", label: "当前目标", html: renderPolicyVersionSummary(appState.adminOverridePolicy || {}, `当前目标是 ${formatAdminGovernanceTargetLabel(current)}。`) },
|
|
|
|
|
{ name: "targetUserId", label: "目标用户", type: "select", value: current.targetUserId, options: getAdminGovernanceDirectoryUserOptions() },
|
|
|
|
|
{ name: "targetProjectId", label: "目标项目", type: "select", value: current.targetProjectId, options: [{ value: "", label: "用户全局" }, ...getAdminGovernanceDirectoryProjectOptions(current.targetUserId)] },
|
|
|
|
|
{ name: "platform", label: "平台", type: "select", value: current.platform, options: getPlatformOptions() },
|
|
|
|
|
{ type: "html", label: "目录提示", html: directoryItems.length ? `<div class="task-item compact"><h4>可选目标</h4><p>当前目录里有 ${escapeHtml(formatNumber(directoryItems.length))} 位已审核账号。</p></div>` : `<div class="task-item compact"><h4>目录为空</h4><p>后端还没有返回可选账号。</p></div>` }
|
|
|
|
|
],
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
|
appState.adminOverrideTarget = {
|
|
|
|
|
targetUserId: String(values.targetUserId || ""),
|
|
|
|
|
targetProjectId: String(values.targetProjectId || ""),
|
|
|
|
|
platform: normalizePlatformValue(values.platform || "douyin", "douyin")
|
|
|
|
|
};
|
|
|
|
|
await loadAgentControlSurfaces(getOneLinerProjectId());
|
|
|
|
|
rememberAction("管理员覆盖目标已更新", `当前目标已切换到 ${formatAdminGovernanceTargetLabel(appState.adminOverrideTarget)}。`, "green");
|
|
|
|
|
renderAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openAdminOverridePolicyAction() {
|
|
|
|
|
const target = getAdminOverrideTargetState();
|
|
|
|
|
const bundle = appState.adminOverridePolicy || {};
|
|
|
|
|
const current = bundle.current_version || {};
|
|
|
|
|
openActionModal({
|
|
|
|
|
title: "编辑管理员覆盖策略",
|
|
|
|
|
description: "这层策略只作用于当前选中的目标,会叠加在用户策略和系统默认之上。",
|
|
|
|
|
submitLabel: "保存覆盖策略",
|
|
|
|
|
fields: [
|
|
|
|
|
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(bundle, `当前还没有为 ${formatAdminGovernanceTargetLabel(target)} 发布覆盖策略。`) },
|
|
|
|
|
{ name: "title", label: "策略标题", value: current.title || `管理员覆盖:${formatAdminGovernanceTargetLabel(target)}`, placeholder: "例如:重点账号短期放量覆盖" },
|
|
|
|
|
{ name: "summary", label: "摘要", type: "textarea", rows: 3, value: current.summary || "", placeholder: "写清楚这层覆盖是为了什么目标" },
|
|
|
|
|
{ name: "policyJson", label: "策略 JSON", type: "textarea", rows: 8, value: JSON.stringify(current.policy || {}, null, 2), placeholder: "{\"guardrails\":{\"require_admin_review\":true}}" },
|
|
|
|
|
{ name: "reason", label: "变更原因", type: "textarea", rows: 3, value: "", placeholder: "例如:对该账号/项目临时放宽首页动作数量" }
|
|
|
|
|
],
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
|
const saved = await storyforgeFetch("/v2/admin/oneliner/governance/overrides", {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: {
|
|
|
|
|
target_user_id: target.targetUserId,
|
|
|
|
|
target_project_id: target.targetProjectId,
|
|
|
|
|
platform: target.platform,
|
|
|
|
|
title: values.title || `管理员覆盖:${formatAdminGovernanceTargetLabel(target)}`,
|
|
|
|
|
summary: values.summary || "",
|
|
|
|
|
policy: parsePolicyJsonField(values.policyJson, "管理员覆盖策略 JSON"),
|
|
|
|
|
reason: values.reason || ""
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
appState.adminOverridePolicy = saved;
|
|
|
|
|
await loadAgentControlSurfaces(getOneLinerProjectId());
|
|
|
|
|
rememberAction("管理员覆盖策略已保存", `已为 ${formatAdminGovernanceTargetLabel(target)} 发布版本 ${saved.current_version?.version_no || 1}。`, "green", saved);
|
|
|
|
|
renderAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function openAdminOverrideHistoryAction() {
|
|
|
|
|
const target = getAdminOverrideTargetState();
|
|
|
|
|
const history = await loadPolicyVersions(`/v2/admin/oneliner/governance/overrides/versions?target_user_id=${encodeURIComponent(target.targetUserId)}&target_project_id=${encodeURIComponent(target.targetProjectId)}&platform=${encodeURIComponent(target.platform)}`);
|
|
|
|
|
const selectedVersionId = history.items[0]?.id || "";
|
|
|
|
|
openActionModal({
|
|
|
|
|
title: "管理员覆盖历史",
|
|
|
|
|
description: "查看当前目标的管理员覆盖版本,并从历史里选择一个版本回滚。",
|
|
|
|
|
submitLabel: "回滚到所选版本",
|
|
|
|
|
fields: [
|
|
|
|
|
{ type: "html", label: "当前目标", html: renderPolicyVersionSummary(appState.adminOverridePolicy || {}, `当前查看的是 ${formatAdminGovernanceTargetLabel(target)} 的覆盖历史。`) },
|
|
|
|
|
{ type: "html", label: "历史版本", html: renderPolicyVersionsHtml(history.items, "当前目标还没有历史版本。") },
|
|
|
|
|
{ name: "versionId", label: "回滚版本", type: "select", value: selectedVersionId, options: safeArray(history.items).map((item) => ({ value: item.id, label: `v${formatNumber(item.version_no || 0)} · ${item.title || brief(item.summary || item.id, 24)}` })) },
|
|
|
|
|
{ name: "reason", label: "回滚原因", type: "textarea", rows: 3, value: "", placeholder: "例如:这版覆盖太激进,需要恢复到上一版" }
|
|
|
|
|
],
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
|
const saved = await storyforgeFetch("/v2/admin/oneliner/governance/overrides/rollback", {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: {
|
|
|
|
|
target_user_id: target.targetUserId,
|
|
|
|
|
target_project_id: target.targetProjectId,
|
|
|
|
|
platform: target.platform,
|
|
|
|
|
version_id: values.versionId || selectedVersionId,
|
|
|
|
|
reason: values.reason || ""
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
appState.adminOverridePolicy = saved;
|
|
|
|
|
await loadAgentControlSurfaces(getOneLinerProjectId());
|
|
|
|
|
rememberAction("管理员覆盖已回滚", `已回滚到版本 ${saved.current_version?.version_no || "所选版本"}。`, "green", saved);
|
|
|
|
|
renderAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function openSystemMainPolicyHistoryAction() {
|
|
|
|
|
const history = await loadPolicyVersions("/v2/admin/oneliner/governance/system/main-agent/versions");
|
|
|
|
|
const selectedVersionId = history.items[0]?.id || "";
|
|
|
|
|
openActionModal({
|
|
|
|
|
title: "系统主 Agent 历史",
|
|
|
|
|
description: "查看系统主 Agent 的历史版本,并选择某个版本回滚。",
|
|
|
|
|
submitLabel: "回滚到所选版本",
|
|
|
|
|
fields: [
|
|
|
|
|
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(appState.adminSystemMainPolicy || {}, "系统主 Agent 还没有历史版本。") },
|
|
|
|
|
{ type: "html", label: "历史版本", html: renderPolicyVersionsHtml(history.items, "系统主 Agent 还没有历史版本。") },
|
|
|
|
|
{ name: "versionId", label: "回滚版本", type: "select", value: selectedVersionId, options: safeArray(history.items).map((item) => ({ value: item.id, label: `v${formatNumber(item.version_no || 0)} · ${item.title || brief(item.summary || item.id, 24)}` })) },
|
|
|
|
|
{ name: "reason", label: "回滚原因", type: "textarea", rows: 3, value: "", placeholder: "例如:恢复到上一版系统主 Agent 策略" }
|
|
|
|
|
],
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
|
const saved = await storyforgeFetch("/v2/admin/oneliner/governance/system/main-agent/rollback", {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: {
|
|
|
|
|
version_id: values.versionId || selectedVersionId,
|
|
|
|
|
reason: values.reason || ""
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
appState.adminSystemMainPolicy = saved;
|
|
|
|
|
await loadAgentControlSurfaces(getOneLinerProjectId());
|
|
|
|
|
rememberAction("系统主 Agent 已回滚", `已回滚到版本 ${saved.current_version?.version_no || "所选版本"}。`, "green", saved);
|
|
|
|
|
renderAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function openSystemPlatformPolicyHistoryAction(platform) {
|
|
|
|
|
const normalizedPlatform = normalizePlatformValue(platform || getPreferredPlatform(), "douyin");
|
|
|
|
|
const history = await loadPolicyVersions(`/v2/admin/oneliner/governance/system/platforms/${encodeURIComponent(normalizedPlatform)}/versions`);
|
|
|
|
|
const selectedVersionId = history.items[0]?.id || "";
|
|
|
|
|
const bundle = safeArray(appState.adminSystemPlatformPolicies).find((item) => item?.scope?.platform === normalizedPlatform) || {};
|
|
|
|
|
openActionModal({
|
|
|
|
|
title: `${platformLabel(normalizedPlatform)} 系统平台历史`,
|
|
|
|
|
description: "查看该平台的系统默认策略历史,并选择某个版本回滚。",
|
|
|
|
|
submitLabel: "回滚到所选版本",
|
|
|
|
|
fields: [
|
|
|
|
|
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(bundle, `当前 ${platformLabel(normalizedPlatform)} 还没有系统平台历史版本。`) },
|
|
|
|
|
{ type: "html", label: "历史版本", html: renderPolicyVersionsHtml(history.items, `${platformLabel(normalizedPlatform)} 还没有历史版本。`) },
|
|
|
|
|
{ name: "versionId", label: "回滚版本", type: "select", value: selectedVersionId, options: safeArray(history.items).map((item) => ({ value: item.id, label: `v${formatNumber(item.version_no || 0)} · ${item.title || brief(item.summary || item.id, 24)}` })) },
|
|
|
|
|
{ name: "reason", label: "回滚原因", type: "textarea", rows: 3, value: "", placeholder: "例如:恢复到上一版平台默认方法论" }
|
|
|
|
|
],
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
|
const saved = await storyforgeFetch(`/v2/admin/oneliner/governance/system/platforms/${encodeURIComponent(normalizedPlatform)}/rollback`, {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: {
|
|
|
|
|
version_id: values.versionId || selectedVersionId,
|
|
|
|
|
reason: values.reason || ""
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
appState.adminSystemPlatformPolicies = safeArray(appState.adminSystemPlatformPolicies)
|
|
|
|
|
.filter((item) => item?.scope?.platform !== normalizedPlatform)
|
|
|
|
|
.concat(saved)
|
|
|
|
|
.sort((a, b) => String(a?.scope?.platform || "").localeCompare(String(b?.scope?.platform || "")));
|
|
|
|
|
await loadAgentControlSurfaces(getOneLinerProjectId());
|
|
|
|
|
rememberAction(`${platformLabel(normalizedPlatform)} 系统平台策略已回滚`, `已回滚到版本 ${saved.current_version?.version_no || "所选版本"}。`, "green", saved);
|
|
|
|
|
renderAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openPlatformAgentProfileAction(platform) {
|
|
|
|
|
const project = requireSelectedProject();
|
|
|
|
|
const agents = safeArray(appState.platformAgents);
|
|
|
|
|
@@ -8316,18 +8763,46 @@ document.addEventListener("click", async (event) => {
|
|
|
|
|
openUserGlobalPolicyAction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-user-global-policy-history") {
|
|
|
|
|
await openUserGlobalPolicyHistoryAction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-user-platform-policy") {
|
|
|
|
|
openUserPlatformPolicyAction(action.dataset.platform || "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-user-platform-policy-history") {
|
|
|
|
|
await openUserPlatformPolicyHistoryAction(action.dataset.platform || "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-system-main-policy") {
|
|
|
|
|
openSystemMainPolicyAction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-system-main-policy-history") {
|
|
|
|
|
await openSystemMainPolicyHistoryAction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-system-platform-policy") {
|
|
|
|
|
openSystemPlatformPolicyAction(action.dataset.platform || "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-system-platform-policy-history") {
|
|
|
|
|
await openSystemPlatformPolicyHistoryAction(action.dataset.platform || "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-admin-override-target") {
|
|
|
|
|
await openAdminOverrideTargetAction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-admin-override-policy") {
|
|
|
|
|
openAdminOverridePolicyAction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "open-admin-override-history") {
|
|
|
|
|
await openAdminOverrideHistoryAction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (name === "select-oneliner-session") {
|
|
|
|
|
appState.selectedOnelinerSessionId = action.dataset.sessionId || "";
|
|
|
|
|
await loadOneLinerMessages(appState.selectedOnelinerSessionId);
|
|
|
|
|
|