- App.vue 应用入口 - algorithms/ 算法模块(黄历、紫微斗数、运势、日历等) - services/ 业务服务层 - utils/ 工具函数(storage、exportImport) - 配置文件(manifest.json、pages.json、vite.config.ts) - H5 入口 index.html
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import { AlmanacService } from './almanacService'
|
|
import type { Almanac } from '../algorithms/types'
|
|
import type { SearchCondition, SearchRequest, SearchResult } from '../types/search'
|
|
import { storage } from '../utils/storage'
|
|
|
|
export interface SearchParams {
|
|
keyword?: string
|
|
dateFrom?: string
|
|
dateTo?: string
|
|
suitableFilter?: string[]
|
|
unsuitableFilter?: string[]
|
|
}
|
|
|
|
export interface SearchHistoryItem {
|
|
keyword: string
|
|
timestamp: number
|
|
resultCount: number
|
|
}
|
|
|
|
function toSearchParams(request: SearchRequest): SearchParams {
|
|
const suitableFilter: string[] = []
|
|
const unsuitableFilter: string[] = []
|
|
|
|
for (const cond of request.conditions) {
|
|
if (cond.type === 'suitable') {
|
|
suitableFilter.push(...cond.items)
|
|
} else {
|
|
unsuitableFilter.push(...cond.items)
|
|
}
|
|
}
|
|
|
|
const today = new Date()
|
|
const dateFrom = today.toISOString().slice(0, 10)
|
|
const endDate = new Date(today)
|
|
endDate.setDate(endDate.getDate() + request.days)
|
|
const dateTo = endDate.toISOString().slice(0, 10)
|
|
|
|
return { suitableFilter, unsuitableFilter, dateFrom, dateTo }
|
|
}
|
|
|
|
function toSearchResult(almanac: Almanac, conditions: SearchCondition[]): SearchResult {
|
|
const matchedSuitable = conditions
|
|
.filter(c => c.type === 'suitable')
|
|
.flatMap(c => c.items)
|
|
.filter(item => almanac.suitable.includes(item))
|
|
|
|
const matchedUnsuitable = conditions
|
|
.filter(c => c.type === 'unsuitable')
|
|
.flatMap(c => c.items)
|
|
.filter(item => almanac.unsuitable.includes(item))
|
|
|
|
return {
|
|
date: almanac.solarDate,
|
|
lunarDate: `${almanac.lunarDate.lunarYear}${almanac.lunarDate.lunarMonth}${almanac.lunarDate.lunarDay}`,
|
|
weekday: almanac.lunarDate.weekday,
|
|
matchedItems: {
|
|
suitable: matchedSuitable,
|
|
unsuitable: matchedUnsuitable,
|
|
},
|
|
matchCount: matchedSuitable.length + matchedUnsuitable.length,
|
|
almanacData: almanac,
|
|
}
|
|
}
|
|
|
|
export class SearchService {
|
|
private almanacService = new AlmanacService()
|
|
private historyKey = 'search_history'
|
|
|
|
async search(request: SearchRequest): Promise<SearchResult[]> {
|
|
const params = toSearchParams(request)
|
|
const almanacs = await this.almanacService.searchAlmanacs(params)
|
|
this.addToHistory(
|
|
request.conditions.map(c => c.items.join(',')).join(';'),
|
|
almanacs.length,
|
|
)
|
|
return almanacs.map(a => toSearchResult(a, request.conditions))
|
|
}
|
|
|
|
async searchByKeyword(keyword: string): Promise<SearchResult[]> {
|
|
const params: SearchParams = { keyword }
|
|
const almanacs = await this.almanacService.searchAlmanacs(params)
|
|
this.addToHistory(keyword, almanacs.length)
|
|
return almanacs.map(a => toSearchResult(a, []))
|
|
}
|
|
|
|
async getSearchHistory(): Promise<SearchHistoryItem[]> {
|
|
return storage.get<SearchHistoryItem[]>(this.historyKey) ?? []
|
|
}
|
|
|
|
async clearSearchHistory(): Promise<void> {
|
|
storage.remove(this.historyKey)
|
|
}
|
|
|
|
private addToHistory(keyword: string, resultCount: number): void {
|
|
if (!keyword) return
|
|
const history = storage.get<SearchHistoryItem[]>(this.historyKey) ?? []
|
|
history.unshift({ keyword, timestamp: Date.now(), resultCount })
|
|
if (history.length > 50) history.length = 50
|
|
storage.set(this.historyKey, history)
|
|
}
|
|
}
|
|
|
|
const searchService = new SearchService()
|
|
export default searchService
|