refactor(Upload/MessageEnter): 重构文件上传组件和消息输入界面
- 简化 SimpleFileUpload 组件接口,移除 disabled 和 className 属性,改为通过 type 参数控制文件类型 - 添加 slot 属性支持自定义上传按钮 - 移除不必要的上传状态管理 - 优化 MessageEnter 界面,移除素材菜单和位置功能 - 添加图片和文件上传按钮
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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}>
|
||||
|
||||
Reference in New Issue
Block a user