541 lines
13 KiB
Plaintext
541 lines
13 KiB
Plaintext
|
<template>
|
|||
|
<view class="mask flex-center">
|
|||
|
<view class="content">
|
|||
|
<view class="content-top">
|
|||
|
<text class="content-top-text">{{title}}</text>
|
|||
|
<image class="content-top-image" mode="widthFix"
|
|||
|
src="/uni_modules/uni-upgrade-center-app/static/app/bg_top.png"></image>
|
|||
|
</view>
|
|||
|
|
|||
|
<view class="content-space"></view>
|
|||
|
|
|||
|
<view class="content-body">
|
|||
|
<view class="content-body-title">
|
|||
|
<text class="text title">{{subTitle}}</text>
|
|||
|
<text class="text version">v{{version}}</text>
|
|||
|
</view>
|
|||
|
<view class="body">
|
|||
|
<scroll-view class="box-des-scroll" scroll-y="true">
|
|||
|
<text class="text 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" :percent="downLoadPercent" activeColor="#3DA7FF"
|
|||
|
:show-info="true" :stroke-width="10" />
|
|||
|
<view
|
|||
|
style="width:100%;display: flex;justify-content: space-around;flex-direction: row;">
|
|||
|
<text class="text" style="font-size: 14px;">{{downLoadingText}}</text>
|
|||
|
<text class="text"
|
|||
|
style="font-size: 14px;">({{downloadedSize}}/{{packageFileSize}}M)</text>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
|
|||
|
<button v-else class="content-button" @click="updateApp">
|
|||
|
{{downLoadBtnText}}
|
|||
|
</button>
|
|||
|
</template>
|
|||
|
|
|||
|
<button v-else-if="downloadSuccess && !installed" class="content-button" :loading="installing"
|
|||
|
:disabled="installing" @click="installPackage">
|
|||
|
{{installing ? '正在安装……' : '下载完成,立即安装'}}
|
|||
|
</button>
|
|||
|
|
|||
|
<button v-else-if="installed" class="content-button" @click="installPackage">
|
|||
|
安装未完成,点击安装
|
|||
|
</button>
|
|||
|
</template>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
|
|||
|
<view class="content-bottom">
|
|||
|
<image v-if="!is_mandatory" class="close-img" mode="widthFix"
|
|||
|
src="/uni_modules/uni-upgrade-center-app/static/app/app_update_close.png" @click="closeUpdate">
|
|||
|
</image>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
import { openSchema as utsOpenSchema } from '@/uni_modules/uts-openSchema'
|
|||
|
import { createNotificationProgress, cancelNotificationProgress, finishNotificationProgress } from '@/uni_modules/uts-progressNotification'
|
|||
|
import { type CreateNotificationProgressOptions, type FinishNotificationProgressOptions } from '@/uni_modules/uts-progressNotification/utssdk/interface.uts'
|
|||
|
import { UniUpgradeCenterResult, StoreListItem } from '../../utils/call-check-version'
|
|||
|
import { platform_iOS, platform_Android } from '../../utils/utils'
|
|||
|
const requiredKey = ['version', 'url', 'type']
|
|||
|
let downloadTask : DownloadTask | null = null;
|
|||
|
let openSchemePromise : Promise<boolean> | null = null;
|
|||
|
|
|||
|
const openSchema = (url : string) : Promise<boolean> => new Promise<boolean>((resolve, reject) => {
|
|||
|
try {
|
|||
|
utsOpenSchema(url)
|
|||
|
resolve(true)
|
|||
|
} catch (e) {
|
|||
|
reject(false)
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
export default {
|
|||
|
data() {
|
|||
|
return {
|
|||
|
// 从之前下载安装
|
|||
|
installForBeforeFilePath: '',
|
|||
|
|
|||
|
// 安装
|
|||
|
installed: false,
|
|||
|
installing: false,
|
|||
|
|
|||
|
// 下载
|
|||
|
downloadSuccess: false,
|
|||
|
downloading: false,
|
|||
|
|
|||
|
downLoadPercent: 0,
|
|||
|
downloadedSize: 0,
|
|||
|
packageFileSize: 0,
|
|||
|
|
|||
|
tempFilePath: '', // 要安装的本地包地址
|
|||
|
|
|||
|
// 默认安装包信息
|
|||
|
title: '更新日志',
|
|||
|
contents: '',
|
|||
|
version: '',
|
|||
|
is_mandatory: false,
|
|||
|
url: "",
|
|||
|
platform: [] as string[],
|
|||
|
store_list: null as StoreListItem[] | null,
|
|||
|
|
|||
|
// 可自定义属性
|
|||
|
subTitle: '发现新版本',
|
|||
|
downLoadBtnTextiOS: '立即跳转更新',
|
|||
|
downLoadBtnText: '立即下载更新',
|
|||
|
downLoadingText: '安装包下载中,请稍后'
|
|||
|
}
|
|||
|
},
|
|||
|
computed: {
|
|||
|
isiOS() : boolean {
|
|||
|
return this.platform.includes(platform_iOS);
|
|||
|
},
|
|||
|
isAndroid() : boolean {
|
|||
|
return this.platform.includes(platform_Android);
|
|||
|
},
|
|||
|
needNotificationProgress() : boolean {
|
|||
|
return this.isAndroid && !this.is_mandatory
|
|||
|
}
|
|||
|
},
|
|||
|
onUnload() {
|
|||
|
if (this.needNotificationProgress) {
|
|||
|
cancelNotificationProgress()
|
|||
|
}
|
|||
|
},
|
|||
|
onLoad(onLoadOptions: OnLoadOptions) {
|
|||
|
const local_storage_key: string | null = onLoadOptions['local_storage_key']
|
|||
|
if (local_storage_key == null) {
|
|||
|
console.error('local_storage_key为空,请检查后重试')
|
|||
|
this.closePopup()
|
|||
|
return;
|
|||
|
};
|
|||
|
|
|||
|
const localPackageInfo = uni.getStorageSync(local_storage_key);
|
|||
|
if (localPackageInfo == null) {
|
|||
|
console.error('安装包信息为空,请检查后重试')
|
|||
|
this.closePopup()
|
|||
|
return;
|
|||
|
};
|
|||
|
|
|||
|
this.show(JSON.parse<UniUpgradeCenterResult>(JSON.stringify(localPackageInfo)) as UniUpgradeCenterResult)
|
|||
|
},
|
|||
|
onBackPress(options : OnBackPressOptions) : boolean | null {
|
|||
|
if (this.is_mandatory) return true
|
|||
|
if (!this.needNotificationProgress) {
|
|||
|
if (downloadTask !== null) {
|
|||
|
downloadTask!.abort()
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
},
|
|||
|
methods: {
|
|||
|
jumpToAppStore() {
|
|||
|
openSchema(this.url)
|
|||
|
},
|
|||
|
show(localPackageInfo : UniUpgradeCenterResult | null) {
|
|||
|
if (localPackageInfo === null) return;
|
|||
|
|
|||
|
for (let key in localPackageInfo) {
|
|||
|
if (requiredKey.indexOf(key) != -1 && localPackageInfo[key] === null) {
|
|||
|
console.error(`参数 ${key} 必填,请检查后重试`)
|
|||
|
this.closePopup()
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.title = localPackageInfo.title
|
|||
|
this.url = localPackageInfo.url
|
|||
|
this.contents = localPackageInfo.contents
|
|||
|
this.is_mandatory = localPackageInfo.is_mandatory
|
|||
|
this.platform = localPackageInfo.platform
|
|||
|
this.version = localPackageInfo.version
|
|||
|
this.store_list = localPackageInfo.store_list
|
|||
|
},
|
|||
|
askAbortDownload() {
|
|||
|
uni.showModal({
|
|||
|
title: '是否取消下载?',
|
|||
|
cancelText: '否',
|
|||
|
confirmText: '是',
|
|||
|
success: res => {
|
|||
|
if (res.confirm) {
|
|||
|
if (downloadTask !== null) downloadTask!.abort()
|
|||
|
if (this.needNotificationProgress) {
|
|||
|
cancelNotificationProgress();
|
|||
|
}
|
|||
|
this.closePopup()
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
},
|
|||
|
closeUpdate() {
|
|||
|
if (this.downloading && !this.needNotificationProgress) {
|
|||
|
this.askAbortDownload()
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
this.closePopup()
|
|||
|
},
|
|||
|
closePopup() {
|
|||
|
this.downloadSuccess = false
|
|||
|
this.downloading = false
|
|||
|
this.downLoadPercent = 0
|
|||
|
this.downloadedSize = 0
|
|||
|
this.packageFileSize = 0
|
|||
|
this.tempFilePath = ''
|
|||
|
|
|||
|
this.installing = false
|
|||
|
this.installed = false
|
|||
|
|
|||
|
uni.closeDialogPage({
|
|||
|
dialogPage: this.$page
|
|||
|
})
|
|||
|
},
|
|||
|
updateApp() {
|
|||
|
const checkStoreScheme = this.checkStoreScheme()
|
|||
|
if (checkStoreScheme !== null) {
|
|||
|
checkStoreScheme
|
|||
|
.then(_ => { })
|
|||
|
.catch(() => { this.downloadPackage() })
|
|||
|
.finally(() => {
|
|||
|
openSchemePromise = null
|
|||
|
})
|
|||
|
} else { this.downloadPackage() }
|
|||
|
},
|
|||
|
// 跳转应用商店
|
|||
|
checkStoreScheme() : Promise<boolean> | null {
|
|||
|
if (this.store_list !== null) {
|
|||
|
const storeList : StoreListItem[] = this.store_list!.filter((item : StoreListItem) : boolean => item.enable)
|
|||
|
if (storeList.length > 0) {
|
|||
|
if (openSchemePromise === null) {
|
|||
|
openSchemePromise = Promise.reject() as Promise<boolean>
|
|||
|
}
|
|||
|
storeList
|
|||
|
.sort((cur : StoreListItem, next : StoreListItem) : number => next.priority - cur.priority)
|
|||
|
.map((item : StoreListItem) : string => item.scheme)
|
|||
|
.reduce((promise : Promise<boolean>, cur : string) : Promise<boolean> => {
|
|||
|
openSchemePromise = promise.catch<boolean>(() : Promise<boolean> => openSchema(cur))
|
|||
|
return openSchemePromise!
|
|||
|
}, openSchemePromise!)
|
|||
|
return openSchemePromise!
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return null
|
|||
|
},
|
|||
|
downloadPackage() {
|
|||
|
//下载包
|
|||
|
downloadTask = uni.downloadFile({
|
|||
|
url: this.url,
|
|||
|
success: res => {
|
|||
|
if (res.statusCode == 200) {
|
|||
|
this.tempFilePath = res.tempFilePath
|
|||
|
this.downLoadComplete()
|
|||
|
} else {
|
|||
|
console.log('downloadFile err: ', res);
|
|||
|
this.downloadFail()
|
|||
|
}
|
|||
|
},
|
|||
|
fail: err => {
|
|||
|
console.log('downloadFile err: ', err);
|
|||
|
this.downloadFail()
|
|||
|
}
|
|||
|
});
|
|||
|
if (downloadTask !== null) {
|
|||
|
this.downloading = true;
|
|||
|
if (this.needNotificationProgress) {
|
|||
|
this.closePopup()
|
|||
|
}
|
|||
|
downloadTask!.onProgressUpdate(res => {
|
|||
|
this.downLoadPercent = parseFloat(res.progress.toFixed(0));
|
|||
|
this.downloadedSize = parseFloat((res.totalBytesWritten / Math.pow(1024, 2)).toFixed(2));
|
|||
|
this.packageFileSize = parseFloat((res.totalBytesExpectedToWrite / Math.pow(1024, 2)).toFixed(2));
|
|||
|
|
|||
|
if (this.needNotificationProgress) {
|
|||
|
createNotificationProgress({
|
|||
|
title: "升级中心正在下载安装包……",
|
|||
|
content: `${this.downLoadPercent}%`,
|
|||
|
progress: this.downLoadPercent,
|
|||
|
onClick: () => {
|
|||
|
if (!this.downloadSuccess) {
|
|||
|
this.askAbortDownload()
|
|||
|
}
|
|||
|
}
|
|||
|
} as CreateNotificationProgressOptions)
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
},
|
|||
|
downloadFail() {
|
|||
|
const errMsg = '下载失败,请点击重试'
|
|||
|
|
|||
|
this.downloadSuccess = false;
|
|||
|
this.downloading = false;
|
|||
|
|
|||
|
this.downLoadPercent = 0;
|
|||
|
this.downloadedSize = 0;
|
|||
|
this.packageFileSize = 0;
|
|||
|
|
|||
|
this.downLoadBtnText = errMsg
|
|||
|
|
|||
|
downloadTask = null;
|
|||
|
|
|||
|
if (this.needNotificationProgress) {
|
|||
|
finishNotificationProgress({
|
|||
|
title: '升级包下载失败',
|
|||
|
content: '请重新检查更新',
|
|||
|
onClick() { }
|
|||
|
} as FinishNotificationProgressOptions);
|
|||
|
}
|
|||
|
},
|
|||
|
downLoadComplete() {
|
|||
|
this.downloadSuccess = true;
|
|||
|
this.downloading = false;
|
|||
|
|
|||
|
this.downLoadPercent = 0
|
|||
|
this.downloadedSize = 0
|
|||
|
this.packageFileSize = 0
|
|||
|
|
|||
|
downloadTask = null;
|
|||
|
|
|||
|
if (this.needNotificationProgress) {
|
|||
|
finishNotificationProgress({
|
|||
|
title: "安装升级包",
|
|||
|
content: "下载完成",
|
|||
|
onClick() { }
|
|||
|
} as FinishNotificationProgressOptions)
|
|||
|
|
|||
|
this.installPackage();
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 强制更新,直接安装
|
|||
|
if (this.is_mandatory) {
|
|||
|
this.installPackage();
|
|||
|
}
|
|||
|
},
|
|||
|
installPackage() {
|
|||
|
this.installing = true;
|
|||
|
// #ifdef APP
|
|||
|
uni.installApk({
|
|||
|
filePath: this.tempFilePath,
|
|||
|
success: _ => {
|
|||
|
this.installing = false;
|
|||
|
this.installed = true;
|
|||
|
},
|
|||
|
fail: err => {
|
|||
|
console.error('installApk fail', err);
|
|||
|
// 安装失败需要重新下载安装包
|
|||
|
this.installing = false;
|
|||
|
this.installed = false;
|
|||
|
|
|||
|
uni.showModal({
|
|||
|
title: '更新失败,请重新下载',
|
|||
|
content: `uni.installApk 错误码 ${err.errCode}`,
|
|||
|
showCancel: false
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// 安装跳出覆盖安装,此处直接返回上一页
|
|||
|
if (!this.is_mandatory) {
|
|||
|
uni.navigateBack()
|
|||
|
}
|
|||
|
// #endif
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style>
|
|||
|
.flex-center {
|
|||
|
/* #ifndef APP-NVUE | UNI-APP-X */
|
|||
|
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, .65);
|
|||
|
}
|
|||
|
|
|||
|
.content {
|
|||
|
position: relative;
|
|||
|
top: 0;
|
|||
|
width: 600rpx;
|
|||
|
background-color: transparent;
|
|||
|
}
|
|||
|
|
|||
|
.text {
|
|||
|
font-family: Source Han Sans CN;
|
|||
|
}
|
|||
|
|
|||
|
.content-top {
|
|||
|
width: 100%;
|
|||
|
border-bottom-color: #fff;
|
|||
|
border-bottom-width: 15px;
|
|||
|
border-bottom-style: solid;
|
|||
|
}
|
|||
|
|
|||
|
.content-space {
|
|||
|
width: 100%;
|
|||
|
height: 120px;
|
|||
|
background-color: #fff;
|
|||
|
position: absolute;
|
|||
|
top: 30%;
|
|||
|
z-index: -1;
|
|||
|
}
|
|||
|
|
|||
|
.content-top-image {
|
|||
|
width: 100%;
|
|||
|
position: relative;
|
|||
|
bottom: -10%;
|
|||
|
}
|
|||
|
|
|||
|
.content-top-text {
|
|||
|
font-size: 22px;
|
|||
|
font-weight: bold;
|
|||
|
color: #F8F8FA;
|
|||
|
position: absolute;
|
|||
|
width: 65%;
|
|||
|
top: 50%;
|
|||
|
left: 25px;
|
|||
|
z-index: 1;
|
|||
|
}
|
|||
|
|
|||
|
.content-body {
|
|||
|
box-sizing: border-box;
|
|||
|
padding: 0 25px;
|
|||
|
width: 100%;
|
|||
|
background-color: #fff;
|
|||
|
border-bottom-left-radius: 15px;
|
|||
|
border-bottom-right-radius: 15px;
|
|||
|
}
|
|||
|
|
|||
|
.content-body-title {
|
|||
|
flex-direction: row;
|
|||
|
align-items: center;
|
|||
|
}
|
|||
|
|
|||
|
.content-body-title .version {
|
|||
|
padding-left: 10px;
|
|||
|
color: #fff;
|
|||
|
font-size: 10px;
|
|||
|
margin-left: 5px;
|
|||
|
padding: 2px 4px;
|
|||
|
border-radius: 10px;
|
|||
|
background: #50aefd;
|
|||
|
}
|
|||
|
|
|||
|
.title {
|
|||
|
font-size: 16px;
|
|||
|
font-weight: bold;
|
|||
|
color: #3DA7FF;
|
|||
|
line-height: 38px;
|
|||
|
}
|
|||
|
|
|||
|
.footer {
|
|||
|
height: 75px;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: space-around;
|
|||
|
}
|
|||
|
|
|||
|
.box-des-scroll {
|
|||
|
box-sizing: border-box;
|
|||
|
padding: 0 15px;
|
|||
|
height: 100px;
|
|||
|
}
|
|||
|
|
|||
|
.box-des {
|
|||
|
font-size: 13px;
|
|||
|
color: #000000;
|
|||
|
line-height: 25px;
|
|||
|
}
|
|||
|
|
|||
|
.progress-box {
|
|||
|
width: 100%;
|
|||
|
}
|
|||
|
|
|||
|
.progress {
|
|||
|
width: 90%;
|
|||
|
height: 20px;
|
|||
|
}
|
|||
|
|
|||
|
.content-bottom {
|
|||
|
height: 75px;
|
|||
|
}
|
|||
|
|
|||
|
.close-img {
|
|||
|
width: 35px;
|
|||
|
height: 35px;
|
|||
|
z-index: 1000;
|
|||
|
position: relative;
|
|||
|
bottom: -30%;
|
|||
|
left: 50%;
|
|||
|
margin-left: -17px;
|
|||
|
}
|
|||
|
|
|||
|
.content-button {
|
|||
|
width: 100%;
|
|||
|
height: 40px;
|
|||
|
line-height: 40px;
|
|||
|
|
|||
|
font-size: 15px;
|
|||
|
font-weight: 400;
|
|||
|
border-radius: 20px;
|
|||
|
border: none;
|
|||
|
color: #fff;
|
|||
|
|
|||
|
text-align: center;
|
|||
|
|
|||
|
background-color: #1785ff;
|
|||
|
}
|
|||
|
|
|||
|
.flex-column {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
align-items: center;
|
|||
|
}
|
|||
|
</style>
|