前端添加HTML实体解码兜底

- 添加decodeHtmlEntities方法解码文件名
- 添加getFileDisplayName统一获取显示名称
- 确保文件名正确显示,即使后端未解码

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-30 14:04:50 +08:00
parent 4250e7de2f
commit dd97328b2f
2 changed files with 46 additions and 4 deletions

View File

@@ -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,7 +1419,7 @@
<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>

View File

@@ -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');