This commit is contained in:
owenchen committed 2026-10-14 18:50:17 +08:00
1 parent 3194f98ac0
commit e740ec77ec
24 files changed
+1561 -65

No files matched your search

+127 -19
View File
@@ -6,9 +6,9 @@
* file-breadcrumb 目录面包屑(仅子目录态:左起排列,放不下折成 根+…+尾部段)
* search-input 搜索框(v-model 即时过滤,确认键触发服务端搜索)
* quick-entry 快捷功能入口(横向滚动图标组)
* file-tab-filter 分类标签 + 排序 + 视图切换 + 多选开关
* file-tab-filter 分类标签 + 新建文件夹 + 排序 + 视图切换 + 多选开关
* file-grid-list 文件网格/列表卡片
* float-add-btn 右下角悬浮加号
* float-add-btn 右下角悬浮加号(直接选文件上传)
* 数据来自后端 DMS 接口(composables/useDmsFiles,调用链对齐旧 WebVue DmsFileEnquiry.vue);
* 组件契约(data/custom/fileBrowser.ts)不关心数据源,演示数据到真实接口只动页面层。
* 目录导航:点文件夹下钻;子目录态隐藏底部 tabbar,返回箭头/面包屑退层级。
@@ -18,24 +18,38 @@ import type { FileCategory, FileItem, FileKind, FileTabItem, QuickEntryItem } fr
import { useLocale } from "uview-pro";
import { computed, ref, watch } from "vue";
import { useAuthGuard, useDmsFiles, useThemeGradient } from "@/composables";
import { DmsFileEntity } from "@/data/auto/dmsFileEntity";
import { pageUrl } from "@/router/routes";
import dmsFileService from "@/service/master/dmsFileService";
import { useUploadQueueStore } from "@/stores/uploadQueue";
import { chooseFiles } from "@/utils/chooseFiles";
import { transferGlyph } from "@/utils/transferGlyph";
const { t } = useLocale();
// 页面底渐变跟随主题(派生逻辑在 composables/useThemeGradient,多页共用)
const { themeBackground } = useThemeGradient();
const { files, loading, errorText, pathStack, atRoot, init, retry, openFolder, back, goTo, search } = useDmsFiles();
const { files, loading, errorText, pathStack, atRoot, init, openTrail, retry, openFolder, back, goTo, search } = useDmsFiles();
// 首次显示拉根目录,之后每次回到页面只刷新当前目录(重进 tab 不该丢位置重新拉全链)
// 上传队列(全局 store):入队在本页、胶囊读它的进行中计数、守卫回调消费它的面包屑导航请求
const uploadQueue = useUploadQueueStore();
// 首次显示拉根目录,之后每次回到页面只刷新当前目录(重进 tab 不该丢位置重新拉全链);
// 回页末尾消费传输页的面包屑导航请求(reLaunch 重建后恢复到目标目录)
let started = false;
useAuthGuard(() => {
useAuthGuard(async () => {
if (started) {
retry();
return;
await retry();
}
else {
started = true;
await init();
}
const trail = uploadQueue.takeNav();
if (trail) {
await openTrail(trail);
}
started = true;
init();
});
// ===== 页面状态(全部单向下发,组件只上报意图) =====
@@ -102,11 +116,6 @@ function toast(title: string): void {
uni.showToast({ title, icon: "none" });
}
/** 待接入真实功能时的统一占位提示 */
function todoTip(): void {
toast(t("FilePage.todoTip"));
}
// ===== 导航栏 / 面包屑 =====
function onToggleSearch(): void {
showSearch.value = !showSearch.value;
@@ -334,20 +343,83 @@ function onSheetAction(key: string, file: FileItem): void {
toast(`${file.name} · ${key} · ${t("FilePage.todoTip")}`);
}
// 新建文件夹命名对话框(CreateDmsFolder 在途标记防连点)
const folderDialogVisible = ref(false);
const folderSubmitting = ref(false);
// 上传队列状态见文件头部的 uploadQueue store
/** 悬浮「+」:新建文件夹已拆到工具栏图标,这里直接选文件上传 */
function onAdd(): void {
todoTip();
pickAndUpload();
}
/** 工具栏「文件夹+」图标:弹新建文件夹命名对话框 */
function onNewFolder(): void {
folderDialogVisible.value = true;
}
/** 名称限制对齐后端目录模型:不能含路径分隔符(FolderLocalName 直接参与路径拼接) */
async function onCreateFolder(name: string): Promise<void> {
if (/[\\/]/.test(name)) {
toast(t("FilePage.folderInvalid"));
return;
}
folderSubmitting.value = true;
try {
const entity = new DmsFileEntity();
entity.FileName = name;
entity.FilePath = pathStack.value[pathStack.value.length - 1]?.value ?? "";
await dmsFileService.CreateDmsFolder(entity);
folderDialogVisible.value = false;
toast(t("FilePage.folderCreated"));
// 新建完直接刷当前目录,不等切回页面才重查
retry();
}
catch (error: any) {
// 业务异常主拦截器已弹模态,这里只兜网络层失败
if (error?.errMsg) {
toast(error.errMsg);
}
}
finally {
folderSubmitting.value = false;
}
}
/** 选文件→入队(快照面包屑链供传输页展示/跳回)→跳传输列表;之后用户跳走不影响上传 */
async function pickAndUpload(): Promise<void> {
try {
const picked = await chooseFiles();
if (!picked.length) {
return;
}
uploadQueue.addFiles(picked, [...pathStack.value]);
uni.navigateTo({ url: pageUrl("transport") });
}
catch (error: any) {
toast(error?.errMsg || error?.message || t("FilePage.todoTip"));
}
}
function goTransport(): void {
uni.navigateTo({ url: pageUrl("transport") });
}
/** 胶囊内的自绘传输字形(白字蓝底,颜色固定,模块级生成一次) */
const transferIconWhite = transferGlyph("#ffffff");
</script>
<template>
<!-- 操作面板/多选操作栏展开时收起 tabbar:tabbar 在页面 fixed 层叠上下文之外,
弹层 z-index 再高也压不住它,直接隐藏最干净(主流云盘同款交互) -->
<app-page :hide-nav="true" :show-tabbar="atRoot && !actionFile && !selectMode">
<app-page :hide-nav="true" :show-tabbar="atRoot && !actionFile && !selectMode && !folderDialogVisible">
<view class="file-page" :style="{ background: themeBackground }">
<!-- 上半屏整体固定,只有文件列表所在的 scroll-view 内部滚动(整页不滚) -->
<view class="file-page__head">
<page-navbar :title="navTitle" :show-back="!atRoot" :search-on="showSearch" :quick-on="showQuick" @back="onBack"
@toggle-search="onToggleSearch" @toggle-quick="onToggleQuick" />
<page-navbar :title="navTitle" :show-back="!atRoot" :search-on="showSearch" :quick-on="showQuick"
:transferring="uploadQueue.uploadingCount" @back="onBack" @toggle-search="onToggleSearch"
@toggle-quick="onToggleQuick" @transfer="goTransport" />
<!-- 子目录态才有的路径条:白色衬底包住面包屑(外面不再是灰页面底),左起全量显示,溢出折叠 -->
<view v-if="!atRoot" class="file-page__crumb">
<file-breadcrumb :items="pathStack" @nav="onCrumbNav" />
@@ -360,7 +432,8 @@ function onAdd(): void {
<quick-entry :items="quickEntries" @click="onQuickClick" />
</view>
<file-tab-filter :tabs="tabs" :active="category" :view-mode="viewMode" :select-mode="selectMode"
@change="onCategoryChange" @sort="onSort" @toggle-view="onToggleView" @toggle-select="onToggleSelect" />
@change="onCategoryChange" @sort="onSort" @toggle-view="onToggleView" @toggle-select="onToggleSelect"
@new-folder="onNewFolder" />
<view v-if="selectMode" class="file-page__selection">
<text class="file-page__selection-text">
{{ t("FilePage.selectedCount", { count: selectedIds.length }) }}
@@ -410,8 +483,17 @@ function onAdd(): void {
</view>
<!-- 多选态加号让位底部操作栏,避免两个悬浮物打架 -->
<float-add-btn v-if="!selectMode" @click="onAdd" />
<!-- 上传中悬浮胶囊:任意目录下一键回传输列表(任务在 store 里,跳走不中断) -->
<view v-if="uploadQueue.uploadingCount && !selectMode" class="file-page__transfer" @click="goTransport">
<image class="file-page__transfer-img" :src="transferIconWhite" mode="aspectFit" />
<text class="file-page__transfer-text">
{{ uploadQueue.uploadingCount }} {{ t("TransportPage.transferring") }}
</text>
</view>
<file-action-sheet :visible="!!actionFile" :file="actionFile" @close="actionFile = null"
@action="onSheetAction" />
<folder-name-dialog :visible="folderDialogVisible" :submitting="folderSubmitting"
@close="folderDialogVisible = false" @confirm="onCreateFolder" />
<!-- 多选底部操作栏:常驻非模态(无遮罩),勾选与动作可交替进行;
动作集是旧系统多选子集——共享/发布按同媒体类型条件,重命名/移动仅单选 -->
<view v-if="selectMode" class="file-page__actions">
@@ -493,6 +575,32 @@ function onAdd(): void {
}
}
/* 上传中悬浮胶囊:左下角常驻(避开右侧可拖动加号),点击回传输列表 */
.file-page__transfer {
position: fixed;
bottom: 220rpx;
left: 24rpx;
z-index: 8;
display: flex;
align-items: center;
gap: 10rpx;
padding: 16rpx 28rpx;
border-radius: 999rpx;
background-color: rgba(41, 121, 255, 0.9);
box-shadow: 0 6rpx 16rpx rgba(41, 121, 255, 0.35);
}
.file-page__transfer-text {
font-size: 24rpx;
color: #ffffff;
}
/* 胶囊内自绘传输字形:与原文案图标同尺寸(26rpx) */
.file-page__transfer-img {
width: 26rpx;
height: 26rpx;
}
.file-page__selection {
display: flex;
align-items: center;