import React from 'react'; import { CheckSquareOutlined, MenuFoldOutlined, MenuUnfoldOutlined, PaperClipOutlined, PlusOutlined, } from '@ant-design/icons'; import Attachments from '@ant-design/x/es/attachments'; import Conversations from '@ant-design/x/es/conversations'; import Sender from '@ant-design/x/es/sender'; import type { ConversationItemType } from '@ant-design/x'; import type { AttachmentsProps } from '@ant-design/x/es/attachments'; import { Button, Dropdown, Spin, Tooltip, Typography } from 'antd'; import type { MenuProps } from 'antd'; import type { AiSkill } from './types'; export interface AiChatSidebarProps { className?: string; conversationItems: ConversationItemType[]; activeConversationKey?: string; selectionMode: boolean; selectedKeys: string[]; loadingList: boolean; conversationCount: number; onActiveChange: (key: string) => void; menu?: MenuProps | ((item: ConversationItemType) => MenuProps); onStartNewConversation: () => void; onSelectAll: () => void; onInvertSelection: () => void; onDeleteSelected: () => void; onExitSelectionMode: () => void; onEnterSelectionMode: () => void; } export const AiChatSidebar: React.FC = ({ className, conversationItems, activeConversationKey, selectionMode, selectedKeys, loadingList, conversationCount, onActiveChange, menu, onStartNewConversation, onSelectAll, onInvertSelection, onDeleteSelected, onExitSelectionMode, onEnterSelectionMode, }) => { return ( ); }; export interface AiChatComposerProps { conversationTitle: string; input: string; onChange: (value: string) => void; isRequesting: boolean; onSubmit: (value: string) => void; onCancel: () => void; uploadItems: AttachmentsProps['items']; onCustomUpload: AttachmentsProps['customRequest']; onRemoveAttachment: AttachmentsProps['onRemove']; deepThinking: boolean; onDeepThinkingChange: (value: boolean) => void; lockedSkill?: AiSkill; onClearSkill: () => void; onToggleSidebar: () => void; sidebarOpen: boolean; skillMenu: MenuProps; } export const AiChatComposer: React.FC = ({ conversationTitle, input, onChange, isRequesting, onSubmit, onCancel, uploadItems, onCustomUpload, onRemoveAttachment, deepThinking, onDeepThinkingChange, lockedSkill, onClearSkill, onToggleSidebar, sidebarOpen, skillMenu, }) => { return ( <>
{ // 中文输入法合成中的回车(确认候选词)不应触发发送。 // 浏览器在 compositionend 后仍会派发 Enter keydown, // 此时 Sender 内部的 composition 标记已失效,需用 // KeyboardEvent.isComposing / keyCode 229 兜底。 if (e.nativeEvent.isComposing || e.keyCode === 229) { return false; } return undefined; }} autoSize={{ minRows: 1, maxRows: 6 }} placeholder="询问学生、考勤、宿舍或账单数据" skill={ lockedSkill ? { title: lockedSkill.name, value: lockedSkill.key, closable: { onClose: onClearSkill }, } : undefined } header={ (uploadItems ?? []).length > 0 && (
) } footer={
} /> AI 操作均在权限范围内执行,写操作需通过表单确认,重要信息请以系统记录为准
); };