Files
smartDriveEEUniApp/pages/furniture_top_sales/furniture_top_sales.vue
2026-01-31 21:10:40 +08:00

391 lines
11 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="page">
<!-- #ifdef APP -->
<statusBar></statusBar>
<!-- #endif -->
<!-- 导航栏 -->
<uni-nav-bar
:fixed="true"
:statusBar="true"
title="AI销冠系统"
leftIcon="left"
@clickLeft="goBack"
color="#333"
backgroundColor="#FFFFFF">
</uni-nav-bar>
<view class="content">
<!-- 标签页 -->
<view class="tabs" :style="{ top: computedNavbarTop || navbarTop }">
<view
class="tab-item"
:class="{ active: activeTab === 'practice' }"
@click="switchTab('practice')">
<text>场景</text>
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'training' }"
@click="switchTab('training')">
<text>陪练</text>
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'quality' }"
@click="switchTab('quality')">
<text>质检</text>
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'material' }"
@click="switchTab('material')">
<text>素材</text>
</view>
</view>
<!-- 场景tab -->
<practice-tab
v-if="activeTab === 'practice'"
class="tab-content-container"
:style="{ top: computedContentTop || contentTop }"
@switch-to-training="handleSwitchToTraining"></practice-tab>
<!-- 陪练tab -->
<training-tab
v-if="activeTab === 'training'"
class="tab-content-container"
:style="{ top: computedContentTop || contentTop }"
@refresh-training-list="handleRefreshTrainingList"></training-tab>
<!-- 质检tab -->
<scroll-view
class="tab-content tab-content-container"
:style="{ top: computedContentTop || contentTop }"
scroll-y
v-if="activeTab === 'quality'">
<view class="champion-card">
<text class="champion-title">质检</text>
<text class="champion-desc">这里是质检相关的内容展示区域</text>
</view>
</scroll-view>
<!-- 素材tab -->
<material-tab
v-if="activeTab === 'material'"
class="tab-content-container"
:style="{ top: computedContentTop || contentTop }"></material-tab>
</view>
</view>
</template>
<script>
// #ifdef APP
import statusBar from "@/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar";
// #endif
import PracticeTab from "./components/practice-tab.vue";
import TrainingTab from "./components/training-tab.vue";
import MaterialTab from "./components/material-tab.vue";
export default {
// #ifdef APP
components: {
statusBar,
PracticeTab,
TrainingTab,
MaterialTab
},
// #endif
// #ifndef APP
components: {
PracticeTab,
TrainingTab,
MaterialTab
},
// #endif
data() {
// 动态计算导航栏高度
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight || 20; // 默认20px
const navbarHeight = 44; // navbar高度44px
// 转换为rpx1px = 2rpx在375px设计稿下
const statusBarHeightRpx = statusBarHeight * 2;
const navbarHeightRpx = navbarHeight * 2;
const totalNavbarHeight = statusBarHeightRpx + navbarHeightRpx;
return {
navbarTop: totalNavbarHeight + 'rpx', // tab栏距离顶部的距离
contentTop: (totalNavbarHeight + 72) + 'rpx', // 内容区域距离顶部的距离tab栏高度72rpx
activeTab: 'practice'
}
},
computed: {
// 计算导航栏和内容区域的位置(使用计算属性确保响应式)
computedNavbarTop() {
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight || 20;
const navbarHeight = 44;
const statusBarHeightRpx = statusBarHeight * 2;
const navbarHeightRpx = navbarHeight * 2;
const totalNavbarHeight = statusBarHeightRpx + navbarHeightRpx;
return totalNavbarHeight + 'rpx';
},
computedContentTop() {
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight || 20;
const navbarHeight = 44;
const statusBarHeightRpx = statusBarHeight * 2;
const navbarHeightRpx = navbarHeight * 2;
const totalNavbarHeight = statusBarHeightRpx + navbarHeightRpx;
return (totalNavbarHeight + 72) + 'rpx'; // tab栏高度72rpx
}
},
onLoad() {
console.log('[FurnitureTopSales][onLoad] 页面加载');
// 更新导航栏位置
this.updateNavbarPosition();
// 页面加载时如果默认是场景tab页子组件会自动加载数据
},
onShow() {
console.log('[FurnitureTopSales][onShow] 页面显示');
// 每次页面显示时都重新计算导航栏位置,确保通过导航菜单进入时也能正确显示
// 使用 $nextTick 确保DOM更新后再设置样式
this.$nextTick(() => {
this.updateNavbarPosition();
// 再次延迟更新,确保样式已应用
setTimeout(() => {
this.updateNavbarPosition();
console.log('[FurnitureTopSales][onShow] 延迟更新后的位置:', {
navbarTop: this.navbarTop,
contentTop: this.contentTop
});
}, 50);
});
},
onReady() {
// 页面渲染完成后检查tab栏是否显示
console.log('[FurnitureTopSales][onReady] 页面渲染完成');
console.log('[FurnitureTopSales][onReady] activeTab:', this.activeTab);
console.log('[FurnitureTopSales][onReady] navbarTop:', this.navbarTop);
console.log('[FurnitureTopSales][onReady] contentTop:', this.contentTop);
// 再次更新导航栏位置,确保渲染后位置正确
this.updateNavbarPosition();
const systemInfo = uni.getSystemInfoSync();
console.log('[FurnitureTopSales][onReady] 系统信息:', {
statusBarHeight: systemInfo.statusBarHeight,
windowHeight: systemInfo.windowHeight,
screenHeight: systemInfo.screenHeight
});
// 检查tab栏元素是否存在和可见
// #ifdef MP-WEIXIN
setTimeout(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.tabs').boundingClientRect((data) => {
console.log('[FurnitureTopSales][onReady] tab栏元素信息:', data);
if (!data) {
console.error('[FurnitureTopSales][onReady] tab栏元素未找到');
} else {
console.log('[FurnitureTopSales][onReady] tab栏位置:', {
top: data.top,
left: data.left,
width: data.width,
height: data.height,
expectedTop: this.navbarTop,
isVisible: data.width > 0 && data.height > 0,
isOnScreen: data.top >= 0 && data.top < systemInfo.windowHeight
});
// 如果tab栏不可见强制更新位置
if (data.width === 0 || data.height === 0 || data.top < 0) {
console.warn('[FurnitureTopSales][onReady] tab栏不可见强制更新位置');
this.updateNavbarPosition();
this.$forceUpdate();
}
}
}).exec();
}, 100);
// #endif
},
methods: {
// 计算并更新导航栏和内容区域的位置
updateNavbarPosition() {
console.log('[FurnitureTopSales][updateNavbarPosition] 开始更新导航栏位置');
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight || 20; // 默认20px
const navbarHeight = 44; // navbar高度44px
// 转换为rpx1px = 2rpx在375px设计稿下
const statusBarHeightRpx = statusBarHeight * 2;
const navbarHeightRpx = navbarHeight * 2;
const totalNavbarHeight = statusBarHeightRpx + navbarHeightRpx;
const navbarTop = totalNavbarHeight + 'rpx';
const contentTop = (totalNavbarHeight + 72) + 'rpx'; // tab栏高度72rpx
console.log('[FurnitureTopSales][updateNavbarPosition] 更新导航栏位置:', {
statusBarHeight: statusBarHeight,
navbarHeight: navbarHeight,
totalNavbarHeight: totalNavbarHeight,
navbarTop: navbarTop,
contentTop: contentTop,
currentNavbarTop: this.navbarTop,
currentContentTop: this.contentTop
});
// 强制更新,确保响应式数据变化被检测到
this.$set(this, 'navbarTop', navbarTop);
this.$set(this, 'contentTop', contentTop);
// 在微信小程序中,可能需要强制更新视图
// #ifdef MP-WEIXIN
this.$forceUpdate();
// #endif
},
goBack() {
// 检查页面栈,如果当前是第一个页面,则不能返回
const pages = getCurrentPages();
if (pages.length <= 1) {
// 如果是第一个页面,不执行返回操作
// 对于 tabBar 页面,通常不需要返回按钮,或者可以隐藏返回按钮
console.log('[FurnitureTopSales][goBack] 当前是第一个页面,无法返回');
return;
}
uni.navigateBack({
fail: (err) => {
console.error('[FurnitureTopSales][goBack] 返回失败:', err);
// 如果返回失败,可能是页面栈问题,忽略错误
}
});
},
switchTab(tab) {
this.activeTab = tab;
},
handleSwitchToTraining() {
// 处理从场景tab切换到陪练tab的事件
this.switchTab('training');
},
handleRefreshTrainingList() {
// 处理刷新陪练列表的事件
// 切换到陪练tab如果不在的话
this.switchTab('training');
}
}
}
</script>
<style>
page {
background-color: #F5F5F5;
}
.page {
min-height: 100vh;
background-color: #F5F5F5;
}
.content {
padding-top: 0; /* 移除padding-top因为tab页和内容区域都使用绝对定位 */
margin-top: 0;
position: relative;
min-height: 100vh; /* 确保content有足够高度 */
}
/* 隐藏导航栏占位区域,避免产生空白 */
::v-deep .uni-navbar__placeholder {
display: none !important;
}
/* 标签页 */
.tabs {
display: flex !important; /* 强制显示 */
visibility: visible !important; /* 强制可见 */
opacity: 1 !important; /* 强制不透明 */
background-color: #FFFFFF;
border-bottom: 1px solid #E0E0E0;
padding: 0 16rpx;
margin-top: 0;
position: fixed; /* 改为fixed定位确保始终可见 */
/* 导航栏高度statusBar + navbar动态计算 */
/* 使用内联样式动态设置top值 */
left: 0;
right: 0;
z-index: 999; /* 提高z-index确保在最上层 */
height: 72rpx; /* 明确设置标签页高度 */
box-sizing: border-box;
align-items: center;
/* 确保tab栏始终可见 */
will-change: top; /* 优化渲染性能 */
}
.tab-item {
padding: 24rpx 32rpx;
position: relative;
flex-shrink: 0;
}
.tab-item text {
font-size: 30rpx;
color: #666;
}
.tab-item.active text {
color: #333;
font-weight: 500;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 32rpx;
right: 32rpx;
height: 4rpx;
background-color: #007AFF;
border-radius: 2rpx;
}
.champion-card {
width: 100%;
box-sizing: border-box;
background-color: #FFFFFF;
border-radius: 16rpx;
padding: 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 400rpx;
}
.champion-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.champion-desc {
font-size: 28rpx;
color: #999;
}
/* tab内容容器 */
.tab-content-container {
/* 使用绝对定位从tab页底部开始到底部导航栏结束 */
position: absolute;
/* top值通过内联样式动态设置 */
left: 0;
right: 0;
bottom: 96rpx; /* 底部导航栏高度 */
overflow-y: auto;
background-color: #F5F5F5;
}
.tab-content {
padding: 24rpx 16rpx;
box-sizing: border-box;
}
</style>