Files
smartDriveEEUniApp/custom-tab-bar/index.vue
2026-04-05 20:37:10 +08:00

498 lines
17 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 class="tabbar">
<!-- 调试信息显示当前可见的tabs -->
<view style="display: none;">
DEBUG: visibleTabs length: {{ visibleTabs.length }},
tabs: {{ visibleTabs.map(t => t.text).join(', ') }},
furnitureTabs length: {{ furnitureTabs.length }},
furnitureTabs: {{ furnitureTabs.map(t => t.text).join(', ') }},
roles: {{ roles.join(', ') }}
</view>
<!-- 强制显示所有家具角色的tab -->
<view
v-for="item in furnitureTabs"
:key="item.key"
class="tabbar-item"
:class="{ active: currentPath === item.pagePath }"
@click="switchTab(item)"
>
<image class="tabbar-icon" :src="currentPath === item.pagePath ? item.selectedIconPath : item.iconPath" />
<text class="tabbar-text">{{ item.text }}</text>
</view>
</view>
</template>
<script>
// 直接在全局作用域添加调试代码,确保能执行
console.log('CUSTOM TABBAR FILE LOADED - THIS MUST SHOW');
export default {
data() {
return {
roleName: '',
roles: [],
currentPath: '',
allTabs: [
{
key: 'furniture_reception',
text: '接待',
pagePath: '/pages/furniture_reception/furniture_reception',
iconPath: '/static/tabbar/reception.png',
selectedIconPath: '/static/tabbar/reception_active.png',
},
{
key: 'furniture_customer',
text: '客户',
pagePath: 'pages/furniture_customer/furniture_customer',
iconPath: '/static/tabbar/customer.png',
selectedIconPath: '/static/tabbar/customer_active.png',
},
{
key: 'ucenter',
text: '我的',
pagePath: 'pages/ucenter/ucenter',
iconPath: '/static/tabbar/me.png',
selectedIconPath: '/static/tabbar/me_active.png',
},
// 已从导航中移除,但保留代码
// {
// key: 'champion',
// text: '销冠',
// pagePath: '/pages/champion/champion',
// iconPath: '/static/tabbar/insight.png',
// selectedIconPath: '/static/tabbar/insight_active.png',
// },
// {
// key: 'workspace',
// text: '工作台',
// pagePath: '/pages/workspace/workspace',
// iconPath: '/static/tabbar/workspace.png',
// selectedIconPath: '/static/tabbar/workspace_active.png',
// },
{
key: 'ucenter',
text: '我的',
pagePath: '/pages/ucenter/ucenter',
iconPath: '/static/tabbar/me.png',
selectedIconPath: '/static/tabbar/me_active.png',
},
{
key: 'ai_analysis',
text: 'AI分析',
pagePath: '/pages/ai_analysis/ai_analysis',
iconPath: '/static/tabbar/ai_analysis.png',
selectedIconPath: '/static/tabbar/ai_analysis_active.png',
},
{
key: 'meeting_summary',
text: '总结和统计',
pagePath: '/pages-subpackage/meeting_summary/meeting_summary',
iconPath: '/static/tabbar/insight.png',
selectedIconPath: '/static/tabbar/insight_active.png',
},
],
};
},
computed: {
furnitureTabs() {
// 强制返回所有家具角色的tab使用与pages.json相同的路径格式
return [
{
key: 'furniture_reception',
text: '接待',
pagePath: 'pages/furniture_reception/furniture_reception', // 移除开头的/
iconPath: '/static/tabbar/reception.png',
selectedIconPath: '/static/tabbar/reception_active.png',
},
{
key: 'furniture_customer',
text: '客户',
pagePath: 'pages/furniture_customer/furniture_customer', // 移除开头的/
iconPath: '/static/tabbar/customer.png',
selectedIconPath: '/static/tabbar/customer_active.png',
},
{
key: 'ai_analysis',
text: 'AI分析',
pagePath: 'pages/ai_analysis/ai_analysis',
iconPath: '/static/tabbar/ai_analysis.png',
selectedIconPath: '/static/tabbar/ai_analysis_active.png',
},
{
key: 'ucenter',
text: '我的',
pagePath: 'pages/ucenter/ucenter', // 移除开头的/
iconPath: '/static/tabbar/me.png',
selectedIconPath: '/static/tabbar/me_active.png',
}
];
},
visibleTabs() {
console.log('=== CUSTOM TABBAR VISIBLE TABS CALCULATED ===');
console.log('VISIBLE TABS CALC - THIS MUST SHOW IN H5');
// 简化逻辑直接返回家具相关的tabs跳过权限检查
const furnitureKeys = ['furniture_reception', 'furniture_customer', 'ai_analysis', 'ucenter'];
const result = furnitureKeys.map(key => {
return this.allTabs.find(tab => tab.key === key);
}).filter(Boolean);
console.log('[TabBar][visibleTabs] 直接返回家具tabs:', result.map(t => t.key), 'texts:', result.map(t => t.text));
return result;
},
},
created() {
console.log('=== CUSTOM TABBAR COMPONENT CREATED ===');
console.log('CUSTOM TABBAR CREATED - THIS MUST SHOW IN H5');
this.refreshRole();
this.updateActivePath();
},
mounted() {
console.log('=== CUSTOM TABBAR COMPONENT MOUNTED ===');
console.log('CUSTOM TABBAR MOUNTED - THIS MUST SHOW IN CONSOLE');
// 强制执行,不依赖条件编译
this.forceH5TabBarSetup();
// 监听外部刷新事件(登录后、页面切换时可触发)
uni.$on('tabbar:refresh', this.handleExternalRefresh);
// 初始化时同步一次
this.handleExternalRefresh();
// H5平台额外处理页面刷新后的显示问题
// #ifdef H5
// 监听页面显示事件确保刷新后tabBar正确显示
uni.on('onShow', () => {
setTimeout(() => {
console.log('H5: 页面显示事件触发刷新tabBar');
this.handleExternalRefresh();
this.forceH5TabBarSetup();
}, 300);
});
// 监听浏览器刷新事件
if (typeof window !== 'undefined') {
window.addEventListener('load', () => {
setTimeout(() => {
console.log('H5: 页面加载完成刷新tabBar');
this.handleExternalRefresh();
this.forceH5TabBarSetup();
}, 500);
});
}
// #endif
},
beforeDestroy() {
uni.$off('tabbar:refresh', this.handleExternalRefresh);
},
methods: {
refreshRole() {
try {
// 角色来源优先级:单独存储的 roleName > 登录响应里的 roleName
const storedRole = uni.getStorageSync('backend-role-name') || '';
const loginResp = uni.getStorageSync('backend-login-response') || {};
const respRole = loginResp.roleName || '';
// 兼容后端返回大小写/空格/多角色逗号分隔的情况
const normalize = (val) =>
typeof val === 'string'
? val
.split(',')
.map((s) => s.trim().toLowerCase())
.filter(Boolean)
: [];
const roles = [
...normalize(storedRole),
...normalize(respRole),
];
// 角色判定
const hasEdu = roles.includes('speaking_training_teacher');
const hasStudent = roles.includes('speaking_training_students');
this.roles = roles;
this.roleName = hasEdu ? 'speaking_training_teacher' : hasStudent ? 'speaking_training_students' : (roles[0] || '');
console.log('[TabBar][role] storedRole:', storedRole, 'respRole:', respRole, 'normalized:', roles, 'hasEdu:', hasEdu, 'hasStudent:', hasStudent, 'finalRoleName:', this.roleName);
// #ifdef H5
// H5 平台自定义 tabBar 无法生效,仍使用原生 DOM这里额外做一次 DOM 显隐
console.log('[TabBar][H5] refreshRole completed, will call toggleNativeTabs');
// 注意不在refreshRole中直接调用而是在setupH5TabBar中处理
// #endif
} catch (e) {
console.warn('读取角色失败:', e);
}
},
updateActivePath() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
// currentPage.route 不带前导斜杠
this.currentPath = currentPage && currentPage.route ? `/${currentPage.route}` : '';
},
switchTab(item) {
// 切换前刷新一次角色,防止角色变更后仍看到教务/作业等
this.refreshRole();
const allowedKeys = this.getAllowedKeys();
if (!allowedKeys.includes(item.key)) {
uni.showToast({ title: '当前账号无此模块权限', icon: 'none', duration: 1200 });
console.warn('[TabBar][block-switch]', 'key:', item.key, 'path:', item.pagePath, 'allowed:', allowedKeys, 'roles:', this.roles);
return;
}
if (this.currentPath === item.pagePath) return;
// uni.switchTab 需要相对路径(去掉前导斜杠)
const url = item.pagePath.startsWith('/') ? item.pagePath.substring(1) : item.pagePath;
uni.switchTab({
url: url,
success: () => {
console.log('[TabBar][switchTab] success:', url);
this.updateActivePath();
},
fail: (err) => {
console.error('[TabBar][switchTab] fail:', err, 'url:', url);
// 如果 switchTab 失败,尝试使用 reLaunch适用于 tabBar 页面)
uni.reLaunch({
url: url,
fail: (err2) => {
console.error('[TabBar][reLaunch] fail:', err2, 'url:', url);
uni.showToast({
title: '页面跳转失败,请检查页面配置',
icon: 'none',
duration: 2000
});
},
success: () => {
this.updateActivePath();
}
});
},
complete: () => {
// 延迟更新,确保页面切换完成
setTimeout(() => {
this.updateActivePath();
}, 100);
},
});
},
handleExternalRefresh() {
// 每次收到事件时重新读取角色并刷新选中态
this.refreshRole();
this.updateActivePath();
console.log('[TabBar][refresh] currentPath:', this.currentPath, 'roleName:', this.roleName, 'visibleKeys:', this.visibleTabs.map(t => t.key), 'roles:', this.roles);
},
getAllowedKeys() {
console.log('=== CUSTOM TABBAR GET ALLOWED KEYS CALLED ===');
console.log('GET ALLOWED KEYS - 简化版本总是返回家具相关tabs');
// 简化逻辑总是返回家具相关的tabs
const furnitureTabs = ['furniture_reception', 'furniture_customer', 'ai_analysis', 'ucenter'];
console.log('[TabBar][allowed] 简化逻辑 ->', furnitureTabs);
return furnitureTabs;
},
// #ifdef H5
toggleNativeTabs() {
// H5 平台自定义 tabbar 不生效,直接根据角色显隐原生 tabbar 项
// 当前位置顺序(根据 pages.json 中的 tabBar.list 顺序接待、客户、AI分析、我的、团队、总结和统计…
const ORDER = ['furniture_reception', 'furniture_customer', 'ai_analysis', 'ucenter', 'reception', 'customer', 'team', 'meeting_summary', 'common_begin_reception'];
const allowed = this.getAllowedKeys();
// 限制重试次数,防止渲染时机未就绪
this._h5TabRetries = (this._h5TabRetries || 0) + 1;
try {
const items = document.querySelectorAll('.uni-tabbar .uni-tabbar__item');
if (!items || !items.length) {
// 原生 tabbar 可能尚未渲染,稍后重试一次
if (this._h5TabRetries <= 10) {
setTimeout(() => this.toggleNativeTabs(), 150);
} else {
console.warn('[TabBar][H5 DOM] retry limit reached, allowed:', allowed.join(','));
}
return;
}
ORDER.forEach((key, idx) => {
const node = items[idx];
if (!node) return;
node.style.display = allowed.includes(key) ? '' : 'none';
});
console.log('[TabBar][H5 DOM] allowed:', allowed.join(','), 'retries:', this._h5TabRetries);
this._h5TabRetries = 0;
} catch (e) {
console.warn('[TabBar][H5 DOM] toggle tabs failed:', e);
}
},
isInTabBar(pagePath) {
// 检查页面路径是否在原生tabBar配置中
const tabBarList = [
'pages/furniture_reception/furniture_reception',
'pages/furniture_customer/furniture_customer',
'pages/ai_analysis/ai_analysis',
'pages/ucenter/ucenter'
];
const normalizedPath = pagePath.startsWith('/') ? pagePath.substring(1) : pagePath;
const result = tabBarList.includes(normalizedPath);
console.log('[TabBar][isInTabBar]', { pagePath, normalizedPath, tabBarList, result });
return result;
},
forceH5TabBarSetup() {
console.log('=== FORCE H5 TABBAR SETUP CALLED ===');
// 立即执行toggleNativeTabs
setTimeout(() => {
console.log('FORCE: Executing toggleNativeTabs immediately');
this.forceToggleNativeTabs();
}, 100);
// 多次延迟执行
[500, 1000, 2000, 3000, 5000].forEach((delay, index) => {
setTimeout(() => {
console.log(`FORCE: Delayed execution ${index + 1} after ${delay}ms`);
this.forceToggleNativeTabs();
}, delay);
});
},
forceToggleNativeTabs() {
console.log('=== FORCE TOGGLE NATIVE TABS START ===');
try {
// 获取允许的tab
const allowed = this.getAllowedKeys();
console.log('FORCE: Current roles:', this.roles);
console.log('FORCE: Allowed keys:', allowed);
// 简化DOM查找 - 直接查找所有可能的tabBar元素
const allElements = document.querySelectorAll('*');
const tabElements = Array.from(allElements).filter(el =>
el.textContent && (
el.textContent.includes('接待') ||
el.textContent.includes('客户') ||
el.textContent.includes('AI分析') ||
el.textContent.includes('我的')
)
);
console.log('FORCE: Found tab elements with text:', tabElements.length);
tabElements.forEach((el, idx) => {
console.log(`FORCE: Element ${idx}:`, {
tag: el.tagName,
class: el.className,
text: el.textContent,
currentDisplay: el.style.display,
computedDisplay: window.getComputedStyle(el).display
});
});
if (tabElements.length === 0) {
console.warn('FORCE: No tab elements found! Looking for containers...');
// 查找可能的容器
const containers = document.querySelectorAll('div, nav, section');
const possibleContainers = Array.from(containers).filter(el =>
el.children && el.children.length >= 4
);
console.log('FORCE: Possible containers:', possibleContainers.length);
possibleContainers.forEach((container, idx) => {
console.log(`FORCE: Container ${idx}:`, {
tag: container.tagName,
class: container.className,
children: container.children.length
});
});
return;
}
// 按文本内容排序接待、客户、AI分析、我的
const sortedElements = tabElements.sort((a, b) => {
const order = ['接待', '客户', 'AI分析', '我的'];
const aIndex = order.findIndex(text => a.textContent.includes(text));
const bIndex = order.findIndex(text => b.textContent.includes(text));
return aIndex - bIndex;
});
console.log('FORCE: Processing sorted elements...');
// 处理每个元素
sortedElements.forEach((element, index) => {
const keyMap = ['furniture_reception', 'furniture_customer', 'ai_analysis', 'ucenter'];
const key = keyMap[index];
const shouldShow = allowed.includes(key);
console.log(`FORCE: Processing ${key} (${element.textContent}): shouldShow=${shouldShow}`);
if (shouldShow) {
element.style.display = '';
element.style.visibility = 'visible';
// 确保父元素也可见
let parent = element.parentElement;
while (parent) {
parent.style.display = '';
parent.style.visibility = 'visible';
parent = parent.parentElement;
}
console.log(`FORCE: SHOWED ${key}`);
} else {
element.style.display = 'none';
element.style.visibility = 'hidden';
console.log(`FORCE: HID ${key}`);
}
});
console.log('=== FORCE TOGGLE NATIVE TABS END ===');
} catch (e) {
console.error('FORCE: Error in forceToggleNativeTabs:', e);
}
},
// #endif
},
};
</script>
<style>
.tabbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 52px;
background: #ffffff;
border-top: 1px solid #e5e7eb;
display: flex;
align-items: center;
justify-content: space-around;
padding-bottom: env(safe-area-inset-bottom);
}
.tabbar-item {
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #7a7e83;
font-size: 12px;
}
.tabbar-item.active {
color: #007aff;
}
.tabbar-icon {
width: 24px;
height: 24px;
margin-bottom: 4px;
}
.tabbar-text {
line-height: 16px;
}
</style>