+
+
+
+ 根目录
+
+ {{ folder }}
+
+
+
+
-
-
-
-
{{ item.channelTag }}
-
{{ item.channelTag }}
-
{{ item.channelTag }}
-
-
-
-
-
-
-
-
-
{{ item.metadata?.FileName || item.name }}
-
+
{{ getFileName(item.metadata?.FileName || item.name) }}
+
@@ -207,6 +254,7 @@
import { mapGetters } from 'vuex';
import JSZip from 'jszip';
import DashboardTabs from '@/components/DashboardTabs.vue';
+import { fileManager } from '@/utils/fileManager';
export default {
data() {
@@ -228,6 +276,8 @@ data() {
useCustomUrl: 'false', // 是否启用自定义链接
customUrlPrefix: '', // 自定义链接前缀
loading: false, // 加载状态
+ currentPath: '', // 当前文件夹路径
+ refreshLoading: false,
}
},
components: {
@@ -837,37 +887,193 @@ methods: {
if (this.currentPage === Math.ceil(this.filteredTableData.length / this.pageSize)) {
this.loadMoreData();
}
- }
+ },
+ // 判断是否为文件夹
+ isFolder(item) {
+ // 如果是已经标记为文件夹的项目,直接返回true
+ if (item.isFolder) {
+ return true;
+ }
+
+ // 获取真实的文件路径(去除URL前缀)
+ let path = item.name;
+ if (path.startsWith('http')) {
+ path = path.split('/file/')[1];
+ }
+
+ // 如果文件名包含'/',需要判断是否是当前路径下的文件
+ if (path && path.includes('/')) {
+ // 获取相对于当前路径的部分
+ const relativePath = this.currentPath ?
+ path.substring(this.currentPath.length) :
+ path;
+
+ // 如果在根目录,第一个斜杠前的部分就是文件夹
+ if (this.currentPath === '') {
+ return !path.split('/')[0].includes('.');
+ }
+
+ // 如果在子文件夹中,检查相对路径是否还包含其他文件夹
+ return relativePath.includes('/');
+ }
+
+ return false;
+ },
+
+ // 获取文件夹名称
+ getFolderName(path) {
+ // 如果是完整URL,获取/file/后的路径
+ if (path.startsWith('http')) {
+ path = path.split('/file/')[1];
+ }
+
+ // 如果是文件夹路径,只返回最后一级文件夹名
+ if (path && path.includes('/')) {
+ const parts = path.split('/');
+ // 如果是根目录下的文件夹
+ if (this.currentPath === '') {
+ return parts[0];
+ }
+ // 如果是子文件夹
+ const relativePath = path.substring(this.currentPath.length);
+ return relativePath.split('/')[0];
+ }
+ return path;
+ },
+
+ // 获取文件名称(去除路径和URL前缀)
+ getFileName(path) {
+ if (path.startsWith('http')) {
+ path = path.split('/file/')[1];
+ }
+ return path.split('/').pop();
+ },
+
+ // 进入文件夹
+ enterFolder(folderPath) {
+ // 确保路径末尾有 '/'
+ this.currentPath = folderPath + (folderPath.endsWith('/') ? '' : '/');
+ this.fetchFileList();
+ },
+
+ // 导航到指定文件夹
+ navigateToFolder(path) {
+ // 确保空路径时不添加 '/'
+ this.currentPath = path ? (path + (path.endsWith('/') ? '' : '/')) : '';
+ this.fetchFileList();
+ },
+
+ // 修改获取文件列表的方法
+ async fetchFileList() {
+ this.loading = true;
+ try {
+ // 从本地存储获取数据
+ const data = fileManager.getLocalFileList();
+
+ // 处理数据,将文件夹和文件分开
+ const folders = new Set();
+ const files = [];
+
+ data.forEach(item => {
+ let path = item.name;
+ if (path.startsWith('http')) {
+ path = path.split('/file/')[1];
+ }
+
+ if (path.includes('/')) {
+ const pathParts = path.split('/');
+ if (this.currentPath === '') {
+ // 在根目录,显示第一级文件夹
+ const firstFolder = pathParts[0];
+ if (!firstFolder.includes('.')) {
+ folders.add(firstFolder);
+ }
+ } else {
+ // 在子文件夹中,显示当前路径下的下一级文件夹
+ if (path.startsWith(this.currentPath)) {
+ const relativePath = path.substring(this.currentPath.length);
+ const nextFolder = relativePath.split('/')[0];
+ if (nextFolder && !nextFolder.includes('.')) {
+ folders.add(this.currentPath + (this.currentPath.endsWith('/') ? '' : '/') + nextFolder);
+ }
+ }
+ }
+ }
+
+ // 只显示当前文件夹下的文件
+ if (this.currentPath === '') {
+ // 在根目录,只显示没有 '/' 的文件
+ if (!path.includes('/')) {
+ files.push(item);
+ }
+ } else {
+ // 在子文件夹中,显示当前路径下的文件
+ if (path.startsWith(this.currentPath)) {
+ const relativePath = path.substring(this.currentPath.length);
+ if (!relativePath.includes('/')) {
+ files.push(item);
+ }
+ }
+ }
+ });
+
+ // 合并文件夹和文件
+ this.tableData = [
+ ...Array.from(folders).map(folder => ({
+ name: folder,
+ isFolder: true,
+ selected: false,
+ metadata: { FileName: folder.split('/').pop() }
+ })),
+ ...files
+ ];
+
+ // 更新统计信息
+ this.updateStats(0, true);
+
+ } catch (error) {
+ console.error('Error fetching file list:', error);
+ this.$message.error('获取文件列表失败');
+ } finally {
+ this.loading = false;
+ }
+ },
+ // 刷新文件列表
+ async refreshFileList() {
+ this.refreshLoading = true;
+ try {
+ const success = await fileManager.refreshFileList(this.fetchWithAuth);
+ if (success) {
+ await this.fetchFileList();
+ this.$message.success('刷新成功');
+ } else {
+ throw new Error('Refresh failed');
+ }
+ } catch (error) {
+ console.error('Error refreshing file list:', error);
+ this.$message.error('刷新失败,请重试');
+ } finally {
+ this.refreshLoading = false;
+ }
+ },
},
mounted() {
this.loading = true;
-
this.fetchWithAuth("/api/manage/check", { method: 'GET' })
.then(response => response.text())
.then(result => {
if(result == "true"){
- this.showLogoutButton=true;
- // 在 check 成功后再执行 list 的 fetch 请求
- return this.fetchWithAuth("/api/manage/list?count=60", { method: 'GET' });
- } else if(result=="Not using basic auth."){
- return this.fetchWithAuth("/api/manage/list?count=60", { method: 'GET' });
- } else{
+ this.showLogoutButton = true;
+ return true;
+ } else if(result == "Not using basic auth."){
+ return true;
+ } else {
throw new Error('Unauthorized');
}
})
- .then(response => response.json())
- .then(result => {
- this.tableData = result.map(file => ({ ...file, selected: false }));
- this.updateStats(0, true);
- const savedSortOption = localStorage.getItem('sortOption');
- if (savedSortOption) {
- this.sortOption = savedSortOption;
- }
- const savedDefaultUrlFormat = localStorage.getItem('defaultUrlFormat');
- if (savedDefaultUrlFormat) {
- this.defaultUrlFormat = savedDefaultUrlFormat;
- }
- this.sortData(this.tableData);
+ .then(() => {
+ // 首次加载时刷新文件列表
+ return this.refreshFileList();
})
.catch((err) => {
if (err.message !== 'Unauthorized') {
@@ -1300,4 +1506,37 @@ mounted() {
.question-icon {
margin: 0 3px;
}
+
+.breadcrumb {
+ margin-bottom: 20px;
+ padding: 10px;
+ background-color: var(--el-bg-color);
+ border-radius: 4px;
+}
+
+.folder-card {
+ cursor: pointer;
+ transition: all 0.3s;
+}
+
+.folder-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+}
+
+.folder-icon {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100px;
+ color: var(--el-color-primary);
+}
+
+:deep(.el-breadcrumb__item) {
+ cursor: pointer;
+}
+
+:deep(.el-breadcrumb__inner:hover) {
+ color: var(--el-color-primary);
+}
diff --git a/src/views/UploadHome.vue b/src/views/UploadHome.vue
index c11e210..5926428 100644
--- a/src/views/UploadHome.vue
+++ b/src/views/UploadHome.vue
@@ -62,6 +62,7 @@
:autoRetry="autoRetry"
:urlPrefix="urlPrefix"
:uploadMethod="uploadMethod"
+ :uploadFolder="uploadFolder"
class="upload"
/>
@@ -102,6 +103,9 @@
S3
+
+
+
@@ -202,6 +206,7 @@ export default {
useDefaultWallPaper: false,
isToolBarOpen: false, //是否打开工具栏
uploadMethod: 'default', //上传方式
+ uploadFolder: '', // 添加上传文件夹属性
}
},
watch: {
@@ -232,6 +237,9 @@ export default {
autoRetry(val) {
this.$store.commit('setStoreAutoRetry', val)
},
+ uploadFolder(val) {
+ this.$store.commit('setStoreUploadFolder', val)
+ },
isDark(val) {
if (this.useDefaultWallPaper) {
const bg1 = document.getElementById('bg1')
@@ -243,7 +251,7 @@ export default {
}
},
computed: {
- ...mapGetters(['userConfig', 'bingWallPapers', 'uploadCopyUrlForm', 'compressConfig', 'storeUploadChannel', 'storeUploadNameType', 'customUrlSettings', 'storeAutoRetry', 'storeUploadMethod']),
+ ...mapGetters(['userConfig', 'bingWallPapers', 'uploadCopyUrlForm', 'compressConfig', 'storeUploadChannel', 'storeUploadNameType', 'customUrlSettings', 'storeAutoRetry', 'storeUploadMethod', 'storeUploadFolder']),
ownerName() {
return this.userConfig?.ownerName || 'Sanyue'
},
@@ -349,6 +357,8 @@ export default {
this.useCustomUrl = this.customUrlSettings.useCustomUrl
// 读取用户偏好的上传方式
this.uploadMethod = this.storeUploadMethod
+ // 读取用户设置的上传文件夹
+ this.uploadFolder = this.storeUploadFolder
},
components: {
UploadForm,