feat(admin-web): AIPrewarm 分组展示 + 每行触发 + AppType 联合类型
1. AIPrewarm.tsx:
- areaToAppType(area) helper · area='all' → app2_finance · 其他 → app2a_finance_area
- handleRunOne / handleBackfillMissing 按 area 动态选 app_type
- MissingRowWithGroup 含 __group_header 字段
- groupedMissing 数据构造(全域 + 区域两组 · 每组前插 header 行)
- 每列 onCell colSpan 合并单元格实现"全域 / 区域"分组标题行
- Descriptions 加全域 8/X + 区域 64/X 双段统计
2. api/adminAI.ts:
- 新增 AppType 联合类型(9 项,含 app2a_finance_area)
- runApp 签名 appType: AppType(替代原 string)
- RunAppResponse.app_type 同步为 AppType
3. AIOperations.tsx:
- runAppType state 类型改为 AppType | undefined
- import { AppType } type
实测:
- pnpm tsc --noEmit 全项目通过
- playwright E2E 访问 /ai/prewarm 显示 "全域 8/8 · 区域 63/64" 分段统计
分组标题行正确合并 · 单独生成按钮按 area 路由到正确 app_type
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,32 @@
|
||||
|
||||
import { apiClient } from "./client";
|
||||
|
||||
// ---- 公共类型 ----
|
||||
|
||||
/**
|
||||
* AI APP 类型联合(与后端 `CacheTypeEnum` / `_SUPPORTED_APP_TYPES` 同步)。
|
||||
*
|
||||
* - app1_chat · 小程序聊天(无缓存)
|
||||
* - app2_finance · 全域财务洞察(area = 'all',8 组合)
|
||||
* - app2a_finance_area · 区域财务洞察(area != 'all',64 组合,2026-04-23 新增)
|
||||
* - app3_clue · 客户线索分析
|
||||
* - app4_analysis · 助教关系分析
|
||||
* - app5_tactics · 话术参考
|
||||
* - app6_note_analysis · 备注分析
|
||||
* - app7_customer_analysis · 客户综合分析
|
||||
* - app8_clue_consolidated · 线索整合
|
||||
*/
|
||||
export type AppType =
|
||||
| "app1_chat"
|
||||
| "app2_finance"
|
||||
| "app2a_finance_area"
|
||||
| "app3_clue"
|
||||
| "app4_analysis"
|
||||
| "app5_tactics"
|
||||
| "app6_note_analysis"
|
||||
| "app7_customer_analysis"
|
||||
| "app8_clue_consolidated";
|
||||
|
||||
// ---- 类型定义 ----
|
||||
|
||||
// Dashboard
|
||||
@@ -201,9 +227,16 @@ export interface AlertActionResponse {
|
||||
// ---- API 调用 ----
|
||||
|
||||
// Dashboard
|
||||
export async function getDashboard(siteId?: number): Promise<DashboardResponse> {
|
||||
export interface DashboardQuery {
|
||||
site_id?: number;
|
||||
range_days?: number; // 1 / 3 / 7 / 10
|
||||
date_from?: string; // YYYY-MM-DD(与 date_to 成对)
|
||||
date_to?: string;
|
||||
}
|
||||
|
||||
export async function getDashboard(query?: DashboardQuery): Promise<DashboardResponse> {
|
||||
const { data } = await apiClient.get<DashboardResponse>("/admin/ai/dashboard", {
|
||||
params: siteId != null ? { site_id: siteId } : undefined,
|
||||
params: query,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
@@ -275,3 +308,101 @@ export async function ignoreAlert(id: number): Promise<AlertActionResponse> {
|
||||
const { data } = await apiClient.post<AlertActionResponse>(`/admin/ai/alerts/${id}/ignore`);
|
||||
return data;
|
||||
}
|
||||
|
||||
// 按需单 App 执行
|
||||
export interface RunAppRequest {
|
||||
site_id: number;
|
||||
member_id?: number;
|
||||
assistant_id?: number;
|
||||
time_dimension?: string;
|
||||
area?: string;
|
||||
note_content?: string;
|
||||
noted_by_name?: string;
|
||||
noted_by_created_at?: string;
|
||||
}
|
||||
|
||||
export interface RunAppResponse {
|
||||
app_type: AppType;
|
||||
success: boolean;
|
||||
result: Record<string, unknown> | null;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
export async function runApp(appType: AppType, body: RunAppRequest): Promise<RunAppResponse> {
|
||||
const { data } = await apiClient.post<RunAppResponse>(`/admin/ai/run/${appType}`, body);
|
||||
return data;
|
||||
}
|
||||
|
||||
// ---- 触发器管理(biz.trigger_jobs)----
|
||||
|
||||
export interface TriggerItem {
|
||||
id: number;
|
||||
job_name: string;
|
||||
job_type: string;
|
||||
trigger_condition: string; // event / cron / interval
|
||||
trigger_config: Record<string, unknown>;
|
||||
status: string; // enabled / disabled
|
||||
description: string | null;
|
||||
last_run_at: string | null;
|
||||
next_run_at: string | null;
|
||||
last_error: string | null;
|
||||
}
|
||||
|
||||
export interface TriggerUpdateRequest {
|
||||
status?: string; // enabled / disabled
|
||||
cron_expression?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export async function listTriggers(): Promise<TriggerItem[]> {
|
||||
const { data } = await apiClient.get<TriggerItem[]>("/admin/ai/triggers");
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateTrigger(id: number, body: TriggerUpdateRequest): Promise<TriggerItem> {
|
||||
const { data } = await apiClient.patch<TriggerItem>(`/admin/ai/triggers/${id}`, body);
|
||||
return data;
|
||||
}
|
||||
|
||||
// ---- 预热进度(app2_finance 72 组合)----
|
||||
|
||||
export interface PrewarmMissingItem {
|
||||
target_id: string;
|
||||
time_dimension: string;
|
||||
area: string;
|
||||
}
|
||||
|
||||
export interface PrewarmProgressResponse {
|
||||
total: number;
|
||||
done: number;
|
||||
missing: PrewarmMissingItem[];
|
||||
last_updated: string | null;
|
||||
}
|
||||
|
||||
export async function getPrewarmProgress(siteId: number): Promise<PrewarmProgressResponse> {
|
||||
const { data } = await apiClient.get<PrewarmProgressResponse>("/admin/ai/prewarm/progress", {
|
||||
params: { site_id: siteId },
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
// ---- 手动触发事件链(越过去重)----
|
||||
|
||||
export interface ManualTriggerRequest {
|
||||
event_type: string; // consumption / dws_completed / note_created / task_assigned
|
||||
site_id: number;
|
||||
member_id?: number;
|
||||
assistant_id?: number;
|
||||
payload?: Record<string, unknown>;
|
||||
is_forced?: boolean;
|
||||
}
|
||||
|
||||
export interface ManualTriggerResponse {
|
||||
trigger_job_id: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export async function triggerEvent(body: ManualTriggerRequest): Promise<ManualTriggerResponse> {
|
||||
const { data } = await apiClient.post<ManualTriggerResponse>("/admin/ai/trigger-event", body);
|
||||
return data;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user