upload project
This commit is contained in:
commit
06961cae04
422 changed files with 110626 additions and 0 deletions
352
custom-tab-bar/index.js
Normal file
352
custom-tab-bar/index.js
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
const config = require('../config/config.js');
|
||||
const apiClient = require('../utils/api-client.js');
|
||||
|
||||
Component({
|
||||
data: {
|
||||
selected: 0,
|
||||
color: '#999999',
|
||||
selectedColor: '#ffffff',
|
||||
showCameraAction: false, // 拍照弹窗显示状态
|
||||
cameraActive: false, // 发布按钮激活状态
|
||||
list: [
|
||||
{
|
||||
pagePath: '/pages/map/map',
|
||||
text: '发现',
|
||||
iconPath: '/images/index/location.png',
|
||||
selectedIconPath: '/images/index/location-active.png'
|
||||
},
|
||||
{
|
||||
pagePath: '/pages/circle/circle',
|
||||
text: '圈子',
|
||||
iconPath: '/images/index/circle.png',
|
||||
selectedIconPath: '/images/index/circle-active.png'
|
||||
},
|
||||
{
|
||||
pagePath: '/subpackages/media/camera/camera',
|
||||
iconPath: '/images/index/phone.png',
|
||||
text: '发布',
|
||||
selectedIconPath: '/images/index/phone-active.png'
|
||||
},
|
||||
|
||||
{
|
||||
pagePath: '/pages/message/message',
|
||||
text: '聊天',
|
||||
iconPath: '/images/index/message.png',
|
||||
selectedIconPath: '/images/index/message-active.png'
|
||||
},
|
||||
{
|
||||
pagePath: '/pages/social/friends/friends',
|
||||
text: '好友',
|
||||
iconPath: '/images/index/friend.png',
|
||||
selectedIconPath: '/images/index/friend-active.png'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage(options) {
|
||||
// options.from 可以是 'button' 或 'menu'
|
||||
// 'button' 表示通过页面内的分享按钮触发
|
||||
// 'menu' 表示通过右上角菜单的分享按钮触发
|
||||
|
||||
return {
|
||||
title: 'Find Me', // 分享标题
|
||||
path: '/custom-tab-bar/index/index', // 分享路径,必须是以 / 开头的完整路径
|
||||
imageUrl: '/images/findme-logo.png', // 分享图标,可以是本地图片或网络图片
|
||||
success(res) {
|
||||
// 分享成功后的回调
|
||||
console.log('分享成功', res);
|
||||
// 可以在这里添加统计代码等
|
||||
},
|
||||
fail(res) {
|
||||
// 分享失败后的回调
|
||||
console.log('分享失败', res);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
attached() {
|
||||
// 已通过CSS调整适配所有设备
|
||||
try {
|
||||
const counts = wx.getStorageSync('unreadCounts') || {};
|
||||
const friends = Number(counts.friends || 0);
|
||||
const messages = Number(counts.messages || 0);
|
||||
if (friends || messages) {
|
||||
this.setData({
|
||||
friendsBadge: friends,
|
||||
messagesBadge: messages
|
||||
});
|
||||
}
|
||||
} catch (_) {}
|
||||
},
|
||||
methods: {
|
||||
// 对外暴露:设置好友请求角标数量
|
||||
setFriendsBadge(count) {
|
||||
const n = Number(count) || 0;
|
||||
if (this.data.friendsBadge === n) return;
|
||||
this.setData({ friendsBadge: n < 0 ? 0 : n });
|
||||
},
|
||||
// 对外暴露:设置消息未读角标数量
|
||||
setMessagesBadge(count) {
|
||||
const n = Number(count) || 0;
|
||||
if (this.data.messagesBadge === n) return;
|
||||
this.setData({ messagesBadge: n < 0 ? 0 : n });
|
||||
},
|
||||
// 清除所有角标
|
||||
clearBadges() {
|
||||
this.setData({ friendsBadge: 0, messagesBadge: 0 });
|
||||
},
|
||||
switchTab(e) {
|
||||
const data = e.currentTarget.dataset;
|
||||
const url = data.path;
|
||||
const index = data.index;
|
||||
|
||||
// 获取当前页面信息
|
||||
const pages = getCurrentPages();
|
||||
const currentPage = pages[pages.length - 1];
|
||||
|
||||
// 检查是否是"发布"按钮(索引2)- 直接跳转到编辑页面
|
||||
if (index === 2) {
|
||||
// 切换发布按钮激活状态
|
||||
this.setData({ cameraActive: !this.data.cameraActive });
|
||||
// 检查登录状态
|
||||
const app = getApp();
|
||||
if (!app.globalData.isLoggedIn) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/login?from=camera'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 已登录时直接跳转到编辑页面
|
||||
wx.navigateTo({
|
||||
url: '/subpackages/media/edits/edits',
|
||||
fail: (err) => {
|
||||
console.error('跳转编辑页面失败:', err);
|
||||
wx.showToast({
|
||||
title: '跳转失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
// 跳转失败时重置激活状态
|
||||
this.setData({ cameraActive: false });
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 切换到其他按钮时,取消发布按钮激活状态
|
||||
if (this.data.cameraActive) {
|
||||
this.setData({ cameraActive: false });
|
||||
}
|
||||
|
||||
// 先更新选中状态(其他 tabBar 页面)
|
||||
this.setData({
|
||||
selected: index
|
||||
});
|
||||
|
||||
// 检查是否是"发现"按钮(索引0)
|
||||
if (index === 0) {
|
||||
// 检查当前是否已经在地图页面
|
||||
if (currentPage.route === 'pages/map/map') {
|
||||
// 如果已经在地图页面,直接打开地点收藏栏
|
||||
currentPage.onOpenLocationFavoriteBar();
|
||||
} else {
|
||||
const app = getApp();
|
||||
// 如果不在地图页面,先跳转到地图页面,然后通过全局变量标记需要打开收藏栏
|
||||
wx.switchTab({
|
||||
url,
|
||||
success: () => {
|
||||
// 设置全局变量,让地图页面加载后知道需要打开收藏栏
|
||||
app.globalData.needOpenLocationFavoriteBar = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否是"圈子"按钮(索引1)
|
||||
if (index === 1) {
|
||||
// 检查登录状态
|
||||
const app = getApp();
|
||||
if (!app.globalData.isLoggedIn) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/login?from=circle'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 正常跳转到圈子页面
|
||||
wx.switchTab({
|
||||
url
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否是"聊天"按钮(索引3)
|
||||
if (index === 3) {
|
||||
// 检查登录状态
|
||||
const app = getApp();
|
||||
if (!app.globalData.isLoggedIn) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/login?from=message'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 已登录时正常跳转
|
||||
wx.switchTab({
|
||||
url
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否是"我的"按钮(索引4)- 跳转到好友列表页面
|
||||
if (index === 4) {
|
||||
// 检查登录状态
|
||||
const app = getApp();
|
||||
if (!app.globalData.isLoggedIn) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/login?from=friends'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 已登录时跳转到好友列表页面(使用 switchTab,因为它在 tabBar 中)
|
||||
wx.switchTab({
|
||||
url: '/pages/social/friends/friends'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他按钮正常跳转
|
||||
wx.switchTab({
|
||||
url
|
||||
});
|
||||
},
|
||||
|
||||
// 显示拍照弹窗
|
||||
showCameraActionSheet() {
|
||||
this.setData({ showCameraAction: true });
|
||||
},
|
||||
|
||||
// 隐藏拍照弹窗
|
||||
hideCameraActionSheet() {
|
||||
this.setData({ showCameraAction: false, cameraActive: false });
|
||||
},
|
||||
|
||||
// 拍照
|
||||
takePhoto() {
|
||||
this.hideCameraActionSheet();
|
||||
wx.navigateTo({
|
||||
url: '/subpackages/media/camera/camera',
|
||||
fail: (err) => {
|
||||
console.error('跳转拍照页面失败:', err);
|
||||
wx.showToast({
|
||||
title: '跳转失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 从相册选择
|
||||
chooseImage() {
|
||||
this.hideCameraActionSheet();
|
||||
wx.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['original', 'compressed'],
|
||||
sourceType: ['album'],
|
||||
success: (res) => {
|
||||
const tempFilePath = res.tempFilePaths[0];
|
||||
wx.showLoading({ title: '上传中...', mask: true });
|
||||
|
||||
// 上传图片
|
||||
this.uploadImage(tempFilePath)
|
||||
.then(imageUrl => {
|
||||
wx.hideLoading();
|
||||
if (imageUrl) {
|
||||
wx.navigateTo({
|
||||
url: `/subpackages/media/edits/edits?imagePath=${encodeURIComponent(imageUrl)}`,
|
||||
fail: (err) => {
|
||||
console.error('跳转编辑页失败:', err);
|
||||
wx.showToast({
|
||||
title: '跳转失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
wx.hideLoading();
|
||||
console.error('上传失败:', error);
|
||||
wx.showToast({
|
||||
title: error.message || '上传失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
});
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('选择图片失败:', error);
|
||||
if (error.errMsg && !error.errMsg.includes('cancel')) {
|
||||
wx.showToast({
|
||||
title: '选择图片失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 上传图片
|
||||
uploadImage(tempFilePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.uploadFile({
|
||||
url: `${config.api.baseUrl}/api/v1/file/upload`,
|
||||
filePath: tempFilePath,
|
||||
name: 'file',
|
||||
formData: {
|
||||
file_type: 'image',
|
||||
usage_type: 'feed'
|
||||
},
|
||||
header: {
|
||||
'Authorization': `Bearer ${apiClient.getToken()}`
|
||||
},
|
||||
success: (uploadRes) => {
|
||||
if (apiClient.is401Error(uploadRes)) {
|
||||
const app = getApp();
|
||||
const isLoggedIn = app?.globalData?.isLoggedIn || false;
|
||||
apiClient.handle401Error(isLoggedIn);
|
||||
if (isLoggedIn) {
|
||||
reject(new Error('登录已过期,请重新登录'));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data);
|
||||
if (data.code === 0) {
|
||||
const fileData = data?.data?.data || data?.data || {};
|
||||
const imageUrl = fileData.file_url || fileData.fileUrl || fileData.url;
|
||||
if (imageUrl) {
|
||||
resolve(imageUrl);
|
||||
} else {
|
||||
reject(new Error('上传成功但未获取到图片URL'));
|
||||
}
|
||||
} else {
|
||||
reject(new Error(data.message || '上传失败'));
|
||||
}
|
||||
} catch (error) {
|
||||
reject(new Error('响应解析失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('上传失败:', error);
|
||||
reject(new Error(error.errMsg || '上传失败'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
3
custom-tab-bar/index.json
Normal file
3
custom-tab-bar/index.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"component": true
|
||||
}
|
||||
33
custom-tab-bar/index.wxml
Normal file
33
custom-tab-bar/index.wxml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<!--custom-tab-bar/index.wxml-->
|
||||
<view class="tab-bar-glass tab-bar">
|
||||
<view wx:for="{{list}}" wx:key="index"
|
||||
class="tab-bar-item {{selected === index ? 'tab-active' : ''}} {{index === 2 ? 'camera-tab-item' : ''}}"
|
||||
data-path="{{item.pagePath}}"
|
||||
data-index="{{index}}"
|
||||
bindtap="switchTab">
|
||||
<!-- 拍照按钮(索引2)根据激活状态显示图标,其他按钮根据选中状态显示 -->
|
||||
<image class="tab-bar-icon {{selected === index ? 'tab-icon-active' : ''}} {{index === 2 && cameraActive ? 'tab-icon-active camera-icon-large' : ''}} {{index === 2 && !cameraActive ? 'camera-icon-normal' : ''}}"
|
||||
src="{{index === 2 ? (cameraActive ? item.selectedIconPath : item.iconPath) : (selected === index ? item.selectedIconPath : item.iconPath)}}"
|
||||
mode="aspectFit" />
|
||||
<!-- 所有按钮未选中/未激活时显示文字 -->
|
||||
<text wx:if="{{index === 2 ? !cameraActive : selected !== index}}" class="tab-bar-text" style="color: {{selected === index ? selectedColor : color}};">{{item.text}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拍照功能弹窗 -->
|
||||
<view class="camera-action-sheet {{showCameraAction ? 'show' : ''}}">
|
||||
<view class="action-sheet-mask" bindtap="hideCameraActionSheet"></view>
|
||||
<view class="action-sheet-content">
|
||||
<view class="action-sheet-item primary" bindtap="takePhoto">
|
||||
<text class="action-text">拍照</text>
|
||||
</view>
|
||||
<view class="action-sheet-divider-thin"></view>
|
||||
<view class="action-sheet-item primary" bindtap="chooseImage">
|
||||
<text class="action-text">从相册选择</text>
|
||||
</view>
|
||||
<view class="action-sheet-divider"></view>
|
||||
<view class="action-sheet-item cancel" bindtap="hideCameraActionSheet">
|
||||
<text class="action-text">取消</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
163
custom-tab-bar/index.wxss
Normal file
163
custom-tab-bar/index.wxss
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/* custom-tab-bar/index.wxss - 自定义底部导航栏样式文件 */
|
||||
|
||||
.tab-bar {
|
||||
position: fixed; /* 固定定位,使导航栏始终显示在屏幕底部 */
|
||||
bottom: 40rpx; /* 距离屏幕底部20px -> 40rpx */
|
||||
left: 100rpx; /* 距离屏幕左侧50px -> 100rpx */
|
||||
right: 100rpx; /* 距离屏幕右侧50px -> 100rpx */
|
||||
min-height: 200rpx; /* 导航栏最小高度(用户希望保持较大值) */
|
||||
height: auto; /* 高度自适应内容 */
|
||||
display: flex; /* 使用flex布局 */
|
||||
justify-content: space-around; /* 水平均匀分布子元素 */
|
||||
align-items: center; /* 垂直居中对齐子元素 */
|
||||
padding: 20rpx; /* 内边距10px -> 20rpx */
|
||||
box-sizing: border-box; /* 盒模型为border-box,宽高包含内边距和边框 */
|
||||
z-index: 9999; /* 层级设为最高,确保在其他元素之上 */
|
||||
border-radius: 52rpx; /* 设置圆角,创建胶囊形状 26px -> 52rpx */
|
||||
}
|
||||
|
||||
/* 深灰色玻璃效果 - 继承自app.wxss并增强 */
|
||||
.tab-bar-glass {
|
||||
/* 基础玻璃效果 */
|
||||
background: rgba(30, 30, 30, 0.7); /* 设置半透明深灰色背景,透明度0.7 */
|
||||
backdrop-filter: blur(20rpx); /* 设置背景模糊效果,10px -> 20rpx */
|
||||
-webkit-backdrop-filter: blur(20rpx); /* WebKit内核浏览器兼容,设置背景模糊效果 */
|
||||
|
||||
/* 添加细微边框增强效果 */
|
||||
border-top: 2rpx solid rgba(255, 255, 255, 0.1); /* 顶部边框为1px -> 2rpx白色半透明线 */
|
||||
|
||||
/* 阴影效果增强层次感 */
|
||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1); /* 设置底部阴影,增强悬浮感 2px -> 4rpx, 10px -> 20rpx */
|
||||
}
|
||||
|
||||
.tab-bar-item {
|
||||
flex: 1; /* 让每个按钮占据相同的宽度 */
|
||||
display: flex; /* 使用flex布局 */
|
||||
flex-direction: column; /* 垂直方向排列子元素(图标在上,文字在下) */
|
||||
align-items: center; /* 水平居中对齐子元素 */
|
||||
justify-content: center; /* 垂直居中对齐子元素 */
|
||||
height: 100%; /* 高度充满父容器 */
|
||||
box-sizing: border-box; /* 盒模型为border-box */
|
||||
}
|
||||
|
||||
.tab-bar-icon {
|
||||
width: 55rpx; /* 图标宽度 */
|
||||
height: 55rpx; /* 图标高度 */
|
||||
margin-bottom: 8rpx; /* 与下方文字的间距 */
|
||||
display: block; /* 显示为块级元素 */
|
||||
transition: transform 0.3s ease, width 0.3s ease, height 0.3s ease; /* 添加过渡效果 */
|
||||
}
|
||||
|
||||
/* 🔥 所有tab选中时图标放大 */
|
||||
.tab-bar-icon.tab-icon-active {
|
||||
width: 80rpx; /* 选中时图标宽度增大 */
|
||||
height: 80rpx; /* 选中时图标高度增大 */
|
||||
margin-bottom: 0; /* 选中时没有文字,不需要间距 */
|
||||
}
|
||||
|
||||
/* 拍照按钮(索引2)未激活时:正常大小图标,显示文字 */
|
||||
.camera-icon-normal {
|
||||
width: 55rpx !important; /* 正常大小 */
|
||||
height: 55rpx !important; /* 正常大小 */
|
||||
margin-bottom: 8rpx !important; /* 有文字,需要间距 */
|
||||
}
|
||||
|
||||
/* 拍照按钮(索引2)激活时:大图标,不显示文字 */
|
||||
.camera-icon-large {
|
||||
width: 80rpx !important; /* 拍照按钮图标更大 */
|
||||
height: 80rpx !important; /* 拍照按钮图标更大 */
|
||||
margin-bottom: 0 !important; /* 没有文字,不需要间距 */
|
||||
}
|
||||
|
||||
.tab-bar-text {
|
||||
font-size: 24rpx; /* 文字大小12px -> 24rpx */
|
||||
line-height: 24rpx; /* 行高12px -> 24rpx,与字体大小一致确保单行显示 */
|
||||
}
|
||||
|
||||
/* 触摸反馈效果 */
|
||||
.tab-bar-item:active {
|
||||
opacity: 0.7; /* 触摸时透明度降低到0.7,提供视觉反馈 */
|
||||
}
|
||||
|
||||
/* 拍照功能弹窗样式 */
|
||||
.camera-action-sheet {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10000;
|
||||
transform: none !important;
|
||||
-webkit-transform: none !important;
|
||||
}
|
||||
|
||||
.camera-action-sheet.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.action-sheet-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.action-sheet-content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
background: #222;
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.action-sheet-item {
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
background: #222;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.action-sheet-item::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.action-sheet-item.primary {
|
||||
background: #222;
|
||||
}
|
||||
|
||||
.action-sheet-item.cancel {
|
||||
background: #222;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.action-sheet-item.cancel::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.action-sheet-divider {
|
||||
height: 8px;
|
||||
background-color: #111;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.action-sheet-divider-thin {
|
||||
height: 2px;
|
||||
background-color: #111;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue