Files
property-resident-side/property-uniapp-project/pages/payment-list/paymentRecord.vue
2026-04-18 08:31:55 +08:00

351 lines
6.3 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="contentStyle" style="">
<view class="status-bar"></view>
<uni-nav-bar title="缴费记录" left-icon="left" @clickLeft="goBack" backgroundColor="transparent"
:border="false">
</uni-nav-bar>
<Loading mask="true" click="true" ref="loading"></Loading>
<!-- 表单区域 -->
<scroll-view class="page" scroll-y="true">
<!-- 累计缴费 -->
<view class="total-box">
<view class="total-title">累计缴费</view>
<view class="total-price">¥800.00</view>
<!-- 折线图 Canvas -->
<canvas canvas-id="chargeChart" class="chart-canvas"></canvas>
</view>
<!-- 缴费明细 -->
<view class="list-wrapper">
<!-- 按月份分组渲染 -->
<view class="month-group" v-for="(item, idx) in monthGroups" :key="idx">
<view class="month-title">
{{ item.month }} 缴费 ¥{{ item.total }}
</view>
<view class="item-list">
<view class="bill-item" v-for="bill in item.list" :key="bill.id">
<view class="bill-icon">
<text class="icon">{{ bill.icon }}</text>
</view>
<view class="bill-info">
<view class="name">{{ bill.name }}</view>
<view class="account">{{ bill.account }}</view>
</view>
<view class="bill-price">-{{ bill.amount }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
onReady: function(e) {},
components: {
},
computed: {
// 自动按月份分组
monthGroups() {
let map = {}
this.billList.forEach(bill => {
if (!map[bill.month]) {
map[bill.month] = {
month: bill.month,
total: 0,
list: []
}
}
map[bill.month].list.push(bill)
map[bill.month].total += bill.amount
})
return Object.values(map).sort((a, b) => b.month - a.month)
}
},
created() {
},
onShow() {
},
mounted() {},
onReady() {
this.$nextTick(() => {
this.drawLineChart();
})
},
data() {
return {
/* 设定状态栏默认高度 */
statusBarHeight: 20,
// 折线图数据
chart: {
months: ['1月', '2月', '3月', '4月', '5月', '6月'],
values: [100, 140, 230, 100, 130, 100]
},
// ====================== 核心5月6月放在一个list里 ======================
billList: [
// 5月数据
{
id: 1,
month: 5,
name: '燃气费',
account: '123123123123',
amount: 25,
icon: ''
},
{
id: 2,
month: 5,
name: '水费',
account: '123123123123',
amount: 25,
icon: ''
},
// 6月数据
{
id: 3,
month: 6,
name: '燃气费',
account: '123123123123',
amount: 30,
icon: ''
},
{
id: 4,
month: 6,
name: '水费',
account: '123123123123',
amount: 10,
icon: ''
},
{
id: 5,
month: 6,
name: '电费',
account: '123123123123',
amount: 30,
icon: '⚡'
}
]
}
},
methods: {
drawLineChart() {
const ctx = uni.createCanvasContext('chargeChart', this)
const canvasPage = uni.getSystemInfoSync();
const w = canvasPage.windowWidth - 30;
const h = canvasPage.windowHeight * 0.3;
const padding = 40
const stepX = (w - 60) / (this.chart.months.length - 1)
const maxVal = 250
ctx.setFillStyle('#999')
ctx.setFontSize(12)
ctx.setTextAlign('center')
// 绘制网格
ctx.beginPath()
ctx.setStrokeStyle('#d8d8d8')
ctx.setLineWidth(1)
for (let i = 0; i <= 5; i++) {
let y = padding + (h - padding * 2) * (1 - i / 5)
ctx.moveTo(40, y)
ctx.lineTo(w - 20, y)
ctx.fillText(i * 50 + '元', 20, y + 4)
}
ctx.stroke()
// 绘制X轴月份
this.chart.months.forEach((m, i) => {
let x = 40 + i * stepX
ctx.fillText(m, x, h - 20)
})
// 绘制折线
let points = []
this.chart.values.forEach((val, i) => {
let x = 40 + i * stepX
let y = padding + (h - padding * 2) * (1 - val / maxVal)
points.push({
x,
y
})
})
ctx.beginPath()
ctx.setStrokeStyle('#4080FF')
ctx.setLineWidth(2)
points.forEach((p, i) => {
if (i === 0) ctx.moveTo(p.x, p.y)
else ctx.lineTo(p.x, p.y)
})
ctx.stroke()
// 绘制圆点
points.forEach((p, i) => {
ctx.beginPath()
ctx.arc(p.x, p.y, 3, 0, 2 * Math.PI)
ctx.setFillStyle('#fff')
ctx.fill()
ctx.setStrokeStyle('#4080FF')
ctx.setLineWidth(2)
ctx.stroke()
ctx.setFillStyle('#4080FF')
ctx.setFontSize(13)
ctx.fillText(this.chart.values[i] + '元', p.x, p.y - 10)
})
ctx.draw()
},
goBack() {
uni.redirectTo({
url: '/pages/payment-list/paymentIndex',
success: res => {},
fail: () => {},
complete: () => {}
});
},
},
}
</script>
<style lang="scss">
page {
background: #f2f1f6;
}
</style>
<style scoped>
.contentStyle {
display: flex;
flex-direction: column;
height: 100vh;
/* 关键:占满屏幕高度 */
background-color: #f9f9f9;
}
.page {
flex: 1;
overflow-y: auto;
padding: 0px 20px;
box-sizing: border-box;
background-color: #fff;
}
.total-box {
padding: 15px;
/* margin-bottom: 10px; */
}
.total-title {
font-size: 16px;
font-weight: 600;
color: #333;
}
.total-price {
font-size: 24px;
font-weight: bold;
margin-top: 6px;
margin-bottom: 10px;
}
.chart-canvas {
width: calc(100vw - 30px);
height: 30vh;
}
.list-wrapper {
padding: 0 15px;
}
.month-group {
padding-bottom: 15px;
border-bottom: 1px solid #f2f2f2;
}
.month-group:last-child {
border-bottom: none;
}
.month-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 15px;
}
.bill-item {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.bill-icon {
width: 40px;
height: 40px;
background: #e6efff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #4080FF;
margin-right: 12px;
font-size: 18px;
}
.bill-info {
flex: 1;
}
.name {
font-size: 14px;
color: #333;
font-weight: 600;
}
.account {
font-size: 12px;
color: #999;
margin-top: 4px;
}
.bill-price {
font-size: 16px;
color: #333;
}.status-bar{
width: 100vw;
height: 46px;
}
</style>