Files
smartDriveEEUniApp/App.vue

700 lines
19 KiB
Vue
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
// 移除自动URL隐藏初始化避免页面刷新时的路由冲突
// 设置全局路由拦截,检查登录状态
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()
// #ifdef H5
// H5平台刷新自定义tabBar确保显示状态正确
setTimeout(() => {
try {
uni.$emit('tabbar:refresh');
console.log('已发送tabbar刷新事件');
} catch (e) {
console.warn('发送tabbar刷新事件失败:', e);
}
}, 500);
// #endif
},
onHide: function() {
console.log('App Hide')
// #ifdef MP-WEIXIN
this.stopTabBarMonitor();
// #endif
// 清理URL保护定时器
if (this.urlProtectionInterval) {
clearInterval(this.urlProtectionInterval);
this.urlProtectionInterval = null;
}
},
onError: function(msg) {
console.error('[App Global Error]:', msg);
},
methods: {
/**
* 完美的URL隐藏系统 - 专为uni-app H5设计
*/
setupPerfectUrlHiding() {
// #ifdef H5
console.log('🎯 初始化完美URL隐藏系统');
// 路径映射:将长路径映射为短路径
this.urlPathMap = {
'pages/furniture_customer/furniture_customer': '/customer',
'pages/furniture_reception/furniture_reception': '/reception',
'pages/furniture_top_sales/furniture_top_sales': '/top-sales',
'pages/ucenter/ucenter': '/profile'
};
// 反向映射:将短路径映射回长路径(用于路由解析)
this.reversePathMap = {};
Object.keys(this.urlPathMap).forEach(key => {
this.reversePathMap[this.urlPathMap[key]] = key;
});
// 初始化标志
this.urlHidingInitialized = false;
// 延迟初始化避免干扰uni-app初始化过程
setTimeout(() => {
console.log('⏰ 3秒延迟结束开始检查页面栈');
// 再次检查页面栈,确保页面已加载
const pages = getCurrentPages();
console.log('📊 检查页面栈长度:', pages.length);
if (pages.length > 0) {
console.log('✅ 页面栈不为空开始初始化URL隐藏');
this.initializeUrlHiding();
} else {
console.log('⏳ 页面栈仍为空,继续等待');
// 如果页面栈仍为空,再等一会儿
setTimeout(() => {
console.log('⏰ 额外2秒等待结束');
const finalPages = getCurrentPages();
console.log('📊 最终页面栈长度:', finalPages.length);
this.initializeUrlHiding(); // 无论如何都初始化
}, 2000);
}
}, 3000);
console.log('✅ URL隐藏系统初始化完成');
// #endif
},
/**
* 初始化URL隐藏功能
*/
initializeUrlHiding() {
// #ifdef H5
console.log('🚀 开始初始化URL隐藏功能');
// 标记为已初始化
this.urlHidingInitialized = true;
// 1. 立即尝试隐藏当前页面的URL
this.hideCurrentPageUrl();
// 2. 监听页面切换事件
this.setupPageChangeListener();
// 3. 监听浏览器导航
this.setupBrowserNavigationListener();
// 4. 设置URL保护机制
this.setupUrlProtection();
console.log('🎉 URL隐藏功能初始化完毕');
// #endif
},
/**
* 隐藏当前页面的URL显示
*/
hideCurrentPageUrl(retryCount = 0) {
// #ifdef H5
// 只有在系统完全初始化后才执行URL隐藏
if (!this.urlHidingInitialized) {
console.log('⏳ URL隐藏系统尚未初始化跳过');
return;
}
try {
const pages = getCurrentPages();
if (pages.length === 0) {
if (retryCount < 5) { // 最多重试5次
console.log(`📄 页面栈为空,重试 ${retryCount + 1}/5`);
setTimeout(() => this.hideCurrentPageUrl(retryCount + 1), 300);
} else {
console.log('📄 页面栈仍然为空停止URL隐藏');
}
return;
}
const currentPage = pages[pages.length - 1];
const currentPath = currentPage.route;
// 确保页面路径有效
if (!currentPath || currentPath === '') {
console.log('⚠️ 页面路径无效,等待页面完全加载');
if (retryCount < 3) {
setTimeout(() => this.hideCurrentPageUrl(retryCount + 1), 200);
}
return;
}
console.log('📍 当前页面路径:', currentPath);
if (this.urlPathMap[currentPath]) {
const shortPath = this.urlPathMap[currentPath];
const currentPathname = window.location.pathname;
// 检查当前URL是否已经是正确的短路径
if (currentPathname !== shortPath) {
console.log(`🔄 URL隐藏: ${currentPathname} -> ${shortPath}`);
// 使用history.replaceState替换URL但保持uni-app的路由正常工作
const newUrl = `${window.location.origin}${shortPath}`;
window.history.replaceState(null, '', newUrl);
console.log('✅ URL隐藏成功');
} else {
console.log(' URL已经是隐藏状态');
}
} else {
console.log('⚠️ 当前路径无需隐藏:', currentPath);
}
} catch (error) {
console.warn('❌ URL隐藏失败:', error);
}
// #endif
},
/**
* 设置页面切换监听器
*/
setupPageChangeListener() {
// #ifdef H5
// 监听uni-app的页面显示事件
if (typeof uni !== 'undefined' && uni.on) {
uni.on('onShow', () => {
console.log('📱 页面显示事件触发延迟检查URL隐藏');
// 延迟执行,确保页面完全稳定
setTimeout(() => {
this.hideCurrentPageUrl();
}, 500);
});
}
// 监听popstate事件浏览器前进后退
window.addEventListener('popstate', () => {
console.log('🔙 浏览器前进后退事件');
setTimeout(() => {
this.handleUrlChange();
}, 100);
});
// #endif
},
/**
* 处理URL变化在history模式下
*/
handleUrlChange() {
// #ifdef H5
console.log('🎯 处理URL变化');
// 检查当前URL是否需要转换
const currentPathname = window.location.pathname;
const shortPaths = Object.values(this.urlPathMap);
// 如果当前路径是短路径,不需要处理
if (shortPaths.includes(currentPathname)) {
console.log('✅ URL已经是短路径格式');
return;
}
// 检查是否是uni-app的路由变化
setTimeout(() => {
this.hideCurrentPageUrl();
}, 200);
// #endif
},
/**
* 设置浏览器导航监听器
*/
setupBrowserNavigationListener() {
// #ifdef H5
// 监听前进后退按钮已经在上面的popstate监听器中处理
console.log('🔄 浏览器导航监听器已设置');
// #endif
},
/**
* 设置URL保护机制防止意外的URL变化
*/
setupUrlProtection() {
// #ifdef H5
// 定期检查并维护URL的隐藏状态
this.urlProtectionInterval = setInterval(() => {
try {
const pages = getCurrentPages();
if (pages.length > 0) {
const currentPage = pages[pages.length - 1];
const currentPath = currentPage.route;
if (this.urlPathMap[currentPath]) {
const expectedPath = this.urlPathMap[currentPath];
const currentPathname = window.location.pathname;
if (currentPathname !== expectedPath) {
console.log('🛡️ 检测到URL异常重新隐藏');
const newUrl = `${window.location.origin}${expectedPath}`;
window.history.replaceState(null, '', newUrl);
}
}
}
} catch (error) {
console.warn('🛡️ URL保护检查失败:', error);
}
}, 3000); // 每3秒检查一次
console.log('🛡️ URL保护机制已启动');
// #endif
},
/**
* 设置全局路由拦截
*/
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>