第一次提交:小程序前端最新版本
This commit is contained in:
194
custom-tab-bar/index.js
Normal file
194
custom-tab-bar/index.js
Normal file
@@ -0,0 +1,194 @@
|
||||
// custom-tab-bar/index.js
|
||||
const app = getApp();
|
||||
|
||||
const roleCfg = {
|
||||
normal: {
|
||||
name: '点单老板',
|
||||
defaultPage: '/pages/index/index',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/index/index', text: '商城', iconPath: '/images/zhuye.png', selectedIconPath: '/images/zhuye.png' },
|
||||
{ pagePath: 'pages/fenlei/fenlei', text: '分类', iconPath: '/images/fenlei.png', selectedIconPath: '/images/fenlei.png' },
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/wode/wode', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }
|
||||
]
|
||||
},
|
||||
dashou: {
|
||||
name: '打手',
|
||||
defaultPage: '/pages/jiedan/jiedan',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/jiedan/jiedan', text: '接单池', iconPath: '/images/jiedanchi.png', selectedIconPath: '/images/jiedanchi.png' },
|
||||
{ pagePath: 'pages/dashoudingdan/dashoudingdan', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' },
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/dashouduan/dashouduan', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }
|
||||
]
|
||||
},
|
||||
shangjia: {
|
||||
name: '商家',
|
||||
defaultPage: 'pages/sjdingdan/sjdingdan',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/sjdingdan/sjdingdan', text: '订单', iconPath: '/images/dingdan.png', selectedIconPath: '/images/dingdan.png' },
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/shangjiaduan/shangjiaduan', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }
|
||||
]
|
||||
},
|
||||
guanshi: {
|
||||
name: '管事',
|
||||
defaultPage: '/pages/guanshiduan/guanshiduan',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/guanshiduan/guanshiduan', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }
|
||||
]
|
||||
},
|
||||
zuzhang: {
|
||||
name: '组长',
|
||||
defaultPage: '/pages/zuzhangduan/zuzhangduan',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/zuzhangduan/zuzhangduan', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }
|
||||
]
|
||||
},
|
||||
kaoheguan: {
|
||||
name: '考核官',
|
||||
defaultPage: '/pages/kaoheguan/kaoheguan',
|
||||
tabList: [
|
||||
{ pagePath: 'pages/xiaoxi/xiaoxi', text: '消息', iconPath: '/images/xiaoxi.png', selectedIconPath: '/images/xiaoxi.png' },
|
||||
{ pagePath: 'pages/kaoheguan/kaoheguan', text: '我的', iconPath: '/images/wode.png', selectedIconPath: '/images/wode.png' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
Component({
|
||||
data: {
|
||||
selectedIndex: 0,
|
||||
tabList: [],
|
||||
currentRole: 'normal',
|
||||
showRolePicker: false,
|
||||
availableRoles: [],
|
||||
badgeText: ''
|
||||
},
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.refresh();
|
||||
this._badgeListener = (data) => {
|
||||
if (data.badgeText !== undefined) {
|
||||
this.setData({ badgeText: data.badgeText });
|
||||
}
|
||||
};
|
||||
app.on('tabBarBadgeChanged', this._badgeListener);
|
||||
},
|
||||
detached() {
|
||||
if (this._badgeListener) {
|
||||
app.off('tabBarBadgeChanged', this._badgeListener);
|
||||
}
|
||||
}
|
||||
},
|
||||
pageLifetimes: {
|
||||
show() {
|
||||
this.refresh();
|
||||
const globalBadge = app.globalData.messageManager?.tabBarBadgeText || '';
|
||||
if (this.data.badgeText !== globalBadge) {
|
||||
this.setData({ badgeText: globalBadge });
|
||||
}
|
||||
this._syncUnreadWithDebounce();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_syncUnreadWithDebounce() {
|
||||
if (this._syncTimer) clearTimeout(this._syncTimer);
|
||||
this._syncTimer = setTimeout(() => {
|
||||
if (app && app.loadConversations) {
|
||||
app.loadConversations();
|
||||
}
|
||||
}, 300);
|
||||
},
|
||||
|
||||
refresh() {
|
||||
const role = app.globalData.currentRole || 'normal';
|
||||
let cfg = roleCfg[role];
|
||||
if (!cfg) return;
|
||||
|
||||
// 打手身份下,如果 isJinpai=1,悄悄把“我的”页面换成金牌页面
|
||||
if (role === 'dashou') {
|
||||
const isJinpai = wx.getStorageSync('isJinpai') === 1;
|
||||
if (isJinpai) {
|
||||
cfg = {
|
||||
...cfg,
|
||||
tabList: cfg.tabList.map(item => {
|
||||
if (item.pagePath === 'pages/dashouduan/dashouduan') {
|
||||
return { ...item, pagePath: 'pages/jinpaids/jinpaids' };
|
||||
}
|
||||
return { ...item };
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const list = cfg.tabList.map((v, i) => ({ ...v, index: i }));
|
||||
const pages = getCurrentPages();
|
||||
const curRoute = pages.length ? pages[pages.length - 1].route : '';
|
||||
let idx = list.findIndex(t => t.pagePath === curRoute);
|
||||
if (idx === -1) idx = 0;
|
||||
const avail = this._getAvail();
|
||||
this.setData({ currentRole: role, tabList: list, selectedIndex: idx, availableRoles: avail });
|
||||
},
|
||||
|
||||
_getAvail() {
|
||||
const arr = [{ key: 'normal', name: '点单老板' }];
|
||||
if (wx.getStorageSync('dashoustatus') === 1) arr.push({ key: 'dashou', name: '打手' });
|
||||
if (wx.getStorageSync('shangjiastatus') === 1) arr.push({ key: 'shangjia', name: '商家' });
|
||||
if (wx.getStorageSync('guanshistatus') === 1) arr.push({ key: 'guanshi', name: '管事' });
|
||||
if (wx.getStorageSync('zuzhangstatus') === 1) arr.push({ key: 'zuzhang', name: '组长' });
|
||||
if (wx.getStorageSync('kaoheguanstatus') === 1) arr.push({ key: 'kaoheguan', name: '考核官' });
|
||||
return arr;
|
||||
},
|
||||
|
||||
toggleRolePicker() {
|
||||
this.setData({ showRolePicker: !this.data.showRolePicker });
|
||||
},
|
||||
|
||||
async selectRole(e) {
|
||||
const newRole = e.currentTarget.dataset.role;
|
||||
if (newRole === this.data.currentRole) {
|
||||
this.setData({ showRolePicker: false });
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ showRolePicker: false });
|
||||
|
||||
// 1. 立即更新角色并保存
|
||||
app.globalData.currentRole = newRole;
|
||||
wx.setStorageSync('currentRole', newRole);
|
||||
|
||||
// 2. 🔥 确定跳转页面:所有角色都去“我的”页面
|
||||
let targetPage = '';
|
||||
if (newRole === 'dashou') {
|
||||
// 打手需要根据金牌状态决定跳转
|
||||
const isJinpai = wx.getStorageSync('isJinpai') === 1;
|
||||
targetPage = isJinpai ? '/pages/jinpaids/jinpaids' : '/pages/dashouduan/dashouduan';
|
||||
} else {
|
||||
// 其他角色直接取 tabList 最后一个页面
|
||||
const cfg = roleCfg[newRole];
|
||||
if (cfg && cfg.tabList.length > 0) {
|
||||
targetPage = '/' + cfg.tabList[cfg.tabList.length - 1].pagePath;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 跳转
|
||||
if (targetPage) {
|
||||
wx.reLaunch({ url: targetPage });
|
||||
}
|
||||
|
||||
// 4. 后台异步切换连接
|
||||
app.switchRoleAndReconnect(newRole).catch(err => {
|
||||
console.error('后台切换连接失败:', err);
|
||||
});
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const path = e.currentTarget.dataset.path;
|
||||
const idx = e.currentTarget.dataset.index;
|
||||
if (idx === this.data.selectedIndex) return;
|
||||
wx.redirectTo({ url: '/' + path });
|
||||
}
|
||||
}
|
||||
});
|
||||
4
custom-tab-bar/index.json
Normal file
4
custom-tab-bar/index.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
42
custom-tab-bar/index.wxml
Normal file
42
custom-tab-bar/index.wxml
Normal file
@@ -0,0 +1,42 @@
|
||||
<view class="custom-tab-bar">
|
||||
<view class="bar-row">
|
||||
<!-- 左侧椭圆身份按钮 -->
|
||||
<view class="role-switch-btn" catchtap="toggleRolePicker">
|
||||
<image class="role-switch-icon" src="/images/role-switch.png" mode="aspectFit" />
|
||||
<text class="role-switch-text">切换</text>
|
||||
</view>
|
||||
|
||||
<!-- 右侧纯黑闪光胶囊 -->
|
||||
<view class="tab-capsule">
|
||||
<block wx:for="{{tabList}}" wx:key="index">
|
||||
<view class="tab-item {{selectedIndex === index ? 'active' : ''}}"
|
||||
data-path="{{item.pagePath}}"
|
||||
data-index="{{index}}"
|
||||
catchtap="switchTab">
|
||||
<!-- 🔥 根据页面路径判断是否显示角标,不再写死 index -->
|
||||
<view class="badge-container" wx:if="{{item.pagePath === 'pages/xiaoxi/xiaoxi' && badgeText}}">
|
||||
<view class="tab-badge">{{badgeText}}</view>
|
||||
</view>
|
||||
<image class="tab-icon" src="{{selectedIndex === index ? item.selectedIconPath : item.iconPath}}" mode="aspectFit" />
|
||||
<text class="tab-text">{{item.text}}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 身份选择弹窗 -->
|
||||
<view wx:if="{{showRolePicker}}" class="picker-mask" catchtap="toggleRolePicker"></view>
|
||||
<view wx:if="{{showRolePicker}}" class="picker-panel">
|
||||
<view class="picker-header">
|
||||
<text class="picker-title">切换身份</text>
|
||||
<text class="picker-close" catchtap="toggleRolePicker">✕</text>
|
||||
</view>
|
||||
<block wx:for="{{availableRoles}}" wx:key="key">
|
||||
<view class="role-option {{currentRole === item.key ? 'active' : ''}}"
|
||||
data-role="{{item.key}}" catchtap="selectRole">
|
||||
<text>{{item.name}}</text>
|
||||
<text wx:if="{{currentRole === item.key}}" class="check-mark">✓</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
165
custom-tab-bar/index.wxss
Normal file
165
custom-tab-bar/index.wxss
Normal file
@@ -0,0 +1,165 @@
|
||||
/* custom-tab-bar/index.wxss - 角标浮于右上角,可超出胶囊 */
|
||||
|
||||
.custom-tab-bar {
|
||||
position: fixed;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.bar-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15rpx;
|
||||
padding: 0 20rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 左侧椭圆身份按钮 */
|
||||
.role-switch-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 110rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50rpx;
|
||||
background: #000000;
|
||||
border: 1px solid rgba(255,255,255,0.15);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.8);
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.role-switch-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-bottom: 2rpx;
|
||||
}
|
||||
|
||||
.role-switch-text {
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
color: #00f7ff;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* 纯黑闪光胶囊,移除overflow保证角标可见 */
|
||||
.tab-capsule {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
height: 100rpx;
|
||||
background: #000000;
|
||||
border-radius: 50rpx;
|
||||
border: 1px solid rgba(255,255,255,0.15);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.8);
|
||||
padding: 0 20rpx;
|
||||
position: relative;
|
||||
}
|
||||
.tab-capsule::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: -100%;
|
||||
width: 60%; height: 100%;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.25) 20%, rgba(255,255,255,0.35) 50%, rgba(255,255,255,0.25) 80%, transparent 100%);
|
||||
animation: shine 3s infinite;
|
||||
z-index: 1;
|
||||
}
|
||||
@keyframes shine {
|
||||
0% { left: -100%; }
|
||||
25% { left: 150%; }
|
||||
100% { left: 150%; }
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
position: relative; /* 角标的定位参考 */
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 70rpx;
|
||||
}
|
||||
.tab-icon {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
margin-bottom: 4rpx;
|
||||
filter: brightness(0) invert(1);
|
||||
opacity: 0.9;
|
||||
}
|
||||
.tab-text {
|
||||
font-size: 20rpx;
|
||||
color: #aaa;
|
||||
z-index: 2;
|
||||
}
|
||||
.active .tab-icon {
|
||||
opacity: 1;
|
||||
filter: brightness(0) invert(1) drop-shadow(0 0 8rpx #00aaff);
|
||||
}
|
||||
.active .tab-text {
|
||||
color: #00aaff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 🔴 角标容器:绝对定位到图标右上角,允许超出 */
|
||||
.badge-container {
|
||||
position: absolute;
|
||||
top: -10rpx; /* 往上提,更接近图标右上角 */
|
||||
right: -15rpx; /* 往右伸,超出tab-item */
|
||||
z-index: 100;
|
||||
pointer-events: none; /* 不阻挡点击 */
|
||||
}
|
||||
.tab-badge {
|
||||
min-width: 36rpx;
|
||||
height: 36rpx;
|
||||
line-height: 36rpx;
|
||||
padding: 0 10rpx;
|
||||
background: #ff3b30;
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
border-radius: 36rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.3);
|
||||
border: 1rpx solid rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
/* 弹窗部分保持不变 */
|
||||
.picker-mask {
|
||||
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: rgba(0,0,0,0.6);
|
||||
z-index: 10000;
|
||||
}
|
||||
.picker-panel {
|
||||
position: fixed; bottom: 0; left: 0; right: 0;
|
||||
background: #000000;
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
z-index: 10001;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.picker-header {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
padding: 30rpx 40rpx 20rpx;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
.picker-title { font-size: 32rpx; color: #00f7ff; }
|
||||
.picker-close { font-size: 36rpx; color: #aaa; padding: 0 10rpx; }
|
||||
.role-option {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
padding: 28rpx 40rpx;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.05);
|
||||
color: #ccc; font-size: 28rpx;
|
||||
}
|
||||
.role-option.active { color: #00f7ff; }
|
||||
.check-mark { font-size: 32rpx; color: #00f7ff; }
|
||||
|
||||
page {
|
||||
padding-bottom: 100rpx;
|
||||
}
|
||||
Reference in New Issue
Block a user