ow
This commit is contained in:
1 parent
7fb4503e0e
commit
69046e827c
9 files changed
+292
-245
No files matched your search
@@ -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 {
|
||||
<view v-if="file.kind === 'folder'" class="fgl-card__folder" :style="folderStyle">
|
||||
<view class="fgl-card__folder-tab" :style="folderTabStyle" />
|
||||
</view>
|
||||
<!-- 图片卡:后端 Url 指向 Scale 原图压缩缩略(旧系统宫格同款),失败回退图标 -->
|
||||
<!-- 缩略图:图片是后端 Scale 压缩图,视频是上传时 ffmpeg 抽的同名 jpg(旧系统 MyComputer 同款),失败回退图标 -->
|
||||
<image v-else-if="thumbSrcOf(file)" class="fgl-card__thumb" :src="thumbSrcOf(file)"
|
||||
mode="aspectFill" @error="onThumbError(file)" />
|
||||
<u-icon v-else :name="visualOf(file.kind)!.icon" size="88" :color="visualOf(file.kind)!.color" />
|
||||
@@ -134,6 +134,10 @@ function onCardTap(file: FileItem): void {
|
||||
:color="file.permission === 'Y' ? '#52c41a' : '#8c8c8c'" />
|
||||
<u-icon v-if="file.shared" name="share-fill" size="28" color="#1890ff" />
|
||||
</view>
|
||||
<!-- 视频封右下角的播放角标(旧系统 play-overlay 同位):没截到图回退图标时不叠 -->
|
||||
<view v-if="file.kind === 'video' && thumbSrcOf(file)" class="fgl-card__play">
|
||||
<u-icon name="play-right-fill" size="18" color="#ffffff" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="fgl-card__info">
|
||||
@@ -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;
|
||||
|
||||
@@ -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<FileKind[]>,
|
||||
default: () => ["image", "audio", "document"],
|
||||
},
|
||||
/** 弹层是否展开 */
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** 可选文件类型(folder 不在此列也始终可进入) */
|
||||
accept: {
|
||||
type: Array as PropType<FileKind[]>,
|
||||
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<FileItem[]>(() =>
|
||||
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<void> {
|
||||
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<void> {
|
||||
const stayed = await files.back();
|
||||
if (!stayed) {
|
||||
emit("close");
|
||||
}
|
||||
const stayed = await files.back();
|
||||
if (!stayed) {
|
||||
emit("close");
|
||||
}
|
||||
}
|
||||
|
||||
async function onSearch(): Promise<void> {
|
||||
await files.search(keyword.value);
|
||||
await files.search(keyword.value);
|
||||
}
|
||||
|
||||
/** 文件类型 -> 图标与配色(与 file-grid-list 同套;文件夹用 CSS 造型,图标库没有 folder) */
|
||||
const kindVisual: Record<Exclude<FileKind, "folder">, { 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<number>());
|
||||
|
||||
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 : "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- u-popup 只认 modelValue(v-model),绑 :show 会静默弹不出 -->
|
||||
<u-popup :model-value="visible" mode="bottom" round="24" @close="emit('close')">
|
||||
<view class="file-pick">
|
||||
<view class="file-pick__head">
|
||||
<text class="file-pick__title">{{ t("FilePage.pickFile") }}</text>
|
||||
<u-icon name="close" size="32" color="#8f959e" @click="emit('close')" />
|
||||
</view>
|
||||
<!-- u-popup 只认 modelValue(v-model),绑 :show 会静默弹不出 -->
|
||||
<u-popup :model-value="visible" mode="bottom" round="24" @close="emit('close')">
|
||||
<view class="file-pick">
|
||||
<view class="file-pick__head">
|
||||
<text class="file-pick__title">{{ t("FilePage.pickFile") }}</text>
|
||||
<u-icon name="close" size="32" color="#8f959e" @click="emit('close')" />
|
||||
</view>
|
||||
|
||||
<!-- 当前目录 + 返回上级 -->
|
||||
<view class="file-pick__bar">
|
||||
<view class="file-pick__back" @tap="onBack">
|
||||
<u-icon name="arrow-left" size="28" color="#5c626b" />
|
||||
</view>
|
||||
<text class="file-pick__path">{{ currName }}</text>
|
||||
</view>
|
||||
<!-- 当前目录 + 返回上级 -->
|
||||
<view class="file-pick__bar">
|
||||
<view class="file-pick__back" @tap="onBack">
|
||||
<u-icon name="arrow-left" size="28" color="#5c626b" />
|
||||
</view>
|
||||
<text class="file-pick__path">{{ currName }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 按名称搜索当前目录(回车或点放大镜) -->
|
||||
<view class="file-pick__search">
|
||||
<input v-model="keyword" class="file-pick__search-input" :placeholder="t('FilePage.searchPlaceholder')"
|
||||
confirm-type="search" @confirm="onSearch">
|
||||
<view class="file-pick__search-btn" @tap="onSearch">
|
||||
<u-icon name="search" size="32" color="#8f959e" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 按名称搜索当前目录(回车或点放大镜) -->
|
||||
<view class="file-pick__search">
|
||||
<input v-model="keyword" class="file-pick__search-input" :placeholder="t('FilePage.searchPlaceholder')"
|
||||
confirm-type="search" @confirm="onSearch">
|
||||
<view class="file-pick__search-btn" @tap="onSearch">
|
||||
<u-icon name="search" size="32" color="#8f959e" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="file-pick__list">
|
||||
<view v-if="loading" class="file-pick__empty">
|
||||
<text>{{ t("FilePage.loading") }}</text>
|
||||
</view>
|
||||
<view v-else-if="!rows.length" class="file-pick__empty">
|
||||
<text>{{ t("FilePage.emptyText") }}</text>
|
||||
</view>
|
||||
<view v-for="row in rows" :key="row.id" class="file-pick__row" @tap="onTap(row)">
|
||||
<view v-if="row.kind === 'folder'" class="file-pick__folder" :style="{ background: accentGradient }">
|
||||
<view class="file-pick__folder-tab" :style="{ background: accentGradient }" />
|
||||
</view>
|
||||
<!-- 图片行:后端 Url 指向 Scale 压缩缩略(网盘宫格同源),失败回退类型图标 -->
|
||||
<image v-else-if="thumbSrcOf(row)" class="file-pick__thumb" :src="thumbSrcOf(row)"
|
||||
mode="aspectFill" @error="onThumbError(row)" />
|
||||
<u-icon v-else :name="visualOf(row.kind).icon" size="36" :color="visualOf(row.kind).color" />
|
||||
<view class="file-pick__row-main">
|
||||
<text class="file-pick__row-name">{{ row.name }}</text>
|
||||
<text v-if="row.sizeText" class="file-pick__row-meta">{{ row.sizeText }}</text>
|
||||
</view>
|
||||
<u-icon v-if="row.kind === 'folder'" name="arrow-right" size="24" color="#c0c4cc" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
<scroll-view scroll-y class="file-pick__list">
|
||||
<view v-if="loading" class="file-pick__empty">
|
||||
<text>{{ t("FilePage.loading") }}</text>
|
||||
</view>
|
||||
<view v-else-if="!rows.length" class="file-pick__empty">
|
||||
<text>{{ t("FilePage.emptyText") }}</text>
|
||||
</view>
|
||||
<view v-for="row in rows" :key="row.id" class="file-pick__row" @tap="onTap(row)">
|
||||
<view v-if="row.kind === 'folder'" class="file-pick__folder"
|
||||
:style="{ background: accentGradient }">
|
||||
<view class="file-pick__folder-tab" :style="{ background: accentGradient }" />
|
||||
</view>
|
||||
<!-- 缩略图:图片走 Scale 压缩图,视频走后端抽的同名 jpg(网盘宫格同源),失败回退类型图标 -->
|
||||
<image v-else-if="thumbSrcOf(row)" class="file-pick__thumb" :src="thumbSrcOf(row)" mode="aspectFill"
|
||||
@error="onThumbError(row)" />
|
||||
<u-icon v-else :name="visualOf(row.kind).icon" size="36" :color="visualOf(row.kind).color" />
|
||||
<view class="file-pick__row-main">
|
||||
<text class="file-pick__row-name">{{ row.name }}</text>
|
||||
<text v-if="row.sizeText" class="file-pick__row-meta">{{ row.sizeText }}</text>
|
||||
</view>
|
||||
<u-icon v-if="row.kind === 'folder'" name="arrow-right" size="24" color="#c0c4cc" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="file-pick__safe" />
|
||||
</view>
|
||||
</u-popup>
|
||||
<view class="file-pick__safe" />
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 底部抽屉统一风格:浅灰面板底 + 白色圆角行 */
|
||||
.file-pick {
|
||||
padding: 32rpx 24rpx 0;
|
||||
background-color: #f2f3f5;
|
||||
padding: 32rpx 24rpx 0;
|
||||
background-color: #f2f3f5;
|
||||
|
||||
&__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 8rpx 24rpx;
|
||||
}
|
||||
&__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 8rpx 24rpx;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
}
|
||||
&__title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
&__bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
&__bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
&__back {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
&__back {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__path {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
font-size: 26rpx;
|
||||
color: #5c626b;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&__path {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
font-size: 26rpx;
|
||||
color: #5c626b;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
height: 76rpx;
|
||||
margin-top: 16rpx;
|
||||
padding: 0 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
&__search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
height: 76rpx;
|
||||
margin-top: 16rpx;
|
||||
padding: 0 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
&__search-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
}
|
||||
&__search-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
&__search-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
&__search-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__list {
|
||||
height: 52vh;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
&__list {
|
||||
height: 52vh;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
&__row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 16rpx;
|
||||
padding: 24rpx 28rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
&__row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 16rpx;
|
||||
padding: 24rpx 28rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
&__row-main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
&__row-main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 图片预览缩略:尺寸与网盘宫格缩略一致 */
|
||||
&__thumb {
|
||||
flex-shrink: 0;
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 14rpx;
|
||||
background-color: rgba(31, 35, 41, 0.04);
|
||||
}
|
||||
/* 图片预览缩略:尺寸与网盘宫格缩略一致 */
|
||||
&__thumb {
|
||||
flex-shrink: 0;
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 14rpx;
|
||||
background-color: rgba(31, 35, 41, 0.04);
|
||||
}
|
||||
|
||||
&__row-name {
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&__row-name {
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__row-meta {
|
||||
margin-top: 6rpx;
|
||||
font-size: 22rpx;
|
||||
color: #a8adb5;
|
||||
}
|
||||
&__row-meta {
|
||||
margin-top: 6rpx;
|
||||
font-size: 22rpx;
|
||||
color: #a8adb5;
|
||||
}
|
||||
|
||||
/* 文件夹:纯 CSS 造型(主体 + 左上页签) */
|
||||
&__folder {
|
||||
position: relative;
|
||||
width: 44rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
/* 文件夹:纯 CSS 造型(主体 + 左上页签) */
|
||||
&__folder {
|
||||
position: relative;
|
||||
width: 44rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
|
||||
&__folder-tab {
|
||||
position: absolute;
|
||||
top: -8rpx;
|
||||
left: 0;
|
||||
width: 20rpx;
|
||||
height: 10rpx;
|
||||
border-radius: 4rpx 4rpx 0 0;
|
||||
}
|
||||
&__folder-tab {
|
||||
position: absolute;
|
||||
top: -8rpx;
|
||||
left: 0;
|
||||
width: 20rpx;
|
||||
height: 10rpx;
|
||||
border-radius: 4rpx 4rpx 0 0;
|
||||
}
|
||||
|
||||
&__empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx 0;
|
||||
font-size: 26rpx;
|
||||
color: #a8adb5;
|
||||
}
|
||||
&__empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx 0;
|
||||
font-size: 26rpx;
|
||||
color: #a8adb5;
|
||||
}
|
||||
|
||||
/* 底部留白:贴屏安全区 */
|
||||
&__safe {
|
||||
height: calc(32rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
/* 底部留白:贴屏安全区 */
|
||||
&__safe {
|
||||
height: calc(32rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1013,7 +1013,8 @@ function onRemoveGroup(familyName: string): void {
|
||||
<u-icon name="close" size="32" color="#8f959e" @click="closeDetailEditor" />
|
||||
</view>
|
||||
<!-- 音轨 6 个字段超出小屏时表单内滚动,按钮固定在底部 -->
|
||||
<scroll-view scroll-y class="detail-sheet__scroll" :class="{ 'detail-sheet__scroll--audio': kind === 'audio' }">
|
||||
<scroll-view scroll-y class="detail-sheet__scroll"
|
||||
:class="{ 'detail-sheet__scroll--audio': kind === 'audio' }">
|
||||
<view class="detail-sheet__form">
|
||||
<!-- 音轨:标题/歌手/封面/地址/歌词(对齐旧系统表单),文件字段走「我的网盘」选择 -->
|
||||
<template v-if="kind === 'audio'">
|
||||
@@ -1031,10 +1032,9 @@ function onRemoveGroup(familyName: string): void {
|
||||
<text class="detail-sheet-field__label">{{ t("MediaPage.detailCover") }}</text>
|
||||
<view class="detail-sheet-field__file">
|
||||
<view class="detail-sheet-field__static">
|
||||
<text
|
||||
class="detail-sheet-field__static-text"
|
||||
:class="{ 'detail-sheet-field__static-text--empty': !detailDraft.picName }"
|
||||
>{{ detailDraft.picName || t("MediaPage.detailCover") }}</text>
|
||||
<text class="detail-sheet-field__static-text"
|
||||
:class="{ 'detail-sheet-field__static-text--empty': !detailDraft.picName }">{{
|
||||
detailDraft.picName || t("MediaPage.detailCover") }}</text>
|
||||
</view>
|
||||
<view class="detail-sheet-field__pick" @tap="openFilePicker('pic')">
|
||||
<u-icon name="search" size="32" color="#8f959e" />
|
||||
@@ -1045,10 +1045,9 @@ function onRemoveGroup(familyName: string): void {
|
||||
<text class="detail-sheet-field__label">{{ t("MediaPage.detailUrl") }}</text>
|
||||
<view class="detail-sheet-field__file">
|
||||
<view class="detail-sheet-field__static">
|
||||
<text
|
||||
class="detail-sheet-field__static-text"
|
||||
:class="{ 'detail-sheet-field__static-text--empty': !detailDraft.urlName }"
|
||||
>{{ detailDraft.urlName || t("MediaPage.detailUrl") }}</text>
|
||||
<text class="detail-sheet-field__static-text"
|
||||
:class="{ 'detail-sheet-field__static-text--empty': !detailDraft.urlName }">{{
|
||||
detailDraft.urlName || t("MediaPage.detailUrl") }}</text>
|
||||
</view>
|
||||
<view class="detail-sheet-field__pick" @tap="openFilePicker('url')">
|
||||
<u-icon name="search" size="32" color="#8f959e" />
|
||||
@@ -1059,10 +1058,9 @@ function onRemoveGroup(familyName: string): void {
|
||||
<text class="detail-sheet-field__label">{{ t("MediaPage.detailLrc") }}</text>
|
||||
<view class="detail-sheet-field__file">
|
||||
<view class="detail-sheet-field__static">
|
||||
<text
|
||||
class="detail-sheet-field__static-text"
|
||||
:class="{ 'detail-sheet-field__static-text--empty': !detailDraft.lrcName }"
|
||||
>{{ detailDraft.lrcName || t("MediaPage.detailLrc") }}</text>
|
||||
<text class="detail-sheet-field__static-text"
|
||||
:class="{ 'detail-sheet-field__static-text--empty': !detailDraft.lrcName }">{{
|
||||
detailDraft.lrcName || t("MediaPage.detailLrc") }}</text>
|
||||
</view>
|
||||
<view class="detail-sheet-field__pick" @tap="openFilePicker('lrc')">
|
||||
<u-icon name="search" size="32" color="#8f959e" />
|
||||
@@ -1092,8 +1090,8 @@ function onRemoveGroup(familyName: string): void {
|
||||
</u-popup>
|
||||
|
||||
<!-- 明细文件选择(封面/地址/歌词):从我的网盘挑文件,回填 DMS 文件名 -->
|
||||
<file-picker-sheet :visible="filePickerVisible" :accept="filePickerAccept"
|
||||
@close="filePickerVisible = false" @select="onPickFile" />
|
||||
<file-picker-sheet :visible="filePickerVisible" :accept="filePickerAccept" @close="filePickerVisible = false"
|
||||
@select="onPickFile" />
|
||||
</view>
|
||||
</app-page>
|
||||
</template>
|
||||
|
||||
Reference in new issue
Block a user