60 lines
2.4 KiB
TypeScript
60 lines
2.4 KiB
TypeScript
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'
|
|
import {
|
|
getDesktopWorkstationDownloads,
|
|
type DesktopWorkstationDownload,
|
|
type DesktopWorkstationDownloads
|
|
} from '@/api/setting/desktop_workstation'
|
|
|
|
// 接诊台、列表和聊天窗口共用一个请求与短缓存。
|
|
const downloads = shallowRef<DesktopWorkstationDownloads>({ version: '', packages: [] })
|
|
const downloadsLoading = ref(false)
|
|
const downloadsFailed = ref(false)
|
|
let pending: Promise<void> | undefined
|
|
let loadedAt = 0
|
|
const CACHE_MS = 5 * 60 * 1000
|
|
|
|
export function normalizeDesktopDownloads(value: DesktopWorkstationDownloads): DesktopWorkstationDownloads {
|
|
const platforms = ['windows_x64', 'macos_arm64', 'macos_x64']
|
|
const packages: DesktopWorkstationDownload[] = []
|
|
const seen = new Set<string>()
|
|
for (const item of Array.isArray(value?.packages) ? value.packages : []) {
|
|
if (!item || typeof item !== 'object') continue
|
|
if (!platforms.includes(item.platform) || seen.has(item.platform)) continue
|
|
try {
|
|
const url = new URL(item.url)
|
|
if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password) continue
|
|
if (!/^[a-f\d]{64}$/i.test(item.sha256)) continue
|
|
packages.push({ ...item, url: url.href })
|
|
seen.add(item.platform)
|
|
} catch { /* 配置异常时不生成无效下载链接。 */ }
|
|
}
|
|
return { version: String(value?.version || ''), packages }
|
|
}
|
|
|
|
export function useDesktopWorkstationDownloads() {
|
|
const loadDownloads = (force = false): Promise<void> => {
|
|
if (pending) return pending
|
|
if (!force && loadedAt > 0 && Date.now() - loadedAt < CACHE_MS) return Promise.resolve()
|
|
downloadsLoading.value = true
|
|
downloadsFailed.value = false
|
|
pending = getDesktopWorkstationDownloads().then(data => {
|
|
downloads.value = normalizeDesktopDownloads(data)
|
|
loadedAt = Date.now()
|
|
}).catch(() => {
|
|
downloadsFailed.value = true
|
|
}).finally(() => {
|
|
downloadsLoading.value = false
|
|
pending = undefined
|
|
})
|
|
return pending
|
|
}
|
|
const refreshOnFocus = () => { void loadDownloads() }
|
|
onMounted(() => {
|
|
void loadDownloads()
|
|
window.addEventListener('focus', refreshOnFocus)
|
|
})
|
|
onUnmounted(() => window.removeEventListener('focus', refreshOnFocus))
|
|
|
|
return { downloads, downloadsLoading, downloadsFailed, loadDownloads }
|
|
}
|