828 lines
24 KiB
Vue
828 lines
24 KiB
Vue
<template>
|
||
<view class="status-bar"></view>
|
||
|
||
<!-- ===== 新建文件夹设置弹窗 ===== -->
|
||
<view v-if="showNewFolder" class="popup-overlay" @click="closeNewFolderModal">
|
||
<view class="popup-card" @click.stop>
|
||
<!-- 关闭按钮 -->
|
||
<view class="close-popup-card" @click="closeNewFolderModal">
|
||
<view class="iconfont icon-quxiao"></view>
|
||
</view>
|
||
<!-- 标题 -->
|
||
<view class="popup-title">新建工作区目录</view>
|
||
|
||
<!-- 目录名称输入 -->
|
||
<view class="new-folder-name">目录名称</view>
|
||
<view class="create-folder-name" :class="{'has-value': isNFNFocused || newFolderName}">
|
||
<input v-model="newFolderName" @focus="isNFNFocused=true" @blur="isNFNFocused=false" type="text"
|
||
placeholder="输入目录名称,如:项目资料/设计图" />
|
||
</view>
|
||
|
||
<!-- 当前路径 -->
|
||
<view class="nf-path-label">当前路径</view>
|
||
<view class="nf-path-display">{{ currentFolderPath }}</view>
|
||
|
||
<!-- 路径预览 -->
|
||
<view class="nf-path-label">路径预览</view>
|
||
<view class="nf-path-preview">{{ folderPathPreview }}</view>
|
||
|
||
<!-- 底部按钮 -->
|
||
<view class="option-wrapper">
|
||
<view class="opt-btn opt-cancel" @click="closeNewFolderModal">取消</view>
|
||
<view class="opt-btn opt-confirm" @click="confirmCreateFolder">确认</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="workspace-container page-container">
|
||
<view class="workspace-header">
|
||
<view class="custom-navbar">
|
||
<view class="navbar-left" @click="handleBackOrCheck ">
|
||
<view class="iconfont icon-fanhui custom-navbar-icon"></view>
|
||
<view class="navbar-before-title workspace-text">{{isSelectFolder?'全选':navbarBeforeTitle}}</view>
|
||
</view>
|
||
|
||
<view class="navbar-title workspace-text">{{navbarTitle}}</view>
|
||
<view class="navbar-right">
|
||
<view v-if="isSelectFolder" class="navbar-right-text workspace-text" @click="handleSelectFolder()">
|
||
完成</view>
|
||
<view v-else class="iconfont icon-gengduo" :class="isMenuOpen ?'menu-open':'custom-navbar-icon'"
|
||
@click="handleMenu"></view>
|
||
</view>
|
||
<view v-if="isMenuOpen" class="menu-card">
|
||
<!-- <view class="menu-card-item" @click="handleSelectFolder();handleMenu()">选择</view>
|
||
<view class="solid-line"></view> -->
|
||
<view class="menu-card-item" @click="handleUploadFile();handleMenu()">上传文件</view>
|
||
<view class="solid-line"></view>
|
||
<view class="menu-card-item" @click="newWorkspaceFolder();handleMenu()">新建文件夹</view>
|
||
</view>
|
||
</view>
|
||
<view class="search-file-warpper">
|
||
<view class="search-file">
|
||
<view class="iconfont icon-sousuo"></view>
|
||
<input class="search-file-input" placeholder="搜索" @focus="handleSearchFocus"
|
||
v-model="searchKeyword" />
|
||
</view>
|
||
<view v-if="isSearchFocus" class="cancel-search" @click="handleSearchFocus">取消</view>
|
||
</view>
|
||
|
||
<!-- 标签切换 -->
|
||
<view class="workspace-tabs">
|
||
<view class="tab-item" :class="{ active: activeTab === 'workspace' }" @click="switchTab('workspace')">
|
||
工作区
|
||
</view>
|
||
<view class="tab-item" :class="{ active: activeTab === 'downloads' }" @click="switchTab('downloads')">
|
||
下载列表
|
||
<text v-if="downloadList.length > 0" class="tab-badge">{{ downloadList.length }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ===== 工作区文件 ===== -->
|
||
<view class="workspace-content" v-if="activeTab === 'workspace'">
|
||
<view class="folder-null" v-if="currentFolderList.length===0">
|
||
<view class="iconfont icon-wenjianjia"></view>
|
||
文件夹为空
|
||
</view>
|
||
<view class="folder-grid" v-if="currentFolderList.length>0">
|
||
<view class="folder-item" :class="{'select-folder':selectFileList.includes(folder.path)}"
|
||
v-for="folder in currentFolderList" :key="folder.path"
|
||
@click="isSelectFolder?selectFolder(folder.path):handleFolderClick(folder)"
|
||
@longpress="handleLongPress(folder)">
|
||
<view v-if="folder.type === 'directory'"
|
||
class="iconfont icon-a-wenjianjiawenjian folder-item-style"></view>
|
||
<view v-else class="iconfont folder-item-style" :class="getFileIcon(folder.extension)"></view>
|
||
<view class="folder-name">{{folder.name}}</view>
|
||
<view v-if="isSelectFolder" class="folder-checkbox"
|
||
:class="{'select-folder':selectFileList.includes(folder.path)}">
|
||
<uni-icons v-if="selectFileList.includes(folder.path)" type="checkmarkempty"
|
||
color="#fff"></uni-icons>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ===== 下载列表 ===== -->
|
||
<view class="download-content" v-if="activeTab === 'downloads'">
|
||
<view v-if="downloadList.length === 0" class="download-empty">
|
||
<text class="iconfont icon-xiazai"></text>
|
||
<text>暂无下载文件</text>
|
||
</view>
|
||
<view v-else class="download-list">
|
||
<view class="download-header">
|
||
<text>已下载 {{ downloadList.length }} 个文件</text>
|
||
<text class="clear-btn" @click="handleClearDownloads">清空</text>
|
||
</view>
|
||
<view class="download-item" v-for="item in downloadList" :key="item.id" @click="openDownloadFile(item)">
|
||
<view class="di-icon">
|
||
<text class="iconfont" :class="getFileIcon(item.name)"></text>
|
||
</view>
|
||
<view class="di-info">
|
||
<text class="di-name">{{ item.name }}</text>
|
||
<text class="di-meta">{{ formatDownloadTime(item.time) }} · {{ formatDownloadSize(item.size) }}</text>
|
||
<text class="di-path">{{ item.displayPath || item.path }}</text>
|
||
</view>
|
||
<view class="di-delete" @click.stop="handleDeleteDownload(item.id)">
|
||
<text class="iconfont icon-del"></text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="isSelectFolder" class="workspace-footer" :class="{'folder-actions':selectFileList.length>0}">
|
||
<view class="iconfont icon-shangchuan" @click="handleUploadFile"></view>
|
||
<!-- <view class="iconfont icon-fuzhi"></view> -->
|
||
<!-- <view class="iconfont icon-wenjian"></view> -->
|
||
<view class="iconfont icon-del"></view>
|
||
<!-- <view class="iconfont icon-gengduo"></view> -->
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
onMounted,
|
||
ref,
|
||
computed
|
||
} from 'vue';
|
||
import {
|
||
getWorkspaceId,
|
||
getToken
|
||
} from '@/utils/user-info.js'
|
||
import {
|
||
chooseFile
|
||
} from '@/uni_modules/lime-choose-file';
|
||
import {
|
||
getWorkspaceList,
|
||
createWorkspaceFolder,
|
||
daleteWorkspace,
|
||
getWorkspaceFileURL,
|
||
uploadFileToShortStorage,
|
||
workspaceUploadFileByURL,
|
||
updateWorkspaceFileName
|
||
} from '@/utils/cloud-api.js'
|
||
import { openFile as openFileNative } from '@/utils/fileOpener.js'
|
||
import {
|
||
getDownloadList,
|
||
saveDownload,
|
||
deleteDownload,
|
||
clearAllDownloads,
|
||
formatFileSize,
|
||
formatTime
|
||
} from '@/utils/downloadManager.js'
|
||
|
||
const UserToken = ref('')
|
||
const workspaceId = ref('')
|
||
const navbarBeforeTitle = ref('');
|
||
const navbarTitle = ref('工作区');
|
||
const activeTab = ref('workspace')
|
||
const downloadList = ref([])
|
||
|
||
// 选择文件模式
|
||
const isSelectFolder = ref(false);
|
||
const selectFileList = ref([]);
|
||
const handleSelectFolder = () => {
|
||
if (isSelectFolder.value) {
|
||
selectFileList.value = []
|
||
}
|
||
isSelectFolder.value = !isSelectFolder.value;
|
||
}
|
||
const selectFolder = (id) => {
|
||
const index = selectFileList.value.indexOf(id);
|
||
if (index !== -1) {
|
||
selectFileList.value.splice(index, 1);
|
||
} else {
|
||
selectFileList.value.push(id);
|
||
}
|
||
}
|
||
// 新建文件夹
|
||
const showNewFolder = ref(false)
|
||
const isNFNFocused = ref(false)
|
||
const newFolderName = ref('')
|
||
const closeNewFolderModal = () => {
|
||
showNewFolder.value = false
|
||
newFolderName.value = ''
|
||
}
|
||
const newWorkspaceFolder = () => {
|
||
showNewFolder.value = true
|
||
}
|
||
|
||
// ========== 上传文件 ==========
|
||
const handleUploadFile = () => {
|
||
chooseFile({
|
||
count: 10,
|
||
type: 'all',
|
||
success: async (res) => {
|
||
const files = res.tempFiles || [];
|
||
if (files.length === 0) {
|
||
uni.showToast({
|
||
title: '未选择文件',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
await doUploadWorkspaceFiles(files);
|
||
},
|
||
fail: (err) => {
|
||
console.error('选择文件失败:', err);
|
||
}
|
||
});
|
||
};
|
||
|
||
const doUploadWorkspaceFiles = async (files) => {
|
||
uni.showLoading({
|
||
title: '上传中...'
|
||
});
|
||
try {
|
||
const dirPath = folderStack.value.length > 0 ?
|
||
'./' + folderStack.value.map(f => f.name).join('/') + '/' :
|
||
'/';
|
||
|
||
// 1. 一次性上传所有文件到短存云端,获取 URL 数组
|
||
const results = await uploadFileToShortStorage(
|
||
workspaceId.value,
|
||
files,
|
||
dirPath
|
||
);
|
||
// results: [{ url, success }, ...]
|
||
|
||
// 2. 收集成功的 URL,批量上传到工作区
|
||
const successUrls = results
|
||
.filter(r => r.success)
|
||
.map(r => r.url);
|
||
|
||
if (successUrls.length === 0) {
|
||
const errors = results.filter(r => !r.success).map(r => r.error).join('; ');
|
||
throw new Error(errors || '所有文件上传失败');
|
||
}
|
||
|
||
await workspaceUploadFileByURL(
|
||
UserToken.value,
|
||
workspaceId.value,
|
||
successUrls,
|
||
dirPath
|
||
);
|
||
|
||
uni.hideLoading();
|
||
const total = files.length;
|
||
const failed = total - successUrls.length;
|
||
const msg = failed > 0 ?
|
||
`上传完成:成功 ${successUrls.length},失败 ${failed}` :
|
||
`成功上传 ${total} 个文件`;
|
||
uni.showToast({
|
||
title: msg,
|
||
icon: successUrls.length > 0 ? 'success' : 'error'
|
||
});
|
||
// 刷新文件列表
|
||
initCurrentFolderList();
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
console.error('上传文件失败:', error);
|
||
uni.showToast({
|
||
title: typeof error === 'string' ? error : '上传失败,请重试',
|
||
icon: 'error'
|
||
});
|
||
}
|
||
};
|
||
|
||
// 当前文件夹路径
|
||
const currentFolderPath = computed(() => {
|
||
if (folderStack.value.length === 0) return '根目录'
|
||
return '/' + folderStack.value.map(f => f.name).join('/')
|
||
})
|
||
|
||
// 路径预览:./ + 当前路径 + 新文件夹名
|
||
const folderPathPreview = computed(() => {
|
||
const folderPath = folderStack.value.map(f => f.name).join('/')
|
||
const name = newFolderName.value.trim()
|
||
if (name) {
|
||
return folderPath ? `./${folderPath}/${name}` : `./${name}`
|
||
}
|
||
return folderPath ? `./${folderPath}/` : './'
|
||
})
|
||
|
||
// 确认创建文件夹
|
||
const confirmCreateFolder = async () => {
|
||
const name = newFolderName.value.trim()
|
||
if (!name) {
|
||
uni.showToast({
|
||
title: '请输入目录名称',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
try {
|
||
// 拼接路径:./ 开头,如 ./项目资料/设计图
|
||
const folderPath = folderStack.value.map(f => f.name).join('/')
|
||
const dirPath = folderPath ? `./${folderPath}/${name}` : `./${name}`
|
||
await createWorkspaceFolder(UserToken.value, workspaceId.value, dirPath)
|
||
uni.showToast({
|
||
title: '创建成功',
|
||
icon: 'success'
|
||
})
|
||
closeNewFolderModal()
|
||
initCurrentFolderList()
|
||
} catch (error) {
|
||
console.error('创建文件夹失败:', error)
|
||
uni.showToast({
|
||
title: '创建失败,请重试',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 长按文件
|
||
const handleLongPress = (folder) => {
|
||
if (isSelectFolder.value) return;
|
||
const isWyxd = folder.name && folder.name.toLowerCase().endsWith('.wyxd');
|
||
const itemList = isWyxd ? ['下载', '删除', 'WYXD查看器', 'AI修改'] : ['下载', '删除'];
|
||
uni.showActionSheet({
|
||
title: folder.name,
|
||
itemList: itemList,
|
||
success: (res) => {
|
||
if (isWyxd) {
|
||
switch (res.tapIndex) {
|
||
case 0:
|
||
handleDownload(folder);
|
||
break;
|
||
case 1:
|
||
handleDelete(folder);
|
||
break;
|
||
case 2:
|
||
openWyxdViewer(folder);
|
||
break;
|
||
case 3: // 'AI修改',
|
||
handleAiModify(folder);
|
||
break;
|
||
}
|
||
} else {
|
||
switch (res.tapIndex) {
|
||
case 0:
|
||
handleDownload(folder);
|
||
break;
|
||
case 1:
|
||
handleDelete(folder);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 重命名
|
||
const handleRename = async (folder) => {
|
||
uni.showModal({
|
||
title: '重命名',
|
||
content: '请输入新名称',
|
||
editable: true,
|
||
placeholderText: folder.name,
|
||
success: async (res) => {
|
||
if (res.confirm && res.content) {
|
||
try {
|
||
uni.showLoading({
|
||
title: '重命名中...'
|
||
});
|
||
// 构建文件路径:当前目录 + 文件名
|
||
const dirPath = folderStack.value.length > 0 ?
|
||
'./' + folderStack.value.map(f => f.name).join('/') + '/' :
|
||
'/';
|
||
const filePath = dirPath + folder.name;
|
||
await updateWorkspaceFileName(
|
||
workspaceId.value,
|
||
filePath,
|
||
res.content
|
||
);
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '重命名成功',
|
||
icon: 'success'
|
||
});
|
||
// 刷新文件列表
|
||
initCurrentFolderList();
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
console.error('重命名失败:', error);
|
||
uni.showToast({
|
||
title: typeof error === 'string' ? error : '重命名失败,请重试',
|
||
icon: 'error'
|
||
});
|
||
}
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
const handleDownload = async (folder) => {
|
||
// 目录不能下载
|
||
if (folder.type === 'directory') {
|
||
uni.showToast({
|
||
title: '暂不支持下载目录',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
uni.showLoading({
|
||
title: '获取下载链接...'
|
||
});
|
||
|
||
// 构建文件路径,去掉开头的 ./
|
||
const filePath = folder.path.startsWith('./') ? folder.path.slice(2) : folder.path;
|
||
const result = await getWorkspaceFileURL(UserToken.value, workspaceId.value, filePath);
|
||
|
||
uni.hideLoading();
|
||
|
||
// 接口返回数组,取第一个文件的 url
|
||
const fileInfo = Array.isArray(result) ? result[0] : result;
|
||
if (!fileInfo || !fileInfo.url) {
|
||
uni.showToast({
|
||
title: '获取下载链接失败',
|
||
icon: 'error'
|
||
});
|
||
return;
|
||
}
|
||
|
||
const downloadUrl = fileInfo.url;
|
||
const fileName = folder.name;
|
||
const fileSize = fileInfo.size || 0;
|
||
|
||
uni.showLoading({
|
||
title: '下载中...'
|
||
});
|
||
|
||
uni.downloadFile({
|
||
url: downloadUrl,
|
||
name: fileName,
|
||
success: (downloadRes) => {
|
||
uni.hideLoading();
|
||
if (downloadRes.statusCode === 200) {
|
||
const tempPath = downloadRes.tempFilePath;
|
||
// 持久化保存到本地
|
||
saveDownload(tempPath, fileName, fileSize).then((record) => {
|
||
downloadList.value.unshift(record);
|
||
uni.showToast({ title: '下载成功', icon: 'success' });
|
||
}).catch(() => {
|
||
// 保存失败不影响打开
|
||
});
|
||
// 下载成功后打开文件
|
||
openFile(tempPath);
|
||
} else {
|
||
uni.showToast({
|
||
title: '下载失败',
|
||
icon: 'error'
|
||
});
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading();
|
||
console.error('下载文件失败:', err);
|
||
uni.showToast({
|
||
title: '下载失败,请重试',
|
||
icon: 'error'
|
||
});
|
||
}
|
||
});
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
console.error('获取下载链接失败:', error);
|
||
uni.showToast({
|
||
title: '获取下载链接失败,请重试',
|
||
icon: 'error'
|
||
});
|
||
}
|
||
};
|
||
|
||
// 打开文件(弹出应用选择菜单)
|
||
const openFile = (filePath) => {
|
||
openFileNative(filePath, () => {
|
||
uni.showToast({ title: '无法打开此文件', icon: 'error' });
|
||
});
|
||
};
|
||
|
||
// ===== 下载列表相关 =====
|
||
const switchTab = (tab) => {
|
||
activeTab.value = tab
|
||
if (tab === 'downloads') {
|
||
loadDownloads()
|
||
}
|
||
}
|
||
|
||
const loadDownloads = () => {
|
||
downloadList.value = getDownloadList()
|
||
}
|
||
|
||
const openDownloadFile = (item) => {
|
||
// #ifdef APP-PLUS
|
||
// 检查公共目录下文件是否存在
|
||
plus.io.resolveLocalFileSystemURL(
|
||
item.path,
|
||
() => {
|
||
// 文件存在,直接打开
|
||
openFile(item.path)
|
||
},
|
||
() => {
|
||
// 文件已被手动删除
|
||
uni.showToast({ title: '文件已失效,将移除记录', icon: 'none' })
|
||
handleDeleteDownload(item.id)
|
||
}
|
||
)
|
||
// #endif
|
||
// #ifndef APP-PLUS
|
||
uni.getSavedFileList({
|
||
success: (res) => {
|
||
const found = res.fileList.find(f => f.filePath === item.path)
|
||
if (found) {
|
||
openFile(item.path)
|
||
} else {
|
||
uni.showToast({ title: '文件已失效,将移除记录', icon: 'none' })
|
||
handleDeleteDownload(item.id)
|
||
}
|
||
},
|
||
fail: () => openFile(item.path)
|
||
})
|
||
// #endif
|
||
}
|
||
|
||
const handleDeleteDownload = (id) => {
|
||
uni.showModal({
|
||
title: '删除文件',
|
||
content: '确定要删除此下载文件吗?',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
deleteDownload(id).then(() => {
|
||
downloadList.value = getDownloadList()
|
||
uni.showToast({ title: '已删除', icon: 'success' })
|
||
}).catch(() => {
|
||
uni.showToast({ title: '删除失败', icon: 'error' })
|
||
})
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
const handleClearDownloads = () => {
|
||
if (downloadList.value.length === 0) return
|
||
uni.showModal({
|
||
title: '清空下载',
|
||
content: '确定要清空所有下载文件吗?此操作不可撤销。',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
clearAllDownloads().then(() => {
|
||
downloadList.value = []
|
||
uni.showToast({ title: '已清空', icon: 'success' })
|
||
})
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
const formatDownloadSize = formatFileSize
|
||
const formatDownloadTime = formatTime
|
||
|
||
// const getFileIcon = (fileName) => {
|
||
// const ext = fileName.split('.').pop().toLowerCase()
|
||
// const iconMap = {
|
||
// pdf: 'icon-PDF',
|
||
// doc: 'icon-word', docx: 'icon-word',
|
||
// xls: 'icon-excel', xlsx: 'icon-excel',
|
||
// ppt: 'icon-PPD', pptx: 'icon-PPD',
|
||
// zip: 'icon-yasuobao', rar: 'icon-yasuobao', '7z': 'icon-yasuobao',
|
||
// jpg: 'icon-tupian', jpeg: 'icon-tupian', png: 'icon-tupian', gif: 'icon-tupian',
|
||
// mp3: 'icon-yinle', wav: 'icon-yinle', flac: 'icon-yinle',
|
||
// mp4: 'icon-shipin', avi: 'icon-shipin', mov: 'icon-shipin',
|
||
// txt: 'icon-txt', md: 'icon-txt',
|
||
// }
|
||
// return iconMap[ext] || 'icon-weizhiwenjian'
|
||
// }
|
||
|
||
// WYXD 查看器入口
|
||
const openWyxdViewer = (folder) => {
|
||
const filePath = folder.path.startsWith('./') ? folder.path.slice(2) : folder.path;
|
||
console.log("解析文件路径:",filePath);
|
||
console.log("folder",folder);
|
||
console.log("encode",encodeURIComponent(filePath));
|
||
console.log("encode",encodeURIComponent(folder.name));
|
||
uni.navigateTo({
|
||
url: '/pages/WYXD/WYXD?workspaceId=' + encodeURIComponent(workspaceId.value)
|
||
+ '&filePath=' + encodeURIComponent(filePath)
|
||
+ '&fileName=' + encodeURIComponent(folder.name)
|
||
+ '&userToken=' + encodeURIComponent(UserToken.value)
|
||
});
|
||
};
|
||
|
||
// AI修改入口:跳转对话页并传入 WYXD 信息
|
||
const handleAiModify = (folder) => {
|
||
const filePath = folder.path.startsWith('./') ? folder.path.slice(2) : folder.path;
|
||
uni.navigateTo({
|
||
url: '/pages/Chat/Chat?wyxdWorkspaceId=' + encodeURIComponent(workspaceId.value)
|
||
+ '&wyxdFilePath=' + encodeURIComponent(filePath)
|
||
+ '&wyxdFileName=' + encodeURIComponent(folder.name)
|
||
+ '&wyxdUserToken=' + encodeURIComponent(UserToken.value)
|
||
});
|
||
};
|
||
|
||
// 删除
|
||
const handleDelete = (folder) => {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: `确定要删除"${folder.name}"吗?`,
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
// 路径加 ./ 前缀
|
||
const filePath = `./${folder.path}`
|
||
console.log("删除的是:", filePath);
|
||
await daleteWorkspace(UserToken.value, workspaceId.value, filePath)
|
||
uni.showToast({
|
||
title: '删除成功',
|
||
icon: 'success'
|
||
})
|
||
initCurrentFolderList()
|
||
} catch (error) {
|
||
console.error('删除失败:', error)
|
||
uni.showToast({
|
||
title: '删除失败,请重试',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
// const handleFolderClick = (id) => {
|
||
// console.log(id);
|
||
// }
|
||
|
||
// 菜单
|
||
const isMenuOpen = ref(false)
|
||
const handleMenu = () => {
|
||
isMenuOpen.value = !isMenuOpen.value;
|
||
}
|
||
|
||
// 搜索框
|
||
const searchKeyword = ref('')
|
||
const isSearchFocus = ref(false)
|
||
const handleSearchFocus = () => {
|
||
isSearchFocus.value = !isSearchFocus.value
|
||
}
|
||
|
||
// 根据文件后缀返回对应图标
|
||
const getFileIcon = (ext) => {
|
||
const iconMap = {
|
||
'.png': 'icon-wenjiantupian',
|
||
'.jpg': 'icon-wenjiantupian',
|
||
'.jpeg': 'icon-wenjiantupian',
|
||
'.gif': 'icon-wenjiantupian',
|
||
'.svg': 'icon-SVG',
|
||
'.bmp': 'icon-wenjiantupian',
|
||
'.webp': 'icon-wenjiantupian',
|
||
'.mp4': 'icon-wenjianshipin',
|
||
'.avi': 'icon-wenjianshipin',
|
||
'.mov': 'icon-wenjianshipin',
|
||
'.wmv': 'icon-wenjianshipin',
|
||
'.flv': 'icon-wenjianshipin',
|
||
'.mkv': 'icon-wenjianshipin',
|
||
'.mp3': 'icon-wenjianyinpin',
|
||
'.wav': 'icon-wenjianyinpin',
|
||
'.flac': 'icon-wenjianyinpin',
|
||
'.aac': 'icon-wenjianyinpin',
|
||
'.pdf': 'icon-PDF1',
|
||
'.doc': 'icon-word',
|
||
'.docx': 'icon-word',
|
||
'.xls': 'icon-execl',
|
||
'.xlsx': 'icon-execl',
|
||
'.ppt': 'icon-PPT1',
|
||
'.pptx': 'icon-PPT1',
|
||
'.txt': 'icon-TXT1',
|
||
'.md': 'icon-file-markdown-fill',
|
||
'.zip': 'icon-wenjianyasuo',
|
||
'.rar': 'icon-wenjianyasuo',
|
||
'.7z': 'icon-wenjianyasuo',
|
||
'.tar': 'icon-wenjianyasuo',
|
||
'.gz': 'icon-wenjianyasuo',
|
||
'.js': 'icon-JS',
|
||
'.ts': 'icon-daimawenjia',
|
||
'.vue': 'icon-daimawenjia',
|
||
'.html': 'icon-HTML',
|
||
'.css': 'icon-CSS',
|
||
'.py': 'icon-daima',
|
||
'.java': 'icon-daima',
|
||
'.json': 'icon-JSON',
|
||
};
|
||
return iconMap[ext?.toLowerCase()] || 'icon-qitalingyu';
|
||
};
|
||
|
||
const allFoldersData = ref({})
|
||
|
||
// 文件夹路径栈
|
||
const folderStack = ref([]);
|
||
// 当前显示的文件夹列表
|
||
const currentFolderList = ref([]);
|
||
const getCurrentFolderList = () => {
|
||
console.log("当前路径为:", JSON.stringify(folderStack.value));
|
||
// 当前路径:栈为空时在根目录,路径为 "."
|
||
const currentPath = folderStack.value.length > 0 ? folderStack.value[folderStack.value.length - 1].path : '.';
|
||
// 在根目录下,直接返回根节点的 children
|
||
if (currentPath === '.') {
|
||
return allFoldersData.value?.children || [];
|
||
}
|
||
// 递归在树中按 path 查找目标节点
|
||
const findFolderByPath = (list, targetPath) => {
|
||
for (const item of list) {
|
||
if (item.path === targetPath) return item;
|
||
if (item.type === 'directory' && item.children?.length) {
|
||
const res = findFolderByPath(item.children, targetPath);
|
||
if (res) return res;
|
||
}
|
||
}
|
||
return null;
|
||
};
|
||
// 从根节点的 children 开始搜索
|
||
const currentFolder = findFolderByPath(allFoldersData.value?.children || [], currentPath);
|
||
return currentFolder ? currentFolder.children : [];
|
||
}
|
||
|
||
// 初始化当前文件夹列表
|
||
const initCurrentFolderList = async () => {
|
||
workspaceId.value = getWorkspaceId();
|
||
UserToken.value = getToken();
|
||
console.log("getWorkspaceId:", workspaceId.value);
|
||
allFoldersData.value = await getWorkspaceList(UserToken.value, workspaceId.value);
|
||
currentFolderList.value = getCurrentFolderList();
|
||
};
|
||
|
||
// 处理文件夹点击(非选择模式下进入文件夹,仅目录可点击进入)
|
||
const handleFolderClick = (folder) => {
|
||
if (folder.type !== 'directory') {
|
||
handleLongPress(folder)
|
||
return
|
||
}
|
||
folderStack.value.push({
|
||
path: folder.path,
|
||
name: folder.name
|
||
});
|
||
navbarTitle.value = folder.name;
|
||
navbarBeforeTitle.value = folderStack.value.length > 1 ? folderStack.value[folderStack.value.length - 2].name :
|
||
'工作区';
|
||
currentFolderList.value = getCurrentFolderList();
|
||
searchKeyword.value = '';
|
||
isSearchFocus.value = false;
|
||
};
|
||
|
||
// 全选/取消全选
|
||
const handleSelectAll = () => {
|
||
if (selectFileList.value.length === currentFolderList.value.length) {
|
||
selectFileList.value = [];
|
||
} else {
|
||
selectFileList.value = currentFolderList.value.map(f => f.path);
|
||
}
|
||
};
|
||
|
||
// 返回上一级
|
||
const handleBackOrCheck = () => {
|
||
if (isSelectFolder.value) {
|
||
// 选择模式下点击全选/取消全选
|
||
handleSelectAll();
|
||
return;
|
||
}
|
||
|
||
if (folderStack.value.length > 0) {
|
||
folderStack.value.pop();
|
||
if (folderStack.value.length === 0) {
|
||
navbarTitle.value = '工作区';
|
||
navbarBeforeTitle.value = null;
|
||
} else {
|
||
navbarTitle.value = folderStack.value[folderStack.value.length - 1].name;
|
||
navbarBeforeTitle.value = folderStack.value.length > 1 ?
|
||
folderStack.value[folderStack.value.length - 2].name :
|
||
'工作区';
|
||
}
|
||
initCurrentFolderList();
|
||
// 返回后清空搜索
|
||
searchKeyword.value = '';
|
||
isSearchFocus.value = false;
|
||
} else {
|
||
// 已在根目录,返回到聊天界面
|
||
uni.navigateBack({
|
||
delta: 1,
|
||
fail() {
|
||
console.log("返回失败,进入兜底跳转")
|
||
uni.reLaunch({
|
||
url: '/pages/Chat/Chat'
|
||
})
|
||
}
|
||
})
|
||
}
|
||
};
|
||
|
||
onMounted(() => {
|
||
initCurrentFolderList();
|
||
loadDownloads();
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
@import url("WorkSpace.css");
|
||
</style> |