fix(frontend): improve directory and timestamp display

This commit is contained in:
yukaidi
2026-06-10 21:22:29 +08:00
parent cbb442ceb6
commit 6ae5d998e6
4 changed files with 129 additions and 27 deletions

View File

@@ -511,6 +511,7 @@
files.forEach(file => { files.forEach(file => {
const item = document.createElement('div'); const item = document.createElement('div');
const metaText = fileMetaText(file);
if (file.fileType === 'folder') { if (file.fileType === 'folder') {
// 文件夹 // 文件夹
@@ -520,9 +521,7 @@
<i class="fas fa-folder"></i> <i class="fas fa-folder"></i>
</div> </div>
<div class="item-name">${file.fileName || '未命名文件夹'}</div> <div class="item-name">${file.fileName || '未命名文件夹'}</div>
<div class="item-meta"> ${metaText ? `<div class="item-meta">${metaText}</div>` : ''}
${file.sizeStr || '0B'} · ${formatDate(file.createTime)}
</div>
`; `;
folderCount++; folderCount++;
@@ -541,9 +540,7 @@
<i class="fas ${fileTypeInfo.icon}"></i> <i class="fas ${fileTypeInfo.icon}"></i>
</div> </div>
<div class="item-name">${file.fileName}</div> <div class="item-name">${file.fileName}</div>
<div class="item-meta"> ${metaText ? `<div class="item-meta">${metaText}</div>` : ''}
${file.sizeStr || '0B'} · ${formatDate(file.createTime)}
</div>
`; `;
fileCount++; fileCount++;
@@ -675,19 +672,65 @@
renderBreadcrumb(); renderBreadcrumb();
} }
// 文件元信息
function fileMetaText(file) {
const parts = [];
if (file.fileType !== 'folder') {
parts.push(file.sizeStr || '0B');
}
const dateText = formatDate(file.createTime);
if (dateText) {
parts.push(dateText);
}
return parts.join(' · ');
}
function hasValidTime(value) {
if (value === null || value === undefined) return false;
if (typeof value !== 'string') return true;
const trimmedValue = value.trim();
return trimmedValue !== '' && trimmedValue !== 'null' && trimmedValue !== 'undefined';
}
function formatDateOnly(yearValue, monthValue, dayValue) {
const year = Number(yearValue);
const month = Number(monthValue);
const day = Number(dayValue);
const date = new Date(year, month - 1, day);
if (
date.getFullYear() !== year ||
date.getMonth() !== month - 1 ||
date.getDate() !== day
) {
return '';
}
return `${yearValue}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
}
// 格式化日期 // 格式化日期
function formatDate(dateString) { function formatDate(dateString) {
if (!dateString) return '未知日期'; if (!hasValidTime(dateString)) return '';
try { try {
const date = new Date(dateString); const value = typeof dateString === 'string' ? dateString.trim() : dateString;
if (typeof value === 'string') {
const dateOnly = value.match(/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})$/);
if (dateOnly) {
return formatDateOnly(dateOnly[1], dateOnly[2], dateOnly[3]);
}
const cnDateOnly = value.match(/^(\d{4})年\s*(\d{1,2})月\s*(\d{1,2})日$/);
if (cnDateOnly) {
return formatDateOnly(cnDateOnly[1], cnDateOnly[2], cnDateOnly[3]);
}
}
const date = new Date(value);
return isNaN(date.getTime()) return isNaN(date.getTime())
? '未知日期' ? ''
: `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`; : `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
} catch { } catch {
return '未知日期'; return '';
} }
} }
</script> </script>
</body> </body>
</html> </html>

View File

@@ -32,8 +32,8 @@
<i :class="getFileIcon(file)"></i> <i :class="getFileIcon(file)"></i>
</div> </div>
<div class="file-name">{{ file.fileName }}</div> <div class="file-name">{{ file.fileName }}</div>
<div class="file-meta"> <div v-if="fileMetaText(file)" class="file-meta">
<template v-if="file.fileType !== 'folder'">{{ file.sizeStr || '0B' }} · </template>{{ formatDate(file.createTime) }} {{ fileMetaText(file) }}
</div> </div>
</div> </div>
<div v-if="!loading && (!currentFileList || currentFileList.length === 0)" class="empty-state"> <div v-if="!loading && (!currentFileList || currentFileList.length === 0)" class="empty-state">
@@ -168,7 +168,8 @@
<div v-if="selectedNode.fileType !== 'folder'" class="file-detail-meta"> <div v-if="selectedNode.fileType !== 'folder'" class="file-detail-meta">
<p>类型: {{ getFileTypeClass(selectedNode) }}</p> <p>类型: {{ getFileTypeClass(selectedNode) }}</p>
<p>大小: {{ selectedNode.sizeStr || '0B' }}</p> <p>大小: {{ selectedNode.sizeStr || '0B' }}</p>
<p v-if="selectedNode.createTime">创建时间: {{ formatDate(selectedNode.createTime) }}</p> <p v-if="formatDate(selectedNode.createTime)">创建时间: {{ formatDate(selectedNode.createTime) }}</p>
<p v-if="formatDate(selectedNode.updateTime)">更新时间: {{ formatDate(selectedNode.updateTime) }}</p>
</div> </div>
<div class="file-detail-actions"> <div class="file-detail-actions">
<el-button v-if="selectedNode.parserUrl" size="small" @click="previewFile(selectedNode)"> <el-button v-if="selectedNode.parserUrl" size="small" @click="previewFile(selectedNode)">
@@ -244,7 +245,8 @@
<div v-if="selectedNode.fileType !== 'folder'" class="file-detail-meta"> <div v-if="selectedNode.fileType !== 'folder'" class="file-detail-meta">
<p>类型: {{ getFileTypeClass(selectedNode) }}</p> <p>类型: {{ getFileTypeClass(selectedNode) }}</p>
<p>大小: {{ selectedNode.sizeStr || '0B' }}</p> <p>大小: {{ selectedNode.sizeStr || '0B' }}</p>
<p v-if="selectedNode.createTime">创建时间: {{ formatDate(selectedNode.createTime) }}</p> <p v-if="formatDate(selectedNode.createTime)">创建时间: {{ formatDate(selectedNode.createTime) }}</p>
<p v-if="formatDate(selectedNode.updateTime)">更新时间: {{ formatDate(selectedNode.updateTime) }}</p>
</div> </div>
<div class="file-detail-actions"> <div class="file-detail-actions">
<el-button v-if="selectedNode.parserUrl" size="small" @click="previewFile(selectedNode)"> <el-button v-if="selectedNode.parserUrl" size="small" @click="previewFile(selectedNode)">
@@ -314,8 +316,9 @@
<div class="file-dialog-content"> <div class="file-dialog-content">
<p><strong>{{ selectedFile?.fileName || '未命名文件' }}</strong></p> <p><strong>{{ selectedFile?.fileName || '未命名文件' }}</strong></p>
<p class="file-info"> <p class="file-info">
大小: {{ selectedFile?.sizeStr || '0B' }}<br> <template v-for="(line, index) in selectedFileInfoLines" :key="index">
创建时间: {{ formatDate(selectedFile?.createTime) }} {{ line }}<br v-if="index < selectedFileInfoLines.length - 1">
</template>
</p> </p>
</div> </div>
@@ -444,6 +447,19 @@ export default {
if (this.batchProgress.failed > 0) return 'exception' if (this.batchProgress.failed > 0) return 'exception'
if (this.batchProgress.current >= this.batchProgress.total && this.batchProgress.total > 0) return 'success' if (this.batchProgress.current >= this.batchProgress.total && this.batchProgress.total > 0) return 'success'
return '' return ''
},
selectedFileInfoLines() {
if (!this.selectedFile) return []
const lines = [`大小: ${this.selectedFile.sizeStr || '0B'}`]
const createTime = this.formatDate(this.selectedFile.createTime)
const updateTime = this.formatDate(this.selectedFile.updateTime)
if (createTime) {
lines.push(`创建时间: ${createTime}`)
}
if (updateTime) {
lines.push(`更新时间: ${updateTime}`)
}
return lines
} }
}, },
watch: { watch: {
@@ -815,11 +831,54 @@ export default {
document.body.removeChild(a) document.body.removeChild(a)
} }
}, },
hasValidTime(value) {
if (value === null || value === undefined) return false
if (typeof value !== 'string') return true
const trimmedValue = value.trim()
return trimmedValue !== '' && trimmedValue !== 'null' && trimmedValue !== 'undefined'
},
formatDateOnly(yearValue, monthValue, dayValue) {
const year = Number(yearValue)
const month = Number(monthValue)
const day = Number(dayValue)
const date = new Date(year, month - 1, day)
if (
date.getFullYear() !== year ||
date.getMonth() !== month - 1 ||
date.getDate() !== day
) {
return ''
}
return `${yearValue}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
},
formatDate(timestamp) { formatDate(timestamp) {
if (!timestamp) return '未知时间' if (!this.hasValidTime(timestamp)) return ''
const date = new Date(timestamp) const value = typeof timestamp === 'string' ? timestamp.trim() : timestamp
if (typeof value === 'string') {
const dateOnly = value.match(/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})$/)
if (dateOnly) {
return this.formatDateOnly(dateOnly[1], dateOnly[2], dateOnly[3])
}
const cnDateOnly = value.match(/^(\d{4})年\s*(\d{1,2})月\s*(\d{1,2})日$/)
if (cnDateOnly) {
return this.formatDateOnly(cnDateOnly[1], cnDateOnly[2], cnDateOnly[3])
}
}
const date = new Date(value)
if (Number.isNaN(date.getTime())) return ''
return date.toLocaleString('zh-CN') return date.toLocaleString('zh-CN')
}, },
fileMetaText(file) {
const parts = []
if (file.fileType !== 'folder') {
parts.push(file.sizeStr || '0B')
}
const timeText = this.formatDate(file.createTime)
if (timeText) {
parts.push(timeText)
}
return parts.join(' · ')
},
checkTheme() { checkTheme() {
this.isDarkTheme = document.documentElement.classList.contains('dark') this.isDarkTheme = document.documentElement.classList.contains('dark')
}, },

View File

@@ -238,8 +238,8 @@
storage: 'hash' storage: 'hash'
}, },
'ctfile': { 'ctfile': {
reg: /((?:https?:\/\/)?(?:[a-zA-Z\d-.]+)?(?:ctfile|545c|u062|ghpym|474b)\.com\/\w+\/[a-zA-Z\d-]+)/, reg: /((?:https?:\/\/)?(?:[a-zA-Z\d-.]+)?(?:ctfile|545c|u062|ghpym|474b)\.com\/(?:f(?:ile)?|d)\/[a-zA-Z\d_-]+\/?(?:\?[^#\s]*)?)/,
host: /(?:[a-zA-Z\d-.]+)?(?:ctfile|545c|u062|474b)\.com/, host: /(?:[a-zA-Z\d-.]+)?(?:ctfile|545c|u062|ghpym|474b)\.com/,
input: ['#passcode'], input: ['#passcode'],
button: ['.card-body button'], button: ['.card-body button'],
name: '城通网盘', name: '城通网盘',

View File

@@ -83,9 +83,9 @@ function registerTypeDefinitions(monaco) {
clearHeaders(): JsHttpClient; clearHeaders(): JsHttpClient;
getHeaders(): Record<string, string>; getHeaders(): Record<string, string>;
setTimeout(seconds: number): JsHttpClient; setTimeout(seconds: number): JsHttpClient;
sendForm(data: Record<string, any>): JsHttpResponse; sendForm(url: string, data: Record<string, any>): JsHttpResponse;
sendMultipartForm(url: string, data: Record<string, any>): JsHttpResponse; sendMultipartForm(url: string, data: Record<string, any>): JsHttpResponse;
sendJson(data: any): JsHttpResponse; sendJson(url: string, data: any): JsHttpResponse;
urlEncode(str: string): string; urlEncode(str: string): string;
urlDecode(str: string): string; urlDecode(str: string): string;
} }
@@ -244,17 +244,17 @@ function registerCompletionProvider(monaco) {
range range
}, },
{ {
label: 'http.sendForm(data)', label: 'http.sendForm(url, data)',
kind: monaco.languages.CompletionItemKind.Method, kind: monaco.languages.CompletionItemKind.Method,
insertText: 'http.sendForm(${1:data})', insertText: 'http.sendForm(${1:url}, ${2:data})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: '发送表单数据', documentation: '发送表单数据',
range range
}, },
{ {
label: 'http.sendJson(data)', label: 'http.sendJson(url, data)',
kind: monaco.languages.CompletionItemKind.Method, kind: monaco.languages.CompletionItemKind.Method,
insertText: 'http.sendJson(${1:data})', insertText: 'http.sendJson(${1:url}, ${2:data})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
documentation: '发送JSON数据', documentation: '发送JSON数据',
range range