✨ 前端添加HTML实体解码兜底
- 添加decodeHtmlEntities方法解码文件名 - 添加getFileDisplayName统一获取显示名称 - 确保文件名正确显示,即使后端未解码 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1373,7 +1373,7 @@
|
|||||||
<i v-else-if="file.name.match(/\.(zip|rar|7z|tar|gz)$/i)" class="fas fa-file-archive" style="font-size: 64px; color: #795548;"></i>
|
<i v-else-if="file.name.match(/\.(zip|rar|7z|tar|gz)$/i)" class="fas fa-file-archive" style="font-size: 64px; color: #795548;"></i>
|
||||||
<i v-else class="fas fa-file" style="font-size: 64px; color: #9E9E9E;"></i>
|
<i v-else class="fas fa-file" style="font-size: 64px; color: #9E9E9E;"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="file-name" :title="file.displayName || file.name">{{ file.displayName || file.name }}</div>
|
<div class="file-name" :title="getFileDisplayName(file)">{{ getFileDisplayName(file) }}</div>
|
||||||
<div class="file-size">{{ file.isDirectory ? '文件夹' : file.sizeFormatted }}</div>
|
<div class="file-size">{{ file.isDirectory ? '文件夹' : file.sizeFormatted }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1419,9 +1419,9 @@
|
|||||||
<i v-else-if="file.name.match(/\.(xls|xlsx)$/i)" class="fas fa-file-excel" style="font-size: 20px; color: #4CAF50; flex-shrink: 0;"></i>
|
<i v-else-if="file.name.match(/\.(xls|xlsx)$/i)" class="fas fa-file-excel" style="font-size: 20px; color: #4CAF50; flex-shrink: 0;"></i>
|
||||||
<i v-else-if="file.name.match(/\.(zip|rar|7z|tar|gz)$/i)" class="fas fa-file-archive" style="font-size: 20px; color: #795548; flex-shrink: 0;"></i>
|
<i v-else-if="file.name.match(/\.(zip|rar|7z|tar|gz)$/i)" class="fas fa-file-archive" style="font-size: 20px; color: #795548; flex-shrink: 0;"></i>
|
||||||
<i v-else class="fas fa-file" style="font-size: 20px; color: #9E9E9E; flex-shrink: 0;"></i>
|
<i v-else class="fas fa-file" style="font-size: 20px; color: #9E9E9E; flex-shrink: 0;"></i>
|
||||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0;" :title="file.displayName || file.name">{{ file.displayName || file.name }}</span>
|
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0;" :title="getFileDisplayName(file)">{{ getFileDisplayName(file) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 10px; color: var(--text-secondary);">{{ file.isDirectory ? '-' : file.sizeFormatted }}</td>
|
<td style="padding: 10px; color: var(--text-secondary);">{{ file.isDirectory ? '-' : file.sizeFormatted }}</td>
|
||||||
<td style="padding: 10px; color: var(--text-secondary);">{{ formatDate(file.modifiedTime) }}</td>
|
<td style="padding: 10px; color: var(--text-secondary);">{{ formatDate(file.modifiedTime) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -2015,6 +2015,48 @@ handleDragLeave(e) {
|
|||||||
return d.toLocaleString();
|
return d.toLocaleString();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// HTML实体解码(前端兜底,防止已实体化的文件名显示乱码)
|
||||||
|
decodeHtmlEntities(str) {
|
||||||
|
if (typeof str !== 'string') return str;
|
||||||
|
const entityMap = {
|
||||||
|
amp: '&',
|
||||||
|
lt: '<',
|
||||||
|
gt: '>',
|
||||||
|
quot: '"',
|
||||||
|
apos: "'",
|
||||||
|
'#x27': "'",
|
||||||
|
'#x2F': '/',
|
||||||
|
'#x60': '`'
|
||||||
|
};
|
||||||
|
const decodeOnce = (input) =>
|
||||||
|
input.replace(/&(#x[0-9a-fA-F]+|#\d+|[a-zA-Z]+);/g, (match, code) => {
|
||||||
|
if (code[0] === '#') {
|
||||||
|
const isHex = code[1]?.toLowerCase() === 'x';
|
||||||
|
const num = isHex ? parseInt(code.slice(2), 16) : parseInt(code.slice(1), 10);
|
||||||
|
if (!Number.isNaN(num)) {
|
||||||
|
return String.fromCharCode(num);
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
const mapped = entityMap[code];
|
||||||
|
return mapped !== undefined ? mapped : match;
|
||||||
|
});
|
||||||
|
let output = str;
|
||||||
|
let decoded = decodeOnce(output);
|
||||||
|
while (decoded !== output) {
|
||||||
|
output = decoded;
|
||||||
|
decoded = decodeOnce(output);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
|
||||||
|
getFileDisplayName(file) {
|
||||||
|
if (!file) return '';
|
||||||
|
const base = file.displayName || file.name || '';
|
||||||
|
const decoded = this.decodeHtmlEntities(base);
|
||||||
|
return decoded || base;
|
||||||
|
},
|
||||||
|
|
||||||
openShare(url) {
|
openShare(url) {
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
const newWindow = window.open(url, '_blank', 'noopener');
|
const newWindow = window.open(url, '_blank', 'noopener');
|
||||||
|
|||||||
Reference in New Issue
Block a user