166 lines
4.4 KiB
Vue
166 lines
4.4 KiB
Vue
<template>
|
||
<view class="page">
|
||
<!-- 顶部子系统标识条 -->
|
||
<view v-if="sub" class="hero" :class="sub.tint" :style="headPad">
|
||
<view class="hero-main">
|
||
<view class="hero-icon">
|
||
<FaIcon :name="sub.icon" color="#ffffff" :size="24" />
|
||
</view>
|
||
<view class="hero-meta">
|
||
<text class="hero-name">{{ sub.title }}</text>
|
||
<text class="hero-desc">{{ sub.desc }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!--
|
||
内容区:三页签共用底部 tabbar,H5 / APK / 微信小程序结构完全一致。
|
||
各自独立 scroll-view(保留各自滚动位置);首页进入即挂载,
|
||
其余页签首次切换才挂载,之后用 v-show 保留状态。
|
||
-->
|
||
<view v-if="sub" class="content">
|
||
<scroll-view v-if="visited.home" v-show="activeTab === 'home'" class="pane" scroll-y>
|
||
<SubHome :slug="slug" embedded @switch-tab="switchByIndex" @back="goBackNav" />
|
||
<view class="pane-bottom" />
|
||
</scroll-view>
|
||
<scroll-view v-if="visited.functions" v-show="activeTab === 'functions'" class="pane" scroll-y>
|
||
<SubFunctions :slug="slug" embedded @switch-tab="switchByIndex" @back="goBackNav" />
|
||
<view class="pane-bottom" />
|
||
</scroll-view>
|
||
<scroll-view v-if="visited.mine" v-show="activeTab === 'mine'" class="pane" scroll-y>
|
||
<SubMine :slug="slug" embedded @switch-tab="switchByIndex" @back="goBackNav" />
|
||
<view class="pane-bottom" />
|
||
</scroll-view>
|
||
</view>
|
||
|
||
<AppTabbar variant="switch" :current="activeTab" :tabs="tabs" @change="onTabChange" />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { getSubsystem } from '@/config/subsystems.js'
|
||
import { mpHeadPad } from '@/utils/mpHead.js'
|
||
import AppTabbar from '@/components/AppTabbar.vue'
|
||
import SubHome from '@/components/sub/SubHome.vue'
|
||
import SubFunctions from '@/components/sub/SubFunctions.vue'
|
||
import SubMine from '@/components/sub/SubMine.vue'
|
||
|
||
// 页签下标顺序,与 Sub 组件 @switch-tab 抛出的数字一一对应
|
||
const TAB_ORDER = ['home', 'functions', 'mine']
|
||
const tabs = [
|
||
{ name: 'home', text: '首页', icon: 'house' },
|
||
{ name: 'functions', text: '功能', icon: 'table-cells' },
|
||
// 末位为「回平台」:点击由 AppTabbar 统一 reLaunch 到 /pages/nav/nav
|
||
{ name: 'mine', text: '回平台', icon: 'arrow-left' }
|
||
]
|
||
|
||
const slug = ref('')
|
||
const sub = ref(null)
|
||
const activeTab = ref('home')
|
||
const visited = ref({ home: true, functions: false, mine: false })
|
||
|
||
const headPad = mpHeadPad()
|
||
|
||
onLoad((options) => {
|
||
slug.value = options && options.slug ? options.slug : 'crm'
|
||
sub.value = getSubsystem(slug.value)
|
||
if (!sub.value) uni.reLaunch({ url: '/pages/nav/nav' })
|
||
})
|
||
|
||
function onTabChange(name) {
|
||
activeTab.value = name
|
||
if (!visited.value[name]) visited.value[name] = true
|
||
}
|
||
|
||
function switchByIndex(i) {
|
||
onTabChange(TAB_ORDER[i] || 'home')
|
||
}
|
||
|
||
function goBackNav() {
|
||
uni.navigateBack({ fail: () => uni.reLaunch({ url: '/pages/nav/nav' }) })
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import '@/src/styles/page-common.scss';
|
||
|
||
.page {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
background: $color-bg-page;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* ============ 顶部标识条 ============ */
|
||
.hero {
|
||
flex-shrink: 0;
|
||
position: relative;
|
||
z-index: 0;
|
||
// H5 端 --status-bar-height 为 0,此时仅保留 32rpx 内边距
|
||
padding: calc(var(--status-bar-height, 44px) + 32rpx) $page-padding-x 72rpx;
|
||
}
|
||
|
||
.hero-main {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 22rpx;
|
||
/* 取消顶部回平台按钮后,补偿其占位;headPad 内联 paddingTop 继续避让胶囊 */
|
||
margin-top: 44rpx;
|
||
}
|
||
|
||
.hero-icon {
|
||
width: 88rpx;
|
||
height: 88rpx;
|
||
border-radius: 26rpx;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border: 1rpx solid rgba(255, 255, 255, 0.32);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.hero-meta {
|
||
flex: 1;
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.hero-name {
|
||
font-size: 38rpx;
|
||
font-weight: 700;
|
||
letter-spacing: 1rpx;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.hero-desc {
|
||
margin-top: 10rpx;
|
||
font-size: 22rpx;
|
||
line-height: 1.4;
|
||
color: rgba(255, 255, 255, 0.82);
|
||
}
|
||
|
||
/* ============ 内容区:上移压住渐变条,圆角衔接 ============ */
|
||
.content {
|
||
flex: 1;
|
||
min-height: 0;
|
||
position: relative;
|
||
z-index: 1;
|
||
margin-top: -44rpx;
|
||
border-radius: 32rpx 32rpx 0 0;
|
||
background: $color-bg-page;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.pane {
|
||
height: 100%;
|
||
}
|
||
|
||
.pane-bottom {
|
||
height: 32rpx;
|
||
}
|
||
</style> |