refactor(Upload/MessageEnter): 重构文件上传组件和消息输入界面

- 简化 SimpleFileUpload 组件接口,移除 disabled 和 className 属性,改为通过 type 参数控制文件类型
- 添加 slot 属性支持自定义上传按钮
- 移除不必要的上传状态管理
- 优化 MessageEnter 界面,移除素材菜单和位置功能
- 添加图片和文件上传按钮
This commit is contained in:
超级老白兔
2025-09-09 16:53:11 +08:00
parent d0953585a7
commit c4866e3865
2 changed files with 38 additions and 121 deletions

View File

@@ -5,21 +5,25 @@ import { uploadFile } from "@/api/common";
interface SimpleFileUploadProps {
onFileUploaded?: (filePath: string) => void;
disabled?: boolean;
className?: string;
maxSize?: number; // 最大文件大小(MB)
accept?: string; // 接受的文件类型
type?: number; // 1: 图片, 2: 视频, 3: 音频, 4: 文件
slot?: React.ReactNode;
}
const SimpleFileUpload: React.FC<SimpleFileUploadProps> = ({
onFileUploaded,
disabled = false,
className,
maxSize = 50,
accept = "*/*",
slot,
type = 4,
}) => {
const fileInputRef = useRef<HTMLInputElement>(null);
const [uploading, setUploading] = useState(false);
const accept = {
1: "image/*",
2: "video/*",
3: "audio/*",
4: "*/*",
};
// 验证文件
const validateFile = (file: File): boolean => {
@@ -46,8 +50,6 @@ const SimpleFileUpload: React.FC<SimpleFileUploadProps> = ({
return;
}
setUploading(true);
try {
const fileUrl = await uploadFile(file);
onFileUploaded?.(fileUrl);
@@ -56,7 +58,6 @@ const SimpleFileUpload: React.FC<SimpleFileUploadProps> = ({
console.error("文件上传失败:", error);
message.error(error.message || "文件上传失败");
} finally {
setUploading(false);
if (fileInputRef.current) {
fileInputRef.current.value = "";
}
@@ -64,7 +65,6 @@ const SimpleFileUpload: React.FC<SimpleFileUploadProps> = ({
};
const handleClick = () => {
if (disabled || uploading) return;
fileInputRef.current?.click();
};
@@ -73,17 +73,11 @@ const SimpleFileUpload: React.FC<SimpleFileUploadProps> = ({
<input
ref={fileInputRef}
type="file"
accept={accept}
accept={accept[type]}
onChange={handleFileSelect}
style={{ display: "none" }}
/>
<Button
type="text"
icon={uploading ? <LoadingOutlined /> : <FolderOutlined />}
onClick={handleClick}
disabled={disabled || uploading}
className={className}
/>
<span onClick={handleClick}>{slot}</span>
</>
);
};

View File

@@ -1,13 +1,12 @@
import React, { useState } from "react";
import { Layout, Input, Button, Dropdown, Menu, Tooltip, Modal } from "antd";
import { Layout, Input, Button, Tooltip, Modal } from "antd";
import {
ShareAltOutlined,
SendOutlined,
AudioOutlined,
CodeSandboxOutlined,
FolderOutlined,
PictureOutlined,
MessageOutlined,
EnvironmentOutlined,
StarOutlined,
} from "@ant-design/icons";
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
import { useWebSocketStore } from "@/store/module/websocket/websocket";
@@ -52,46 +51,6 @@ const MessageEnter: React.FC<MessageEnterProps> = ({ contract }) => {
// Ctrl+Enter 换行由 TextArea 自动处理,不需要阻止默认行为
};
// 素材菜单项
const materialMenuItems = [
{
key: "text",
label: "文字素材",
icon: <span>📝</span>,
},
{
key: "audio",
label: "语音素材",
icon: <span>🎵</span>,
},
{
key: "image",
label: "图片素材",
icon: <span>🖼</span>,
},
{
key: "video",
label: "视频素材",
icon: <span>🎬</span>,
},
{
key: "link",
label: "链接素材",
icon: <span>🔗</span>,
},
{
key: "card",
label: "名片素材",
icon: <span>📇</span>,
},
];
const handleMaterialSelect = (key: string) => {
console.log("选择素材类型:", key);
setShowMaterialModal(true);
// 这里可以根据不同的素材类型显示不同的模态框
};
// 处理表情选择
const handleEmojiSelect = (emoji: EmojiInfo) => {
setInputValue(prevValue => prevValue + `[${emoji.name}]`);
@@ -161,24 +120,29 @@ const MessageEnter: React.FC<MessageEnterProps> = ({ contract }) => {
<EmojiPicker onEmojiSelect={handleEmojiSelect} />
<SimpleFileUpload
onFileUploaded={handleFileUploaded}
className={styles.toolbarButton}
maxSize={50}
accept="*/*"
maxSize={1}
type={4}
slot={
<Button
className={styles.toolbarButton}
type="text"
icon={<FolderOutlined />}
/>
}
/>
<Tooltip title="收藏">
<Button
type="text"
icon={<StarOutlined />}
className={styles.toolbarButton}
/>
</Tooltip>
<Tooltip title="位置">
<Button
type="text"
icon={<EnvironmentOutlined />}
className={styles.toolbarButton}
/>
</Tooltip>
<SimpleFileUpload
onFileUploaded={handleFileUploaded}
maxSize={1}
type={1}
slot={
<Button
className={styles.toolbarButton}
type="text"
icon={<PictureOutlined />}
/>
}
/>
<Tooltip title="语音">
<Button
type="text"
@@ -186,47 +150,6 @@ const MessageEnter: React.FC<MessageEnterProps> = ({ contract }) => {
className={styles.toolbarButton}
/>
</Tooltip>
<Tooltip title="按住说话">
<Button
type="text"
icon={<AudioOutlined />}
className={styles.toolbarButton}
style={{ position: "relative" }}
>
<span
style={{
position: "absolute",
top: "2px",
right: "2px",
fontSize: "8px",
color: "#52c41a",
fontWeight: "bold",
}}
>
H
</span>
</Button>
</Tooltip>
<Dropdown
overlay={
<Menu
items={materialMenuItems}
onClick={({ key }) => handleMaterialSelect(key)}
style={{
borderRadius: "8px",
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
}}
/>
}
trigger={["click"]}
placement="topLeft"
>
<Button
type="text"
icon={<CodeSandboxOutlined />}
className={styles.toolbarButton}
/>
</Dropdown>
</div>
<div className={styles.rightTool}>
<div className={styles.rightToolItem}>