fix: fix style problem by fengqian

feat/unify-api-and-responsive-pages
yannyang 2026-06-26 18:00:29 +08:00
parent 4d2bc459ca
commit b013fff224
17 changed files with 343 additions and 156 deletions

View File

@ -176,7 +176,7 @@ export default function ChatPreview({ agent, agentId }: Props) {
)} )}
</div> </div>
<div className="p-4 bg-white border-t"> <div className="p-4 bg-white">
<div className="flex gap-2"> <div className="flex gap-2">
<Input.TextArea <Input.TextArea
value={input} value={input}

View File

@ -18,6 +18,7 @@ interface CapabilitySettingsProps {
beforeUploadKnowledge: (file: any) => Promise<boolean>; beforeUploadKnowledge: (file: any) => Promise<boolean>;
onDeleteKnowledge: (fileId: string) => Promise<void>; onDeleteKnowledge: (fileId: string) => Promise<void>;
markDirty: () => void; markDirty: () => void;
isMobile?: boolean;
} }
export default function CapabilitySettings({ export default function CapabilitySettings({
@ -32,6 +33,7 @@ export default function CapabilitySettings({
beforeUploadKnowledge, beforeUploadKnowledge,
onDeleteKnowledge, onDeleteKnowledge,
markDirty, markDirty,
isMobile = false,
}: CapabilitySettingsProps) { }: CapabilitySettingsProps) {
return ( return (
<div className="flex-1 agent-editor-pane"> <div className="flex-1 agent-editor-pane">
@ -55,7 +57,7 @@ export default function CapabilitySettings({
setAvatarSelectorOpen={setAvatarSelectorOpen} setAvatarSelectorOpen={setAvatarSelectorOpen}
/> />
<BasicSettingsPanel teams={teams} /> <BasicSettingsPanel teams={teams} />
<ModelSettingsCard models={models} /> <ModelSettingsCard models={models} isMobile={isMobile} />
<KnowledgeSettingsPanel <KnowledgeSettingsPanel
agent={agent} agent={agent}
beforeUploadKnowledge={beforeUploadKnowledge} beforeUploadKnowledge={beforeUploadKnowledge}

View File

@ -40,7 +40,7 @@ export default function InitModal({
open={open} open={open}
onCancel={onCancel} onCancel={onCancel}
footer={null} footer={null}
width={720} width={isMobile ? 360 : 720}
centered centered
maskClosable={false} maskClosable={false}
destroyOnHidden destroyOnHidden
@ -84,7 +84,7 @@ export default function InitModal({
onValuesChange={(changed) => { onValuesChange={(changed) => {
if (changed.name !== undefined) setAgentName(changed.name); if (changed.name !== undefined) setAgentName(changed.name);
}} }}
className="agent-editor-modal-card agent-editor-init-form" className="agent-editor-init-form"
> >
<Form.Item <Form.Item
name="name" name="name"
@ -93,7 +93,7 @@ export default function InitModal({
> >
<Input <Input
placeholder="给你的智能体起个名字" placeholder="给你的智能体起个名字"
size="large" size={isMobile ? 'middle' : 'large'}
autoFocus autoFocus
className="agent-editor-form-input" className="agent-editor-form-input"
/> />
@ -105,7 +105,7 @@ export default function InitModal({
> >
<Input.TextArea <Input.TextArea
placeholder="介绍一下这个智能体是做什么的..." placeholder="介绍一下这个智能体是做什么的..."
rows={3} rows={isMobile ? 2 : 3}
className="agent-editor-form-textarea" className="agent-editor-form-textarea"
/> />
</Form.Item> </Form.Item>
@ -140,20 +140,23 @@ export default function InitModal({
</div> </div>
<div className="agent-editor-avatar-section"> <div className="agent-editor-avatar-section">
<div className="agent-editor-avatar-heading"></div> {!isMobile && <div className="agent-editor-avatar-heading"></div>}
<div className="agent-editor-avatar-toolbar"> <div className="agent-editor-avatar-toolbar">
<div className="agent-editor-avatar-hint"> <div className="agent-editor-avatar-hint">
使 使
</div> </div>
<Upload <div className="agent-editor-avatar-upload-container">
accept="image/png,image/jpeg,image/webp,image/gif" {isMobile && <div className="agent-editor-avatar-heading"></div>}
showUploadList={false} <Upload
beforeUpload={beforeUploadInitAvatar} accept="image/png,image/jpeg,image/webp,image/gif"
> showUploadList={false}
<Button icon={<UploadOutlined />} loading={avatarUploading} className="agent-editor-upload-button"> beforeUpload={beforeUploadInitAvatar}
>
</Button> <Button icon={<UploadOutlined />} size={isMobile ? 'small' : 'middle'} loading={avatarUploading} className="agent-editor-upload-button">
</Upload>
</Button>
</Upload>
</div>
</div> </div>
<div className="agent-editor-avatar-grid monica-scrollbar"> <div className="agent-editor-avatar-grid monica-scrollbar">
{[DEFAULT_AVATAR, ...PRESET_AVATARS].map((url) => { {[DEFAULT_AVATAR, ...PRESET_AVATARS].map((url) => {

View File

@ -8,9 +8,10 @@ interface ModelCheckboxDropdownProps {
value?: string[]; value?: string[];
onChange?: (value: string[]) => void; onChange?: (value: string[]) => void;
models: AiModel[]; models: AiModel[];
isMobile?: boolean;
} }
export default function ModelCheckboxDropdown({ value = [], onChange, models }: ModelCheckboxDropdownProps) { export default function ModelCheckboxDropdown({ value = [], onChange, models, isMobile = false }: ModelCheckboxDropdownProps) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const summary = value.length ? `${value.length} 个已选` : '选择模型'; const summary = value.length ? `${value.length} 个已选` : '选择模型';
@ -20,7 +21,7 @@ export default function ModelCheckboxDropdown({ value = [], onChange, models }:
open={open} open={open}
onOpenChange={setOpen} onOpenChange={setOpen}
popupRender={() => ( popupRender={() => (
<div className="agent-model-dropdown-panel" onClick={(e) => e.stopPropagation()}> <div className={`agent-model-dropdown-panel${isMobile ? ' is-h5-panel' : ''}`} onClick={(e) => e.stopPropagation()}>
<Checkbox.Group <Checkbox.Group
value={value} value={value}
onChange={(checked) => onChange?.(checked.map((item) => String(item)))} onChange={(checked) => onChange?.(checked.map((item) => String(item)))}

View File

@ -4,9 +4,10 @@ import { FileTextOutlined } from '@ant-design/icons';
interface PromptEditorProps { interface PromptEditorProps {
form: any; form: any;
markDirty: () => void; markDirty: () => void;
isMobile?: boolean;
} }
export default function PromptEditor({ form, markDirty }: PromptEditorProps) { export default function PromptEditor({ form, markDirty, isMobile }: PromptEditorProps) {
return ( return (
<div className="flex-1 agent-editor-pane"> <div className="flex-1 agent-editor-pane">
<div className="agent-editor-pane-body"> <div className="agent-editor-pane-body">
@ -42,7 +43,7 @@ export default function PromptEditor({ form, markDirty }: PromptEditorProps) {
<div className="agent-editor-prompt"> <div className="agent-editor-prompt">
<Form.Item name="prompt" noStyle> <Form.Item name="prompt" noStyle>
<Input.TextArea <Input.TextArea
rows={30} rows={isMobile ? 10 : 30}
placeholder="在这里输入智能体的人设、技能、风格和输出规范..." placeholder="在这里输入智能体的人设、技能、风格和输出规范..."
className="agent-editor-prompt-textarea border-none focus:ring-0 bg-transparent p-4 font-mono text-sm leading-relaxed" className="agent-editor-prompt-textarea border-none focus:ring-0 bg-transparent p-4 font-mono text-sm leading-relaxed"
/> />

View File

@ -29,10 +29,10 @@ export default function BasicSettingsPanel({ teams }: BasicSettingsPanelProps) {
<span className="text-[11px] text-gray-400"></span> <span className="text-[11px] text-gray-400"></span>
</div> </div>
</div> </div>
<Form.Item name="name" label="名称" rules={[{ required: true }]} className="mb-3"> <Form.Item name="name" label="名称" rules={[{ required: true }]} className="mb-2">
<Input placeholder="智能体名称" className="agent-editor-field-input" /> <Input placeholder="智能体名称" className="agent-editor-field-input" />
</Form.Item> </Form.Item>
<Form.Item name="description" label="描述" className="mb-3"> <Form.Item name="description" label="描述" className="mb-2">
<Input.TextArea rows={3} placeholder="简短描述这个智能体是做什么的..." className="agent-editor-field-textarea" /> <Input.TextArea rows={3} placeholder="简短描述这个智能体是做什么的..." className="agent-editor-field-textarea" />
</Form.Item> </Form.Item>
<div className="flex gap-2"> <div className="flex gap-2">

View File

@ -5,9 +5,10 @@ import ModelCheckboxDropdown from '../ModelCheckboxDropdown';
interface ModelSettingsCardProps { interface ModelSettingsCardProps {
models: any[]; models: any[];
isMobile?: boolean;
} }
export default function ModelSettingsCard({ models }: ModelSettingsCardProps) { export default function ModelSettingsCard({ models, isMobile = false }: ModelSettingsCardProps) {
return ( return (
<div className="monica-card agent-editor-section-card"> <div className="monica-card agent-editor-section-card">
<div className="agent-editor-section-title"> <div className="agent-editor-section-title">
@ -31,7 +32,7 @@ export default function ModelSettingsCard({ models }: ModelSettingsCardProps) {
className="mb-0" className="mb-0"
getValueProps={(value) => ({ value: parseModelSelections(value) })} getValueProps={(value) => ({ value: parseModelSelections(value) })}
> >
<ModelCheckboxDropdown models={models} /> <ModelCheckboxDropdown models={models} isMobile={isMobile} />
</Form.Item> </Form.Item>
<Form.Item name="temperature" label="Temperature" className="mb-0" hidden> <Form.Item name="temperature" label="Temperature" className="mb-0" hidden>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">

View File

@ -86,6 +86,7 @@ export default function AgentEditor() {
beforeUploadKnowledge={beforeUploadKnowledge} beforeUploadKnowledge={beforeUploadKnowledge}
onDeleteKnowledge={handleDeleteKnowledge} onDeleteKnowledge={handleDeleteKnowledge}
markDirty={markDirty} markDirty={markDirty}
isMobile={isMobile}
/> />
<PreviewPane liveAgent={liveAgent} agentId={id} /> <PreviewPane liveAgent={liveAgent} agentId={id} />
</div> </div>

View File

@ -44,7 +44,7 @@
.agent-editor-init-modal .agent-editor-avatar-grid, .agent-editor-init-modal .agent-editor-avatar-grid,
.agent-editor-avatar-modal .agent-editor-avatar-grid { .agent-editor-avatar-modal .agent-editor-avatar-grid {
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: repeat(4, minmax(0, 1fr));
} }
.agent-editor-avatar-toolbar, .agent-editor-avatar-toolbar,

View File

@ -8,14 +8,14 @@
} }
.agent-editor-init-header { .agent-editor-init-header {
margin-bottom: 1.125rem; margin-bottom: 12px;
} }
.agent-editor-init-badge { .agent-editor-init-badge {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
margin-bottom: 0.875rem; margin-bottom: 12px;
padding: 0.375rem 0.75rem; padding: 0.375rem 0.75rem;
border-radius: 999px; border-radius: 999px;
background: rgba(0, 97, 255, 0.08); background: rgba(0, 97, 255, 0.08);
@ -24,6 +24,13 @@
font-weight: 700; font-weight: 700;
} }
.agent-editor-avatar-upload-container {
display: flex;
justify-content: space-between;
align-items: center;
}
.agent-editor-init-title { .agent-editor-init-title {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
color: var(--color-text); color: var(--color-text);
@ -31,6 +38,50 @@
font-weight: 800; font-weight: 800;
} }
.is-h5-modal {
.agent-editor-init-title {
font-size: 16px;
font-weight: 500;
line-height: 1.2;
}
.agent-editor-init-subtitle {
font-size: 12px;
line-height: 1.2;
}
.agent-editor-avatar-preview {
width: 44px;
height: 44px;
}
.agent-editor-preview-text {
margin-top: 12px;
}
.agent-editor-preview-name {
font-size: 14px;
}
.agent-editor-modal-hero {
gap: 12px;
margin-bottom: 12px;
}
.ant-form-item {
margin-bottom: 8px;
}
.agent-editor-avatar-heading {
margin-bottom: 0;
}
.agent-editor-avatar-option {
width: 44px;
height: 44px;
}
.agent-editor-preview-card {
padding: 8px;
}
}
.agent-editor-init-subtitle { .agent-editor-init-subtitle {
color: var(--color-text-secondary); color: var(--color-text-secondary);
font-size: 0.90625rem; font-size: 0.90625rem;
@ -44,10 +95,10 @@
} }
.agent-editor-modal-card { .agent-editor-modal-card {
border: 1px solid rgba(150, 177, 217, 0.32);
border-radius: 1.25rem;
background: var(--color-surface);
box-shadow: 0 18px 42px rgba(10, 28, 72, 0.08); box-shadow: 0 18px 42px rgba(10, 28, 72, 0.08);
border-radius: 12px;
border: 1px solid rgba(148, 163, 184, 0.14);
background: linear-gradient(180deg, rgba(255,255,255,0.96) 0%, rgba(248,250,252,0.88) 100%);
} }
.agent-editor-preview-card { .agent-editor-preview-card {
@ -97,13 +148,7 @@
line-height: 1.7; line-height: 1.7;
} }
.agent-editor-init-form { .agent-editor-init-form {}
padding: 12px;
}
.is-h5-modal .ant-form-item {
margin-bottom: 12px;
}
.agent-editor-form-label { .agent-editor-form-label {
color: var(--color-text-secondary); color: var(--color-text-secondary);
@ -166,7 +211,6 @@
.agent-editor-avatar-heading { .agent-editor-avatar-heading {
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
padding: 0 0.25rem;
color: #8a9ab8; color: #8a9ab8;
font-size: 0.6875rem; font-size: 0.6875rem;
font-weight: 800; font-weight: 800;
@ -210,7 +254,6 @@
position: relative; position: relative;
width: 5rem; width: 5rem;
height: 5rem; height: 5rem;
min-width: 5rem;
margin: 0 auto; margin: 0 auto;
overflow: hidden; overflow: hidden;
border: 2px solid transparent; border: 2px solid transparent;

View File

@ -113,7 +113,7 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 4px;
position: relative; /* 为右上角标签提供定位参考 */ position: relative; /* 为右上角标签提供定位参考 */
overflow: hidden; overflow: hidden;
} }
@ -166,7 +166,7 @@
.h5-agent-name { .h5-agent-name {
font-weight: 700; font-weight: 700;
font-size: 13px; font-size: 12px;
color: var(--color-text); color: var(--color-text);
margin-bottom: 0; margin-bottom: 0;
/* 支持最多展示两行 */ /* 支持最多展示两行 */
@ -175,7 +175,7 @@
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
line-height: 1.4; line-height: 1.3;
min-height: 1.4em; /* 调整为单行高度占位,因为下面加了描述 */ min-height: 1.4em; /* 调整为单行高度占位,因为下面加了描述 */
} }
@ -242,7 +242,6 @@
display: flex; display: flex;
gap: 4px; gap: 4px;
margin-top: auto; margin-top: auto;
padding-top: 8px;
border-top: 1px solid var(--color-border); border-top: 1px solid var(--color-border);
justify-content: space-around; justify-content: space-around;
} }

View File

@ -0,0 +1,94 @@
.chat-side.is-full {
width: 100%;
border: 0;
}
.chat-agent-sidebar-header {
padding: 16px;
border-bottom: 1px solid var(--color-border);
}
.chat-agent-sidebar-list {
flex: 1;
overflow-y: auto;
padding: 8px 0;
}
.chat-agent-item {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 16px;
cursor: pointer;
background: transparent;
border-left: 3px solid transparent;
transition: background 0.2s;
}
.chat-agent-item:hover {
background: var(--color-surface-2);
}
.chat-agent-item.active {
background: var(--color-surface-2);
border-left: 3px solid var(--color-brand);
}
.chat-agent-avatar-wrap {
width: 32px;
height: 32px;
border-radius: 50%;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 14px;
overflow: hidden;
flex-shrink: 0;
}
.chat-agent-avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.chat-agent-info {
flex: 1;
min-width: 0;
}
.chat-agent-name {
font-size: 14px;
color: var(--color-text);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 500;
}
.chat-agent-item.active .chat-agent-name {
font-weight: 600;
}
.chat-agent-sidebar-status {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200px;
padding: 20px;
text-align: center;
}
.chat-agent-empty-text,
.chat-agent-loading-text {
font-size: 12px;
color: var(--color-text-tertiary);
line-height: 1.6;
}
.chat-agent-loading-text {
margin-top: 8px;
}

View File

@ -1,5 +1,8 @@
import { Button } from 'antd'; import { Button, Spin, Empty } from 'antd';
import { MessageOutlined } from '@ant-design/icons';
import { useEffect, useState } from 'react';
import type { Agent } from '../../../api'; import type { Agent } from '../../../api';
import './AgentSidebar.css';
const isImageUrl = (url: string) => url?.startsWith('http') || url?.startsWith('/'); const isImageUrl = (url: string) => url?.startsWith('http') || url?.startsWith('/');
@ -8,68 +11,75 @@ export default function AgentSidebar(props: {
activeAgentId?: string; activeAgentId?: string;
onCreate: () => void; onCreate: () => void;
onSelect: (agentId: string) => void; onSelect: (agentId: string) => void;
isSidebar?: boolean;
}) { }) {
const { agentList, activeAgentId, onCreate, onSelect } = props; const { agentList, activeAgentId, onCreate, onSelect, isSidebar = true } = props;
const [loadingTimeout, setLoadingTimeout] = useState(false);
useEffect(() => {
if (agentList.length > 0) return;
const timer = setTimeout(() => {
setLoadingTimeout(true);
}, 5000);
return () => clearTimeout(timer);
}, [agentList.length]);
return ( return (
<aside className="chat-side"> <aside className={`chat-side${isSidebar ? '' : ' is-full'}`}>
<div style={{ padding: '16px', borderBottom: '1px solid var(--color-border)' }}> <div className="chat-agent-sidebar-header">
<Button block type="dashed" onClick={onCreate}> <Button block type="dashed" onClick={onCreate}>
+ +
</Button> </Button>
</div> </div>
<div style={{ flex: 1, overflowY: 'auto', padding: '8px 0' }}> <div className="chat-agent-sidebar-list">
{agentList.map((a) => { {agentList.length > 0 ? (
const isActive = a.id === activeAgentId; agentList.map((a) => {
return ( const isActive = a.id === activeAgentId;
<div return (
key={a.id}
onClick={() => onSelect(a.id)}
style={{
display: 'flex',
alignItems: 'center',
gap: 12,
padding: '10px 16px',
cursor: 'pointer',
background: isActive ? 'var(--color-surface-2)' : 'transparent',
borderLeft: `3px solid ${isActive ? 'var(--color-brand)' : 'transparent'}`,
transition: 'background 0.2s'
}}
>
<div <div
style={{ key={a.id}
width: 32, onClick={() => onSelect(a.id)}
height: 32, className={`chat-agent-item ${isActive ? 'active' : ''}`}
borderRadius: '50%',
background: a.avatar || 'var(--gradient-brand)',
color: '#fff',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: 700,
fontSize: 14,
overflow: 'hidden'
}}
> >
{isImageUrl(a.avatar) ? <img src={a.avatar} className="w-full h-full object-cover" alt="avatar" /> : (a.name?.charAt(0) || '?').toUpperCase()}
</div>
<div style={{ flex: 1, minWidth: 0 }}>
<div <div
style={{ className="chat-agent-avatar-wrap"
fontWeight: isActive ? 600 : 500, style={{ background: a.avatar || 'var(--gradient-brand)' }}
fontSize: 14,
color: 'var(--color-text)',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}
> >
{a.name} {isImageUrl(a.avatar) ? (
<img src={a.avatar} className="chat-agent-avatar-img" alt="avatar" />
) : (
(a.name?.charAt(0) || '?').toUpperCase()
)}
</div>
<div className="chat-agent-info">
<div className="chat-agent-name">
{a.name}
{!isSidebar && <MessageOutlined style={{marginLeft: 12}} />}
</div>
</div> </div>
</div> </div>
</div> );
); })
})} ) : !loadingTimeout ? (
<div className="chat-agent-sidebar-status">
<Spin />
<div className="chat-agent-loading-text">...</div>
</div>
) : (
<div className="chat-agent-sidebar-status">
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description={
<span className="chat-agent-empty-text">
<br />
</span>
}
/>
</div>
)}
</div> </div>
</aside> </aside>
); );

View File

@ -293,7 +293,7 @@ export default function ChatInput(props: {
<div className="chat-input-toolbar"> <div className="chat-input-toolbar">
<div className="chat-input-toolbar-left"> <div className="chat-input-toolbar-left">
<Select {/* <Select
value={activeModelValue || undefined} value={activeModelValue || undefined}
className="chat-model-select" className="chat-model-select"
popupMatchSelectWidth={false} popupMatchSelectWidth={false}
@ -301,7 +301,7 @@ export default function ChatInput(props: {
suffixIcon={<DownOutlined className="chat-model-select-arrow" />} suffixIcon={<DownOutlined className="chat-model-select-arrow" />}
placeholder="选择模型" placeholder="选择模型"
onChange={onChangeModel} onChange={onChangeModel}
/> /> */}
<Upload <Upload
className="chat-upload" className="chat-upload"

View File

@ -166,7 +166,8 @@ export default function ChatInputH5(props: {
return ( return (
<div className="chat-input-h5-container"> <div className="chat-input-h5-container">
{/* 顶部附件展示 */} {/* 顶部附件展示 */}
<div className="chat-input-h5-attachments"> {(attachments.length > 0 || imageUrls.length > 0) && (
<div className="chat-input-h5-attachments">
{attachments.map((a, i) => ( {attachments.map((a, i) => (
<Tag key={i} color="blue" closable className="chat-input-h5-attachment-tag" onClose={() => setAttachments((arr) => arr.filter((_, j) => j !== i))}> <Tag key={i} color="blue" closable className="chat-input-h5-attachment-tag" onClose={() => setAttachments((arr) => arr.filter((_, j) => j !== i))}>
📎 {a.name} 📎 {a.name}
@ -185,12 +186,12 @@ export default function ChatInputH5(props: {
/> />
</div> </div>
))} ))}
</div> </div>)}
{/* 模型切换与工具栏 */} {/* 模型切换与工具栏 */}
<div className="chat-input-h5-toolbar"> <div className="chat-input-h5-toolbar">
<div className="chat-input-h5-toolbar-scroll"> <div className="chat-input-h5-toolbar-scroll">
<Select {/* <Select
value={activeModelValue || undefined} value={activeModelValue || undefined}
size="small" size="small"
className="chat-input-h5-model-select" className="chat-input-h5-model-select"
@ -201,21 +202,16 @@ export default function ChatInputH5(props: {
onChange={onChangeModel} onChange={onChangeModel}
dropdownStyle={{ minWidth: 160 }} dropdownStyle={{ minWidth: 160 }}
/> />
<div className="chat-input-h5-toolbar-divider" /> <div className="chat-input-h5-toolbar-divider" /> */}
<Button size="small" className="chat-input-h5-action-icon" icon={<UserOutlined />} onClick={onOpenAgents}> <Button size="small" title="智能体" className="chat-input-h5-action-icon" icon={<UserOutlined />} onClick={onOpenAgents}>
</Button> </Button>
<Button size="small" className="chat-input-h5-action-icon" disabled={!hasAgent} icon={<UnorderedListOutlined />} onClick={onOpenOutline}> <Button size="small" title="大纲" className="chat-input-h5-action-icon" disabled={!hasAgent} icon={<UnorderedListOutlined />} onClick={onOpenOutline}>
</Button> </Button>
<Button size="small" className="chat-input-h5-action-icon" disabled={!hasId} icon={<HistoryIcon />} onClick={onOpenHistory}> <Button size="small" title="历史" className="chat-input-h5-action-icon" disabled={!hasId} icon={<HistoryIcon />} onClick={onOpenHistory}>
</Button> </Button>
<Button size="small" className="chat-input-h5-action-icon" disabled={!hasId} icon={<NewChatIcon />} onClick={onNewSession}> <Button size="small" title="新建" className="chat-input-h5-action-icon" disabled={!hasId} icon={<NewChatIcon />} onClick={onNewSession}>
</Button> </Button>
<Button size="small" className="chat-input-h5-action-icon" icon={<BookOutlined />} onClick={onOpenTpl}> <Button size="small" title="模板" className="chat-input-h5-action-icon" icon={<BookOutlined />} onClick={onOpenTpl}>
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -88,9 +88,13 @@ export default function ChatPageH5({ logic }: { logic: ChatPageLogicOutput }) {
<section className="chat-main h5-chat-main"> <section className="chat-main h5-chat-main">
{!agent ? ( {!agent ? (
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}> <AgentSidebar
<Empty description="请选择一个智能体开始对话" /> isSidebar={false}
</div> agentList={agentList}
activeAgentId={id}
onCreate={() => navigate('/agents/new')}
onSelect={(aid) => navigate(`/chat/${aid}`)}
/>
) : ( ) : (
<> <>
<ChatHeader <ChatHeader
@ -126,40 +130,40 @@ export default function ChatPageH5({ logic }: { logic: ChatPageLogicOutput }) {
}} }}
/> />
</div> </div>
<ChatInputH5
input={sender.input}
setInput={sender.setInput}
sending={sender.sending}
attachments={sender.attachments}
setAttachments={sender.setAttachments}
imageUrls={sender.imageUrls}
setImageUrls={sender.setImageUrls}
onSend={sender.handleSend}
onStop={sender.handleStop}
onAttach={sender.handleAttach}
onOpenTpl={() => setTplDrawerOpen(true)}
modelOptions={sender.modelOptions}
activeModelValue={sender.activeModelValue}
onChangeModel={(modelId: string) => {
const picked = sender.modelOptions.find((o) => o.value === modelId);
setOverrides((o: ModelOverrides) => ({
...o,
model_id: modelId,
model: picked?.label ?? o.model
}));
}}
agentList={agentList}
onInsertMention={() => { }}
onOpenHistory={() => setHistoryDrawerOpen(true)}
onNewSession={handleNewSession}
onOpenAgents={() => setAgentDrawerOpen(true)}
onOpenOutline={() => setOutlineDrawerOpen(true)}
hasAgent={!!agent}
hasId={!!id}
showActions={false}
/>
</> </>
)} )}
<ChatInputH5
input={sender.input}
setInput={sender.setInput}
sending={sender.sending}
attachments={sender.attachments}
setAttachments={sender.setAttachments}
imageUrls={sender.imageUrls}
setImageUrls={sender.setImageUrls}
onSend={sender.handleSend}
onStop={sender.handleStop}
onAttach={sender.handleAttach}
onOpenTpl={() => setTplDrawerOpen(true)}
modelOptions={sender.modelOptions}
activeModelValue={sender.activeModelValue}
onChangeModel={(modelId: string) => {
const picked = sender.modelOptions.find((o) => o.value === modelId);
setOverrides((o: ModelOverrides) => ({
...o,
model_id: modelId,
model: picked?.label ?? o.model
}));
}}
agentList={agentList}
onInsertMention={() => { }}
onOpenHistory={() => setHistoryDrawerOpen(true)}
onNewSession={handleNewSession}
onOpenAgents={() => setAgentDrawerOpen(true)}
onOpenOutline={() => setOutlineDrawerOpen(true)}
hasAgent={!!agent}
hasId={!!id}
showActions={false}
/>
</section> </section>
<ChatDrawers <ChatDrawers

View File

@ -389,7 +389,6 @@ body {
background: var(--color-surface); background: var(--color-surface);
border-radius: 14px; border-radius: 14px;
padding: 20px; padding: 20px;
border: 1px solid var(--color-border);
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -398,6 +397,13 @@ body {
box-shadow: var(--shadow-xs); box-shadow: var(--shadow-xs);
} }
.is-h5 {
.agent-card {
padding: 12px 12px 0;
gap: 4px;
}
}
.agent-card:hover { .agent-card:hover {
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: var(--shadow-md); box-shadow: var(--shadow-md);
@ -1220,11 +1226,19 @@ body {
overflow-y: auto; overflow-y: auto;
padding: 12px; padding: 12px;
background: var(--color-surface); background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 12px; border-radius: 12px;
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
} }
.is-h5-panel {
.agent-model-dropdown-panel {
padding: 8px;
}
.agent-model-checkbox-item {
padding: 8px;
}
}
.agent-model-checkbox-group { .agent-model-checkbox-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -1335,6 +1349,12 @@ body {
margin-bottom: 16px; margin-bottom: 16px;
} }
.is-h5 {
.monica-card {
border: 0;
}
}
.monica-header { .monica-header {
height: 56px; height: 56px;
border-bottom: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
@ -1382,6 +1402,17 @@ body {
padding: 22px; padding: 22px;
} }
.is-h5 {
.agent-editor-pane {
border-radius: 12px;
padding: 8px;
box-shadow: none;
}
.agent-editor-pane-body {
padding: 0;
}
}
.agent-editor-pane-header { .agent-editor-pane-header {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
@ -1419,11 +1450,10 @@ body {
} }
.agent-editor-intro { .agent-editor-intro {
border-radius: 18px; border-radius: 16px;
padding: 16px 18px; padding: 12px;
background: linear-gradient(135deg, rgba(236,253,245,0.92) 0%, rgba(240,249,255,0.92) 100%); background: linear-gradient(135deg, rgba(236,253,245,0.92) 0%, rgba(240,249,255,0.92) 100%);
border: 1px solid rgba(8, 145, 178, 0.12); margin-bottom: 12px;
margin-bottom: 16px;
} }
.agent-editor-intro-title { .agent-editor-intro-title {
@ -1446,6 +1476,14 @@ body {
box-shadow: inset 0 1px 0 rgba(255,255,255,0.65); box-shadow: inset 0 1px 0 rgba(255,255,255,0.65);
} }
.is-h5 {
.agent-editor-surface {
padding: 0;
border: 0;
box-shadow: none;
}
}
.agent-editor-prompt-wrap { .agent-editor-prompt-wrap {
padding: 12px; padding: 12px;
} }
@ -1469,12 +1507,6 @@ body {
margin-bottom: 20px; margin-bottom: 20px;
} }
.agent-editor-modal-card {
border-radius: 12px;
border: 1px solid rgba(148, 163, 184, 0.14);
background: linear-gradient(180deg, rgba(255,255,255,0.96) 0%, rgba(248,250,252,0.88) 100%);
}
.agent-editor-avatar-grid { .agent-editor-avatar-grid {
display: grid; display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-columns: repeat(6, minmax(0, 1fr));