适配小程序代码结构

This commit is contained in:
zhonghua1
2026-01-20 08:46:36 +08:00
parent 3b169467ac
commit 9c00db8ff5
615 changed files with 62726 additions and 8 deletions

310
custom-tab-bar/index.js Normal file
View File

@@ -0,0 +1,310 @@
Component({
data: {
roleName: '',
roles: [],
currentPath: '',
visibleTabs: [],
allTabs: [
{
key: 'reception',
text: '接待',
pagePath: '/pages/reception/reception',
iconPath: '/static/tabbar/reception.png',
selectedIconPath: '/static/tabbar/reception_active.png',
},
{
key: 'customer',
text: '客户',
pagePath: '/pages/customer/customer',
iconPath: '/static/tabbar/customer.png',
selectedIconPath: '/static/tabbar/customer_active.png',
},
{
key: 'team',
text: '团队',
pagePath: '/pages/team/team',
iconPath: '/static/tabbar/team.png',
selectedIconPath: '/static/tabbar/team_active.png',
},
{
key: 'ucenter',
text: '我的',
pagePath: '/pages/ucenter/ucenter',
iconPath: '/static/tabbar/me.png',
selectedIconPath: '/static/tabbar/me_active.png',
},
{
key: 'meeting_summary',
text: '总结和统计',
pagePath: '/pages/meeting_summary/meeting_summary',
iconPath: '/static/tabbar/insight.png',
selectedIconPath: '/static/tabbar/insight_active.png',
},
{
key: 'furniture_reception',
text: '接待',
pagePath: '/pages/furniture_reception/furniture_reception',
iconPath: '/static/tabbar/reception.png',
selectedIconPath: '/static/tabbar/reception_active.png',
},
{
key: 'common_begin_reception',
text: '开始接待',
pagePath: '/pages/furniture_reception/common_begin_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: 'furniture_top_sales',
text: '销冠',
pagePath: '/pages/furniture_top_sales/furniture_top_sales',
iconPath: '/static/tabbar/insight.png',
selectedIconPath: '/static/tabbar/insight_active.png',
},
],
},
lifetimes: {
attached() {
this.refreshRole();
this.updateActivePath();
// 监听全局事件用于登录后刷新tabBar
// 注意微信小程序不支持uni.$on需要通过其他方式实现
// 这里通过监听storage变化来实现
try {
// 使用定时器定期检查角色变化(登录后)
this._refreshTimer = setInterval(() => {
const storedRole = wx.getStorageSync('backend-role-name') || '';
if (storedRole !== this.data.roleName) {
this.refreshRole();
this.updateActivePath();
}
}, 1000);
} catch (e) {
console.warn('设置tabBar刷新监听失败:', e);
}
},
detached() {
// 清理定时器
if (this._refreshTimer) {
clearInterval(this._refreshTimer);
this._refreshTimer = null;
}
},
},
pageLifetimes: {
show() {
this.refreshRole();
this.updateActivePath();
},
},
methods: {
refreshRole() {
try {
const storedRole = wx.getStorageSync('backend-role-name') || '';
const loginResp = wx.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');
const roleName = hasEdu ? 'speaking_training_teacher' : hasStudent ? 'speaking_training_students' : (roles[0] || '');
this.setData({
roles: roles,
roleName: roleName,
});
// 更新可见的tabs
this.updateVisibleTabs();
console.log('[TabBar][role] storedRole:', storedRole, 'respRole:', respRole, 'normalized:', roles);
} catch (e) {
console.warn('读取角色失败:', e);
}
},
updateActivePath() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const currentPath = currentPage && currentPage.route ? `/${currentPage.route}` : '';
this.setData({
currentPath: currentPath,
});
// 更新可见的tabs
this.updateVisibleTabs();
},
updateVisibleTabs() {
const allowedKeys = this.getAllowedKeys();
console.log('[TabBar][visibleTabs] getAllowedKeys returned:', JSON.stringify(allowedKeys));
const tabMap = {};
this.data.allTabs.forEach(tab => {
tabMap[tab.key] = tab;
});
const otherKeys = [];
let hasUcenter = false;
allowedKeys.forEach(key => {
if (key !== 'ucenter') {
otherKeys.push(key);
} else {
hasUcenter = true;
}
});
const finalKeys = hasUcenter ? [...otherKeys, 'ucenter'] : otherKeys;
const result = finalKeys
.filter(key => tabMap[key])
.map(key => tabMap[key]);
console.log('[TabBar][visibleTabs] final result keys:', result.map(t => t.key));
this.setData({
visibleTabs: result,
});
},
// 外部调用刷新tabBar登录成功后调用
refresh() {
this.refreshRole();
this.updateActivePath();
console.log('[TabBar][refresh] currentPath:', this.data.currentPath, 'roleName:', this.data.roleName, 'visibleKeys:', this.data.visibleTabs.map(t => t.key), 'roles:', this.data.roles);
},
switchTab(e) {
const item = e.currentTarget.dataset.item;
if (!item) return;
this.refreshRole();
const allowedKeys = this.getAllowedKeys();
if (!allowedKeys.includes(item.key)) {
wx.showToast({
title: '当前账号无此模块权限',
icon: 'none',
duration: 1200
});
console.warn('[TabBar][block-switch]', 'key:', item.key, 'path:', item.pagePath, 'allowed:', allowedKeys);
return;
}
if (this.data.currentPath === item.pagePath) return;
const url = item.pagePath.startsWith('/') ? item.pagePath.substring(1) : item.pagePath;
wx.switchTab({
url: url,
success: () => {
console.log('[TabBar][switchTab] success:', url);
this.updateActivePath();
},
fail: (err) => {
console.error('[TabBar][switchTab] fail:', err, 'url:', url);
wx.reLaunch({
url: url,
fail: (err2) => {
console.error('[TabBar][reLaunch] fail:', err2, 'url:', url);
wx.showToast({
title: '页面跳转失败,请检查页面配置',
icon: 'none',
duration: 2000
});
},
success: () => {
this.updateActivePath();
}
});
},
complete: () => {
setTimeout(() => {
this.updateActivePath();
}, 100);
},
});
},
getAllowedKeys() {
const roles = this.data.roles || [];
const isTeacher = roles.includes('speaking_training_teacher');
const isStudent = roles.includes('speaking_training_students');
const isAdmin = roles.includes('admin');
const isMeetingAdmin = roles.includes('meeting_admin');
const isAdminFurniture = roles.includes('admin_furniture');
const meetingTabKeys = ['meeting_summary'];
const removedTabKeys = ['champion', 'workspace'];
const hasFurnitureRole = roles.includes('furniture');
if (isAdminFurniture || hasFurnitureRole) {
const furnitureTabs = ['furniture_reception', 'furniture_customer', 'furniture_top_sales', 'ucenter'];
console.log('[TabBar][allowed] furniture/admin_furniture role ->', furnitureTabs);
return furnitureTabs;
}
if (isMeetingAdmin) {
const meetingAdminTabs = [...meetingTabKeys, 'ucenter'];
console.log('[TabBar][allowed] meeting_admin ->', meetingAdminTabs);
return meetingAdminTabs;
}
if (isAdmin) {
const all = this.data.allTabs
.map((t) => t.key)
.filter((key) => !meetingTabKeys.includes(key) && !['furniture_reception', 'common_begin_reception', 'furniture_customer', 'furniture_top_sales', 'reception', 'customer', ...removedTabKeys].includes(key));
console.log('[TabBar][allowed] admin ->', all);
return all;
}
if (isTeacher && !isAdmin) {
const teacherTabs = ['ucenter'];
console.log('[TabBar][allowed] teacher ->', teacherTabs);
return teacherTabs;
}
if (isStudent && !isAdmin) {
const studentTabs = ['ucenter'];
console.log('[TabBar][allowed] student ->', studentTabs);
return studentTabs;
}
const otherTabs = this.data.allTabs
.map((t) => t.key)
.filter((key) => !['homework', 'edu', 'voice', 'expression', 'furniture_reception', 'common_begin_reception', 'furniture_customer', 'furniture_top_sales', 'reception', 'customer', ...meetingTabKeys, ...removedTabKeys].includes(key));
if (!otherTabs.includes('ucenter')) {
otherTabs.push('ucenter');
}
console.log('[TabBar][allowed] other ->', otherTabs);
return otherTabs;
},
},
observers: {
'roles, currentPath': function() {
this.updateVisibleTabs();
},
},
});

View File

@@ -0,0 +1,5 @@
{
"component": true,
"usingComponents": {}
}

13
custom-tab-bar/index.wxml Normal file
View File

@@ -0,0 +1,13 @@
<view class="tabbar">
<view
wx:for="{{visibleTabs}}"
wx:key="key"
class="tabbar-item {{currentPath === item.pagePath ? 'active' : ''}}"
data-item="{{item}}"
bindtap="switchTab"
>
<image class="tabbar-icon" src="{{currentPath === item.pagePath ? item.selectedIconPath : item.iconPath}}" />
<text class="tabbar-text">{{item.text}}</text>
</view>
</view>

39
custom-tab-bar/index.wxss Normal file
View File

@@ -0,0 +1,39 @@
.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;
}