feat: 新增搜索选项

This commit is contained in:
jmal 2025-04-10 14:32:26 +08:00
parent 69ca54add7
commit b129287d4f
2 changed files with 121 additions and 76 deletions

View File

@ -1,15 +1,10 @@
<template> <template>
<el-dialog <div
:visible.sync="dialogVisible" v-show="dialogVisible"
:show-close="false" :show-close="false"
custom-class="no-header-dialog" custom-class="no-header-dialog"
class="file-search-dialog"> class="file-search-dialog">
<!-- 关闭按钮 -->
<div class="dialog-close-btn">
<el-button type="text" icon="el-icon-close" @click="dialogVisible = false"></el-button>
</div>
<div class="search-bar"> <div class="search-bar">
<div class="search-input-wrapper"> <div class="search-input-wrapper">
<div class="search-filters"> <div class="search-filters">
@ -105,27 +100,37 @@
<!-- 搜索条件标签 --> <!-- 搜索条件标签 -->
<div class="search-tags" v-if="hasSearchConditions"> <div class="search-tags" v-if="hasSearchConditions">
<el-tag <div v-if="keyword !== ''">
v-if="fileTypeText !== '全部文件'" <el-tag
closable closable
@close="resetFileType"> @close="resetKeyword">
文件类型: {{ fileTypeText }} 关键字: {{ keyword }}
</el-tag> </el-tag>
<el-tag </div>
v-if="sizeRange[0] > 0 || sizeRange[1] < sliderConfig.max" <div v-if="fileTypeText !== '全部文件'">
closable <el-tag
@close="resetSizeRange"> closable
文件大小: {{ formatSizeRange }} @close="resetFileType">
</el-tag> 文件类型: {{ fileTypeText }}
<el-tag </el-tag>
v-if="timeRange" </div>
closable <div v-if="hasSizeRange">
@close="resetTimeRange"> <el-tag
时间范围: {{ formatTimeRange }} closable
</el-tag> @close="resetSizeRange">
文件大小: {{ formatSizeRange }}
</el-tag>
</div>
<div v-if="timeRange">
<el-tag
closable
@close="resetTimeRange">
时间范围: {{ formatTimeRange }}
</el-tag>
</div>
</div> </div>
</el-dialog> </div>
</template> </template>
<script> <script>
@ -136,13 +141,17 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
keyword: {
type: String,
default: ''
}
}, },
data() { data() {
return { return {
dialogVisible: false, dialogVisible: false,
fileType: 'all', fileType: 'all',
timeRange: null, timeRange: null,
sizeRange: [0, 1073741824], // 默认范围:0 到 1GB sizeRange: [0, -1], // 默认范围:0 到 1GB
fileTypeText: '全部文件', fileTypeText: '全部文件',
filterOption: { filterOption: {
type: null, type: null,
@ -155,8 +164,10 @@ export default {
}, },
computed: { computed: {
hasSearchConditions() { hasSearchConditions() {
return this.fileType !== 'all' || this.timeRange || return this.keyword || this.fileType !== 'all' || this.timeRange || this.hasSizeRange
(this.sizeRange[0] > 0 || this.sizeRange[1] < 1073741824) },
hasSizeRange () {
return this.sizeRange[0] >= 0 && this.sizeRange[1] > 0
}, },
formatTimeRange() { formatTimeRange() {
if (!this.timeRange) return '' if (!this.timeRange) return ''
@ -172,7 +183,7 @@ export default {
return { return {
min: 1073741824, min: 1073741824,
max: 10737418240, max: 10737418240,
step: 1073741824 / 100 // 约10MB的步长 step: 20971520 // 20MB
} }
} else { } else {
// 普通模式 (0 - 1GB) // 普通模式 (0 - 1GB)
@ -197,10 +208,10 @@ export default {
updateFilterOption() { updateFilterOption() {
this.filterOption = { this.filterOption = {
type: this.fileType === 'all' ? null : this.fileType, type: this.fileType === 'all' ? null : this.fileType,
modifyStart: this.timeRange ? this.timeRange[0] : null, modifyStart: this.timeRange ? new Date(this.timeRange[0]).getTime() : null,
modifyEnd: this.timeRange ? this.timeRange[1] : null, modifyEnd: this.timeRange ? new Date(this.timeRange[1]).getTime() : null,
sizeMin: this.sizeRange[0], sizeMin: this.hasSizeRange ? this.sizeRange[0] : null,
sizeMax: this.sizeRange[1] sizeMax: this.hasSizeRange ? this.sizeRange[1] : null
} }
this.$emit('filter-change', this.filterOption) this.$emit('filter-change', this.filterOption)
@ -246,6 +257,12 @@ export default {
this.updateFilterOption() this.updateFilterOption()
}, },
resetKeyword() {
this.$emit('update:keyword', '')
this.$emit('update:visible', false)
this.updateFilterOption()
},
resetFileType() { resetFileType() {
this.handleFileType('all') this.handleFileType('all')
}, },
@ -256,7 +273,7 @@ export default {
}, },
resetSizeRange() { resetSizeRange() {
this.sizeRange = [0, 1073741824] this.sizeRange = [-1, -1]
this.updateFilterOption() this.updateFilterOption()
}, },
@ -265,13 +282,10 @@ export default {
}, },
formatFileSize(size) { formatFileSize(size) {
const units = ['B', 'KB', 'MB', 'GB', 'TB'] const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let index = 0 if (size === 0) return '0 B';
while (size >= 1024 && index < units.length - 1) { const i = Math.floor(Math.log(size) / Math.log(1024));
size /= 1024 return `${(size / Math.pow(1024, i)).toFixed(2)} ${units[i]}`;
index++
}
return `${size.toFixed(2)} ${units[index]}`
}, },
setTimePreset(preset) { setTimePreset(preset) {
@ -324,6 +338,17 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.file-search-dialog { .file-search-dialog {
display: flex;
justify-content: center;
gap: 16px;
.search-bar {
display: flex;
align-content: center;
align-items: center;
}
>>> .el-dialog { >>> .el-dialog {
margin-top: 6vh !important; margin-top: 6vh !important;
border-radius: 12px; border-radius: 12px;
@ -341,35 +366,10 @@ export default {
padding: 20px 24px; padding: 20px 24px;
} }
.dialog-close-btn {
position: absolute;
right: -44px;
top: 0;
z-index: 100;
.el-button {
color: #fff;
font-size: 20px;
padding: 10px;
border-radius: 50%;
transition: all 0.3s ease;
&:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.2);
transform: scale(1.1);
}
}
}
.search-input-wrapper {
display: flex;
justify-content: center;
}
.search-filters { .search-filters {
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: column;
gap: 8px; gap: 8px;
.el-divider--vertical { .el-divider--vertical {
@ -440,10 +440,11 @@ export default {
} }
.search-tags { .search-tags {
margin: 16px 0;
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-direction: column;
gap: 8px; gap: 8px;
min-width: 250px;
>>> .el-tag { >>> .el-tag {
border-radius: 6px; border-radius: 6px;

View File

@ -161,7 +161,6 @@
ref="searchInput" ref="searchInput"
placeholder="搜索" placeholder="搜索"
v-model="searchFileName" v-model="searchFileName"
@keyup.enter.native="searchFileEnter(searchFileName)" @keyup.enter.native="searchFileEnter(searchFileName)"
@focus="setInputFocus" @focus="setInputFocus"
@input="searchFileEnter(searchFileName)" @input="searchFileEnter(searchFileName)"
@ -169,9 +168,16 @@
@clear="searchFileEnter(searchFileName)" @clear="searchFileEnter(searchFileName)"
> >
<template v-slot:suffix> <template v-slot:suffix>
<el-button type="text" class="search-option" @click="searchDialogVisible = true"> <el-popover
<i class="el-icon-s-operation"></i> v-if="searchFileName"
</el-button> placement="bottom-end"
popper-class="search-filter-popover"
trigger="click">
<search-dialog :visible.sync="searchDialogVisible" :keyword.sync="searchFileName" @filter-change="searchFilterChange"></search-dialog>
<el-button slot="reference" type="text" :class="searchOptionBtnClass" @click="searchDialogVisible = true">
<i class="el-icon-s-operation"></i>
</el-button>
</el-popover>
</template> </template>
</el-input> </el-input>
<el-dropdown <el-dropdown
@ -821,8 +827,6 @@
</el-dialog> </el-dialog>
<file-clipboard ref="fileClipboard" v-if="showClipboard && fileClipboard.length > 0" :file-list="fileClipboard" :image-url="imageUrl" :audio-cover-url="audioCoverUrl" :target-path="path" :target-folder="currentFolder" @onCopy="onCopy" @onMove="onMove"></file-clipboard> <file-clipboard ref="fileClipboard" v-if="showClipboard && fileClipboard.length > 0" :file-list="fileClipboard" :image-url="imageUrl" :audio-cover-url="audioCoverUrl" :target-path="path" :target-folder="currentFolder" @onCopy="onCopy" @onMove="onMove"></file-clipboard>
<search-dialog :visible.sync="searchDialogVisible"></search-dialog>
</div> </div>
</template> </template>
@ -1157,6 +1161,8 @@ export default {
debounceSearch: null,// 搜索防抖 debounceSearch: null,// 搜索防抖
debounceGetFileList: null,// 获取文件列表防抖 debounceGetFileList: null,// 获取文件列表防抖
searchDialogVisible: false, searchDialogVisible: false,
filterOption: {}, // 搜索选项
hasSearchFilterOption: false, // 是否有搜索选项
fileUsername: '', // 一般用于挂载文件 fileUsername: '', // 一般用于挂载文件
} }
}, },
@ -1177,6 +1183,13 @@ export default {
return '名称' return '名称'
} }
}, },
searchOptionBtnClass() {
if (this.hasSearchFilterOption) {
return 'search-option-btn search-option-btn-active'
} else {
return 'search-option-btn'
}
},
cmdKey() { cmdKey() {
return navigator.platform.startsWith('Mac') ? '⌘' : 'Ctrl' return navigator.platform.startsWith('Mac') ? '⌘' : 'Ctrl'
}, },
@ -2920,10 +2933,15 @@ export default {
tagId: this.$route.query.tagId, tagId: this.$route.query.tagId,
isFolder: this.queryCondition.isFolder, isFolder: this.queryCondition.isFolder,
isFavorite: this.queryCondition.isFavorite, isFavorite: this.queryCondition.isFavorite,
queryFileType: this.queryFileType, queryFileType: this.filterOption.type || this.queryFileType,
pageIndex: this.pagination.pageIndex, pageIndex: this.pagination.pageIndex,
pageSize: this.pagination.pageSize, pageSize: this.pagination.pageSize,
showFolderSize: localStorage.getItem('showFolderSize'), showFolderSize: localStorage.getItem('showFolderSize'),
type: this.filterOption.type,
queryModifyStart: this.filterOption.modifyStart,
queryModifyEnd: this.filterOption.modifyEnd,
querySizeMin: this.filterOption.sizeMin,
querySizeMax: this.filterOption.sizeMax,
}).then(res => { }).then(res => {
this.loadData(res, onLoad) this.loadData(res, onLoad)
this.listModeSearch = true this.listModeSearch = true
@ -4457,6 +4475,22 @@ export default {
this.fileHandler = {} this.fileHandler = {}
this.specifyPreviewer = 'office' this.specifyPreviewer = 'office'
}, },
searchFilterChange(filterOption) {
this.filterOption = filterOption
let hasSearchFilterOption = false
if (filterOption.type !== 'all' && filterOption.type !== null) {
hasSearchFilterOption = true
}
if (filterOption.modifyStart !== null && filterOption.modifyEnd !== null) {
hasSearchFilterOption = true
}
if (filterOption.sizeMin !== null && filterOption.sizeMax !== null) {
hasSearchFilterOption = true
}
this.hasSearchFilterOption = hasSearchFilterOption
this.debounceSearch(this.searchFileName, false)
},
checkPreviewVisible() { checkPreviewVisible() {
if (this.searchDialogVisible) { if (this.searchDialogVisible) {
return true return true
@ -4723,4 +4757,14 @@ export default {
margin-top: 5px; margin-top: 5px;
} }
.search-option-btn {
padding: 8px;
}
.search-option-btn-active {
padding: 8px;
background: #409EFF;
color: #fff;
}
</style> </style>