bm-bmt/components/asset-page-shell.vue

211 lines
4.6 KiB
Vue

<template>
<view class="asset-shell" :style="shellStyle">
<view class="asset-shell__nav">
<view class="asset-shell__side">
<view v-if="backable" class="asset-shell__back" @click="handleBack">
<image
class="asset-shell__back-image"
src="https://imgs.agrimedia.cn/bm-bmt/bacn-icon.png"
mode="aspectFit"
></image>
</view>
</view>
<view class="asset-shell__title">
<text class="asset-shell__title-text">{{ title }}</text>
</view>
<view class="asset-shell__side asset-shell__side--right">
<slot name="right">
<text
v-if="rightText"
class="asset-shell__action"
@click="$emit('right-click')"
>
{{ rightText }}
</text>
</slot>
</view>
</view>
<slot />
</view>
</template>
<script>
import { refreshCurrentWebviewToken } from "../utils/webview-token";
export default {
props: {
title: {
type: String,
default: "",
},
rightText: {
type: String,
default: "",
},
backable: {
type: Boolean,
default: true,
},
sideWidth: {
type: String,
default: "120rpx",
},
},
data() {
return {
navLayout: {
paddingTop: "calc(env(safe-area-inset-top) + 20rpx)",
navHeight: "64rpx",
},
};
},
computed: {
shellStyle() {
return {
"--asset-shell-side-width": this.sideWidth,
"--asset-shell-padding-top": this.navLayout.paddingTop,
"--asset-shell-nav-height": this.navLayout.navHeight,
};
},
},
created() {
refreshCurrentWebviewToken();
this.initNavLayout();
},
methods: {
initNavLayout() {
const fallbackLayout = {
paddingTop: "calc(env(safe-area-inset-top) + 20rpx)",
navHeight: "64rpx",
};
try {
if (
typeof uni !== "undefined" &&
typeof uni.getMenuButtonBoundingClientRect === "function"
) {
const menuButtonRect = uni.getMenuButtonBoundingClientRect();
if (
menuButtonRect &&
Number(menuButtonRect.top) > 0 &&
Number(menuButtonRect.height) > 0
) {
const menuButtonHeight = Number(menuButtonRect.height);
this.navLayout = {
paddingTop: Number(menuButtonRect.top) + "px",
navHeight: Math.max(menuButtonHeight + 8, 36) + "px",
};
return;
}
}
if (
typeof uni !== "undefined" &&
typeof uni.getSystemInfoSync === "function"
) {
const systemInfo = uni.getSystemInfoSync() || {};
const statusBarHeight = Number(systemInfo.statusBarHeight || 0);
if (statusBarHeight > 0) {
this.navLayout = {
paddingTop: statusBarHeight + 12 + "px",
navHeight: "64rpx",
};
return;
}
}
} catch (error) {
// Ignore runtime layout failures and keep fallback spacing.
}
this.navLayout = fallbackLayout;
},
handleBack() {
if (getCurrentPages().length > 1) {
uni.navigateBack();
return;
}
uni.reLaunch({
url: "/pages/index/index",
});
},
},
};
</script>
<style lang="scss" scoped>
@import "../styles/tokens.scss";
.asset-shell {
position: sticky;
top: 0;
z-index: 20;
padding: var(--asset-shell-padding-top) 18rpx 24rpx;
background: #191e32;
}
.asset-shell__nav {
display: flex;
align-items: flex-end;
min-height: calc(var(--asset-shell-nav-height) + 12rpx);
padding-bottom: 16rpx;
}
.asset-shell__side {
display: flex;
align-items: flex-end;
width: var(--asset-shell-side-width);
flex: 0 0 var(--asset-shell-side-width);
min-width: 0;
}
.asset-shell__side--right {
align-items: flex-end;
justify-content: flex-end;
width: 64rpx;
height: 64rpx;
}
.asset-shell__back {
display: flex;
align-items: flex-end;
justify-content: center;
width: 64rpx;
height: 64rpx;
}
.asset-shell__back-image {
width: 56rpx;
height: 56rpx;
}
.asset-shell__title {
flex: 1;
display: flex;
align-items: flex-end;
justify-content: center;
min-width: 0;
}
.asset-shell__title-text {
display: block;
width: 100%;
text-align: center;
font-size: 36rpx;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #ffffff;
}
.asset-shell__action {
font-size: 24rpx;
font-weight: 600;
color: rgba(232, 239, 255, 0.86);
}
</style>