diff --git a/webui/package.json b/webui/package.json index dcb02e53..195595e0 100644 --- a/webui/package.json +++ b/webui/package.json @@ -26,7 +26,6 @@ "axios": "^0.27.2", "naive-ui": "^2.39.0", "pinia": "^2.2.2", - "rxjs": "^7.8.1", "vue": "^3.5.8", "vue-i18n": "^9.14.0", "vue-inline-svg": "^3.1.4", diff --git a/webui/pnpm-lock.yaml b/webui/pnpm-lock.yaml index 5045441d..1f3afd48 100644 --- a/webui/pnpm-lock.yaml +++ b/webui/pnpm-lock.yaml @@ -26,9 +26,6 @@ importers: pinia: specifier: ^2.2.2 version: 2.2.2(typescript@4.9.5)(vue@3.5.8(typescript@4.9.5)) - rxjs: - specifier: ^7.8.1 - version: 7.8.1 vue: specifier: ^3.5.8 version: 3.5.8(typescript@4.9.5) diff --git a/webui/src/api/search.ts b/webui/src/api/search.ts index 0be88f79..a1c518e7 100644 --- a/webui/src/api/search.ts +++ b/webui/src/api/search.ts @@ -1,57 +1,60 @@ -import { Observable } from 'rxjs'; +import type { Ref } from 'vue'; +import type { BangumiRule } from '#/bangumi'; -import type { BangumiAPI, BangumiRule } from '#/bangumi'; +type EventSourceStatus = 'OPEN' | 'CONNECTING' | 'CLOSED'; export const apiSearch = { - /** - * 番剧搜索接口是 Server Send 流式数据,每条是一个 Bangumi JSON 字符串, - * 使用接口方式是监听连接消息后,转为 Observable 配合外层调用时 switchMap 订阅使用 - */ - get(keyword: string, site = 'mikan'): Observable { - const bangumiInfo$ = new Observable((observer) => { - const eventSource = new EventSource( - `api/v1/search/bangumi?site=${site}&keywords=${encodeURIComponent( - keyword - )}`, - { withCredentials: true } - ); + get() { + const eventSource = ref(null) as Ref; + const status = ref('CLOSED'); + const data = ref([]); - eventSource.onmessage = (ev) => { - try { - const apiData: BangumiAPI = JSON.parse(ev.data); - const data: BangumiRule = { - ...apiData, - filter: apiData.filter.split(','), - rss_link: apiData.rss_link.split(','), - }; - observer.next(data); - } catch (error) { - console.error( - '[/search/bangumi] Parse Error |', - { keyword }, - 'response:', - ev.data - ); - } + const keyword = ref(''); + const provider = ref(''); + + const close = () => { + if (eventSource.value) { + eventSource.value.close(); + eventSource.value = null; + status.value = 'CLOSED'; + } + }; + + const _init = () => { + status.value = 'CONNECTING'; + + const url = `api/v1/search/bangumi?site=${ + provider.value + }&keywords=${encodeURIComponent(keyword.value)}`; + + const es = new EventSource(url, { withCredentials: true }); + eventSource.value = es; + es.onopen = () => { + status.value = 'OPEN'; }; - - eventSource.onerror = (ev) => { - console.error( - '[/search/bangumi] Server Error |', - { keyword }, - 'error:', - ev - ); - // 目前后端搜索完成关闭连接时会触发 error 事件,前端手动调用 close 不再自动重连 - eventSource.close(); + es.onmessage = (e) => { + const newData = JSON.parse(e.data) as BangumiRule; + data.value = [...data.value, newData]; }; - - return () => { - eventSource.close(); + es.onerror = (err) => { + console.error('EventSource error:', err); + close(); }; - }); + }; - return bangumiInfo$; + const open = () => { + data.value = []; + _init(); + }; + + return { + keyword, + provider, + status, + data, + open, + close, + }; }, async getProvider() { diff --git a/webui/src/components/ab-search-bar.vue b/webui/src/components/ab-search-bar.vue index 7f36e5d6..3c4dd1b1 100644 --- a/webui/src/components/ab-search-bar.vue +++ b/webui/src/components/ab-search-bar.vue @@ -13,10 +13,10 @@ defineEmits<{ (e: 'add-bangumi', bangumiRule: BangumiRule): void; }>(); -const { providers, provider, loading, inputValue, bangumiList } = storeToRefs( +const { providers, provider, loading, keyword, searchData } = storeToRefs( useSearchStore() ); -const { getProviders, onSearch, clearSearch } = useSearchStore(); +const { getProviders, clearSearch, openSearch } = useSearchStore(); onMounted(() => { getProviders(); @@ -54,20 +54,20 @@ onMounted(() => { z-5 >
-