feat: AI 对话支持 A2UI 表单/审查/图表与 Agent 工具

This commit is contained in:
2026-08-05 17:11:00 +08:00
parent 644c35ce53
commit 0e6e3e2d96
64 changed files with 8395 additions and 6434 deletions

View File

@@ -1,7 +1,21 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { XCard, registerCatalog } from '@ant-design/x-card';
import type { ActionPayload, XAgentCommand_v0_9 } from '@ant-design/x-card';
import { Alert, Button, DatePicker, Flex, Form, Input, InputNumber, Select, Typography } from 'antd';
import {
XCard,
registerCatalog,
type ActionPayload,
type XAgentCommand_v0_9,
} from '@ant-design/x-card';
import {
Alert,
Button,
DatePicker,
Flex,
Form,
Input,
InputNumber,
Select,
Typography,
} from 'antd';
import dayjs from 'dayjs';
import type { AiFormField, AiFormSchema } from './types';
@@ -47,7 +61,11 @@ function normalizeValues(
}
interface FormPreviewProps {
form?: AiFormSchema;
form?: AiFormSchema & {
submitting?: boolean;
submitted?: boolean;
error?: string | null;
};
disabled?: boolean;
onAction?: (name: string, context: Record<string, unknown>) => void;
}
@@ -58,18 +76,14 @@ interface FormPreviewProps {
* normalized values back through the `form:submit` action.
*/
const FormPreview: React.FC<FormPreviewProps> = ({ form, disabled, onAction }) => {
const runtime = form as unknown as {
submitting?: boolean;
submitted?: boolean;
error?: string | null;
};
const submitting = Boolean(runtime.submitting);
const submitting = Boolean(form?.submitting);
const initialValues = useMemo(
() => Object.fromEntries((form?.fields ?? []).map((field) => [field.name, initialValue(field)])),
() =>
Object.fromEntries((form?.fields ?? []).map((field) => [field.name, initialValue(field)])),
[form?.fields],
);
if (!form) return null;
const finished = Boolean(runtime.submitted) || form.status === 'submitted';
const finished = Boolean(form.submitted) || form.status === 'submitted';
const handleFinish = (values: Record<string, unknown>) => {
onAction?.('form:submit', { values: normalizeValues(form.fields, values) });
@@ -124,17 +138,20 @@ const FormPreview: React.FC<FormPreviewProps> = ({ form, disabled, onAction }) =
options={field.options}
/>
) : field.type === 'date' ? (
<DatePicker className="ai-chat-dynamic-form__date" placeholder={field.placeholder} />
<DatePicker
className="ai-chat-dynamic-form__date"
placeholder={field.placeholder}
/>
) : (
<Input placeholder={field.placeholder} />
)}
</Form.Item>
))}
{runtime.error && (
{form.error && (
<Alert
type="error"
showIcon
message={runtime.error}
title={form.error}
className="ai-chat-dynamic-form__error"
/>
)}
@@ -235,5 +252,3 @@ export const DynamicForm: React.FC<DynamicFormProps> = ({ form, disabled, onSubm
</div>
);
};
export default DynamicForm;