support search file
This commit is contained in:
		
							parent
							
								
									1da8fbd02a
								
							
						
					
					
						commit
						5f116222fd
					
				| @ -24,6 +24,7 @@ StackEdit中文版的docker镜像地址:[mafgwo/stackedit](https://hub.docker. | ||||
| - 支持GitHub图床粘贴/拖拽图片自动上传(2022-07-31) | ||||
| - 支持了右上角一键切换主题,补全了深色主题的样式(2022-08-07) | ||||
| - 编辑与预览区域样式优化(2022-08-10) | ||||
| - 左边栏文件资源管理支持搜索文件(2022-08-17) | ||||
| 
 | ||||
| ## 国外开源版本弊端: | ||||
| - 作者已经不维护了 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <template> | ||||
|   <div class="explorer flex flex--column"> | ||||
|     <div class="side-title flex flex--row flex--space-between"> | ||||
|       <div class="flex flex--row"> | ||||
|       <div class="flex flex--row" v-if="!showSearch"> | ||||
|         <button class="side-title__button side-title__button--new-file button" @click="newItem()" v-title="'创建文件'"> | ||||
|           <icon-file-plus></icon-file-plus> | ||||
|         </button> | ||||
| @ -14,14 +14,36 @@ | ||||
|         <button class="side-title__button side-title__button--rename button" @click="editItem()" v-title="'重命名'"> | ||||
|           <icon-pen></icon-pen> | ||||
|         </button> | ||||
|         <button class="side-title__button side-title__button--search button" @click="toSearch()" v-title="'搜索文件'"> | ||||
|           <icon-search></icon-search> | ||||
|         </button> | ||||
|       </div> | ||||
|       <div class="flex flex--row" v-else> | ||||
|         <button class="side-title__button button" @click="back()" v-title="'返回资源管理器'"> | ||||
|           <icon-dots-horizontal></icon-dots-horizontal> | ||||
|         </button> | ||||
|         <div class="side-title__title"> | ||||
|           搜索文件 | ||||
|         </div> | ||||
|       </div> | ||||
|       <button class="side-title__button side-title__button--close button" @click="toggleExplorer(false)" v-title="'关闭资源管理器'"> | ||||
|         <icon-close></icon-close> | ||||
|       </button> | ||||
|     </div> | ||||
|     <div class="explorer__tree" :class="{'explorer__tree--new-item': !newChildNode.isNil}" v-if="!light" tabindex="0" @keydown.delete="deleteItem()"> | ||||
|     <div class="explorer__tree" :class="{'explorer__tree--new-item': !newChildNode.isNil}" v-if="!light" v-show="!showSearch" tabindex="0" @keydown.delete="deleteItem()"> | ||||
|       <explorer-node :node="rootNode" :depth="0"></explorer-node> | ||||
|     </div> | ||||
|     <div class="explorer__search" tabindex="0" v-if="!light && showSearch"> | ||||
|       <input type="text" v-model="searchText" class="text-input" placeholder="请输入关键字回车" @keyup.enter="search"></input> | ||||
|       <div class="explorer__search-list"> | ||||
|         <div class="search-tips" v-if="searching">正在查询中...</div> | ||||
|         <a class="menu-entry button flex flex--row flex--align-center" :class="{'search-node--selected': currentFileId === fileItem.id}" | ||||
|             v-for="fileItem in searchItems" :key="fileItem.id" @click="clickSearch(fileItem)" href="javascript:void(0)"> | ||||
|           {{ fileItem.name }} | ||||
|         </a> | ||||
|         <div class="search-tips">最多返回匹配的50个文档</div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| @ -30,11 +52,21 @@ import { mapState, mapGetters, mapActions } from 'vuex'; | ||||
| import ExplorerNode from './ExplorerNode'; | ||||
| import explorerSvc from '../services/explorerSvc'; | ||||
| import store from '../store'; | ||||
| import MenuEntry from './menus/common/MenuEntry'; | ||||
| import localDbSvc from '../services/localDbSvc'; | ||||
| 
 | ||||
| export default { | ||||
|   components: { | ||||
|     ExplorerNode, | ||||
|     MenuEntry, | ||||
|   }, | ||||
|   data: () => ({ | ||||
|     currentFileId: '', | ||||
|     showSearch: false, | ||||
|     searching: false, | ||||
|     searchText: '', | ||||
|     searchItems: [], | ||||
|   }), | ||||
|   computed: { | ||||
|     ...mapState([ | ||||
|       'light', | ||||
| @ -46,6 +78,7 @@ export default { | ||||
|       'rootNode', | ||||
|       'selectedNode', | ||||
|     ]), | ||||
|     workspaceId: () => store.getters['workspace/currentWorkspace'].id, | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('data', [ | ||||
| @ -59,11 +92,62 @@ export default { | ||||
|         store.commit('explorer/setEditingId', node.item.id); | ||||
|       } | ||||
|     }, | ||||
|     back() { | ||||
|       this.showSearch = false; | ||||
|     }, | ||||
|     toSearch() { | ||||
|       this.showSearch = true; | ||||
|     }, | ||||
|     search() { | ||||
|       this.searchItems = []; | ||||
|       if (!this.searchText) { | ||||
|         return; | ||||
|       } | ||||
|       this.searching = true; | ||||
|       const allFileById = {}; | ||||
|       const filterIds = []; | ||||
|       localDbSvc.getWorkspaceItems(this.workspaceId, (item) => { | ||||
|         if (item.type !== 'file' && item.type !== 'content') { | ||||
|           return; | ||||
|         } | ||||
|         if (item.type === 'file') { | ||||
|           allFileById[item.id] = item; | ||||
|         } | ||||
|         if (filterIds.length >= 50) { | ||||
|           return; | ||||
|         } | ||||
|         const fileId = item.id.split('/')[0]; | ||||
|         // 包含了直接跳过 | ||||
|         if (filterIds.indexOf(fileId) > -1) { | ||||
|           return; | ||||
|         } | ||||
|         if (item.name && item.name.indexOf(this.searchText) > -1) { | ||||
|           filterIds.push(fileId); | ||||
|         } | ||||
|         if (item.text && item.text.indexOf(this.searchText) > -1) { | ||||
|           filterIds.push(fileId); | ||||
|         } | ||||
|       }, () => { | ||||
|         filterIds.forEach((it) => { | ||||
|           const file = allFileById[it]; | ||||
|           if (file) { | ||||
|             this.searchItems.push(file); | ||||
|           } | ||||
|         }); | ||||
|         this.searching = false; | ||||
|       }); | ||||
|     }, | ||||
|     clickSearch(item) { | ||||
|       store.commit('explorer/setSelectedId', item.id); | ||||
|       store.commit('file/setCurrentId', item.id); | ||||
|       this.showSearch = false; | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.$watch( | ||||
|       () => store.getters['file/current'].id, | ||||
|       (currentFileId) => { | ||||
|         this.currentFileId = currentFileId; | ||||
|         store.commit('explorer/setSelectedId', currentFileId); | ||||
|         store.dispatch('explorer/openNode', currentFileId); | ||||
|       }, { | ||||
| @ -75,6 +159,8 @@ export default { | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss"> | ||||
| @import '../styles/variables.scss'; | ||||
| 
 | ||||
| .explorer, | ||||
| .explorer__tree { | ||||
|   height: 100%; | ||||
| @ -89,4 +175,38 @@ export default { | ||||
|     cursor: auto; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .explorer__search { | ||||
|   overflow: auto; | ||||
| 
 | ||||
|   .explorer__search-list { | ||||
|     margin-top: 10px; | ||||
|   } | ||||
| 
 | ||||
|   .menu-entry { | ||||
|     font-size: 14px; | ||||
|     padding: 5px; | ||||
|   } | ||||
| 
 | ||||
|   .menu-entry__icon { | ||||
|     width: 0; | ||||
|     margin-left: 0; | ||||
|     border-bottom: 1px solid $hr-color; | ||||
|   } | ||||
| 
 | ||||
|   .search-tips { | ||||
|     font-size: 10px; | ||||
|     background-color: rgba(255, 173, 51, 0.14902); | ||||
|     padding: 5px; | ||||
|     text-align: center; | ||||
|   } | ||||
| 
 | ||||
|   .search-node--selected { | ||||
|     background-color: rgba(0, 0, 0, 0.2); | ||||
| 
 | ||||
|     .app--dark & { | ||||
|       background-color: rgba(0, 0, 0, 0.4); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -215,6 +215,10 @@ $item-font-size: 14px; | ||||
|   .explorer-node--selected > & { | ||||
|     background-color: rgba(0, 0, 0, 0.2); | ||||
| 
 | ||||
|     .app--dark & { | ||||
|       background-color: rgba(0, 0, 0, 0.4); | ||||
|     } | ||||
| 
 | ||||
|     .explorer__tree:focus & { | ||||
|       background-color: #39f; | ||||
|       color: #fff; | ||||
|  | ||||
							
								
								
									
										3
									
								
								src/icons/Search.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/icons/Search.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| <template> | ||||
|   <svg t="1660710445280" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2419" width="32" height="32"><path d="M576 672a192 192 0 0 1 192-192 182.72 182.72 0 0 1 48 6.4v-106.56a48 48 0 0 0-13.12-32L565.76 96a48 48 0 0 0-34.88-15.04H128A48 48 0 0 0 80 128v768A48 48 0 0 0 128 944h640a48 48 0 0 0 48-48v-38.4a184.64 184.64 0 0 1-48 6.4 192 192 0 0 1-192-192z m-64-326.72V112l272 272h-233.28A38.72 38.72 0 0 1 512 345.28z" p-id="2420"></path><path d="M957.76 774.4l-71.36-53.76A128 128 0 1 0 768 800a125.76 125.76 0 0 0 79.36-28.48l72 54.08zM768 736a64 64 0 1 1 64-64 64 64 0 0 1-64 64z" p-id="2421"></path></svg> | ||||
| </template> | ||||
| @ -56,6 +56,7 @@ import Key from './Key'; | ||||
| import DotsHorizontal from './DotsHorizontal'; | ||||
| import Seal from './Seal'; | ||||
| import SwitchTheme from './SwitchTheme'; | ||||
| import Search from './Search'; | ||||
| 
 | ||||
| Vue.component('iconProvider', Provider); | ||||
| Vue.component('iconFormatBold', FormatBold); | ||||
| @ -114,3 +115,4 @@ Vue.component('iconKey', Key); | ||||
| Vue.component('iconDotsHorizontal', DotsHorizontal); | ||||
| Vue.component('iconSeal', Seal); | ||||
| Vue.component('iconSwitchTheme', SwitchTheme); | ||||
| Vue.component('iconSearch', Search); | ||||
|  | ||||
| @ -87,7 +87,7 @@ textarea { | ||||
|   font-size: inherit; | ||||
|   line-height: 1.5; | ||||
|   color: inherit; | ||||
|   background-color: #fff; | ||||
|   background-color: rgba(255, 255, 255, 0.8); | ||||
|   background-image: none; | ||||
|   border: 0; | ||||
|   border-radius: $border-radius-base; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 xiaoqi.cxq
						xiaoqi.cxq