470 lines
12 KiB
Vue
470 lines
12 KiB
Vue
<template>
|
||
<view class="contentStyle">
|
||
<scroll-view class="page" scroll-y>
|
||
<view class="setting-item" v-for="(item, index) in settingList" :key="index" @click="onItemClick(item)">
|
||
<text class="item-title">{{ item.title }}</text>
|
||
|
||
<view class="item-right" v-if="item.type === 'text'">
|
||
<text :class="item.valueClass || 'item-value'">{{ item.value }}</text>
|
||
<view class="item-arrow"></view>
|
||
</view>
|
||
|
||
<switch class="no-cross-switch" v-else-if="item.type === 'switch'" :checked="item.checked"
|
||
@change="onSwitchChange(item, $event)" />
|
||
|
||
<view class="item-arrow" v-else></view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<view class="bottom-btn">
|
||
<button class="logout-btn" @click="logout">退出登录</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
ref,
|
||
onMounted
|
||
} from 'vue'
|
||
import {
|
||
authLogout, getUserProfile, getUserNotify, changeUserNotify, getAppVersion, checkAppUpdate, postUpdateLog
|
||
} from '/pageSubPack/api/apiSub.js'
|
||
|
||
//
|
||
const cacheSize = ref(0)
|
||
const currentVersion = ref('1.0.0')
|
||
const currentVersionCode = ref(1)
|
||
const settingList = ref([{
|
||
title: '更改手机号码',
|
||
type: 'text',
|
||
value: ''
|
||
},
|
||
{
|
||
title: '修改密码',
|
||
type: 'arrow'
|
||
},
|
||
{
|
||
title: '消息通知',
|
||
type: 'switch',
|
||
checked: false
|
||
},
|
||
{
|
||
title: '清除缓存',
|
||
type: 'text',
|
||
value: '9.2M'
|
||
},
|
||
{
|
||
title: '注销账号',
|
||
type: 'arrow'
|
||
},
|
||
// {
|
||
// title: '升级版本',
|
||
// type: 'text',
|
||
// value: '当前版本 1.0.0',
|
||
// valueClass: 'item-version'
|
||
// }
|
||
])
|
||
|
||
// 格式化字节大小
|
||
const formatSize = (bytes) => {
|
||
if (!bytes || bytes === 0) return '0B'
|
||
const k = 1024
|
||
const sizes = ['B', 'KB', 'M', 'G']
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + sizes[i]
|
||
}
|
||
|
||
// 获取真实缓存大小
|
||
const getCacheSizeData = () => {
|
||
return new Promise((resolve) => {
|
||
// #ifdef APP-PLUS
|
||
// App 端获取完整缓存(含图片、文件等)
|
||
plus.cache.calculate((size) => {
|
||
resolve(formatSize(size))
|
||
})
|
||
// #endif
|
||
// #ifndef APP-PLUS
|
||
// 小程序/H5 端只能获取 storage 缓存
|
||
const info = uni.getStorageInfoSync()
|
||
const size = (info.currentSize || 0) * 1024 // currentSize 单位 KB
|
||
resolve(formatSize(size))
|
||
// #endif
|
||
})
|
||
}
|
||
|
||
// 获取当前运行版本号
|
||
const initCurrentVersion = () => {
|
||
// #ifdef APP-PLUS
|
||
currentVersion.value = plus.runtime.version || '1.0.0'
|
||
currentVersionCode.value = plus.runtime.versionCode || 1
|
||
// #endif
|
||
// #ifndef APP-PLUS
|
||
const manifest = uni.getAppAuthorizeSetting ? uni.getAppAuthorizeSetting() : null
|
||
if (manifest && manifest.version) {
|
||
currentVersion.value = manifest.version
|
||
}
|
||
// #endif
|
||
if (settingList.value[5]) {
|
||
settingList.value[5].value = '当前版本 ' + currentVersion.value
|
||
}
|
||
}
|
||
|
||
// 版本号比较:v1 > v2 返回 1,v1 = v2 返回 0,v1 < v2 返回 -1
|
||
const compareVersion = (v1, v2) => {
|
||
const arr1 = v1.split('.').map(Number)
|
||
const arr2 = v2.split('.').map(Number)
|
||
const len = Math.max(arr1.length, arr2.length)
|
||
for (let i = 0; i < len; i++) {
|
||
const n1 = arr1[i] || 0
|
||
const n2 = arr2[i] || 0
|
||
if (n1 > n2) return 1
|
||
if (n1 < n2) return -1
|
||
}
|
||
return 0
|
||
}
|
||
|
||
// 跳转到应用商店更新
|
||
const openAppStore = (downloadUrl, platform) => {
|
||
// #ifdef APP-PLUS
|
||
if (downloadUrl) {
|
||
// 优先使用服务端返回的应用商店地址
|
||
const pkgName = plus.runtime.appid || ''
|
||
console.log('包名---------',pkgName)
|
||
// 无论返回哪种 downloadUrl,都在后面拼接包名
|
||
const finalUrl = downloadUrl + pkgName
|
||
plus.runtime.openURL(finalUrl)
|
||
} else if (platform === 'ios') {
|
||
// iOS: 打开 App Store(需在 Apple Developer 后台获取 Apple ID)
|
||
plus.runtime.openURL('itms-apps://itunes.apple.com/app/id' + plus.runtime.appid)
|
||
} else {
|
||
// Android: 通过 market 协议唤起手机自带应用商店
|
||
const packageName = plus.runtime.appid || ''
|
||
plus.runtime.openURL('market://details?id=' + packageName, () => {
|
||
// market 协议失败时的回调,提示用户手动前往应用商店
|
||
uni.showToast({ title: '请前往应用商店更新', icon: 'none' })
|
||
})
|
||
}
|
||
// #endif
|
||
// #ifndef APP-PLUS
|
||
uni.showToast({ title: '请在应用商店更新', icon: 'none' })
|
||
// #endif
|
||
}
|
||
|
||
// 检查版本更新
|
||
const checkVersionUpdate = async () => {
|
||
uni.showLoading({ title: '检查中...', mask: true })
|
||
// #ifdef APP-PLUS
|
||
const channel = plus.runtime.channel; // 云打包自动写入,自定义包为空
|
||
// const channel = 'xiaomi'
|
||
// console.log('channel',channel)
|
||
// #endif
|
||
|
||
try {
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
const platform = systemInfo.platform === 'android' ? 'android':'ios'
|
||
const appChannel = 'resident'
|
||
// const channel = 'xiaomi'
|
||
|
||
// 1. 查询最新版本
|
||
const versionRes = await getAppVersion(platform, channel, appChannel)
|
||
console.log('查询最新版本',versionRes.data)
|
||
if (versionRes.code === 200 && versionRes.data) {
|
||
const latestVersion = versionRes.data.versionName || ''
|
||
const latestVersionCode = versionRes.data.versionCode || 0
|
||
|
||
// 2. 调 checkAppUpdate 检查是否需要更新
|
||
const checkRes = await checkAppUpdate({
|
||
platform: platform,
|
||
channel: channel,
|
||
appChannel: appChannel,
|
||
currentVersionCode: currentVersionCode.value
|
||
})
|
||
uni.hideLoading()
|
||
|
||
if (checkRes.code === 200 && checkRes.data) {
|
||
console.log('是否需要更新',checkRes.data)
|
||
const needUpdate = checkRes.data.needUpdate !== false
|
||
if (needUpdate) {
|
||
// 如果版本号一致,直接提示已是最新版本
|
||
if (compareVersion(currentVersion.value, latestVersion) >= 0) {
|
||
uni.showToast({ title: '已是最新版本', icon: 'success' })
|
||
return
|
||
}
|
||
const updateType = checkRes.data.updateType || versionRes.data.updateType || 'optional'
|
||
const isForce = updateType === 'force'
|
||
const downloadUrl = versionRes.data.downloadUrl || ''
|
||
uni.showModal({
|
||
title: isForce ? '强制更新' : '发现新版本',
|
||
content: `当前版本:${currentVersion.value}\n最新版本:${latestVersion}${versionRes.data.releaseNotes ? '\n\n更新内容:' + (versionRes.data.releaseNotes) : ''}`,
|
||
showCancel: !isForce,
|
||
confirmText: '立即更新',
|
||
cancelText: '稍后',
|
||
success: (modalRes) => {
|
||
if (modalRes.confirm) {
|
||
// 记录更新日志
|
||
const userId = uni.getStorageSync('userId')
|
||
if (userId) {
|
||
postUpdateLog({
|
||
userId: userId,
|
||
platform: platform,
|
||
fromVersion: currentVersionCode.value,
|
||
toVersion: latestVersionCode
|
||
})
|
||
}
|
||
// 跳转到应用商店更新
|
||
openAppStore(downloadUrl, platform)
|
||
} else if (isForce && !modalRes.confirm) {
|
||
// 强制更新时用户点取消,退出应用
|
||
// #ifdef APP-PLUS
|
||
plus.runtime.quit()
|
||
// #endif
|
||
}
|
||
}
|
||
})
|
||
} else {
|
||
uni.showToast({ title: '已是最新版本', icon: 'success' })
|
||
}
|
||
} else {
|
||
uni.showToast({ title: '检查更新失败1', icon: 'none' })
|
||
}
|
||
} else {
|
||
uni.hideLoading()
|
||
uni.showToast({ title: '检查更新失败2', icon: 'none' })
|
||
}
|
||
} catch (err) {
|
||
uni.hideLoading()
|
||
uni.showToast({ title: err.msg || '检查更新失败', icon: 'none' })
|
||
}
|
||
}
|
||
|
||
//
|
||
const onItemClick = (item) => {
|
||
if (item.title == '更改手机号码') {
|
||
uni.navigateTo({
|
||
url: '/pageSubPack/my/changePhone'
|
||
});
|
||
} else if (item.title == '修改密码') {
|
||
uni.navigateTo({
|
||
url: '/pageSubPack/my/changePwd'
|
||
});
|
||
} else if (item.title == '清除缓存') {
|
||
// 保存登录相关数据,清完恢复
|
||
const preserveKeys = ['token', 'userId', 'currentVillageId', 'hasShowGuide', 'push_cid']
|
||
const saved = {}
|
||
preserveKeys.forEach(key => { saved[key] = uni.getStorageSync(key) })
|
||
uni.clearStorageSync()
|
||
preserveKeys.forEach(key => { if (saved[key]) uni.setStorageSync(key, saved[key]) })
|
||
// #ifdef APP-PLUS
|
||
plus.cache.clear(() => {})
|
||
// #endif
|
||
settingList.value[3].value = '0B'
|
||
uni.showLoading({
|
||
title: '清除中...',
|
||
mask: true
|
||
});
|
||
setTimeout(() => {
|
||
uni.showToast({
|
||
title: '清除成功',
|
||
icon: 'success'
|
||
});
|
||
}, 1000);
|
||
setTimeout(() => {
|
||
uni.hideLoading();
|
||
}, 2500);
|
||
} else if (item.title == '注销账号') {
|
||
uni.navigateTo({
|
||
url: '/pageSubPack/my/deleteAccount'
|
||
});
|
||
} else if (item.title == '升级版本') {
|
||
checkVersionUpdate()
|
||
}
|
||
}
|
||
|
||
const logout = () => {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定要退出当前账号吗?',
|
||
success: (res) => {
|
||
if (!res.confirm) return
|
||
uni.showLoading({ title: '退出中...', mask: true })
|
||
|
||
const clearAndGo = () => {
|
||
const uid = uni.getStorageSync('userId') || ''
|
||
uni.removeStorageSync('token')
|
||
uni.removeStorageSync('userId')
|
||
uni.removeStorageSync('currentVillageId')
|
||
uni.removeStorageSync('home_cache_' + uid)
|
||
uni.removeStorageSync('home_cache')
|
||
// 清除小区相关缓存,防止切换账号后显示上一个账号的小区和公告
|
||
uni.removeStorageSync('communityName')
|
||
uni.removeStorageSync('communityId')
|
||
uni.removeStorageSync('needReloadUserInfo')
|
||
uni.hideLoading()
|
||
uni.hideToast()
|
||
uni.reLaunch({ url: '/pageSubPack/loginSub/login?mode=pwd' })
|
||
}
|
||
|
||
authLogout().then(res => {
|
||
if (res.code === 200) {
|
||
uni.hideLoading()
|
||
uni.showToast({ title: '退出成功', icon: 'success' })
|
||
setTimeout(clearAndGo, 1500)
|
||
} else {
|
||
clearAndGo()
|
||
}
|
||
}).catch(err => {
|
||
console.log(err)
|
||
clearAndGo()
|
||
})
|
||
}
|
||
})
|
||
}
|
||
|
||
const onSwitchChange = (item, e) => {
|
||
const checked = e.detail.value
|
||
const notifyEnabled = checked ? '1' : '0'
|
||
changeUserNotify({ notifyEnabled }).then(res => {
|
||
if (res.code === 200) {
|
||
item.checked = checked
|
||
} else {
|
||
uni.showToast({ title: res.msg || '更新失败', icon: 'none' })
|
||
item.checked = !checked
|
||
}
|
||
}).catch(() => {
|
||
uni.showToast({ title: '更新失败', icon: 'none' })
|
||
item.checked = !checked
|
||
})
|
||
}
|
||
|
||
|
||
onMounted(async () => {
|
||
initCurrentVersion()
|
||
settingList.value[3].value = await getCacheSizeData()
|
||
getUserProfile().then(res => {
|
||
if (res.code === 200 && res.data) {
|
||
const phone = res.data.phone || ''
|
||
settingList.value[0].value = phone
|
||
}
|
||
})
|
||
getUserNotify().then(res => {
|
||
if (res.code === 200 && res.data) {
|
||
settingList.value[2].checked = res.data.notifyEnabled === '1'
|
||
}
|
||
})
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
background: #f9f9f9;
|
||
}
|
||
</style>
|
||
|
||
<style lang="scss" scoped>
|
||
.contentStyle {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
background-color: #f9f9f9;
|
||
}
|
||
|
||
.page {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 0 40rpx 140rpx;
|
||
box-sizing: border-box;
|
||
background-color: #fff;
|
||
}
|
||
|
||
.bottom-btn {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
padding: 20rpx 30rpx;
|
||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||
background-color: #fff;
|
||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
|
||
}
|
||
</style>
|
||
|
||
<style scoped>
|
||
.setting-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
border-bottom: 2rpx solid #f0f0f0;
|
||
}
|
||
|
||
.item-title {
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.item-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
}
|
||
|
||
.item-value {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.item-version {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.item-arrow {
|
||
width: 10rpx;
|
||
height: 10rpx;
|
||
border-top: 2rpx solid #999;
|
||
border-right: 2rpx solid #999;
|
||
transform: rotate(45deg);
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
.logout-btn {
|
||
width: 100%;
|
||
height: 96rpx;
|
||
line-height: 96rpx;
|
||
text-align: center;
|
||
font-size: 32rpx;
|
||
border-radius: 12rpx;
|
||
color: #666;
|
||
background-color: #F3F3F3;
|
||
/* box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06); */
|
||
}
|
||
|
||
.logout-btn:active {
|
||
background-color: #f5f5f5;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
</style>
|
||
|
||
<style>
|
||
::v-deep .uni-switch-input:before {
|
||
background-color: #cccccd !important;
|
||
}
|
||
|
||
.no-cross-switch::before {
|
||
display: none !important;
|
||
}
|
||
|
||
.no-cross-switch {
|
||
transform: scale(0.85);
|
||
border-radius: 50rpx !important;
|
||
}
|
||
|
||
.no-cross-switch>>>.uni-switch-input-checked {
|
||
background-color: #007aff !important;
|
||
}
|
||
</style>
|