This commit is contained in:
zpc 2026-02-20 19:12:08 +08:00
parent 07562a377b
commit de7eb8234c
14 changed files with 244 additions and 140 deletions

View File

@ -0,0 +1,12 @@
-- 为测评类型表添加详情横幅图字段
-- 用于小程序测评信息填写页顶部的横幅图展示
IF NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'assessment_types' AND COLUMN_NAME = 'DetailImageUrl'
)
BEGIN
ALTER TABLE assessment_types
ADD DetailImageUrl nvarchar(500) NULL;
END
GO

View File

@ -36,6 +36,12 @@ public class AssessmentType
[MaxLength(500)] [MaxLength(500)]
public string? ImageUrl { get; set; } public string? ImageUrl { get; set; }
/// <summary>
/// 详情横幅图URL
/// </summary>
[MaxLength(500)]
public string? DetailImageUrl { get; set; }
/// <summary> /// <summary>
/// 介绍内容 /// 介绍内容
/// </summary> /// </summary>

View File

@ -25,6 +25,11 @@ public class AssessmentTypeDto
/// </summary> /// </summary>
public string? ImageUrl { get; set; } public string? ImageUrl { get; set; }
/// <summary>
/// 详情横幅图URL
/// </summary>
public string? DetailImageUrl { get; set; }
/// <summary> /// <summary>
/// 介绍内容 /// 介绍内容
/// </summary> /// </summary>

View File

@ -27,6 +27,12 @@ public class CreateAssessmentTypeRequest
[MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")] [MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")]
public string? ImageUrl { get; set; } public string? ImageUrl { get; set; }
/// <summary>
/// 详情横幅图URL
/// </summary>
[MaxLength(500, ErrorMessage = "详情横幅图URL不能超过500个字符")]
public string? DetailImageUrl { get; set; }
/// <summary> /// <summary>
/// 介绍内容 /// 介绍内容
/// </summary> /// </summary>

View File

@ -33,6 +33,12 @@ public class UpdateAssessmentTypeRequest
[MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")] [MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")]
public string? ImageUrl { get; set; } public string? ImageUrl { get; set; }
/// <summary>
/// 详情横幅图URL
/// </summary>
[MaxLength(500, ErrorMessage = "详情横幅图URL不能超过500个字符")]
public string? DetailImageUrl { get; set; }
/// <summary> /// <summary>
/// 介绍内容 /// 介绍内容
/// </summary> /// </summary>

View File

@ -83,6 +83,7 @@ public class AssessmentService : IAssessmentService
Name = t.Name, Name = t.Name,
Code = t.Code, Code = t.Code,
ImageUrl = t.ImageUrl, ImageUrl = t.ImageUrl,
DetailImageUrl = t.DetailImageUrl,
IntroContent = t.IntroContent, IntroContent = t.IntroContent,
Price = t.Price, Price = t.Price,
QuestionCount = t.QuestionCount, QuestionCount = t.QuestionCount,
@ -108,6 +109,7 @@ public class AssessmentService : IAssessmentService
Name = t.Name, Name = t.Name,
Code = t.Code, Code = t.Code,
ImageUrl = t.ImageUrl, ImageUrl = t.ImageUrl,
DetailImageUrl = t.DetailImageUrl,
IntroContent = t.IntroContent, IntroContent = t.IntroContent,
Price = t.Price, Price = t.Price,
QuestionCount = t.QuestionCount, QuestionCount = t.QuestionCount,
@ -159,6 +161,7 @@ public class AssessmentService : IAssessmentService
Name = request.Name, Name = request.Name,
Code = request.Code, Code = request.Code,
ImageUrl = request.ImageUrl, ImageUrl = request.ImageUrl,
DetailImageUrl = request.DetailImageUrl,
IntroContent = request.IntroContent, IntroContent = request.IntroContent,
Price = request.Price, Price = request.Price,
QuestionCount = request.QuestionCount, QuestionCount = request.QuestionCount,
@ -219,6 +222,7 @@ public class AssessmentService : IAssessmentService
assessmentType.Name = request.Name; assessmentType.Name = request.Name;
assessmentType.Code = request.Code; assessmentType.Code = request.Code;
assessmentType.ImageUrl = request.ImageUrl; assessmentType.ImageUrl = request.ImageUrl;
assessmentType.DetailImageUrl = request.DetailImageUrl;
assessmentType.IntroContent = request.IntroContent; assessmentType.IntroContent = request.IntroContent;
assessmentType.Price = request.Price; assessmentType.Price = request.Price;
assessmentType.QuestionCount = request.QuestionCount; assessmentType.QuestionCount = request.QuestionCount;

View File

@ -21,6 +21,8 @@ export interface AssessmentTypeItem {
code: string code: string
/** 图片URL */ /** 图片URL */
imageUrl: string imageUrl: string
/** 详情横幅图URL */
detailImageUrl: string
/** 介绍内容(富文本) */ /** 介绍内容(富文本) */
introContent: string introContent: string
/** 价格 */ /** 价格 */
@ -59,6 +61,8 @@ export interface CreateAssessmentTypeRequest {
code: string code: string
/** 图片URL */ /** 图片URL */
imageUrl?: string imageUrl?: string
/** 详情横幅图URL */
detailImageUrl?: string
/** 介绍内容(富文本) */ /** 介绍内容(富文本) */
introContent?: string introContent?: string
/** 价格 */ /** 价格 */

View File

@ -212,6 +212,15 @@
/> />
</el-form-item> </el-form-item>
<el-form-item label="详情横幅图" prop="detailImageUrl">
<ImageUpload
v-model="state.formData.detailImageUrl"
placeholder="点击上传详情页横幅图"
tip="建议尺寸750x400支持 jpg、png、gif 格式"
:max-size="10"
/>
</el-form-item>
<el-form-item label="价格" prop="price"> <el-form-item label="价格" prop="price">
<el-input-number <el-input-number
v-model="state.formData.price" v-model="state.formData.price"
@ -302,6 +311,7 @@ interface AssessmentTypeFormData {
name: string name: string
code: string code: string
imageUrl: string imageUrl: string
detailImageUrl: string
introContent: string introContent: string
price: number price: number
sort: number sort: number
@ -384,6 +394,7 @@ function getDefaultFormData(): AssessmentTypeFormData {
name: '', name: '',
code: '', code: '',
imageUrl: '', imageUrl: '',
detailImageUrl: '',
introContent: '', introContent: '',
price: 0, price: 0,
sort: 0, sort: 0,
@ -497,6 +508,7 @@ function handleEdit(row: AssessmentTypeItem) {
name: row.name, name: row.name,
code: row.code, code: row.code,
imageUrl: row.imageUrl || '', imageUrl: row.imageUrl || '',
detailImageUrl: row.detailImageUrl || '',
introContent: row.introContent || '', introContent: row.introContent || '',
price: row.price, price: row.price,
sort: row.sort, sort: row.sort,
@ -570,6 +582,7 @@ async function handleSubmit() {
name: formData.name, name: formData.name,
code: formData.code, code: formData.code,
imageUrl: formData.imageUrl || undefined, imageUrl: formData.imageUrl || undefined,
detailImageUrl: formData.detailImageUrl || undefined,
introContent: formData.introContent || undefined, introContent: formData.introContent || undefined,
price: formData.price, price: formData.price,
sort: formData.sort, sort: formData.sort,

View File

@ -48,6 +48,7 @@ public class AssessmentService : IAssessmentService
.Where(a => a.Id == typeId && !a.IsDeleted) .Where(a => a.Id == typeId && !a.IsDeleted)
.Select(a => new AssessmentIntroDto .Select(a => new AssessmentIntroDto
{ {
ImageUrl = a.DetailImageUrl,
Content = a.IntroContent ?? string.Empty, Content = a.IntroContent ?? string.Empty,
ContentType = "html", ContentType = "html",
Price = a.Price Price = a.Price

View File

@ -1124,6 +1124,9 @@ public partial class MiAssessmentDbContext : DbContext
entity.Property(e => e.ImageUrl) entity.Property(e => e.ImageUrl)
.HasMaxLength(500) .HasMaxLength(500)
.HasComment("入口图片URL"); .HasComment("入口图片URL");
entity.Property(e => e.DetailImageUrl)
.HasMaxLength(500)
.HasComment("详情横幅图URL");
entity.Property(e => e.IntroContent) entity.Property(e => e.IntroContent)
.HasComment("介绍内容"); .HasComment("介绍内容");
entity.Property(e => e.Price) entity.Property(e => e.Price)

View File

@ -36,6 +36,12 @@ public class AssessmentType
[MaxLength(500)] [MaxLength(500)]
public string? ImageUrl { get; set; } public string? ImageUrl { get; set; }
/// <summary>
/// 详情横幅图URL
/// </summary>
[MaxLength(500)]
public string? DetailImageUrl { get; set; }
/// <summary> /// <summary>
/// 介绍内容 /// 介绍内容
/// </summary> /// </summary>

View File

@ -5,6 +5,11 @@ namespace MiAssessment.Model.Models.Assessment;
/// </summary> /// </summary>
public class AssessmentIntroDto public class AssessmentIntroDto
{ {
/// <summary>
/// 详情横幅图URL
/// </summary>
public string? ImageUrl { get; set; }
/// <summary> /// <summary>
/// 介绍内容 /// 介绍内容
/// </summary> /// </summary>

View File

@ -316,7 +316,7 @@ onLoad((options) => {
<template> <template>
<view class="assessment-info-page"> <view class="assessment-info-page">
<!-- 导航栏 --> <!-- 导航栏 -->
<Navbar title="测评信息" :showBack="true" /> <Navbar :title="introData.title || '多元智能测评'" :showBack="true" />
<!-- 页面内容 --> <!-- 页面内容 -->
<view class="page-content"> <view class="page-content">
@ -336,19 +336,26 @@ onLoad((options) => {
<!-- 表单区域 --> <!-- 表单区域 -->
<view class="form-section"> <view class="form-section">
<!-- 表单提示 -->
<view class="form-header">
<text class="form-header-text">正式测评前请先填写您的基本信息</text>
</view>
<!-- 姓名 --> <!-- 姓名 -->
<view class="form-item"> <view class="form-item">
<view class="form-label"> <view class="form-label">
<text class="required">*</text> <text class="required">*</text>
<text>姓名</text> <text>姓名</text>
</view> </view>
<input <view class="form-input-wrap">
class="form-input" <input
type="text" class="form-input"
placeholder="请输入姓名" type="text"
v-model="formData.name" placeholder="请输入"
maxlength="20" v-model="formData.name"
/> maxlength="20"
/>
</view>
</view> </view>
<!-- 手机号 --> <!-- 手机号 -->
@ -357,13 +364,15 @@ onLoad((options) => {
<text class="required">*</text> <text class="required">*</text>
<text>手机号</text> <text>手机号</text>
</view> </view>
<input <view class="form-input-wrap">
class="form-input" <input
type="number" class="form-input"
placeholder="请输入手机号" type="number"
v-model="formData.phone" placeholder="请输入"
maxlength="11" v-model="formData.phone"
/> maxlength="11"
/>
</view>
</view> </view>
<!-- 性别 --> <!-- 性别 -->
@ -379,7 +388,7 @@ onLoad((options) => {
> >
<view class="form-picker"> <view class="form-picker">
<text :class="{ 'placeholder': !formData.gender }"> <text :class="{ 'placeholder': !formData.gender }">
{{ formData.gender || '请选择性别' }} {{ formData.gender || '请选择' }}
</text> </text>
<view class="picker-arrow"></view> <view class="picker-arrow"></view>
</view> </view>
@ -399,7 +408,7 @@ onLoad((options) => {
> >
<view class="form-picker"> <view class="form-picker">
<text :class="{ 'placeholder': !formData.age }"> <text :class="{ 'placeholder': !formData.age }">
{{ formData.age || '请选择年龄' }} {{ formData.age || '请选择' }}
</text> </text>
<view class="picker-arrow"></view> <view class="picker-arrow"></view>
</view> </view>
@ -419,15 +428,15 @@ onLoad((options) => {
> >
<view class="form-picker"> <view class="form-picker">
<text :class="{ 'placeholder': !formData.educationStage }"> <text :class="{ 'placeholder': !formData.educationStage }">
{{ formData.educationStage || '请选择学业阶段' }} {{ formData.educationStage || '请选择' }}
</text> </text>
<view class="picker-arrow"></view> <view class="picker-arrow"></view>
</view> </view>
</picker> </picker>
</view> </view>
<!-- 省市区 --> <!-- 所在城市 -->
<view class="form-item"> <view class="form-item form-item-last">
<view class="form-label"> <view class="form-label">
<text class="required">*</text> <text class="required">*</text>
<text>所在城市</text> <text>所在城市</text>
@ -436,11 +445,25 @@ onLoad((options) => {
mode="region" mode="region"
@change="onRegionChange" @change="onRegionChange"
> >
<view class="form-picker"> <view class="form-region-picker">
<text :class="{ 'placeholder': !formData.province }"> <view class="region-item">
{{ formData.province ? `${formData.province} ${formData.city} ${formData.district}` : '请选择省市区' }} <text :class="{ 'placeholder': !formData.province }">
</text> {{ formData.province || '省' }}
<view class="picker-arrow"></view> </text>
<view class="picker-arrow"></view>
</view>
<view class="region-item">
<text :class="{ 'placeholder': !formData.city }">
{{ formData.city || '市' }}
</text>
<view class="picker-arrow"></view>
</view>
<view class="region-item">
<text :class="{ 'placeholder': !formData.district }">
{{ formData.district || '区/县' }}
</text>
<view class="picker-arrow"></view>
</view>
</view> </view>
</picker> </picker>
</view> </view>
@ -448,22 +471,24 @@ onLoad((options) => {
<!-- 底部按钮区域 --> <!-- 底部按钮区域 -->
<view class="bottom-section"> <view class="bottom-section">
<!-- 支付测评按钮 --> <view class="bottom-btn-group">
<view <!-- 邀请码测评按钮 -->
class="btn-pay" <view
:class="{ 'btn-disabled': !isFormComplete }" class="btn-invite"
@click="handlePayAssessment" :class="{ 'btn-disabled': !isFormComplete }"
> @click="openInvitePopup"
<text>支付{{ introData.price || 0 }} 开始测评</text> >
</view> <text>邀请码免费测评</text>
</view>
<!-- 邀请码测评按钮 -->
<view <!-- 支付测评按钮 -->
class="btn-invite" <view
:class="{ 'btn-disabled': !isFormComplete }" class="btn-pay"
@click="openInvitePopup" :class="{ 'btn-disabled': !isFormComplete }"
> @click="handlePayAssessment"
<text>邀请码免费测评</text> >
<text>支付{{ introData.price || 0 }}元开始测评</text>
</view>
</view> </view>
</view> </view>
</view> </view>
@ -513,14 +538,11 @@ onLoad((options) => {
} }
.page-content { .page-content {
padding: $spacing-lg;
padding-bottom: 200rpx; padding-bottom: 200rpx;
} }
// //
.intro-section { .intro-section {
background-color: $bg-white;
border-radius: $border-radius-lg;
overflow: hidden; overflow: hidden;
margin-bottom: $spacing-lg; margin-bottom: $spacing-lg;
@ -531,6 +553,7 @@ onLoad((options) => {
.intro-text { .intro-text {
padding: $spacing-lg; padding: $spacing-lg;
background-color: $bg-white;
.intro-title { .intro-title {
font-size: $font-size-xl; font-size: $font-size-xl;
@ -551,25 +574,35 @@ onLoad((options) => {
.form-section { .form-section {
background-color: $bg-white; background-color: $bg-white;
border-radius: $border-radius-lg; border-radius: $border-radius-lg;
margin: 0 $spacing-lg;
padding: 0 $spacing-lg; padding: 0 $spacing-lg;
} }
//
.form-header {
padding: $spacing-xl 0 $spacing-md;
text-align: center;
.form-header-text {
font-size: $font-size-sm;
color: $text-secondary;
}
}
.form-item { .form-item {
display: flex;
align-items: center;
padding: $spacing-lg 0; padding: $spacing-lg 0;
border-bottom: 1rpx solid $border-light; border-bottom: 1rpx solid $border-light;
&:last-child { &.form-item-last {
border-bottom: none; border-bottom: none;
} }
} }
.form-label { .form-label {
width: 160rpx;
flex-shrink: 0;
font-size: $font-size-md; font-size: $font-size-md;
color: $text-color; color: $text-color;
font-weight: $font-weight-medium;
margin-bottom: $spacing-sm;
.required { .required {
color: $error-color; color: $error-color;
@ -577,9 +610,12 @@ onLoad((options) => {
} }
} }
.form-input-wrap {
margin-top: $spacing-xs;
}
.form-input { .form-input {
flex: 1; height: 56rpx;
height: 48rpx;
font-size: $font-size-md; font-size: $font-size-md;
color: $text-color; color: $text-color;
@ -589,11 +625,11 @@ onLoad((options) => {
} }
.form-picker { .form-picker {
flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
height: 48rpx; height: 56rpx;
margin-top: $spacing-xs;
font-size: $font-size-md; font-size: $font-size-md;
color: $text-color; color: $text-color;
@ -611,6 +647,39 @@ onLoad((options) => {
} }
} }
//
.form-region-picker {
display: flex;
align-items: center;
gap: $spacing-md;
margin-top: $spacing-xs;
.region-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
background-color: $bg-gray;
border-radius: $border-radius-sm;
font-size: $font-size-md;
color: $text-color;
.placeholder {
color: $text-placeholder;
}
.picker-arrow {
width: 12rpx;
height: 12rpx;
border-right: 3rpx solid $text-placeholder;
border-bottom: 3rpx solid $text-placeholder;
transform: rotate(45deg);
margin-left: $spacing-xs;
}
}
}
// //
.bottom-section { .bottom-section {
position: fixed; position: fixed;
@ -623,19 +692,25 @@ onLoad((options) => {
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05); box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
} }
.btn-pay { .bottom-btn-group {
display: flex;
gap: $spacing-md;
}
.btn-invite {
flex: 1;
height: 88rpx; height: 88rpx;
background: linear-gradient(135deg, #FF6B6B 0%, #FF5252 100%); background-color: $bg-white;
border: 2rpx solid #FF5252;
border-radius: 44rpx; border-radius: 44rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-bottom: $spacing-md;
text { text {
font-size: $font-size-lg; font-size: $font-size-md;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: $text-white; color: #FF5252;
} }
&:active { &:active {
@ -643,19 +718,19 @@ onLoad((options) => {
} }
} }
.btn-invite { .btn-pay {
flex: 1;
height: 88rpx; height: 88rpx;
background-color: $bg-white; background: linear-gradient(135deg, #FF6B6B 0%, #FF5252 100%);
border: 2rpx solid $primary-color;
border-radius: 44rpx; border-radius: 44rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
text { text {
font-size: $font-size-lg; font-size: $font-size-md;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: $primary-color; color: $text-white;
} }
&:active { &:active {

View File

@ -73,36 +73,24 @@ function handleBack() {
} }
/** /**
* 处理点击参与 * 处理点击按钮
*/ */
function handleParticipate() { function handleButtonClick() {
if (!businessDetail.value) return if (!businessDetail.value) return
const detail = businessDetail.value const detail = businessDetail.value
// if (detail.buttonLink) {
if (detail.linkType === 'assessment') { //
//
uni.navigateTo({ uni.navigateTo({
url: `/pages/assessment/info/index?typeId=${detail.linkId || ''}&typeName=${encodeURIComponent(detail.name || '')}` url: detail.buttonLink,
})
} else if (detail.linkType === 'planner') {
//
uni.navigateTo({
url: '/pages/planner/list/index'
})
} else if (detail.linkUrl) {
//
uni.navigateTo({
url: detail.linkUrl,
fail: () => { fail: () => {
uni.switchTab({ uni.switchTab({
url: detail.linkUrl url: detail.buttonLink
}) })
} }
}) })
} else { } else {
//
uni.showToast({ uni.showToast({
title: '功能开发中', title: '功能开发中',
icon: 'none' icon: 'none'
@ -130,7 +118,7 @@ onLoad((options) => {
</view> </view>
<!-- 标题 --> <!-- 标题 -->
<view class="navbar-title-wrap"> <view class="navbar-title-wrap">
<text class="navbar-title">{{ businessDetail?.name || '业务详情' }}</text> <text class="navbar-title">{{ businessDetail?.title || '业务详情' }}</text>
</view> </view>
<!-- 右侧占位 --> <!-- 右侧占位 -->
<view class="navbar-right"></view> <view class="navbar-right"></view>
@ -158,17 +146,12 @@ onLoad((options) => {
class="detail-image" class="detail-image"
@error="handleImageError" @error="handleImageError"
/> />
<!-- 多张图片支持 --> <!-- 底部按钮悬浮在图片底部 -->
<template v-if="businessDetail.images && businessDetail.images.length > 0"> <view v-if="businessDetail.showButton" class="image-bottom-action">
<image <view class="action-btn" @click="handleButtonClick">
v-for="(img, index) in businessDetail.images" <text class="btn-text">{{ businessDetail.buttonText || '点击参与' }}</text>
:key="index" </view>
:src="img.imageUrl || img" </view>
mode="widthFix"
class="detail-image"
@error="handleImageError"
/>
</template>
</view> </view>
</template> </template>
@ -183,14 +166,8 @@ onLoad((options) => {
</view> </view>
</view> </view>
<!-- 底部按钮区域 --> <!-- 底部安全区域 -->
<view v-if="businessDetail && !pageLoading" class="bottom-action"> <view class="safe-area-bottom"></view>
<view class="action-btn" @click="handleParticipate">
<text class="btn-text">点击参与</text>
</view>
<!-- 底部安全区域 -->
<view class="safe-area-bottom"></view>
</view>
</view> </view>
</template> </template>
@ -200,7 +177,6 @@ onLoad((options) => {
.business-detail-page { .business-detail-page {
min-height: 100vh; min-height: 100vh;
background-color: $bg-white; background-color: $bg-white;
padding-bottom: 160rpx; //
} }
// //
@ -277,6 +253,7 @@ onLoad((options) => {
// //
.detail-image-wrap { .detail-image-wrap {
width: 100%; width: 100%;
position: relative;
.detail-image { .detail-image {
width: 100%; width: 100%;
@ -284,59 +261,40 @@ onLoad((options) => {
} }
} }
// //
.empty-state { .image-bottom-action {
display: flex; position: absolute;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 200rpx 0;
.empty-icon {
width: 200rpx;
height: 200rpx;
margin-bottom: $spacing-lg;
}
.empty-text {
font-size: $font-size-md;
color: $text-placeholder;
}
}
//
.bottom-action {
position: fixed;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 80rpx;
background-color: $bg-white; display: flex;
padding: $spacing-md $spacing-lg; justify-content: center;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
z-index: 100;
.action-btn { .action-btn {
width: 100%; min-width: 320rpx;
height: 96rpx; height: 88rpx;
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%); background-color: $bg-white;
border-radius: 48rpx; border-radius: $border-radius-round;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 0 60rpx;
box-shadow: $shadow-md;
&:active { &:active {
opacity: 0.9; opacity: 0.9;
} }
.btn-text { .btn-text {
font-size: 34rpx; font-size: 32rpx;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: $text-white; color: $text-color;
} }
} }
}
.safe-area-bottom {
height: env(safe-area-inset-bottom); //
} .safe-area-bottom {
height: env(safe-area-inset-bottom);
} }
</style> </style>