feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本

包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Neo
2026-04-06 00:03:48 +08:00
parent 70324d8542
commit 6f8f12314f
515 changed files with 76604 additions and 7456 deletions

View File

@@ -0,0 +1,277 @@
/**
* AI 监控后台 API
*
* 对接后端 /api/admin/ai/* 端点,提供 Dashboard、调度任务、调用记录、
* 缓存管理、Token 预算、批量执行、告警管理等功能。
*/
import { apiClient } from "./client";
// ---- 类型定义 ----
// Dashboard
export interface DailyTrend {
date: string;
calls: number;
success_rate: number;
}
export interface AppDistItem {
app_type: string;
count: number;
percentage: number;
}
export interface BudgetInfo {
daily_used: number;
daily_limit: number;
daily_pct: number;
monthly_used: number;
monthly_limit: number;
monthly_pct: number;
}
export interface AlertItem {
id: number;
app_type: string;
status: string;
alert_status: string | null;
error_message: string | null;
created_at: string;
}
export interface AppHealthItem {
app_type: string;
last_status: string | null;
last_call_at: string | null;
}
export interface DashboardResponse {
today_calls: number;
today_success_rate: number;
today_tokens: number;
today_avg_latency_ms: number;
trend_7d: DailyTrend[];
app_distribution: AppDistItem[];
budget: BudgetInfo;
recent_alerts: AlertItem[];
app_health: AppHealthItem[];
}
// 调度任务
export interface TriggerJobItem {
id: number;
event_type: string;
member_id: number | null;
status: string;
app_chain: string | null;
is_forced: boolean;
site_id: number;
started_at: string | null;
finished_at: string | null;
created_at: string;
}
export interface TriggerJobDetailResponse extends TriggerJobItem {
payload: Record<string, unknown> | null;
error_message: string | null;
connector_type: string;
}
export interface TriggerJobListResponse {
items: TriggerJobItem[];
total: number;
page: number;
page_size: number;
today_skipped_duplicates: number;
}
export interface RetryResponse {
trigger_job_id: number;
status: string;
}
export interface TriggerJobQuery {
event_type?: string;
status?: string;
site_id?: number;
date_from?: string;
date_to?: string;
page?: number;
page_size?: number;
}
// 调用记录
export interface RunLogItem {
id: number;
app_type: string;
trigger_type: string;
member_id: number | null;
tokens_used: number;
latency_ms: number | null;
status: string;
site_id: number;
created_at: string;
}
export interface RunLogDetailResponse extends RunLogItem {
request_prompt: string | null;
response_text: string | null;
error_message: string | null;
session_id: string | null;
finished_at: string | null;
}
export interface RunLogListResponse {
items: RunLogItem[];
total: number;
page: number;
page_size: number;
}
export interface RunLogQuery {
app_type?: string;
status?: string;
trigger_type?: string;
site_id?: number;
date_from?: string;
date_to?: string;
page?: number;
page_size?: number;
}
// 缓存管理
export interface CacheInvalidateReq {
site_id: number;
app_type?: string;
member_id?: number;
}
export interface CacheInvalidateResponse {
affected_count: number;
}
// Token 预算
export interface BudgetResponse {
daily_used: number;
daily_limit: number;
daily_pct: number;
monthly_used: number;
monthly_limit: number;
monthly_pct: number;
}
// 批量执行
export interface BatchRunReq {
app_types: string[];
member_ids: number[];
site_id: number;
}
export interface BatchRunEstimate {
batch_id: string;
estimated_calls: number;
estimated_tokens: number;
}
export interface BatchRunConfirmResponse {
status: string;
}
// 告警
export interface AlertQuery {
alert_status?: string;
site_id?: number;
page?: number;
page_size?: number;
}
export interface AlertListResponse {
items: AlertItem[];
total: number;
page: number;
page_size: number;
}
export interface AlertActionResponse {
id: number;
alert_status: string;
}
// ---- API 调用 ----
// Dashboard
export async function getDashboard(siteId?: number): Promise<DashboardResponse> {
const { data } = await apiClient.get<DashboardResponse>("/admin/ai/dashboard", {
params: siteId != null ? { site_id: siteId } : undefined,
});
return data;
}
// 调度任务
export async function getTriggerJobs(params: TriggerJobQuery): Promise<TriggerJobListResponse> {
const { data } = await apiClient.get<TriggerJobListResponse>("/admin/ai/trigger-jobs", { params });
return data;
}
export async function getTriggerJobDetail(id: number): Promise<TriggerJobDetailResponse> {
const { data } = await apiClient.get<TriggerJobDetailResponse>(`/admin/ai/trigger-jobs/${id}`);
return data;
}
export async function retryTriggerJob(id: number): Promise<RetryResponse> {
const { data } = await apiClient.post<RetryResponse>(`/admin/ai/trigger-jobs/${id}/retry`);
return data;
}
// 调用记录
export async function getRunLogs(params: RunLogQuery): Promise<RunLogListResponse> {
const { data } = await apiClient.get<RunLogListResponse>("/admin/ai/run-logs", { params });
return data;
}
export async function getRunLogDetail(id: number): Promise<RunLogDetailResponse> {
const { data } = await apiClient.get<RunLogDetailResponse>(`/admin/ai/run-logs/${id}`);
return data;
}
// 缓存管理
export async function invalidateCache(body: CacheInvalidateReq): Promise<CacheInvalidateResponse> {
const { data } = await apiClient.post<CacheInvalidateResponse>("/admin/ai/cache/invalidate", body);
return data;
}
// Token 预算
export async function getBudget(): Promise<BudgetResponse> {
const { data } = await apiClient.get<BudgetResponse>("/admin/ai/budget");
return data;
}
// 批量执行
export async function createBatchRun(body: BatchRunReq): Promise<BatchRunEstimate> {
const { data } = await apiClient.post<BatchRunEstimate>("/admin/ai/batch-run", body);
return data;
}
export async function confirmBatchRun(batchId: string): Promise<BatchRunConfirmResponse> {
const { data } = await apiClient.post<BatchRunConfirmResponse>("/admin/ai/batch-run/confirm", {
batch_id: batchId,
});
return data;
}
// 告警
export async function getAlerts(params: AlertQuery): Promise<AlertListResponse> {
const { data } = await apiClient.get<AlertListResponse>("/admin/ai/alerts", { params });
return data;
}
export async function ackAlert(id: number): Promise<AlertActionResponse> {
const { data } = await apiClient.post<AlertActionResponse>(`/admin/ai/alerts/${id}/ack`);
return data;
}
export async function ignoreAlert(id: number): Promise<AlertActionResponse> {
const { data } = await apiClient.post<AlertActionResponse>(`/admin/ai/alerts/${id}/ignore`);
return data;
}

View File

@@ -122,20 +122,22 @@ apiClient.interceptors.response.use(
try {
// 用独立 axios 调用避免被自身拦截器干扰
const { data } = await axios.post<{
access_token: string;
refresh_token: string;
// ResponseWrapperMiddleware 包装响应为 { code: 0, data: { access_token, refresh_token } }
const resp = await axios.post<{
code: number;
data: { access_token: string; refresh_token: string };
}>("/api/auth/refresh", { refresh_token: refreshToken });
localStorage.setItem(ACCESS_TOKEN_KEY, data.access_token);
localStorage.setItem(REFRESH_TOKEN_KEY, data.refresh_token);
const tokens = resp.data.data;
localStorage.setItem(ACCESS_TOKEN_KEY, tokens.access_token);
localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refresh_token);
processPendingQueue(data.access_token, null);
processPendingQueue(tokens.access_token, null);
// 重放原始请求
originalRequest.headers = {
...originalRequest.headers,
Authorization: `Bearer ${data.access_token}`,
Authorization: `Bearer ${tokens.access_token}`,
};
return apiClient(originalRequest);
} catch (refreshError) {

View File

@@ -0,0 +1,21 @@
/**
* 数据库健康监控 API 调用。
*/
import { apiClient } from './client';
/** 数据库健康状态 */
export interface DbHealthItem {
db_name: string;
status: 'connected' | 'disconnected';
active_connections: number | null;
idle_connections: number | null;
db_size_mb: number | null;
slow_query_count: number | null;
}
/** 获取所有数据库健康状态 */
export async function fetchDbHealth(): Promise<DbHealthItem[]> {
const { data } = await apiClient.get<DbHealthItem[]>('/admin/db-health');
return data;
}

View File

@@ -0,0 +1,84 @@
/**
* 开发调试全链路日志 API。
*
* 对接后端 /api/admin/dev-trace/* 端点,提供日志查询、设置管理、
* 覆盖率扫描、手动清理等功能。
*/
import { apiClient } from "./client";
import type {
TraceFilter,
TraceRequest,
TraceDetail,
TraceSettings,
TraceCoverage,
} from "../types/devTrace";
// ---- 响应类型 ----
export interface TraceRequestListResponse {
items: TraceRequest[];
total: number;
page: number;
page_size: number;
}
export interface CleanupResponse {
deleted_dates: string[];
deleted_files: number;
}
// ---- 日期列表 ----
export async function fetchDates(): Promise<{ dates: string[] }> {
const { data } = await apiClient.get<{ dates: string[] }>("/admin/dev-trace/dates");
return data;
}
// ---- 请求列表(分页 + 筛选) ----
export async function fetchRequests(params: TraceFilter): Promise<TraceRequestListResponse> {
const { data } = await apiClient.get<TraceRequestListResponse>("/admin/dev-trace/requests", { params });
return data;
}
// ---- 请求详情(含完整 spans ----
export async function fetchRequestDetail(requestId: string): Promise<TraceDetail> {
const { data } = await apiClient.get<TraceDetail>(`/admin/dev-trace/request/${requestId}`);
return data;
}
// ---- 手动清理 ----
export async function cleanupLogs(startDate: string, endDate: string): Promise<CleanupResponse> {
const { data } = await apiClient.post<CleanupResponse>("/admin/dev-trace/cleanup", {
start_date: startDate,
end_date: endDate,
});
return data;
}
// ---- 设置 ----
export async function fetchSettings(): Promise<TraceSettings> {
const { data } = await apiClient.get<TraceSettings>("/admin/dev-trace/settings");
return data;
}
export async function updateSettings(settings: Partial<TraceSettings>): Promise<TraceSettings> {
const { data } = await apiClient.put<TraceSettings>("/admin/dev-trace/settings", settings);
return data;
}
// ---- 覆盖率 ----
export async function fetchCoverage(): Promise<TraceCoverage> {
const { data } = await apiClient.get<TraceCoverage>("/admin/dev-trace/coverage");
return data;
}
export async function triggerCoverageScan(): Promise<TraceCoverage> {
const { data } = await apiClient.post<TraceCoverage>("/admin/dev-trace/coverage/scan");
return data;
}

View File

@@ -10,8 +10,8 @@ import { apiClient } from './client';
/** ETL 游标信息 */
export interface CursorInfo {
task_code: string;
last_fetch_time: string | null;
record_count: number | null;
last_start: string | null;
last_end: string | null;
}
/** 最近执行记录 */

View File

@@ -45,3 +45,17 @@ export async function deleteFromQueue(id: string): Promise<void> {
export async function cancelExecution(id: string): Promise<void> {
await apiClient.post(`/execution/${id}/cancel`);
}
// CHANGE 2026-03-22 | 重新执行历史任务
/** 重新执行指定的历史任务 */
export async function rerunExecution(id: string): Promise<{ execution_id: string }> {
const { data } = await apiClient.post<{ execution_id: string }>(`/execution/${id}/rerun`);
return data;
}
// CHANGE 2026-03-27 | 清理输出目录,每类任务只保留最近 10 个运行记录
/** 清理 EXPORT_ROOT 下旧运行记录 */
export async function cleanupOutput(): Promise<{ task_folders_scanned: number; dirs_deleted: number; errors: string[] }> {
const { data } = await apiClient.post<{ task_folders_scanned: number; dirs_deleted: number; errors: string[] }>('/execution/cleanup-output');
return data;
}

View File

@@ -0,0 +1,134 @@
/**
* 注册体系 API 调用(租户/店铺/简写ID/同步)。
*
* 复用 apiClient已含 JWT 拦截器 + 响应解包)。
* 端点前缀:/admin
*/
import { apiClient } from "./client";
/* ------------------------------------------------------------------ */
/* 类型定义 */
/* ------------------------------------------------------------------ */
/** 租户列表项(后端 CamelModel 序列化为 camelCase */
export interface TenantItem {
id: number;
tenantId: number;
tenantName: string;
connectorName: string;
isActive: boolean;
}
/** 店铺列表项 */
export interface SiteItem {
id: number;
siteId: number;
siteName: string;
siteCode: string | null;
siteLabel: string | null;
isActive: boolean;
}
/** 设置/修改简写ID 请求 */
export interface UpdateSiteCodeRequest {
newCode: string;
}
/** 简写ID 修改结果 */
export interface SiteCodeResult {
siteId: number;
oldCode: string | null;
newCode: string;
historyCleaned: boolean;
}
/** 简写ID 变更历史条目 */
export interface SiteCodeHistoryItem {
id: number;
siteCode: string;
isCurrent: boolean;
createdAt: string;
retiredAt: string | null;
}
/** 店铺同步结果 */
export interface SiteSyncResult {
inserted: number;
updated: number;
}
/* ------------------------------------------------------------------ */
/* API 调用 */
/* ------------------------------------------------------------------ */
/** 获取所有活跃租户列表 */
export async function fetchTenants(): Promise<TenantItem[]> {
const { data } = await apiClient.get<TenantItem[]>("/admin/tenants");
return data;
}
/** 获取指定租户下所有活跃店铺 */
export async function fetchTenantSites(
tenantId: number,
): Promise<SiteItem[]> {
const { data } = await apiClient.get<SiteItem[]>(
`/admin/tenants/${tenantId}/sites`,
);
return data;
}
/** 设置/修改店铺简写ID */
export async function updateSiteCode(
siteId: number,
newCode: string,
): Promise<SiteCodeResult> {
const { data } = await apiClient.put<SiteCodeResult>(
`/admin/sites/${siteId}/site-code`,
{ newCode } satisfies UpdateSiteCodeRequest,
);
return data;
}
/** 查看简写ID 变更历史 */
export async function fetchSiteCodeHistory(
siteId: number,
): Promise<SiteCodeHistoryItem[]> {
const { data } = await apiClient.get<SiteCodeHistoryItem[]>(
`/admin/sites/${siteId}/site-code-history`,
);
return data;
}
/** 手动触发店铺同步 */
export async function syncSites(): Promise<SiteSyncResult> {
const { data } = await apiClient.post<SiteSyncResult>(
"/admin/sites/sync",
);
return data;
}
/* ------------------------------------------------------------------ */
/* 测试功能:手动创建/删除店铺 */
/* ------------------------------------------------------------------ */
/** 创建店铺请求 */
export interface CreateSitePayload {
tenantId: number;
siteId: number;
siteName: string;
siteCode?: string;
}
/** 手动创建店铺(测试功能) */
export async function createSite(
payload: CreateSitePayload,
): Promise<SiteItem> {
const { data } = await apiClient.post<SiteItem>("/admin/sites", payload);
return data;
}
/** 删除店铺(测试功能,硬删除) */
export async function deleteSite(id: number): Promise<void> {
await apiClient.delete(`/admin/sites/${id}`);
}

View File

@@ -3,7 +3,7 @@
*/
import { apiClient } from './client';
import type { ScheduledTask, ScheduleConfig, TaskConfig, ExecutionLog } from '../types';
import type { ScheduledTask, ScheduleConfig, TaskConfig, ExecutionLog, MinRunIntervalItem } from '../types';
/** 获取调度任务列表 */
export async function fetchSchedules(): Promise<ScheduledTask[]> {
@@ -18,6 +18,9 @@ export async function createSchedule(payload: {
task_config: TaskConfig;
schedule_config: ScheduleConfig;
run_immediately?: boolean;
min_run_interval_value?: number;
min_run_interval_unit?: string;
min_run_intervals?: Record<string, MinRunIntervalItem>;
}): Promise<ScheduledTask> {
const { data } = await apiClient.post<ScheduledTask>('/schedules', payload);
return data;
@@ -31,6 +34,9 @@ export async function updateSchedule(
task_codes: string[];
task_config: TaskConfig;
schedule_config: ScheduleConfig;
min_run_interval_value: number;
min_run_interval_unit: string;
min_run_intervals: Record<string, MinRunIntervalItem>;
}>,
): Promise<ScheduledTask> {
const { data } = await apiClient.put<ScheduledTask>(`/schedules/${id}`, payload);
@@ -49,8 +55,10 @@ export async function toggleSchedule(id: string): Promise<ScheduledTask> {
}
/** 手动执行调度任务一次(不更新调度间隔) */
export async function runScheduleNow(id: string): Promise<{ message: string; task_id: string }> {
const { data } = await apiClient.post<{ message: string; task_id: string }>(`/schedules/${id}/run`);
export async function runScheduleNow(id: string, force = false): Promise<{ message: string; task_id: string }> {
const { data } = await apiClient.post<{ message: string; task_id: string }>(`/schedules/${id}/run`, null, {
params: force ? { force: true } : undefined,
});
return data;
}

View File

@@ -0,0 +1,187 @@
/**
* P18 任务引擎运营看板 API。
*
* 端点前缀:/api/admin/task-engine
*/
import { apiClient } from "./client";
/* ------------------------------------------------------------------ */
/* 类型定义 */
/* ------------------------------------------------------------------ */
export interface TransferLogItem {
id: number;
site_id: number;
site_name: string;
member_id: number;
member_name: string;
from_assistant_id: number;
from_assistant_name: string;
to_assistant_id: number;
to_assistant_name: string;
transfer_reason: string | null;
transfer_score: number | null;
guard_checks: Record<string, unknown> | null;
created_at: string;
}
export interface TransferLogPage {
items: TransferLogItem[];
total: number;
}
export interface PendingReviewItem {
id: number;
site_id: number;
site_name: string;
member_id: number;
member_name: string;
assistant_id: number;
assistant_name: string;
task_type: string;
task_type_label: string;
transfer_count: number;
priority_score: number | null;
created_at: string;
}
export interface PendingReviewPage {
items: PendingReviewItem[];
total: number;
}
export interface ConfigParam {
id: number;
site_id: number | null;
site_name: string | null;
param_key: string;
param_value: number;
description: string | null;
updated_at: string;
}
export interface ConfigParamList {
params: ConfigParam[];
}
/* ------------------------------------------------------------------ */
/* 转移日志 */
/* ------------------------------------------------------------------ */
export interface TransferLogQuery {
site_id?: number;
from_date?: string;
to_date?: string;
assistant_id?: number;
page?: number;
page_size?: number;
}
export async function fetchTransferLogs(
query: TransferLogQuery = {},
): Promise<TransferLogPage> {
const resp = await apiClient.get<TransferLogPage>(
"/admin/task-engine/transfer-log",
{ params: query },
);
return resp.data;
}
export async function fetchMemberTransferHistory(
memberId: number,
): Promise<TransferLogItem[]> {
const resp = await apiClient.get<TransferLogItem[]>(
`/admin/task-engine/transfer-log/${memberId}/history`,
);
return resp.data;
}
/* ------------------------------------------------------------------ */
/* 待审核任务 */
/* ------------------------------------------------------------------ */
export interface PendingReviewQuery {
site_id?: number;
page?: number;
page_size?: number;
}
export async function fetchPendingReviews(
query: PendingReviewQuery = {},
): Promise<PendingReviewPage> {
const resp = await apiClient.get<PendingReviewPage>(
"/admin/task-engine/pending-review",
{ params: query },
);
return resp.data;
}
export async function reassignTask(
taskId: number,
toAssistantId: number,
): Promise<{ success: boolean; new_task_id: number | null }> {
const resp = await apiClient.post(
`/admin/task-engine/pending-review/${taskId}/reassign`,
{ to_assistant_id: toAssistantId },
);
return resp.data;
}
export async function closeTask(
taskId: number,
reason: string,
): Promise<{ success: boolean }> {
const resp = await apiClient.post(
`/admin/task-engine/pending-review/${taskId}/close`,
{ reason },
);
return resp.data;
}
/* ------------------------------------------------------------------ */
/* 参数管理 */
/* ------------------------------------------------------------------ */
export async function fetchConfigParams(
siteId?: number,
): Promise<ConfigParamList> {
const resp = await apiClient.get<ConfigParamList>(
"/admin/task-engine/config",
{ params: siteId != null ? { site_id: siteId } : {} },
);
return resp.data;
}
export async function updateConfigParam(
paramId: number,
paramValue: number,
): Promise<{ success: boolean }> {
const resp = await apiClient.put(
`/admin/task-engine/config/${paramId}`,
{ param_value: paramValue },
);
return resp.data;
}
export async function createConfigParam(
siteId: number,
paramKey: string,
paramValue: number,
): Promise<{ success: boolean; id: number }> {
const resp = await apiClient.post("/admin/task-engine/config", {
site_id: siteId,
param_key: paramKey,
param_value: paramValue,
});
return resp.data;
}
export async function deleteConfigParam(
paramId: number,
): Promise<{ success: boolean }> {
const resp = await apiClient.delete(
`/admin/task-engine/config/${paramId}`,
);
return resp.data;
}

View File

@@ -0,0 +1,110 @@
/**
* 租户管理员 CRUD API 调用。
*
* 复用 apiClient已含 JWT 拦截器 + 响应解包)。
* 端点前缀:/admin/tenant-admins
*/
import { apiClient } from "./client";
/* ------------------------------------------------------------------ */
/* 类型定义 */
/* ------------------------------------------------------------------ */
/** 列表项(后端 CamelModel 序列化为 camelCase */
export interface TenantAdminItem {
id: number;
username: string;
displayName: string | null;
tenantId: number;
tenantName: string | null;
adminType: string;
managedSiteIds: number[];
isActive: boolean;
createdAt: string;
lastLoginAt: string | null;
}
/** 分页响应 */
export interface TenantAdminListResponse {
items: TenantAdminItem[];
total: number;
page: number;
page_size: number;
}
/** 创建请求 */
export interface TenantAdminCreatePayload {
username: string;
password: string;
displayName: string;
tenantId: number;
managedSiteIds: number[];
}
/** 编辑请求(所有字段可选) */
export interface TenantAdminEditPayload {
username?: string;
displayName?: string;
managedSiteIds?: number[];
isActive?: boolean;
}
/** 重置密码请求 */
export interface ResetPasswordPayload {
newPassword: string;
}
/* ------------------------------------------------------------------ */
/* API 调用 */
/* ------------------------------------------------------------------ */
/** 列表查询(分页 + 关键词搜索 + 可选包含已禁用) */
export async function fetchTenantAdmins(params: {
page?: number;
page_size?: number;
keyword?: string;
include_inactive?: boolean;
}): Promise<TenantAdminListResponse> {
const { data } = await apiClient.get<TenantAdminListResponse>(
"/admin/tenant-admins",
{ params },
);
return data;
}
/** 创建租户管理员 */
export async function createTenantAdmin(
payload: TenantAdminCreatePayload,
): Promise<TenantAdminItem> {
const { data } = await apiClient.post<TenantAdminItem>(
"/admin/tenant-admins",
payload,
);
return data;
}
/** 编辑租户管理员 */
export async function editTenantAdmin(
id: number,
payload: TenantAdminEditPayload,
): Promise<TenantAdminItem> {
const { data } = await apiClient.patch<TenantAdminItem>(
`/admin/tenant-admins/${id}`,
payload,
);
return data;
}
/** 重置密码 */
export async function resetTenantAdminPassword(
id: number,
payload: ResetPasswordPayload,
): Promise<void> {
await apiClient.post(`/admin/tenant-admins/${id}/reset-password`, payload);
}
/** 删除租户管理员(软删除) */
export async function deleteTenantAdmin(id: number): Promise<void> {
await apiClient.delete(`/admin/tenant-admins/${id}`);
}

View File

@@ -0,0 +1,62 @@
/**
* 定时任务管理 API 调用。
*/
import { apiClient } from './client';
/** 定时任务信息 */
export interface TriggerJob {
id: number;
job_type: string;
job_name: string;
trigger_condition: string;
trigger_config: Record<string, unknown> | null;
last_run_at: string | null;
next_run_at: string | null;
status: string;
description: string | null;
last_error: string | null;
created_at: string | null;
}
/** 手动执行结果 */
export interface RunJobResult {
success: boolean;
message: string;
}
/** 获取所有定时任务 */
export async function fetchTriggerJobs(): Promise<TriggerJob[]> {
const { data } = await apiClient.get<TriggerJob[]>('/trigger-jobs');
return data;
}
/** 手动执行指定任务 */
export async function runTriggerJob(jobId: number): Promise<RunJobResult> {
const { data } = await apiClient.post<RunJobResult>(`/trigger-jobs/${jobId}/run`);
return data;
}
/** 触发器配置更新请求 */
export interface UpdateTriggerConfigReq {
cron_expression?: string;
interval_seconds?: number;
}
/** 更新触发器配置cron 表达式或间隔秒数) */
export async function updateTriggerConfig(
jobId: number,
body: UpdateTriggerConfigReq,
): Promise<TriggerJob> {
const { data } = await apiClient.patch<TriggerJob>(
`/trigger-jobs/${jobId}/config`,
body,
);
return data;
}
/** 【测试】清空所有 coach_tasks */
export async function clearAllTasks(): Promise<RunJobResult> {
const { data } = await apiClient.delete<RunJobResult>('/admin/task-engine/clear-all-tasks');
return data;
}

View File

@@ -0,0 +1,23 @@
/**
* 触发器统一视图 API 调用。
*/
import { apiClient } from './client';
/** 统一触发器条目 */
export interface UnifiedTriggerItem {
id: number;
name: string;
source: 'biz' | 'ai' | 'etl';
trigger_condition: string;
status: string;
last_run_at: string | null;
next_run_at: string | null;
last_error: string | null;
}
/** 获取所有触发器统一视图 */
export async function fetchUnifiedTriggers(): Promise<UnifiedTriggerItem[]> {
const { data } = await apiClient.get<UnifiedTriggerItem[]>('/admin/triggers/unified');
return data;
}