alipay-emulator/pages/finance-management/index.vue

1209 lines
29 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 v-if="$isVip()">
<watermark :dark="data.dark" />
<liu-drag-button :canDocking="false" @clickBtn="$goRechargePage('watermark')">
<c-lottie ref="cLottieRef" :src='$watermark()' width="94px" height='74px' :loop="true"></c-lottie>
</liu-drag-button>
</view>
<view class="container flex flex-column" @touchstart="handleTouchStart" @touchmove.stop.prevent="handleTouchMove"
@touchend="handleTouchEnd">
<!-- 下层信息盒子 -->
<view class="main-info-container" :class="{ 'open': isOpen }"
:style="{ 'padding-bottom': `${cardArrowHeight}px` }">
<!-- 导航栏 placeholder -->
<NavBar v-if="!selectedImage" bgColor="transparent" :buttonGroup="buttonGroup"
@button-click="clickTitlePopupButton">
<view class="nav-bar flex-align-center h100">
<view class="left flex-align-center">
<image src="/static/image/finance-management/search/search-left.png"></image>
</view>
<view class="nav-bar-search flex-align-center flex-1">
<image class="search-icon" src="/static/image/bill/bill-list/search-black.png" mode=""></image>
<input type="text" class="search-input flex-1" placeholder="小而美的基金" />
<view class="line h100"></view>
<view class="search-button">搜索</view>
</view>
<view class="right flex-align-center">
<image src="/static/image/finance-management/search/search-right.png"></image>
</view>
</view>
</NavBar>
<NavBar v-else title="拼图" bgColor="#EFEFEF" noBack @back="closeImage" isRightButton
@right-click="confirmImage">
</NavBar>
<view class="total-money-box flex-align-center flex-justify-between">
<!-- 总资产信息 -->
<view class="revenue-box flex-1">
<view class="total-money flex-align-center">
<view class="total-money-title flex-align-center">
<text>总资产(元)</text>
<image class="eye-icon" src="/static/image/finance-management/eye.png"></image>
<view class="flex-align-center" style="color: #A39797;font-size: 22rpx;">
<image class="safe-icon" src="/static/image/finance-management/safe.png"></image>
<text>免费升级保障</text>
</view>
</view>
<view class="total-money-title flex-align-center">
<text>昨日收益</text>
</view>
</view>
<view class="total-money flex-align-center" style="margin-top: 10px;">
<view class="total-money-value flex-align-center">
<text class="alipay-font">{{ numberUtil.formatMoneyWithThousand(totalMoney) }}</text>
</view>
<view class="total-money-value flex-align-center">
<text class="alipay-font">{{ yesterdayIncome > 0 ? "+" +
numberUtil.formatMoneyWithThousand(yesterdayIncome) :
numberUtil.formatMoneyWithThousand(yesterdayIncome)
}}</text>
</view>
</view>
</view>
<view class="family-protection">
<view class="total-money-title flex-align-center">
<text>家庭保障</text>
</view>
<view class=" flex-align-end" style="margin-top: 10px;">
<text class="value alipay-font">{{ familyProtection }}</text>
<text class="text">份</text>
</view>
</view>
</view>
<!-- 财富信息 -->
<view class="data-box">
<view v-for="item in myAssets" :key="item.title">
<view v-if="item.title" class="title second-color">{{ item.title }}</view>
<view class="group-data flex-justify-between">
<template v-for="subItem in item.items" :key="subItem.label">
<view
v-if="financeInfo[item.key][subItem.key].labelSub && (financeInfo[item.key][subItem.key].labelSub > 0 || financeInfo[item.key][subItem.key].type == 'text')"
class="item flex-align-center flex-justify-between">
<view class="flex-align-center">
<text class="label primary-color">{{ subItem.label }}</text>
<text v-if="financeInfo[item.key][subItem.key].type == 'text'"
class="label-sub second-color">
{{ formatTextWithNumber(financeInfo[item.key][subItem.key].labelSub) }}
</text>
<text v-else class="label-sub second-color">
{{
numberUtil.formatMoneyWithThousand(financeInfo[item.key][subItem.key].labelSub)
}}</text>
</view>
<text v-if="financeInfo[item.key][subItem.key].value" class="value primary-color">{{
financeInfo[item.key][subItem.key].value > 0 ? "+" +
numberUtil.formatMoneyWithThousand(financeInfo[item.key][subItem.key].value) :
numberUtil.formatMoneyWithThousand(financeInfo[item.key][subItem.key].value)
}}</text>
</view>
</template>
<view v-if="item.groupId == '1'" class="item flex-align-center flex-justify-between">
<view class="flex-align-center">
<text class="label primary-color">更多资产服务</text>
</view>
<text class="value primary-color">去看看</text>
</view>
</view>
</view>
</view>
</view>
<!-- 图片盒子 -->
<view class="image-service-box flex-column"
:style="{ top: topHeight + 'px', 'height': `calc(100vh - ${imageCardBoxtopHeight}px)`, transition: isDragging || !isReady ? 'none' : 'top 0.3s ease-out' }">
<view class="card-arrow-box">
<view class="arrow-box">
<image @click="data.isOpen = !data.isOpen" class="arrow-icon"
:src="`/static/image/finance-management/arrow-${isOpen ? 'up' : 'down'}.png`">
</image>
</view>
<view class="card-box flex-column">
<view class="wealth-card-box flex">
<!-- 占位图片设置为透明 -->
<image class="wealth-card-opacity0" src="/static/image/finance-management/v1/bg.png"
mode="widthFix" @load="updateTopHeight" />
<!-- 背景图片高度自适应 -->
<image class="wealth-card"
:src="`/static/image/finance-management/${financeInfo.vipLevel}/bg.png`" mode="widthFix" />
<view class="card-info">
<image class="logo"
:src="`/static/image/finance-management/${financeInfo.vipLevel}/logo.png`"
mode="scaleToFill" />
<view class="name-box flex-align-center">
<image class="card-holder-icon"
:src="`/static/image/finance-management/${financeInfo.vipLevel}/card-holder.png`"
mode="scaleToFill" />
<view class="card-holder-name sacramento-font">{{ financeInfo.cardHolderName }}</view>
</view>
</view>
<view class="enjoy-benefits flex-align-center">
<text class="benefits-text">{{ financeInfo.benefitsText }}</text>
<image class="arrow-icon"
:src="`/static/image/finance-management/${financeInfo.vipLevel}/arrow.png`"></image>
</view>
</view>
<view class="content-box">
<view class="service-icons">
<view class="service-icon" v-for="item in serviceIcons" :key="item.name">
<image class="icon"
:src="`/static/image/finance-management/service-icon/${item.icon}.png`"
mode="scaleToFill" />
<text class="name">{{ item.name }}</text>
</view>
</view>
</view>
</view>
</view>
<view v-if="!selectedImage" class="content flex-1 flex-column flex" @touchstart="clickHandleTouchStart"
@touchend="clickHandleTouchEnd">
<view v-if="financeInfo.bgImage" class="w100 h100" style="margin-top: -1px;">
<image class="w100 h100" :src="financeInfo.bgImage" mode="widthFix">
</image>
</view>
<view v-else class="flex-align-center flex-justify-center flex-column flex-1 w100 h100">
<image style="width:92rpx; height: 92rpx;margin-top: 16rpx;"
src="/static/image/common/upload-screenshot.png">
</image>
<text style="font-size: 36rpx;color: #1777FF;">长按替换真实截图</text>
</view>
</view>
<view v-else class="scroll-image-box flex-1">
<scroll-view class="image-box h100" style="width: 100%;" scroll-y :show-scrollbar="false"
@scroll="onImageScroll">
<image class="crop-image-target" style="width:100%;" :src="selectedImage" mode="widthFix"></image>
</scroll-view>
<view class="dashed-line-box">
<view class="dashed-line-text">我是分割线</view>
</view>
</view>
<canvas canvas-id="crop-canvas"
style="position: fixed; left: -9999px; width: 750rpx; height: 100vh; pointer-events: none;"></canvas>
</view>
<!-- 底部导航栏 -->
<view class="bottom-box"
:class="`navigation-menu-${financeInfo.navigationMenuStyle}`, { 'ios-bottom-box': $system == 'iOS' }">
<view class="bottom-item" v-for="item in navigationMenu" :key="item.name">
<image
:src="`/static/image/finance-management/navigation-menu/${financeInfo.navigationMenuStyle}/${item.icon}.png`">
</image>
<text>{{ item.name }}</text>
</view>
</view>
</view>
<!-- 样式选择弹窗 -->
<uni-popup ref="stylePopup" type="center">
<view class="popup-content">
<view class="popup-title">选择底部导航样式</view>
<view class="style-list">
<view class="style-item" v-for="(item, index) in styleList" :key="index"
@click="confirmStyleDialog(item.value)">
<text>{{ item.label }}</text>
<uni-icons v-if="financeInfo.navigationMenuStyle == item.value" type="checkmarkempty" size="20"
color="#1777FF"></uni-icons>
</view>
</view>
<view class="popup-btns">
<view class="btn cancel" @click="closeStyleDialog">取消</view>
</view>
</view>
</uni-popup>
<!-- 蒙层 -->
<view v-if="showMask" class="mask" @click="closeMask">
<image class="mask-icon" src="/static/image/common/mask-icon.png" mode="widthFix">
</image>
</view>
</template>
<script setup>
import NavBar from '@/components/nav-bar/nav-bar.vue'
import {
ref,
toRefs,
reactive,
onMounted,
watch,
computed,
getCurrentInstance
} from 'vue'
import {
onLoad,
onReady,
onShow
} from '@dcloudio/uni-app'
import {
serviceIcons,
navigationMenu,
myAssets
} from '@/static/json/fortune.json'
import {
numberUtil,
util
} from '@/utils/common.js'
const instance = getCurrentInstance();
const { proxy } = instance
const buttonGroup = [{
name: "编辑理财数据",
click: () => {
util.goPage('/pages/finance-management/edit/edit')
}
}, {
name: "切换导航栏样式",
click: () => {
openStyleDialog()
}
}, {
name: "选择理财图片样式",
click: () => {
util.goPage('/pages/finance-management/select-image/select-image')
}
}, {
name: "删除当前理财图片",
click: () => {
financeInfo.value.bgImage = ""
uni.setStorageSync('financeInfo', financeInfo.value)
}
}]
const defualtData = {
benefitsText: '尊享礼遇18000元/年',
cardHolderName: 'XiaoMing',
vipLevel: "v3",
navigationMenuStyle: "style-1",
bgImage: "",
fortune: {
yuebao: { value: 3.53, labelSub: "100000" },
dingqi: { value: 50, labelSub: "100000" },
jijin: { value: 5000, labelSub: "100000" },
huangjin: { value: -300, labelSub: "100000" },
yulingbao: { value: 20, labelSub: "100000" }
},
myAssets: {
baoxian: { labelSub: "3份保单保障中", type: "text" }
},
myQuota: {
huabei: { labelSub: "可用100000", type: "text" },
jubei: { labelSub: "可用100000", type: "text" },
beizhi: { labelSub: "可用100000", type: "text" },
wangshangdai: { labelSub: "预计可借100000", type: "text" }
}
}
onLoad(() => {
// 理财页面埋点
proxy.$apiUserEvent('all', {
type: 'click',
key: 'fortune',
value: "理财"
})
})
onReady(() => {
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight;
uni.createSelectorQuery().select('.total-money-box').boundingClientRect((data) => {
console.log("total-money-box height: " + (data ? data.height : "null"));
const initialH = data ? data.height + 44 + statusBarHeight.value : 44 + statusBarHeight.value;
topHeight.value = initialH;
minTop = initialH;
imageCardBoxtopHeight.value = initialH;
setTimeout(() => {
isReady.value = true
}, 200)
}).exec()
})
onShow(() => {
financeInfo.value = uni.getStorageSync('financeInfo') || defualtData
console.log("financeInfo.value", financeInfo.value)
// #ifdef APP-PLUS
util.setAndroidSystemBarColor(financeInfo.value.navigationMenuStyle == 'style-1' ? '#ffffff' : '#F8F8F8')
setTimeout(() => {
plus.navigator.setStatusBarStyle("light");
}, 500)
// #endif
})
const updateTopHeight = () => {
setTimeout(() => {
uni.createSelectorQuery().select('.card-arrow-box').boundingClientRect((data) => {
console.log("card-arrow-box height: " + (data ? data.height : "null"));
cardArrowHeight.value = data ? data.height - 20 : 0;
}).exec()
}, 500)
}
// 总资产
const totalMoney = computed(() => {
let totalMoney = 0;
for (const key in financeInfo.value.fortune) {
if (!Object.prototype.hasOwnProperty.call(financeInfo.value.fortune, key)) continue;
const element = financeInfo.value.fortune[key];
totalMoney += Number(element.labelSub)
}
return totalMoney
})
// 昨日收益
const yesterdayIncome = computed(() => {
let yesterdayIncome = 0;
for (const key in financeInfo.value.fortune) {
if (!Object.prototype.hasOwnProperty.call(financeInfo.value.fortune, key)) continue;
const element = financeInfo.value.fortune[key];
yesterdayIncome += Number(element.value)
}
return yesterdayIncome
})
// 家庭保障
const familyProtection = computed(() => {
return parseInt(financeInfo.value.myAssets.baoxian.labelSub)
})
const scrollTop = ref(0)
const onImageScroll = (e) => {
scrollTop.value = e.detail.scrollTop
}
const data = reactive({
financeInfo: { ...defualtData },
topHeight: 0,
statusBarHeight: 0,
cardArrowHeight: 0,
imageCardBoxtopHeight: 0,
isOpen: false,
isDragging: false,
isReady: false,
selectedImage: '',
showMask: false
})
let {
financeInfo,
topHeight,
statusBarHeight,
cardArrowHeight,
imageCardBoxtopHeight,
isOpen,
isDragging,
isReady,
selectedImage,
showMask
} = toRefs(data)
const formatTextWithNumber = (str) => {
if (!str) return '';
return str.replace(/(\d+(\.\d+)?)/g, (match) => {
return match > 100 ? numberUtil.formatMoneyWithThousand(match) : match;
});
}
let startY = 0;
let startTop = 0;
let minTop = 0;
let maxTop = 0;
// 监听 isOpen 变化来控制 topHeight
watch(() => isOpen.value, () => {
updateHeightByState();
})
const handleTouchStart = (e) => {
if (selectedImage.value) return
isDragging.value = true;
startY = e.touches[0].clientY;
startTop = topHeight.value;
// 如果未设置边界(或为了安全起见每次开始时),则计算边界
if (!minTop || !maxTop) {
const systemInfo = uni.getSystemInfoSync();
const statusBar = systemInfo.statusBarHeight;
// 创建查询以获取当前尺寸
const query = uni.createSelectorQuery();
query.select('.total-money-box').boundingClientRect();
query.select('.main-info-container').boundingClientRect();
query.exec(([totalMoneyBox, mainInfoContainer]) => {
if (totalMoneyBox) {
// 最小高度关闭状态total-money-box 高度 + 导航栏 + 状态栏 - 卡片箭头偏移量
minTop = totalMoneyBox.height + 44 + statusBar;
}
});
}
}
const handleTouchMove = (e) => {
if (selectedImage.value) return
let currentY = e.touches[0].clientY;
let delta = currentY - startY;
let newTop = startTop + delta;
// 如果为 0让我们获取它们。
if (minTop === 0 && !isOpen.value) minTop = startTop;
if (maxTop === 0 && isOpen.value) maxTop = startTop;
// 如果有值,则进行简单钳位
if (minTop && newTop < minTop) newTop = minTop;
if (maxTop && newTop > maxTop) newTop = maxTop;
// 应用
topHeight.value = newTop;
}
const updateHeightByState = () => {
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight;
if (isOpen.value) {
// 打开状态:计算 main-info-container 高度
uni.createSelectorQuery().select('.main-info-container').boundingClientRect((data) => {
if (data) {
const targetH = data.height - cardArrowHeight.value;
topHeight.value = targetH;
maxTop = targetH; // 更新 maxTop
}
}).exec()
} else {
// 关闭状态:计算 total-money-box 位置
uni.createSelectorQuery().select('.total-money-box').boundingClientRect((data) => {
if (data) {
const targetH = data.height + 44 + statusBarHeight.value;
topHeight.value = targetH;
minTop = targetH; // 更新 minTop
}
}).exec()
}
}
const handleTouchEnd = (e) => {
if (selectedImage.value) return
isDragging.value = false;
let endY = e.changedTouches[0].clientY;
let diff = endY - startY;
let targetState = isOpen.value;
// 判断滑动意图
if (diff > 50) {
targetState = true;
} else if (diff < -50) {
targetState = false;
}
// 如果状态改变watch 会处理动画/高度更新
if (targetState !== isOpen.value) {
isOpen.value = targetState;
} else {
// 如果状态未改变,手动恢复高度(吸附回原位)
updateHeightByState();
}
}
// 长按事件定时器
let longPressTimer = null
const clickHandleTouchStart = (e) => {
// 兼容iOS上滑HOME条如果有底部安全区且触摸位置在底部安全区内则不触发
const systemInfo = uni.getSystemInfoSync()
if (systemInfo.platform === 'ios' && systemInfo.safeAreaInsets?.bottom) {
const clientY = e.touches[0].clientY
const windowHeight = systemInfo.windowHeight
// 如果触摸点在底部安全区范围内通常是34px则忽略
if (clientY > windowHeight - systemInfo.safeAreaInsets.bottom) {
return
}
}
longPressTimer = setTimeout(() => {
uni.vibrateShort()
chooseImage()
}, 1200) // 长按时间大于1s
}
// 选择图片
const chooseImage = () => {
if (selectedImage.value) return
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
selectedImage.value = res.tempFilePaths[0]
data.showMask = true
setTimeout(() => {
plus.navigator.setStatusBarStyle("dark");
}, 500)
}
})
}
// 确认图片裁剪
const confirmImage = () => {
uni.showLoading({
title: '处理中...'
})
const query = uni.createSelectorQuery().in(instance)
// 获取容器和图片信息
query.select('.image-box').boundingClientRect()
query.select('.crop-image-target').boundingClientRect()
query.exec(res => {
if (!res[0] || !res[1]) {
uni.hideLoading()
return
}
console.log('rects', res)
const container = res[0] // 容器
const image = res[1] // 图片实际渲染尺寸
// 计算缩放比例 (渲染宽度 / 实际宽度 不准确,应该反过来用 图片原始宽/渲染宽?)
// 这里更简单的方法是canvas设为容器大小把图片画进去
// canvas drawImage 参数: img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight
// 获取图片原始尺寸
uni.getImageInfo({
src: selectedImage.value,
success: (imgInfo) => {
const scale = imgInfo.width / image.width // 图片 原始宽 / 渲染宽
const sTop = scrollTop.value * scale // 原始图上的裁切起始Y
const sHeight = container.height * scale // 原始图上的裁切高度
// 因为是 widthFix宽度就是原始图宽度或裁切全宽
const sWidth = imgInfo.width
// 设置画布尺寸 (使用像素值)
// 注意canvasContext绘制使用的是逻辑像素还是物理像素通常需要考虑到 pixelRatio
// 但 uni-app canvas-id 方式通常对应逻辑像素(px)
// 我们把 canvas 大小设为和容器显示一致
const canvasW = container.width
const canvasH = container.height
const ctx = uni.createCanvasContext('crop-canvas', instance)
// 清除画布
ctx.clearRect(0, 0, canvasW, canvasH)
// 绘制
// drawImage(imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
ctx.drawImage(
imgInfo.path,
0, sTop, sWidth, sHeight, // 源图裁剪区域
0, 0, canvasW, canvasH // 画布绘制区域
)
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: 'crop-canvas',
width: canvasW,
height: canvasH,
destWidth: sWidth, // 使用原图实际宽度,保持原图清晰度
destHeight: sHeight, // 使用原图实际高度,保持原图清晰度
success: (res) => {
console.log('crop success (temp)', res
.tempFilePath)
// 将临时路径保存为永久路径
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
console.log('save success (saved)', saveRes.savedFilePath)
financeInfo.value.bgImage = saveRes.savedFilePath
selectedImage.value = '' // 隐藏编辑模式
setTimeout(() => {
plus.navigator.setStatusBarStyle("light");
}, 200)
// 保存到缓存
uni.setStorageSync("financeInfo", financeInfo.value)
uni.hideLoading()
},
fail: (err) => {
console.error('saveFile fail', err)
uni.hideLoading()
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
})
},
fail: (err) => {
console.error(err)
uni.hideLoading()
uni.showToast({
title: '裁剪失败',
icon: 'none'
})
}
}, instance)
})
},
fail: () => {
uni.hideLoading()
uni.showToast({
title: '图片加载失败',
icon: 'none'
})
}
})
})
}
const clickHandleTouchEnd = () => {
if (longPressTimer) {
clearTimeout(longPressTimer)
longPressTimer = null
}
}
const closeImage = () => {
selectedImage.value = ''
data.showMask = false
plus.navigator.setStatusBarStyle("light");
return false
}
const closeMask = () => {
data.showMask = false
}
const stylePopup = ref(null)
const styleList = [{
label: '样式 1 (默认)',
value: 'style-1'
},
{
label: '样式 2',
value: 'style-2'
}
]
// 打开样式选择弹窗
const openStyleDialog = () => {
stylePopup.value.open()
}
// 关闭样式选择弹窗
const closeStyleDialog = () => {
stylePopup.value.close()
}
// 确认样式选择
const confirmStyleDialog = (type) => {
financeInfo.value.navigationMenuStyle = type
uni.setStorageSync('financeInfo', financeInfo.value)
// #ifdef APP-PLUS
util.setAndroidSystemBarColor(financeInfo.value.navigationMenuStyle == 'style-1' ? '#ffffff' : '#F8F8F8')
// #endif
stylePopup.value.close()
}
const clickTitlePopupButton = (button) => {
button.click()
}
</script>
<style>
@import "@/common/main.css";
</style>
<style lang="less" scoped>
.container {
height: 100vh;
background-color: #ffffff;
overflow: hidden;
}
.main-info-container {
background: linear-gradient(348deg, #0B1028 49%, #0B1028 76.26%, #18336C 86.18%, #18336C 100%);
.nav-bar {
padding: 20rpx;
.left {
image {
height: 48rpx;
width: 48rpx;
}
}
.right {
image {
height: 36rpx;
width: 36rpx;
}
}
.nav-bar-search {
background-color: #ffffff;
border-radius: 300rpx;
height: 56rpx;
padding: 4px 0;
margin: 0 26rpx 0 14rpx;
.search-icon {
width: 32rpx;
height: 32rpx;
margin-left: 4px;
margin-right: 6px;
}
.search-input {
font-size: 14px;
}
::v-deep .input-placeholder {
color: #767676;
}
.line {
width: 1px;
background-color: #D8D8D8;
}
.search-button {
font-size: 14px;
padding: 0 12px;
color: #8B634E;
font-weight: 500;
}
}
}
.total-money-box {
padding-top: 10rpx;
padding-bottom: 6rpx;
margin-bottom: 32rpx;
.revenue-box {
padding: 0 24rpx;
.total-money {
font-size: 24rpx;
display: flex;
justify-content: space-between;
}
.total-money-value {
color: #F1CFAB;
}
}
.total-money-title {
color: #A39797;
.eye-icon {
width: 44rpx;
height: 44rpx;
margin: 0 32rpx 0 20rpx;
}
.safe-icon {
width: 24rpx;
height: 24rpx;
margin-right: 4rpx;
}
}
.total-money-value {
font-size: 50rpx;
font-weight: 500;
line-height: 64rpx;
}
.family-protection {
display: flex;
flex-direction: column;
flex-shrink: 0;
height: 100%;
padding: 0 28rpx;
border-left: 1rpx solid #172139;
align-items: center;
font-size: 24rpx;
.value {
color: #F1CFAB;
font-size: 56rpx;
font-weight: 500;
line-height: 64rpx;
}
.text {
color: #F1CFAB;
font-size: 24rpx;
margin-left: 8rpx;
}
}
}
.data-box {
padding: 0 26rpx 0;
font-size: 26rpx;
.title {
margin-bottom: 40rpx;
}
.group-data {
// margin-top: 8rpx;
flex-wrap: wrap;
.item {
width: calc(50% - 15rpx);
flex-shrink: 0;
margin-bottom: 40rpx;
.label {
margin-right: 18rpx;
flex-shrink: 0;
}
.label-sub {
white-space: nowrap;
}
}
}
.second-color {
color: #787174;
}
.primary-color {
color: #EAD2B8;
}
}
}
.open {
// background: #08112E;
background: linear-gradient(146deg, #0B1028 49%, #08112E 71.26%, #18336C 83.18%, #18336C 96%)
}
.image-service-box {
position: absolute;
display: flex;
flex-direction: column;
top: 20%;
width: 100%;
.arrow-box {
display: flex;
align-items: center;
justify-content: center;
padding: 4rpx;
.arrow-icon {
width: 28rpx;
height: 28rpx;
}
}
.card-box {
display: flex;
flex-direction: column;
.wealth-card-box {
position: relative;
.card-info {
display: flex;
justify-content: space-between;
align-items: flex-start;
position: absolute;
width: 100%;
top: 12%;
padding: 0 5%;
.logo {
width: 188rpx;
height: 40rpx;
}
.name-box {
display: flex;
align-items: flex-start;
}
.card-holder-icon {
width: 68rpx;
height: 28rpx;
margin-right: 8rpx;
}
.card-holder-name {
color: #F1CFAB;
font-size: 30rpx;
}
}
.enjoy-benefits {
position: absolute;
bottom: 25%;
right: 4%;
.benefits-text {
color: #F1CFAB;
font-size: 24rpx;
}
.arrow-icon {
width: 28rpx;
height: 28rpx;
margin-left: 6rpx;
}
}
}
.wealth-card-opacity0 {
width: 100%;
opacity: 0;
}
.wealth-card {
position: absolute;
width: 100%;
}
.content-box {
margin-top: -1px;
background: linear-gradient(180deg, #FFFFFF 56.37%, #F0F4F9 100%);
padding: 20rpx;
padding-bottom: 12rpx;
.service-icons {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.service-icon {
display: flex;
flex-direction: column;
align-items: center;
width: 20%;
margin-top: 22rpx;
margin-bottom: 8rpx;
.icon {
width: 62rpx;
height: 62rpx;
}
.name {
font-size: 26rpx;
color: #5D5D5D;
}
}
}
}
}
.image-box {
width: 100%;
overflow: hidden; // scroll-view 需要
}
.scroll-image-box {
background-color: #ffffff;
width: 100%;
min-height: 0; // 修复 flex一出问题
position: relative;
}
.dashed-line-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border: 4rpx dashed #ffffff;
pointer-events: none;
.dashed-line-text {
height: 44rpx;
line-height: 44rpx;
width: 180rpx;
padding: 0 20rpx;
border-radius: 8rpx;
color: #1777FF;
font-size: 24rpx;
font-weight: 500;
background-color: #fff;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 999;
.mask-icon {
position: absolute;
top: 50%;
right: 52rpx;
transform: translateY(-25%);
width: 360rpx;
height: 360rpx;
}
}
.content {
background-color: #ffffff;
// padding: 20rpx;
margin-top: -1px;
}
.bottom-box {
position: fixed;
bottom: 0;
width: 100%;
// height: 100rpx;
background-color: #ffffff;
display: flex;
justify-content: space-around;
align-items: center;
padding: 4rpx 0;
.bottom-item {
display: flex;
flex-direction: column;
align-items: center;
image {
width: 56rpx;
height: 56rpx;
}
text {
margin-top: 12rpx;
font-size: 20rpx;
line-height: 25rpx;
color: #333;
}
}
}
.navigation-menu-style-1 {
background-color: #ffffff;
.bottom-item:nth-child(2) {
text {
color: #A27140;
}
}
}
.navigation-menu-style-2 {
background-color: #F8F8F8;
border-top: 1rpx solid #C3CED1;
padding: 6rpx 0;
.bottom-item:nth-child(2) {
text {
color: #0075FF;
}
}
}
.ios-bottom-box {
padding-bottom: constant(safe-area-inset-bottom); // 兼容 IOS<11.2
padding-bottom: env(safe-area-inset-bottom); // 兼容 IOS>11.2
}
</style>
<style scoped>
.popup-content {
background-color: #fff;
border-radius: 12px;
width: 600rpx;
padding: 20px;
}
.popup-title {
text-align: center;
font-size: 18px;
font-weight: 500;
margin-bottom: 20px;
color: #333;
}
.style-list {
margin-bottom: 20px;
}
.style-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 10px;
border-bottom: 1px solid #f5f5f5;
font-size: 16px;
color: #333;
}
.style-item:active {
background-color: #f9f9f9;
border-radius: 8px;
}
.popup-btns {
display: flex;
justify-content: center;
}
.btn {
width: 100%;
height: 44px;
line-height: 44px;
text-align: center;
border-radius: 22px;
font-size: 16px;
}
.btn.cancel {
background-color: #f5f5f5;
color: #666;
}
</style>