Files
2026-08-10 14:34:59 +08:00

180 lines
5.2 KiB
Vue

<template>
<view class="fee-card">
<view class="fee-card-header">
<text class="fee-title">收费总览</text>
<picker mode="selector" :range="feeTypeOptions" range-key="label" @change="onFeeTypeChange">
<view class="fee-type-picker">
<text>{{ selectedFeeTypeLabel || '全部收费类型' }}</text>
<text class="filter-arrow">&#9660;</text>
</view>
</picker>
</view>
<view class="fee-tabs">
<view class="fee-tab-item" :class="{ active: activeTab === 'day' }" @click="switchTab('day')">本日</view>
<view class="fee-tab-item" :class="{ active: activeTab === 'month' }" @click="switchTab('month')">本月</view>
<view class="fee-tab-item" :class="{ active: activeTab === 'year' }" @click="switchTab('year')">本年</view>
</view>
<view class="fee-content">
<view class="fee-ring" v-if="!chartLoading">
<qiun-data-charts type="arcbar" :chartData="arcbarData" :opts="arcbarOpts" :animation="false" />
</view>
<view class="fee-ring fee-ring-loading" v-else>
<text class="loading-text">加载中...</text>
</view>
<view class="fee-metrics">
<view class="metric-row" v-for="item in metricList" :key="item.label">
<view class="metric-info">
<text class="metric-label">{{ item.label }}(元)</text>
<text class="metric-num">{{ item.value }}</text>
</view>
<view class="metric-compare">
<text class="compare-line">同比 <text class="compare-num" :class="compareClass(item.yoy)">{{ item.yoy }}</text></text>
<text class="compare-line">环比 <text class="compare-num" :class="compareClass(item.mom)">{{ item.mom }}</text></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
feeTypeOptions: { type: Array, default: () => [] },
selectedFeeTypeLabel: { type: String, default: '全部收费类型' },
activeTab: { type: String, default: 'day' },
arcbarPercent: { type: Number, default: 0 },
metricList: { type: Array, default: () => [] },
chartLoading: { type: Boolean, default: false }
})
const emit = defineEmits(['tab-change', 'fee-type-change'])
const arcbarData = computed(() => ({
series: [{ name: '实收占比', data: props.arcbarPercent / 100 }]
}))
const arcbarOpts = computed(() => ({
color: ["#4D5DFA"],
title: { name: props.arcbarPercent + '%', fontSize: 12, color: '#4D5DFA' },
subtitle: { name: '' },
extra: {
arcbar: {
type: 'circle',
width: 16,
backgroundColor: '#EAEAEA',
startAngle: 1.5,
endAngle: 0.25,
gap: 2,
lineCap: 'butt'
}
}
}))
const compareClass = (val) => {
if (val && val.startsWith('-')) return 'down'
if (val && val.startsWith('+')) return 'up'
return ''
}
const switchTab = (tab) => { emit('tab-change', tab) }
const onFeeTypeChange = (e) => {
const opt = props.feeTypeOptions[e.detail.value]
emit('fee-type-change', opt)
}
</script>
<style scoped lang="scss">
.fee-card {
margin-top: 20rpx;
background: #fff;
border-radius: 8rpx;
padding: 30rpx 24rpx;
.fee-card-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
.fee-title { font-size: 32rpx; font-weight: 600; color: #222; }
.fee-type-picker { display: flex; align-items: center; font-size: 24rpx; color: #666; border: 2rpx solid #DCDFE6; border-radius: 6rpx; padding: 8rpx 16rpx; }
.filter-arrow { font-size: 18rpx; color: #999; margin-left: 6rpx; }
}
.fee-tabs {
display: flex;
.fee-tab-item {
text-align: center;
padding: 14rpx 32rpx;
font-size: 26rpx;
color: #666;
position: relative;
&.active {
color: #4D5DFA;
font-weight: 600;
&::after {
content: '';
position: absolute;
bottom: -2rpx;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background: #4D5DFA;
border-radius: 2rpx;
}
}
}
}
.fee-content {
display: flex;
align-items: center;
margin-top: 30rpx;
.fee-ring {
width: 240rpx;
height: 180rpx;
flex-shrink: 0;
}
.fee-ring-loading {
display: flex;
align-items: center;
justify-content: center;
.loading-text { font-size: 24rpx; color: #999; }
}
.fee-metrics {
flex: 1;
display: flex;
flex-direction: column;
gap: 20rpx;
margin-left: 20rpx;
.metric-row {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
.metric-info {
display: flex;
flex-direction: column;
.metric-label { font-size: 28rpx; color: #666; }
.metric-num { font-size: 32rpx; color: #333; font-weight: 600; margin-top: 2rpx; }
}
.metric-compare {
display: flex;
flex-direction: column;
align-items: flex-start;
.compare-line { font-size: 24rpx; color: #666; line-height: 1.7; }
.compare-num { font-weight: 600; &.up { color: #67C23A; } &.down { color: #F56C6C; } }
}
}
}
}
</style>