完善自动化任务广场目标选择
自动化任务目标改为从广场发布资源获取,不再按当前空间筛选。 任务中心允许任务归档空间与发布目标空间不同,并在执行时透传组件、技能和模型参数。
This commit is contained in:
@@ -9,6 +9,7 @@ import com.xspaceagi.agent.core.adapter.dto.TryReqDto;
|
|||||||
import com.xspaceagi.agent.core.adapter.dto.WorkflowExecuteRequestDto;
|
import com.xspaceagi.agent.core.adapter.dto.WorkflowExecuteRequestDto;
|
||||||
import com.xspaceagi.agent.core.adapter.dto.config.ModelConfigDto;
|
import com.xspaceagi.agent.core.adapter.dto.config.ModelConfigDto;
|
||||||
import com.xspaceagi.agent.core.adapter.dto.config.workflow.WorkflowConfigDto;
|
import com.xspaceagi.agent.core.adapter.dto.config.workflow.WorkflowConfigDto;
|
||||||
|
import com.xspaceagi.agent.core.adapter.repository.entity.AgentComponentConfig;
|
||||||
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
|
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
|
||||||
import com.xspaceagi.agent.core.infra.component.agent.dto.AgentExecuteResult;
|
import com.xspaceagi.agent.core.infra.component.agent.dto.AgentExecuteResult;
|
||||||
import com.xspaceagi.system.application.dto.SendNotifyMessageDto;
|
import com.xspaceagi.system.application.dto.SendNotifyMessageDto;
|
||||||
@@ -84,7 +85,7 @@ public class TaskCenterApplicationServiceImpl implements TaskExecuteService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void executeWorkflowTask(MonoSink<Boolean> sink, ScheduleTaskDto scheduleTask) {
|
private void executeWorkflowTask(MonoSink<Boolean> sink, ScheduleTaskDto scheduleTask) {
|
||||||
WorkflowConfigDto workflowConfigDto = workflowApplicationService.queryPublishedWorkflowConfig(Long.parseLong(scheduleTask.getTargetId()), scheduleTask.getSpaceId(), true);
|
WorkflowConfigDto workflowConfigDto = workflowApplicationService.queryPublishedWorkflowConfig(Long.parseLong(scheduleTask.getTargetId()), null, true);
|
||||||
if (workflowConfigDto == null) {
|
if (workflowConfigDto == null) {
|
||||||
sink.error(BizException.of(ErrorCodeEnum.INVALID_PARAM, BizExceptionCodeEnum.agentWorkflowOffline));
|
sink.error(BizException.of(ErrorCodeEnum.INVALID_PARAM, BizExceptionCodeEnum.agentWorkflowOffline));
|
||||||
return;
|
return;
|
||||||
@@ -133,13 +134,22 @@ public class TaskCenterApplicationServiceImpl implements TaskExecuteService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
mergeSelectedComponents(selectedComponents, params.get("selectedComponents"));
|
||||||
TryReqDto tryReqDto = new TryReqDto();
|
TryReqDto tryReqDto = new TryReqDto();
|
||||||
tryReqDto.setDebug(false);
|
tryReqDto.setDebug(false);
|
||||||
tryReqDto.setConversationId(conversation.getId());
|
tryReqDto.setConversationId(conversation.getId());
|
||||||
tryReqDto.setMessage(params.get("message").toString());
|
tryReqDto.setMessage(params.get("message").toString());
|
||||||
tryReqDto.setSelectedComponents(selectedComponents);
|
tryReqDto.setSelectedComponents(selectedComponents);
|
||||||
|
List<Long> skillIds = toLongList(params.get("skillIds"));
|
||||||
|
if (!skillIds.isEmpty()) {
|
||||||
|
tryReqDto.setSkillIds(skillIds);
|
||||||
|
}
|
||||||
|
Long modelId = toLong(params.get("modelId"));
|
||||||
|
if (modelId != null) {
|
||||||
|
tryReqDto.setModelId(modelId);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (YesOrNoEnum.Y.getKey().equals(conversation.getAgent().getAllowOtherModel())) {
|
if (tryReqDto.getModelId() == null && YesOrNoEnum.Y.getKey().equals(conversation.getAgent().getAllowOtherModel())) {
|
||||||
List<ModelConfigDto> modelConfigDtos = agentApplicationService.queryUserCanSelectModelListForAgent(conversation.getUserId(), conversation.getAgentId());
|
List<ModelConfigDto> modelConfigDtos = agentApplicationService.queryUserCanSelectModelListForAgent(conversation.getUserId(), conversation.getAgentId());
|
||||||
if (!CollectionUtils.isEmpty(modelConfigDtos)) {
|
if (!CollectionUtils.isEmpty(modelConfigDtos)) {
|
||||||
tryReqDto.setModelId(modelConfigDtos.get(0).getId());
|
tryReqDto.setModelId(modelConfigDtos.get(0).getId());
|
||||||
@@ -154,6 +164,94 @@ public class TaskCenterApplicationServiceImpl implements TaskExecuteService {
|
|||||||
executeAgentTask0(sink, requestContext, tryReqDto, scheduleTask, 0);
|
executeAgentTask0(sink, requestContext, tryReqDto, scheduleTask, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mergeSelectedComponents(List<TryReqDto.SelectedComponentDto> selectedComponents, Object rawSelectedComponents) {
|
||||||
|
if (!(rawSelectedComponents instanceof Collection<?> rawList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> existing = new HashSet<>();
|
||||||
|
for (TryReqDto.SelectedComponentDto item : selectedComponents) {
|
||||||
|
if (item.getId() != null && item.getType() != null) {
|
||||||
|
existing.add(item.getType().name() + ":" + item.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Object rawItem : rawList) {
|
||||||
|
TryReqDto.SelectedComponentDto selectedComponentDto = parseSelectedComponent(rawItem);
|
||||||
|
if (selectedComponentDto == null || selectedComponentDto.getId() == null || selectedComponentDto.getType() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String key = selectedComponentDto.getType().name() + ":" + selectedComponentDto.getId();
|
||||||
|
if (existing.add(key)) {
|
||||||
|
selectedComponents.add(selectedComponentDto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TryReqDto.SelectedComponentDto parseSelectedComponent(Object rawItem) {
|
||||||
|
if (rawItem instanceof TryReqDto.SelectedComponentDto selectedComponentDto) {
|
||||||
|
return selectedComponentDto.getId() != null && selectedComponentDto.getType() != null ? selectedComponentDto : null;
|
||||||
|
}
|
||||||
|
if (!(rawItem instanceof Map<?, ?> map)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Long id = toLong(map.get("id"));
|
||||||
|
AgentComponentConfig.Type type = toComponentType(map.get("type"));
|
||||||
|
if (id == null || type == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TryReqDto.SelectedComponentDto selectedComponentDto = new TryReqDto.SelectedComponentDto();
|
||||||
|
selectedComponentDto.setId(id);
|
||||||
|
selectedComponentDto.setType(type);
|
||||||
|
return selectedComponentDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AgentComponentConfig.Type toComponentType(Object value) {
|
||||||
|
if (value instanceof AgentComponentConfig.Type type) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String typeName = value.toString();
|
||||||
|
for (AgentComponentConfig.Type type : AgentComponentConfig.Type.values()) {
|
||||||
|
if (type.name().equalsIgnoreCase(typeName)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Long> toLongList(Object value) {
|
||||||
|
if (!(value instanceof Collection<?> collection)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<Long> result = new ArrayList<>();
|
||||||
|
for (Object item : collection) {
|
||||||
|
Long parsed = toLong(item);
|
||||||
|
if (parsed != null) {
|
||||||
|
result.add(parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long toLong(Object value) {
|
||||||
|
if (value instanceof Number number) {
|
||||||
|
return number.longValue();
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String text = value.toString();
|
||||||
|
if (text.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Long.parseLong(text);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void executeAgentTask0(MonoSink<Boolean> sink, RequestContext<Object> requestContext, TryReqDto tryReqDto, ScheduleTaskDto scheduleTask, int times) {
|
private void executeAgentTask0(MonoSink<Boolean> sink, RequestContext<Object> requestContext, TryReqDto tryReqDto, ScheduleTaskDto scheduleTask, int times) {
|
||||||
RequestContext.set(requestContext);
|
RequestContext.set(requestContext);
|
||||||
AtomicBoolean retry = new AtomicBoolean(false);
|
AtomicBoolean retry = new AtomicBoolean(false);
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ public class TaskCenterController {
|
|||||||
if (publishedDto == null) {
|
if (publishedDto == null) {
|
||||||
return ReqResult.error("Target object does not exist or has been removed");
|
return ReqResult.error("Target object does not exist or has been removed");
|
||||||
}
|
}
|
||||||
if (!publishedDto.getSpaceId().equals(scheduleTaskAddDto.getSpaceId())) {
|
|
||||||
return ReqResult.error("Target object space ID does not match task space ID");
|
|
||||||
}
|
|
||||||
ScheduleTaskDto scheduleTaskDto = new ScheduleTaskDto();
|
ScheduleTaskDto scheduleTaskDto = new ScheduleTaskDto();
|
||||||
BeanUtils.copyProperties(scheduleTaskAddDto, scheduleTaskDto);
|
BeanUtils.copyProperties(scheduleTaskAddDto, scheduleTaskDto);
|
||||||
scheduleTaskDto.setTaskId(UUID.randomUUID().toString().replace("-", ""));
|
scheduleTaskDto.setTaskId(UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,432 @@
|
|||||||
|
import { message } from "antd";
|
||||||
|
import {
|
||||||
|
AUTH_KEYS,
|
||||||
|
DEFAULT_API_TIMEOUT,
|
||||||
|
DEFAULT_SERVER_HOST,
|
||||||
|
} from "@shared/constants";
|
||||||
|
import { getDomainTokenKey } from "@shared/utils/domain";
|
||||||
|
import { normalizeServerHost } from "./auth";
|
||||||
|
import type { AiManualComponent } from "./aiChat";
|
||||||
|
|
||||||
|
const SUCCESS_CODE = "0000";
|
||||||
|
|
||||||
|
interface ApiResponse<T> {
|
||||||
|
code: string;
|
||||||
|
message?: string;
|
||||||
|
data: T;
|
||||||
|
success?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RequestOptions {
|
||||||
|
method?: "GET" | "POST";
|
||||||
|
data?: unknown;
|
||||||
|
showError?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationPageResult<T> {
|
||||||
|
records: T[];
|
||||||
|
total: number;
|
||||||
|
size?: number;
|
||||||
|
current?: number;
|
||||||
|
pages?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationSpace {
|
||||||
|
id: number;
|
||||||
|
name?: string;
|
||||||
|
spaceName?: string;
|
||||||
|
icon?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationCronItem {
|
||||||
|
cron?: string;
|
||||||
|
desc?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationCronGroup {
|
||||||
|
typeName: string;
|
||||||
|
items: AutomationCronItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AutomationTargetType = "Agent" | "Workflow";
|
||||||
|
|
||||||
|
export interface AutomationTarget {
|
||||||
|
id: number;
|
||||||
|
targetId: number;
|
||||||
|
targetType: AutomationTargetType;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
category?: string;
|
||||||
|
spaceId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationArgDetail {
|
||||||
|
key?: string | number;
|
||||||
|
name?: string;
|
||||||
|
displayName?: string;
|
||||||
|
description?: string;
|
||||||
|
dataType?: string;
|
||||||
|
inputType?: string;
|
||||||
|
require?: boolean;
|
||||||
|
required?: boolean;
|
||||||
|
enable?: boolean;
|
||||||
|
bindValue?: string | number | boolean | null;
|
||||||
|
children?: AutomationArgDetail[];
|
||||||
|
subArgs?: AutomationArgDetail[];
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationAgentDetail extends AutomationTarget {
|
||||||
|
variables?: AutomationArgDetail[];
|
||||||
|
manualComponents?: AiManualComponent[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationWorkflowDetail extends AutomationTarget {
|
||||||
|
inputArgs?: AutomationArgDetail[];
|
||||||
|
outputArgs?: AutomationArgDetail[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AutomationTaskStatus =
|
||||||
|
| "CREATE"
|
||||||
|
| "EXECUTING"
|
||||||
|
| "CONTINUE"
|
||||||
|
| "OVERFLOW_MAX_EXEC_TIMES"
|
||||||
|
| "COMPLETE"
|
||||||
|
| "FAIL"
|
||||||
|
| "CANCEL"
|
||||||
|
| string;
|
||||||
|
|
||||||
|
export interface AutomationTask {
|
||||||
|
id: number;
|
||||||
|
spaceId: number;
|
||||||
|
targetName?: string;
|
||||||
|
targetIcon?: string;
|
||||||
|
targetType: AutomationTargetType;
|
||||||
|
targetId: string;
|
||||||
|
taskName: string;
|
||||||
|
taskId?: string;
|
||||||
|
cron?: string | null;
|
||||||
|
params?: Record<string, unknown>;
|
||||||
|
status?: AutomationTaskStatus;
|
||||||
|
latestExecTime?: string | null;
|
||||||
|
lockTime?: string | null;
|
||||||
|
execTimes?: number;
|
||||||
|
maxExecTimes?: number | null;
|
||||||
|
keepConversation?: 0 | 1;
|
||||||
|
error?: string;
|
||||||
|
modified?: string;
|
||||||
|
created?: string;
|
||||||
|
creator?: {
|
||||||
|
userId?: number;
|
||||||
|
userName?: string;
|
||||||
|
avatar?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationSelectedComponent {
|
||||||
|
id: number;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationTaskCreateParams {
|
||||||
|
id?: number;
|
||||||
|
spaceId: number;
|
||||||
|
targetType: AutomationTargetType;
|
||||||
|
targetId: string;
|
||||||
|
taskName: string;
|
||||||
|
cron: string | null;
|
||||||
|
lockTime?: number | null;
|
||||||
|
maxExecTimes?: number | null;
|
||||||
|
keepConversation?: 0 | 1;
|
||||||
|
params: {
|
||||||
|
message?: string;
|
||||||
|
variables?: Record<string, unknown>;
|
||||||
|
selectedComponents?: AutomationSelectedComponent[];
|
||||||
|
skillIds?: number[];
|
||||||
|
modelId?: number | null;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationRunLog {
|
||||||
|
id: string;
|
||||||
|
requestId?: string;
|
||||||
|
spaceId?: number;
|
||||||
|
userId?: number;
|
||||||
|
userName?: string;
|
||||||
|
targetType?: string;
|
||||||
|
targetName?: string;
|
||||||
|
targetId?: string;
|
||||||
|
input?: string;
|
||||||
|
output?: string;
|
||||||
|
status?: string;
|
||||||
|
elapsedTime?: number;
|
||||||
|
created?: string;
|
||||||
|
requestTime?: string;
|
||||||
|
startTime?: string;
|
||||||
|
endTime?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
icon: string;
|
||||||
|
prompt: string;
|
||||||
|
cronHint?: "daily" | "weekly" | "once";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBaseUrl(): Promise<string> {
|
||||||
|
const config = (await window.electronAPI?.settings.get(
|
||||||
|
AUTH_KEYS.STEP1_CONFIG,
|
||||||
|
)) as { serverHost?: string } | null;
|
||||||
|
|
||||||
|
return normalizeServerHost(config?.serverHost || DEFAULT_SERVER_HOST);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAuthToken(domain: string): Promise<string | null> {
|
||||||
|
const oneShotToken = (await window.electronAPI?.settings.get(
|
||||||
|
AUTH_KEYS.AUTH_TOKEN,
|
||||||
|
)) as string | null;
|
||||||
|
if (oneShotToken) return oneShotToken;
|
||||||
|
|
||||||
|
const domainTokenKey = getDomainTokenKey(domain);
|
||||||
|
return (await window.electronAPI?.settings.get(domainTokenKey)) as
|
||||||
|
| string
|
||||||
|
| null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAssetUrl(
|
||||||
|
baseUrl: string,
|
||||||
|
value?: string,
|
||||||
|
): string | undefined {
|
||||||
|
if (!value) return value;
|
||||||
|
if (/^(https?:)?\/\//i.test(value) || value.startsWith("data:")) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new URL(value, baseUrl).toString();
|
||||||
|
} catch {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function automationRequest<T>(
|
||||||
|
path: string,
|
||||||
|
options: RequestOptions = {},
|
||||||
|
): Promise<T> {
|
||||||
|
const baseUrl = await getBaseUrl();
|
||||||
|
const token = await getAuthToken(baseUrl);
|
||||||
|
const response = await fetch(`${baseUrl}${path}`, {
|
||||||
|
method: options.method || "GET",
|
||||||
|
credentials: "include",
|
||||||
|
cache: "no-store",
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json, text/plain, */*",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||||
|
},
|
||||||
|
signal: AbortSignal.timeout(DEFAULT_API_TIMEOUT),
|
||||||
|
...(options.data !== undefined
|
||||||
|
? { body: JSON.stringify(options.data) }
|
||||||
|
: {}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
if (options.showError !== false) message.error(error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = (await response.json()) as ApiResponse<T>;
|
||||||
|
if (result.code !== SUCCESS_CODE) {
|
||||||
|
const errorMessage = result.message || "请求失败";
|
||||||
|
if (options.showError !== false) message.error(errorMessage);
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeTarget<T extends AutomationTarget>(
|
||||||
|
baseUrl: string,
|
||||||
|
item: T,
|
||||||
|
targetType: AutomationTargetType,
|
||||||
|
): T {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
targetType,
|
||||||
|
targetId: item.targetId || item.id,
|
||||||
|
icon: normalizeAssetUrl(baseUrl, item.icon),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationSpaces(): Promise<AutomationSpace[]> {
|
||||||
|
return automationRequest<AutomationSpace[]>("/api/space/list", {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationTasks(
|
||||||
|
spaceId: number,
|
||||||
|
): Promise<AutomationTask[]> {
|
||||||
|
const baseUrl = await getBaseUrl();
|
||||||
|
const tasks = await automationRequest<AutomationTask[]>(
|
||||||
|
`/api/task/list/${spaceId}`,
|
||||||
|
{ method: "POST" },
|
||||||
|
);
|
||||||
|
|
||||||
|
return (tasks || []).map((task) => ({
|
||||||
|
...task,
|
||||||
|
targetIcon: normalizeAssetUrl(baseUrl, task.targetIcon),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createAutomationTask(
|
||||||
|
params: AutomationTaskCreateParams,
|
||||||
|
): Promise<AutomationTask> {
|
||||||
|
return automationRequest<AutomationTask>("/api/task/create", {
|
||||||
|
method: "POST",
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateAutomationTask(
|
||||||
|
params: AutomationTaskCreateParams & { id: number },
|
||||||
|
): Promise<void> {
|
||||||
|
await automationRequest<null>("/api/task/update", {
|
||||||
|
method: "POST",
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function executeAutomationTask(id: number): Promise<void> {
|
||||||
|
await automationRequest<null>(`/api/task/execute/${id}`, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function enableAutomationTask(id: number): Promise<void> {
|
||||||
|
await automationRequest<null>(`/api/task/enable/${id}`, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function disableAutomationTask(id: number): Promise<void> {
|
||||||
|
await automationRequest<null>(`/api/task/cancel/${id}`, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteAutomationTask(id: number): Promise<void> {
|
||||||
|
await automationRequest<null>(`/api/task/delete/${id}`, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationCronList(): Promise<
|
||||||
|
AutomationCronGroup[]
|
||||||
|
> {
|
||||||
|
return automationRequest<AutomationCronGroup[]>("/api/task/cron/list", {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationTargets(params: {
|
||||||
|
targetType: AutomationTargetType;
|
||||||
|
kw?: string;
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
}): Promise<AutomationPageResult<AutomationTarget>> {
|
||||||
|
const baseUrl = await getBaseUrl();
|
||||||
|
const path =
|
||||||
|
params.targetType === "Agent"
|
||||||
|
? "/api/published/agent/list"
|
||||||
|
: "/api/published/workflow/list";
|
||||||
|
const page = await automationRequest<AutomationPageResult<AutomationTarget>>(
|
||||||
|
path,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
data: {
|
||||||
|
page: params.page || 1,
|
||||||
|
pageSize: params.pageSize || 50,
|
||||||
|
kw: params.kw || undefined,
|
||||||
|
...(params.targetType === "Agent"
|
||||||
|
? { targetType: "Agent", targetSubType: "ChatBot" }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
showError: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...page,
|
||||||
|
records: (page.records || []).map((item) =>
|
||||||
|
normalizeTarget(baseUrl, item, params.targetType),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationAgentDetail(
|
||||||
|
agentId: number,
|
||||||
|
): Promise<AutomationAgentDetail> {
|
||||||
|
const baseUrl = await getBaseUrl();
|
||||||
|
const detail = await automationRequest<AutomationAgentDetail>(
|
||||||
|
`/api/published/agent/${agentId}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return normalizeTarget(baseUrl, detail, "Agent");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationWorkflowDetail(
|
||||||
|
workflowId: number,
|
||||||
|
): Promise<AutomationWorkflowDetail> {
|
||||||
|
const baseUrl = await getBaseUrl();
|
||||||
|
const detail = await automationRequest<AutomationWorkflowDetail>(
|
||||||
|
`/api/published/workflow/${workflowId}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return normalizeTarget(baseUrl, detail, "Workflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationRunLogs(params: {
|
||||||
|
targetType: string;
|
||||||
|
targetId: string | number;
|
||||||
|
current?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
}): Promise<AutomationPageResult<AutomationRunLog>> {
|
||||||
|
return automationRequest<AutomationPageResult<AutomationRunLog>>(
|
||||||
|
"/api/requestLogs/list",
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
data: {
|
||||||
|
current: params.current || 1,
|
||||||
|
pageSize: params.pageSize || 10,
|
||||||
|
queryFilter: {
|
||||||
|
targetType: params.targetType,
|
||||||
|
targetId: String(params.targetId),
|
||||||
|
from: "task_center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
showError: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAutomationRunLogDetail(
|
||||||
|
id: string,
|
||||||
|
): Promise<AutomationRunLog> {
|
||||||
|
return automationRequest<AutomationRunLog>("/api/requestLogs/detail", {
|
||||||
|
method: "POST",
|
||||||
|
data: { id },
|
||||||
|
showError: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,445 @@
|
|||||||
|
.page {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fbfaf8;
|
||||||
|
color: #1f211f;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 36px 32px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
color: #171817;
|
||||||
|
font-size: 30px;
|
||||||
|
line-height: 38px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header p {
|
||||||
|
margin: 14px 0 0;
|
||||||
|
color: #2f312f;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerActions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerActions :global(.ant-btn) {
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 0 32px 36px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionTitle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 0 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionTitle h2 {
|
||||||
|
margin: 0;
|
||||||
|
color: #686b66;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 26px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionTitle span {
|
||||||
|
color: #9b9e98;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emptyState {
|
||||||
|
min-height: 320px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskList {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskItem {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 18px minmax(0, 1fr) auto 36px 36px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
min-height: 58px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusDot {
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
margin-left: 4px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #777a74;
|
||||||
|
}
|
||||||
|
|
||||||
|
.running {
|
||||||
|
background: #1677ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.waiting {
|
||||||
|
background: #74776f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
background: #00a870;
|
||||||
|
}
|
||||||
|
|
||||||
|
.failed {
|
||||||
|
background: #d9363e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ended {
|
||||||
|
background: #c7c9c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskMain {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskTitleRow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskTitleRow strong {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #20211f;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskTitleRow span,
|
||||||
|
.taskMetaRow span {
|
||||||
|
max-width: 220px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #70736d;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskTitleRow span {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border: 1px solid #e4e1da;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskMetaRow {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskMetaRow span {
|
||||||
|
padding: 3px 8px;
|
||||||
|
border: 1px solid #e8e5de;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f7f6f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskNext {
|
||||||
|
color: #656862;
|
||||||
|
font-size: 15px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templateGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templateCard {
|
||||||
|
min-height: 108px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 56px minmax(0, 1fr);
|
||||||
|
align-items: center;
|
||||||
|
gap: 18px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
border: 1px solid #e6e3dc;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: inherit;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
transition:
|
||||||
|
border-color 0.18s ease,
|
||||||
|
box-shadow 0.18s ease,
|
||||||
|
transform 0.18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templateCard:hover {
|
||||||
|
border-color: #d8d3c8;
|
||||||
|
box-shadow: 0 10px 24px rgba(31, 33, 31, 0.07);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.templateIcon {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #73766f;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templateCard strong {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #171817;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 28px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templateCard small {
|
||||||
|
display: -webkit-box;
|
||||||
|
margin-top: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #5f625d;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 22px;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskModal :global(.ant-modal-content) {
|
||||||
|
border-radius: 18px;
|
||||||
|
padding: 34px 40px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskModal :global(.ant-modal-header) {
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskModal :global(.ant-modal-title) {
|
||||||
|
color: #1c1d1b;
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 36px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskModal :global(.ant-modal-footer) {
|
||||||
|
margin-top: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskModal :global(.ant-modal-footer .ant-btn) {
|
||||||
|
min-width: 144px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskModal :global(.ant-modal-footer .ant-btn-primary) {
|
||||||
|
background: #111111;
|
||||||
|
border-color: #111111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskForm {
|
||||||
|
max-height: min(70vh, 800px);
|
||||||
|
padding-right: 10px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskForm :global(.ant-form-item-label > label) {
|
||||||
|
color: #686b66;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskForm :global(.ant-input),
|
||||||
|
.taskForm :global(.ant-input-affix-wrapper),
|
||||||
|
.taskForm :global(.ant-select-selector),
|
||||||
|
.taskForm :global(.ant-picker) {
|
||||||
|
border-radius: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineFields {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(220px, 0.7fr) minmax(280px, 1.3fr);
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promptInput {
|
||||||
|
min-height: 210px !important;
|
||||||
|
border-color: #9a9c98 !important;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promptTools {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin: -10px 0 22px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolSelect {
|
||||||
|
min-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolSelectWide {
|
||||||
|
min-width: 280px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variablePanel {
|
||||||
|
margin: 8px 0 20px;
|
||||||
|
padding: 18px;
|
||||||
|
border: 1px solid #e8e4dc;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formSubTitle {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #323431;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frequencyBlock {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullWidth {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logList {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logItem {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border: 1px solid #e7e3dc;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: inherit;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logItem strong {
|
||||||
|
color: #20211f;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logItem span,
|
||||||
|
.logItem small {
|
||||||
|
overflow: hidden;
|
||||||
|
color: #777b74;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logDetail {
|
||||||
|
margin-top: 22px;
|
||||||
|
padding-top: 18px;
|
||||||
|
border-top: 1px solid #ece8e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logDetail h3 {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logDetail pre {
|
||||||
|
max-height: 360px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 14px;
|
||||||
|
overflow: auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #f6f5f2;
|
||||||
|
color: #30322f;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1180px) {
|
||||||
|
.templateGrid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 860px) {
|
||||||
|
.header {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerActions {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar,
|
||||||
|
.sectionTitle {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskItem {
|
||||||
|
grid-template-columns: 18px minmax(0, 1fr) 36px 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskNext {
|
||||||
|
grid-column: 2 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templateGrid,
|
||||||
|
.inlineFields {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user