接入H5讲解后端数据闭环

This commit is contained in:
lyf
2026-06-30 17:22:20 +08:00
parent 1c2cc788d1
commit e3682ed3ec
13 changed files with 815 additions and 68 deletions

View File

@@ -29,6 +29,7 @@ export interface AudioPlayInfo {
playUrl?: string | null
expiresAt?: string | null
subtitleUrl?: string | null
hasText?: boolean
fallback?: boolean
fallbackReason?: string | null
reason?: string | null
@@ -40,8 +41,34 @@ interface AudioPlayInfoResponse {
data?: AudioPlayInfo
}
export interface AudioTextInfoRequest {
targetType: AudioPlayTargetType
targetId: string
lang?: AudioLanguage
}
export interface AudioTextInfo {
available: boolean
targetType: AudioPlayTargetType
targetId: string | number
lang: AudioLanguage
narrationTier?: 'STANDARD' | 'EXTENDED'
title?: string | null
text?: string | null
textLength?: number | null
textHash?: string | null
reason?: string | null
}
interface AudioTextInfoResponse {
code: number
msg?: string
data?: AudioTextInfo
}
export interface AudioPlayInfoRepository {
getPlayInfo(request: AudioPlayInfoRequest): Promise<AudioPlayInfo>
getTextInfo(request: AudioTextInfoRequest): Promise<AudioTextInfo>
clearCache(lang?: AudioLanguage): void
}
@@ -67,6 +94,7 @@ const requestJson = <T>(url: string): Promise<T> => new Promise((resolve, reject
uni.request({
url,
method: 'GET',
timeout: 8000,
success: (response) => {
const statusCode = Number(response.statusCode || 0)
if (statusCode < 200 || statusCode >= 300) {
@@ -95,6 +123,10 @@ const audioKey = ({ targetType, targetId, lang }: Required<AudioPlayInfoRequest>
`${targetType}:${targetId}:${lang}`
)
const audioTextKey = ({ targetType, targetId, lang }: Required<AudioTextInfoRequest>) => (
`${targetType}:${targetId}:${lang}`
)
const isExpired = (expiresAt?: string | null) => (
Boolean(expiresAt) && new Date(expiresAt as string).getTime() <= Date.now()
)
@@ -105,6 +137,7 @@ export const audioReasonToText = (reason?: string | null) => (
export class DefaultAudioPlayInfoRepository implements AudioPlayInfoRepository {
private readonly cache = new Map<string, AudioPlayInfo>()
private readonly textCache = new Map<string, AudioTextInfo>()
async getPlayInfo(request: AudioPlayInfoRequest): Promise<AudioPlayInfo> {
const normalizedRequest: Required<AudioPlayInfoRequest> = {
@@ -140,9 +173,42 @@ export class DefaultAudioPlayInfoRepository implements AudioPlayInfoRepository {
return response.data
}
async getTextInfo(request: AudioTextInfoRequest): Promise<AudioTextInfo> {
const normalizedRequest: Required<AudioTextInfoRequest> = {
targetType: request.targetType,
targetId: request.targetId,
lang: request.lang || (dataSourceConfig.audioLanguage as AudioLanguage)
}
const key = audioTextKey(normalizedRequest)
const cached = this.textCache.get(key)
if (cached) {
return cached
}
const params = new URLSearchParams({
targetType: normalizedRequest.targetType,
targetId: normalizedRequest.targetId,
lang: normalizedRequest.lang
})
const url = `${resolveAudioApiBaseUrl()}/gis/guide/audio/text-info?${params.toString()}`
const response = await requestJson<AudioTextInfoResponse>(url)
if (response.code !== 0 || !response.data) {
throw new Error(response.msg || '讲解词正文解析失败')
}
if (response.data.available) {
this.textCache.set(key, response.data)
}
return response.data
}
clearCache(lang?: AudioLanguage) {
if (!lang) {
this.cache.clear()
this.textCache.clear()
return
}
@@ -151,6 +217,11 @@ export class DefaultAudioPlayInfoRepository implements AudioPlayInfoRepository {
this.cache.delete(key)
}
})
Array.from(this.textCache.keys()).forEach((key) => {
if (key.endsWith(`:${lang}`)) {
this.textCache.delete(key)
}
})
}
}