feat: 修复API密钥默认值 & 添加Markdown文件预览支持

- config.go: AuthAPIKey 默认值从空字符串恢复为 xn001624.
- index.html: 引入 marked.js,支持 .md/.markdown 文件渲染预览
- 新增 markdown 预览类型,自动获取内容并渲染为 HTML
- 文件图标识别 md 文件显示为代码文件图标

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root 2026-05-06 15:24:42 +08:00
parent c2111e5473
commit f5a906a208
2 changed files with 33 additions and 7 deletions

View File

@ -18,7 +18,7 @@ func LoadConfig() *Config {
RustFSSecretAccessKey: getEnv("RUSTFS_SECRET_ACCESS_KEY", ""),
RustFSRegion: getEnv("RUSTFS_REGION", "us-east-1"),
ServerPort: getEnv("SERVER_PORT", "8080"),
AuthAPIKey: getEnv("AUTH_API_KEY", ""),
AuthAPIKey: getEnv("AUTH_API_KEY", "xn001624."),
}
}

View File

@ -12,6 +12,8 @@
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<!-- Marked.js Markdown 渲染 -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
body { background-color: #f8f9fa; font-family: "Microsoft YaHei", sans-serif; }
.card { border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); border: none; margin-bottom: 20px; }
@ -22,6 +24,19 @@
.action-btn { cursor: pointer; margin-right: 10px; }
.action-btn:hover { color: #0d6efd; }
[v-cloak] { display: none; }
/* Markdown 预览样式 */
.markdown-body { text-align: left; padding: 20px; max-height: 80vh; overflow-y: auto; }
.markdown-body h1 { font-size: 1.8rem; border-bottom: 1px solid #eee; padding-bottom: 0.3rem; }
.markdown-body h2 { font-size: 1.5rem; border-bottom: 1px solid #eee; padding-bottom: 0.3rem; }
.markdown-body h3 { font-size: 1.3rem; }
.markdown-body pre { background: #f6f8fa; padding: 16px; border-radius: 6px; overflow-x: auto; }
.markdown-body code { background: #f6f8fa; padding: 2px 6px; border-radius: 3px; font-size: 90%; }
.markdown-body pre code { background: none; padding: 0; }
.markdown-body blockquote { border-left: 4px solid #ddd; padding: 0 15px; color: #666; }
.markdown-body table { border-collapse: collapse; width: 100%; margin: 16px 0; }
.markdown-body th, .markdown-body td { border: 1px solid #ddd; padding: 8px 12px; }
.markdown-body th { background: #f6f8fa; }
.markdown-body img { max-width: 100%; }
</style>
</head>
<body>
@ -219,10 +234,13 @@
<h5 class="modal-title">文件预览</h5>
<button type="button" class="btn-close" @click="previewUrl = null"></button>
</div>
<div class="modal-body text-center bg-light p-4">
<img v-if="isPreviewImage" :src="previewUrl" class="img-fluid" style="max-height: 80vh">
<video v-else-if="isPreviewVideo" :src="previewUrl" controls class="w-100" style="max-height: 80vh"></video>
<iframe v-else :src="previewUrl" class="w-100" style="height: 60vh; border:none"></iframe>
<div class="modal-body bg-light p-4">
<div v-if="isPreviewMarkdown" class="markdown-body" v-html="markdownHtml"></div>
<div v-else class="text-center">
<img v-if="isPreviewImage" :src="previewUrl" class="img-fluid" style="max-height: 80vh">
<video v-else-if="isPreviewVideo" :src="previewUrl" controls class="w-100" style="max-height: 80vh"></video>
<iframe v-else :src="previewUrl" class="w-100" style="height: 60vh; border:none"></iframe>
</div>
</div>
<div class="modal-footer justify-content-center">
<a :href="previewUrl" target="_blank" class="btn btn-outline-primary">
@ -258,6 +276,7 @@
const previewUrl = ref(null);
const previewType = ref('');
const markdownHtml = ref('');
// 检查登录状态
const checkAuth = () => {
@ -467,7 +486,12 @@
previewUrl.value = res.data.url;
const ext = key.split('.').pop().toLowerCase();
if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(ext)) {
if (['md', 'markdown'].includes(ext)) {
// Markdown 文件:获取内容并渲染
previewType.value = 'markdown';
const mdRes = await axios.get(res.data.url);
markdownHtml.value = marked.parse(mdRes.data);
} else if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(ext)) {
previewType.value = 'image';
} else if (['mp4', 'webm', 'ogg'].includes(ext)) {
previewType.value = 'video';
@ -481,6 +505,7 @@
const isPreviewImage = computed(() => previewType.value === 'image');
const isPreviewVideo = computed(() => previewType.value === 'video');
const isPreviewMarkdown = computed(() => previewType.value === 'markdown');
// Download
const downloadFile = (key) => {
@ -537,6 +562,7 @@
if (['pdf', 'doc', 'docx'].includes(ext)) return 'fas fa-file-pdf text-danger';
if (['mp4', 'avi'].includes(ext)) return 'fas fa-file-video text-success';
if (['zip', 'rar'].includes(ext)) return 'fas fa-file-archive text-warning';
if (['md', 'markdown'].includes(ext)) return 'fas fa-file-code text-info';
return 'fas fa-file text-secondary';
};
@ -556,7 +582,7 @@
return {
isAuthenticated,
buckets, currentBucket, files, loadingFiles, nextToken, pageHistory, filters,
showCreateBucketModal, newBucketName, uploads, previewUrl, isPreviewImage, isPreviewVideo,
showCreateBucketModal, newBucketName, uploads, previewUrl, isPreviewImage, isPreviewVideo, isPreviewMarkdown, markdownHtml,
logout,
loadBuckets, createBucket, selectBucket, deleteBucket, refreshFiles,
nextPage: nextP, prevPage,