1
This commit is contained in:
507
pages/setting/upgrade-popup.vue
Normal file
507
pages/setting/upgrade-popup.vue
Normal file
@@ -0,0 +1,507 @@
|
||||
<template>
|
||||
<view class="mask flex-center">
|
||||
<view class="content botton-radius">
|
||||
<view class="content-top">
|
||||
<text class="content-top-text">{{ title }}</text>
|
||||
<image
|
||||
class="content-top"
|
||||
style="top: 0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
src="../../static/images/app_update_bg_top.png"
|
||||
>
|
||||
</image>
|
||||
</view>
|
||||
<view class="content-header"></view>
|
||||
<view class="content-body">
|
||||
<view class="title">
|
||||
<text>{{ subTitle }}</text>
|
||||
<!-- <text style="padding-left:20rpx;font-size: 0.5em;color: #666;">v.{{version}}</text> -->
|
||||
</view>
|
||||
<view class="body">
|
||||
<scroll-view class="box-des-scroll" scroll-y="true">
|
||||
<text class="box-des">
|
||||
{{ contents }}
|
||||
</text>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="footer flex-center">
|
||||
<template v-if="isiOS">
|
||||
<button class="content-button" style="border: none; color: #fff" plain @click="jumpToAppStore">
|
||||
{{ downLoadBtnTextiOS }}
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="!downloadSuccess">
|
||||
<view class="progress-box flex-column" v-if="downloading">
|
||||
<progress
|
||||
class="progress"
|
||||
border-radius="35"
|
||||
:percent="downLoadPercent"
|
||||
activeColor="#3DA7FF"
|
||||
show-info
|
||||
stroke-width="10"
|
||||
/>
|
||||
<view style="width: 100%; font-size: 14px; display: flex; justify-content: space-around">
|
||||
<text>{{ downLoadingText }}</text>
|
||||
<text>({{ downloadedSize }}/{{ packageFileSize }}M)</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<button v-else class="content-button" style="border: none; color: #fff" plain @click="downloadPackage">
|
||||
{{ downLoadBtnText }}
|
||||
</button>
|
||||
</template>
|
||||
<button
|
||||
v-else-if="downloadSuccess"
|
||||
class="content-button"
|
||||
style="border: none; color: #fff"
|
||||
plain
|
||||
:loading="installing"
|
||||
:disabled="installing"
|
||||
@click="installPackage"
|
||||
>
|
||||
{{ installing ? '正在安装……' : '下载完成,立即安装' }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="installed && isWGT"
|
||||
class="content-button"
|
||||
style="border: none; color: #fff"
|
||||
plain
|
||||
@click="restart"
|
||||
>
|
||||
安装完毕,点击重启
|
||||
</button>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<image
|
||||
v-if="!is_mandatory"
|
||||
class="close-img"
|
||||
src="../../static/images/app_update_close.png"
|
||||
@click.stop="closeUpdate"
|
||||
></image>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { onLoad, onBackPress } from '@dcloudio/uni-app'
|
||||
|
||||
const localFilePathKey = '__localFilePath__'
|
||||
const platform_iOS = 'iOS'
|
||||
let downloadTask = null
|
||||
|
||||
// 工具函数保持原样
|
||||
function compare(v1 = '0', v2 = '0') {
|
||||
v1 = String(v1).split('.')
|
||||
v2 = String(v2).split('.')
|
||||
const minVersionLens = Math.min(v1.length, v2.length)
|
||||
|
||||
let result = 0
|
||||
for (let i = 0; i < minVersionLens; i++) {
|
||||
const curV1 = Number(v1[i])
|
||||
const curV2 = Number(v2[i])
|
||||
|
||||
if (curV1 > curV2) {
|
||||
result = 1
|
||||
break
|
||||
} else if (curV1 < curV2) {
|
||||
result = -1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (result === 0 && v1.length !== v2.length) {
|
||||
const v1BiggerThenv2 = v1.length > v2.length
|
||||
const maxLensVersion = v1BiggerThenv2 ? v1 : v2
|
||||
for (let i = minVersionLens; i < maxLensVersion.length; i++) {
|
||||
const curVersion = Number(maxLensVersion[i])
|
||||
if (curVersion > 0) {
|
||||
v1BiggerThenv2 ? (result = 1) : (result = -1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 响应式状态
|
||||
const installForBeforeFilePath = ref('')
|
||||
const installed = ref(false)
|
||||
const installing = ref(false)
|
||||
const downloadSuccess = ref(false)
|
||||
const downloading = ref(false)
|
||||
const downLoadPercent = ref(0)
|
||||
const downloadedSize = ref(0)
|
||||
const packageFileSize = ref(0)
|
||||
const tempFilePath = ref('')
|
||||
|
||||
const title = ref('更新日志')
|
||||
const contents = ref('')
|
||||
const is_mandatory = ref(false)
|
||||
const subTitle = ref('发现新版本')
|
||||
const downLoadBtnTextiOS = ref('立即跳转更新')
|
||||
const downLoadBtnText = ref('立即下载更新')
|
||||
const downLoadingText = ref('安装包下载中,请稍后')
|
||||
|
||||
const version = ref('')
|
||||
const url = ref('')
|
||||
const type = ref('')
|
||||
const platform = ref('')
|
||||
|
||||
// 计算属性
|
||||
const isWGT = computed(() => type.value === 'wgt')
|
||||
const isiOS = computed(() => !isWGT.value && platform.value.includes(platform_iOS))
|
||||
|
||||
// 方法
|
||||
function checkLocalStoragePackage() {
|
||||
const localFilePathRecord = uni.getStorageSync(localFilePathKey)
|
||||
if (localFilePathRecord) {
|
||||
const { version: recordVersion, savedFilePath, installed: recordInstalled } = localFilePathRecord
|
||||
|
||||
if (!recordInstalled && compare(recordVersion, version.value) === 0) {
|
||||
downloadSuccess.value = true
|
||||
installForBeforeFilePath.value = savedFilePath
|
||||
tempFilePath.value = savedFilePath
|
||||
} else {
|
||||
deleteSavedFile(savedFilePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function closeUpdate() {
|
||||
if (downloading.value) {
|
||||
if (is_mandatory.value) {
|
||||
uni.showToast({ title: '下载中,请稍后……', icon: 'none', duration: 500 })
|
||||
return
|
||||
}
|
||||
uni.showModal({
|
||||
title: '是否取消下载?',
|
||||
cancelText: '否',
|
||||
confirmText: '是',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
downloadTask?.abort()
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (downloadSuccess.value && tempFilePath.value) {
|
||||
await saveFile(tempFilePath.value, version.value)
|
||||
uni.navigateBack()
|
||||
return
|
||||
}
|
||||
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
function downloadPackage() {
|
||||
downloading.value = true
|
||||
|
||||
downloadTask = uni.downloadFile({
|
||||
url: url.value,
|
||||
success: res => {
|
||||
if (res.statusCode === 200) {
|
||||
downloadSuccess.value = true
|
||||
tempFilePath.value = res.tempFilePath
|
||||
// 强制更新
|
||||
if (is_mandatory.value) {
|
||||
installPackage()
|
||||
}
|
||||
}
|
||||
},
|
||||
complete: () => {
|
||||
downloading.value = false
|
||||
downLoadPercent.value = 0
|
||||
downloadedSize.value = 0
|
||||
packageFileSize.value = 0
|
||||
downloadTask = null
|
||||
}
|
||||
})
|
||||
|
||||
downloadTask.onProgressUpdate(res => {
|
||||
downLoadPercent.value = res.progress
|
||||
downloadedSize.value = (res.totalBytesWritten / 1024 ** 2).toFixed(2)
|
||||
packageFileSize.value = (res.totalBytesExpectedToWrite / 1024 ** 2).toFixed(2)
|
||||
})
|
||||
}
|
||||
|
||||
function installPackage() {
|
||||
// #ifdef APP-PLUS
|
||||
if (isWGT.value) {
|
||||
installing.value = true
|
||||
}
|
||||
|
||||
plus.runtime.install(
|
||||
tempFilePath.value,
|
||||
{
|
||||
force: false
|
||||
},
|
||||
async () => {
|
||||
installing.value = false
|
||||
installed.value = true
|
||||
|
||||
if (isWGT.value) {
|
||||
if (is_mandatory.value) {
|
||||
uni.showLoading({ icon: 'none', title: '安装成功,正在重启……' })
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
restart()
|
||||
}, 1000)
|
||||
}
|
||||
} else {
|
||||
const localFilePathRecord = uni.getStorageSync(localFilePathKey)
|
||||
uni.setStorageSync(localFilePathKey, {
|
||||
...localFilePathRecord,
|
||||
installed: true
|
||||
})
|
||||
}
|
||||
},
|
||||
async err => {
|
||||
if (installForBeforeFilePath.value) {
|
||||
await deleteSavedFile(installForBeforeFilePath.value)
|
||||
installForBeforeFilePath.value = ''
|
||||
}
|
||||
|
||||
installing.value = false
|
||||
installed.value = false
|
||||
|
||||
uni.showModal({
|
||||
title: `更新失败${isWGT.value ? '' : ',APK文件不存在'},请重新下载`,
|
||||
content: err.message,
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if (!isWGT.value) {
|
||||
uni.navigateBack()
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
function restart() {
|
||||
installed.value = false
|
||||
// #ifdef APP-PLUS
|
||||
plus.runtime.restart()
|
||||
// #endif
|
||||
}
|
||||
|
||||
async function saveFile(tempFilePath, version) {
|
||||
try {
|
||||
const res = await uni.saveFile({ tempFilePath })
|
||||
uni.setStorageSync(localFilePathKey, {
|
||||
version,
|
||||
savedFilePath: res.savedFilePath
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('保存文件失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteSavedFile(filePath) {
|
||||
try {
|
||||
await uni.removeSavedFile({ filePath })
|
||||
uni.removeStorageSync(localFilePathKey)
|
||||
} catch (err) {
|
||||
console.error('删除文件失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
function jumpToAppStore() {
|
||||
plus.runtime.openURL(url.value)
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onLoad(params => {
|
||||
const { local_storage_key } = params
|
||||
if (!local_storage_key) {
|
||||
console.error('local_storage_key为空')
|
||||
// uni.navigateBack()
|
||||
return
|
||||
}
|
||||
|
||||
const localPackageInfo = uni.getStorageSync(local_storage_key)
|
||||
if (!localPackageInfo) {
|
||||
console.error('安装包信息为空')
|
||||
uni.navigateBack()
|
||||
return
|
||||
}
|
||||
|
||||
const requiredKeys = ['version', 'url', 'type']
|
||||
for (const key of requiredKeys) {
|
||||
if (!localPackageInfo[key]) {
|
||||
console.error(`参数 ${key} 必填`)
|
||||
uni.navigateBack()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 更新响应式状态
|
||||
version.value = localPackageInfo.version
|
||||
url.value = localPackageInfo.url
|
||||
type.value = localPackageInfo.type
|
||||
platform.value = localPackageInfo.platform || ''
|
||||
title.value = localPackageInfo.title || '更新日志'
|
||||
contents.value = localPackageInfo.contents || ''
|
||||
is_mandatory.value = localPackageInfo.is_mandatory || false
|
||||
subTitle.value = localPackageInfo.subTitle || '发现新版本'
|
||||
downLoadBtnTextiOS.value = localPackageInfo.downLoadBtnTextiOS || '立即跳转更新'
|
||||
downLoadBtnText.value = localPackageInfo.downLoadBtnText || '立即下载更新'
|
||||
downLoadingText.value = localPackageInfo.downLoadingText || '安装包下载中,请稍后'
|
||||
|
||||
checkLocalStoragePackage()
|
||||
})
|
||||
|
||||
onBackPress(() => {
|
||||
if (is_mandatory.value) return true
|
||||
if (downloadTask) downloadTask.abort()
|
||||
return false
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.botton-radius {
|
||||
border-bottom-left-radius: 15px;
|
||||
border-bottom-right-radius: 15px;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
top: 0;
|
||||
width: 400px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 0 30px;
|
||||
font-family: Source Han Sans CN;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.content-top {
|
||||
position: absolute;
|
||||
top: -55px;
|
||||
left: 0;
|
||||
width: 400px;
|
||||
height: 180px;
|
||||
}
|
||||
|
||||
.content-top-text {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #f8f8fa;
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: 30px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.content-header {
|
||||
padding-top: 80px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.content-body {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #3da7ff;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
height: 90px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.box-des-scroll {
|
||||
box-sizing: border-box;
|
||||
padding: 0 20px;
|
||||
height: 50px;
|
||||
text-align: left;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.box-des {
|
||||
font-size: 16px;
|
||||
color: #000000;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.progress-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.progress {
|
||||
width: 90%;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.close-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
bottom: -70px;
|
||||
left: calc(50% - 20px);
|
||||
}
|
||||
|
||||
.content-button {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
color: #ffffff;
|
||||
border-radius: 20px;
|
||||
margin: 0 10px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background: linear-gradient(to right, #1785ff, #3da7ff);
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user