Commit 01e9aab5 by liangjianmin

feat(mine): 优化登录页版本更新逻辑和样式

- 重构版本检查按钮样式,新增红点提示更新状态
- 使用 UpdateModal 组件替代原有更新提示弹窗
- 实现静默检查更新功能,减少用户干扰
- 新增 compareVersion 函数用于版本号比较
- 封装下载与安装 APK 的通用函数
- 登录页显示当前年份并调整版权样式位置
- 修复本地存储版本号获取和使用逻辑
- 清理旧版本代码,提升代码可维护性和体验
parent 914d32da
...@@ -64,43 +64,48 @@ ...@@ -64,43 +64,48 @@
margin-top: 33rpx; margin-top: 33rpx;
} }
.check-update { .update-btn-box {
position: relative;
margin-top: 33rpx;
width: 495rpx; width: 495rpx;
font-size: 22rpx; margin: 28rpx auto 0;
justify-content: flex-end;
.tip {
color: #1969f9; .update-btn {
} height: 56rpx;
padding: 0 20rpx;
.version { background: transparent;
color: #919399; border: 1rpx solid #cbd5e1;
font-size: 20rpx; border-radius: 28rpx;
margin-left: 6rpx; font-size: 24rpx;
} color: #64748b;
.online_version {
position: relative; position: relative;
&.curr { &:active {
&::after { background: #f1f5f9;
position: absolute; border-color: #1969f9;
top: -14rpx; color: #1969f9;
right: -8rpx; }
width: 10rpx;
height: 10rpx; .red-dot {
border-radius: 50%; position: absolute;
background-color: #f00; top: -4rpx;
content: ''; right: -4rpx;
} width: 14rpx;
height: 14rpx;
background: #ef4444;
border-radius: 50%;
border: 2rpx solid #ffffff;
} }
} }
} }
.copyright { .copyright {
margin-top: 34rpx; position: fixed;
font-size: 15rpx; bottom: 90rpx;
color: #919399; left: 0;
right: 0;
text-align: center;
font-size: 20rpx;
color: #94a3b8;
letter-spacing: 0.5rpx;
} }
} }
\ No newline at end of file
<template>
<uni-popup ref="updatePopup" type="center" :mask-click="false">
<view class="update-modal">
<view class="modal-header">
<view class="header-decoration">
<view class="decoration-circle circle-1"></view>
<view class="decoration-circle circle-2"></view>
<view class="decoration-circle circle-3"></view>
</view>
<view class="icon-wrapper">
<uni-icons type="cloud-download" size="48" color="#ffffff"></uni-icons>
</view>
<text class="title">更新提示</text>
</view>
<view class="modal-body">
<scroll-view scroll-y="true" class="content-scroll">
<view class="content-text">{{ remark }}</view>
</scroll-view>
</view>
<view class="modal-footer">
<view class="btn-cancel" @click="handleCancel">
<text>取消更新</text>
</view>
<view class="btn-confirm" @click="handleConfirm">
<text>确定更新</text>
</view>
</view>
</view>
</uni-popup>
</template>
<script>
import { downloadApk } from '@/util/util.js';
export default {
name: 'UpdateModal',
data() {
return {
remark: '',
downloadUrl: '',
onlineVersion: '',
successCallback: null
};
},
methods: {
/**
* 显示更新弹窗
* @param {string} remark 更新说明
* @param {string} downloadUrl 下载地址
* @param {string} onlineVersion 线上版本号
* @param {function} successCallback 成功回调
*/
show(remark, downloadUrl, onlineVersion, successCallback) {
this.remark = remark || '发现新版本,请更新';
this.downloadUrl = downloadUrl;
this.onlineVersion = onlineVersion;
this.successCallback = successCallback;
this.$refs.updatePopup.open();
},
/**
* 隐藏弹窗
*/
hide() {
this.$refs.updatePopup.close();
},
/**
* 确认更新
*/
handleConfirm() {
this.hide();
downloadApk(this.downloadUrl, this.onlineVersion, this.successCallback);
this.$emit('confirm');
},
/**
* 取消更新
*/
handleCancel() {
this.hide();
this.$emit('cancel');
}
}
};
</script>
<style scoped lang="scss">
.update-modal {
width: 600rpx;
background: #ffffff;
border-radius: 24rpx;
overflow: hidden;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.15);
}
.modal-header {
position: relative;
background: linear-gradient(135deg, #197adb 0%, #1565c0 50%, #0d47a1 100%);
padding: 48rpx 40rpx 40rpx;
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden;
.header-decoration {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
}
.decoration-circle {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.08);
}
.circle-1 {
width: 200rpx;
height: 200rpx;
top: -60rpx;
right: -40rpx;
}
.circle-2 {
width: 120rpx;
height: 120rpx;
top: 40rpx;
left: -30rpx;
}
.circle-3 {
width: 80rpx;
height: 80rpx;
bottom: 20rpx;
right: 60rpx;
}
.icon-wrapper {
position: relative;
z-index: 1;
width: 100rpx;
height: 100rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
}
.title {
position: relative;
z-index: 1;
font-size: 36rpx;
font-weight: 600;
color: #ffffff;
letter-spacing: 2rpx;
}
}
.modal-body {
padding: 40rpx;
background: #ffffff;
.content-scroll {
max-height: 400rpx;
}
.content-text {
font-size: 28rpx;
color: #4a4a4a;
line-height: 1.8;
text-align: left;
white-space: pre-wrap;
word-break: break-word;
}
}
.modal-footer {
display: flex;
padding: 24rpx 32rpx 32rpx;
gap: 20rpx;
border-top: 1rpx solid #f0f0f0;
.btn-cancel,
.btn-confirm {
flex: 1;
height: 76rpx;
border-radius: 38rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 500;
transition: opacity 0.2s ease;
&:active {
opacity: 0.8;
}
}
.btn-cancel {
background: #f7f8fa;
color: #646566;
&:active {
background: #f2f3f5;
}
}
.btn-confirm {
background: #197adb;
color: #ffffff;
&:active {
background: #1565c0;
}
}
}
</style>
<template> <template>
<view class="page-login column rowCenter verCenter"> <view class="page-login column rowCenter verCenter">
<!-- 更新弹窗 -->
<UpdateModal ref="updateModal" @confirm="onUpdateConfirm" />
<view class="logo"> <view class="logo">
<image src="/static/WMS@2x.png" mode="aspectFill"></image> <image src="/static/WMS@2x.png" mode="aspectFill"></image>
</view> </view>
...@@ -20,25 +22,25 @@ ...@@ -20,25 +22,25 @@
<input class="uni-input" password placeholder="请输入账号密码" placeholder-style="color:#919399" v-model="passwd" @input="onKeyInput" confirm-type="go" @confirm="submit()" /> <input class="uni-input" password placeholder="请输入账号密码" placeholder-style="color:#919399" v-model="passwd" @input="onKeyInput" confirm-type="go" @confirm="submit()" />
</view> </view>
<button class="btn row rowCenter verCenter" @click="submit()" :disabled="disabled">登录</button> <button class="btn row rowCenter verCenter" @click="submit()" :disabled="disabled">登录</button>
<view class="check-update row verCenter bothSide" @click="checkUpdate(1)"> <view class="update-btn-box row rowCenter">
<view class="local_version row verCenter"> <view class="update-btn row rowCenter verCenter" @click="checkUpdate()">检查更新
<text class="tip">本地版本</text> <text class="red-dot" v-if="hasUpdate"></text>
<text class="version">{{ local_version || '0.0.0' }}</text>
</view>
<view class="online_version row verCenter" :class="{ curr: active }">
<text class="tip">最新版本</text>
<text class="version">{{ online_version }}</text>
</view> </view>
</view> </view>
<text class="copyright">© 深圳市猎芯科技有限公司</text> <view class="copyright">©{{ currentYear }} 深圳市猎芯科技有限公司 ALL RIGHTS RESERVED</view>
</view> </view>
</template> </template>
<script> <script>
import { API } from '@/util/api.js'; import { API } from '@/util/api.js';
import md5 from '@/util/md5.js'; import md5 from '@/util/md5.js';
import { compareVersion } from '@/util/util.js';
import UpdateModal from '@/components/UpdateModal.vue';
export default { export default {
components: {
UpdateModal
},
data() { data() {
return { return {
index: 0, index: 0,
...@@ -54,10 +56,10 @@ ...@@ -54,10 +56,10 @@
passwd: '', passwd: '',
org_id: 1, org_id: 1,
disabled: false, disabled: false,
isFirst: true, currentYear: new Date().getFullYear(),
online_version: '', //线上后台版本 localVersion: '', // 本地版本号
local_version: uni.getStorageSync('wms_version'), //本地存储的版本 onlineVersion: '', // 线上版本号
active: false //是否更新 hasUpdate: false // 是否有更新
}; };
}, },
onLoad() { onLoad() {
...@@ -67,16 +69,19 @@ ...@@ -67,16 +69,19 @@
uni.removeStorageSync('org_name'); uni.removeStorageSync('org_name');
uni.removeStorageSync('oa_user_email'); uni.removeStorageSync('oa_user_email');
//记住密码 var savedName = uni.getStorageSync('name') || '';
const name = uni.getStorageSync('name') || ''; var savedPasswd = uni.getStorageSync('passwd') || '';
const passwd = uni.getStorageSync('passwd') || '';
this.checkUpdate();
if (name && passwd) { if (savedName && savedPasswd) {
this.name = name; this.name = savedName;
this.passwd = passwd; this.passwd = savedPasswd;
} }
// 获取APP版本号
this.getAppVersion();
// 页面加载时静默检查更新
this.silentCheckUpdate();
}, },
methods: { methods: {
onKeyInput(e) { onKeyInput(e) {
...@@ -91,97 +96,81 @@ ...@@ -91,97 +96,81 @@
this.org_id = this.array[e.detail.value].value; this.org_id = this.array[e.detail.value].value;
this.disabled = false; this.disabled = false;
}, },
/**
* 获取APP版本号
* 使用 plus.runtime.getProperty 获取 manifest.json 中配置的 versionName
*/
getAppVersion() {
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, (info) => {
this.localVersion = info.version || '1.0.0';
});
// #endif
// #ifndef APP-PLUS
this.localVersion = '1.0.0';
// #endif
},
/** /**
* 检查app是否需要更新 * 检查更新(点击触发,带 UI 反馈)
*/ */
checkUpdate(type) { checkUpdate() {
this.request(API.getLatestAppInfo, 'POST', {}, true).then(res => { this.request(API.getLatestAppInfo, 'POST', {}, true).then(res => {
this.online_version = res.data.latest_app_info.wms_version || '0.0.0'; //赋值线上版本
if (res.code === 0) { if (res.code === 0) {
//判断进来第一次 this.onlineVersion = res.data.latest_app_info.wms_version || '0.0.0';
if (this.isFirst && !this.local_version) { var downloadUrl = res.data.latest_app_info.download_url || '';
this.local_version = res.data.latest_app_info.wms_version; //更新本地版本号 var remark = res.data.latest_app_info.remark || '发现新版本,是否更新?';
uni.setStorageSync('wms_version', res.data.latest_app_info.wms_version); //第一次存取本地版本号
//本地版本和线上版本不一样,就提示小红点 if (!compareVersion(this.localVersion, this.onlineVersion)) {
if (this.local_version != this.online_version) { this.hasUpdate = true;
this.active = true; //样式标记 this.$refs.updateModal.show(remark, downloadUrl, this.onlineVersion);
this.isFirst = false;
return false;
}
} else { } else {
if (this.local_version != this.online_version) { this.hasUpdate = false;
this.active = true; //样式标记 uni.showModal({
} title: '版本检查',
} content: `当前已是最新版本\n版本号:v${this.localVersion}`,
//只有点击才会触发 showCancel: false,
if (type) { confirmText: '知道了'
//判断本地版本和线上版本是否一致 });
if (this.local_version != this.online_version) {
//用户更新提示确认
uni.showModal({
title: '更新提示',
content: res.data.latest_app_info.remark,
confirmText: '确定更新',
cancelText: '取消更新',
success: data => {
if (data.confirm) {
this.downloadApk(res.data.latest_app_info.download_url); //开始下载apk文件
console.log('用户点击确定');
} else if (data.cancel) {
console.log('用户点击取消');
}
}
});
} else {
uni.showToast({
title: '已是最新版本',
icon: 'success'
});
}
} }
}
});
},
//下载apk文件
downloadApk(url) {
uni.showLoading({
title: '下载安装文件',
mask: true
});
let dtask = plus.downloader.createDownload(url, {}, (d, status) => {
if (status == 200) {
this.local_version = this.online_version; //更新最新版本号
uni.setStorageSync('wms_version', this.online_version); //更新本地存储最新版本号
uni.hideLoading();
//下载成功后调用安装方法
this.installApk(d.filename);
} else { } else {
uni.showToast({ uni.showToast({
title: '下载失败', title: '检查更新失败',
icon: 'error' icon: 'error'
}); });
console.log('下载失败');
} }
}).catch(() => {
uni.showToast({
title: '网络异常',
icon: 'error'
});
}); });
// 后端要求下载请求必须带 Referer 头
dtask.setRequestHeader('Referer', 'wms-liexin2026');
dtask.start();
}, },
//安装apk文件
installApk(filePath) { /**
plus.runtime.install( * 更新确认回调
filePath, {}, */
() => { onUpdateConfirm() {
console.log('更新成功'); this.hasUpdate = false;
}, },
e => {
uni.showToast({ /**
title: '安装失败', * 静默检查更新(不显示加载和成功提示)
icon: 'error' */
}); silentCheckUpdate() {
console.log('安装失败:' + JSON.stringify(e)); this.request(API.getLatestAppInfo, 'POST', {}, false).then(res => {
if (res.code === 0) {
this.onlineVersion = res.data.latest_app_info.wms_version || '0.0.0';
if (!compareVersion(this.localVersion, this.onlineVersion)) {
this.hasUpdate = true;
} else {
this.hasUpdate = false;
}
} }
); }).catch(err => {
console.log('静默检查更新失败:', err);
});
}, },
/** /**
...@@ -240,7 +229,6 @@ ...@@ -240,7 +229,6 @@
uni.setStorageSync('oa_user_id', res.data.userId); uni.setStorageSync('oa_user_id', res.data.userId);
uni.setStorageSync('company_id', this.org_id); uni.setStorageSync('company_id', this.org_id);
uni.setStorageSync('org_name', this.array[this.index].name); uni.setStorageSync('org_name', this.array[this.index].name);
//必须调用选用组织
this.changeOrgId(); this.changeOrgId();
} else { } else {
this.disabled = true; this.disabled = true;
......
...@@ -96,10 +96,86 @@ const formatDate = (date) => { ...@@ -96,10 +96,86 @@ const formatDate = (date) => {
}; };
/**
* 版本号比较函数
* @param {string} version1 版本号1
* @param {string} version2 版本号2
* @returns {boolean} true: 版本号相等, false: 版本号不相等
*/
const compareVersion = (version1, version2) => {
return version1 === version2;
}
/**
* 下载apk文件
* @param {string} url 下载地址
* @param {string} onlineVersion 线上版本号
* @param {function} successCallback 成功回调
*/
const downloadApk = (url, onlineVersion, successCallback) => {
if (!url) {
uni.showToast({
title: '下载地址无效',
icon: 'error'
});
return;
}
uni.showLoading({
title: '下载安装文件',
mask: true
});
var dtask = plus.downloader.createDownload(url, {}, (d, status) => {
if (status == 200) {
uni.setStorageSync('wms_version', onlineVersion);
uni.hideLoading();
installApk(d.filename);
if (successCallback) successCallback();
} else {
uni.hideLoading();
uni.showToast({
title: '下载失败',
icon: 'error'
});
console.log('下载失败');
}
});
dtask.setRequestHeader('Referer', 'wms-liexin2026');
dtask.start();
}
/**
* 安装apk文件(强制覆盖安装)
* @param {string} filePath 文件路径
*/
const installApk = (filePath) => {
plus.runtime.install(
filePath, { force: true },
() => {
console.log('更新成功');
plus.cache.clear(() => {
console.log('缓存已清空');
});
plus.runtime.restart();
},
e => {
uni.showToast({
title: '安装失败',
icon: 'error'
});
console.log(`安装失败:${JSON.stringify(e)}`);
}
);
}
module.exports = { module.exports = {
request, request,
getPlatform, getPlatform,
createArray, createArray,
getFirstEightChars, getFirstEightChars,
formatDate formatDate,
compareVersion,
downloadApk,
installApk
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment