diff --git a/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs index 79512cf..6a3f6f1 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs @@ -1456,6 +1456,14 @@ namespace CloudBuilder.Master.Service { ImageToScare(fullName, dmsFile); } + else if (FileTypePolicy.GetType(fileExtension.ToLower()) == FileTypePolicy.VIDEO) + { + // 单片上传(小文件、App 端整文件不分片)也要出视频封面:走与多片合并分支同一条链, + // 截图落在备份目录里的同名 .jpg(前端宫格/详情封面读的就是这个文件), + // 否则只有被切成多片的视频有封面,小视频上传后永远是黑块 + dmsFile.TranscodeIndc = YesNoPolicy.YES; + TsToM3u8(dmsFile.OrderKey, backupName, backupName.Replace(fileExtension, FileTypePolicy.JPG)); + } } else//合并文件 { diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user index 7e78ab0..82c436f 100644 --- a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user @@ -3,7 +3,7 @@ <_PublishTargetUrl>C:\inetpub\wwwroot\dockwebapi2 - True|2026-10-20T07:45:39.3393674Z||;True|2026-10-17T20:49:21.0401213+08:00||;True|2026-09-23T13:19:13.0148919+08:00||;True|2026-09-23T13:16:07.8584304+08:00||;True|2026-09-22T23:03:13.6509491+08:00||;True|2026-09-22T16:07:15.9177123+08:00||;True|2026-09-22T11:19:19.6087109+08:00||;True|2026-09-22T11:09:24.9165065+08:00||;True|2026-09-21T22:40:07.1232044+08:00||;True|2026-09-21T22:35:06.9446571+08:00||;True|2026-09-21T22:27:42.1146825+08:00||;False|2026-09-21T22:27:17.6066573+08:00||;True|2026-09-21T21:01:22.8888913+08:00||;True|2026-09-21T19:15:03.4753747+08:00||;True|2026-09-21T18:08:30.0866986+08:00||;True|2026-09-21T16:51:19.8137872+08:00||;True|2026-09-21T16:30:01.0950896+08:00||;True|2026-09-21T15:09:00.2326737+08:00||;True|2026-09-21T14:47:09.6120256+08:00||;True|2026-09-21T14:16:35.3194409+08:00||;True|2026-09-21T13:54:58.2829712+08:00||;True|2026-09-21T13:36:45.3134499+08:00||;True|2026-09-19T09:48:52.0085130+08:00||;False|2026-09-19T09:47:56.1658214+08:00||;True|2026-09-17T18:50:15.9493380+08:00||;True|2026-09-17T18:11:11.5364547+08:00||;True|2026-09-17T18:07:27.7830758+08:00||;True|2026-09-17T17:58:16.5798560+08:00||;True|2026-09-17T15:37:30.9025614+08:00||;True|2026-09-17T15:25:46.9116292+08:00||;True|2026-09-17T15:05:18.6592403+08:00||;True|2026-09-17T14:57:28.7997437+08:00||;True|2026-09-17T14:36:00.6339386+08:00||;True|2026-09-17T13:56:43.2376873+08:00||;True|2026-09-16T13:56:51.8724546+08:00||;True|2026-09-15T20:44:46.6559899+08:00||;True|2026-09-13T19:02:59.5654245+08:00||;True|2026-09-10T09:14:56.2914193+08:00||;True|2026-09-09T16:40:16.6461154+08:00||;True|2026-09-08T13:55:23.1502435+08:00||;True|2026-09-08T08:04:53.4279263+08:00||;True|2026-09-07T08:48:17.4682304+08:00||;True|2026-09-04T14:39:08.7878670+08:00||;True|2026-09-04T14:35:48.2937877+08:00||;True|2026-09-04T11:45:16.1372876+08:00||;True|2026-09-04T11:42:59.9356436+08:00||;True|2026-09-03T16:05:52.5270232+08:00||;True|2026-09-03T14:52:56.8559144+08:00||;True|2026-09-02T11:08:23.8720038+08:00||;True|2026-09-02T10:58:16.8081797+08:00||;True|2026-08-26T13:34:12.3805892+08:00||;True|2026-08-25T08:31:30.7787234+08:00||;True|2026-08-20T13:10:46.4725468+08:00||;True|2026-08-20T13:10:28.3142576+08:00||;True|2026-08-19T16:10:27.3362887+08:00||;True|2026-08-19T16:01:12.6234971+08:00||;True|2026-08-19T15:42:46.6576265+08:00||;True|2026-08-19T13:39:59.9363522+08:00||;True|2026-08-19T13:36:53.0379313+08:00||;True|2026-08-19T13:31:36.0841398+08:00||;True|2026-08-19T11:44:37.5319626+08:00||;True|2026-08-19T09:36:45.6000047+08:00||;True|2026-08-19T09:34:36.8468631+08:00||;True|2026-08-19T08:35:41.2202300+08:00||;True|2026-08-18T16:20:59.0170916+08:00||; + True|2026-10-21T13:22:01.1456473Z||;True|2026-10-20T15:45:39.3393674+08:00||;True|2026-10-17T20:49:21.0401213+08:00||;True|2026-09-23T13:19:13.0148919+08:00||;True|2026-09-23T13:16:07.8584304+08:00||;True|2026-09-22T23:03:13.6509491+08:00||;True|2026-09-22T16:07:15.9177123+08:00||;True|2026-09-22T11:19:19.6087109+08:00||;True|2026-09-22T11:09:24.9165065+08:00||;True|2026-09-21T22:40:07.1232044+08:00||;True|2026-09-21T22:35:06.9446571+08:00||;True|2026-09-21T22:27:42.1146825+08:00||;False|2026-09-21T22:27:17.6066573+08:00||;True|2026-09-21T21:01:22.8888913+08:00||;True|2026-09-21T19:15:03.4753747+08:00||;True|2026-09-21T18:08:30.0866986+08:00||;True|2026-09-21T16:51:19.8137872+08:00||;True|2026-09-21T16:30:01.0950896+08:00||;True|2026-09-21T15:09:00.2326737+08:00||;True|2026-09-21T14:47:09.6120256+08:00||;True|2026-09-21T14:16:35.3194409+08:00||;True|2026-09-21T13:54:58.2829712+08:00||;True|2026-09-21T13:36:45.3134499+08:00||;True|2026-09-19T09:48:52.0085130+08:00||;False|2026-09-19T09:47:56.1658214+08:00||;True|2026-09-17T18:50:15.9493380+08:00||;True|2026-09-17T18:11:11.5364547+08:00||;True|2026-09-17T18:07:27.7830758+08:00||;True|2026-09-17T17:58:16.5798560+08:00||;True|2026-09-17T15:37:30.9025614+08:00||;True|2026-09-17T15:25:46.9116292+08:00||;True|2026-09-17T15:05:18.6592403+08:00||;True|2026-09-17T14:57:28.7997437+08:00||;True|2026-09-17T14:36:00.6339386+08:00||;True|2026-09-17T13:56:43.2376873+08:00||;True|2026-09-16T13:56:51.8724546+08:00||;True|2026-09-15T20:44:46.6559899+08:00||;True|2026-09-13T19:02:59.5654245+08:00||;True|2026-09-10T09:14:56.2914193+08:00||;True|2026-09-09T16:40:16.6461154+08:00||;True|2026-09-08T13:55:23.1502435+08:00||;True|2026-09-08T08:04:53.4279263+08:00||;True|2026-09-07T08:48:17.4682304+08:00||;True|2026-09-04T14:39:08.7878670+08:00||;True|2026-09-04T14:35:48.2937877+08:00||;True|2026-09-04T11:45:16.1372876+08:00||;True|2026-09-04T11:42:59.9356436+08:00||;True|2026-09-03T16:05:52.5270232+08:00||;True|2026-09-03T14:52:56.8559144+08:00||;True|2026-09-02T11:08:23.8720038+08:00||;True|2026-09-02T10:58:16.8081797+08:00||;True|2026-08-26T13:34:12.3805892+08:00||;True|2026-08-25T08:31:30.7787234+08:00||;True|2026-08-20T13:10:46.4725468+08:00||;True|2026-08-20T13:10:28.3142576+08:00||;True|2026-08-19T16:10:27.3362887+08:00||;True|2026-08-19T16:01:12.6234971+08:00||;True|2026-08-19T15:42:46.6576265+08:00||;True|2026-08-19T13:39:59.9363522+08:00||;True|2026-08-19T13:36:53.0379313+08:00||;True|2026-08-19T13:31:36.0841398+08:00||;True|2026-08-19T11:44:37.5319626+08:00||;True|2026-08-19T09:36:45.6000047+08:00||;True|2026-08-19T09:34:36.8468631+08:00||;True|2026-08-19T08:35:41.2202300+08:00||;True|2026-08-18T16:20:59.0170916+08:00||; \ No newline at end of file diff --git a/uniapp/youjiala/src/components/file-grid-list/file-grid-list.vue b/uniapp/youjiala/src/components/file-grid-list/file-grid-list.vue index 1962673..97f3859 100644 --- a/uniapp/youjiala/src/components/file-grid-list/file-grid-list.vue +++ b/uniapp/youjiala/src/components/file-grid-list/file-grid-list.vue @@ -65,9 +65,9 @@ function onThumbError(file: FileItem): void { thumbFailed.value.add(file.id); } -/** 可显缩略图的地址:仅图片类型且后端 Url(Scale 压缩图)有值、未报错 */ +/** 可显缩略图的地址:图片是 Scale 压缩图、视频是上传时抽的同名 jpg(两者都在 thumbUrl 里),有值且未报错才显 */ function thumbSrcOf(file: FileItem): string { - return file.kind === "image" && file.thumbUrl && !thumbFailed.value.has(file.id) ? file.thumbUrl : ""; + return file.thumbUrl && !thumbFailed.value.has(file.id) ? file.thumbUrl : ""; } function isSelected(file: FileItem): boolean { @@ -120,7 +120,7 @@ function onCardTap(file: FileItem): void { - + @@ -134,6 +134,10 @@ function onCardTap(file: FileItem): void { :color="file.permission === 'Y' ? '#52c41a' : '#8c8c8c'" /> + + + + @@ -259,6 +263,20 @@ function onCardTap(file: FileItem): void { background-color: rgba(31, 35, 41, 0.04); } +/* 视频播放角标:压在封面右下角,半透黑圆底 + 白三角 */ +.fgl-card__play { + position: absolute; + right: 6rpx; + bottom: 6rpx; + display: flex; + align-items: center; + justify-content: center; + width: 36rpx; + height: 36rpx; + border-radius: 50%; + background-color: rgba(31, 35, 41, 0.55); +} + .fgl-card__info { width: 100%; padding: 0 12rpx; diff --git a/uniapp/youjiala/src/components/file-picker-sheet/file-picker-sheet.vue b/uniapp/youjiala/src/components/file-picker-sheet/file-picker-sheet.vue index 734f104..0db9e95 100644 --- a/uniapp/youjiala/src/components/file-picker-sheet/file-picker-sheet.vue +++ b/uniapp/youjiala/src/components/file-picker-sheet/file-picker-sheet.vue @@ -12,23 +12,23 @@ import { computed, ref, watch } from "vue"; import { useDmsFiles, useThemeTokens } from "@/composables"; const props = defineProps({ - /** 弹层是否展开 */ - visible: { - type: Boolean, - default: false, - }, - /** 可选文件类型(folder 不在此列也始终可进入) */ - accept: { - type: Array as PropType, - default: () => ["image", "audio", "document"], - }, + /** 弹层是否展开 */ + visible: { + type: Boolean, + default: false, + }, + /** 可选文件类型(folder 不在此列也始终可进入) */ + accept: { + type: Array as PropType, + default: () => ["image", "audio", "document"], + }, }); const emit = defineEmits<{ - /** 关闭弹层(遮罩/关闭按钮/根目录点返回) */ - (e: "close"): void; - /** 选中一个文件,回传完整记录(FileName 是提交值,Url 可直接预览) */ - (e: "select", record: DmsFileUploadViewDisplayData): void; + /** 关闭弹层(遮罩/关闭按钮/根目录点返回) */ + (e: "close"): void; + /** 选中一个文件,回传完整记录(FileName 是提交值,Url 可直接预览) */ + (e: "select", record: DmsFileUploadViewDisplayData): void; }>(); const { t } = useLocale(); @@ -39,278 +39,279 @@ const keyword = ref(""); /** 类型过滤:文件夹保留用于下钻,文件只留 accept 内的类型 */ const rows = computed(() => - files.files.value.filter( - file => file.kind === "folder" || props.accept.includes(file.kind), - ), + files.files.value.filter( + file => file.kind === "folder" || props.accept.includes(file.kind), + ), ); const loading = files.loading; /** 当前目录名(面包屑末项),用于顶部路径展示 */ const currName = computed( - () => files.pathStack.value[files.pathStack.value.length - 1]?.displayName || t("FilePage.myCloud"), + () => files.pathStack.value[files.pathStack.value.length - 1]?.displayName || t("FilePage.myCloud"), ); // 每次打开都从「我的网盘」根目录重新加载:目录可能被别的操作改过,也避免停在上一轮的下钻位置 watch( - () => props.visible, - (open) => { - if (!open) { - return; - } - keyword.value = ""; - void files.init(); - }, - { immediate: true }, + () => props.visible, + (open) => { + if (!open) { + return; + } + keyword.value = ""; + void files.init(); + }, + { immediate: true }, ); /** 点文件夹下钻,点文件回传并关闭 */ async function onTap(row: FileItem): Promise { - if (row.kind === "folder") { - await files.openFolder(row); - return; - } - const record = files.records.value.get(row.id); - if (!record) { - return; - } - emit("select", record); - emit("close"); + if (row.kind === "folder") { + await files.openFolder(row); + return; + } + const record = files.records.value.get(row.id); + if (!record) { + return; + } + emit("select", record); + emit("close"); } /** 返回上级;已在根目录则关闭弹层 */ async function onBack(): Promise { - const stayed = await files.back(); - if (!stayed) { - emit("close"); - } + const stayed = await files.back(); + if (!stayed) { + emit("close"); + } } async function onSearch(): Promise { - await files.search(keyword.value); + await files.search(keyword.value); } /** 文件类型 -> 图标与配色(与 file-grid-list 同套;文件夹用 CSS 造型,图标库没有 folder) */ const kindVisual: Record, { icon: string; color: string }> = { - image: { icon: "photo-fill", color: "#0ea5e9" }, - video: { icon: "play-right-fill", color: "#8b5cf6" }, - document: { icon: "file-text-fill", color: "#3b82f6" }, - audio: { icon: "volume-up", color: "#f59e0b" }, + image: { icon: "photo-fill", color: "#0ea5e9" }, + video: { icon: "play-right-fill", color: "#8b5cf6" }, + document: { icon: "file-text-fill", color: "#3b82f6" }, + audio: { icon: "volume-up", color: "#f59e0b" }, }; function visualOf(kind: FileKind): { icon: string; color: string } { - return kind === "folder" ? { icon: "file-text-fill", color: "#8f959e" } : kindVisual[kind]; + return kind === "folder" ? { icon: "file-text-fill", color: "#8f959e" } : kindVisual[kind]; } // 缩略图加载失败的行记住失败态,回退类型图标(与网盘宫格同一套处理,图被清理时不致白块) const thumbFailed = ref(new Set()); function onThumbError(row: FileItem): void { - thumbFailed.value.add(row.id); + thumbFailed.value.add(row.id); } -/** 可显缩略图的地址:仅图片类型且后端 Url(Scale 压缩图)有值、未报错 */ +/** 可显缩略图的地址:图片是 Scale 压缩图、视频是上传时抽的同名 jpg(两者都在 thumbUrl 里),有值且未报错才显 */ function thumbSrcOf(row: FileItem): string { - return row.kind === "image" && row.thumbUrl && !thumbFailed.value.has(row.id) ? row.thumbUrl : ""; + return row.thumbUrl && !thumbFailed.value.has(row.id) ? row.thumbUrl : ""; } diff --git a/uniapp/youjiala/src/composables/useDmsFiles.ts b/uniapp/youjiala/src/composables/useDmsFiles.ts index 2b0c678..ebc6ce4 100644 --- a/uniapp/youjiala/src/composables/useDmsFiles.ts +++ b/uniapp/youjiala/src/composables/useDmsFiles.ts @@ -20,6 +20,7 @@ import { computed, ref } from "vue"; import { DmsFileSearchCriteria } from "@/data/auto/dmsFileSearchCriteria"; import { DmsFileUploadViewDisplayData as UploadView } from "@/data/auto/dmsFileUploadViewDisplayData"; import { SearchFilter } from "@/data/auto/searchFilter"; +import { pickThumbUrl } from "@/data/custom/fileBrowser"; import fileTypePolicy, { FileTypePolicy } from "@/policy/custom/fileTypePolicy"; import dmsFileService from "@/service/master/dmsFileService"; @@ -132,8 +133,8 @@ export function useDmsFiles() { id: record.FileId, name: record.OrgFileName || record.FileName, kind, - // 图片卡显 Scale 缩略图(后端 Url 字段已拼好,旧系统宫格同款) - thumbUrl: kind === "image" ? record.Url || undefined : undefined, + // 图片卡显 Scale 缩略图(后端 Url),视频卡显上传时抽的同名 jpg(后端 FormattedPic,旧系统视频卡同款) + thumbUrl: pickThumbUrl(kind, record.Url, record.FormattedPic), // 卡片元数据不显示用户:文件夹 sizeText 为空只剩时间,文件显示大小+时间 // FileSize 单位是 KB(旧系统 DmsFileEnquiry 下载缓冲 (FileSize+1)*1024 字节佐证),先换算成字节 sizeText: formatSize( diff --git a/uniapp/youjiala/src/composables/useShareHall.ts b/uniapp/youjiala/src/composables/useShareHall.ts index 6831c46..6ba7e31 100644 --- a/uniapp/youjiala/src/composables/useShareHall.ts +++ b/uniapp/youjiala/src/composables/useShareHall.ts @@ -24,6 +24,7 @@ import { DmsFileSearchCriteria } from "@/data/auto/dmsFileSearchCriteria"; import { FamilyDmsFileViewDisplayData as FamilyView } from "@/data/auto/familyDmsFileViewDisplayData"; import { FamilyDmsFileViewEntity } from "@/data/auto/familyDmsFileViewEntity"; import { SearchFilter } from "@/data/auto/searchFilter"; +import { pickThumbUrl } from "@/data/custom/fileBrowser"; import dmsFileService from "@/service/master/dmsFileService"; import familyGroupService from "@/service/master/familyGroupService"; import { @@ -88,8 +89,8 @@ export function useShareHall() { id: record.FileId, name: record.OrgFileName || record.FileName, kind, - // 图片卡显 Scale 缩略图(后端 Url 字段已拼好,旧系统宫格同款) - thumbUrl: kind === "image" ? record.Url || undefined : undefined, + // 图片卡显 Scale 缩略图(后端 Url),视频卡显上传时抽的同名 jpg(后端 FormattedPic,旧系统视频卡同款) + thumbUrl: pickThumbUrl(kind, record.Url, record.FormattedPic), // FileSize 单位是 KB(旧系统下载缓冲 (FileSize+1)*1024 字节佐证),先换算成字节 sizeText: formatSize( record.FileSize ? record.FileSize * 1024 : undefined, diff --git a/uniapp/youjiala/src/composables/useTrashFiles.ts b/uniapp/youjiala/src/composables/useTrashFiles.ts index 123d1c1..c535be2 100644 --- a/uniapp/youjiala/src/composables/useTrashFiles.ts +++ b/uniapp/youjiala/src/composables/useTrashFiles.ts @@ -16,6 +16,7 @@ import { ref } from "vue"; import { DmsFileSearchCriteria } from "@/data/auto/dmsFileSearchCriteria"; import { DmsFileUploadDeleteLogViewDisplayData as DeleteLogView } from "@/data/auto/dmsFileUploadDeleteLogViewDisplayData"; import { SearchFilter } from "@/data/auto/searchFilter"; +import { pickThumbUrl } from "@/data/custom/fileBrowser"; import dmsFileService from "@/service/master/dmsFileService"; import { formatModifiedLabel, @@ -45,8 +46,8 @@ export function useTrashFiles() { id: record.FileId, name: record.OrgFileName || record.FileName, kind, - // 回收站也显缩略图(日志视图 Url 同口径拼的 Scale 图,文件删了图还在) - thumbUrl: kind === "image" ? record.Url || undefined : undefined, + // 回收站也显缩略图:图片是 Scale 压缩图、视频是同名 jpg 封面(日志视图同口径拼的,文件删了图还在) + thumbUrl: pickThumbUrl(kind, record.Url, record.FormattedPic), // FileSize 单位是 KB(旧系统下载缓冲 (FileSize+1)*1024 字节佐证),先换算成字节 sizeText: formatSize( record.FileSize ? record.FileSize * 1024 : undefined, diff --git a/uniapp/youjiala/src/data/custom/fileBrowser.ts b/uniapp/youjiala/src/data/custom/fileBrowser.ts index b6c6be5..5f21aa3 100644 --- a/uniapp/youjiala/src/data/custom/fileBrowser.ts +++ b/uniapp/youjiala/src/data/custom/fileBrowser.ts @@ -28,10 +28,29 @@ export interface FileItem { permission?: "Y" | "N"; /** 已被收藏共享(PermissionIndc=Y 且 FavoriteIndc=Y):显示蓝色共享角标 */ shared?: boolean; - /** 图片缩略图地址(后端 PackUrl 拼的 Scale 压缩图,旧系统宫格同款);仅 image 类型且有值时卡片显图,否则显类型图标 */ + /** 缩略图地址:图片是后端 PackUrl 拼的 Scale 压缩图,视频是后端 ffmpeg 截的同名 jpg(旧系统 MyComputer 同款); + * 没值(如老视频从未截过图)时卡片回退类型图标 */ thumbUrl?: string; } +/** + * 卡片缩略图取值:图片用 Url(Scale 压缩图)、视频用 FormattedPic(上传时抽帧的同名 .jpg), + * 其余类型不给图。三处列表(网盘 / 共享域 / 回收站)统一走这里,不再各自写判断。 + */ +export function pickThumbUrl( + kind: FileKind, + url?: string | null, + formattedPic?: string | null, +): string | undefined { + if (kind === "image") { + return url || undefined; + } + if (kind === "video") { + return formattedPic || undefined; + } + return undefined; +} + /** 快捷功能入口的单项:图标 + 渐变底色,页面给什么画什么 */ export interface QuickEntryItem { key: string; diff --git a/uniapp/youjiala/src/pages/tab/media.vue b/uniapp/youjiala/src/pages/tab/media.vue index 3746e47..424045d 100644 --- a/uniapp/youjiala/src/pages/tab/media.vue +++ b/uniapp/youjiala/src/pages/tab/media.vue @@ -1013,7 +1013,8 @@ function onRemoveGroup(familyName: string): void { - +