alipay-emulator/pages/common/alipay-annual-bill/alipay-annual-bill.vue

951 lines
20 KiB
Vue

<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">
<view class="bg-container"></view>
<view class="status-nav-bar" :style="{ height: (statusBarHeight + 44) + 'px' }">
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
<view class="nav-bar">
<view class="nav-bar-left" @click="goback()">
<image class="nav-bar-left-image" src="@/static/image/alipay-bill/back.png" mode=""></image>
</view>
<view class="nav-bar-right">
<image class="nav-bar-right-image" src="@/static/image/alipay-bill/music-icon.png" mode=""></image>
<image class="nav-bar-right-image" src="@/static/image/alipay-bill/share-icon.png" mode=""></image>
</view>
</view>
</view>
<image ref="bgImage" class="bg-image" src="@/static/image/alipay-bill/main-bg.png" mode="widthFix"></image>
<image class="eye-image" src="@/static/image/alipay-bill/hide.png" mode="widthFix"></image>
<image class="find-more" src="@/static/image/alipay-bill/find-more.png" mode=""></image>
<view class="total-money">
<text>年度总支出</text>
<text class="money alipay-font-bold" @click="openPopup">{{ formatMoney(totalMoney) }}</text>
<text class="unit">元</text>
</view>
<view class="frist-money money-type-item">
<view class="type-input-box">
<!-- <{{ moneyFrist.type }}>支出最多! -->
<<view class="percentage-input-box">
<text class="ghost-text">{{ moneyFrist.type }}</text>
<input class="percentage-input" type="text" v-model="moneyFrist.type"
@input="inputPercentage($event, 'moneyFrist')" maxlength="4"></input>
</view>>支出最多!
</view>
<view class="money">
<view class="percentage-input-box">
<text class="ghost-text">{{ moneyFrist.percentage }}</text>
<input class="percentage-input" type="digit" v-model="moneyFrist.percentage"
@input="inputPercentage($event, 'moneyFrist')"></input>
</view>
<view>%</view>
</view>
</view>
<view class="second-money money-type-item">
<view class="type-input-box">
<!-- {{ moneySecond.type }} -->
<view class="percentage-input-box">
<text class="ghost-text">{{ moneySecond.type }}</text>
<input class="percentage-input" type="text" v-model="moneySecond.type"
@input="inputPercentage($event, 'moneySecond')"></input>
</view>
</view>
<view class="money">
<view class="percentage-input-box">
<text class="ghost-text">{{ moneySecond.percentage }}</text>
<input class="percentage-input" type="digit" v-model="moneySecond.percentage"
@input="inputPercentage($event, 'moneySecond')"></input>
</view>
<view>%</view>
</view>
</view>
<view class="third-money money-type-item">
<view class="type-input-box">
<!-- {{ moneyThird.type }} -->
<view class="percentage-input-box">
<text class="ghost-text">{{ moneyThird.type }}</text>
<input class="percentage-input" type="text" v-model="moneyThird.type"
@input="inputPercentage($event, 'moneyThird')"></input>
</view>
</view>
<view class="money">
<view class="percentage-input-box">
<text class="ghost-text">{{ moneyThird.percentage }}</text>
<input class="percentage-input" type="digit" v-model="moneyThird.percentage"
@input="inputPercentage($event, 'moneyThird')"></input>
</view>
<view>%</view>
</view>
</view>
<view class="fourth-money money-type-item">
<view class="type-input-box">
<!-- {{ moneyFourth.type }} -->
<view class="percentage-input-box">
<text class="ghost-text">{{ moneyFourth.type }}</text>
<input class="percentage-input" type="text" v-model="moneyFourth.type"
@input="inputPercentage($event, 'moneyFourth')"></input>
</view>
</view>
<view class="money">
<view class="percentage-input-box">
<text class="ghost-text">{{ moneyFourth.percentage }}</text>
<input class="percentage-input" type="digit" v-model="moneyFourth.percentage"
@input="inputPercentage($event, 'moneyFourth')"></input>
</view>
<view>%</view>
</view>
</view>
<view class="fifth-money money-type-item">
<view class="type-input-box">
<!-- {{ moneyFifth.type }} -->
<view class="percentage-input-box">
<text class="ghost-text">{{ moneyFifth.type }}</text>
<input class="percentage-input" type="text" v-model="moneyFifth.type"
@input="inputPercentage($event, 'moneyFifth')"></input>
</view>
</view>
<view class="money">
<view class="percentage-input-box">
<text class="ghost-text">{{ moneyFifth.percentage }}</text>
<input class="percentage-input" type="digit" v-model="moneyFifth.percentage"
@input="inputPercentage($event, 'moneyFifth')"></input>
</view>
<view>%</view>
</view>
</view>
<view class="time-box" @click="openTimePopup">
数据统计截至{{ formatDate(time) }}
</view>
<image class="footer-image" src="@/static/image/alipay-bill/footer.png" mode="heightFix"></image>
<!-- 修改金额弹窗 -->
<uni-popup ref="dialogPopup" type="dialog">
<uni-popup-dialog class="popup-dialog" mode="input" title="修改年度总支出" :before-close="true"
@close="dialogPopupClose()" @confirm="confirm">
<uni-easyinput v-model="totalMoney" step="0.01" type="digit" :focus="true"
placeholder="请输入金额"></uni-easyinput>
</uni-popup-dialog>
</uni-popup>
<!-- 修改时间弹窗 -->
<uni-popup ref="timeDialogPopup" type="dialog">
<uni-popup-dialog class="popup-dialog" mode="input" title="修改时间" :before-close="true"
@close="timeDialogPopupClose()" @confirm="confirmTime">
<picker mode="date" fields="day" :value="time" @change="bindTimeChange" start="2025-12-29"
:end="formatDateISO(new Date())">
<view class="picker-view" style="padding: 10px; border-radius: 4px; text-align: center;">
{{ formatDate(time) || '请选择时间' }}
</view>
</picker>
</uni-popup-dialog>
</uni-popup>
</view>
<!-- 水印 -->
<!-- <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> -->
</template>
<script setup>
import {
ref,
reactive,
toRefs,
getCurrentInstance
} from 'vue';
import {
onLoad,
onShow,
onUnload
} from '@dcloudio/uni-app';
const statusBarHeight = ref(0);
const dialogPopup = ref(null);
const timeDialogPopup = ref(null);
const instance = getCurrentInstance();
const { proxy } = instance;
const data = reactive({
totalMoney: 10000000,
time: "",
moneyFrist: {
type: '转账红包',
percentage: "83"
},
moneySecond: {
type: '家居家装',
percentage: "83"
},
moneyThird: {
type: '餐饮美食',
percentage: "83"
},
moneyFourth: {
type: '日用百货',
percentage: "83"
},
moneyFifth: {
type: '服饰装扮',
percentage: "83"
},
navBarHeight: 0
})
let {
totalMoney,
moneyFrist,
moneySecond,
moneyThird,
moneyFourth,
moneyFifth,
time,
navBarHeight
} = toRefs(data)
onLoad(() => {
// 进入花呗页面埋点
proxy.$apiUserEvent('all', {
type: 'click',
key: 'year_in_review',
value: "年度账单"
})
time.value = getYesterday();
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight;
const config = uni.getStorageSync('config')
console.log("---config---", config);
const font = config.config['client.uniapp.font']
console.log("字体地址信息", font.alipay2025);
// Font loading logic
const fontUrl = font.alipay2025;
const fontName = 'AlibabaSemiBold';
const loadFont = (path) => {
uni.loadFontFace({
family: fontName,
source: `url("${path}")`,
success() {
console.log('字体加载成功');
},
fail(err) {
console.error('字体加载失败', err);
}
});
};
// #ifdef H5
// H5 环境直接从 URL 加载字体
loadFont(fontUrl);
// #endif
// #ifndef H5
// 非 H5 环境使用下载和保存逻辑
const savedFontPath = uni.getStorageSync('alipay_font_path');
if (savedFontPath) {
loadFont(savedFontPath);
} else {
uni.downloadFile({
url: fontUrl,
success: (res) => {
if (res.statusCode === 200) {
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
const savedPath = saveRes.savedFilePath;
uni.setStorageSync('alipay_font_path', savedPath);
console.log("字体保存路径", savedPath);
loadFont(savedPath);
},
fail: (err) => {
console.error('保存文件失败', err);
// Fallback: 尝试加载临时路径
loadFont(res.tempFilePath);
}
});
}
},
fail: (err) => {
console.error('下载字体失败', err);
}
});
}
// #endif
try {
data.totalMoney = uni.getStorageSync('totalMoney') || 1000000;
data.moneyFrist = uni.getStorageSync('moneyFrist') || {
type: '转账红包',
percentage: "66.3"
};
data.moneySecond = uni.getStorageSync('moneySecond') || {
type: '家居家装',
percentage: "16.8"
};
data.moneyThird = uni.getStorageSync('moneyThird') || {
type: '服饰装备',
percentage: "8.3"
};
data.moneyFourth = uni.getStorageSync('moneyFourth') || {
type: '日用百货',
percentage: "5.2"
};
data.moneyFifth = uni.getStorageSync('moneyFifth') || {
type: '餐饮美食',
percentage: "3.2"
};
data.time = uni.getStorageSync('alipayBillEndTime') || getYesterday();
console.log('数据同步缓存成功');
} catch (err) {
console.log('数据同步缓存失败', err);
}
})
/**
* 打开修改金额弹窗
*/
const openPopup = () => {
dialogPopup.value.open();
}
const goback = () => {
uni.navigateBack();
}
const formatMoney = (val) => {
let num = Number(val);
if (isNaN(num)) {
return '0.00';
}
let str = num.toFixed(2);
let parts = str.split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
}
const dialogPopupClose = () => {
dialogPopup.value.close();
}
const confirm = () => {
uni.setStorageSync('totalMoney', totalMoney.value);
dialogPopup.value.close();
}
/**
* 格式化时间
* @param {Object} date
*/
const formatDate = (date) => {
const d = new Date(date);
const y = d.getFullYear();
const m = d.getMonth() + 1;
const day = d.getDate();
return `${y}${m}${day}`;
}
const inputPercentage = (e, type) => {
console.log('Saving', type, data[type]);
uni.setStorageSync(type, data[type]);
}
/**
* 打开修改时间弹窗
*/
const openTimePopup = () => {
timeDialogPopup.value.open();
}
const timeDialogPopupClose = () => {
timeDialogPopup.value.close();
}
const bindTimeChange = (e) => {
time.value = e.detail.value;
}
/**
* 获取昨天的时间
*/
const getYesterday = () => {
const date = new Date();
date.setDate(date.getDate() - 1);
return formatDateISO(date);
}
/**
* 格式化时间 2025-12-01
* @param {Object} date
*/
const formatDateISO = (date) => {
const d = new Date(date);
const y = d.getFullYear();
const m = (d.getMonth() + 1).toString().padStart(2, '0');
const day = d.getDate().toString().padStart(2, '0');
return `${y}-${m}-${day}`;
}
const confirmTime = () => {
uni.setStorageSync('alipayBillEndTime', time.value);
timeDialogPopup.value.close();
}
</script>
<style lang="scss" scoped>
.container {
width: 100vw;
height: 100vh;
background-color: #D3E9FE;
// background: linear-gradient(180deg, #6BB8FE 0%, #D3E9FE 100%);
position: relative;
overflow: hidden;
.nav-bar {
box-sizing: border-box;
width: 100vw;
height: 44px;
background-color: transparent;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
.nav-bar-left-image {
width: 24px;
height: 24px;
}
.nav-bar-right-image {
width: 28px;
height: 28px;
margin-left: 16px;
}
}
.bg-container {
width: 100vw;
height: 50%;
background: linear-gradient(180deg, #6BB8FE 0%, #D3E9FE 100%);
position: absolute;
top: 0;
left: 0;
}
}
.bg-image {
width: 100vw;
height: 85% !important;
position: fixed;
left: 0;
bottom: 0;
}
.total-money {
position: absolute;
top: calc(15% + 12px);
left: 10%;
color: #fff;
font-size: 30rpx;
font-weight: 500;
display: flex;
align-items: center;
.money {
font-weight: 700;
font-size: 44rpx;
margin-left: 6rpx;
}
.percentage-input-box {
margin-left: 6rpx;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.ghost-text {
font-size: 44rpx;
min-width: 20px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 44rpx;
line-height: 44rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 44rpx;
text-align: center;
font-weight: 700;
}
.unit {
font-size: 44rpx;
}
}
.frist-money {
position: absolute;
top: calc(48%);
left: 16%;
font-size: 36rpx;
font-weight: 500;
display: flex;
align-items: center;
flex-direction: column;
transform: rotate(6deg);
font-weight: 700;
line-height: 58rpx;
.type-input-box {
.ghost-text {
font-size: 36rpx;
min-width: 20px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 36rpx;
line-height: 36rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 36rpx;
text-align: center;
font-weight: 700;
}
}
.money {
font-weight: 700;
font-size: 44rpx;
margin-left: 6rpx;
display: flex;
.percentage-input-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.ghost-text {
font-size: 44rpx;
min-width: 20px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 44rpx;
line-height: 44rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 44rpx;
text-align: center;
font-weight: 700;
}
}
}
.second-money {
position: absolute;
top: calc(33% + 8rpx);
right: 12%;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
flex-direction: column;
transform: rotate(6deg);
font-weight: 700;
line-height: 44rpx;
.type-input-box {
height: 44rpx;
.ghost-text {
font-size: 32rpx;
min-width: 20px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 32rpx;
line-height: 32rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 32rpx;
text-align: center;
font-weight: 700;
}
}
.money {
display: flex;
align-items: center;
font-size: 32rpx;
margin-left: 6rpx;
.percentage-input-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.ghost-text {
font-size: 32rpx;
min-width: 16px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 32rpx;
line-height: 32rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 32rpx;
text-align: center;
font-weight: 700;
}
}
}
.third-money {
position: absolute;
top: calc(25% + 8rpx);
left: 23%;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
flex-direction: column;
transform: rotate(4deg);
font-weight: 700;
line-height: 42rpx;
.type-input-box {
height: 42rpx;
line-height: 42rpx;
.ghost-text {
font-size: 32rpx;
min-width: 20px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 32rpx;
line-height: 32rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 32rpx;
text-align: center;
font-weight: bold;
}
}
.money {
font-size: 32rpx;
margin-left: 6rpx;
display: flex;
align-items: center;
.percentage-input-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.ghost-text {
font-size: 32rpx;
min-width: 16px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 32rpx;
line-height: 32rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 32rpx;
text-align: center;
font-weight: 700;
}
}
}
.fourth-money {
position: absolute;
top: calc(44% - 4rpx);
right: calc(14% + 4px);
font-size: 24rpx;
font-weight: 500;
display: flex;
align-items: center;
flex-direction: column;
transform: rotate(4deg);
line-height: 28rpx;
font-weight: 700;
.type-input-box {
height: 28rpx;
line-height: 28rpx;
.ghost-text {
font-size: 24rpx;
min-width: 20px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 24rpx;
line-height: 24rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 24rpx;
text-align: center;
font-weight: 700;
}
}
.money {
display: flex;
align-items: center;
font-size: 24rpx;
margin-left: 6rpx;
.percentage-input-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.ghost-text {
font-size: 24rpx;
min-width: 16px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 24rpx;
line-height: 24rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 24rpx;
text-align: center;
font-weight: 700;
}
}
}
.fifth-money {
position: absolute;
top: calc(35% - 4rpx);
left: 7%;
font-size: 30rpx;
font-weight: 500;
display: flex;
align-items: center;
flex-direction: column;
transform: rotate(4deg);
font-weight: 700;
line-height: 42rpx;
.type-input-box {
height: 42rpx;
line-height: 42rpx;
.ghost-text {
font-size: 30rpx;
min-width: 20px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 30rpx;
line-height: 30rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 30rpx;
text-align: center;
font-weight: bold;
}
}
.money {
display: flex;
align-items: center;
font-size: 30rpx;
margin-left: 6rpx;
.percentage-input-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.ghost-text {
font-size: 30rpx;
min-width: 16px;
font-weight: 700;
visibility: hidden;
opacity: 0;
white-space: pre;
height: 30rpx;
line-height: 30rpx;
}
.percentage-input {
position: absolute;
left: 0;
width: 100%;
height: 100%;
font-size: 30rpx;
text-align: center;
font-weight: 700;
}
}
}
.money-type-item {
color: #000000;
font-weight: 700;
.type-input-box {
display: flex;
align-items: center;
.percentage-input-box {
margin-left: 6rpx;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.find-more {
width: 118rpx;
height: 50rpx;
position: absolute;
top: 28%;
right: -4%;
transform: translateX(-50%);
}
.eye-image {
width: 98rpx;
height: 40rpx;
position: absolute;
top: 17%;
right: 8%;
}
.time-box {
padding: 10rpx 56rpx;
background-color: #000000;
opacity: 0.35;
color: #FAC6CA;
font-size: 22rpx;
line-height: 22rpx;
font-weight: 500;
display: inline-block;
text-align: center;
border-radius: 286px;
position: absolute;
white-space: nowrap;
left: 50%;
transform: translateX(-50%);
bottom: 30%;
}
.footer-image {
height: 190rpx;
position: fixed;
left: 50%;
transform: translateX(-50%);
bottom: 32rpx;
}
.alipay-font-bold {
font-family: 'AlibabaSemiBold';
}
</style>