|
|
@@ -23,6 +23,11 @@ import MediaTable from './MediaTable';
|
|
|
|
|
|
const TAG = 'heanup RemoteDriveManager';
|
|
|
|
|
|
+export interface BreadcrumbItem {
|
|
|
+ label: string;
|
|
|
+ path: string;
|
|
|
+}
|
|
|
+
|
|
|
// WebDAV认证信息接口
|
|
|
export interface WebDavAuthInfo {
|
|
|
headers: Record<string, string>;
|
|
|
@@ -1173,11 +1178,51 @@ export class RemoteDriveManager {
|
|
|
}
|
|
|
|
|
|
private registerPathLabel(path: string, label: string): void {
|
|
|
- if (!path || !label) {
|
|
|
+ if (!path || label === undefined) {
|
|
|
return;
|
|
|
}
|
|
|
const normalized = this.normalizeFullPath(path);
|
|
|
- this.pathDisplayNames.set(normalized, label);
|
|
|
+ const sanitizedLabel = this.sanitizeLabel(label);
|
|
|
+ this.pathDisplayNames.set(normalized, sanitizedLabel);
|
|
|
+ }
|
|
|
+
|
|
|
+ private sanitizeLabel(label: string): string {
|
|
|
+ if (!label) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ if (label === '根目录') {
|
|
|
+ return label;
|
|
|
+ }
|
|
|
+ let sanitized = label.trim();
|
|
|
+ sanitized = sanitized.replace(/\/+$/, '');
|
|
|
+ if (sanitized.length === 0) {
|
|
|
+ sanitized = '/';
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ sanitized = decodeURIComponent(sanitized);
|
|
|
+ } catch (error) {
|
|
|
+ // ignore decode failure, keep original label
|
|
|
+ }
|
|
|
+ return sanitized;
|
|
|
+ }
|
|
|
+
|
|
|
+ private getBasePath(account: WebDavAccount | null = this.currentAccount): string {
|
|
|
+ if (account && account.filepath) {
|
|
|
+ return this.normalizeFullPath(account.filepath);
|
|
|
+ }
|
|
|
+ return '/';
|
|
|
+ }
|
|
|
+
|
|
|
+ private getRelativePath(fullPath: string, basePath: string): string {
|
|
|
+ const normalizedFull = this.normalizeFullPath(fullPath);
|
|
|
+ const normalizedBase = this.normalizeFullPath(basePath);
|
|
|
+ if (normalizedFull === normalizedBase) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ if (normalizedFull.startsWith(normalizedBase) && normalizedBase !== '/') {
|
|
|
+ return normalizedFull.substring(normalizedBase.length).replace(/^\/+/, '');
|
|
|
+ }
|
|
|
+ return normalizedFull.replace(/^\/+/, '');
|
|
|
}
|
|
|
|
|
|
private normalizeSmbRelativePath(path: string, shareName?: string): string {
|
|
|
@@ -1258,46 +1303,51 @@ export class RemoteDriveManager {
|
|
|
}
|
|
|
|
|
|
public async enterFolderFromPath(path: string): Promise<void> {
|
|
|
+ const normalizedTarget = this.normalizeFullPath(path);
|
|
|
|
|
|
Logger.info(TAG, '当前路径:', this.currentPath);
|
|
|
- Logger.info(TAG, '目标路径:', path);
|
|
|
- // 保存当前路径到历史记录
|
|
|
- this.pathHistory.push(this.currentPath);
|
|
|
+ Logger.info(TAG, '目标路径:', normalizedTarget);
|
|
|
+
|
|
|
+ this.rebuildPathHistoryForTarget(normalizedTarget);
|
|
|
Logger.info(TAG, '路径历史:', JSON.stringify(this.pathHistory));
|
|
|
- // 加载文件夹内容
|
|
|
- await this.loadFilesInfoFromAccount(this.currentAccount, path);
|
|
|
+
|
|
|
+ await this.loadFilesInfoFromAccount(this.currentAccount, normalizedTarget);
|
|
|
}
|
|
|
|
|
|
- // 在 RemoteDriveManager 类中添加以下方法
|
|
|
- navigateToBreadcrumb(breadcrumbIndex: number): Promise<string> {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- try {
|
|
|
- // 面包屑索引0是"根目录"
|
|
|
- if (breadcrumbIndex === 0) {
|
|
|
- resolve('/');
|
|
|
- return;
|
|
|
- }
|
|
|
+ private rebuildPathHistoryForTarget(targetPath: string): void {
|
|
|
+ if (!targetPath) {
|
|
|
+ this.pathHistory = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // 根据当前路径构建目标路径
|
|
|
- const pathParts = this.currentPath.split('/').filter(part => part !== '');
|
|
|
+ const normalizedTarget = this.normalizeFullPath(targetPath);
|
|
|
+ const basePath = this.getBasePath();
|
|
|
|
|
|
- // 验证索引有效性
|
|
|
- if (breadcrumbIndex > pathParts.length) {
|
|
|
- reject(new Error('Invalid breadcrumb index'));
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (normalizedTarget === basePath) {
|
|
|
+ this.pathHistory = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // 构建目标路径
|
|
|
- let targetPath = '/';
|
|
|
- for (let i = 0; i < breadcrumbIndex; i++) {
|
|
|
- targetPath += pathParts[i] + '/';
|
|
|
- }
|
|
|
+ const relativePath = this.getRelativePath(normalizedTarget, basePath);
|
|
|
+ if (!relativePath) {
|
|
|
+ this.pathHistory = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- resolve(targetPath);
|
|
|
- } catch (error) {
|
|
|
- reject(error);
|
|
|
- }
|
|
|
- });
|
|
|
+ const parts = relativePath.split('/').filter(part => part.length > 0);
|
|
|
+ const rebuiltHistory: string[] = [];
|
|
|
+
|
|
|
+ // 把账户根路径作为栈底,以便可以返回
|
|
|
+ rebuiltHistory.push(basePath);
|
|
|
+
|
|
|
+ let cumulative = basePath;
|
|
|
+ for (let i = 0; i < parts.length - 1; i++) {
|
|
|
+ const segment = parts[i];
|
|
|
+ cumulative = this.normalizeFullPath(`${cumulative === '/' ? '' : cumulative}/${segment}`);
|
|
|
+ rebuiltHistory.push(cumulative);
|
|
|
+ }
|
|
|
+
|
|
|
+ this.pathHistory = rebuiltHistory;
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1316,19 +1366,33 @@ export class RemoteDriveManager {
|
|
|
}
|
|
|
|
|
|
// 获取面包屑路径数组
|
|
|
- public getBreadcrumbs(): string[] {
|
|
|
- if (!this.currentPath || this.currentPath === '/') {
|
|
|
- return ['根目录'];
|
|
|
+ public getBreadcrumbs(): BreadcrumbItem[] {
|
|
|
+ const basePath = this.getBasePath();
|
|
|
+ const breadcrumbs: BreadcrumbItem[] = [{
|
|
|
+ label: '根目录',
|
|
|
+ path: basePath
|
|
|
+ }];
|
|
|
+
|
|
|
+ if (!this.currentPath || this.normalizeFullPath(this.currentPath) === basePath) {
|
|
|
+ return breadcrumbs;
|
|
|
}
|
|
|
|
|
|
- const parts = this.currentPath.split('/').filter(part => part !== '');
|
|
|
- const breadcrumbs = ['根目录'];
|
|
|
+ const relativePath = this.getRelativePath(this.currentPath, basePath);
|
|
|
+ if (!relativePath) {
|
|
|
+ return breadcrumbs;
|
|
|
+ }
|
|
|
|
|
|
- let cumulative = '';
|
|
|
+ const parts = relativePath.split('/').filter(part => part.length > 0);
|
|
|
+ let cumulative = basePath;
|
|
|
for (let i = 0; i < parts.length; i++) {
|
|
|
- cumulative += `/${parts[i]}`;
|
|
|
- const label = this.pathDisplayNames.get(cumulative) ?? parts[i];
|
|
|
- breadcrumbs.push(label);
|
|
|
+ const segment = parts[i];
|
|
|
+ const targetPath = this.normalizeFullPath(`${cumulative === '/' ? '' : cumulative}/${segment}`);
|
|
|
+ const label = this.pathDisplayNames.get(targetPath) ?? segment;
|
|
|
+ breadcrumbs.push({
|
|
|
+ label: this.sanitizeLabel(label),
|
|
|
+ path: targetPath
|
|
|
+ });
|
|
|
+ cumulative = targetPath;
|
|
|
}
|
|
|
|
|
|
return breadcrumbs;
|