From ff69990daa4f3c6fcb30bdbb762468e9481a34c6 Mon Sep 17 00:00:00 2001 From: zthxxx Date: Fri, 8 Sep 2023 01:32:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E7=95=AA=E5=89=A7=E8=BE=93=E5=85=A5=E6=A1=86=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E5=90=8E=E4=B8=AD=E6=96=AD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 报错信息改为 console 中展示,不打断 observer - input 输入框改为 v-model 绑定,解决 IME 输入法输入时打断问题 待优化: - 后端解析时报错信息应该和重新约定接口格式,将解析数据或报错信息都能返回到前端解析和提示 - 搜索项数据没限制,条数太多等时间太长没有意义 - 列表项的 UI 待优化,比如展示样式和点击添加/关闭啥的 --- webui/src/api/search.ts | 51 +++--------------------- webui/src/components/basic/ab-search.vue | 4 +- webui/src/store/search.ts | 19 ++++----- 3 files changed, 14 insertions(+), 60 deletions(-) diff --git a/webui/src/api/search.ts b/webui/src/api/search.ts index 41e7866b..9837c222 100644 --- a/webui/src/api/search.ts +++ b/webui/src/api/search.ts @@ -7,50 +7,7 @@ import type { BangumiRule } from '#/bangumi'; export const apiSearch = { /** * 番剧搜索接口是 Server Send 流式数据,每条是一个 Bangumi JSON 字符串, - * 使用接口方式需要订阅使用 - * - * Usage Example: - * - * ```ts - * import { - * Subject, - * tap, - * map, - * switchMap, - * debounceTime, - * } from 'rxjs'; - * - * - * const input$ = new Subject(); - * const onInput = (e: Event) => input$.next(e.target); - * - * // vue: - * - * const bangumiInfo$ = apiSearch.get('魔女之旅'); - * - * // vue: start loading animation - * - * input$.pipe( - * debounceTime(1000), - * tap((input: string) => { - * console.log('input', input) - * // clear Search Result List - * }), - * - * // switchMap 把输入 keyword 查询为 bangumiInfo$ 流,多次输入停用前一次查询 - * switchMap((input: string) => apiSearch(input, site)), - * - * tap((bangumi: BangumiRule) => console.log(bangumi)), - * tap((bangumi: BangumiRule) => { - * console.log('bangumi', bangumi) - * // set bangumi info to Search Result List - * }), - * ).subscribe({ - * complete() { - * // end of stream, stop loading animation - * }, - * }) - * ``` + * 使用接口方式是监听连接消息后,转为 Observable 配合外层调用时 switchMap 订阅使用 */ get(keyword: string, site = 'mikan'): Observable { const bangumiInfo$ = new Observable(observer => { @@ -64,11 +21,13 @@ export const apiSearch = { const data: BangumiRule = JSON.parse(ev.data); observer.next(data); } catch (error) { - observer.error(error); + console.error('[/search/bangumi] Parse Error |', { keyword }, 'response:', ev.data) } }; - eventSource.onerror = ev => observer.error(ev); + eventSource.onerror = ev => { + console.error('[/search/bangumi] Server Error |', { keyword }, 'error:', ev) + }; return () => { eventSource.close(); diff --git a/webui/src/components/basic/ab-search.vue b/webui/src/components/basic/ab-search.vue index bf5dd858..9b4a073a 100644 --- a/webui/src/components/basic/ab-search.vue +++ b/webui/src/components/basic/ab-search.vue @@ -3,7 +3,6 @@ import {Down, Search} from '@icon-park/vue-next'; const { onSelect, - onInput, onSearch, inputValue, selectingProvider, @@ -43,12 +42,11 @@ onMounted(() => { />
(); + watch(inputValue, input => { + input$.next(input); + }) + const {execute: getProviders, onResult: onGetProvidersResult} = useApi( apiSearch.getProvider ); @@ -33,27 +37,21 @@ export function useSearchStore() { * - 切换 provider 源站时触发搜索 */ - - const bangumiInfo$ = input$.pipe( debounceTime(600), tap(() => { + // 有输入更新后清理之前的搜索结果 bangumiList.value = []; }), filter(Boolean), - switchMap((input: string) => apiSearch.get(input, provider.value).pipe(takeUntil(input$))), + // switchMap 把输入 keyword 查询为 bangumiInfo$ 流,多次输入自动取消并停止前一次查询 + switchMap((input: string) => apiSearch.get(input, provider.value)), tap((bangumi: BangumiRule) => { bangumiList.value.push(bangumi); }), ) .subscribe() - function onInput(e: Event) { - const value = (e.target as HTMLInputElement).value; - input$.next(value); - inputValue.value = value; - } - function onSearch() { input$.next(inputValue.value); } @@ -70,7 +68,6 @@ export function useSearchStore() { inputValue, selectingProvider, onSelect, - onInput, onSearch, provider, getProviders,