aura-web/src/pages/AgentEditor/components/InitModal.tsx

232 lines
8.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { Form, Input, Modal, Button, Upload } from 'antd';
import { RocketOutlined, UploadOutlined } from '@ant-design/icons';
import { DEFAULT_AVATAR, PRESET_AVATARS, isImageUrl } from '../constants';
interface InitModalProps {
open: boolean;
onCancel: () => void;
onConfirm: (values: any) => Promise<void>;
avatarUploading: boolean;
selectedAvatar: string;
setSelectedAvatar: (url: string) => void;
agentName: string;
setAgentName: (name: string) => void;
saving: boolean;
beforeUploadInitAvatar: (file: any) => Promise<boolean>;
}
export default function InitModal({
open,
onCancel,
onConfirm,
avatarUploading,
selectedAvatar,
setSelectedAvatar,
agentName,
setAgentName,
saving,
beforeUploadInitAvatar,
}: InitModalProps) {
const [initForm] = Form.useForm();
return (
<Modal
title={null}
open={open}
onCancel={onCancel}
footer={null}
width={720}
centered
maskClosable={false}
destroyOnHidden
>
<div className="py-2">
<div style={{ marginBottom: 18 }}>
<div
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 8,
padding: '6px 12px',
borderRadius: 999,
background: 'rgba(8, 145, 178, 0.08)',
color: 'var(--color-brand)',
fontSize: 12,
fontWeight: 600,
marginBottom: 14,
}}
>
<RocketOutlined />
·
</div>
<div style={{ fontSize: 28, fontWeight: 700, color: 'var(--color-text)', marginBottom: 8, letterSpacing: '-0.02em' }}>
</div>
<div style={{ fontSize: 14.5, color: 'var(--color-text-secondary)', lineHeight: 1.75 }}>
</div>
</div>
<div className="agent-editor-modal-hero">
<div
className="agent-editor-modal-card"
style={{
padding: '22px 20px',
background: 'linear-gradient(180deg, rgba(236,253,245,0.96) 0%, rgba(240,249,255,0.96) 100%)',
}}
>
<div
className="rounded-full flex items-center justify-center text-3xl text-white font-bold shadow-xl relative transition-all duration-500 overflow-hidden ring-4 ring-white mx-auto"
style={{
width: 88,
height: 88,
background: isImageUrl(selectedAvatar) ? '#f3f4f6' : selectedAvatar,
}}
>
{isImageUrl(selectedAvatar) ? (
<img src={selectedAvatar} className="w-full h-full object-cover" alt="avatar" />
) : (
(agentName?.charAt(0) || '?').toUpperCase()
)}
</div>
<div style={{ textAlign: 'center', marginTop: 16 }}>
<div style={{ fontSize: 17, fontWeight: 700, color: 'var(--color-text)', marginBottom: 4 }}>
{agentName || '你的新智能体'}
</div>
<div style={{ fontSize: 12.5, color: 'var(--color-text-secondary)', lineHeight: 1.7 }}>
</div>
</div>
</div>
<Form
form={initForm}
layout="vertical"
onFinish={onConfirm}
onValuesChange={(changed) => {
if (changed.name !== undefined) setAgentName(changed.name);
}}
className="agent-editor-modal-card"
style={{ padding: 20 }}
>
<Form.Item
name="name"
label={
<span className="text-gray-500 font-medium" style={{ color: 'var(--color-text-secondary)' }}>
</span>
}
rules={[{ required: true, message: '请输入智能体名称' }]}
>
<Input
placeholder="给你的智能体起个名字"
size="large"
autoFocus
className="rounded-xl h-12 border-gray-200 focus:border-cyan-500"
/>
</Form.Item>
<Form.Item
name="description"
label={
<span className="text-gray-500 font-medium" style={{ color: 'var(--color-text-secondary)' }}>
</span>
}
>
<Input.TextArea
placeholder="介绍一下这个智能体是做什么的..."
rows={3}
className="rounded-xl border-gray-200 focus:border-cyan-500"
/>
</Form.Item>
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 16 }}>
{['客服助理', '内容创作', '数据分析', '私人教练'].map((label) => (
<span
key={label}
onClick={() => initForm.setFieldsValue({ description: label })}
style={{
padding: '6px 10px',
borderRadius: 999,
background: 'var(--color-surface-2)',
color: 'var(--color-text-secondary)',
fontSize: 12.5,
cursor: 'pointer',
transition: 'all 0.2s',
}}
onMouseEnter={(e) => {
e.currentTarget.style.background = 'var(--color-border)';
e.currentTarget.style.color = 'var(--color-text)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.background = 'var(--color-surface-2)';
e.currentTarget.style.color = 'var(--color-text-secondary)';
}}
>
{label}
</span>
))}
</div>
<div className="flex gap-4 pt-2">
<Button
onClick={onCancel}
className="flex-1 h-12 rounded-xl border-gray-200 text-gray-500 font-semibold hover:bg-gray-50"
>
</Button>
<Button
type="primary"
htmlType="submit"
loading={saving}
className="flex-1 h-12 rounded-xl border-none font-semibold"
>
</Button>
</div>
</Form>
</div>
<div>
<div className="text-[11px] font-bold text-gray-400 uppercase tracking-widest mb-3 px-1">
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, gap: 12 }}>
<div style={{ fontSize: 12.5, color: 'var(--color-text-secondary)' }}>
使
</div>
<Upload accept="image/png,image/jpeg,image/webp,image/gif" showUploadList={false} beforeUpload={beforeUploadInitAvatar}>
<Button icon={<UploadOutlined />} loading={avatarUploading} style={{ borderRadius: 10 }}>
</Button>
</Upload>
</div>
<div className="agent-editor-avatar-grid monica-scrollbar">
{[DEFAULT_AVATAR, ...PRESET_AVATARS].map((url) => (
<div
key={url}
onClick={() => setSelectedAvatar(url)}
className={`relative aspect-square rounded-full cursor-pointer transition-all duration-300 overflow-hidden border-2 ${selectedAvatar === url ? 'scale-110 shadow-lg z-10' : 'border-transparent opacity-70 hover:opacity-100 hover:scale-105'}`}
style={{ borderColor: selectedAvatar === url ? 'var(--color-brand)' : 'transparent' }}
>
<img src={url} className="w-full h-full object-cover" alt="preset" />
{selectedAvatar === url && (
<div
className="absolute inset-0 flex items-center justify-center"
style={{ background: 'rgba(8, 145, 178, 0.10)' }}
>
<div className="bg-white rounded-full p-0.5 shadow-sm">
<div className="w-2 h-2 rounded-full" style={{ background: 'var(--color-brand)' }} />
</div>
</div>
)}
</div>
))}
</div>
</div>
</div>
</Modal>
);
}