1
1
<script setup lang="ts">
2
2
import { useReqStore } from ' @/stores/req.ts'
3
- import { reactive , ref , h } from ' vue'
3
+ import { reactive , ref , h , computed } from ' vue'
4
4
import { useRoute , useRouter } from ' vue-router'
5
5
import type { DropdownOption } from ' naive-ui'
6
- import { Folder , FolderOpenOutline , Trash } from ' @vicons/ionicons5'
6
+ import { Folder , FolderOpenOutline , KeyOutline , Trash } from ' @vicons/ionicons5'
7
7
import { NIcon } from ' naive-ui'
8
8
import { useResize } from ' @/hooks/life.ts'
9
- import { ID , parseTreeWithNameSpace } from ' @/tools/keys.ts'
9
+ import { ID } from ' @/tools/keys.ts'
10
10
import type { Tree } from ' @/types.ts'
11
+ import KeysWorker from ' @/worker/keys.ts?worker'
11
12
13
+ const keysWorker = new KeysWorker ()
12
14
const router = useRouter ()
13
15
const reqStore = useReqStore ()
14
16
const route = useRoute ()
@@ -39,40 +41,105 @@ const original = reactive<{
39
41
// todo: enable name space by configure.
40
42
const nameSpaceEnable = ref (true )
41
43
// here we do some no search patten logic.
42
- const queryOriginalData = async () => {
43
- original .loading = true
44
+ const queryData = async (isSearch ? : boolean ) => {
45
+ if (isSearch ) search .loading = true
46
+ else original .loading = true
44
47
try {
45
48
// fetch data pass through rust side.
46
49
const resp = await reqStore .reqWithHost <string >({
47
50
path: ' /cmd' ,
48
- data: JSON .stringify ([' scan' , original .cursor , ' MATCH' , ' *' , ' COUNT' , ' 5000' ]),
51
+ data: JSON .stringify ([
52
+ ' scan' ,
53
+ isSearch ? search .cursor : original .cursor ,
54
+ ' MATCH' ,
55
+ isSearch ? search .match : ' *' ,
56
+ ' COUNT' ,
57
+ ' 5000' ,
58
+ ]),
49
59
})
50
60
// parse data
51
61
const v = resp .data .split (' \n ' )
62
+ if (isSearch ) {
63
+ let arr = []
52
64
53
- if (original .cursor === ' 0' ) {
54
- originalKeyList = v
55
- .splice (1 )
56
- .map ((e ) => ({ type: ' key' , label: e , icon: ' key' , id: ID () }) as Tree )
65
+ if (search .cursor === ' 0' ) {
66
+ arr = v .splice (1 ).map ((e ) => ({ type: ' key' , label: e , icon: ' key' , id: ID () }) as Tree )
67
+ } else {
68
+ arr = search .tree .concat (
69
+ v .splice (1 ).map (
70
+ (e ) =>
71
+ ({
72
+ type: ' key' ,
73
+ label: e ,
74
+ icon: ' key' ,
75
+ id: ID (),
76
+ }) as Tree ,
77
+ ),
78
+ )
79
+ }
80
+ search .cursor = v [0 ]
81
+ // const data = [] as Tree[]
82
+ // arr.forEach((e) => {
83
+ // parseTreeWithNameSpace(data, e.label)
84
+ // })
85
+ // search.tree = data
86
+ keysWorker .postMessage ({
87
+ type: ' parse' ,
88
+ data: arr ,
89
+ })
90
+ search .tree = await new Promise ((resolve ) => {
91
+ keysWorker .onmessage = (e ) => {
92
+ resolve (e .data )
93
+ }
94
+ })
57
95
} else {
58
- v .splice (1 ).forEach ((e ) => {
59
- originalKeyList .push ({ type: ' key' , label: e , icon: ' key' , id: ID () })
96
+ // no search match
97
+ if (original .cursor === ' 0' ) {
98
+ originalKeyList = v
99
+ .splice (1 )
100
+ .map ((e ) => ({ type: ' key' , label: e , icon: ' key' , id: ID () }) as Tree )
101
+ } else {
102
+ v .splice (1 ).forEach ((e ) => {
103
+ originalKeyList .push ({ type: ' key' , label: e , icon: ' key' , id: ID () })
104
+ })
105
+ }
106
+ original .cursor = v [0 ]
107
+ // const arr = [] as Tree[]
108
+ // originalKeyList.forEach((e) => {
109
+ // parseTreeWithNameSpace(arr, e.label)
110
+ // })
111
+ // original.tree = arr
112
+ keysWorker .postMessage ({
113
+ type: ' parse' ,
114
+ data: originalKeyList ,
115
+ })
116
+ original .tree = await new Promise ((resolve ) => {
117
+ keysWorker .onmessage = (e ) => {
118
+ resolve (e .data )
119
+ }
60
120
})
61
- console .log (originalKeyList .length )
62
121
}
63
- original .cursor = v [0 ]
64
- const arr = [] as Tree []
65
- originalKeyList .forEach ((e ) => {
66
- parseTreeWithNameSpace (arr , e .label )
67
- })
68
- original .tree = arr
69
- } catch (e ) {}
122
+ } catch (e ) {
123
+ console .error (e )
124
+ }
70
125
original .loading = false
126
+ search .loading = false
71
127
}
72
- queryOriginalData ()
73
-
74
- const { height } = useResize (120 )
128
+ queryData ()
75
129
130
+ const { height } = useResize (115 )
131
+ const calcHeight = computed (() => {
132
+ if (search .match !== ' ' ) {
133
+ if (search .cursor === ' 0' ) {
134
+ return height .value + 30 + ' px'
135
+ }
136
+ return height .value + ' px'
137
+ }
138
+ if (original .cursor === ' 0' ) {
139
+ return height .value + 30 + ' px'
140
+ }
141
+ return height .value + ' px'
142
+ })
76
143
const updatePrefixWithExpand = (
77
144
_keys : Array <string | number >,
78
145
_option : Array <Tree | null >,
@@ -81,6 +148,7 @@ const updatePrefixWithExpand = (
81
148
action: ' expand' | ' collapse' | ' filter'
82
149
},
83
150
) => {
151
+ console .log (' updatePrefixWithExpand' , _keys , _option , meta )
84
152
if (! meta .node ) return
85
153
switch (meta .action ) {
86
154
case ' expand' :
@@ -100,8 +168,9 @@ const updatePrefixWithExpand = (
100
168
101
169
const loadMoreFn = () => {
102
170
if (search .match !== ' ' ) {
171
+ queryData (true )
103
172
} else {
104
- queryOriginalData ()
173
+ queryData ()
105
174
}
106
175
}
107
176
@@ -154,6 +223,7 @@ const nodeProps = ({ option }: { option: Tree }) => {
154
223
},
155
224
}
156
225
}
226
+ // contextmenu selected function.
157
227
const handleSelect = async (act : string ) => {
158
228
showDropdownRef .value = false
159
229
const data = focusNodeData
@@ -164,7 +234,7 @@ const handleSelect = async (act: string) => {
164
234
data: [' del' , data .value ],
165
235
})
166
236
if (code === 0 ) {
167
- await queryOriginalData ( )
237
+ await queryData ( search . match !== " " )
168
238
}
169
239
return
170
240
}
@@ -180,16 +250,33 @@ const handleSelect = async (act: string) => {
180
250
}
181
251
}
182
252
findKeys (data ?.children || [])
183
- // todo: need implement batch delete at 'rust' end. this implementation so ugly.
253
+ // todo: need implement batch delete at 'rust' end. this implementation is so ugly.
184
254
for (const key of keys ) {
185
255
await reqStore .reqWithHost <string >({
186
256
path: ' /cmd' ,
187
257
data: [' del' , key ],
188
258
})
189
259
}
190
- await queryOriginalData ( )
260
+ await queryData ( search . match !== " " )
191
261
}
192
262
}
263
+ // throttle
264
+ let timer = - 1 as any
265
+ const doFilter = async () => {
266
+ console .log (search )
267
+ search .cursor = ' 0'
268
+ clearTimeout (timer )
269
+ if (search .match === ' ' ) return
270
+ timer = setTimeout (async () => {
271
+ await queryData (true )
272
+ }, 100 )
273
+ }
274
+
275
+ function renderPrefix(data : { option: Tree }) {
276
+ return h (NIcon , null , {
277
+ default : () => h (data .option .type === ' key' ? KeyOutline : Folder ),
278
+ })
279
+ }
193
280
</script >
194
281
<template >
195
282
<div ref =" treeBoxRef" class =" w-full flex flex-col flex-1 justify-start items-start" >
@@ -199,6 +286,7 @@ const handleSelect = async (act: string) => {
199
286
class =" flex-1"
200
287
size =" tiny"
201
288
v-model:value =" search.match"
289
+ @update:value =" doFilter"
202
290
placeholder =" redis query format"
203
291
>
204
292
<template #prefix >
@@ -213,17 +301,31 @@ const handleSelect = async (act: string) => {
213
301
ref =" treeInstRef"
214
302
block-line
215
303
show-line
304
+ :render-prefix =" renderPrefix"
216
305
:on-update:expanded-keys =" updatePrefixWithExpand"
217
- :data =" original.tree"
306
+ :data =" search.match != '' ? search.tree : original.tree"
218
307
virtual-scroll
219
308
expand-on-click
220
309
:node-props =" nodeProps"
221
- :style =" { height: height + 'px' }"
310
+ :style =" { height: calcHeight }"
222
311
key-field =" id"
223
312
children-field =" children"
224
313
class =" whitespace-nowrap"
225
314
/>
226
- <div class =" flex flex-1 w-full justify-center items-center" v-show =" original.cursor != '0'" >
315
+ <div
316
+ class =" flex flex-1 w-full justify-center items-center"
317
+ v-if =" !search.match"
318
+ v-show =" original.cursor != '0'"
319
+ >
320
+ <n-button size =" small" type =" primary" :loading =" reqStore.reqLoading" @click =" loadMoreFn"
321
+ >加载更多
322
+ </n-button >
323
+ </div >
324
+ <div
325
+ v-else
326
+ class =" flex flex-1 w-full justify-center items-center"
327
+ v-show =" search.cursor != '0'"
328
+ >
227
329
<n-button size =" small" type =" primary" :loading =" reqStore.reqLoading" @click =" loadMoreFn"
228
330
>加载更多
229
331
</n-button >
0 commit comments