🎈 perf: 优化部分样式的展示

This commit is contained in:
砂糖
2025-08-28 16:44:04 +08:00
parent 8634549dd3
commit 96b5c3ee45
15 changed files with 977 additions and 165 deletions

View File

@@ -1,44 +1,84 @@
<template>
<div style="display: flex; height: calc(100vh - 84px);">
<div class="file-preview-container">
<!-- 左侧文件列表 -->
<div style="width: 250px; border-right: 1px solid #eee; overflow-y: auto;">
<div style="padding: 8px 16px; border-bottom: 1px solid #eee; display: flex; gap: 8px; align-items: center;">
<button @click="handleClearAll" style="background: #f56c6c; color: #fff; border: none; border-radius: 3px; padding: 4px 10px; cursor: pointer;">清空全部</button>
<div class="file-list-sidebar">
<!-- 顶部操作栏 -->
<div class="file-list-header">
<button class="clear-all-btn" @click="handleClearAll">
清空全部
</button>
</div>
<div v-if="loadingList" style="padding: 24px; color: #888; text-align: center;">文件列表加载中...</div>
<ul v-else style="list-style: none; padding: 0; margin: 0;">
<!-- 加载状态 -->
<div class="list-loading" v-if="loadingList">
文件列表加载中...
</div>
<!-- 文件列表 -->
<ul class="file-group-list" v-else>
<template v-for="(group, groupName) in groupedFiles">
<li style="background:#f5f5f5; color:#888; font-weight:bold; padding:8px 16px; display: flex; align-items: center; justify-content: space-between;">
<span>{{ groupName }}</span>
<button @click.stop="handleClearGroup(groupName)" style="background: #e6a23c; color: #fff; border: none; border-radius: 3px; padding: 2px 8px; font-size: 12px; cursor: pointer;">清空分组</button>
<!-- 分组标题 -->
<li class="group-header">
<span class="group-name">{{ groupName }}</span>
<button class="clear-group-btn" @click.stop="handleClearGroup(groupName)">
清空分组
</button>
</li>
<li v-for="file in group" :key="file.fileName"
:style="{padding: '12px 16px', cursor: 'pointer', background: file.fileName === selectedFileName ? '#f0f0f0' : ''}"
@click="selectFile(file)">
{{ file.fileName }}
<span style="float: right; color: #f56c6c; cursor: pointer;" @click.stop="handleDeleteFile(file)">删除</span>
<!-- 分组文件项 -->
<li
class="file-item"
v-for="file in group"
:key="file.fileName"
:class="{ 'file-item--active': file.fileName === selectedFileName }"
@click="selectFile(file)"
>
<div class="file-item__content">
<span class="file-name">{{ file.fileName }}</span>
<span class="delete-file-btn" @click.stop="handleDeleteFile(file)">
删除
</span>
</div>
</li>
</template>
</ul>
</div>
<!-- 右侧文件预览 -->
<div style="flex: 1; padding: 24px; overflow-y: auto;">
<div v-if="loadingContent" style="color: #888;">内容加载中...</div>
<div v-else-if="selectedFile">
<h3>{{ selectedFile.fileName }}</h3>
<div class="file-preview-main">
<!-- 加载状态 -->
<div class="content-loading" v-if="loadingContent">
内容加载中...
</div>
<!-- 选中文件预览 -->
<div class="preview-card" v-else-if="selectedFile">
<h3 class="preview-title">{{ selectedFile.fileName }}</h3>
<!-- 文本文件预览 -->
<template v-if="selectedFile.fileType === 'text'">
<pre style="background: #fafafa; padding: 16px; border-radius: 4px; min-height: 300px;">{{ selectedFile.fileContent }}</pre>
<pre class="text-preview">{{ selectedFile.fileContent }}</pre>
</template>
<!-- 图片文件预览保留注释需时启用 -->
<!-- <template v-else-if="selectedFile.fileType === 'image'">
<div style="padding: 16px; background: #fafafa; border-radius: 4px; min-height: 300px; display: flex; align-items: center; justify-content: center;">
<img :src="selectedFile.fileContent" alt="图片预览" style="max-width: 100%; max-height: 600px;" />
<div class="image-preview-container">
<img :src="selectedFile.fileContent" alt="图片预览" class="image-preview" />
</div>
</template> -->
<!-- 其他文件类型 -->
<template v-else>
<div style="background: #fafafa; padding: 16px; border-radius: 4px; min-height: 300px; color: #f56c6c;">{{ selectedFile.fileContent }}</div>
<div class="unsupported-type">
{{ selectedFile.fileContent }}
</div>
</template>
</div>
<div v-else style="color: #888;">请选择左侧文件进行预览</div>
<!-- 未选中文件 -->
<div class="no-selection" v-else>
请选择左侧文件进行预览
</div>
</div>
</div>
</template>
@@ -58,7 +98,7 @@ export default {
},
created() {
this.fetchFileList();
getFileStats()
getFileStats(); // 补充括号,修复语法问题
},
computed: {
groupedFiles() {
@@ -79,6 +119,7 @@ export default {
weekAgo.setDate(today.getDate() - 6);
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
const threeMonthsAgo = new Date(now.getFullYear(), now.getMonth() - 2, 1);
(this.files || []).forEach(file => {
const d = file.lastModified ? new Date(file.lastModified) : null;
if (!d) {
@@ -99,6 +140,7 @@ export default {
groups['更久'].push(file);
}
});
// 只返回有文件的分组
return Object.fromEntries(Object.entries(groups).filter(([k, v]) => v.length));
}
@@ -111,10 +153,12 @@ export default {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
confirmButtonClass: 'el-button--warning',
cancelButtonClass: 'el-button--text'
}).then(async () => {
const names = this.files.map(f => f.fileName);
await this.batchDelete(names);
}).catch(() => {});
}).catch(() => { });
},
// 清空某个分组
@@ -125,10 +169,12 @@ export default {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
confirmButtonClass: 'el-button--warning',
cancelButtonClass: 'el-button--text'
}).then(async () => {
const names = group.map(f => f.fileName);
await this.batchDelete(names);
}).catch(() => {});
}).catch(() => { });
},
// 批量删除
@@ -154,6 +200,8 @@ export default {
this.loadingList = false;
}
},
// 获取文件列表
async fetchFileList() {
this.loadingList = true;
this.files = [];
@@ -168,6 +216,7 @@ export default {
}
},
// 选择文件预览
async selectFile(file) {
this.selectedFileName = file.fileName;
this.selectedFile = null;
@@ -175,26 +224,25 @@ export default {
try {
const isText = /\.(txt|md|json|js|ts|log|csv|xml|html|css)$/i.test(file.fileName);
const isImage = /\.(png|jpe?g|gif|bmp|webp|svg)$/i.test(file.fileName);
if (isText) {
const textResult = await getFileContent(file.fileName)
this.selectedFile = {...textResult.data, fileType: 'text'};
}
const textResult = await getFileContent(file.fileName);
this.selectedFile = { ...textResult.data, fileType: 'text' };
}
// 图片预览逻辑(保留,需时启用)
// else if (isImage) {
// // 图片文件
// let blob = null;
// if (typeof this.$options.components?.getFileContent === 'function') {
// blob = await this.$options.components.getFileContent(file.fileName);
// } else if (typeof window.getFileContent === 'function') {
// blob = await window.getFileContent(file.fileName);
// }
// // blob 可能是base64字符串或Blob对象需适配
// let imgUrl = '';
// if (blob instanceof Blob) {
// imgUrl = URL.createObjectURL(blob);
// } else if (typeof blob === 'string' && blob.startsWith('data:image')) {
// imgUrl = blob;
// } else if (typeof blob === 'string') {
// // 假设后端返回base64
// imgUrl = 'data:image/*;base64,' + blob;
// }
// this.selectedFile = { fileName: file.fileName, fileContent: imgUrl, fileType: 'image' };
@@ -206,11 +254,13 @@ export default {
this.loadingContent = false;
}
},
// 单个文件删除
handleDeleteFile(file) {
deleteFile(file.fileName)
.then(() => {
this.$message.success('文件删除成功');
this.fetchFileList(); // 重新加载文件列表
this.fetchFileList();
})
.catch(err => {
this.$message.error('删除文件失败: ' + (err.message || '未知错误'));
@@ -221,5 +271,291 @@ export default {
</script>
<style scoped>
/* 可根据需要自定义样式 */
</style>
/* 全局容器 */
.file-preview-container {
display: flex;
height: calc(100vh - 84px);
background: var(--color-background);
color: var(--color-text-regular);
}
/* 左侧文件列表侧边栏 */
.file-list-sidebar {
width: 250px;
border-right: 1px solid var(--border-color-light);
overflow-y: auto;
background: var(--color-background-light);
}
/* 列表顶部操作栏 */
.file-list-header {
padding: var(--spacing-base) var(--spacing-lg);
border-bottom: 1px solid var(--border-color-light);
display: flex;
gap: var(--spacing-base);
align-items: center;
background: var(--metal-gradient-light);
}
/* 清空全部按钮 */
.clear-all-btn {
background: linear-gradient(145deg, #e53e3e, #c53030);
color: #fff;
border: 1px solid #9b2c2c;
border-radius: 4px;
padding: 4px 10px;
cursor: pointer;
transition: all 0.2s;
box-shadow: var(--metal-shadow-inset);
}
.clear-all-btn:hover {
box-shadow: var(--metal-shadow);
transform: translateY(-1px);
}
.clear-all-btn:active {
box-shadow: var(--metal-shadow-inset);
transform: translateY(0);
}
/* 列表加载状态 */
.list-loading {
padding: 24px;
color: var(--color-text-secondary);
text-align: center;
background: var(--metal-gradient-light);
}
/* 文件分组列表 */
.file-group-list {
list-style: none;
padding: 0;
margin: 0;
}
/* 分组标题栏 */
.group-header {
background: var(--metal-gradient-dark);
color: var(--color-text-primary);
font-weight: 600;
padding: var(--spacing-base) var(--spacing-lg);
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--border-color-lighter);
}
/* 清空分组按钮 */
.clear-group-btn {
background: linear-gradient(145deg, #e6a23c, #d48822);
color: #fff;
border: 1px solid #b87319;
border-radius: 3px;
padding: 2px 8px;
font-size: 12px;
cursor: pointer;
transition: all 0.2s;
box-shadow: var(--metal-shadow-inset);
}
.clear-group-btn:hover {
box-shadow: var(--metal-shadow);
transform: translateY(-1px);
}
.clear-group-btn:active {
box-shadow: var(--metal-shadow-inset);
transform: translateY(0);
}
/* 文件项基础样式 */
.file-item {
padding: 12px var(--spacing-lg);
cursor: pointer;
transition: all 0.2s;
background: var(--color-background-light);
border-left: 3px solid transparent;
}
.file-item:hover {
background: var(--metal-gradient-light);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* 文件项选中状态 */
.file-item--active {
background: rgba(var(--color-primary-rgb), 0.2);
border-left: 3px solid var(--color-primary);
}
/* 文件项内容容器 */
.file-item__content {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 文件名 */
.file-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
/* 删除文件按钮 */
.delete-file-btn {
color: var(--color-danger);
cursor: pointer;
padding: 2px 4px;
border-radius: 3px;
transition: all 0.2s;
}
.delete-file-btn:hover {
background: rgba(var(--color-danger-rgb), 0.15);
}
/* 右侧预览主区域 */
.file-preview-main {
flex: 1;
padding: var(--spacing-lg);
overflow-y: auto;
}
/* 内容加载状态 */
.content-loading {
color: var(--color-text-secondary);
padding: 24px;
background: var(--metal-gradient-light);
border-radius: 6px;
border: 1px solid var(--border-color-light);
}
/* 预览卡片容器 */
.preview-card {
background: var(--metal-gradient-light);
border-radius: 6px;
border: 1px solid var(--border-color-light);
padding: var(--spacing-lg);
box-shadow: var(--metal-shadow);
}
/* 预览标题 */
.preview-title {
color: var(--color-text-primary);
margin-top: 0;
padding-bottom: var(--spacing-base);
border-bottom: 1px solid var(--border-color-lighter);
}
/* 文本预览样式 */
.text-preview {
background: var(--table-bg);
color: var(--color-text-regular);
padding: var(--spacing-lg);
border-radius: 4px;
min-height: 300px;
border: 1px solid var(--border-color-lighter);
overflow-x: auto;
font-size: 13px;
line-height: 1.5;
margin: 0;
}
/* 图片预览容器(保留,需时启用) */
/* .image-preview-container {
padding: var(--spacing-lg);
background: var(--table-bg);
border-radius: 4px;
min-height: 300px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border-color-lighter);
}
.image-preview {
max-width: 100%;
max-height: 600px;
border-radius: 4px;
box-shadow: var(--metal-shadow);
} */
/* 不支持的文件类型样式 */
.unsupported-type {
background: var(--table-bg);
padding: var(--spacing-lg);
border-radius: 4px;
min-height: 300px;
color: var(--color-warning);
border: 1px solid var(--border-color-lighter);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
/* 未选择文件状态 */
.no-selection {
color: var(--color-text-secondary);
padding: 24px;
background: var(--metal-gradient-light);
border-radius: 6px;
border: 1px solid var(--border-color-light);
}
/* 滚动条样式优化 */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: var(--color-background-light);
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: var(--border-color-light);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--border-color-base);
}
/* 修复Element消息提示框样式适配深色 */
::v-deep .el-message {
background: var(--metal-gradient-light);
border-color: var(--border-color-light);
color: var(--color-text-regular);
}
::v-deep .el-message__icon--success {
color: var(--color-success);
}
::v-deep .el-message__icon--error {
color: var(--color-danger);
}
::v-deep .el-message__icon--info {
color: var(--color-info);
}
/* 修复确认对话框样式 */
::v-deep .el-dialog {
background: var(--metal-gradient-light) !important;
border-color: var(--border-color-light) !important;
}
::v-deep .el-dialog__title {
color: var(--color-text-primary) !important;
}
::v-deep .el-dialog__body {
color: var(--color-text-regular) !important;
}
</style>