Просмотр исходного кода

fix(miniprogram): adapt mp-header for WeChat capsule safe area

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 1 месяц назад
Родитель
Сommit
1a97ec954b

+ 2 - 6
miniprogram/components/app-safe-header.vue

@@ -17,7 +17,7 @@
 
 <script setup>
 import { computed } from 'vue'
-import { getGlobalSafeArea } from '@/utils/safeArea'
+import { getGlobalSafeArea, buildSafeAreaCssVarsStyle } from '@/utils/safeArea'
 
 const props = defineProps({
   title: {
@@ -30,12 +30,8 @@ const props = defineProps({
   },
 })
 
-const safeArea = getGlobalSafeArea()
-
 const headerStyle = computed(() => ({
-  '--sq-safe-top': `${safeArea.topSafeHeight}px`,
-  '--sq-nav-height': `${safeArea.navContentHeight}px`,
-  '--sq-capsule-right-safe': `${safeArea.capsuleRightSafeWidth}px`,
+  ...buildSafeAreaCssVarsStyle(getGlobalSafeArea()),
   '--sq-header-background': props.background,
 }))
 </script>

+ 5 - 2
miniprogram/components/bx-ui/bx-placeholder-page.vue

@@ -2,6 +2,9 @@
 import { computed } from 'vue'
 import { onLoad } from '@dcloudio/uni-app'
 import { PAGE_PATHS } from '@/config/api'
+import { getSafeAreaStyle } from '@/utils/safeArea'
+
+const safeAreaStyle = getSafeAreaStyle()
 
 const props = defineProps({
   defaultTitle: { type: String, default: '报销业务' }
@@ -11,7 +14,7 @@ const title = computed(() => props.defaultTitle)
 
 const goBack = () => {
   uni.navigateBack({
-    fail: () => uni.switchTab({ url: PAGE_PATHS.workbench })
+    fail: () => uni.reLaunch({ url: PAGE_PATHS.workbench })
   })
 }
 
@@ -20,7 +23,7 @@ onLoad(() => {})
 
 <template>
   <view class="mp-page">
-    <view class="mp-header">
+    <view class="mp-header" :style="safeAreaStyle">
       <view class="bx-ph__nav" @click="goBack">
         <text class="bx-ph__back">← 工作台</text>
       </view>

+ 4 - 2
miniprogram/pages/common/biz-placeholder.vue

@@ -1,7 +1,9 @@
 <script setup>
 import { ref } from 'vue'
 import { onLoad } from '@dcloudio/uni-app'
+import { getSafeAreaStyle } from '@/utils/safeArea'
 
+const safeAreaStyle = getSafeAreaStyle()
 const title = ref('业务页')
 const moduleTitle = ref('')
 const code = ref('')
@@ -14,14 +16,14 @@ onLoad((query) => {
 
 const goBack = () => {
   uni.navigateBack({
-    fail: () => uni.switchTab({ url: '/pages/workbench/workbench' })
+    fail: () => uni.reLaunch({ url: '/pages/workbench/workbench' })
   })
 }
 </script>
 
 <template>
   <view class="mp-page">
-    <view class="mp-header">
+    <view class="mp-header" :style="safeAreaStyle">
       <view class="biz-placeholder__nav" @click="goBack">
         <text class="biz-placeholder__back">← 工作台</text>
       </view>

+ 4 - 2
miniprogram/pages/home/home.vue

@@ -2,7 +2,9 @@
 import { onShow } from '@dcloudio/uni-app'
 import { useUserStore } from '@/stores/user'
 import { PAGE_PATHS } from '@/config/api'
+import { getSafeAreaStyle } from '@/utils/safeArea'
 
+const safeAreaStyle = getSafeAreaStyle()
 const userStore = useUserStore()
 
 onShow(() => {
@@ -13,13 +15,13 @@ onShow(() => {
 })
 
 const goWorkbench = () => {
-  uni.switchTab({ url: PAGE_PATHS.workbench })
+  uni.reLaunch({ url: PAGE_PATHS.workbench })
 }
 </script>
 
 <template>
   <view class="mp-page mp-page--tab">
-    <view class="mp-header">
+    <view class="mp-header mp-header--home" :style="safeAreaStyle">
       <text class="mp-header__title">首页</text>
       <text class="mp-header__meta">概览与快捷入口(本期占位)</text>
     </view>

+ 3 - 1
miniprogram/pages/todo/todo.vue

@@ -2,7 +2,9 @@
 import { onShow } from '@dcloudio/uni-app'
 import { useUserStore } from '@/stores/user'
 import { PAGE_PATHS } from '@/config/api'
+import { getSafeAreaStyle } from '@/utils/safeArea'
 
+const safeAreaStyle = getSafeAreaStyle()
 const userStore = useUserStore()
 
 onShow(() => {
@@ -15,7 +17,7 @@ onShow(() => {
 
 <template>
   <view class="mp-page mp-page--tab">
-    <view class="mp-header">
+    <view class="mp-header" :style="safeAreaStyle">
       <text class="mp-header__title">待办</text>
       <text class="mp-header__meta">跨模块待办汇总(本期占位)</text>
     </view>

+ 3 - 1
miniprogram/pages/workbench/workbench.vue

@@ -5,7 +5,9 @@ import { useUserStore } from '@/stores/user'
 import { WORKBENCH_MODULES } from '@/config/workbench-menus'
 import { PAGE_PATHS, WORKBENCH_ROUTE_MAP } from '@/config/api'
 import { filterWorkbenchModules } from '@/utils/workbenchMenuFilter'
+import { getSafeAreaStyle } from '@/utils/safeArea'
 
+const safeAreaStyle = getSafeAreaStyle()
 const userStore = useUserStore()
 const modules = computed(() =>
   filterWorkbenchModules(WORKBENCH_MODULES, {
@@ -67,7 +69,7 @@ const handleLogout = async () => {
 
 <template>
   <view class="mp-page mp-page--tab">
-    <view class="mp-header mp-header--workbench">
+    <view class="mp-header mp-header--workbench" :style="safeAreaStyle">
       <view class="mp-header__row">
         <view class="mp-header__main">
           <text class="mp-header__title">工作台</text>

+ 72 - 1
miniprogram/styles/mp-shell.scss

@@ -32,10 +32,33 @@ page {
 .mp-header {
   background: var(--mp-header-gradient);
   color: #fff;
-  padding: calc(28rpx + env(safe-area-inset-top, 0px)) 32rpx 32rpx;
+  padding:
+    calc(28rpx + var(--sq-safe-top, env(safe-area-inset-top, 0px)))
+    calc(32rpx + var(--sq-capsule-right-safe, 96px))
+    32rpx
+    32rpx;
   border-bottom-left-radius: var(--mp-radius-xl);
   border-bottom-right-radius: var(--mp-radius-xl);
   box-shadow: 0 16rpx 40rpx rgba(10, 159, 109, 0.12);
+  box-sizing: border-box;
+}
+
+.mp-header--home {
+  padding-top: calc(40rpx + var(--sq-safe-top, env(safe-area-inset-top, 0px)));
+  padding-bottom: 48rpx;
+}
+
+.mp-header--workbench {
+  /* 去掉魔法 40px 双叠加;仅用 safe-top + 内容间距 */
+  padding-top: calc(48rpx + var(--sq-safe-top, env(safe-area-inset-top, 0px)));
+  padding-bottom: 56rpx;
+  min-height: calc(200rpx + var(--sq-safe-top, 0px));
+  box-sizing: border-box;
+}
+
+.mp-header__main {
+  flex: 1;
+  min-width: 0;
 }
 
 .mp-header__title {
@@ -52,6 +75,45 @@ page {
   line-height: 1.4;
 }
 
+.mp-header__user-stack {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+  justify-content: center;
+  gap: 8rpx;
+  flex-shrink: 0;
+  max-width: 42%;
+}
+
+.mp-header__user-name {
+  font-size: 26rpx;
+  font-weight: 600;
+  line-height: 1.3;
+  max-width: 100%;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.mp-header__logout {
+  font-size: 22rpx;
+  line-height: 1.3;
+  padding: 6rpx 16rpx;
+  border-radius: 999rpx;
+  border: 1rpx solid rgba(255, 255, 255, 0.45);
+  color: #fff;
+  opacity: 0.95;
+}
+
+.mp-header__logout:active {
+  background: rgba(255, 255, 255, 0.12);
+}
+
+.mp-header__logout--disabled {
+  opacity: 0.55;
+  pointer-events: none;
+}
+
 .mp-section {
   padding: 24rpx 32rpx;
 }
@@ -157,6 +219,11 @@ page {
   height: 60rpx;
   border-radius: 16rpx;
   background: linear-gradient(145deg, #e8f5ef, #d9efe5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 32rpx;
+  line-height: 1;
 }
 
 .mp-module-block--bx .mp-menu-card__icon {
@@ -180,6 +247,10 @@ page {
   pointer-events: none;
 }
 
+.mp-menu-card--pad {
+  pointer-events: none;
+}
+
 .mp-placeholder {
   min-height: 60vh;
   display: flex;