fix: allow 500MB async knowledge uploads
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- **2026-07-29,资料处理中心普通文档/图片单文件上限扩展至 500MB,待发布验证**:管理端批量导入与后端异步队列统一允许文档、图片、视频和 ZIP 单文件 `≤500MB`,沿用生产 Spring/Undertow `500MB/520MB` 传输层配置;ZIP 单个受支持子文件同步放宽至 500MB,仍保留最多 1000 个子文件、解压总量 ≤2GB、禁止嵌套 ZIP 等安全边界。同步 SOP 上传和公司文件不在本次范围,继续保持 100MB。新增前后端契约回归,生产发布与大文件实际解析结果需在发布后补记。
|
||||
- **2026-07-29,资料处理媒体任务恢复已发布并完成生产验证**:修复历史图片/视频在视觉输入不兼容或未提取到文字时长期停在“等待解析”的问题;图片在送入视觉模型前会按方向纠正、限制像素和体积并统一编码,异步队列只有生成至少一个片段才进入完成态,零片段会保留为可重试失败。新增 `POST /api/knowledge/doc/processing-tasks/{attachmentId}/retry`,可从当前租户原 OSS 对象重新暂存并入队;正式迁移 `aihr_20260729_media_reprocess_mysql8.sql` 增加 `source_attach_id` 和 `(tenant_id, source_attach_id, id)` 索引。生产已备份 schema、后端和完整站点,发布管理端与后端 JAR `5376b67b33b171b5c85e22cd6a2f20bbb0bc527fc50a223603d0aec3f6587bac`,移动 H5 未重发;发布脚本在重启后等待公开端点真实就绪再执行预检,服务为 `active`,根站、租户和移动首页均返回 HTTP 200。原卡住任务 `1133/1175/1308/1405` 从原文件重试为队列 `1185–1188`,四项均完成、各生成一个片段且向量存在;资料处理页显示“待重试 0”、Tika `1028/1028`、可引用资料 `1028`。该证据证明本次资料恢复和定向发布成功,不代表移动 H5 与当前工作树完整匹配,也不替代 Android 真机或正式试点验收。
|
||||
- **2026-07-29,新增移动端 UI token 与渲染态审计,未发布静态资源**:`audit:ui-tokens` 以 `mobile-uni/src/styles/base.css` 为源扫描颜色、字阶、间距和圆角,`audit:ui-rendered` 在 390×844 的真实 Chrome 中审计 H5 构建的六个默认路由并保存截图。两项均把报告写入 Git 已忽略的 `output/ui-ux/`;本地实跑覆盖 53 个源码文件和 6 个渲染路由,渲染路由均无横向溢出或控制台错误,同时如实记录现有 palette 外颜色、孤立字号和非 token 圆角,不能把“脚本执行成功”解释为视觉债务已清零。
|
||||
- **2026-07-29,移动端固定码认证与身份失败关闭收口,候选升级为 `0.1.13 (113)`,未发布生产**:生产验证只选择已存在 `app_user` 且双向唯一的在职组织主体;固定码请求、登录、非空项目范围、认证首页、训练历史/画像、五通道、我的反馈、大喇叭、考试、案例/全网只读入口、退出、旧令牌拒绝、等待防刷窗口后的再次获取和重新登录全部通过,应用日志确认两次验证码请求均命中“未真实发送短信”分支。脚本不输出手机号、固定码或令牌,不触发自动注册,不提交反馈、训练、附件、ASR/TTS 或 Agent 请求。后端 `/api/aihr/mobile/me` 与认证首页遇到身份缺失、组织查询异常、无在职身份或后台账号时改为失败关闭;前端角色和岗位加载失败清空缓存并展示明确错误,不再回退普通员工、陈旧岗位或公开首页。干净提交 `af8af2f6` 的统一 RC 已达到 `releaseEligible=true`:移动端 199 项、`ruoyi-aihr` 700 项、类型检查、H5/App、管理端构建、后端打包和 APK 深检全部通过,证据在 `output/aug1-rc/0.1.13-113-af8af2f6-frozen/`。DCloud 云端证书 APK 大小 `33,921,543` 字节、SHA-256 `FA2D2A6DC84AE759714E6D16D146C1E1552A0F3F53C046069422012361D1D0C0`,API 35、v2 测试签名、禁止明文 HTTP、包内业务资源/登录法务/身份失败关闭和敏感值深检通过;候选后端 JAR SHA-256 为 `93AD272118F6A28F88C2BFA305F5C450E163CBE22577FF5BE3E85B3BD3958DAD`,生产只读发布计划通过,现网仍为 `46C99CFF…`。当前双提交交付包 `bangdao-aug1-0.1.13-113-af8af2f6-ops46f4616b.zip` 大小 `192,948,093` 字节、SHA-256 `F6DF4AB2660A4D3523C7E9785C1F8B572770F1F795A841E2D95C88936A8AE9C0`,20 个条目及内部哈希逐项通过;严格门禁会校验固定码模式、5/5 场景、30/30 问题证据、五类负责人签认、每个直通角色至少两名有效处理人、生产场景版本/哈希、五通道正向授权/越权拒绝/一次正式回复,以及受控分发、法务例外和测试签名接受。包内 Go/No-Go 已指向当前包,旧 `ops9c53668c` ZIP 只作历史追溯。机器签认当前准确保持正式场景 `0/5`、问题证据 `0/30`、通道验收 `0/5`、负责人签认 `0/5`、受控分发 `PENDING`,五个处理角色有效绑定均为 `0`。本项未发布后端、H5、数据库或生产静态资源;固定码、登录和重新登录不再列为功能缺口。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- # 临时文件存储位置 避免临时文件被系统清理报错
|
||||
spring.servlet.multipart.location: /ruoyi/server/temp
|
||||
# 资料处理异步队列支持视频和 ZIP 单文件至 500MB;具体接口仍按各自业务上限校验。
|
||||
# 资料处理中心异步队列支持文档、图片、视频和 ZIP 单文件至 500MB;其他接口仍按各自业务上限校验。
|
||||
spring.servlet.multipart.max-file-size: 500MB
|
||||
spring.servlet.multipart.max-request-size: 520MB
|
||||
|
||||
|
||||
+6
-12
@@ -56,10 +56,8 @@ public class AihrUploadQueueService {
|
||||
|
||||
private static final String TENANT_ID = "000000";
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("MM-dd HH:mm:ss");
|
||||
private static final long MAX_FILE_BYTES = 100L * 1024 * 1024;
|
||||
/** 视频单独放宽:培训视频普遍大于文档;更大的走服务端目录导入。 */
|
||||
private static final long MAX_VIDEO_BYTES = 500L * 1024 * 1024;
|
||||
private static final long MAX_ARCHIVE_BYTES = 500L * 1024 * 1024;
|
||||
/** 资料处理中心统一支持单文件 500 MiB;Spring multipart 请求上限需保持不低于该值。 */
|
||||
private static final long MAX_FILE_BYTES = 500L * 1024 * 1024;
|
||||
private static final long MAX_ARCHIVE_UNPACKED_BYTES = 2L * 1024 * 1024 * 1024;
|
||||
private static final int MAX_ARCHIVE_ENTRIES = 1000;
|
||||
private static final int MAX_ERROR_CHARS = 480;
|
||||
@@ -125,14 +123,12 @@ public class AihrUploadQueueService {
|
||||
if (!archive && !AihrSopSeedService.supportedFile(fileName)) {
|
||||
throw new ServiceException("仅支持 txt/md/markdown/pdf/doc/docx/xls/xlsx/ppt/pptx/图片/视频/zip文件");
|
||||
}
|
||||
long maxBytes = archive ? MAX_ARCHIVE_BYTES
|
||||
: AihrVideoService.videoFile(fileName) ? MAX_VIDEO_BYTES : MAX_FILE_BYTES;
|
||||
if (file.getSize() > maxBytes) {
|
||||
if (file.getSize() > MAX_FILE_BYTES) {
|
||||
throw new ServiceException(archive
|
||||
? "ZIP不能超过 500MB"
|
||||
: AihrVideoService.videoFile(fileName)
|
||||
? "视频不能超过 500MB,更大的请放到导入根目录走服务端导入"
|
||||
: "文件不能超过 100MB");
|
||||
: "文件不能超过 500MB");
|
||||
}
|
||||
ensureTable();
|
||||
String batch = sanitizeBatchId(batchId);
|
||||
@@ -494,7 +490,6 @@ public class AihrUploadQueueService {
|
||||
if (!AihrSopSeedService.supportedFile(fileName)) {
|
||||
continue;
|
||||
}
|
||||
long maxBytes = AihrVideoService.videoFile(fileName) ? MAX_VIDEO_BYTES : MAX_FILE_BYTES;
|
||||
Path extracted = stagingPath(fileName);
|
||||
long entryBytes = 0;
|
||||
try (var output = Files.newOutputStream(extracted)) {
|
||||
@@ -503,7 +498,7 @@ public class AihrUploadQueueService {
|
||||
while ((read = zip.read(buffer)) != -1) {
|
||||
entryBytes += read;
|
||||
unpackedBytes += read;
|
||||
if (entryBytes > maxBytes || unpackedBytes > MAX_ARCHIVE_UNPACKED_BYTES) {
|
||||
if (entryBytes > MAX_FILE_BYTES || unpackedBytes > MAX_ARCHIVE_UNPACKED_BYTES) {
|
||||
throw new ArchiveException("ZIP解压后文件超过大小限制");
|
||||
}
|
||||
output.write(buffer, 0, read);
|
||||
@@ -735,12 +730,11 @@ public class AihrUploadQueueService {
|
||||
|| object.getFileName() == null || object.getFileName().isBlank()) {
|
||||
throw new ServiceException("MEDIA_RETRY_SOURCE_UNAVAILABLE: 原始文件不存在");
|
||||
}
|
||||
long maxBytes = AihrVideoService.videoFile(source.fileName()) ? MAX_VIDEO_BYTES : MAX_FILE_BYTES;
|
||||
OssClient client = OssFactory.instance(object.getService());
|
||||
Files.createDirectories(target.getParent());
|
||||
try (InputStream input = client.getObjectContent(object.getFileName());
|
||||
OutputStream output = Files.newOutputStream(target)) {
|
||||
copyWithLimit(input, output, maxBytes);
|
||||
copyWithLimit(input, output, MAX_FILE_BYTES);
|
||||
} catch (RuntimeException | IOException e) {
|
||||
deleteQuietly(target);
|
||||
throw e;
|
||||
|
||||
+9
@@ -8,6 +8,7 @@ import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -35,6 +36,14 @@ class AihrUploadQueueServiceTest {
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
@Test
|
||||
void asyncQueueAllowsOrdinaryDocumentsUpTo500MiB() throws Exception {
|
||||
Field field = AihrUploadQueueService.class.getDeclaredField("MAX_FILE_BYTES");
|
||||
field.setAccessible(true);
|
||||
|
||||
assertEquals(500L * 1024 * 1024, field.getLong(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void expandsLegacyGbkZipAtomicallyAndKeepsDuplicateEntries() throws Exception {
|
||||
Path staging = Files.createDirectories(tempDir.resolve("staging"));
|
||||
|
||||
@@ -129,7 +129,7 @@ SOP 文档上传第三片已经落最小后端边界:
|
||||
| 解析状态聚合 | `GET /api/knowledge/processing/overview` | 聚合 `aihr_knowledge_attach.status`、fragment 数、embedding 数、`sys_oss.ext1.fileSize`,生成资料处理页指标、分类、任务、链路和事件列表 |
|
||||
| 服务端目录导入(运维) | `POST /api/knowledge/doc/import-local` | JSON `{ directory, category, limit }`;`directory` 只能是 `AIHR_IMPORT_ROOT` / `aihr.import.root` 下的相对目录,默认根目录为 `./.data/import`;逐文件复用上传解析链路,同步执行,仅保留给运维/调试,不在资料处理页暴露 |
|
||||
| 服务端导入任务(运维) | `POST /api/knowledge/doc/import-local-task`、`GET /api/knowledge/doc/import-tasks`、`POST /api/knowledge/doc/import-tasks/{id}/cancel` | 启动后台目录导入并返回任务;任务写入 `aihr_knowledge_import_task`,调用方可查询总数、成功数、失败数、当前文件和进度,运行中任务可取消;仅保留给运维/调试,不在资料处理页暴露 |
|
||||
| 批量异步上传 | `POST /api/knowledge/doc/upload-async`(multipart `file`+`category`+`batchId`)、`GET /api/knowledge/doc/upload-items?batchId=`、`POST /api/knowledge/doc/upload-items/{id}/retry`、`POST /api/knowledge/doc/processing-tasks/{attachmentId}/retry` | 上传只做暂存(`aihr.upload.staging`,默认 `./.data/staging`)+ 写入 `aihr_knowledge_upload_item`(0待处理/1处理中/2完成/3失败)即返回;`source_attach_id` 记录从原 OSS 重试的附件。视频和 ZIP 单文件 ≤500MB,其他文件 ≤100MB。生产 Spring/Undertow multipart 上限为单文件 500MB、请求 520MB;worker 限制最多 1000 个 ZIP 子文件、解压总量 ≤2GB,拒绝嵌套 ZIP/不安全路径并忽略未知格式;ZIP 文件名优先按 UTF-8 解码,旧版中文 Windows ZIP 自动回退 GBK;同名子文件自动追加编号并以单条批量写入入队;只有片段数大于 0 才记为完成并删除暂存文件,零片段或安全媒体错误保持失败态供重试;卡住 30 分钟(视频 120 分钟)由清扫重置,失败暂存文件保留 72h;同步接口 `POST /api/knowledge/doc/upload` 不支持 ZIP,保留给 SOP 页单文件即时预览 |
|
||||
| 批量异步上传 | `POST /api/knowledge/doc/upload-async`(multipart `file`+`category`+`batchId`)、`GET /api/knowledge/doc/upload-items?batchId=`、`POST /api/knowledge/doc/upload-items/{id}/retry`、`POST /api/knowledge/doc/processing-tasks/{attachmentId}/retry` | 上传只做暂存(`aihr.upload.staging`,默认 `./.data/staging`)+ 写入 `aihr_knowledge_upload_item`(0待处理/1处理中/2完成/3失败)即返回;`source_attach_id` 记录从原 OSS 重试的附件。文档、图片、视频和 ZIP 单文件均 ≤500MB,生产 Spring/Undertow multipart 上限为单文件 500MB、请求 520MB;worker 限制最多 1000 个 ZIP 子文件、单个受支持子文件 ≤500MB、解压总量 ≤2GB,拒绝嵌套 ZIP/不安全路径并忽略未知格式;ZIP 文件名优先按 UTF-8 解码,旧版中文 Windows ZIP 自动回退 GBK;同名子文件自动追加编号并以单条批量写入入队;只有片段数大于 0 才记为完成并删除暂存文件,零片段或安全媒体错误保持失败态供重试;卡住 30 分钟(视频 120 分钟)由清扫重置,失败暂存文件保留 72h;同步接口 `POST /api/knowledge/doc/upload` 不支持 ZIP,保留给 SOP 页单文件即时预览且仍按 100MB 契约执行 |
|
||||
| 视频解析 | 走批量异步上传,支持 `.mp4/.mov/.avi/.mkv/.webm/.m4v`,单文件 ≤500MB、时长 ≤60 分钟 | 依赖服务器 ffmpeg/ffprobe;抽音轨按 5 分钟分段调 asr 模型转写(`[mm:ss]` 时间戳),按 30s 间隔(≤40 帧)抽关键帧调 vision 模型提取画面文字(相邻重复画面去重);两类文本合并后走归类/切片/向量化;无音轨、ASR 无文本且 vision 无结果时以 `MEDIA_NO_TEXT` 进入可重试失败态,不冒充仍在排队;视频同时只加工 1 个 |
|
||||
|
||||
模型能力第二片已经落最小后端边界:
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
|
||||
- 已备份线上外置 `application-prod.yml`,并将 Spring/Undertow `max-file-size` 设为 `500MB`、`max-request-size` 设为 `520MB` 后重启 `wygj-aihr.service`;
|
||||
- 服务重启后为 `active`,101MB 的无认证回环 multipart 请求已通过解析层并止于鉴权,未写入业务表或 OSS;
|
||||
- 此配置只让既有异步队列的视频和 ZIP 兑现其 `≤500MB` 契约;普通文档、同步 SOP 上传和公司文件仍按各自的 `100MB` 业务限制执行。
|
||||
- 此配置在当时只让既有异步队列的视频和 ZIP 兑现其 `≤500MB` 契约;普通文档、同步 SOP 上传和公司文件仍按各自的 `100MB` 业务限制执行。
|
||||
|
||||
资料处理中心当前发布约束:
|
||||
|
||||
- 异步批量上传的文档、图片、视频和 ZIP 统一为单文件 `≤500MB`,需要管理端校验和后端 `AihrUploadQueueService` 同批发布;
|
||||
- 生产 Spring/Undertow 继续保持单文件 `500MB`、单请求 `520MB`,无须进一步放大传输层;
|
||||
- 同步 SOP 上传和公司文件不属于本次范围,继续保持 `100MB`。
|
||||
|
||||
2026-07-25 已完成最新完整包发布,发布源为 `230dfb4d`:
|
||||
|
||||
|
||||
+1
-1
@@ -255,7 +255,7 @@ docker compose -f docker-compose.dev.yml stop
|
||||
- 本地组织 seed 带演示手机号;从 `aihr_org_snapshot` 按角色查询测试账号,分别验证员工端岗位识别和主管端项目范围,不在文档保存具体号码
|
||||
- 生产移动端回归同样由执行者从 `aihr_org_snapshot` 只读选择账号,不等待人工提供手机号:限定目标岗位、`employment_status='active'`、11 位 `person_phone`,并确认手机号与 `ext_party_id` 双向唯一。账号值只注入当前浏览器进程,不输出到终端、截图、报告或仓库。试点固定码开启时,登录顺序仍为先请求 `/resource/sms/code`、再提交固定码;直接提交固定码会得到 `Captcha invalid`,不应误判为账号或功能故障。
|
||||
- SOP 知识库支持 `.txt/.md/.markdown/.pdf/.doc/.docx/.xls/.xlsx/.ppt/.pptx` 上传到 MinIO 后解析入库,接口为 `POST /api/knowledge/doc/upload`,单文件上限 100MB;管理端上传请求单独放宽到 180s,PDF 解析/归类/向量化较慢时不要改全局 axios 超时。
|
||||
- 资料处理中心异步接口支持 `.zip` 和视频单文件 ≤500MB;生产 Spring/Undertow multipart 配置必须保持 `max-file-size=500MB`、`max-request-size=520MB`(源文件 `backend/ruoyi-admin/src/main/resources/application-prod.yml`,线上外置 `/opt/wygj/config/application-prod.yml`),修改后重启 `wygj-aihr.service`。非视频/ZIP 文件仍由队列限制为 100MB;ZIP 最多 1000 个子文件、解压总量 ≤2GB,不支持嵌套 ZIP。
|
||||
- 资料处理中心异步接口支持文档、图片、视频和 `.zip` 单文件 ≤500MB;生产 Spring/Undertow multipart 配置必须保持 `max-file-size=500MB`、`max-request-size=520MB`(源文件 `backend/ruoyi-admin/src/main/resources/application-prod.yml`,线上外置 `/opt/wygj/config/application-prod.yml`),修改后重启 `wygj-aihr.service`。ZIP 最多 1000 个子文件、单个受支持子文件 ≤500MB、解压总量 ≤2GB,不支持嵌套 ZIP。同步 SOP 上传和公司文件仍按各自的 100MB 契约执行。
|
||||
- 视频(`.mp4/.mov/.avi/.mkv/.webm/.m4v`,≤500MB、≤60 分钟)只走资料处理中心批量导入(异步队列):ffmpeg 抽音轨分段调 asr 转写 + 抽关键帧调 vision 提取画面文字,合并后归类切片入库,片段带 `[mm:ss]` 时间戳;**依赖服务器安装 ffmpeg/ffprobe**(macOS `brew install ffmpeg`,Linux `apt install ffmpeg`)
|
||||
- 服务端目录导入接口为 `POST /api/knowledge/doc/import-local-task`,只读取导入根目录下的相对目录,后台逐文件复用同一上传解析链路;`POST /api/knowledge/doc/import-tasks/{id}/cancel` 可取消运行中任务;`POST /api/knowledge/doc/import-local` 保留为同步调试接口。这组接口仅供运维/调试,不在资料处理页提供入口。
|
||||
- 启用 `aihr_model_config.category='vector'` 的模型配置后,上传会同步写入片段 embedding,并尽力 upsert 到 Qdrant;模型配置页可查看 Qdrant 维度、点数和片段向量数,并在维度不一致时重建索引;未配置或 Qdrant 不可用时只走 MySQL Fulltext/seed fallback,不影响检索。
|
||||
|
||||
@@ -5,6 +5,14 @@ import { resolve } from 'node:path';
|
||||
const read = (path: string) => readFileSync(resolve(process.cwd(), path), 'utf8');
|
||||
|
||||
describe('资料处理媒体重试契约', () => {
|
||||
it('批量队列允许普通文档和图片上传至 500 MiB', () => {
|
||||
const page = read('src/views/knowledge/processing.vue');
|
||||
|
||||
expect(page).toContain('const maxFileSize = 500 * 1024 * 1024');
|
||||
expect(page).toContain('仅支持非空且 500MB 内的 txt/md/pdf/Word/Excel/PPT/图片/视频/ZIP 文件');
|
||||
expect(page).toContain('超过 500MB 的文件');
|
||||
});
|
||||
|
||||
it('把零文本媒体展示为待重试并从原文件重新入队', () => {
|
||||
const api = read('src/api/aihr/processing.ts');
|
||||
const page = read('src/views/knowledge/processing.vue');
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
</ul>
|
||||
<el-table v-if="uploadBatch.length" :data="uploadBatch" size="small" max-height="260" class="batch-table">
|
||||
<el-table-column prop="fileName" label="文件名" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column label="目标空间" min-width="180" show-overflow-tooltip><template #default="{ row }">{{ row.spaceCodes?.join('、') || '-' }}</template></el-table-column>
|
||||
<el-table-column label="目标空间" min-width="180" show-overflow-tooltip
|
||||
><template #default="{ row }">{{ row.spaceCodes?.join('、') || '-' }}</template></el-table-column
|
||||
>
|
||||
<el-table-column label="状态" width="96">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small" :type="batchItemTagType(row.status)">{{ row.statusLabel }}</el-tag>
|
||||
@@ -151,13 +153,7 @@
|
||||
<el-table-column prop="updatedAt" label="更新时间" width="138" />
|
||||
<el-table-column label="操作" width="86" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="canRetryProcessingTask(row)"
|
||||
link
|
||||
type="danger"
|
||||
:loading="taskRetryingId === row.id"
|
||||
@click="retryTask(row)"
|
||||
>
|
||||
<el-button v-if="canRetryProcessingTask(row)" link type="danger" :loading="taskRetryingId === row.id" @click="retryTask(row)">
|
||||
重试
|
||||
</el-button>
|
||||
<span v-else>-</span>
|
||||
@@ -281,11 +277,7 @@ import { listPersonalPublishRequests, reviewPersonalPublishRequest, type Persona
|
||||
|
||||
const acceptTypes = '.txt,.md,.markdown,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.webp,.bmp,.mp4,.mov,.avi,.mkv,.webm,.m4v,.zip';
|
||||
const supportedPattern = /\.(txt|md|markdown|pdf|doc|docx|xls|xlsx|ppt|pptx|jpg|jpeg|png|gif|webp|bmp|mp4|mov|avi|mkv|webm|m4v|zip)$/i;
|
||||
const videoPattern = /\.(mp4|mov|avi|mkv|webm|m4v)$/i;
|
||||
const archivePattern = /\.zip$/i;
|
||||
const maxFileSize = 100 * 1024 * 1024;
|
||||
const maxVideoSize = 500 * 1024 * 1024;
|
||||
const maxArchiveSize = 500 * 1024 * 1024;
|
||||
const maxFileSize = 500 * 1024 * 1024;
|
||||
const browserBatchWarnCount = 20;
|
||||
const browserBatchWarnSize = 200 * 1024 * 1024;
|
||||
|
||||
@@ -519,18 +511,13 @@ async function uploadFiles(files: File[]) {
|
||||
ElMessage.warning('请先选择至少一个可管理的知识空间');
|
||||
return;
|
||||
}
|
||||
const readyFiles = files.filter(
|
||||
(file) =>
|
||||
supportedPattern.test(file.name) &&
|
||||
file.size > 0 &&
|
||||
file.size <= (videoPattern.test(file.name) ? maxVideoSize : archivePattern.test(file.name) ? maxArchiveSize : maxFileSize)
|
||||
);
|
||||
const readyFiles = files.filter((file) => supportedPattern.test(file.name) && file.size > 0 && file.size <= maxFileSize);
|
||||
if (readyFiles.length === 0) {
|
||||
ElMessage.warning('仅支持非空的 txt/md/pdf/Word/Excel/PPT/图片(100MB内)、视频或 ZIP(500MB内)文件');
|
||||
ElMessage.warning('仅支持非空且 500MB 内的 txt/md/pdf/Word/Excel/PPT/图片/视频/ZIP 文件');
|
||||
return;
|
||||
}
|
||||
if (readyFiles.length < files.length) {
|
||||
ElMessage.warning(`已跳过 ${files.length - readyFiles.length} 个不支持、空文件或超限文件(文档/图片 100MB、视频/ZIP 500MB)`);
|
||||
ElMessage.warning(`已跳过 ${files.length - readyFiles.length} 个不支持、空文件或超过 500MB 的文件`);
|
||||
}
|
||||
|
||||
const totalSize = readyFiles.reduce((sum, file) => sum + file.size, 0);
|
||||
|
||||
Reference in New Issue
Block a user