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

934 lines
20 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 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
} from 'vue';
import {
onLoad,
onShow,
onUnload
} from '@dcloudio/uni-app';
const statusBarHeight = ref(0);
const dialogPopup = ref(null);
const timeDialogPopup = ref(null);
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(() => {
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>