Files
smartDriveEEUniApp/App.vue
2026-02-01 09:49:48 +08:00

456 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view id="app">
<!-- 加载状态 -->
<view v-if="showLoading" class="loading-container">
<view class="loading-spinner">
<view class="spinner"></view>
<text class="loading-text">正在加载...</text>
</view>
</view>
<!-- 页面内容 -->
<router-view v-else />
</view>
</template>
<script>
// 强制引用这些按需加载的文件,确保它们被打包
// #ifdef MP-WEIXIN
import '@/uni_modules/uni-id-pages/common/check-id-card.js';
// #endif
import initApp from '@/common/appInit.js';
import openApp from '@/common/openApp.js';
// #ifdef H5
openApp() //创建在h5端全局悬浮引导用户下载app的功能
// #endif
// uni-agree 已在子包中,主包不再引用(避免跨包引用问题)
// import checkIsAgree from '@/pages-subpackage/uni-agree/utils/uni-agree.js';
import uniIdPageInit from '@/common/uni-id-pages-init.js';
import { store, mutations } from '@/common/store.js';
export default {
globalData: {
searchText: '',
appVersion: {},
config: {},
$i18n: {},
$t: {}
},
data() {
return {
showLoading: true // 初始显示加载状态
};
},
onLaunch: async function() {
console.log('App Launch')
// 设置全局角色信息
this.setGlobalRoleInfo();
// 初始化当前页面路径
this.updateCurrentPath();
// 安全地设置 i18n确保在 i18n 初始化完成后再赋值
// 使用 try-catch 防止访问未初始化的 i18n 对象
try {
if (this.$i18n) {
this.globalData.$i18n = this.$i18n
} else {
// 如果 i18n 还未初始化,延迟设置
setTimeout(() => {
try {
if (this.$i18n) {
this.globalData.$i18n = this.$i18n
}
} catch (e) {
console.warn('[App] i18n 初始化延迟设置失败:', e)
}
}, 100)
}
} catch (e) {
console.warn('[App] i18n 初始化失败:', e)
}
this.globalData.$t = str => {
try {
return this.$t ? this.$t(str) : str
} catch (e) {
return str
}
}
initApp();
await uniIdPageInit()
// #ifdef H5
// H5平台不需要额外的tabBar处理使用原生tabBar
// #endif
// 设置全局路由拦截,检查登录状态
this.setupRouteInterceptor()
// #ifdef MP-WEIXIN
// 微信小程序:等待页面完全加载后再检查登录状态,避免扫码进入时空白页面
// 延迟检查,确保页面栈已初始化且页面已完全加载
setTimeout(() => {
// 检查页面是否已完全加载
const checkPageLoaded = () => {
const pages = getCurrentPages()
if (pages.length > 0 && pages[pages.length - 1].route) {
// 页面已加载,检查登录状态
if (!this.isLoggedIn()) {
this.showLoading = false // 隐藏加载状态
this.redirectToLogin()
} else {
// 已登录,检查当前页面
this.checkCurrentPageLogin()
// 延迟隐藏加载状态,确保页面渲染完成
setTimeout(() => {
this.showLoading = false
}, 200)
}
} else {
// 页面还没加载完成,继续等待
setTimeout(checkPageLoaded, 100)
}
}
checkPageLoaded()
}, 500)
// #endif
// #ifndef MP-WEIXIN
// 其他平台:延迟检查登录状态
setTimeout(() => {
this.checkCurrentPageLogin()
// 延迟隐藏加载状态,确保页面渲染完成
setTimeout(() => {
this.showLoading = false
}, 200)
}, 100)
// #endif
// #ifdef APP
//checkIsAgree(); APP端暂时先用原生默认生成的。目前自定义方式启动vue界面时原生层已经请求了部分权限这并不符合国家的法规
// #endif
// #ifdef H5
// checkIsAgree(); // 默认不开启。目前全球,仅欧盟国家有网页端同意隐私权限的需要。如果需要可以自己去掉注视后生效
// #endif
// #ifdef APP-PLUS
//idfa有需要的用户在应用首次启动时自己获取存储到storage中
/*var idfa = '';
var manager = plus.ios.invoke('ASIdentifierManager', 'sharedManager');
if(plus.ios.invoke(manager, 'isAdvertisingTrackingEnabled')){
var identifier = plus.ios.invoke(manager, 'advertisingIdentifier');
idfa = plus.ios.invoke(identifier, 'UUIDString');
plus.ios.deleteObject(identifier);
}
plus.ios.deleteObject(manager);
console.log('idfa = '+idfa);*/
// #endif
},
onShow: function() {
console.log('App Show')
// 每次应用显示时同步用户信息解决store初始化时uni未准备好导致的问题
try {
mutations.syncUserInfoFromStorage();
} catch (e) {
// 静默失败
}
// 每次应用显示时也检查当前页面是否需要登录
this.checkCurrentPageLogin()
},
onHide: function() {
console.log('App Hide')
// #ifdef MP-WEIXIN
this.stopTabBarMonitor();
// #endif
},
onError: function(msg) {
console.error('[App Global Error]:', msg);
},
methods: {
/**
* 设置全局路由拦截
*/
setupRouteInterceptor() {
const app = this
// 拦截路由跳转(适用于所有平台)
uni.addInterceptor('navigateTo', {
invoke: (options) => {
if (app.shouldRedirectToLogin(options.url)) {
app.redirectToLogin()
return false // 阻止跳转
}
}
})
uni.addInterceptor('redirectTo', {
invoke: (options) => {
if (app.shouldRedirectToLogin(options.url)) {
app.redirectToLogin()
return false // 阻止跳转
}
}
})
uni.addInterceptor('switchTab', {
invoke: (options) => {
if (app.shouldRedirectToLogin(options.url)) {
app.redirectToLogin()
return false // 阻止跳转
}
}
})
uni.addInterceptor('reLaunch', {
invoke: (options) => {
if (app.shouldRedirectToLogin(options.url)) {
app.redirectToLogin()
return false // 阻止跳转
}
}
})
},
/**
* 判断是否需要跳转到登录页
*/
shouldRedirectToLogin(url) {
if (!url) return false
// 排除登录相关页面
const excludePaths = [
'/uni_modules/uni-id-pages/pages/login',
'/uni_modules/uni-id-pages/pages/register',
'/uni_modules/uni-id-pages/pages/retrieve'
]
// 检查是否在排除列表中
for (let excludePath of excludePaths) {
if (url.includes(excludePath)) {
return false
}
}
// 检查登录状态
return !this.isLoggedIn()
},
/**
* 检查是否已登录
*/
isLoggedIn() {
// 优先检查后端登录态
const backendToken = uni.getStorageSync('backend-token')
if (backendToken) {
return true
}
// 其次检查 uni-id 的登录态
return store.hasLogin
},
/**
* 跳转到登录页
*/
redirectToLogin() {
const loginPage = '/uni_modules/uni-id-pages/pages/login/login-withpwd'
const pages = getCurrentPages()
// 如果当前已经在登录页,不重复跳转
if (pages.length > 0) {
const currentPage = pages[pages.length - 1]
if (currentPage.route && currentPage.route.includes('login')) {
return
}
}
// #ifdef MP-WEIXIN
// 微信小程序登录页在subPackage中必须使用reLaunch
// redirectTo不能用于跳转到subPackage页面只能用于主包页面
uni.reLaunch({
url: loginPage,
success: () => {
console.log('跳转登录页成功')
},
fail: (err) => {
console.error('跳转登录页失败:', err)
// 如果reLaunch失败可能是路径问题尝试不带前导斜杠
const loginPageWithoutSlash = loginPage.startsWith('/') ? loginPage.substring(1) : loginPage
uni.reLaunch({
url: loginPageWithoutSlash,
fail: (err2) => {
console.error('跳转登录页失败(重试):', err2)
}
})
}
})
// #endif
// #ifndef MP-WEIXIN
// 其他平台使用reLaunch
uni.reLaunch({
url: loginPage,
fail: (err) => {
console.error('跳转登录页失败:', err)
}
})
// #endif
},
/**
* 更新当前页面路径(用于更新 tabBar 等)
*/
updateCurrentPath() {
try {
const pages = getCurrentPages();
if (pages.length > 0) {
const currentPage = pages[pages.length - 1];
if (currentPage && currentPage.route) {
const currentPath = `/${currentPage.route}`;
// 更新 tabBar 的当前路径(如果存在)
try {
const app = getApp({ allowDefault: true });
if (app && app.globalData) {
const tabBar = app.globalData.tabBarInstance;
if (tabBar && typeof tabBar.updateCurrentPath === 'function') {
tabBar.updateCurrentPath(currentPath);
}
}
} catch (e) {
// 静默失败
}
}
}
} catch (e) {
// 静默失败,不影响应用启动
}
},
/**
* 检查当前页面是否需要登录
*/
setGlobalRoleInfo() {
try {
const tokenData = uni.getStorageSync('uni_id_token');
if (tokenData && tokenData.roles) {
console.log('[App] Setting global role info:', tokenData.roles);
this.globalData.roles = tokenData.roles;
this.globalData.roleName = tokenData.roleName || '';
// 通知自定义 tabBar 更新
try {
const app = getApp({ allowDefault: true });
if (app && app.globalData) {
const tabBar = app.globalData.tabBarInstance;
if (tabBar) {
tabBar.refreshRole();
}
}
} catch (e) {
// 静默失败
}
}
} catch (e) {
console.warn('[App] Failed to set global role info:', e);
}
},
checkCurrentPageLogin() {
const pages = getCurrentPages()
if (pages.length === 0) {
// #ifdef MP-WEIXIN
// 微信小程序:如果页面栈为空,延迟重试
setTimeout(() => {
this.checkCurrentPageLogin()
}, 200)
// #endif
return
}
const currentPage = pages[pages.length - 1]
if (!currentPage || !currentPage.route) {
// #ifdef MP-WEIXIN
// 微信小程序:如果页面信息不完整,延迟重试
setTimeout(() => {
this.checkCurrentPageLogin()
}, 200)
// #endif
return
}
const currentRoute = '/' + currentPage.route
// 排除登录相关页面
if (currentRoute.includes('/uni_modules/uni-id-pages/pages/login') ||
currentRoute.includes('/uni_modules/uni-id-pages/pages/register') ||
currentRoute.includes('/uni_modules/uni-id-pages/pages/retrieve')) {
return
}
// 如果未登录,跳转到登录页
if (!this.isLoggedIn()) {
// #ifdef MP-WEIXIN
// 微信小程序确保页面已完全加载后再跳转使用setTimeout代替$nextTick
setTimeout(() => {
this.redirectToLogin()
}, 100)
// #endif
// #ifndef MP-WEIXIN
this.redirectToLogin()
// #endif
}
}
}
}
</script>
<style>
/*每个页面公共css */
/* 加载状态样式 */
.loading-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #f8f8f8;
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.loading-spinner {
display: flex;
flex-direction: column;
align-items: center;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #e0e0e0;
border-top: 4px solid #007AFF;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 16px;
}
.loading-text {
color: #666;
font-size: 14px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>