232 lines
8.7 KiB
TypeScript
232 lines
8.7 KiB
TypeScript
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>
|
||
);
|
||
}
|