Created
March 14, 2023 07:34
-
-
Save d1y/343dd54c4f2bb94d17f418d2ec581436 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { onMounted, ref, watch, computed } from "vue" | |
import { | |
getSyncPendings, | |
getSyncFinisheds, | |
getUploadPendings, | |
getUploadFinisheds, | |
getDownloadPendings, | |
getDownloadeds, | |
} from "@/shared/api/photoalbum" | |
import { | |
clearDownloadHistory, | |
clearUserSyncHistory, | |
clearUserSelfUploadHistory, | |
} from "@/shared/api/photoalbum" | |
import type { SyncStatusType, AlbumFile } from "@/shared/types" | |
import { backendApi } from "@/shared/api/axios" | |
import { useStatusChecker } from "@/mobile/use/useStatusChecker" | |
export interface useUploadItem { | |
type: string | |
content?: number | |
item?: SyncStatusType | AlbumFile | |
} | |
export type ISyncStatusType = SyncStatusType | null | |
const enum ICallbackCustomKey { | |
pending, | |
finished, | |
} | |
const enum PauseAndResumeDict { | |
pause, | |
resume, | |
} | |
/* | |
* 传输类型 | |
*/ | |
export const enum ITransType { | |
/** | |
* 上传 | |
*/ | |
upload = "upload", | |
/** | |
* 同步 | |
*/ | |
async = "async", | |
/** | |
* 下载 | |
*/ | |
download = "download", | |
} | |
export const enum ITransTriggerAction { | |
// 用户手动同步 | |
userSelfSync = "/api/albums/record", | |
// 自动同步 | |
sync = "/api/sync", | |
// 下载 | |
download = "/api/download", | |
} | |
const getPauseUrl = (type: ITransTriggerAction) => `${type}/pause` | |
const getResumeUrl = (type: ITransTriggerAction) => `${type}/resume` | |
/** | |
* 获取WS接口地址 | |
*/ | |
function getLinkByTransType(type: ITransType): string { | |
switch (type) { | |
case ITransType.upload: | |
return "/api/albums/record/status" | |
case ITransType.async: | |
return "/api/sync/status" | |
case ITransType.download: | |
return "/api/download/status" | |
} | |
} | |
type FetchListResponse = Promise<{ | |
data: any[] | |
next: boolean | |
total: number | |
}> | |
type FetchListFunction = (page: number) => FetchListResponse | |
const KJobMap = new Map< | |
ITransType, | |
Record<ICallbackCustomKey, FetchListFunction> | |
>([ | |
[ | |
ITransType.upload, | |
{ | |
[ICallbackCustomKey.pending]: getUploadPendings, | |
[ICallbackCustomKey.finished]: getUploadFinisheds, | |
}, | |
], | |
[ | |
ITransType.async, | |
{ | |
[ICallbackCustomKey.pending]: getSyncPendings, | |
[ICallbackCustomKey.finished]: getSyncFinisheds, | |
}, | |
], | |
[ | |
ITransType.download, | |
{ | |
[ICallbackCustomKey.pending]: getDownloadPendings, | |
[ICallbackCustomKey.finished]: getDownloadeds, | |
}, | |
], | |
]) | |
/** | |
* 清除下载历史 | |
*/ | |
async function clearFinishedHistory(type: ITransType) { | |
switch (type) { | |
case "download": | |
return await clearDownloadHistory() | |
case "async": | |
return await clearUserSyncHistory() | |
case "upload": | |
return await clearUserSelfUploadHistory() | |
} | |
} | |
/** | |
* 获取准备下载的列表 | |
*/ | |
async function getPending(type: ITransType = ITransType.upload, page = 1) { | |
const response = await KJobMap.get(type)![ICallbackCustomKey.pending](page) | |
return response | |
} | |
/** | |
* 获取已完成的列表 | |
*/ | |
async function getFinished(type: ITransType = ITransType.upload, page = 1) { | |
const response = await KJobMap.get(type)![ICallbackCustomKey.finished](page) | |
return response | |
} | |
/** | |
* 循环获取数据 | |
*/ | |
async function getDataWithLoop<T>( | |
type: ITransType, | |
key: ICallbackCustomKey, | |
page: number = 1 | |
) { | |
const fn = KJobMap.get(type)![key] | |
const res = await fn(page) | |
let { next, data } = res | |
if (next) { | |
const nextPage = page + 1 | |
const newData = await getDataWithLoop(type, key, nextPage) | |
data = data.concat(newData) | |
} | |
return data as T[] | |
} | |
async function pauseAndResume( | |
type: ITransTriggerAction, | |
dict: PauseAndResumeDict | |
): Promise<boolean> { | |
const fn = dict == PauseAndResumeDict.pause ? getPauseUrl : getResumeUrl | |
const url = fn(type) | |
try { | |
await backendApi.get(url) | |
return true | |
} catch (error) { | |
// FIXME(d1y): api fail | |
console.error(error) | |
return false | |
} | |
} | |
function calcSyncInfoText( | |
item: ISyncStatusType, | |
type: ITransType = ITransType.upload | |
): string { | |
if (item && item.current_file !== "") { | |
if (item.status === "running") { | |
let currentPhotoSize = (item.current_size / (1024 * 1024)).toFixed(2) | |
let downloadedSize = (item.current_downloaded / (1024 * 1024)).toFixed(2) | |
return `${downloadedSize}M/${currentPhotoSize}M` | |
} else { | |
return type === "upload" ? "暂停同步" : "暂停下载" | |
} | |
} | |
return "暂无同步数据" | |
} | |
export default (type: ITransType, actionType: ITransTriggerAction) => { | |
const statusInfo = ref<ISyncStatusType>(null) | |
const currentWSURL = getLinkByTransType(type) | |
const pendingItems = ref<AlbumFile[]>([]) | |
const finishItems = ref<AlbumFile[]>([]) | |
let _pauseLock = false | |
let _resumeLock = false | |
async function getPendingItems() { | |
return await getDataWithLoop<AlbumFile>(type, ICallbackCustomKey.pending) | |
} | |
async function getFinishItems() { | |
return await getDataWithLoop<AlbumFile>(type, ICallbackCustomKey.finished) | |
} | |
function updatePendingAndFinishedInfo() { | |
getPendingItems().then((data) => { | |
pendingItems.value = data | |
}) | |
getFinishItems().then((data) => { | |
finishItems.value = data | |
}) | |
} | |
async function cleanHistory() { | |
await clearFinishedHistory(type) | |
finishItems.value = [] | |
} | |
const { signal } = useStatusChecker(currentWSURL, (response: any)=> { | |
const result = JSON.parse(response) | |
const { type, data } = result | |
if (type === "status") { | |
statusInfo.value = data | |
} else if (type === "done") { | |
const pendingIndex = pendingItems.value.findIndex((t) => t.id === result.data.id) | |
finishItems.value.unshift(...pendingItems.value.splice(pendingIndex, 1)) | |
if (pendingItems.value.length == 0) { | |
statusInfo.value = null | |
} | |
} else if (type == "idle") { | |
statusInfo.value = null | |
} | |
}) | |
const list = computed<useUploadItem[]>(() => { | |
let tasklist: useUploadItem[] = [] | |
if (statusInfo.value) { | |
const offset = statusInfo.value.total - statusInfo.value.current | |
tasklist = tasklist.concat([ | |
{ | |
type: "pendingTitle", | |
content: offset, | |
}, | |
{ | |
type: "current", | |
item: statusInfo.value, | |
}, | |
]) | |
} | |
if (pendingItems.value.length > 0) { | |
tasklist = tasklist.concat( | |
pendingItems.value.slice(1).map((item) => { | |
return { | |
type: "pending", | |
item: item, | |
} | |
}) | |
) | |
} | |
if (finishItems.value.length > 0) { | |
tasklist.push({ | |
type: "finishTitle", | |
content: finishItems.value.length, | |
}) | |
tasklist = tasklist.concat( | |
finishItems.value.map((item) => { | |
return { | |
type: "finish", | |
item: item, | |
} | |
}) | |
) | |
} | |
return tasklist | |
}) | |
function init() { | |
updatePendingAndFinishedInfo() | |
} | |
async function pause() { | |
if (_pauseLock) return | |
_pauseLock = true | |
await pauseAndResume(actionType, PauseAndResumeDict.pause) | |
_pauseLock = false | |
} | |
async function resume() { | |
if (_resumeLock) return | |
_resumeLock = true | |
await pauseAndResume(actionType, PauseAndResumeDict.resume) | |
_pauseLock = false | |
} | |
function dispose() { | |
_resumeLock = false | |
_pauseLock = false | |
} | |
return { | |
updatePendingAndFinishedInfo, | |
cleanHistory, | |
pause, | |
resume, | |
dispose, | |
init, | |
list, | |
statusInfo, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment