414 lines
10 KiB
TypeScript
414 lines
10 KiB
TypeScript
import * as Vue from 'vue'
|
||
import SelectDialog from '../components/dialog/SelectDialog.vue'
|
||
import SimpleConfirmDialog from '../components/dialog/SimpleConfirmDialog.vue'
|
||
import ConfirmDialog from '../components/dialog/ConfirmDialog.vue'
|
||
import Loading from '../components/Loading.vue'
|
||
import { IMG_URL, IS_DEV, IS_GITEE_PAGES } from '@/config'
|
||
import NoticeDialog from '../components/dialog/NoticeDialog.vue'
|
||
import bus, { EVENT_KEY } from './bus'
|
||
import { ArchiveReader, libarchiveWasm } from 'libarchive-wasm'
|
||
|
||
export function _updateItem(props, key, val, emit) {
|
||
const old = cloneDeep(props.item)
|
||
old[key] = val
|
||
emit('update:item', old)
|
||
bus.emit(EVENT_KEY.UPDATE_ITEM, { position: props.position, item: old })
|
||
}
|
||
|
||
export function _storageSet(key, value) {
|
||
localStorage.setItem(key, JSON.stringify(value))
|
||
}
|
||
|
||
export function _storageGet(key, defaultValue = '') {
|
||
const res = localStorage.getItem(key)
|
||
if (res) {
|
||
return JSON.parse(res)
|
||
}
|
||
return defaultValue
|
||
}
|
||
|
||
export function _stopPropagation(e: Event) {
|
||
e.stopImmediatePropagation()
|
||
e.stopPropagation()
|
||
e.preventDefault()
|
||
}
|
||
|
||
export function _stop(e: Event) {
|
||
e.stopPropagation()
|
||
}
|
||
|
||
export function _copy(val) {
|
||
const textarea = document.createElement('textarea')
|
||
document.body.appendChild(textarea)
|
||
textarea.style.position = 'absolute'
|
||
textarea.style.clip = 'rect(0 0 0 0)'
|
||
textarea.value = val
|
||
textarea.select()
|
||
if (document.execCommand) {
|
||
document.execCommand('copy', true)
|
||
_notice('已复制')
|
||
}
|
||
document.body.removeChild(textarea)
|
||
}
|
||
|
||
export function _formatNumber(num) {
|
||
if (!num) return
|
||
if (num > 100000000) {
|
||
return (num / 100000000).toFixed(1) + '亿'
|
||
} else if (num > 10000) {
|
||
return (num / 10000).toFixed(1) + '万'
|
||
} else {
|
||
return num
|
||
}
|
||
}
|
||
|
||
export function _dateFormat(val, type?): string {
|
||
if (!val) return
|
||
if (String(val).length === 10) {
|
||
val = val * 1000
|
||
}
|
||
const d = new Date(Number(val))
|
||
const year = d.getFullYear()
|
||
const m = d.getMonth() + 1
|
||
const mStr = m < 10 ? '0' + m : m
|
||
const day = d.getDate()
|
||
const dayStr = day < 10 ? '0' + day : day
|
||
const h = d.getHours()
|
||
const hStr = h < 10 ? '0' + h : h
|
||
const min = d.getMinutes()
|
||
const minStr = min < 10 ? '0' + min : min
|
||
const sec = d.getSeconds()
|
||
const secStr = sec < 10 ? '0' + sec : sec
|
||
switch (type) {
|
||
case 'Y':
|
||
return year + ''
|
||
case 'M':
|
||
return `${year}-${mStr}`
|
||
case 'M_D':
|
||
return `${mStr}-${dayStr}`
|
||
case 'M_CN':
|
||
return `${year}年${mStr}月`
|
||
case 'D':
|
||
return `${year}-${mStr}-${dayStr}`
|
||
case 'm':
|
||
return `${year}-${mStr}-${dayStr} ${hStr}:${minStr}`
|
||
default:
|
||
return `${year}-${mStr}-${dayStr} ${hStr}:${minStr}:${secStr}`
|
||
}
|
||
}
|
||
|
||
export function _time(time) {
|
||
if (String(time).length === 10) {
|
||
time = time * 1000
|
||
}
|
||
const date = new Date(Number(time))
|
||
const now = new Date()
|
||
const d = now.valueOf() - date.valueOf()
|
||
let str = ''
|
||
if (d < 1000 * 60) {
|
||
str = '刚刚'
|
||
} else if (d < 1000 * 60 * 60) {
|
||
str = `${(d / (1000 * 60)).toFixed()}分钟前`
|
||
} else if (d < 1000 * 60 * 60 * 24) {
|
||
str = `${(d / (1000 * 60 * 60)).toFixed()}小时前`
|
||
} else if (d < 1000 * 60 * 60 * 24 * 2) {
|
||
str = '1天前'
|
||
} else if (d < 1000 * 60 * 60 * 24 * 3) {
|
||
str = '2天前'
|
||
} else if (d < 1000 * 60 * 60 * 24 * 4) {
|
||
str = '3天前'
|
||
} else if (date.getFullYear() === now.getFullYear()) {
|
||
str = _dateFormat(time, 'M_D')
|
||
} else {
|
||
str = _dateFormat(time, 'D')
|
||
}
|
||
return str
|
||
}
|
||
|
||
export function _checkImgUrl(url) {
|
||
// console.log(url)
|
||
if (!url) return
|
||
//本地图片
|
||
if (
|
||
url.includes('assets/img') ||
|
||
url.includes('file://') ||
|
||
url.includes('data:image') ||
|
||
url.includes('http') ||
|
||
url.includes('https')
|
||
) {
|
||
return url
|
||
}
|
||
return IMG_URL + url
|
||
}
|
||
|
||
export function _duration(v) {
|
||
if (!v) return '00:00'
|
||
const m = Math.floor(v / 60)
|
||
// let s = v % 60
|
||
const s = Math.round(v % 60)
|
||
let str: string = ''
|
||
if (m === 0) {
|
||
str = '00'
|
||
} else if (m > 0 && m < 10) {
|
||
str = '0' + m
|
||
} else {
|
||
str = m + ''
|
||
}
|
||
str += ':'
|
||
if (s === 0) {
|
||
str += '00'
|
||
} else if (s > 0 && s < 10) {
|
||
str += '0' + s
|
||
} else {
|
||
str += s
|
||
}
|
||
return str
|
||
}
|
||
|
||
export function _getUserDouyinId(item) {
|
||
return item.author.unique_id || item.author.short_id
|
||
}
|
||
|
||
/**
|
||
* @param {number} duration
|
||
*/
|
||
export function _sleep(duration) {
|
||
return new Promise((resolve) => {
|
||
setTimeout(resolve, duration)
|
||
})
|
||
}
|
||
|
||
export function cloneDeep(val) {
|
||
return JSON.parse(JSON.stringify(val))
|
||
}
|
||
|
||
export function random(min, max) {
|
||
const minCeiled = Math.ceil(min)
|
||
const maxFloored = Math.floor(max)
|
||
return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled) // 包含最小值和最大值
|
||
}
|
||
|
||
export function sampleSize(arr, num) {
|
||
const list = []
|
||
const indexs = []
|
||
while (list.length !== num) {
|
||
const j = random(0, arr.length - 1)
|
||
if (!indexs.includes(j)) {
|
||
list.push(arr[j])
|
||
indexs.push(j)
|
||
}
|
||
}
|
||
return list
|
||
}
|
||
|
||
export function _showLoading() {
|
||
const app = Vue.createApp({
|
||
render() {
|
||
return <Loading />
|
||
}
|
||
})
|
||
const parent = document.createElement('div')
|
||
parent.classList.add(...['dialog-ctn'])
|
||
document.body.append(parent)
|
||
app.mount(parent)
|
||
}
|
||
|
||
export function _hideLoading() {
|
||
const parent = document.querySelector('.dialog-ctn')
|
||
parent.remove()
|
||
}
|
||
|
||
export function _showSelectDialog(sexList, cb) {
|
||
const remove = () => {
|
||
const parent = document.querySelector('.dialog-ctn')
|
||
parent.classList.replace('fade-in', 'fade-out')
|
||
setTimeout(() => {
|
||
parent.remove()
|
||
}, 300)
|
||
}
|
||
const tempCb = (e) => {
|
||
remove()
|
||
cb(e)
|
||
}
|
||
const app = Vue.createApp({
|
||
render() {
|
||
return <SelectDialog onCancel={remove} list={sexList} onOk={tempCb} />
|
||
}
|
||
})
|
||
const parent = document.createElement('div')
|
||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||
document.body.append(parent)
|
||
app.mount(parent)
|
||
}
|
||
|
||
export function _showSimpleConfirmDialog(title, okCb, cancelCb, okText, cancelText) {
|
||
if (!cancelCb) {
|
||
cancelCb = () => {}
|
||
}
|
||
const remove = () => {
|
||
const parent = document.querySelector('.dialog-ctn')
|
||
parent.classList.replace('fade-in', 'fade-out')
|
||
setTimeout(() => {
|
||
parent.remove()
|
||
}, 300)
|
||
}
|
||
const tempOkCb = (e) => {
|
||
remove()
|
||
okCb(e)
|
||
}
|
||
const tempCancelCb = (e) => {
|
||
remove()
|
||
cancelCb(e)
|
||
}
|
||
const app = Vue.createApp({
|
||
render() {
|
||
return (
|
||
<SimpleConfirmDialog
|
||
onCancel={tempCancelCb}
|
||
onDismiss={remove}
|
||
title={title}
|
||
okText={okText}
|
||
cancelText={cancelText}
|
||
onOk={tempOkCb}
|
||
/>
|
||
)
|
||
}
|
||
})
|
||
const parent = document.createElement('div')
|
||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||
document.body.append(parent)
|
||
app.mount(parent)
|
||
}
|
||
|
||
export function _showConfirmDialog(
|
||
title,
|
||
subtitle,
|
||
subtitleColor,
|
||
okCb,
|
||
cancelCb,
|
||
okText,
|
||
cancelText,
|
||
cancelTextColor
|
||
) {
|
||
const remove = () => {
|
||
const parent = document.querySelector('.dialog-ctn')
|
||
parent.classList.replace('fade-in', 'fade-out')
|
||
setTimeout(() => {
|
||
parent.remove()
|
||
}, 300)
|
||
}
|
||
const tempOkCb = (e) => {
|
||
remove()
|
||
okCb && okCb(e)
|
||
}
|
||
const tempCancelCb = (e) => {
|
||
remove()
|
||
cancelCb && cancelCb(e)
|
||
}
|
||
const app = Vue.createApp({
|
||
render() {
|
||
return (
|
||
<ConfirmDialog
|
||
onCancel={tempCancelCb}
|
||
onDismiss={remove}
|
||
title={title}
|
||
subtitle={subtitle}
|
||
subtitleColor={subtitleColor}
|
||
cancelTextColor={cancelTextColor}
|
||
okText={okText}
|
||
cancelText={cancelText}
|
||
onOk={tempOkCb}
|
||
/>
|
||
)
|
||
}
|
||
})
|
||
const parent = document.createElement('div')
|
||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||
document.body.append(parent)
|
||
app.mount(parent)
|
||
}
|
||
|
||
export function _showNoticeDialog(title, subtitle, subtitleColor, cancelCb, cancelText) {
|
||
const remove = () => {
|
||
const parent = document.querySelector('.dialog-ctn')
|
||
parent.classList.replace('fade-in', 'fade-out')
|
||
setTimeout(() => {
|
||
parent.remove()
|
||
}, 300)
|
||
}
|
||
const tempCancelCb = (e) => {
|
||
remove()
|
||
cancelCb(e)
|
||
}
|
||
const app = Vue.createApp({
|
||
render() {
|
||
return (
|
||
<NoticeDialog
|
||
onCancel={tempCancelCb}
|
||
onDismiss={remove}
|
||
title={title}
|
||
subtitleColor={subtitleColor}
|
||
cancelText={cancelText}
|
||
subtitle={subtitle}
|
||
/>
|
||
)
|
||
}
|
||
})
|
||
const parent = document.createElement('div')
|
||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||
document.body.append(parent)
|
||
app.mount(parent)
|
||
}
|
||
|
||
export function _notice(val) {
|
||
const div = document.createElement('div')
|
||
div.classList.add('global-notice')
|
||
div.textContent = val
|
||
document.body.append(div)
|
||
setTimeout(() => {
|
||
document.body.removeChild(div)
|
||
}, 1000)
|
||
}
|
||
|
||
export function _no() {
|
||
_notice('未实现')
|
||
}
|
||
|
||
/**
|
||
* 逃避国内某pages审查,因为json文件被提示有违禁词,json压缩成7z文件,7z和zip文件被屏蔽了,所以7z重命名为md
|
||
* @param url
|
||
* @returns Promise<{ json(): Promise<any> } | Response>
|
||
* @privateF
|
||
*/
|
||
export async function _fetch(url: string): Promise<{ json(): Promise<any> } | Response> {
|
||
if (IS_DEV || !IS_GITEE_PAGES) {
|
||
url = url.replace('.md', '.json')
|
||
return fetch(url)
|
||
} else {
|
||
// eslint-disable-next-line no-async-promise-executor
|
||
return new Promise(async (resolve) => {
|
||
const r = await fetch(url)
|
||
if (url.includes('.md')) {
|
||
// console.time()
|
||
const data = await r.arrayBuffer()
|
||
const mod = await libarchiveWasm()
|
||
const reader = new ArchiveReader(mod, new Int8Array(data))
|
||
for (const entry of reader.entries()) {
|
||
if (entry.getPathname().endsWith('.json')) {
|
||
const data = new TextDecoder().decode(entry.readData())
|
||
resolve({
|
||
json() {
|
||
return Promise.resolve(JSON.parse(data))
|
||
}
|
||
})
|
||
}
|
||
// console.timeEnd()
|
||
}
|
||
reader.free()
|
||
} else {
|
||
resolve(r)
|
||
}
|
||
})
|
||
}
|
||
}
|