refactor(system): 重构文件管理页面为卡片视图
- 将文件列表从表格布局改为响应式卡片网格布局 - 添加文件类型图标和颜色分类,提升视觉识别效果 - 重构页面头部结构,整合统计数据、筛选标签和工具栏 - 实现卡片多选功能和批量操作支持 - 优化文件详情弹窗布局,调整预览和元数据区域 - 更新样式系统,统一间距和交互反馈效果 - 移除高级搜索切换功能,简化查询界面 - 添加文件扩展名获取和图标分类辅助方法
This commit is contained in:
@@ -1,98 +1,78 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<!-- 左右分栏布局 -->
|
<!-- 顶部:统计卡片 + 工具栏 + 筛选标签 -->
|
||||||
<div class="file-layout">
|
<div class="page-header">
|
||||||
<!-- 左侧边栏 -->
|
<div class="stats-area">
|
||||||
<div class="file-sidebar">
|
<el-card class="stats-card" shadow="hover" :body-style="{ padding: '0' }">
|
||||||
<!-- 统计卡片 -->
|
<div class="stats-grid">
|
||||||
<el-card class="summary-card" shadow="hover" :body-style="{ padding: '10px' }">
|
<div class="stats-item">
|
||||||
<el-row :gutter="6">
|
<span class="stats-label">文件总数</span>
|
||||||
<el-col :span="12">
|
<span class="stats-value">{{ stats.totalFiles }}</span>
|
||||||
<div class="summary-item">
|
|
||||||
<span class="item-label">文件总数</span>
|
|
||||||
<span class="item-value">{{ stats.totalFiles }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
<div class="stats-item">
|
||||||
<el-col :span="12">
|
<span class="stats-label">公开文件</span>
|
||||||
<div class="summary-item">
|
<span class="stats-value">{{ stats.publicFiles }}</span>
|
||||||
<span class="item-label">公开文件</span>
|
|
||||||
<span class="item-value">{{ stats.publicFiles }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
<div class="stats-item">
|
||||||
</el-row>
|
<span class="stats-label">私有文件</span>
|
||||||
<el-row :gutter="6" style="margin-top: 4px;">
|
<span class="stats-value">{{ stats.privateFiles }}</span>
|
||||||
<el-col :span="12">
|
</div>
|
||||||
<div class="summary-item">
|
<div class="stats-item">
|
||||||
<span class="item-label">私有文件</span>
|
<span class="stats-label">我上传的</span>
|
||||||
<span class="item-value">{{ stats.privateFiles }}</span>
|
<span class="stats-value">{{ stats.myFiles }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<div class="summary-item">
|
|
||||||
<span class="item-label">我上传的</span>
|
|
||||||
<span class="item-value">{{ stats.myFiles }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 搜索框 -->
|
<div class="header-main">
|
||||||
<div class="sidebar-section">
|
<div class="filter-row">
|
||||||
|
<div class="type-tags">
|
||||||
|
<span
|
||||||
|
v-for="opt in fileTypeOptions"
|
||||||
|
:key="opt.value"
|
||||||
|
class="type-tag"
|
||||||
|
:class="{ active: (queryParams.fileType || '') === opt.value }"
|
||||||
|
@click="handleTypeTabClick(opt.value)"
|
||||||
|
>{{ opt.label }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="filter-extra">
|
||||||
|
<el-select v-model="queryParams.scopeType" placeholder="可见范围" clearable size="mini" @change="handleQuery" style="width:110px;">
|
||||||
|
<el-option label="公开" :value="1" />
|
||||||
|
<el-option label="私有" :value="2" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="toolbar-row">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.fileName"
|
v-model="queryParams.fileName"
|
||||||
prefix-icon="el-icon-search"
|
prefix-icon="el-icon-search"
|
||||||
placeholder="按名称搜索"
|
placeholder="按名称搜索"
|
||||||
clearable
|
clearable
|
||||||
size="mini"
|
size="mini"
|
||||||
|
style="width:200px;"
|
||||||
@change="handleQuery"
|
@change="handleQuery"
|
||||||
@clear="handleQuery"
|
@clear="handleQuery"
|
||||||
></el-input>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 文件类型列表 -->
|
|
||||||
<div class="sidebar-section sidebar-file-types">
|
|
||||||
<div class="sidebar-label">文件类型</div>
|
|
||||||
<div class="file-type-list">
|
|
||||||
<div
|
|
||||||
v-for="opt in fileTypeOptions"
|
|
||||||
:key="opt.value"
|
|
||||||
class="type-list-item"
|
|
||||||
:class="{ active: (queryParams.fileType || '') === opt.value }"
|
|
||||||
@click="handleTypeTabClick(opt.value)"
|
|
||||||
>{{ opt.label }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 右侧主区域 -->
|
|
||||||
<div class="file-main">
|
|
||||||
<!-- 高级搜索 + 操作按钮 -->
|
|
||||||
<div class="main-toolbar">
|
|
||||||
<el-button icon="el-icon-sort" size="mini" @click="toggleQuery">高级搜索</el-button>
|
|
||||||
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd">上传文件</el-button>
|
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd">上传文件</el-button>
|
||||||
<el-button type="danger" icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">删除</el-button>
|
<el-button type="danger" icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">删除</el-button>
|
||||||
|
<span v-if="selectedCardIds.length > 0" class="selected-count">已选 {{ selectedCardIds.length }} 项</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-show="showQuery" class="advanced-search">
|
<div class="advanced-search">
|
||||||
<el-form :model="queryParams" inline size="mini" class="advanced-search-form">
|
<el-form :model="queryParams" inline size="mini" class="advanced-search-form">
|
||||||
<el-form-item label="订单编号">
|
<el-form-item label="订单编号">
|
||||||
<el-input v-model="queryParams.orderNo" placeholder="订单编号" clearable @change="handleQuery" style="width:140px;"></el-input>
|
<el-input v-model="queryParams.orderNo" placeholder="订单编号" clearable @change="handleQuery" style="width:140px;" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="所属部门">
|
<el-form-item label="所属部门">
|
||||||
<el-input v-model="queryParams.dept" placeholder="所属部门" clearable @change="handleQuery" style="width:140px;"></el-input>
|
<el-input v-model="queryParams.dept" placeholder="所属部门" clearable @change="handleQuery" style="width:140px;" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="文件类型">
|
<el-form-item label="文件类型">
|
||||||
<el-select v-model="queryParams.fileType" placeholder="文件类型" clearable @change="handleQuery" style="width:120px;">
|
<el-select v-model="queryParams.fileType" placeholder="文件类型" clearable @change="handleQuery" style="width:120px;">
|
||||||
<el-option v-for="item in dict.type.sys_file_type" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in dict.type.sys_file_type" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="可见范围">
|
|
||||||
<el-select v-model="queryParams.scopeType" placeholder="可见范围" clearable @change="handleQuery" style="width:120px;">
|
|
||||||
<el-option label="公开" :value="1" />
|
|
||||||
<el-option label="私有" :value="2" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="上传时间">
|
<el-form-item label="上传时间">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="dateRange"
|
v-model="dateRange"
|
||||||
@@ -105,60 +85,48 @@
|
|||||||
clearable
|
clearable
|
||||||
style="width:240px;"
|
style="width:240px;"
|
||||||
@change="handleQuery"
|
@change="handleQuery"
|
||||||
></el-date-picker>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 文件表格 -->
|
|
||||||
<div class="file-table-wrapper">
|
|
||||||
<KLPTable v-loading="loading" :data="fileList" @selection-change="handleSelectionChange" highlight-current-row @row-click="handleRowClick">
|
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
|
||||||
<el-table-column label="文件名称" align="center" prop="fileName" :show-overflow-tooltip="true" min-width="160">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-link type="primary" @click="handleShowInfo(scope.row)">{{ scope.row.fileName }}</el-link>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="上传人" align="center" prop="createByName" width="120" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column label="所属部门" align="center" prop="dept" width="120" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column label="订单编号" align="center" prop="orderNo" width="130" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column label="文件类型" align="center" width="100">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<dict-tag :options="dict.type.sys_file_type" :value="scope.row.fileType"/>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="文件大小" align="center" width="90">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span>{{ formatFileSize(scope.row.fileSize) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="可见范围" align="center" width="80">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-tag :type="scope.row.scopeType === 1 ? 'success' : 'warning'" size="small">
|
|
||||||
{{ scope.row.scopeType === 1 ? '公开' : '私有' }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="上传时间" align="center" width="155">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="浏览次数" align="center" width="75">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span>{{ scope.row.viewCount != null ? scope.row.viewCount : 0 }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" align="center" width="140" fixed="right">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<div class="action-cell">
|
|
||||||
<el-button type="text" size="mini" icon="el-icon-view" @click.stop="handleShowInfo(scope.row)">详情</el-button>
|
|
||||||
<el-button v-if="canEdit(scope.row)" type="text" size="mini" icon="el-icon-edit" @click.stop="handleUpdate(scope.row)">编辑</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</el-table-column>
|
|
||||||
</KLPTable>
|
|
||||||
|
|
||||||
|
<!-- 文件卡片网格 -->
|
||||||
|
<div class="card-container" v-loading="loading">
|
||||||
|
<div v-if="fileList.length > 0" class="card-grid">
|
||||||
|
<div
|
||||||
|
v-for="file in fileList"
|
||||||
|
:key="file.fileId"
|
||||||
|
class="file-card"
|
||||||
|
:class="{ selected: isSelected(file.fileId) }"
|
||||||
|
@click="handleCardClick(file)"
|
||||||
|
>
|
||||||
|
<div class="card-checkbox" @click.stop="toggleSelect(file)">
|
||||||
|
<i v-if="isSelected(file.fileId)" class="el-icon-check"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-icon" :class="getFileIconClass(file)">
|
||||||
|
<span class="card-ext">{{ getFileExt(file) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-name" :title="file.fileName">{{ file.fileName }}</div>
|
||||||
|
<div class="card-uploader">{{ file.createByName || file.createBy }}</div>
|
||||||
|
<div class="card-meta">
|
||||||
|
<span>{{ formatFileSize(file.fileSize) }}</span>
|
||||||
|
<span class="meta-sep">·</span>
|
||||||
|
<span>{{ parseTime(file.createTime, '{mm}-{dd}') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-view" @click.stop="handleShowInfo(file)">详情</el-button>
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-download" @click.stop="downloadFile(file)">下载</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else-if="!loading" description="暂无文件" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
<pagination
|
<pagination
|
||||||
v-show="total>0"
|
v-show="total>0"
|
||||||
:total="total"
|
:total="total"
|
||||||
@@ -166,9 +134,6 @@
|
|||||||
:limit.sync="queryParams.pageSize"
|
:limit.sync="queryParams.pageSize"
|
||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 上传/编辑对话框 -->
|
<!-- 上传/编辑对话框 -->
|
||||||
<el-dialog :title="dialogTitle" :visible.sync="open" width="650px" append-to-body @close="handleDialogClose">
|
<el-dialog :title="dialogTitle" :visible.sync="open" width="650px" append-to-body @close="handleDialogClose">
|
||||||
@@ -225,8 +190,9 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 文件详情弹窗(含预览) -->
|
<!-- 文件详情弹窗(含预览) -->
|
||||||
<el-dialog :title="infoTitle" :visible.sync="infoVisible" width="1100px" append-to-body top="5vh" @close="handleInfoClose">
|
<el-dialog :title="infoTitle" :visible.sync="infoVisible" width="1200px" append-to-body top="3vh" @close="handleInfoClose">
|
||||||
<div v-if="infoFile" class="info-dialog-body">
|
<div v-if="infoFile" class="info-dialog-body">
|
||||||
|
<div class="info-main-row">
|
||||||
<div class="info-preview">
|
<div class="info-preview">
|
||||||
<ImagePreview v-if="infoFileCategory === 'image'" :src="infoFile.filePath" />
|
<ImagePreview v-if="infoFileCategory === 'image'" :src="infoFile.filePath" />
|
||||||
<PdfPreview v-else-if="infoFileCategory === 'pdf'" :src="infoFile.filePath" />
|
<PdfPreview v-else-if="infoFileCategory === 'pdf'" :src="infoFile.filePath" />
|
||||||
@@ -257,7 +223,13 @@
|
|||||||
<el-descriptions-item label="上传时间">{{ parseTime(infoFile.createTime) }}</el-descriptions-item>
|
<el-descriptions-item label="上传时间">{{ parseTime(infoFile.createTime) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="备注">{{ infoFile.remark || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="备注">{{ infoFile.remark || '-' }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<!-- 评论区域 -->
|
<div style="margin-top:12px;text-align:right;">
|
||||||
|
<el-button type="warning" plain size="mini" icon="el-icon-download" @click="handleExportInfo">导出</el-button>
|
||||||
|
<el-button type="primary" size="mini" icon="el-icon-download" @click="downloadFile(infoFile)">下载</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 评论区域单独放在下面 -->
|
||||||
<div class="info-comment">
|
<div class="info-comment">
|
||||||
<div class="comment-bar" @click="commentExpanded = !commentExpanded">
|
<div class="comment-bar" @click="commentExpanded = !commentExpanded">
|
||||||
<span><i class="el-icon-chat-dot-round"></i> 评论 ({{ comments.length }})</span>
|
<span><i class="el-icon-chat-dot-round"></i> 评论 ({{ comments.length }})</span>
|
||||||
@@ -282,11 +254,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top:12px;text-align:right;">
|
|
||||||
<el-button type="warning" plain size="mini" icon="el-icon-download" @click="handleExportInfo">导出</el-button>
|
|
||||||
<el-button type="primary" size="mini" icon="el-icon-download" @click="downloadFile(infoFile)">下载</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -320,12 +287,11 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
// 选中数组
|
// 选中数组
|
||||||
ids: [],
|
ids: [],
|
||||||
|
selectedCardIds: [],
|
||||||
// 非单个禁用
|
// 非单个禁用
|
||||||
single: true,
|
single: true,
|
||||||
// 非多个禁用
|
// 非多个禁用
|
||||||
multiple: true,
|
multiple: true,
|
||||||
// 显示高级搜索
|
|
||||||
showQuery: false,
|
|
||||||
// 总条数
|
// 总条数
|
||||||
total: 0,
|
total: 0,
|
||||||
// 文件列表
|
// 文件列表
|
||||||
@@ -433,6 +399,9 @@ export default {
|
|||||||
/** 查询文件列表 */
|
/** 查询文件列表 */
|
||||||
getList() {
|
getList() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
this.selectedCardIds = []
|
||||||
|
this.ids = []
|
||||||
|
this.multiple = true
|
||||||
const params = this.addDateRange(this.queryParams, this.dateRange)
|
const params = this.addDateRange(this.queryParams, this.dateRange)
|
||||||
listFile(params).then(response => {
|
listFile(params).then(response => {
|
||||||
this.fileList = response.rows
|
this.fileList = response.rows
|
||||||
@@ -450,17 +419,57 @@ export default {
|
|||||||
listFile({ pageNum: 1, pageSize: 1, createBy: this.$store.getters.name }).then(r => { this.stats.myFiles = r.total })
|
listFile({ pageNum: 1, pageSize: 1, createBy: this.$store.getters.name }).then(r => { this.stats.myFiles = r.total })
|
||||||
listFile({ pageNum: 1, pageSize: 1 }).then(r => { this.stats.totalFiles = r.total })
|
listFile({ pageNum: 1, pageSize: 1 }).then(r => { this.stats.totalFiles = r.total })
|
||||||
},
|
},
|
||||||
|
/** 获取文件扩展名(大写,用于图标显示) */
|
||||||
|
getFileExt(file) {
|
||||||
|
const raw = file.suffix || file.fileName || ''
|
||||||
|
const ext = raw.includes('.') ? raw.split('.').pop() : raw
|
||||||
|
return ext.slice(0, 4).toUpperCase()
|
||||||
|
},
|
||||||
|
/** 文件图标颜色类 */
|
||||||
|
getFileIconClass(file) {
|
||||||
|
const ext = (file.suffix || file.fileName || '').toLowerCase()
|
||||||
|
if (['doc', 'docx'].includes(ext)) return 'icon-word'
|
||||||
|
if (['xls', 'xlsx'].includes(ext)) return 'icon-excel'
|
||||||
|
if (['ppt', 'pptx'].includes(ext)) return 'icon-ppt'
|
||||||
|
if (ext === 'pdf') return 'icon-pdf'
|
||||||
|
if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'ico'].includes(ext)) return 'icon-image'
|
||||||
|
if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)) return 'icon-archive'
|
||||||
|
if (['mp4', 'avi', 'mov', 'mkv', 'wmv', 'flv'].includes(ext)) return 'icon-video'
|
||||||
|
if (['mp3', 'wav', 'flac', 'aac', 'ogg'].includes(ext)) return 'icon-audio'
|
||||||
|
if (['txt', 'log', 'md'].includes(ext)) return 'icon-text'
|
||||||
|
return 'icon-other'
|
||||||
|
},
|
||||||
/** 格式化文件大小 */
|
/** 格式化文件大小 */
|
||||||
formatFileSize(size) {
|
formatFileSize(size) {
|
||||||
if (!size) return '0 B'
|
if (!size) return '0 B'
|
||||||
if (size < 1024) return size + ' B'
|
if (size < 1024) return size + ' B'
|
||||||
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB'
|
if (size < 1024 * 1024) return (size / 1024).toFixed(1) + ' KB'
|
||||||
return (size / 1024 / 1024).toFixed(2) + ' MB'
|
return (size / 1024 / 1024).toFixed(1) + ' MB'
|
||||||
},
|
},
|
||||||
/** 是否可编辑 */
|
/** 是否可编辑 */
|
||||||
canEdit(row) {
|
canEdit(row) {
|
||||||
return row.createBy === this.$store.getters.name
|
return row.createBy === this.$store.getters.name
|
||||||
},
|
},
|
||||||
|
/** 卡片选中判断 */
|
||||||
|
isSelected(fileId) {
|
||||||
|
return this.selectedCardIds.includes(fileId)
|
||||||
|
},
|
||||||
|
/** 切换卡片选中 */
|
||||||
|
toggleSelect(file) {
|
||||||
|
const idx = this.selectedCardIds.indexOf(file.fileId)
|
||||||
|
if (idx > -1) {
|
||||||
|
this.selectedCardIds.splice(idx, 1)
|
||||||
|
} else {
|
||||||
|
this.selectedCardIds.push(file.fileId)
|
||||||
|
}
|
||||||
|
this.ids = [...this.selectedCardIds]
|
||||||
|
this.single = this.selectedCardIds.length !== 1
|
||||||
|
this.multiple = this.selectedCardIds.length === 0
|
||||||
|
},
|
||||||
|
/** 点击卡片(打开详情) */
|
||||||
|
handleCardClick(file) {
|
||||||
|
this.handleShowInfo(file)
|
||||||
|
},
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
cancel() {
|
cancel() {
|
||||||
this.open = false
|
this.open = false
|
||||||
@@ -501,10 +510,6 @@ export default {
|
|||||||
this.queryParams.pageNum = 1
|
this.queryParams.pageNum = 1
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
/** 切换高级搜索 */
|
|
||||||
toggleQuery() {
|
|
||||||
this.showQuery = !this.showQuery
|
|
||||||
},
|
|
||||||
/** 文件类型筛选切换 */
|
/** 文件类型筛选切换 */
|
||||||
handleTypeTabClick(value) {
|
handleTypeTabClick(value) {
|
||||||
this.queryParams.fileType = value || undefined
|
this.queryParams.fileType = value || undefined
|
||||||
@@ -525,7 +530,7 @@ export default {
|
|||||||
}
|
}
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
/** 多选框 */
|
/** 多选框(兼容保留) */
|
||||||
handleSelectionChange(selection) {
|
handleSelectionChange(selection) {
|
||||||
this.ids = selection.map(item => item.fileId)
|
this.ids = selection.map(item => item.fileId)
|
||||||
this.single = selection.length !== 1
|
this.single = selection.length !== 1
|
||||||
@@ -719,126 +724,128 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 左右分栏 */
|
/* ========== 页面顶部:统计 + 工具栏 + 筛选标签 ========== */
|
||||||
.file-layout {
|
.page-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
gap: 0;
|
gap: 12px;
|
||||||
height: calc(100vh - 100px);
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 左侧边栏 */
|
/* 统计卡片区域 */
|
||||||
.file-sidebar {
|
.stats-area {
|
||||||
width: 220px;
|
width: 220px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding-right: 12px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-section {
|
.stats-card {
|
||||||
margin-bottom: 12px;
|
height: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-label {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #606266;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
padding-left: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 文件类型列表(纵向) */
|
|
||||||
.sidebar-file-types {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-type-list {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
border: 1px solid #ebeef5;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type-list-item {
|
|
||||||
padding: 8px 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #606266;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
border-bottom: 1px solid #f2f2f2;
|
|
||||||
transition: all 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type-list-item:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type-list-item:hover {
|
|
||||||
color: #5F7BA0;
|
|
||||||
background: #f5f7fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type-list-item.active {
|
|
||||||
color: #fff;
|
|
||||||
background: #5F7BA0;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 操作列按钮对齐 */
|
|
||||||
.action-cell {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 2px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计卡片 */
|
|
||||||
.summary-card {
|
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-item {
|
.stats-card /deep/ .el-card__body {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 4px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-item {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 6px 4px;
|
padding: 2px 4px;
|
||||||
border: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
border-radius: 2px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-label {
|
.stats-label {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
margin-bottom: 2px;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-value {
|
.stats-value {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 20px;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: 700;
|
||||||
color: #1f2d3d;
|
color: #1f2d3d;
|
||||||
line-height: 1.2;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 右侧主区域 */
|
/* 右侧主区域 */
|
||||||
.file-main {
|
.header-main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-toolbar {
|
/* 工具栏行 */
|
||||||
|
.toolbar-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 8px;
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-count {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #409eff;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选标签行 */
|
||||||
|
.filter-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tag {
|
||||||
|
padding: 3px 14px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #606266;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
transition: all 0.2s;
|
||||||
|
user-select: none;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tag:hover {
|
||||||
|
color: #5F7BA0;
|
||||||
|
border-color: #5F7BA0;
|
||||||
|
background: #f0f4f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tag.active {
|
||||||
|
color: #fff;
|
||||||
|
background: #5F7BA0;
|
||||||
|
border-color: #5F7BA0;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-extra {
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 高级搜索 */
|
/* 高级搜索 */
|
||||||
@@ -847,7 +854,7 @@ export default {
|
|||||||
border: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
margin-bottom: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.advanced-search-form {
|
.advanced-search-form {
|
||||||
@@ -860,27 +867,191 @@ export default {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表格区域 */
|
/* ========== 文件卡片网格 ========== */
|
||||||
.file-table-wrapper {
|
.card-container {
|
||||||
flex: 1;
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(185px, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-card {
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px 14px 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.25s;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border: 1px solid #ebeef5;
|
align-items: center;
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-table-wrapper .KLPTable {
|
.file-card:hover {
|
||||||
flex: 1;
|
border-color: #c0c4cc;
|
||||||
|
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
|
||||||
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 上传区域 */
|
.file-card.selected {
|
||||||
.upload-demo {
|
border-color: #409eff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.15), 0 4px 16px 0 rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片选中复选框 */
|
||||||
|
.card-checkbox {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 6px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 1px solid #d0d5dd;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #fff;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-card:hover .card-checkbox {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-card.selected .card-checkbox {
|
||||||
|
opacity: 1;
|
||||||
|
background: #409eff;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-checkbox .el-icon-check {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文件类型图标 */
|
||||||
|
.card-icon {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-ext {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 各文件类型颜色梯度 */
|
||||||
|
.icon-word {
|
||||||
|
background: linear-gradient(135deg, #4a90d9, #357abd);
|
||||||
|
}
|
||||||
|
.icon-excel {
|
||||||
|
background: linear-gradient(135deg, #52b86a, #3d9e55);
|
||||||
|
}
|
||||||
|
.icon-ppt {
|
||||||
|
background: linear-gradient(135deg, #f09b4a, #d9822e);
|
||||||
|
}
|
||||||
|
.icon-pdf {
|
||||||
|
background: linear-gradient(135deg, #e06060, #cc4444);
|
||||||
|
}
|
||||||
|
.icon-image {
|
||||||
|
background: linear-gradient(135deg, #a877d9, #8e5fc4);
|
||||||
|
}
|
||||||
|
.icon-archive {
|
||||||
|
background: linear-gradient(135deg, #8a9bb0, #6d7e93);
|
||||||
|
}
|
||||||
|
.icon-video {
|
||||||
|
background: linear-gradient(135deg, #4db8a8, #389e8e);
|
||||||
|
}
|
||||||
|
.icon-audio {
|
||||||
|
background: linear-gradient(135deg, #e8924a, #d47d35);
|
||||||
|
}
|
||||||
|
.icon-text {
|
||||||
|
background: linear-gradient(135deg, #90a4ae, #78909c);
|
||||||
|
}
|
||||||
|
.icon-other {
|
||||||
|
background: linear-gradient(135deg, #b0bec5, #90a4ae);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片内容 */
|
||||||
|
.card-body {
|
||||||
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 详情弹窗主体 */
|
.card-name {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-uploader {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #aaa;
|
||||||
|
margin-top: 2px;
|
||||||
|
line-height: 1.3;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #909399;
|
||||||
|
margin-top: 4px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-sep {
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片悬停操作按钮 */
|
||||||
|
.card-actions {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-card:hover .card-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-actions .el-button {
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 详情弹窗 ========== */
|
||||||
.info-dialog-body {
|
.info-dialog-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-main-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
@@ -908,14 +1079,13 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info-meta {
|
.info-meta {
|
||||||
width: 320px;
|
width: 340px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 详情弹窗评论区 */
|
/* 评论区 */
|
||||||
.info-comment {
|
.info-comment {
|
||||||
margin-top: 12px;
|
|
||||||
border: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
@@ -999,10 +1169,3 @@ export default {
|
|||||||
border-top: 1px solid #f2f2f2;
|
border-top: 1px solid #f2f2f2;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- 表格选中行高亮 -->
|
|
||||||
<style>
|
|
||||||
.file-main .el-table .current-row > td {
|
|
||||||
background-color: #ecf5ff !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user