mirror of
https://github.com/putyy/res-downloader.git
synced 2026-01-12 06:04:55 +08:00
feat: Add version update detection
This commit is contained in:
2
frontend/components.d.ts
vendored
2
frontend/components.d.ts
vendored
@@ -9,8 +9,6 @@ declare module 'vue' {
|
|||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
Action: typeof import('./src/components/Action.vue')['default']
|
Action: typeof import('./src/components/Action.vue')['default']
|
||||||
ActionDesc: typeof import('./src/components/ActionDesc.vue')['default']
|
ActionDesc: typeof import('./src/components/ActionDesc.vue')['default']
|
||||||
DescriptionHeader: typeof import('./src/components/DescriptionHeader.vue')['default']
|
|
||||||
DescriptionSearch: typeof import('./src/components/DescriptionSearch.vue')['default']
|
|
||||||
Footer: typeof import('./src/components/Footer.vue')['default']
|
Footer: typeof import('./src/components/Footer.vue')['default']
|
||||||
ImportJson: typeof import('./src/components/ImportJson.vue')['default']
|
ImportJson: typeof import('./src/components/ImportJson.vue')['default']
|
||||||
Index: typeof import('./src/components/layout/Index.vue')['default']
|
Index: typeof import('./src/components/layout/Index.vue')['default']
|
||||||
|
|||||||
@@ -2,7 +2,12 @@
|
|||||||
<div class="flex pb-2 flex-col h-full min-w-[80px] border-r border-slate-100 dark:border-slate-900">
|
<div class="flex pb-2 flex-col h-full min-w-[80px] border-r border-slate-100 dark:border-slate-900">
|
||||||
<Screen v-if="envInfo.platform!=='darwin'"></Screen>
|
<Screen v-if="envInfo.platform!=='darwin'"></Screen>
|
||||||
<div class="w-full flex flex-row items-center justify-center pt-5" :class="envInfo.platform==='darwin' ? 'pt-8' : 'pt-2'">
|
<div class="w-full flex flex-row items-center justify-center pt-5" :class="envInfo.platform==='darwin' ? 'pt-8' : 'pt-2'">
|
||||||
<img class="w-12 h-12 cursor-pointer" src="@/assets/image/logo.png" alt="res-downloader logo" @click="handleFooterUpdate('github')"/>
|
<div class="relative flex items-center justify-center cursor-pointer" @click="handleFooterUpdate('github')">
|
||||||
|
<img class="w-12 h-12 rounded-full transition-transform duration-300 hover:scale-105 dark" src="@/assets/image/logo.png" alt="res-downloader logo"/>
|
||||||
|
<span class="absolute right-[-25px] top-0 font-semibold rounded-full bg-red-500 text-white dark:bg-red-600 dark:text-gray-100 text-[10px] px-1.5 py-0.5 animate-pulse" v-if="showUpdate">
|
||||||
|
New
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main class="flex-1 flex-grow-1 mb-5 overflow-auto flex flex-col pt-1 items-center h-full" v-if="is">
|
<main class="flex-1 flex-grow-1 mb-5 overflow-auto flex flex-col pt-1 items-center h-full" v-if="is">
|
||||||
<NScrollbar :size="1">
|
<NScrollbar :size="1">
|
||||||
@@ -66,6 +71,8 @@ import Footer from "@/components/Footer.vue"
|
|||||||
import Screen from "@/components/Screen.vue"
|
import Screen from "@/components/Screen.vue"
|
||||||
import {BrowserOpenURL} from "../../../wailsjs/runtime"
|
import {BrowserOpenURL} from "../../../wailsjs/runtime"
|
||||||
import {useI18n} from "vue-i18n"
|
import {useI18n} from "vue-i18n"
|
||||||
|
import request from "@/api/request"
|
||||||
|
import {compareVersions} from "@/func"
|
||||||
|
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -77,6 +84,7 @@ const showAppInfo = ref(false)
|
|||||||
const menuValue = ref(route.fullPath.substring(1))
|
const menuValue = ref(route.fullPath.substring(1))
|
||||||
const store = useIndexStore()
|
const store = useIndexStore()
|
||||||
const is = ref(false)
|
const is = ref(false)
|
||||||
|
const showUpdate = ref(false)
|
||||||
|
|
||||||
const envInfo = store.envInfo
|
const envInfo = store.envInfo
|
||||||
|
|
||||||
@@ -98,6 +106,13 @@ onMounted(()=>{
|
|||||||
collapsed.value = JSON.parse(collapsedCache).collapsed
|
collapsed.value = JSON.parse(collapsedCache).collapsed
|
||||||
}
|
}
|
||||||
is.value = true
|
is.value = true
|
||||||
|
|
||||||
|
request({
|
||||||
|
url: 'https://res.putyy.com/version.json',
|
||||||
|
method: 'get',
|
||||||
|
}).then((res)=>{
|
||||||
|
showUpdate.value = compareVersions(res.version, store.appInfo.Version) === 1
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const renderIcon = (icon: any) => {
|
const renderIcon = (icon: any) => {
|
||||||
@@ -182,4 +197,21 @@ const collapsedChange = (value: boolean)=>{
|
|||||||
collapsed.value = value
|
collapsed.value = value
|
||||||
localStorage.setItem("collapsed", JSON.stringify({collapsed: value}))
|
localStorage.setItem("collapsed", JSON.stringify({collapsed: value}))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-pulse {
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
29
frontend/src/func.ts
Normal file
29
frontend/src/func.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
const ipv4Regex = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/
|
||||||
|
const domainRegex = /^(?!:\/\/)([a-zA-Z0-9-_]+\.)*[a-zA-Z0-9][a-zA-Z0-9-_]+\.[a-zA-Z]{2,11}?$/
|
||||||
|
const localhostRegex = /^localhost$/
|
||||||
|
|
||||||
|
export const compareVersions = (v1: string, v2: string) => {
|
||||||
|
const parts1 = v1.split('.').map(Number)
|
||||||
|
const parts2 = v2.split('.').map(Number)
|
||||||
|
|
||||||
|
const maxLength = Math.max(parts1.length, parts2.length)
|
||||||
|
|
||||||
|
for (let i = 0; i < maxLength; i++) {
|
||||||
|
const num1 = parts1[i] || 0
|
||||||
|
const num2 = parts2[i] || 0
|
||||||
|
|
||||||
|
if (num1 < num2) return -1
|
||||||
|
if (num1 > num2) return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isValidHost = (host: string) => {
|
||||||
|
return ipv4Regex.test(host) || domainRegex.test(host) || localhostRegex.test(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isValidPort = (port: number) => {
|
||||||
|
const portNumber = Number(port)
|
||||||
|
return Number.isInteger(portNumber) && portNumber > 1024 && portNumber < 65535
|
||||||
|
}
|
||||||
@@ -97,7 +97,6 @@ import {
|
|||||||
DownloadOutline,
|
DownloadOutline,
|
||||||
ArrowRedoCircleOutline,
|
ArrowRedoCircleOutline,
|
||||||
ServerOutline,
|
ServerOutline,
|
||||||
HelpCircleOutline,
|
|
||||||
SearchOutline,
|
SearchOutline,
|
||||||
TrashOutline
|
TrashOutline
|
||||||
} from "@vicons/ionicons5"
|
} from "@vicons/ionicons5"
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ import type {appType} from "@/types/app"
|
|||||||
import appApi from "@/api/app"
|
import appApi from "@/api/app"
|
||||||
import {computed} from "vue"
|
import {computed} from "vue"
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
|
import {isValidHost, isValidPort} from '@/func'
|
||||||
|
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
const store = useIndexStore()
|
const store = useIndexStore()
|
||||||
@@ -221,9 +222,6 @@ const renderKey = ref(999)
|
|||||||
|
|
||||||
const hostValidationFeedback = ref("")
|
const hostValidationFeedback = ref("")
|
||||||
const portValidationFeedback = ref("")
|
const portValidationFeedback = ref("")
|
||||||
const ipv4Regex = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/
|
|
||||||
const domainRegex = /^(?!:\/\/)([a-zA-Z0-9-_]+\.)*[a-zA-Z0-9][a-zA-Z0-9-_]+\.[a-zA-Z]{2,11}?$/
|
|
||||||
const localhostRegex = /^localhost$/
|
|
||||||
|
|
||||||
watch(formValue.value, () => {
|
watch(formValue.value, () => {
|
||||||
formValue.value.Port = formValue.value.Port.trim()
|
formValue.value.Port = formValue.value.Port.trim()
|
||||||
@@ -262,15 +260,6 @@ watch(() => store.globalConfig.Locale, () => {
|
|||||||
renderKey.value++
|
renderKey.value++
|
||||||
})
|
})
|
||||||
|
|
||||||
const isValidPort = (port: number) => {
|
|
||||||
const portNumber = Number(port)
|
|
||||||
return Number.isInteger(portNumber) && portNumber > 1024 && portNumber < 65535
|
|
||||||
}
|
|
||||||
|
|
||||||
const isValidHost = (host: string) => {
|
|
||||||
return ipv4Regex.test(host) || domainRegex.test(host) || localhostRegex.test(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectDir = () => {
|
const selectDir = () => {
|
||||||
appApi.openDirectoryDialog().then((res: any) => {
|
appApi.openDirectoryDialog().then((res: any) => {
|
||||||
if (res.code === 1) {
|
if (res.code === 1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user