refactor: 移除测试相关代码及组件

fix(websocket): 禁用所有Toast提示以优化用户体验

删除开发环境下的测试路由、页面及组件,清理不再使用的代码。同时修改websocket模块,移除所有Toast提示以避免干扰用户操作。
This commit is contained in:
超级老白兔
2025-09-11 17:23:47 +08:00
parent dd2f58dc78
commit 1e34ecffc2
8 changed files with 19 additions and 1418 deletions

View File

@@ -1,111 +0,0 @@
# 上传组件测试页面
## 功能说明
这是一个完整的上传组件测试页面,用于演示和测试各种上传组件的功能。
## 包含的组件
### 1. 图片上传组件 (UploadComponent)
- 支持多图片上传
- 可设置最大上传数量
- 文件类型验证
- 文件大小限制 (5MB)
- 删除确认功能
### 2. 头像上传组件 (AvatarUpload)
- 圆形头像显示
- 支持尺寸调节
- 单张图片上传
- 悬停效果
### 3. 视频上传组件 (VideoUpload)
- 支持视频文件上传
- 文件大小限制 (50MB)
- 上传进度显示
## 测试功能
### 控制面板
- 图片上传数量限制调节 (1-20张)
- 头像尺寸调节 (60-200px)
- 各组件禁用状态切换
### 表单集成测试
- 模拟真实表单场景
- 包含文本输入、文本域、图片、头像、视频上传
- 展示组件在表单中的使用方式
### 操作功能
- 提交表单数据 (输出到控制台)
- 加载模拟数据
- 重置所有数据
- 页面刷新功能
### 数据展示
- 实时显示所有组件的当前状态
- JSON格式展示便于调试
## 使用Layout组件
页面使用了Layout组件进行布局包含
1. **自定义头部**
- 返回按钮
- 页面标题和图标
- 搜索功能
- 刷新功能
2. **主要内容区域**
- 响应式设计
- 滚动支持
- 加载状态显示
3. **样式特点**
- 响应式设计
- 暗色主题支持
- 现代化UI设计
## 访问方式
访问路径:`/mobile/test/upload`
## 开发说明
### 文件结构
```
src/pages/mobile/test/
├── upload.tsx # 主测试页面
├── upload.module.scss # 样式文件
└── README.md # 说明文档
```
### 依赖组件
- Layout: 页面布局组件
- PopupHeader: 头部搜索组件
- UploadComponent: 图片上传组件
- AvatarUpload: 头像上传组件
- VideoUpload: 视频上传组件
### 技术栈
- React 18
- TypeScript
- Antd Mobile
- SCSS Modules
## 注意事项
1. 上传功能需要配置正确的API地址
2. 文件上传需要有效的认证token
3. 测试数据使用外部图片服务,需要网络连接
4. 建议在移动端环境下测试以获得最佳体验

View File

@@ -1,72 +0,0 @@
import React from "react";
import { Card, Button, Space, Typography, Tag } from "antd";
import {
MessageOutlined,
SelectOutlined,
UploadOutlined,
} from "@ant-design/icons";
import { useNavigate } from "react-router-dom";
import { isDevelopment } from "@/utils/env";
import Layout from "@/components/Layout/Layout";
import NavCommon from "@/components/NavCommon";
const { Title, Text } = Typography;
const TestIndex: React.FC = () => {
const navigate = useNavigate();
return (
<Layout header={<NavCommon title="测试页面" />}>
<div style={{ padding: "20px", maxWidth: "800px", margin: "0 auto" }}>
<Title level={2}>
{isDevelopment && (
<Tag color="orange" style={{ marginLeft: 8, fontSize: "12px" }}>
</Tag>
)}
</Title>
<Space direction="vertical" style={{ width: "100%" }} size="large">
<Card title="组件测试" size="small">
<Space direction="vertical" style={{ width: "100%" }}>
<Button
type="primary"
icon={<MessageOutlined />}
size="large"
block
onClick={() => navigate("/test/iframe")}
>
UniApp桥接测试
</Button>
<Button
icon={<SelectOutlined />}
size="large"
block
onClick={() => navigate("/test/select")}
>
</Button>
<Button
icon={<UploadOutlined />}
size="large"
block
onClick={() => navigate("/test/upload")}
>
</Button>
</Space>
</Card>
<Card title="说明" size="small">
<Text>便</Text>
</Card>
</Space>
</div>
</Layout>
);
};
export default TestIndex;

View File

@@ -1,221 +0,0 @@
import React, { useState } from "react";
import { Tabs, Tag } from "antd-mobile";
import Layout from "@/components/Layout/Layout";
import NavCommon from "@/components/NavCommon";
import DeviceSelection from "@/components/DeviceSelection";
import FriendSelection from "@/components/FriendSelection";
import GroupSelection from "@/components/GroupSelection";
import ContentSelection from "@/components/ContentSelection";
import AccountSelection from "@/components/AccountSelection";
import PoolSelection from "@/components/PoolSelection";
import { isDevelopment } from "@/utils/env";
import { GroupSelectionItem } from "@/components/GroupSelection/data";
import { ContentItem } from "@/components/ContentSelection/data";
import { FriendSelectionItem } from "@/components/FriendSelection/data";
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
import { AccountItem } from "@/components/AccountSelection/data";
import { PoolSelectionItem } from "@/components/PoolSelection/data";
const ComponentTest: React.FC = () => {
const [activeTab, setActiveTab] = useState("pools");
// 设备选择状态
const [selectedDevices, setSelectedDevices] = useState<DeviceSelectionItem[]>(
[],
);
// 群组选择状态
const [selectedGroups, setSelectedGroups] = useState<GroupSelectionItem[]>(
[],
);
// 内容库选择状态
const [selectedContent, setSelectedContent] = useState<ContentItem[]>([]);
const [selectedAccounts, setSelectedAccounts] = useState<AccountItem[]>([]);
// 好友选择状态
const [selectedFriendsOptions, setSelectedFriendsOptions] = useState<
FriendSelectionItem[]
>([]);
// 流量池选择状态
const [selectedPools, setSelectedPools] = useState<PoolSelectionItem[]>([]);
return (
<Layout header={<NavCommon title="组件调试" />}>
<div style={{ padding: 16 }}>
{isDevelopment && (
<div style={{ marginBottom: 16, textAlign: "center" }}>
<Tag color="orange" style={{ fontSize: "12px" }}>
-
</Tag>
</div>
)}
<Tabs activeKey={activeTab} onChange={setActiveTab}>
<Tabs.Tab title="好友选择" key="friends">
<div style={{ padding: "16px 0" }}>
<h3 style={{ marginBottom: 16 }}>FriendSelection </h3>
<FriendSelection
selectedOptions={selectedFriendsOptions}
onSelect={setSelectedFriendsOptions}
placeholder="请选择微信好友"
showSelectedList={true}
selectedListMaxHeight={300}
/>
</div>
</Tabs.Tab>
<Tabs.Tab title="内容库选择" key="libraries">
<div style={{ padding: "16px 0" }}>
<h3 style={{ marginBottom: 16 }}>ContentSelection </h3>
<ContentSelection
selectedOptions={selectedContent}
onSelect={setSelectedContent}
placeholder="请选择内容库"
showSelectedList={true}
selectedListMaxHeight={300}
/>
<div
style={{
marginTop: 16,
padding: 12,
background: "#f5f5f5",
borderRadius: 8,
}}
>
<strong>:</strong> {selectedContent.length}
<br />
<strong>ID:</strong>{" "}
{selectedContent.map(c => c.id).join(", ") || "无"}
</div>
</div>
</Tabs.Tab>
<Tabs.Tab title="群组选择" key="groups2">
<div style={{ padding: "16px 0" }}>
<h3 style={{ marginBottom: 16 }}>GroupSelection </h3>
<GroupSelection
selectedOptions={selectedGroups}
onSelect={setSelectedGroups}
placeholder="请选择微信群组"
showSelectedList={true}
selectedListMaxHeight={300}
/>
<div
style={{
marginTop: 16,
padding: 12,
background: "#f5f5f5",
borderRadius: 8,
}}
>
<strong>:</strong> {selectedGroups.length}
<br />
<strong>ID:</strong>{" "}
{selectedGroups.map(g => g.id).join(", ") || "无"}
</div>
</div>
</Tabs.Tab>
<Tabs.Tab title="设备选择" key="devices">
<div style={{ padding: "16px 0" }}>
<h3 style={{ marginBottom: 16 }}>DeviceSelection </h3>
<DeviceSelection
selectedOptions={selectedDevices}
onSelect={setSelectedDevices}
placeholder="请选择设备"
showSelectedList={true}
selectedListMaxHeight={300}
/>
<div
style={{
marginTop: 16,
padding: 12,
background: "#f5f5f5",
borderRadius: 8,
}}
>
<strong>:</strong> {selectedDevices.length}
<br />
<strong>ID:</strong>
{selectedDevices.map(d => d.id).join(", ") || "无"}
</div>
</div>
</Tabs.Tab>
<Tabs.Tab title="账号选择" key="accounts">
<div style={{ padding: "16px 0" }}>
<h3 style={{ marginBottom: 16 }}>AccountSelection </h3>
<AccountSelection
selectedOptions={selectedAccounts}
onSelect={setSelectedAccounts}
placeholder="请选择账号"
showSelectedList={true}
selectedListMaxHeight={300}
// 可根据实际API和props补充其它参数
/>
<div style={{ marginTop: 16 }}>
<strong></strong>
{selectedAccounts.length > 0
? selectedAccounts.join(", ")
: "无"}
</div>
</div>
</Tabs.Tab>
<Tabs.Tab title="群组选择" key="groups">
<div style={{ padding: "16px 0" }}>
<h3 style={{ marginBottom: 16 }}>GroupSelection </h3>
<GroupSelection
selectedOptions={selectedGroups}
onSelect={setSelectedGroups}
placeholder="请选择微信群组"
showSelectedList={true}
selectedListMaxHeight={300}
/>
<div
style={{
marginTop: 16,
padding: 12,
background: "#f5f5f5",
borderRadius: 8,
}}
>
<strong>:</strong> {selectedGroups.length}
<br />
<strong>ID:</strong>{" "}
{selectedGroups.map(g => g.id).join(", ") || "无"}
</div>
</div>
</Tabs.Tab>
<Tabs.Tab title="流量池选择" key="pools">
<div style={{ padding: "16px 0" }}>
<h3 style={{ marginBottom: 16 }}>PoolSelection </h3>
<PoolSelection
selectedOptions={selectedPools}
onSelect={setSelectedPools}
placeholder="请选择流量池"
showSelectedList={true}
selectedListMaxHeight={300}
/>
<div
style={{
marginTop: 16,
padding: 12,
background: "#f5f5f5",
borderRadius: 8,
}}
>
<strong>:</strong> {selectedPools.length}
<br />
<strong>ID:</strong>{" "}
{selectedPools.map(p => p.id).join(", ") || "无"}
</div>
</div>
</Tabs.Tab>
</Tabs>
</div>
</Layout>
);
};
export default ComponentTest;

View File

@@ -1,179 +0,0 @@
import React from "react";
import UpdateNotification from "@/components/UpdateNotification";
const UpdateNotificationTest: React.FC = () => {
return (
<div
style={{
minHeight: "100vh",
backgroundColor: "#f5f5f5",
position: "relative",
}}
>
{/* 更新通知组件 */}
<UpdateNotification forceShow={true} />
{/* 页面内容 */}
<div
style={{
paddingTop: "calc(80px + env(safe-area-inset-top))", // 为通知栏留出空间
padding: "20px",
maxWidth: "800px",
margin: "0 auto",
}}
>
<div
style={{
backgroundColor: "white",
borderRadius: "12px",
padding: "24px",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
marginBottom: "20px",
}}
>
<h2
style={{
fontSize: "20px",
fontWeight: "600",
marginBottom: "16px",
color: "#333",
}}
>
UpdateNotification
</h2>
<div style={{ marginBottom: "16px" }}>
<h3
style={{
fontSize: "16px",
fontWeight: "500",
marginBottom: "8px",
color: "#666",
}}
>
</h3>
<ul
style={{
paddingLeft: "20px",
lineHeight: "1.6",
color: "#666",
}}
>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<div style={{ marginBottom: "16px" }}>
<h3
style={{
fontSize: "16px",
fontWeight: "500",
marginBottom: "8px",
color: "#666",
}}
>
</h3>
<ul
style={{
paddingLeft: "20px",
lineHeight: "1.6",
color: "#666",
}}
>
<li>&ldquo;&rdquo;</li>
<li>&ldquo;&rdquo;10</li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<div
style={{
padding: "16px",
backgroundColor: "#f8f9fa",
borderRadius: "8px",
border: "1px solid #e9ecef",
}}
>
<p
style={{
margin: 0,
fontSize: "14px",
color: "#666",
lineHeight: "1.5",
}}
>
<strong></strong>
使
</p>
</div>
</div>
{/* 模拟页面内容 */}
<div
style={{
backgroundColor: "white",
borderRadius: "12px",
padding: "24px",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
}}
>
<h3
style={{
fontSize: "18px",
fontWeight: "500",
marginBottom: "16px",
color: "#333",
}}
>
</h3>
<p
style={{
lineHeight: "1.6",
color: "#666",
marginBottom: "16px",
}}
>
</p>
<p
style={{
lineHeight: "1.6",
color: "#666",
marginBottom: "16px",
}}
>
</p>
<div
style={{
height: "200px",
backgroundColor: "#f8f9fa",
borderRadius: "8px",
display: "flex",
alignItems: "center",
justifyContent: "center",
color: "#999",
fontSize: "14px",
}}
>
</div>
</div>
</div>
</div>
);
};
export default UpdateNotificationTest;

View File

@@ -1,354 +0,0 @@
.container {
padding: 16px;
background: #f5f5f5;
min-height: 100vh;
.customHeader {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background: #fff;
border-bottom: 1px solid #f0f0f0;
.headerLeft {
display: flex;
align-items: center;
gap: 12px;
.backButton {
padding: 4px;
border: none;
background: transparent;
color: #666;
font-size: 18px;
&:hover {
color: #1890ff;
}
}
.headerTitle {
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
font-weight: bold;
color: #333;
.headerIcon {
font-size: 20px;
color: #1890ff;
}
}
}
}
.controlPanel {
margin-bottom: 16px;
h3 {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 16px;
}
.controlItem {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
span {
font-size: 14px;
color: #333;
}
}
}
.testSection {
margin-bottom: 16px;
h3 {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 8px;
}
p {
font-size: 12px;
color: #666;
margin-bottom: 16px;
}
.result {
margin-top: 16px;
padding: 12px;
background: #f8f9fa;
border-radius: 8px;
h4 {
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 8px;
}
.urlList {
.urlItem {
display: flex;
align-items: flex-start;
margin-bottom: 4px;
font-size: 12px;
span:first-child {
color: #666;
margin-right: 8px;
min-width: 20px;
flex-shrink: 0;
}
.url {
color: #1890ff;
word-break: break-all;
line-height: 1.4;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
flex: 1;
min-width: 0; // 确保flex项目可以收缩
}
}
}
.emptyText {
color: #999;
font-style: italic;
}
}
}
.form {
.formItem {
margin-bottom: 16px;
label {
display: block;
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 8px;
}
input,
textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
&:focus {
outline: none;
border-color: #1890ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
&::placeholder {
color: #bfbfbf;
}
}
textarea {
resize: vertical;
min-height: 80px;
}
}
}
.actionPanel {
margin-bottom: 16px;
}
.dataPanel {
h3 {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 16px;
}
.dataContent {
background: #f8f9fa;
border-radius: 8px;
padding: 12px;
max-height: 300px;
overflow-y: auto;
pre {
margin: 0;
font-size: 12px;
line-height: 1.4;
color: #333;
white-space: pre-wrap;
word-break: break-all;
}
}
}
}
// 响应式设计
@media (max-width: 768px) {
.container {
padding: 12px;
.customHeader {
padding: 8px 12px;
.headerLeft {
.headerTitle {
font-size: 14px;
.headerIcon {
font-size: 18px;
}
}
}
}
.testSection {
.result {
.urlList {
.urlItem {
font-size: 11px;
}
}
}
}
.dataPanel {
.dataContent {
pre {
font-size: 11px;
}
}
}
}
}
// 暗色主题支持
@media (prefers-color-scheme: dark) {
.container {
background: #1f1f1f;
.customHeader {
background: #2a2a2a;
border-bottom-color: #434343;
.headerLeft {
.backButton {
color: #ccc;
&:hover {
color: #40a9ff;
}
}
.headerTitle {
color: #fff;
.headerIcon {
color: #40a9ff;
}
}
}
}
.testSection {
h3 {
color: #fff;
}
p {
color: #ccc;
}
.result {
background: #2a2a2a;
h4 {
color: #fff;
}
.urlList {
.urlItem {
span:first-child {
color: #ccc;
}
.url {
color: #40a9ff;
}
}
}
// 单个URL项头像、视频的样式
.urlItem {
.url {
color: #40a9ff;
}
}
.emptyText {
color: #888;
}
}
}
.form {
.formItem {
label {
color: #fff;
}
input,
textarea {
background: #2a2a2a;
border-color: #434343;
color: #fff;
&:focus {
border-color: #40a9ff;
box-shadow: 0 0 0 2px rgba(64, 169, 255, 0.2);
}
&::placeholder {
color: #666;
}
}
}
}
.dataPanel {
h3 {
color: #fff;
}
.dataContent {
background: #2a2a2a;
pre {
color: #fff;
}
}
}
}
}

View File

@@ -1,423 +0,0 @@
import React, { useState } from "react";
import { Button, Card, Space, Divider, Toast, Switch } from "antd-mobile";
import Layout from "@/components/Layout/Layout";
import NavCommon from "@/components/NavCommon";
import ImageUpload from "@/components/Upload/ImageUpload/ImageUpload";
import AvatarUpload from "@/components/Upload/AvatarUpload";
import VideoUpload from "@/components/Upload/VideoUpload";
import FileUpload from "@/components/Upload/FileUpload";
import MainImgUpload from "@/components/Upload/MainImgUpload";
import styles from "./upload.module.scss";
// 错误边界组件
class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean; error: Error | null }
> {
constructor(props: { children: React.ReactNode }) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error("Error caught by boundary:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div style={{ padding: 20, textAlign: "center" }}>
<h3></h3>
<p>: {this.state.error?.message}</p>
<Button
onClick={() => this.setState({ hasError: false, error: null })}
>
</Button>
</div>
);
}
return this.props.children;
}
}
const UploadTestPage: React.FC = () => {
// 搜索状态
const [searchQuery, setSearchQuery] = useState("");
const [loading, setLoading] = useState(false);
// 图片上传状态
const [imageUrls, setImageUrls] = useState<string[]>([]);
const [imageCount, setImageCount] = useState(9);
const [imageDisabled, setImageDisabled] = useState(false);
// 头像上传状态
const [avatarUrl, setAvatarUrl] = useState<string>("");
const [avatarSize, setAvatarSize] = useState(100);
const [avatarDisabled, setAvatarDisabled] = useState(false);
// 视频上传状态
const [videoUrl, setVideoUrl] = useState<string>("");
const [videoUrls, setVideoUrls] = useState<string[]>([]);
const [videoDisabled, setVideoDisabled] = useState(false);
const [videoCount, setVideoCount] = useState(1);
// 文件上传状态
const [fileUrl, setFileUrl] = useState<string>("");
const [fileUrls, setFileUrls] = useState<string[]>([]);
const [fileDisabled, setFileDisabled] = useState(false);
const [fileCount, setFileCount] = useState(1);
const [fileTypes, setFileTypes] = useState<string[]>([
"excel",
"word",
"ppt",
]);
// 主图上传状态
const [mainImgUrl, setMainImgUrl] = useState<string>("");
const [mainImgDisabled, setMainImgDisabled] = useState(false);
const [mainImgMaxSize, setMainImgMaxSize] = useState(5);
const [mainImgShowPreview, setMainImgShowPreview] = useState(true);
return (
<Layout header={<NavCommon title="上传组件功能测试" />} loading={loading}>
<div className={styles.container}>
{/* 图片上传测试 */}
<ErrorBoundary>
<Card className={styles.testSection}>
<h3></h3>
<p></p>
<ImageUpload
value={imageUrls}
onChange={setImageUrls}
count={imageCount}
accept="image/*"
disabled={imageDisabled}
/>
<div className={styles.result}>
<h4>URLs:</h4>
<div className={styles.urlList}>
{imageUrls.length > 0 ? (
imageUrls.map((url, index) => (
<div key={index} className={styles.urlItem}>
<span>{index + 1}.</span>
<span className={styles.url}>
{typeof url === "string" ? url : "无效URL"}
</span>
</div>
))
) : (
<span className={styles.emptyText}></span>
)}
</div>
</div>
</Card>
</ErrorBoundary>
{/* 头像上传测试 */}
<ErrorBoundary>
<Card className={styles.testSection}>
<h3></h3>
<p></p>
<AvatarUpload
value={avatarUrl}
onChange={setAvatarUrl}
disabled={avatarDisabled}
size={avatarSize}
/>
<div className={styles.result}>
<h4>URL:</h4>
<div className={styles.urlList}>
<div className={styles.urlItem}>
{avatarUrl ? (
<div className={styles.url}>
{typeof avatarUrl === "string" ? avatarUrl : "无效URL"}
</div>
) : (
<span className={styles.emptyText}></span>
)}
</div>
</div>
</div>
</Card>
</ErrorBoundary>
{/* 视频上传测试 */}
<ErrorBoundary>
<Card className={styles.testSection}>
<h3></h3>
<p>50MB</p>
{/* 视频上传控制面板 */}
<div className={styles.controlPanel}>
<div className={styles.controlItem}>
<span>:</span>
<Space>
<Button
size="small"
onClick={() => setVideoCount(Math.max(1, videoCount - 1))}
>
-
</Button>
<span>{videoCount}</span>
<Button
size="small"
onClick={() => setVideoCount(Math.min(10, videoCount + 1))}
>
+
</Button>
</Space>
</div>
</div>
<VideoUpload
value={videoCount === 1 ? videoUrl : videoUrls}
onChange={url => {
if (videoCount === 1) {
setVideoUrl(url as string);
} else {
setVideoUrls(url as string[]);
}
}}
disabled={videoDisabled}
maxSize={50}
showPreview={true}
maxCount={videoCount}
/>
<div className={styles.result}>
<h4>URL:</h4>
<div className={styles.urlList}>
{videoCount === 1 ? (
<div className={styles.urlItem}>
{videoUrl ? (
<div className={styles.url}>
{typeof videoUrl === "string" ? videoUrl : "无效URL"}
</div>
) : (
<span className={styles.emptyText}></span>
)}
</div>
) : videoUrls.length > 0 ? (
videoUrls.map((url, index) => (
<div key={index} className={styles.urlItem}>
<span>{index + 1}.</span>
<div className={styles.url}>
{typeof url === "string" ? url : "无效URL"}
</div>
</div>
))
) : (
<span className={styles.emptyText}></span>
)}
</div>
</div>
</Card>
</ErrorBoundary>
{/* 文件上传测试 */}
<ErrorBoundary>
<Card className={styles.testSection}>
<h3></h3>
<p>ExcelWordPPT格式文件上传</p>
{/* 文件上传控制面板 */}
<div className={styles.controlPanel}>
<div className={styles.controlItem}>
<span>:</span>
<Space>
<Button
size="small"
onClick={() => setFileCount(Math.max(1, fileCount - 1))}
>
-
</Button>
<span>{fileCount}</span>
<Button
size="small"
onClick={() => setFileCount(Math.min(10, fileCount + 1))}
>
+
</Button>
</Space>
</div>
<div className={styles.controlItem}>
<span>:</span>
<Space>
<Button
size="small"
color={fileTypes.includes("excel") ? "primary" : "default"}
onClick={() => {
if (fileTypes.includes("excel")) {
setFileTypes(fileTypes.filter(t => t !== "excel"));
} else {
setFileTypes([...fileTypes, "excel"]);
}
}}
>
Excel
</Button>
<Button
size="small"
color={fileTypes.includes("word") ? "primary" : "default"}
onClick={() => {
if (fileTypes.includes("word")) {
setFileTypes(fileTypes.filter(t => t !== "word"));
} else {
setFileTypes([...fileTypes, "word"]);
}
}}
>
Word
</Button>
<Button
size="small"
color={fileTypes.includes("ppt") ? "primary" : "default"}
onClick={() => {
if (fileTypes.includes("ppt")) {
setFileTypes(fileTypes.filter(t => t !== "ppt"));
} else {
setFileTypes([...fileTypes, "ppt"]);
}
}}
>
PPT
</Button>
</Space>
</div>
</div>
<FileUpload
value={fileCount === 1 ? fileUrl : fileUrls}
onChange={url => {
if (fileCount === 1) {
setFileUrl(url as string);
} else {
setFileUrls(url as string[]);
}
}}
disabled={fileDisabled}
maxSize={10}
showPreview={true}
maxCount={fileCount}
acceptTypes={fileTypes}
/>
<div className={styles.result}>
<h4>URL:</h4>
<div className={styles.urlList}>
{fileCount === 1 ? (
<div className={styles.urlItem}>
{fileUrl ? (
<div className={styles.url}>
{typeof fileUrl === "string" ? fileUrl : "无效URL"}
</div>
) : (
<span className={styles.emptyText}></span>
)}
</div>
) : fileUrls.length > 0 ? (
fileUrls.map((url, index) => (
<div key={index} className={styles.urlItem}>
<span>{index + 1}.</span>
<div className={styles.url}>
{typeof url === "string" ? url : "无效URL"}
</div>
</div>
))
) : (
<span className={styles.emptyText}></span>
)}
</div>
</div>
</Card>
</ErrorBoundary>
{/* 主图上传测试 */}
<ErrorBoundary>
<Card className={styles.testSection}>
<h3></h3>
<p></p>
{/* 主图上传控制面板 */}
<div className={styles.controlPanel}>
<div className={styles.controlItem}>
<span>:</span>
<Space>
<Button
size="small"
onClick={() =>
setMainImgMaxSize(Math.max(1, mainImgMaxSize - 1))
}
>
-
</Button>
<span>{mainImgMaxSize}MB</span>
<Button
size="small"
onClick={() =>
setMainImgMaxSize(Math.min(20, mainImgMaxSize + 1))
}
>
+
</Button>
</Space>
</div>
<div className={styles.controlItem}>
<span>:</span>
<Switch
checked={mainImgShowPreview}
onChange={setMainImgShowPreview}
/>
</div>
<div className={styles.controlItem}>
<span>:</span>
<Switch
checked={mainImgDisabled}
onChange={setMainImgDisabled}
/>
</div>
</div>
<MainImgUpload
value={mainImgUrl}
onChange={setMainImgUrl}
disabled={mainImgDisabled}
maxSize={mainImgMaxSize}
showPreview={mainImgShowPreview}
/>
<div className={styles.result}>
<h4>URL:</h4>
<div className={styles.urlList}>
<div className={styles.urlItem}>
{mainImgUrl ? (
<div className={styles.url}>
{typeof mainImgUrl === "string" ? mainImgUrl : "无效URL"}
</div>
) : (
<span className={styles.emptyText}></span>
)}
</div>
</div>
</div>
</Card>
</ErrorBoundary>
</div>
</Layout>
);
};
export default UploadTestPage;